Plan 1: Critical bug fixes (v0.7.1, zero breakage) - ACTION chain, panic recovery, defer shutdown, stale code removal Plan 2: Registry[T] primitive (Section 20) - Foundation brick, migration of 5 internal registries Plan 3: Action/Task system (Section 18) - Named callables, task composition, cascade fix Plan 4: c.Process() primitive (Section 17) - go-process v0.7.0, proc.go migration, atomic writes Plan 5: Missing primitives + AX-7 - core.ID(), ValidateName, WriteAtomic, RunE(), test coverage Plan 6: Ecosystem sweep (Phase 3) - 44 repos in 5 batches, Codex dispatch with RFC as spec Each plan lists: files to change, code examples, what it resolves, dependencies on other plans, and migration strategy. Co-Authored-By: Virgil <virgil@lethean.io>
2.4 KiB
2.4 KiB
Implementation Plan 3 — Action/Task System (Section 18)
Depends on: Plan 2 (Registry). The execution primitive.
Phase A: Action Registry
New file: action.go (renamed from task.go)
type ActionDef struct {
Name string
Handler ActionHandler
Description string
Schema Options // expected input keys
enabled bool // for Disable()
}
type ActionHandler func(context.Context, Options) Result
Core accessor:
// Dual-purpose (like Service):
c.Action("process.run", handler) // register
c.Action("process.run").Run(ctx, opts) // invoke
c.Action("process.run").Exists() // check
c.Action("process.run").Def() // metadata
Internally uses Registry[*ActionDef].
Phase B: Move Registration to IPC
Move from task.go:
RegisterAction→ipc.go(registers inRegistry[ActionHandler])RegisterActions→ipc.goRegisterTask→ipc.go
Keep in action.go:
Perform→ becomesc.Action("name").Run()PerformAsync→ becomesc.Action("name").RunAsync()Progress→ stays
Phase C: Panic Recovery on All Actions
Every Action.Run() wraps in recover:
func (a *ActionDef) Run(ctx context.Context, opts Options) (result Result) {
defer func() {
if r := recover(); r != nil {
result = Result{E("action.Run", Sprint("panic: ", r), nil), false}
}
}()
return a.Handler(ctx, opts)
}
Phase D: Task Composition (v0.8.0 stretch)
type TaskDef struct {
Name string
Steps []Step
}
type Step struct {
Action string
With Options
Async bool // run in background
Input string // "previous" = output of last step
}
c.Task("name", def) registers. c.Task("name").Run(ctx) executes steps in order.
Resolves
I16 (task.go concerns), P6-1 (cascade → Task pipeline), P6-2 (O(N×M) → direct dispatch), P7-3 (panic recovery), P7-8 (circuit breaker via Disable), P10-2 (PERFORM not ACTION for request/response).
Migration in core/agent
After Actions exist, refactor handlers.go:
// Current: nested c.ACTION() cascade
// Target:
c.Task("agent.completion", TaskDef{
Steps: []Step{
{Action: "agentic.qa"},
{Action: "agentic.auto-pr"},
{Action: "agentic.verify"},
{Action: "agentic.ingest", Async: true},
{Action: "agentic.poke", Async: true},
},
})