go/CLAUDE.md
Snider cd452791e5 fix: rewrite CLAUDE.md and llm.txt — badly stale, wrong API documented
CLAUDE.md was telling agents NOT to use WithService (the actual API).
Tests path was wrong (tests/ vs root *_test.go). core.New() example
showed deleted DTO pattern. PERFORM listed as current. Missing 6
subsystem accessors.

llm.txt had pkg/core/ path (doesn't exist), PERFORM reference,
missing 8 key types.

Both now match v0.8.0 implementation.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 17:05:07 +00:00

2.8 KiB

CLAUDE.md

Guidance for Claude Code and Codex when working with this repository.

Module

dappco.re/go/core — dependency injection, service lifecycle, permission, and message-passing for Go.

Source files and tests live at the module root. No pkg/ nesting.

Build & Test

go test ./... -count=1       # run all tests (483 tests, 84.7% coverage)
go build ./...               # verify compilation

Or via the Core CLI:

core go test
core go qa                   # fmt + vet + lint + test

API Shape

c := core.New(
    core.WithOption("name", "myapp"),
    core.WithService(mypackage.Register),
    core.WithServiceLock(),
)
c.Run()    // or: if err := c.RunE(); err != nil { ... }

Service factory:

func Register(c *core.Core) core.Result {
    svc := &MyService{ServiceRuntime: core.NewServiceRuntime(c, MyOpts{})}
    return core.Result{Value: svc, OK: true}
}

Subsystems

Accessor Returns Purpose
c.Options() *Options Input configuration
c.App() *App Application identity
c.Config() *Config Runtime settings, feature flags
c.Data() *Data Embedded assets (Registry[*Embed])
c.Drive() *Drive Transport handles (Registry[*DriveHandle])
c.Fs() *Fs Filesystem I/O (sandboxable)
c.Cli() *Cli CLI command framework
c.IPC() *Ipc Message bus internals
c.Process() *Process Managed execution (Action sugar)
c.API() *API Remote streams (protocol handlers)
c.Action(name) *Action Named callable (register/invoke)
c.Task(name) *Task Composed Action sequence
c.Entitled(name) Entitlement Permission check
c.RegistryOf(n) *Registry Cross-cutting queries
c.I18n() *I18n Internationalisation

Messaging

Method Pattern
c.ACTION(msg) Broadcast to all handlers (panic recovery per handler)
c.QUERY(q) First responder wins
c.QUERYALL(q) Collect all responses
c.PerformAsync(action, opts) Background goroutine with progress

Lifecycle

type Startable interface { OnStartup(ctx context.Context) Result }
type Stoppable interface { OnShutdown(ctx context.Context) Result }

RunE() always calls defer ServiceShutdown — even on startup failure or panic.

Error Handling

Use core.E() for structured errors:

return core.E("service.Method", "what failed", underlyingErr)

Never use fmt.Errorf, errors.New, os/exec, or unsafe.Pointer on Core types.

Test Naming (AX-7)

TestFile_Function_{Good,Bad,Ugly} — 100% compliance.

Docs

Full API contract: docs/RFC.md (1476 lines, 21 sections).

Go Workspace

Part of ~/Code/go.work. Use GOWORK=off to test in isolation.