go/docs/RFC.md

2082 lines
35 KiB
Markdown

# Core API Contract (RFC)
This file is the canonical API catalog for `dappco.re/go/core`.
- Exports follow the `core.Result` contract (`{Value any, OK bool}`) for outcomes.
- Inputs are passed as `core.Options` collections of `core.Option` key-value pairs.
- All method and function examples below compile against current repository behavior.
## 1) Core construction and top-level bootstrap types
### `type CoreOption func(*Core) Result`
```go
func customOption(*core.Core) core.Result
```
### `func New(opts ...CoreOption) *Core`
```go
c := core.New(
core.WithOption("name", "agent"),
core.WithService(process.Register),
core.WithServiceLock(),
)
```
### `func WithOptions(opts Options) CoreOption`
```go
c := core.New(core.WithOptions(core.NewOptions(
core.Option{Key: "name", Value: "agent"},
)))
```
### `func WithService(factory func(*Core) Result) CoreOption`
```go
c := core.New(core.WithService(process.Register))
```
### `func WithName(name string, factory func(*Core) Result) CoreOption`
```go
c := core.New(core.WithName("process", process.Register))
```
### `func WithOption(key string, value any) CoreOption`
```go
c := core.New(
core.WithOption("name", "agent"),
core.WithOption("debug", true),
)
```
### `func WithServiceLock() CoreOption`
```go
c := core.New(
core.WithService(auth.Register),
core.WithServiceLock(),
)
```
### `type ServiceFactory func() Result`
```go
type ServiceFactory func() core.Result
```
### `func NewWithFactories(app any, factories map[string]ServiceFactory) Result`
```go
r := core.NewWithFactories(nil, map[string]core.ServiceFactory{
"audit": func() core.Result {
return core.Result{Value: mySvc(core.NewServiceRuntime(core.Core, core.MyOptions{})), OK: true}
},
})
if !r.OK { panic(r.Value) }
```
### `func NewRuntime(app any) Result`
```go
r := core.NewRuntime(nil)
runtime := r.Value.(*core.Runtime)
```
### `type Runtime struct`
- `app any`
- `Core *Core`
#### `func (r *Runtime) ServiceName() string`
```go
name := rt.ServiceName() // "Core"
```
#### `func (r *Runtime) ServiceStartup(ctx context.Context, options any) Result`
```go
r := rt.ServiceStartup(context.Background(), nil)
```
#### `func (r *Runtime) ServiceShutdown(ctx context.Context) Result`
```go
r := rt.ServiceShutdown(context.Background())
```
## 2) Core accessors and lifecycle
### `type Core struct`
#### `func (c *Core) Options() *Options`
```go
name := c.Options().String("name")
```
#### `func (c *Core) App() *App`
```go
appName := c.App().Name
```
#### `func (c *Core) Data() *Data`
```go
r := c.Data().ReadString("brain/prompt.md")
```
#### `func (c *Core) Drive() *Drive`
```go
r := c.Drive().Get("api")
```
#### `func (c *Core) Fs() *Fs`
```go
r := c.Fs().Write("status.json", "ok")
```
#### `func (c *Core) Config() *Config`
```go
c.Config().Set("debug", true)
```
#### `func (c *Core) Error() *ErrorPanic`
```go
defer c.Error().Recover()
```
#### `func (c *Core) Log() *ErrorLog`
```go
_ = c.Log().Info("boot")
```
#### `func (c *Core) Cli() *Cli`
```go
c.Cli().SetBanner(func(_ *core.Cli) string { return "agent" })
```
#### `func (c *Core) IPC() *Ipc`
```go
c.RegisterAction(func(_ *core.Core, _ core.Message) core.Result { return core.Result{OK: true} })
```
#### `func (c *Core) I18n() *I18n`
```go
_ = c.I18n().Language()
```
#### `func (c *Core) Env(key string) string`
```go
home := c.Env("DIR_HOME")
```
#### `func (c *Core) Context() context.Context`
```go
goCtx := c.Context()
```
#### `func (c *Core) Core() *Core`
```go
self := c.Core()
```
#### `func (c *Core) RunE() error`
```go
if err := c.RunE(); err != nil { /* handle */ }
```
#### `func (c *Core) Run()`
```go
c.Run()
```
#### `func (c *Core) ACTION(msg Message) Result`
```go
c.ACTION(core.ActionServiceStartup{})
```
#### `func (c *Core) QUERY(q Query) Result`
```go
r := c.QUERY(core.NewOptions(core.Option{Key: "name", Value: "agent"}))
```
#### `func (c *Core) QUERYALL(q Query) Result`
```go
r := c.QUERYALL(core.NewOptions())
```
#### `func (c *Core) LogError(err error, op, msg string) Result`
```go
_ = c.LogError(err, "core.Start", "startup failed")
```
#### `func (c *Core) LogWarn(err error, op, msg string) Result`
```go
_ = c.LogWarn(err, "agent.Check", "warning")
```
#### `func (c *Core) Must(err error, op, msg string)`
```go
c.Must(err, "core.op", "must hold")
```
#### `func (c *Core) RegistryOf(name string) *Registry[any]`
```go
svcNames := c.RegistryOf("services").Names()
```
## 3) Service and lifecycle discovery APIs
### `type Service struct`
```go
type Service struct {
Name string
Instance any
Options Options
OnStart func() Result
OnStop func() Result
OnReload func() Result
}
```
### `func (c *Core) Service(name string, service ...Service) Result`
```go
_ = c.Service("cache", core.Service{
OnStart: func() core.Result { return core.Result{OK: true} },
OnStop: func() core.Result { return core.Result{OK: true} },
})
```
### `func (c *Core) RegisterService(name string, instance any) Result`
```go
_ = c.RegisterService("process", processSvc)
```
### `func (c *Core) Services() []string`
```go
names := c.Services()
```
### `func (c *Core) Lock(name string) *Lock`
```go
l := c.Lock("agent")
l.Mutex.Lock()
defer l.Mutex.Unlock()
```
### `func (c *Core) LockEnable(name ...string)`
```go
c.LockEnable()
```
### `func (c *Core) LockApply(name ...string)`
```go
c.LockApply()
```
### `func (c *Core) Startables() Result`
```go
r := c.Startables()
```
### `func (c *Core) Stoppables() Result`
```go
r := c.Stoppables()
```
### `func (c *Core) ServiceStartup(ctx context.Context, options any) Result`
```go
r := c.ServiceStartup(context.Background(), nil)
```
### `func (c *Core) ServiceShutdown(ctx context.Context) Result`
```go
r := c.ServiceShutdown(context.Background())
```
### `type ServiceRuntime[T any]`
```go
sr := core.NewServiceRuntime(c, MyServiceOptions{})
```
#### `func NewServiceRuntime[T any](c *Core, opts T) *ServiceRuntime[T]`
```go
sr := core.NewServiceRuntime(c, core.MyOpts{})
```
#### `func (r *ServiceRuntime[T]) Core() *Core`
```go
c := sr.Core()
```
#### `func (r *ServiceRuntime[T]) Options() T`
```go
opts := sr.Options()
```
#### `func (r *ServiceRuntime[T]) Config() *Config`
```go
cfg := sr.Config()
```
### `type ServiceRegistry struct`
`*Registry[*Service]` + `lockEnabled bool`.
### `func ServiceFor[T any](c *Core, name string) (T, bool)`
```go
svc, ok := core.ServiceFor[*myService](c, "myservice")
```
### `func MustServiceFor[T any](c *Core, name string) T`
```go
svc := core.MustServiceFor[*myService](c, "myservice")
```
### `type Startable interface { OnStartup(context.Context) Result }`
### `type Stoppable interface { OnShutdown(context.Context) Result }`
## 4) Actions, Tasks, and message-driven capability primitives
### `type ActionHandler func(context.Context, Options) Result`
```go
var h ActionHandler = func(ctx context.Context, opts core.Options) core.Result { return core.Result{OK: true} }
```
### `type Action struct`
```go
a := c.Action("process.run")
```
#### `func (a *Action) Run(ctx context.Context, opts Options) Result`
```go
r := a.Run(ctx, core.NewOptions(core.Option{Key: "command", Value: "go test"}))
```
#### `func (a *Action) Exists() bool`
```go
if c.Action("process.run").Exists() { /* invoke */ }
```
### `func (c *Core) Action(name string, handler ...ActionHandler) *Action`
```go
c.Action("agent.echo", func(_ context.Context, opts core.Options) core.Result {
return core.Result{Value: opts.String("msg"), OK: true}
})
```
### `func (c *Core) Actions() []string`
```go
names := c.Actions()
```
### `type Step struct`
`Action`, `With`, `Async`, `Input`.
### `type Task struct`
`Name`, `Description`, `Steps`.
#### `func (t *Task) Run(ctx context.Context, c *Core, opts Options) Result`
```go
r := c.Task("deploy").Run(ctx, c, core.NewOptions())
```
### `func (c *Core) Task(name string, def ...Task) *Task`
```go
c.Task("deploy", core.Task{Steps: []core.Step{{Action: "agent.echo", Async: false}}})
```
### `func (c *Core) Tasks() []string`
```go
for _, n := range c.Tasks() {}
```
### `type Message any`
```go
c.ACTION(core.ActionTaskStarted{TaskIdentifier: "t1", Action: "agent.echo"})
```
### `type Query any`
```go
type statusQuery struct{}
_ = statusQuery{}
```
### `type QueryHandler func(*Core, Query) Result`
### `func (c *Core) Query(q Query) Result`
```go
r := c.Query(core.Query("ping"))
```
### `func (c *Core) QueryAll(q Query) Result`
```go
r := c.QueryAll(core.Query("ping"))
```
### `func (c *Core) RegisterQuery(handler QueryHandler)`
```go
c.RegisterQuery(func(_ *core.Core, _ core.Query) core.Result { return core.Result{Value: "pong", OK: true} })
```
### `func (c *Core) RegisterAction(handler func(*Core, Message) Result)`
```go
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result { return core.Result{OK: true} })
```
### `func (c *Core) RegisterActions(handlers ...func(*Core, Message) Result)`
```go
c.RegisterActions(h1, h2)
```
### `func (c *Core) RemoteAction(name string, ctx context.Context, opts Options) Result`
```go
r := c.RemoteAction("charon:agent.status", ctx, core.NewOptions())
```
### `type ActionServiceStartup struct{}`
### `type ActionServiceShutdown struct{}`
### `type ActionTaskStarted struct`
`TaskIdentifier`, `Action`, `Options`.
### `type ActionTaskProgress struct`
`TaskIdentifier`, `Action`, `Progress`, `Message`.
### `type ActionTaskCompleted struct`
`TaskIdentifier`, `Action`, `Result`.
## 5) Remote API and stream transport
### `type Stream interface`
```go
type Stream interface {
Send(data []byte) error
Receive() ([]byte, error)
Close() error
}
```
### `type StreamFactory func(handle *DriveHandle) (Stream, error)`
```go
var f core.StreamFactory = func(h *core.DriveHandle) (core.Stream, error) { return nil, nil }
```
### `type API struct`
#### `func (c *Core) API() *API`
```go
_ = c.API()
```
#### `func (a *API) RegisterProtocol(scheme string, factory StreamFactory)`
```go
c.API().RegisterProtocol("mcp", mcpStreamFactory)
```
#### `func (a *API) Stream(name string) Result`
```go
r := c.API().Stream("api")
```
#### `func (a *API) Call(endpoint, action string, opts Options) Result`
```go
r := c.API().Call("api", "agent.status", core.NewOptions())
```
#### `func (a *API) Protocols() []string`
```go
names := c.API().Protocols()
```
## 6) Command and CLI layer
### `type CliOptions struct{}`
### `type Cli struct`
#### `func CliRegister(c *Core) Result`
```go
_ = core.CliRegister(c)
```
#### `func (cl *Cli) Print(format string, args ...any)`
```go
cl.Print("starting %s", "agent")
```
#### `func (cl *Cli) SetOutput(w io.Writer)`
```go
cl.SetOutput(os.Stderr)
```
#### `func (cl *Cli) Run(args ...string) Result`
```go
r := cl.Run("deploy", "to", "homelab")
```
#### `func (cl *Cli) PrintHelp()`
```go
cl.PrintHelp()
```
#### `func (cl *Core) SetBanner(fn func(*Cli) string)`
```go
cl.SetBanner(func(_ *core.Cli) string { return "agent-cli" })
```
#### `func (cl *Cli) Banner() string`
```go
label := cl.Banner()
```
### `type CommandAction func(Options) Result`
### `type Command struct`
```go
c.Command("deploy", core.Command{Action: func(opts core.Options) core.Result {
return core.Result{Value: "ok", OK: true}
}})
```
#### `func (cmd *Command) I18nKey() string`
```go
key := c.Command("deploy/to/homelab").Value.(*core.Command).I18nKey()
```
#### `func (cmd *Command) Run(opts Options) Result`
```go
r := cmd.Run(core.NewOptions(core.Option{Key: "name", Value: "x"}))
```
#### `func (cmd *Command) IsManaged() bool`
```go
if cmd.IsManaged() { /* managed lifecycle */ }
```
### `type CommandRegistry struct`
`*Registry[*Command]`.
#### `func (c *Core) Command(path string, command ...Command) Result`
```go
c.Command("agent/deploy", core.Command{
Action: func(opts core.Options) core.Result { return core.Result{OK: true} },
})
```
#### `func (c *Core) Commands() []string`
```go
paths := c.Commands()
```
### `type Command` fields
`Name`, `Description`, `Path`, `Action`, `Managed`, `Flags`, `Hidden`, internal `commands`.
## 7) Subsystems: App, Data, Drive, Fs, I18n, Process
### `type App struct`
#### `func (a App) New(opts Options) App`
```go
app := (core.App{}).New(core.NewOptions(
core.Option{Key: "name", Value: "agent"},
))
```
#### `func (a App) Find(filename, name string) Result`
```go
r := core.App{}.Find("go", "Go")
```
### `type Data struct`
#### `func (d *Data) New(opts Options) Result`
```go
r := c.Data().New(core.NewOptions(
core.Option{Key: "name", Value: "brain"},
core.Option{Key: "source", Value: brainFS},
core.Option{Key: "path", Value: "prompts"},
))
```
#### `func (d *Data) ReadFile(path string) Result`
```go
r := c.Data().ReadFile("brain/readme.md")
```
#### `func (d *Data) ReadString(path string) Result`
```go
r := c.Data().ReadString("brain/readme.md")
```
#### `func (d *Data) List(path string) Result`
```go
r := c.Data().List("brain/templates")
```
#### `func (d *Data) ListNames(path string) Result`
```go
r := c.Data().ListNames("brain/templates")
```
#### `func (d *Data) Extract(path, targetDir string, templateData any) Result`
```go
r := c.Data().Extract("brain/template", "/tmp/ws", map[string]string{"Name": "demo"})
```
#### `func (d *Data) Mounts() []string`
```go
for _, m := range c.Data().Mounts() {}
```
### `type DriveHandle struct`
`Name`, `Transport`, `Options`.
### `type Drive struct`
#### `func (d *Drive) New(opts Options) Result`
```go
r := c.Drive().New(core.NewOptions(
core.Option{Key: "name", Value: "mcp"},
core.Option{Key: "transport", Value: "mcp://localhost:1234"},
))
```
### `type Fs struct`
#### `func (m *Fs) New(root string) *Fs`
```go
fs := (&core.Fs{}).New("/tmp")
```
#### `func (m *Fs) NewUnrestricted() *Fs`
```go
fs := (&core.Fs{}).NewUnrestricted()
```
#### `func (m *Fs) Root() string`
```go
root := c.Fs().Root()
```
#### `func (m *Fs) Read(p string) Result`
```go
r := c.Fs().Read("status.txt")
```
#### `func (m *Fs) Write(p, content string) Result`
```go
_ = c.Fs().Write("status.txt", "ok")
```
#### `func (m *Fs) WriteMode(p, content string, mode os.FileMode) Result`
```go
_ = c.Fs().WriteMode("secret", "x", 0600)
```
#### `func (m *Fs) TempDir(prefix string) string`
```go
tmp := c.Fs().TempDir("agent-")
```
#### `func (m *Fs) WriteAtomic(p, content string) Result`
```go
_ = c.Fs().WriteAtomic("status.json", "{\"ok\":true}")
```
#### `func (m *Fs) EnsureDir(p string) Result`
```go
_ = c.Fs().EnsureDir("cache")
```
#### `func (m *Fs) IsDir(p string) bool`
```go
ok := c.Fs().IsDir("cache")
```
#### `func (m *Fs) IsFile(p string) bool`
```go
ok := c.Fs().IsFile("go.mod")
```
#### `func (m *Fs) Exists(p string) bool`
```go
if c.Fs().Exists("go.mod") {}
```
#### `func (m *Fs) List(p string) Result`
```go
r := c.Fs().List(".")
```
#### `func (m *Fs) Stat(p string) Result`
```go
r := c.Fs().Stat("go.mod")
```
#### `func (m *Fs) Open(p string) Result`
```go
r := c.Fs().Open("go.mod")
```
#### `func (m *Fs) Create(p string) Result`
```go
r := c.Fs().Create("notes.txt")
```
#### `func (m *Fs) Append(p string) Result`
```go
r := c.Fs().Append("notes.txt")
```
#### `func (m *Fs) Rename(oldPath, newPath string) Result`
```go
_ = c.Fs().Rename("a.txt", "b.txt")
```
#### `func (m *Fs) Delete(p string) Result`
```go
_ = c.Fs().Delete("tmp.txt")
```
#### `func (m *Fs) DeleteAll(p string) Result`
```go
_ = c.Fs().DeleteAll("tmpdir")
```
#### `func (m *Fs) ReadStream(path string) Result`
```go
r := c.Fs().ReadStream("go.mod")
```
#### `func (m *Fs) WriteStream(path string) Result`
```go
r := c.Fs().WriteStream("go.mod")
```
### Package functions in `fs.go`
### `func DirFS(dir string) fs.FS`
```go
fsys := core.DirFS("/tmp")
```
### `func ReadAll(reader any) Result`
```go
r := core.ReadAll(c.Fs().ReadStream("go.mod").Value)
```
### `func WriteAll(writer any, content string) Result`
```go
r := core.WriteAll(c.Fs().WriteStream("out.txt").Value, "value")
```
### `func CloseStream(v any)`
```go
core.CloseStream(handle)
```
### `type I18n struct`
#### `func (i *I18n) AddLocales(mounts ...*Embed)`
```go
c.I18n().AddLocales(emb)
```
#### `func (i *I18n) Locales() Result`
```go
r := c.I18n().Locales()
```
#### `func (i *I18n) SetTranslator(t Translator)`
```go
c.I18n().SetTranslator(translator)
```
#### `func (i *I18n) Translator() Result`
```go
r := c.I18n().Translator()
```
#### `func (i *I18n) Translate(messageID string, args ...any) Result`
```go
r := c.I18n().Translate("cmd.deploy.description")
```
#### `func (i *I18n) SetLanguage(lang string) Result`
```go
r := c.I18n().SetLanguage("de")
```
#### `func (i *I18n) Language() string`
```go
lang := c.I18n().Language()
```
#### `func (i *I18n) AvailableLanguages() []string`
```go
langs := c.I18n().AvailableLanguages()
```
### `type Process struct`
#### `func (c *Core) Process() *Process`
```go
p := c.Process()
```
#### `func (p *Process) Run(ctx context.Context, command string, args ...string) Result`
```go
r := c.Process().Run(ctx, "git", "status")
```
#### `func (p *Process) RunIn(ctx context.Context, dir, command string, args ...string) Result`
```go
r := c.Process().RunIn(ctx, "/tmp", "go", "test", "./...")
```
#### `func (p *Process) RunWithEnv(ctx context.Context, dir string, env []string, command string, args ...string) Result`
```go
r := c.Process().RunWithEnv(ctx, "/", []string{"CI=true"}, "go", "version")
```
#### `func (p *Process) Start(ctx context.Context, opts Options) Result`
```go
r := c.Process().Start(ctx, core.NewOptions(core.Option{Key: "command", Value: "sleep"}))
```
#### `func (p *Process) Kill(ctx context.Context, opts Options) Result`
```go
r := c.Process().Kill(ctx, core.NewOptions(core.Option{Key: "id", Value: "1234"))
```
#### `func (p *Process) Exists() bool`
```go
if c.Process().Exists() {}
```
## 8) Task/background execution and progress
### `func (c *Core) PerformAsync(action string, opts Options) Result`
```go
r := c.PerformAsync("agent.dispatch", core.NewOptions(core.Option{Key: "id", Value: 1}))
```
### `func (c *Core) Progress(taskID string, progress float64, message string, action string)`
```go
c.Progress(taskID, 0.5, "halfway", "agent.dispatch")
```
### `func (c *Core) RegisterAction(handler func(*Core, Message) Result)`
```go
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
_ = msg
return core.Result{OK: true}
})
```
## 9) Logging and output
### `type Level int`
```go
const (
core.LevelQuiet Level = iota
core.LevelError
core.LevelWarn
core.LevelInfo
core.LevelDebug
)
```
#### `func (l Level) String() string`
```go
s := core.LevelInfo.String()
```
### `type Log struct`
#### `func NewLog(opts LogOptions) *Log`
```go
logger := core.NewLog(core.LogOptions{Level: core.LevelDebug})
```
#### `func (l *Log) SetLevel(level Level)`
```go
logger.SetLevel(core.LevelWarn)
```
#### `func (l *Log) Level() Level`
```go
lvl := logger.Level()
```
#### `func (l *Log) SetOutput(w io.Writer)`
```go
logger.SetOutput(os.Stderr)
```
#### `func (l *Log) SetRedactKeys(keys ...string)`
```go
logger.SetRedactKeys("token", "password")
```
#### `func (l *Log) Debug(msg string, keyvals ...any)`
```go
logger.Debug("booted", "pid", 123)
```
#### `func (l *Log) Info(msg string, keyvals ...any)`
```go
logger.Info("agent started")
```
#### `func (l *Log) Warn(msg string, keyvals ...any)`
```go
logger.Warn("disk nearly full")
```
#### `func (l *Log) Error(msg string, keyvals ...any)`
```go
logger.Error("failed to bind", "err", err)
```
#### `func (l *Log) Security(msg string, keyvals ...any)`
```go
logger.Security("sandbox escape", "attempt", path)
```
### `type ErrorLog struct`
#### `func (el *ErrorLog) Error(err error, op, msg string) Result`
```go
r := c.Log().Error(err, "core.Run", "startup failed")
```
#### `func (el *ErrorLog) Warn(err error, op, msg string) Result`
```go
r := c.Log().Warn(err, "warn", "soft error")
```
#### `func (el *ErrorLog) Must(err error, op, msg string)`
```go
c.Log().Must(err, "core.maybe", "must hold")
```
### `type ErrorPanic struct`
#### `func (h *ErrorPanic) Recover()`
```go
defer c.Error().Recover()
```
#### `func (h *ErrorPanic) SafeGo(fn func())`
```go
c.Error().SafeGo(func() { panic("boom") })
```
#### `func (h *ErrorPanic) Reports(n int) Result`
```go
r := c.Error().Reports(3)
```
### `type LogErr struct`
#### `func NewLogErr(log *Log) *LogErr`
```go
le := core.NewLogErr(core.Default())
```
#### `func (le *LogErr) Log(err error)`
```go
le.Log(err)
```
### `type LogPanic struct`
#### `func NewLogPanic(log *Log) *LogPanic`
```go
lp := core.NewLogPanic(core.Default())
```
#### `func (lp *LogPanic) Recover()`
```go
defer lp.Recover()
```
### Package-level logger helpers
`Default`, `SetDefault`, `SetLevel`, `SetRedactKeys`, `Debug`, `Info`, `Warn`, `Error`, `Security`.
### `func Default() *Log`
```go
l := core.Default()
```
### `func SetDefault(l *Log)`
```go
core.SetDefault(core.NewLog(core.LogOptions{Level: core.LevelDebug}))
```
### `func SetLevel(level Level)`
```go
core.SetLevel(core.LevelInfo)
```
### `func SetRedactKeys(keys ...string)`
```go
core.SetRedactKeys("password")
```
### `func Debug(msg string, keyvals ...any)`
```go
core.Debug("start")
```
### `func Info(msg string, keyvals ...any)`
```go
core.Info("ready")
```
### `func Warn(msg string, keyvals ...any)`
```go
core.Warn("high load")
```
### `func Error(msg string, keyvals ...any)`
```go
core.Error("failure", "err", err)
```
### `func Security(msg string, keyvals ...any)`
```go
core.Security("policy", "event", "denied")
```
### `type LogOptions struct`
`Level`, `Output`, `Rotation`, `RedactKeys`.
### `type RotationLogOptions struct`
`Filename`, `MaxSize`, `MaxAge`, `MaxBackups`, `Compress`.
### `var RotationWriterFactory func(RotationLogOptions) io.WriteCloser`
```go
core.RotationWriterFactory = myFactory
```
### `func Username() string`
```go
u := core.Username()
```
## 10) Error model and diagnostics
### `type Err struct`
`Operation`, `Message`, `Cause`, `Code`.
#### `func (e *Err) Error() string`
```go
_ = err.Error()
```
#### `func (e *Err) Unwrap() error`
```go
_ = errors.Unwrap(err)
```
### `func E(op, msg string, err error) error`
```go
r := core.E("core.Run", "startup failed", err)
```
### `func Wrap(err error, op, msg string) error`
```go
r := core.Wrap(err, "api.Call", "request failed")
```
### `func WrapCode(err error, code, op, msg string) error`
```go
r := core.WrapCode(err, "NOT_AUTHORIZED", "api.Call", "forbidden")
```
### `func NewCode(code, msg string) error`
```go
_ = core.NewCode("VALIDATION", "invalid input")
```
### `func NewError(text string) error`
```go
_ = core.NewError("boom")
```
### `func ErrorJoin(errs ...error) error`
```go
err := core.ErrorJoin(e1, e2, e3)
```
### `func ErrorMessage(err error) string`
```go
msg := core.ErrorMessage(err)
```
### `func ErrorCode(err error) string`
```go
code := core.ErrorCode(err)
```
### `func Operation(err error) string`
```go
op := core.Operation(err)
```
### `func Root(err error) error`
```go
root := core.Root(err)
```
### `func AllOperations(err error) iter.Seq[string]`
```go
for op := range core.AllOperations(err) { fmt.Println(op) }
```
### `func StackTrace(err error) []string`
```go
stack := core.StackTrace(err)
```
### `func FormatStackTrace(err error) string`
```go
fmt.Println(core.FormatStackTrace(err))
```
### `func As(err error, target any) bool`
```go
var ee *core.Err
_ = core.As(err, &ee)
```
### `func Is(err, target error) bool`
```go
_ = core.Is(err, io.EOF)
```
### `type CrashReport struct`
### `type CrashSystem struct`
## 11) Asset packing and embed helpers
### `type AssetGroup struct`
### `type AssetRef struct`
### `type ScannedPackage struct`
### `func AddAsset(group, name, data string)`
```go
core.AddAsset("g", "n", "payload")
```
### `func GetAsset(group, name string) Result`
```go
r := core.GetAsset("g", "n")
```
### `func GetAssetBytes(group, name string) Result`
```go
r := core.GetAssetBytes("g", "n")
```
### `func ScanAssets(filenames []string) Result`
```go
r := core.ScanAssets([]string{"main.go"})
```
### `func GeneratePack(pkg ScannedPackage) Result`
```go
r := core.GeneratePack(scanned)
```
### `func Mount(fsys fs.FS, basedir string) Result`
```go
r := core.Mount(appFS, "assets")
```
### `func MountEmbed(efs embed.FS, basedir string) Result`
```go
r := core.MountEmbed(efs, "assets")
```
### `func Extract(fsys fs.FS, targetDir string, data any, opts ...ExtractOptions) Result`
```go
r := core.Extract(embeds, "/tmp/out", map[string]string{"Name": "demo"})
```
### `type ExtractOptions struct`
`TemplateFilters []string`, `IgnoreFiles map[string]struct{}`, `RenameFiles map[string]string`.
### `type Embed struct`
#### `func (s *Embed) Open(name string) Result`
```go
r := emb.Open("readme.md")
```
#### `func (s *Embed) ReadDir(name string) Result`
```go
r := emb.ReadDir("templates")
```
#### `func (s *Embed) ReadFile(name string) Result`
```go
r := emb.ReadFile("readme.md")
```
#### `func (s *Embed) ReadString(name string) Result`
```go
r := emb.ReadString("readme.md")
```
#### `func (s *Embed) Sub(subDir string) Result`
```go
r := emb.Sub("assets")
```
#### `func (s *Embed) FS() fs.FS`
```go
fsys := emb.FS()
```
#### `func (s *Embed) EmbedFS() embed.FS`
```go
efs := emb.EmbedFS()
```
#### `func (s *Embed) BaseDirectory() string`
```go
base := emb.BaseDirectory()
```
## 12) Configuration and primitives
### `type Option struct`
```go
opt := core.Option{Key: "name", Value: "agent"}
```
### `type ConfigVar[T any]`
#### `func NewConfigVar[T any](val T) ConfigVar[T]`
```go
v := core.NewConfigVar("blue")
```
#### `func (v *ConfigVar[T]) Get() T`
```go
val := v.Get()
```
#### `func (v *ConfigVar[T]) Set(val T)`
```go
v.Set("red")
```
#### `func (v *ConfigVar[T]) IsSet() bool`
```go
if v.IsSet() {}
```
#### `func (v *ConfigVar[T]) Unset()`
```go
v.Unset()
```
### `type ConfigOptions struct`
`Settings map[string]any`, `Features map[string]bool`.
### `type Config struct`
#### `func (e *Config) New() *Config`
```go
cfg := (&core.Config{}).New()
```
#### `func (e *Config) Set(key string, val any)`
```go
cfg.Set("port", 8080)
```
#### `func (e *Config) Get(key string) Result`
```go
r := cfg.Get("port")
```
#### `func (e *Config) String(key string) string`
```go
v := cfg.String("port")
```
#### `func (e *Config) Int(key string) int`
```go
v := cfg.Int("retries")
```
#### `func (e *Config) Bool(key string) bool`
```go
v := cfg.Bool("debug")
```
#### `func (e *Config) Enable(feature string)`
```go
e.Enable("tracing")
```
#### `func (e *Config) Disable(feature string)`
```go
e.Disable("tracing")
```
#### `func (e *Config) Enabled(feature string) bool`
```go
if e.Enabled("tracing") {}
```
#### `func (e *Config) EnabledFeatures() []string`
```go
features := e.EnabledFeatures()
```
### `func ConfigGet[T any](e *Config, key string) T`
```go
limit := core.ConfigGet[int](cfg, "retries")
```
### `type Options struct`
#### `func NewOptions(items ...Option) Options`
```go
opts := core.NewOptions(core.Option{Key: "name", Value: "x"})
```
#### `func (o *Options) Set(key string, value any)`
```go
opts.Set("debug", true)
```
#### `func (o Options) Get(key string) Result`
```go
r := opts.Get("debug")
```
#### `func (o Options) Has(key string) bool`
```go
if opts.Has("debug") {}
```
#### `func (o Options) String(key string) string`
```go
v := opts.String("name")
```
#### `func (o Options) Int(key string) int`
```go
v := opts.Int("port")
```
#### `func (o Options) Bool(key string) bool`
```go
b := opts.Bool("debug")
```
#### `func (o Options) Len() int`
```go
n := opts.Len()
```
#### `func (o Options) Items() []Option`
```go
all := opts.Items()
```
### `type Result struct`
#### `func (r Result) Result(args ...any) Result`
```go
r := core.Result{}.Result(file, err)
```
#### `func (r Result) New(args ...any) Result`
```go
r := core.Result{}.New(file, nil)
```
#### `func (r Result) Get() Result`
```go
v := r.Get()
```
### `func JSONMarshal(v any) Result`
```go
r := core.JSONMarshal(map[string]string{"k": "v"})
```
### `func JSONMarshalString(v any) string`
```go
s := core.JSONMarshalString(map[string]any{"k": "v"})
```
### `func JSONUnmarshal(data []byte, target any) Result`
```go
r := core.JSONUnmarshal([]byte(`{"x":1}`), &cfg)
```
### `func JSONUnmarshalString(s string, target any) Result`
```go
r := core.JSONUnmarshalString(`{"x":1}`, &cfg)
```
## 13) Registry primitive
### `type Registry[T any] struct`
#### `func NewRegistry[T any]() *Registry[T]`
```go
r := core.NewRegistry[*core.Service]()
```
#### `func (r *Registry[T]) Set(name string, item T) Result`
```go
r.Set("process", svc)
```
#### `func (r *Registry[T]) Get(name string) Result`
```go
got := r.Get("process")
```
#### `func (r *Registry[T]) Has(name string) bool`
```go
if r.Has("process") {}
```
#### `func (r *Registry[T]) Names() []string`
```go
for _, n := range r.Names() {}
```
#### `func (r *Registry[T]) List(pattern string) []T`
```go
vals := r.List("process.*")
```
#### `func (r *Registry[T]) Each(fn func(string, T))`
```go
r.Each(func(name string, v *core.Service) {})
```
#### `func (r *Registry[T]) Len() int`
```go
n := r.Len()
```
#### `func (r *Registry[T]) Delete(name string) Result`
```go
_ = r.Delete("legacy")
```
#### `func (r *Registry[T]) Disable(name string) Result`
```go
_ = r.Disable("legacy")
```
#### `func (r *Registry[T]) Enable(name string) Result`
```go
_ = r.Enable("legacy")
```
#### `func (r *Registry[T]) Disabled(name string) bool`
```go
if r.Disabled("legacy") {}
```
#### `func (r *Registry[T]) Lock()`
```go
r.Lock()
```
#### `func (r *Registry[T]) Locked() bool`
```go
locked := r.Locked()
```
#### `func (r *Registry[T]) Seal()`
```go
r.Seal()
```
#### `func (r *Registry[T]) Sealed() bool`
```go
if r.Sealed() {}
```
#### `func (r *Registry[T]) Open()`
```go
r.Open()
```
## 14) Entitlement and security policy hooks
### `type Entitlement struct`
`Allowed`, `Unlimited`, `Limit`, `Used`, `Remaining`, `Reason`.
### `func (e Entitlement) NearLimit(threshold float64) bool`
```go
if e.NearLimit(0.8) {}
```
### `func (e Entitlement) UsagePercent() float64`
```go
pct := e.UsagePercent()
```
### `type EntitlementChecker func(action string, quantity int, ctx context.Context) Entitlement`
### `type UsageRecorder func(action string, quantity int, ctx context.Context)`
#### `func (c *Core) Entitled(action string, quantity ...int) Entitlement`
```go
e := c.Entitled("process.run")
```
#### `func (c *Core) SetEntitlementChecker(checker EntitlementChecker)`
```go
c.SetEntitlementChecker(myChecker)
```
#### `func (c *Core) RecordUsage(action string, quantity ...int)`
```go
c.RecordUsage("process.run")
```
#### `func (c *Core) SetUsageRecorder(recorder UsageRecorder)`
```go
c.SetUsageRecorder(myRecorder)
```
## 15) Generic and helper collections
### `type Array[T comparable]`
#### `func NewArray[T comparable](items ...T) *Array[T]`
```go
arr := core.NewArray("a", "b")
```
#### `func (s *Array[T]) Add(values ...T)`
```go
arr.Add("c")
```
#### `func (s *Array[T]) AddUnique(values ...T)`
```go
arr.AddUnique("a")
```
#### `func (s *Array[T]) Contains(val T) bool`
```go
_ = arr.Contains("a")
```
#### `func (s *Array[T]) Filter(fn func(T) bool) Result`
```go
r := arr.Filter(func(v string) bool { return v != "x" })
```
#### `func (s *Array[T]) Each(fn func(T))`
```go
arr.Each(func(v string) {})
```
#### `func (s *Array[T]) Remove(val T)`
```go
arr.Remove("b")
```
#### `func (s *Array[T]) Deduplicate()`
```go
arr.Deduplicate()
```
#### `func (s *Array[T]) Len() int`
```go
n := arr.Len()
```
#### `func (s *Array[T]) Clear()`
```go
arr.Clear()
```
#### `func (s *Array[T]) AsSlice() []T`
```go
vals := arr.AsSlice()
```
## 16) String and path utility API
### String helpers
- `HasPrefix`, `HasSuffix`, `TrimPrefix`, `TrimSuffix`, `Contains`, `Split`, `SplitN`, `Join`, `Replace`, `Lower`, `Upper`, `Trim`, `RuneCount`, `NewBuilder`, `NewReader`, `Sprint`, `Sprintf`, `Concat`.
```go
core.Join("/", "deploy", "to", "homelab")
core.Concat("cmd.", "deploy", ".description")
```
### Path helpers
- `Path`, `PathBase`, `PathDir`, `PathExt`, `PathIsAbs`, `JoinPath`, `CleanPath`, `PathGlob`.
```go
core.Path("Code", "agent")
core.PathIsAbs("/tmp")
```
#### `func JoinPath(segments ...string) string`
```go
p := core.JoinPath("workspace", "deploy", "main.go")
```
### Generic I/O helpers
- `Arg`, `ArgString`, `ArgInt`, `ArgBool`, `ParseFlag`, `FilterArgs`, `IsFlag`, `ID`, `ValidateName`, `SanitisePath`.
```go
id := core.ID()
name := core.ValidateName("agent").Value
```
### Package-level functions in this section
#### `func Print(w io.Writer, format string, args ...any)`
```go
core.Print(os.Stderr, "hello %s", "world")
```
#### `func Println(args ...any)`
```go
core.Println("ready")
```
#### `func Arg(index int, args ...any) Result`
```go
r := core.Arg(0, "x", 1)
```
#### `func ArgString(index int, args ...any) string`
```go
v := core.ArgString(0, "x", 1)
```
#### `func ArgInt(index int, args ...any) int`
```go
v := core.ArgInt(1, "x", 42)
```
#### `func ArgBool(index int, args ...any) bool`
```go
v := core.ArgBool(2, true)
```
#### `func IsFlag(arg string) bool`
```go
ok := core.IsFlag("--debug")
```
#### `func ParseFlag(arg string) (string, string, bool)`
```go
key, val, ok := core.ParseFlag("--name=agent")
```
#### `func FilterArgs(args []string) []string`
```go
clean := core.FilterArgs(os.Args[1:])
```
#### `func ID() string`
```go
id := core.ID()
```
#### `func ValidateName(name string) Result`
```go
r := core.ValidateName("deploy")
```
#### `func SanitisePath(path string) string`
```go
safe := core.SanitisePath("../../etc")
```
#### `func DirFS(dir string) fs.FS`
```go
root := core.DirFS("/tmp")
```
## 17) System and environment helpers
### `func Env(key string) string`
```go
home := core.Env("DIR_HOME")
```
### `func EnvKeys() []string`
```go
keys := core.EnvKeys()
```
### `func Username() string`
```go
who := core.Username()
```
## 18) Remaining interfaces and types
### `type ErrorSink interface`
`Error(msg string, keyvals ...any)` and `Warn(msg string, keyvals ...any)`.
### `type Stream interface`
`Send`, `Receive`, `Close` as above.
### `type Translator interface`
`Translate`, `SetLanguage`, `Language`, `AvailableLanguages`.
### `type LocaleProvider interface`
`Locales() *Embed`.
### `type Runtime helpers`
- `type Ipc` (named fields, no exported methods)
- `type Lock struct{ Name string; Mutex *sync.RWMutex }`
- `type SysInfo struct{ values map[string]string }`
### `type Ipc struct`
```go
ipc := c.IPC()
```
### `type Lock struct`
```go
guard := c.Lock("core-bootstrap")
guard.Mutex.Lock()
defer guard.Mutex.Unlock()
```
### `type SysInfo struct`
```go
// SysInfo values are accessed through Env()/EnvKeys(); direct type construction is not required.
home := core.Env("DIR_HOME")
keys := core.EnvKeys()
```
## 19) Legacy behavior notes
- `Service` lifecycle callbacks are the DTO fields `OnStart` and `OnStop`.
- `Startable`/`Stoppable` are the interface contracts and map to `OnStartup(context.Context)` / `OnShutdown(context.Context)`.
- Registry iteration (`Names`, `List`, `Each`, `Services`, `Startables`, `Stoppables`) is insertion-order based via `Registry.order`.