fix(ax): align runtime names with AX principles

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-03-30 20:53:36 +00:00
parent f32edaa17e
commit f9eca5e395
14 changed files with 105 additions and 105 deletions

View file

@ -20,7 +20,7 @@ import (
// AgentOptions configures the agentic service.
//
// opts := agentic.AgentOptions{}
// options := agentic.AgentOptions{}
type AgentOptions struct{}
// PrepSubsystem provides agentic MCP tools for workspace orchestration.
@ -49,8 +49,8 @@ var _ coremcp.Subsystem = (*PrepSubsystem)(nil)
// NewPrep creates an agentic subsystem.
//
// sub := agentic.NewPrep()
// sub.SetCompletionNotifier(monitor)
// subsystem := agentic.NewPrep()
// subsystem.SetCompletionNotifier(monitor)
func NewPrep() *PrepSubsystem {
home := HomeDir()
@ -217,8 +217,8 @@ func (s *PrepSubsystem) OnStartup(ctx context.Context) core.Result {
// OnShutdown implements core.Stoppable and freezes the queue.
//
// prep := agentic.NewPrep()
// _ = prep.OnShutdown(context.Background())
// subsystem := agentic.NewPrep()
// _ = subsystem.OnShutdown(context.Background())
func (s *PrepSubsystem) OnShutdown(ctx context.Context) core.Result {
s.frozen = true
return core.Result{OK: true}
@ -271,15 +271,15 @@ func envOr(key, fallback string) string {
// Name identifies the MCP subsystem.
//
// prep := agentic.NewPrep()
// name := prep.Name()
// subsystem := agentic.NewPrep()
// name := subsystem.Name()
// _ = name // "agentic"
func (s *PrepSubsystem) Name() string { return "agentic" }
// RegisterTools publishes the agentic MCP tools on the server.
//
// prep := agentic.NewPrep()
// prep.RegisterTools(server)
// subsystem := agentic.NewPrep()
// subsystem.RegisterTools(server)
func (s *PrepSubsystem) RegisterTools(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{
Name: "agentic_prep_workspace",
@ -309,8 +309,8 @@ func (s *PrepSubsystem) RegisterTools(server *mcp.Server) {
// Shutdown satisfies mcp.SubsystemWithShutdown for clean server teardown.
//
// prep := agentic.NewPrep()
// _ = prep.Shutdown(context.Background())
// subsystem := agentic.NewPrep()
// _ = subsystem.Shutdown(context.Background())
func (s *PrepSubsystem) Shutdown(_ context.Context) error { return nil }
// --- Input/Output types ---

View file

@ -12,7 +12,7 @@ import (
// DispatchConfig controls agent dispatch behaviour.
//
// cfg := agentic.DispatchConfig{DefaultAgent: "claude", DefaultTemplate: "coding"}
// config := agentic.DispatchConfig{DefaultAgent: "claude", DefaultTemplate: "coding"}
type DispatchConfig struct {
DefaultAgent string `yaml:"default_agent"`
DefaultTemplate string `yaml:"default_template"`
@ -71,7 +71,7 @@ func (c *ConcurrencyLimit) UnmarshalYAML(value *yaml.Node) error {
// AgentsConfig is the root of config/agents.yaml.
//
// cfg := agentic.AgentsConfig{Version: 1, Dispatch: agentic.DispatchConfig{DefaultAgent: "claude"}}
// config := agentic.AgentsConfig{Version: 1, Dispatch: agentic.DispatchConfig{DefaultAgent: "claude"}}
type AgentsConfig struct {
Version int `yaml:"version"`
Dispatch DispatchConfig `yaml:"dispatch"`
@ -91,11 +91,11 @@ func (s *PrepSubsystem) loadAgentsConfig() *AgentsConfig {
if !r.OK {
continue
}
var cfg AgentsConfig
if err := yaml.Unmarshal([]byte(r.Value.(string)), &cfg); err != nil {
var config AgentsConfig
if err := yaml.Unmarshal([]byte(r.Value.(string)), &config); err != nil {
continue
}
return &cfg
return &config
}
return &AgentsConfig{
@ -119,8 +119,8 @@ func (s *PrepSubsystem) delayForAgent(agent string) time.Duration {
rates, _ = s.Core().Config().Get("agents.rates").Value.(map[string]RateConfig)
}
if rates == nil {
cfg := s.loadAgentsConfig()
rates = cfg.Rates
config := s.loadAgentsConfig()
rates = config.Rates
}
base := baseAgent(agent)
rate, ok := rates[base]
@ -261,8 +261,8 @@ func (s *PrepSubsystem) canDispatchAgent(agent string) bool {
}
}
if concurrency == nil {
cfg := s.loadAgentsConfig()
concurrency = cfg.Concurrency
config := s.loadAgentsConfig()
concurrency = config.Concurrency
}
base := baseAgent(agent)

View file

@ -15,14 +15,14 @@ import (
// core.WithService(agentic.Register),
// )
func Register(c *core.Core) core.Result {
prep := NewPrep()
prep.ServiceRuntime = core.NewServiceRuntime(c, AgentOptions{})
subsystem := NewPrep()
subsystem.ServiceRuntime = core.NewServiceRuntime(c, AgentOptions{})
// Load agents config once into Core shared config
cfg := prep.loadAgentsConfig()
c.Config().Set("agents.concurrency", cfg.Concurrency)
c.Config().Set("agents.rates", cfg.Rates)
c.Config().Set("agents.dispatch", cfg.Dispatch)
config := subsystem.loadAgentsConfig()
c.Config().Set("agents.concurrency", config.Concurrency)
c.Config().Set("agents.rates", config.Rates)
c.Config().Set("agents.dispatch", config.Dispatch)
// Pipeline feature flags — all enabled by default.
// Disable with c.Config().Disable("auto-qa") etc.
@ -39,5 +39,5 @@ func Register(c *core.Core) core.Result {
// IPC handlers auto-discovered via HandleIPCEvents interface on PrepSubsystem.
// No manual RegisterHandlers call needed — WithService wires it.
return core.Result{Value: prep, OK: true}
return core.Result{Value: subsystem, OK: true}
}

View file

@ -4,8 +4,8 @@ package agentic
// StartRunner preserves the legacy PrepSubsystem call after queue ownership moved to pkg/runner.Service.
//
// prep := agentic.NewPrep()
// prep.StartRunner()
// subsystem := agentic.NewPrep()
// subsystem.StartRunner()
//
// The runner service registers as core.WithService(runner.Register) and
// manages its own background loop, frozen state, and concurrency checks.
@ -13,8 +13,8 @@ func (s *PrepSubsystem) StartRunner() {}
// Poke preserves the legacy queue signal after queue ownership moved to pkg/runner.Service.
//
// prep := agentic.NewPrep()
// prep.Poke()
// subsystem := agentic.NewPrep()
// subsystem.Poke()
//
// Runner catches AgentCompleted via HandleIPCEvents and pokes itself.
func (s *PrepSubsystem) Poke() {}

View file

@ -9,9 +9,9 @@ import (
// Register exposes the direct OpenBrain subsystem through `core.WithService`.
//
// c := core.New(core.WithService(brain.Register))
// sub, _ := core.ServiceFor[*brain.DirectSubsystem](c, "brain")
// core.Println(sub.Name()) // "brain"
// subsystem, _ := core.ServiceFor[*brain.DirectSubsystem](c, "brain")
// core.Println(subsystem.Name()) // "brain"
func Register(c *core.Core) core.Result {
brn := NewDirect()
return core.Result{Value: brn, OK: true}
subsystem := NewDirect()
return core.Result{Value: subsystem, OK: true}
}

View file

@ -2,8 +2,8 @@
// Package monitor keeps workspace state and inbox status visible to MCP clients.
//
// mon := monitor.New(monitor.Options{Interval: 30 * time.Second})
// mon.RegisterTools(server)
// service := monitor.New(monitor.Options{Interval: 30 * time.Second})
// service.RegisterTools(server)
package monitor
import (
@ -58,8 +58,8 @@ func resultString(r core.Result) (string, bool) {
return value, true
}
// mon := monitor.New()
// mon.Start(context.Background())
// service := monitor.New(Options{})
// service.Start(context.Background())
type Subsystem struct {
*core.ServiceRuntime[Options]
server *mcp.Server
@ -114,17 +114,17 @@ func (m *Subsystem) HandleIPCEvents(_ *core.Core, msg core.Message) core.Result
return core.Result{OK: true}
}
// opts := monitor.Options{Interval: 30 * time.Second}
// mon := monitor.New(opts)
// options := monitor.Options{Interval: 30 * time.Second}
// service := monitor.New(options)
type Options struct {
Interval time.Duration
}
// mon := monitor.New(monitor.Options{Interval: 30 * time.Second})
func New(opts ...Options) *Subsystem {
// service := monitor.New(monitor.Options{Interval: 30 * time.Second})
func New(options ...Options) *Subsystem {
interval := 2 * time.Minute
if len(opts) > 0 && opts[0].Interval > 0 {
interval = opts[0].Interval
if len(options) > 0 && options[0].Interval > 0 {
interval = options[0].Interval
}
if envInterval := core.Env("MONITOR_INTERVAL"); envInterval != "" {
if d, err := time.ParseDuration(envInterval); err == nil {
@ -143,10 +143,10 @@ func (m *Subsystem) debug(msg string) {
core.Debug(msg)
}
// name := mon.Name() // "monitor"
// name := service.Name() // "monitor"
func (m *Subsystem) Name() string { return "monitor" }
// mon.RegisterTools(server)
// service.RegisterTools(server)
func (m *Subsystem) RegisterTools(server *mcp.Server) {
m.server = server
@ -158,7 +158,7 @@ func (m *Subsystem) RegisterTools(server *mcp.Server) {
}, m.agentStatusResource)
}
// mon.Start(ctx)
// service.Start(ctx)
func (m *Subsystem) Start(ctx context.Context) {
monitorCtx, cancel := context.WithCancel(ctx)
m.cancel = cancel
@ -172,21 +172,21 @@ func (m *Subsystem) Start(ctx context.Context) {
}()
}
// r := mon.OnStartup(context.Background())
// r := service.OnStartup(context.Background())
// core.Println(r.OK)
func (m *Subsystem) OnStartup(ctx context.Context) core.Result {
m.Start(ctx)
return core.Result{OK: true}
}
// r := mon.OnShutdown(context.Background())
// r := service.OnShutdown(context.Background())
// core.Println(r.OK)
func (m *Subsystem) OnShutdown(ctx context.Context) core.Result {
_ = m.Shutdown(ctx)
return core.Result{OK: true}
}
// _ = mon.Shutdown(ctx)
// _ = service.Shutdown(ctx)
func (m *Subsystem) Shutdown(_ context.Context) error {
if m.cancel != nil {
m.cancel()
@ -195,7 +195,7 @@ func (m *Subsystem) Shutdown(_ context.Context) error {
return nil
}
// mon.Poke()
// service.Poke()
func (m *Subsystem) Poke() {
select {
case m.poke <- struct{}{}:

View file

@ -9,9 +9,9 @@ import (
// Register wires the monitor service into Core and lets HandleIPCEvents auto-register.
//
// c := core.New(core.WithService(monitor.Register))
// mon, _ := core.ServiceFor[*monitor.Subsystem](c, "monitor")
// service, _ := core.ServiceFor[*monitor.Subsystem](c, "monitor")
func Register(c *core.Core) core.Result {
monitorService := New()
monitorService.ServiceRuntime = core.NewServiceRuntime(c, Options{})
return core.Result{Value: monitorService, OK: true}
service := New(Options{})
service.ServiceRuntime = core.NewServiceRuntime(c, Options{})
return core.Result{Value: service, OK: true}
}

View file

@ -13,7 +13,7 @@ import (
// DispatchConfig mirrors the `dispatch:` block in `agents.yaml`.
//
// cfg := runner.DispatchConfig{
// config := runner.DispatchConfig{
// DefaultAgent: "codex", DefaultTemplate: "coding", WorkspaceRoot: "/srv/core/workspace",
// }
type DispatchConfig struct {
@ -73,7 +73,7 @@ func (c *ConcurrencyLimit) UnmarshalYAML(value *yaml.Node) error {
// AgentsConfig mirrors the full `agents.yaml` file.
//
// cfg := runner.AgentsConfig{
// config := runner.AgentsConfig{
// Version: 1,
// Dispatch: runner.DispatchConfig{DefaultAgent: "codex", DefaultTemplate: "coding"},
// }
@ -86,8 +86,8 @@ type AgentsConfig struct {
// loadAgentsConfig reads `agents.yaml` from the Core root.
//
// cfg := s.loadAgentsConfig()
// core.Println(cfg.Dispatch.DefaultAgent)
// config := s.loadAgentsConfig()
// core.Println(config.Dispatch.DefaultAgent)
func (s *Service) loadAgentsConfig() *AgentsConfig {
paths := []string{
core.JoinPath(CoreRoot(), "agents.yaml"),
@ -127,8 +127,8 @@ func (s *Service) canDispatchAgent(agent string) (bool, string) {
}
}
if concurrency == nil {
cfg := s.loadAgentsConfig()
concurrency = cfg.Concurrency
config := s.loadAgentsConfig()
concurrency = config.Concurrency
}
base := baseAgent(agent)
@ -301,8 +301,8 @@ func (s *Service) delayForAgent(agent string) time.Duration {
rates, _ = s.Core().Config().Get("agents.rates").Value.(map[string]RateConfig)
}
if rates == nil {
cfg := s.loadAgentsConfig()
rates = cfg.Rates
config := s.loadAgentsConfig()
rates = config.Rates
}
base := baseAgent(agent)
rate, ok := rates[base]

View file

@ -19,15 +19,15 @@ import (
// Options configures the runner service.
//
// opts := runner.Options{}
// options := runner.Options{}
type Options struct{}
// Service is the agent dispatch runner.
// Manages concurrency limits, queue drain, workspace lifecycle, and frozen state.
// All dispatch requests — MCP tool, CLI, or IPC — go through this service.
//
// svc := runner.New()
// svc.TrackWorkspace("core/go-io/task-5", &runner.WorkspaceStatus{Status: "running", Agent: "codex"})
// service := runner.New()
// service.TrackWorkspace("core/go-io/task-5", &runner.WorkspaceStatus{Status: "running", Agent: "codex"})
type Service struct {
*core.ServiceRuntime[Options]
dispatchMu sync.Mutex
@ -45,7 +45,7 @@ type channelSender interface {
// New creates a runner service.
//
// svc := runner.New()
// service := runner.New()
func New() *Service {
return &Service{
backoff: make(map[string]time.Time),
@ -58,22 +58,22 @@ func New() *Service {
//
// core.New(core.WithService(runner.Register))
func Register(c *core.Core) core.Result {
svc := New()
svc.ServiceRuntime = core.NewServiceRuntime(c, Options{})
service := New()
service.ServiceRuntime = core.NewServiceRuntime(c, Options{})
// Load agents config
cfg := svc.loadAgentsConfig()
c.Config().Set("agents.concurrency", cfg.Concurrency)
c.Config().Set("agents.rates", cfg.Rates)
c.Config().Set("agents.dispatch", cfg.Dispatch)
config := service.loadAgentsConfig()
c.Config().Set("agents.concurrency", config.Concurrency)
c.Config().Set("agents.rates", config.Rates)
c.Config().Set("agents.dispatch", config.Dispatch)
c.Config().Set("agents.config_path", core.JoinPath(CoreRoot(), "agents.yaml"))
codexTotal := 0
if cl, ok := cfg.Concurrency["codex"]; ok {
if cl, ok := config.Concurrency["codex"]; ok {
codexTotal = cl.Total
}
c.Config().Set("agents.codex_limit_debug", codexTotal)
return core.Result{Value: svc, OK: true}
return core.Result{Value: service, OK: true}
}
// OnStartup registers Actions and starts the queue runner.
@ -108,9 +108,9 @@ func (s *Service) OnStartup(ctx context.Context) core.Result {
// OnShutdown freezes the queue.
//
// r := svc.OnShutdown(context.Background())
// r := service.OnShutdown(context.Background())
// if r.OK {
// core.Println(svc.IsFrozen())
// core.Println(service.IsFrozen())
// }
func (s *Service) OnShutdown(_ context.Context) core.Result {
s.frozen = true

View file

@ -2,7 +2,7 @@
// Package setup provisions `.core/` files and workspace scaffolds for a repo.
//
// svc := core.ServiceFor[*setup.Service](core.New(core.WithService(setup.Register)), "setup")
// service := core.ServiceFor[*setup.Service](core.New(core.WithService(setup.Register)), "setup")
package setup
import (

View file

@ -8,40 +8,40 @@ import (
core "dappco.re/go/core"
)
// SetupOptions carries service-level setup configuration.
// RuntimeOptions carries service-level setup configuration.
//
// opts := setup.SetupOptions{}
type SetupOptions struct{}
// options := setup.RuntimeOptions{}
type RuntimeOptions struct{}
// Service exposes workspace setup through Core service registration.
//
// c := core.New(core.WithService(setup.Register))
// svc, _ := core.ServiceFor[*setup.Service](c, "setup")
// service, _ := core.ServiceFor[*setup.Service](c, "setup")
type Service struct {
*core.ServiceRuntime[SetupOptions]
*core.ServiceRuntime[RuntimeOptions]
}
// Register wires the setup service into Core.
//
// c := core.New(core.WithService(setup.Register))
// svc, _ := core.ServiceFor[*setup.Service](c, "setup")
// service, _ := core.ServiceFor[*setup.Service](c, "setup")
func Register(c *core.Core) core.Result {
svc := &Service{
ServiceRuntime: core.NewServiceRuntime(c, SetupOptions{}),
service := &Service{
ServiceRuntime: core.NewServiceRuntime(c, RuntimeOptions{}),
}
return core.Result{Value: svc, OK: true}
return core.Result{Value: service, OK: true}
}
// OnStartup keeps the setup service ready for Core startup hooks.
//
// result := svc.OnStartup(context.Background())
// result := service.OnStartup(context.Background())
func (s *Service) OnStartup(ctx context.Context) core.Result {
return core.Result{OK: true}
}
// DetectGitRemote reads `origin` and returns `owner/repo` when available.
//
// remote := svc.DetectGitRemote("/srv/repos/agent")
// remote := service.DetectGitRemote("/srv/repos/agent")
func (s *Service) DetectGitRemote(path string) string {
r := s.Core().Process().RunIn(context.Background(), path, "git", "remote", "get-url", "origin")
if !r.OK {

View file

@ -8,9 +8,9 @@ import (
func ExampleRegister_serviceFor() {
c := core.New(core.WithService(Register))
svc, ok := core.ServiceFor[*Service](c, "setup")
service, ok := core.ServiceFor[*Service](c, "setup")
core.Println(ok)
core.Println(svc != nil)
core.Println(service != nil)
// Output:
// true
// true
@ -18,10 +18,10 @@ func ExampleRegister_serviceFor() {
func ExampleService_DetectGitRemote() {
c := core.New()
svc := &Service{ServiceRuntime: core.NewServiceRuntime(c, SetupOptions{})}
service := &Service{ServiceRuntime: core.NewServiceRuntime(c, RuntimeOptions{})}
// Non-git dir returns empty
remote := svc.DetectGitRemote((&core.Fs{}).NewUnrestricted().TempDir("example"))
remote := service.DetectGitRemote((&core.Fs{}).NewUnrestricted().TempDir("example"))
core.Println(remote == "")
// Output: true
}

View file

@ -21,19 +21,19 @@ func TestService_Register_Good(t *testing.T) {
func TestService_OnStartup_Good(t *testing.T) {
c := core.New()
svc := &Service{ServiceRuntime: core.NewServiceRuntime(c, SetupOptions{})}
service := &Service{ServiceRuntime: core.NewServiceRuntime(c, RuntimeOptions{})}
result := svc.OnStartup(context.Background())
result := service.OnStartup(context.Background())
assert.True(t, result.OK)
}
func TestService_OnStartup_Bad_CancelledContext(t *testing.T) {
c := core.New()
svc := &Service{ServiceRuntime: core.NewServiceRuntime(c, SetupOptions{})}
service := &Service{ServiceRuntime: core.NewServiceRuntime(c, RuntimeOptions{})}
ctx, cancel := context.WithCancel(context.Background())
cancel()
result := svc.OnStartup(ctx)
result := service.OnStartup(ctx)
assert.True(t, result.OK)
}
@ -46,25 +46,25 @@ func TestService_DetectGitRemote_Good_GitOrigin(t *testing.T) {
dir := t.TempDir()
c := core.New()
require.True(t, agentic.ProcessRegister(c).OK)
svc := &Service{ServiceRuntime: core.NewServiceRuntime(c, SetupOptions{})}
service := &Service{ServiceRuntime: core.NewServiceRuntime(c, RuntimeOptions{})}
require.True(t, c.Process().RunIn(context.Background(), dir, "git", "init").OK)
require.True(t, c.Process().RunIn(context.Background(), dir, "git", "remote", "add", "origin", "git@forge.lthn.ai:core/agent.git").OK)
assert.Equal(t, "core/agent", svc.DetectGitRemote(dir))
assert.Equal(t, "core/agent", service.DetectGitRemote(dir))
}
func TestService_DetectGitRemote_Bad_NonGitDir(t *testing.T) {
c := core.New()
svc := &Service{ServiceRuntime: core.NewServiceRuntime(c, SetupOptions{})}
remote := svc.DetectGitRemote(t.TempDir())
service := &Service{ServiceRuntime: core.NewServiceRuntime(c, RuntimeOptions{})}
remote := service.DetectGitRemote(t.TempDir())
assert.Equal(t, "", remote)
}
func TestService_DetectGitRemote_Ugly_EmptyPath(t *testing.T) {
c := core.New()
svc := &Service{ServiceRuntime: core.NewServiceRuntime(c, SetupOptions{})}
service := &Service{ServiceRuntime: core.NewServiceRuntime(c, RuntimeOptions{})}
assert.NotPanics(t, func() {
svc.DetectGitRemote("")
service.DetectGitRemote("")
})
}

View file

@ -12,7 +12,7 @@ import (
func newSetupService() *Service {
c := core.New()
return &Service{ServiceRuntime: core.NewServiceRuntime(c, SetupOptions{})}
return &Service{ServiceRuntime: core.NewServiceRuntime(c, RuntimeOptions{})}
}
func TestSetup_Run_Good_WritesCoreConfigs(t *testing.T) {