Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
c45b228
feat: restore functional option pattern for New()
Snider Mar 24, 2026
9f6caa3
Merge pull request '[agent/codex] Review PR #28. Read CLAUDE.md first…
Mar 24, 2026
2d01798
fix: address Codex review findings on PR #28
Snider Mar 24, 2026
9b5f6df
fix: prevent double IPC registration + empty service placeholder
Snider Mar 24, 2026
64e6a26
fix: move HandleIPCEvents discovery to New() post-construction
Snider Mar 24, 2026
74f78c8
feat: RegisterService with instance storage + interface discovery
Snider Mar 24, 2026
a49bc46
feat: Options struct + Result methods + WithOption convenience
Snider Mar 24, 2026
2a81b4f
feat: App struct with New(Options) + Find() as method
Snider Mar 24, 2026
85faedf
fix: update Cli doc comment + tests for new Options contract
Snider Mar 24, 2026
f69be96
feat: Cli.New(c) constructor — Core uses it during construction
Snider Mar 24, 2026
198ab83
wip: checkpoint before v0.3.3 parity rewrite
Snider Mar 24, 2026
177f73c
feat: WithService with v0.3.3 name discovery + IPC handler auto-regis…
Snider Mar 24, 2026
b03c1a3
feat: WithService with v0.3.3 name discovery + IPC handler auto-regis…
Snider Mar 24, 2026
001e90e
feat: WithName for explicit service naming
Snider Mar 24, 2026
d1579f6
test: lifecycle + HandleIPCEvents end-to-end via WithService
Snider Mar 24, 2026
05d0a64
fix: WithServiceLock enables, New() applies after all opts — v0.3.3 p…
Snider Mar 24, 2026
2303c27
feat: MustServiceFor[T] + fix service names test for auto-registered cli
Snider Mar 24, 2026
ae48254
wip: v0.3.3 parity — Tasks 1-7 complete, data/embed tests need fixing
Snider Mar 24, 2026
94e1f40
fix: Result.New handles (value, error) pairs correctly + embed test f…
Snider Mar 24, 2026
9c5cc6e
feat: New() constructors for Config, Fs + simplify contract.go init
Snider Mar 24, 2026
7f4c434
fix: Service() returns instance, ServiceFor uses type assertion directly
Snider Mar 24, 2026
7608808
feat: Core.Run() — ServiceStartup → Cli → ServiceShutdown lifecycle
Snider Mar 24, 2026
af1cee2
feat: Core.Run() handles os.Exit on error
Snider Mar 24, 2026
5362a99
feat: New() returns *Core directly — no Result wrapper needed
Snider Mar 24, 2026
f72c578
Merge pull request 'feat: restore functional option pattern for New()…
Mar 24, 2026
95076be
fix: shutdown context, double IPC registration
Snider Mar 24, 2026
5855a61
Merge pull request 'fix: shutdown context + double IPC registration' …
Mar 24, 2026
d982193
test: add _Bad/_Ugly tests + fix per-Core lock isolation
Snider Mar 24, 2026
f6ed40d
Merge pull request 'test: _Bad/_Ugly tests + per-Core lock isolation'…
Mar 24, 2026
e7c3b3a
feat: add llm.txt — agent entry point for CoreGO framework
Snider Mar 25, 2026
1455764
feat: add docs/RFC.md — CoreGO API contract specification
Snider Mar 25, 2026
f658840
feat(rfc): add Design Philosophy + Known Issues to API spec
Snider Mar 25, 2026
ec17e3d
feat(rfc): Section 17 — c.Process() primitive spec
Snider Mar 25, 2026
76714fa
feat(rfc): Section 18 — Action and Task execution primitives
Snider Mar 25, 2026
8f7a122
feat(rfc): Known Issues 9-16 — recovered ADHD brain dumps
Snider Mar 25, 2026
773e9ee
feat(rfc): Issue 9 — three-layer CLI architecture (Cli/cli/go-process)
Snider Mar 25, 2026
7a9f9df
feat(rfc): Section 19 — c.API() remote stream primitive
Snider Mar 25, 2026
68b7530
feat(rfc): resolve Issues 1+12 — naming convention + IPC as registry …
Snider Mar 25, 2026
5211d97
feat(rfc): resolve Issue 16 — task.go splits into ipc.go + action.go
Snider Mar 25, 2026
79fd8c4
feat(rfc): Section 20 — c.Registry() universal collection primitive
Snider Mar 25, 2026
b130309
feat(rfc): resolve Issues 10+11 — Array[T] and ConfigVar[T] as guardr…
Snider Mar 25, 2026
59dcbc2
feat(rfc): resolve ALL 16 known issues
Snider Mar 25, 2026
881c8f2
feat(rfc): versioning model + v0.8.0 requirements checklist
Snider Mar 25, 2026
42fc6fa
feat(rfc): Pass Two — 8 architectural findings
Snider Mar 25, 2026
ecd27e3
feat(rfc): Pass Three — 8 spec contradictions found
Snider Mar 25, 2026
6709b0b
feat(rfc): Pass Four — 8 concurrency and performance findings
Snider Mar 25, 2026
2167f0c
feat(rfc): Pass Five — 8 consumer experience findings
Snider Mar 25, 2026
f23e4d2
feat(rfc): Pass Six — cascade analysis reveals synchronous pipeline b…
Snider Mar 25, 2026
630f1d5
feat(rfc): Pass Seven — failure modes, no recovery on most paths
Snider Mar 25, 2026
c847b5d
feat(rfc): Pass Eight — type safety analysis, 50 hidden panic sites
Snider Mar 25, 2026
a06af7b
feat(rfc): Pass Nine — what's missing, what shouldn't be there
Snider Mar 25, 2026
20f3ee3
feat(rfc): Pass Ten — the spec auditing itself, 80 findings total
Snider Mar 25, 2026
caa1dea
feat(rfc): Pass Eleven — security model, God Mode, sandbox bypass
Snider Mar 25, 2026
1ef8846
feat(rfc): Pass Twelve — migration risk across 44 repos
Snider Mar 25, 2026
ef548d0
feat(rfc): Pass Thirteen — hidden assumptions, final review
Snider Mar 25, 2026
21c1a3e
feat(rfc): Pass 4 Revisited — 4 deeper concurrency findings
Snider Mar 25, 2026
93c21cf
feat(rfc): Synthesis — 108 findings reduce to 5 root causes
Snider Mar 25, 2026
c640385
feat(rfc): Root Cause 2 resolved — Entitlements not CoreView
Snider Mar 25, 2026
f7e91f0
feat(rfc): cross-reference existing RFCs to open findings
Snider Mar 25, 2026
9cd83da
feat: 6 implementation plans for v0.8.0
Snider Mar 25, 2026
0704a7a
feat: session continuity plans — RFC.plan.md + plan.1 + plan.2
Snider Mar 25, 2026
2dff772
feat: implement RFC plans 1-5 — Registry[T], Action/Task, Process, pr…
Snider Mar 25, 2026
c5c16a7
feat(rfc): Section 21 — Entitlement permission primitive design
Snider Mar 25, 2026
028ec84
fix: remove type Task any — untyped IPC replaced by named Actions
Snider Mar 25, 2026
1d174a9
docs(rfc): update RFC.md — consumer RFCs, versioning, v0.8.0 status
Snider Mar 25, 2026
14cd9c6
fix(rfc): remove all v0.9.0 deferrals — everything is v0.8.0
Snider Mar 25, 2026
ec423cf
feat: implement Section 21 — Entitlement permission primitive
Snider Mar 25, 2026
693dde0
feat: implement Section 19 — API remote streams primitive
Snider Mar 25, 2026
77563be
docs(rfc): all 21 sections implemented — v0.8.0 requirements met
Snider Mar 25, 2026
fe46e33
refactor(rfc): trim RFC.md from 4193 to 1935 lines (54% reduction)
Snider Mar 25, 2026
390b392
chore: remove completed implementation plans — RFC.md is the single s…
Snider Mar 25, 2026
a26d943
fix(rfc): update stale specs to match v0.8.0 implementation
Snider Mar 25, 2026
b0e54a8
fix(rfc): review pass — update stale specs found at 60%+ context
Snider Mar 25, 2026
7069def
fix(rfc): rewrite Section 17 — match implementation, remove consumer …
Snider Mar 25, 2026
377afa0
fix(rfc): pass 3 — rewrite Sections 18, 19, 20 to match implementation
Snider Mar 25, 2026
d33765c
fix(rfc): pass 4 — RegistryOf not Registry, implementation pending→done
Snider Mar 25, 2026
da2e547
fix(rfc): pass 5 — PERFORM→Actions, Entitlement→Entitled, RunE, Task …
Snider Mar 25, 2026
7b68ead
fix(rfc): pass 6 — root cause table done, method names, test count
Snider Mar 25, 2026
340b817
fix(rfc): pass 7 — 4 items: insertion order, RunE, Plan 6 ref, Design…
Snider Mar 25, 2026
c91f96d
fix(rfc): pass 8 — cross-ref table: open→resolved, remove phantom c.S…
Snider Mar 25, 2026
cd45279
fix: rewrite CLAUDE.md and llm.txt — badly stale, wrong API documented
Snider Mar 25, 2026
ba77e02
fix: rewrite README.md — stale quick example used deleted API
Snider Mar 25, 2026
1f0c618
fix: rewrite 4 stale docs — messaging, primitives, index, getting-sta…
Snider Mar 25, 2026
12adc97
refactor(rfc): remove retrospective — RFC is a contract, not a journal
Snider Mar 25, 2026
8626710
feat: add JSON primitives + fix api.go placeholder
Snider Mar 25, 2026
0911d5a
fix: add usage-example comments to all 37 exported functions (AX Prin…
Snider Mar 25, 2026
ecf6485
feat: add 22 Example tests — documentation seeds + coverage + godoc
Snider Mar 25, 2026
8b905f3
feat: per-file example tests — action, registry, fs, api, string, pat…
Snider Mar 25, 2026
a2fa841
fix: CleanPath example + remove duplicate tests
Snider Mar 25, 2026
e65cbde
feat: complete per-file examples — 54 examples across 17 files
Snider Mar 25, 2026
48a9bd6
fix: dogfood Core primitives in tests — eliminate errors import
Snider Mar 25, 2026
9cba5a8
fix: dogfood core.Path() — eliminate path/filepath from all tests
Snider Mar 25, 2026
1cafdff
feat: zero os/errors/filepath/json/exec/runtime in tests — full dogfood
Snider Mar 25, 2026
921b4f2
feat: eliminate io import — add ReadAll, WriteAll, CloseStream primit…
Snider Mar 25, 2026
5be20af
feat: eliminate fmt, string concat — add core.Println, use Concat/Pat…
Snider Mar 25, 2026
f83ecc7
merge: resolve main divergence — dev (v0.8.0) takes precedence
Snider Mar 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 47 additions & 40 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ Guidance for Claude Code and Codex when working with this repository.

## Module

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

Source files live at the module root (not `pkg/core/`). Tests live in `tests/`.
Source files and tests live at the module root. No `pkg/` nesting.

## Build & Test

```bash
go test ./tests/... # run all tests
go build . # verify compilation
GOWORK=off go test ./tests/ # test without workspace
go test ./... -count=1 # run all tests (483 tests, 84.7% coverage)
go build ./... # verify compilation
```

Or via the Core CLI:
Expand All @@ -25,55 +24,61 @@ core go qa # fmt + vet + lint + test

## API Shape

CoreGO uses the DTO/Options/Result pattern, not functional options:

```go
c := core.New(core.Options{
{Key: "name", Value: "myapp"},
})

c.Service("cache", core.Service{
OnStart: func() core.Result { return core.Result{OK: true} },
OnStop: func() core.Result { return core.Result{OK: true} },
})

c.Command("deploy/to/homelab", core.Command{
Action: func(opts core.Options) core.Result {
return core.Result{Value: "deployed", OK: true}
},
})

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

**Do not use:** `WithService`, `WithName`, `WithApp`, `WithServiceLock`, `Must*`, `ServiceFor[T]` — these no longer exist.
Service factory:

```go
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.Data()` | `*Data` | Embedded filesystem mounts |
| `c.Drive()` | `*Drive` | Named transport handles |
| `c.Fs()` | `*Fs` | Local filesystem I/O |
| `c.Config()` | `*Config` | Runtime settings |
| `c.Cli()` | `*Cli` | CLI surface |
| `c.Command("path")` | `Result` | Command tree |
| `c.Service("name")` | `Result` | Service registry |
| `c.Lock("name")` | `*Lock` | Named mutexes |
| `c.IPC()` | `*Ipc` | Message bus |
| `c.I18n()` | `*I18n` | Locale + translation |
| `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 |
| `c.ACTION(msg)` | Broadcast to all handlers (panic recovery per handler) |
| `c.QUERY(q)` | First responder wins |
| `c.QUERYALL(q)` | Collect all responses |
| `c.PERFORM(task)` | First executor wins |
| `c.PerformAsync(task)` | Background goroutine |
| `c.PerformAsync(action, opts)` | Background goroutine with progress |

## Lifecycle

```go
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

Expand All @@ -83,13 +88,15 @@ Use `core.E()` for structured errors:
return core.E("service.Method", "what failed", underlyingErr)
```

## Test Naming
**Never** use `fmt.Errorf`, `errors.New`, `os/exec`, or `unsafe.Pointer` on Core types.

## Test Naming (AX-7)

`_Good` (happy path), `_Bad` (expected errors), `_Ugly` (panics/edge cases).
`TestFile_Function_{Good,Bad,Ugly}` — 100% compliance.

## Docs

Full documentation in `docs/`. Start with `docs/getting-started.md`.
Full API contract: `docs/RFC.md` (1476 lines, 21 sections).

## Go Workspace

Expand Down
117 changes: 20 additions & 97 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# CoreGO

Dependency injection, service lifecycle, command routing, and message-passing for Go.

Import path:
Dependency injection, service lifecycle, permission, and message-passing for Go.

```go
import "dappco.re/go/core"
Expand All @@ -14,75 +12,24 @@ CoreGO is the foundation layer for the Core ecosystem. It gives you:
- one input shape: `Options`
- one output shape: `Result`
- one command tree: `Command`
- one message bus: `ACTION`, `QUERY`, `PERFORM`

## Why It Exists

Most non-trivial Go systems end up needing the same small set of infrastructure:

- a place to keep runtime state and shared subsystems
- a predictable way to start and stop managed components
- a clean command surface for CLI-style workflows
- decoupled communication between components without tight imports

CoreGO keeps those pieces small and explicit.
- one message bus: `ACTION`, `QUERY` + named `Action` callables
- one permission gate: `Entitled`
- one collection primitive: `Registry[T]`

## Quick Example

```go
package main

import (
"context"
"fmt"

"dappco.re/go/core"
)

type flushCacheTask struct {
Name string
}
import "dappco.re/go/core"

func main() {
c := core.New(core.Options{
{Key: "name", Value: "agent-workbench"},
})

c.Service("cache", core.Service{
OnStart: func() core.Result {
core.Info("cache started", "app", c.App().Name)
return core.Result{OK: true}
},
OnStop: func() core.Result {
core.Info("cache stopped", "app", c.App().Name)
return core.Result{OK: true}
},
})

c.RegisterTask(func(_ *core.Core, task core.Task) core.Result {
switch t := task.(type) {
case flushCacheTask:
return core.Result{Value: "cache flushed for " + t.Name, OK: true}
}
return core.Result{}
})

c.Command("cache/flush", core.Command{
Action: func(opts core.Options) core.Result {
return c.PERFORM(flushCacheTask{
Name: opts.String("name"),
})
},
})

if !c.ServiceStartup(context.Background(), nil).OK {
panic("startup failed")
}

r := c.Cli().Run("cache", "flush", "--name=session-store")
fmt.Println(r.Value)

_ = c.ServiceShutdown(context.Background())
c := core.New(
core.WithOption("name", "agent-workbench"),
core.WithService(cache.Register),
core.WithServiceLock(),
)
c.Run()
}
```

Expand All @@ -93,22 +40,16 @@ func main() {
| `Core` | Central container and access point |
| `Service` | Managed lifecycle component |
| `Command` | Path-based executable operation |
| `Cli` | CLI surface over the command tree |
| `Action` | Named callable with panic recovery + entitlement |
| `Task` | Composed sequence of Actions |
| `Registry[T]` | Thread-safe named collection |
| `Process` | Managed execution (Action sugar) |
| `API` | Remote streams (protocol handlers) |
| `Entitlement` | Permission check result |
| `Data` | Embedded filesystem mounts |
| `Drive` | Named transport handles |
| `Fs` | Local filesystem operations |
| `Fs` | Local filesystem (sandboxable) |
| `Config` | Runtime settings and feature flags |
| `I18n` | Locale collection and translation delegation |
| `E`, `Wrap`, `ErrorLog`, `ErrorPanic` | Structured failures and panic recovery |

## AX-Friendly Model

CoreGO follows the same design direction as the AX spec:

- predictable names over compressed names
- paths as documentation, such as `deploy/to/homelab`
- one repeated vocabulary across the framework
- examples that show how to call real APIs

## Install

Expand All @@ -121,30 +62,12 @@ Requires Go 1.26 or later.
## Test

```bash
core go test
```

Or with the standard toolchain:

```bash
go test ./...
go test ./... # 483 tests, 84.7% coverage
```

## Docs

The full documentation set lives in `docs/`.

| Path | Covers |
|------|--------|
| `docs/getting-started.md` | First runnable CoreGO app |
| `docs/primitives.md` | `Options`, `Result`, `Service`, `Message`, `Query`, `Task` |
| `docs/services.md` | Service registry, runtime helpers, service locks |
| `docs/commands.md` | Path-based commands and CLI execution |
| `docs/messaging.md` | `ACTION`, `QUERY`, `QUERYALL`, `PERFORM`, `PerformAsync` |
| `docs/lifecycle.md` | Startup, shutdown, context, and task draining |
| `docs/subsystems.md` | `App`, `Data`, `Drive`, `Fs`, `I18n`, `Cli` |
| `docs/errors.md` | Structured errors, logging helpers, panic recovery |
| `docs/testing.md` | Test naming and framework testing patterns |
The authoritative API contract is `docs/RFC.md` (21 sections).

## License

Expand Down
Loading