2026-03-16 11:10:33 +00:00
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
|
|
// Package agentic provides MCP tools for agent orchestration.
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Prepares workspaces and dispatches subagents.
|
2026-03-16 11:10:33 +00:00
|
|
|
package agentic
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/base64"
|
2026-03-21 17:10:43 +00:00
|
|
|
"sync"
|
2026-03-16 11:10:33 +00:00
|
|
|
"time"
|
|
|
|
|
|
2026-03-21 11:10:31 +00:00
|
|
|
"dappco.re/go/agent/pkg/lib"
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
core "dappco.re/go/core"
|
2026-03-22 14:15:41 +00:00
|
|
|
"dappco.re/go/core/forge"
|
2026-03-29 20:15:58 +00:00
|
|
|
coremcp "forge.lthn.ai/core/mcp/pkg/mcp"
|
2026-03-16 11:10:33 +00:00
|
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
|
)
|
|
|
|
|
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
// AgentOptions configures the agentic service.
|
2026-03-30 00:20:03 +00:00
|
|
|
//
|
|
|
|
|
// opts := agentic.AgentOptions{}
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
type AgentOptions struct{}
|
|
|
|
|
|
2026-03-22 03:41:07 +00:00
|
|
|
// PrepSubsystem provides agentic MCP tools for workspace orchestration.
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
// Agent lifecycle events are broadcast via s.Core().ACTION(messages.AgentCompleted{}).
|
2026-03-22 03:41:07 +00:00
|
|
|
//
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
// core.New(core.WithService(agentic.Register))
|
2026-03-16 11:10:33 +00:00
|
|
|
type PrepSubsystem struct {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
*core.ServiceRuntime[AgentOptions]
|
2026-03-22 14:15:41 +00:00
|
|
|
forge *forge.Forge
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
forgeURL string
|
|
|
|
|
forgeToken string
|
|
|
|
|
brainURL string
|
|
|
|
|
brainKey string
|
|
|
|
|
codePath string
|
2026-03-29 23:37:28 +00:00
|
|
|
commandCtx context.Context
|
feat(runner): extract dispatch runner into independent Core service
Moves concurrency, queue drain, workspace lifecycle, and frozen state
from agentic/prep into pkg/runner/ — a standalone Core service that
communicates via IPC Actions only.
- runner.Register wires Actions: dispatch, status, start, stop, kill, poke
- runner.HandleIPCEvents catches AgentCompleted → ChannelPush + queue poke
- Agentic dispatch asks runner for permission via c.Action("runner.dispatch")
- Dispatch mutex moved to struct-level sync.Mutex (fixes core.Lock init race)
- Registry-based concurrency counting replaces disk scanning
- TrackWorkspace called on both queued and running status writes
- SpawnQueued message added for runner→agentic spawn requests
- ChannelPush message in core/mcp enables any service to push channel events
- 51 new tests covering runner service, queue, and config parsing
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 11:00:47 +00:00
|
|
|
dispatchMu sync.Mutex // serialises concurrency check + spawn
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
drainMu sync.Mutex
|
2026-03-23 12:53:33 +00:00
|
|
|
pokeCh chan struct{}
|
2026-03-23 16:08:08 +00:00
|
|
|
frozen bool
|
2026-03-29 20:15:58 +00:00
|
|
|
backoff map[string]time.Time // pool → paused until
|
|
|
|
|
failCount map[string]int // pool → consecutive fast failures
|
2026-03-26 06:38:02 +00:00
|
|
|
workspaces *core.Registry[*WorkspaceStatus] // in-memory workspace state
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-22 06:42:42 +00:00
|
|
|
var _ coremcp.Subsystem = (*PrepSubsystem)(nil)
|
|
|
|
|
|
2026-03-16 11:10:33 +00:00
|
|
|
// NewPrep creates an agentic subsystem.
|
2026-03-22 03:41:07 +00:00
|
|
|
//
|
|
|
|
|
// sub := agentic.NewPrep()
|
|
|
|
|
// sub.SetCompletionNotifier(monitor)
|
2026-03-16 11:10:33 +00:00
|
|
|
func NewPrep() *PrepSubsystem {
|
refactor(agentic): adopt core.Env() + core.Path() across package
Replace all os.UserHomeDir/os.Getenv/os.Hostname with core.Env().
Replace all filepath.Base/Dir/Glob/IsAbs with core.PathBase/PathDir/
PathGlob/PathIsAbs.
10 files migrated: paths, prep, review_queue, remote, dispatch,
ingest, mirror, plan, verify, watch.
Imports eliminated: 5x os, 7x filepath. All file I/O and path
construction now routes through Core primitives.
Bumps dappco.re/go/core to v0.6.0.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 10:15:15 +00:00
|
|
|
home := core.Env("DIR_HOME")
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): adopt core.Env() + core.Path() across package
Replace all os.UserHomeDir/os.Getenv/os.Hostname with core.Env().
Replace all filepath.Base/Dir/Glob/IsAbs with core.PathBase/PathDir/
PathGlob/PathIsAbs.
10 files migrated: paths, prep, review_queue, remote, dispatch,
ingest, mirror, plan, verify, watch.
Imports eliminated: 5x os, 7x filepath. All file I/O and path
construction now routes through Core primitives.
Bumps dappco.re/go/core to v0.6.0.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 10:15:15 +00:00
|
|
|
forgeToken := core.Env("FORGE_TOKEN")
|
2026-03-16 11:10:33 +00:00
|
|
|
if forgeToken == "" {
|
refactor(agentic): adopt core.Env() + core.Path() across package
Replace all os.UserHomeDir/os.Getenv/os.Hostname with core.Env().
Replace all filepath.Base/Dir/Glob/IsAbs with core.PathBase/PathDir/
PathGlob/PathIsAbs.
10 files migrated: paths, prep, review_queue, remote, dispatch,
ingest, mirror, plan, verify, watch.
Imports eliminated: 5x os, 7x filepath. All file I/O and path
construction now routes through Core primitives.
Bumps dappco.re/go/core to v0.6.0.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 10:15:15 +00:00
|
|
|
forgeToken = core.Env("GITEA_TOKEN")
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): adopt core.Env() + core.Path() across package
Replace all os.UserHomeDir/os.Getenv/os.Hostname with core.Env().
Replace all filepath.Base/Dir/Glob/IsAbs with core.PathBase/PathDir/
PathGlob/PathIsAbs.
10 files migrated: paths, prep, review_queue, remote, dispatch,
ingest, mirror, plan, verify, watch.
Imports eliminated: 5x os, 7x filepath. All file I/O and path
construction now routes through Core primitives.
Bumps dappco.re/go/core to v0.6.0.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 10:15:15 +00:00
|
|
|
brainKey := core.Env("CORE_BRAIN_KEY")
|
2026-03-16 11:10:33 +00:00
|
|
|
if brainKey == "" {
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
if r := fs.Read(core.JoinPath(home, ".claude", "brain.key")); r.OK {
|
|
|
|
|
brainKey = core.Trim(r.Value.(string))
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 14:15:41 +00:00
|
|
|
forgeURL := envOr("FORGE_URL", "https://forge.lthn.ai")
|
|
|
|
|
|
2026-03-16 11:10:33 +00:00
|
|
|
return &PrepSubsystem{
|
2026-03-22 14:15:41 +00:00
|
|
|
forge: forge.NewForge(forgeURL, forgeToken),
|
|
|
|
|
forgeURL: forgeURL,
|
2026-03-17 18:13:44 +00:00
|
|
|
forgeToken: forgeToken,
|
|
|
|
|
brainURL: envOr("CORE_BRAIN_URL", "https://api.lthn.sh"),
|
|
|
|
|
brainKey: brainKey,
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
codePath: envOr("CODE_PATH", core.JoinPath(home, "Code")),
|
2026-03-23 16:08:08 +00:00
|
|
|
backoff: make(map[string]time.Time),
|
|
|
|
|
failCount: make(map[string]int),
|
2026-03-26 06:38:02 +00:00
|
|
|
workspaces: core.NewRegistry[*WorkspaceStatus](),
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
// SetCore wires the Core framework instance via ServiceRuntime.
|
|
|
|
|
// Deprecated: Use Register with core.WithService(agentic.Register) instead.
|
2026-03-24 14:34:56 +00:00
|
|
|
//
|
|
|
|
|
// prep.SetCore(c)
|
|
|
|
|
func (s *PrepSubsystem) SetCore(c *core.Core) {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
s.ServiceRuntime = core.NewServiceRuntime(c, AgentOptions{})
|
2026-03-24 14:34:56 +00:00
|
|
|
}
|
|
|
|
|
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
// OnStartup implements core.Startable — registers named Actions, starts the queue runner,
|
|
|
|
|
// and registers CLI commands. The Action registry IS the capability map.
|
|
|
|
|
//
|
|
|
|
|
// c.Action("agentic.dispatch").Run(ctx, opts)
|
|
|
|
|
// c.Actions() // ["agentic.dispatch", "agentic.prep", "agentic.status", ...]
|
|
|
|
|
func (s *PrepSubsystem) OnStartup(ctx context.Context) core.Result {
|
|
|
|
|
c := s.Core()
|
|
|
|
|
|
2026-03-26 06:38:02 +00:00
|
|
|
// Entitlement — gates agentic Actions when queue is frozen.
|
|
|
|
|
// Per-agent concurrency is checked inside handlers (needs Options for agent name).
|
|
|
|
|
// Entitlement gates the global capability: "can this Core dispatch at all?"
|
|
|
|
|
//
|
|
|
|
|
// e := c.Entitled("agentic.dispatch")
|
|
|
|
|
// e.Allowed // false when frozen
|
|
|
|
|
// e.Reason // "agent queue is frozen"
|
|
|
|
|
c.SetEntitlementChecker(func(action string, qty int, _ context.Context) core.Entitlement {
|
|
|
|
|
// Only gate agentic.* actions
|
|
|
|
|
if !core.HasPrefix(action, "agentic.") {
|
|
|
|
|
return core.Entitlement{Allowed: true, Unlimited: true}
|
|
|
|
|
}
|
2026-03-26 07:16:48 +00:00
|
|
|
// Read-only + internal actions always allowed
|
|
|
|
|
if core.HasPrefix(action, "agentic.monitor.") || core.HasPrefix(action, "agentic.complete") {
|
|
|
|
|
return core.Entitlement{Allowed: true, Unlimited: true}
|
|
|
|
|
}
|
2026-03-26 06:38:02 +00:00
|
|
|
switch action {
|
|
|
|
|
case "agentic.status", "agentic.scan", "agentic.watch",
|
|
|
|
|
"agentic.issue.get", "agentic.issue.list", "agentic.pr.get", "agentic.pr.list",
|
|
|
|
|
"agentic.prompt", "agentic.task", "agentic.flow", "agentic.persona":
|
|
|
|
|
return core.Entitlement{Allowed: true, Unlimited: true}
|
|
|
|
|
}
|
|
|
|
|
// Write actions gated by frozen state
|
|
|
|
|
if s.frozen {
|
|
|
|
|
return core.Entitlement{Allowed: false, Reason: "agent queue is frozen — shutting down"}
|
|
|
|
|
}
|
|
|
|
|
return core.Entitlement{Allowed: true}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Data — mount embedded content so other services can access it via c.Data()
|
|
|
|
|
//
|
|
|
|
|
// c.Data().ReadString("prompts/coding.md")
|
|
|
|
|
// c.Data().ListNames("flows")
|
|
|
|
|
lib.MountData(c)
|
|
|
|
|
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
// Transport — register HTTP protocol + Drive endpoints
|
|
|
|
|
RegisterHTTPTransport(c)
|
|
|
|
|
c.Drive().New(core.NewOptions(
|
|
|
|
|
core.Option{Key: "name", Value: "forge"},
|
|
|
|
|
core.Option{Key: "transport", Value: s.forgeURL},
|
|
|
|
|
core.Option{Key: "token", Value: s.forgeToken},
|
|
|
|
|
))
|
|
|
|
|
c.Drive().New(core.NewOptions(
|
|
|
|
|
core.Option{Key: "name", Value: "brain"},
|
|
|
|
|
core.Option{Key: "transport", Value: s.brainURL},
|
|
|
|
|
core.Option{Key: "token", Value: s.brainKey},
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
// Dispatch & workspace
|
2026-03-26 06:38:02 +00:00
|
|
|
c.Action("agentic.dispatch", s.handleDispatch).Description = "Prep workspace and spawn a subagent"
|
|
|
|
|
c.Action("agentic.prep", s.handlePrep).Description = "Clone repo and build agent prompt"
|
|
|
|
|
c.Action("agentic.status", s.handleStatus).Description = "List workspace states (running/completed/blocked)"
|
|
|
|
|
c.Action("agentic.resume", s.handleResume).Description = "Resume a blocked or completed workspace"
|
|
|
|
|
c.Action("agentic.scan", s.handleScan).Description = "Scan Forge repos for actionable issues"
|
|
|
|
|
c.Action("agentic.watch", s.handleWatch).Description = "Watch workspace for changes and report"
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
|
|
|
|
|
// Pipeline
|
2026-03-26 06:38:02 +00:00
|
|
|
c.Action("agentic.qa", s.handleQA).Description = "Run build + test QA checks on workspace"
|
|
|
|
|
c.Action("agentic.auto-pr", s.handleAutoPR).Description = "Create PR from completed workspace"
|
|
|
|
|
c.Action("agentic.verify", s.handleVerify).Description = "Verify PR and auto-merge if clean"
|
|
|
|
|
c.Action("agentic.ingest", s.handleIngest).Description = "Create issues from agent findings"
|
|
|
|
|
c.Action("agentic.poke", s.handlePoke).Description = "Drain next queued task from the queue"
|
|
|
|
|
c.Action("agentic.mirror", s.handleMirror).Description = "Mirror agent branches to GitHub"
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
|
|
|
|
|
// Forge
|
2026-03-26 06:38:02 +00:00
|
|
|
c.Action("agentic.issue.get", s.handleIssueGet).Description = "Get a Forge issue by number"
|
|
|
|
|
c.Action("agentic.issue.list", s.handleIssueList).Description = "List Forge issues for a repo"
|
|
|
|
|
c.Action("agentic.issue.create", s.handleIssueCreate).Description = "Create a Forge issue"
|
|
|
|
|
c.Action("agentic.pr.get", s.handlePRGet).Description = "Get a Forge PR by number"
|
|
|
|
|
c.Action("agentic.pr.list", s.handlePRList).Description = "List Forge PRs for a repo"
|
|
|
|
|
c.Action("agentic.pr.merge", s.handlePRMerge).Description = "Merge a Forge PR"
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
|
|
|
|
|
// Review
|
2026-03-26 06:38:02 +00:00
|
|
|
c.Action("agentic.review-queue", s.handleReviewQueue).Description = "Run CodeRabbit review on completed workspaces"
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
|
|
|
|
|
// Epic
|
2026-03-26 06:38:02 +00:00
|
|
|
c.Action("agentic.epic", s.handleEpic).Description = "Create sub-issues from an epic plan"
|
|
|
|
|
|
|
|
|
|
// Content — accessible via IPC, no lib import needed
|
2026-03-29 21:56:45 +00:00
|
|
|
c.Action("agentic.prompt", s.handlePrompt).Description = "Read a system prompt by slug"
|
|
|
|
|
c.Action("agentic.task", s.handleTask).Description = "Read a task plan by slug"
|
|
|
|
|
c.Action("agentic.flow", s.handleFlow).Description = "Read a build/release flow by slug"
|
|
|
|
|
c.Action("agentic.persona", s.handlePersona).Description = "Read a persona by path"
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
|
|
|
|
|
// Completion pipeline — Task composition
|
|
|
|
|
c.Task("agent.completion", core.Task{
|
|
|
|
|
Description: "QA → PR → Verify → Merge",
|
|
|
|
|
Steps: []core.Step{
|
|
|
|
|
{Action: "agentic.qa"},
|
|
|
|
|
{Action: "agentic.auto-pr"},
|
|
|
|
|
{Action: "agentic.verify"},
|
|
|
|
|
{Action: "agentic.ingest", Async: true},
|
|
|
|
|
{Action: "agentic.poke", Async: true},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
2026-03-26 06:38:02 +00:00
|
|
|
// PerformAsync wrapper — runs the completion Task in background with progress tracking.
|
|
|
|
|
// c.PerformAsync("agentic.complete", opts) broadcasts ActionTaskStarted/Completed.
|
2026-03-29 21:56:45 +00:00
|
|
|
c.Action("agentic.complete", s.handleComplete).Description = "Run completion pipeline (QA → PR → Verify) in background"
|
2026-03-26 06:38:02 +00:00
|
|
|
|
|
|
|
|
// Hydrate workspace registry from disk
|
|
|
|
|
s.hydrateWorkspaces()
|
|
|
|
|
|
|
|
|
|
// QUERY handler — "what workspaces exist?"
|
|
|
|
|
//
|
|
|
|
|
// r := c.QUERY(agentic.WorkspaceQuery{})
|
|
|
|
|
// if r.OK { workspaces := r.Value.(*core.Registry[*WorkspaceStatus]) }
|
2026-03-29 21:56:45 +00:00
|
|
|
c.RegisterQuery(s.handleWorkspaceQuery)
|
2026-03-26 06:38:02 +00:00
|
|
|
|
2026-03-24 17:42:16 +00:00
|
|
|
s.StartRunner()
|
2026-03-24 21:16:20 +00:00
|
|
|
s.registerCommands(ctx)
|
2026-03-25 00:03:22 +00:00
|
|
|
s.registerWorkspaceCommands()
|
2026-03-25 00:06:46 +00:00
|
|
|
s.registerForgeCommands()
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
return core.Result{OK: true}
|
2026-03-24 17:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-24 21:24:29 +00:00
|
|
|
// registerCommands is in commands.go
|
2026-03-24 21:16:20 +00:00
|
|
|
|
2026-03-29 23:14:26 +00:00
|
|
|
// OnShutdown implements core.Stoppable and freezes the queue.
|
|
|
|
|
//
|
|
|
|
|
// prep := agentic.NewPrep()
|
|
|
|
|
// _ = prep.OnShutdown(context.Background())
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
func (s *PrepSubsystem) OnShutdown(ctx context.Context) core.Result {
|
2026-03-24 17:42:16 +00:00
|
|
|
s.frozen = true
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
return core.Result{OK: true}
|
2026-03-24 17:42:16 +00:00
|
|
|
}
|
2026-03-17 17:45:04 +00:00
|
|
|
|
2026-03-26 06:38:02 +00:00
|
|
|
// hydrateWorkspaces scans disk and populates the workspace Registry on startup.
|
|
|
|
|
// Keyed by workspace name (relative path from workspace root).
|
|
|
|
|
//
|
|
|
|
|
// s.hydrateWorkspaces()
|
|
|
|
|
// s.workspaces.Names() // ["core/go-io/task-5", "ws-blocked", ...]
|
|
|
|
|
func (s *PrepSubsystem) hydrateWorkspaces() {
|
|
|
|
|
if s.workspaces == nil {
|
|
|
|
|
s.workspaces = core.NewRegistry[*WorkspaceStatus]()
|
|
|
|
|
}
|
2026-03-29 21:19:37 +00:00
|
|
|
for _, path := range WorkspaceStatusPaths() {
|
|
|
|
|
wsDir := core.PathDir(path)
|
|
|
|
|
st, err := ReadStatus(wsDir)
|
|
|
|
|
if err != nil || st == nil {
|
|
|
|
|
continue
|
2026-03-26 06:38:02 +00:00
|
|
|
}
|
2026-03-29 21:19:37 +00:00
|
|
|
s.workspaces.Set(WorkspaceName(wsDir), st)
|
2026-03-26 06:38:02 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TrackWorkspace registers or updates a workspace in the in-memory Registry.
|
|
|
|
|
//
|
|
|
|
|
// s.TrackWorkspace("core/go-io/task-5", st)
|
|
|
|
|
func (s *PrepSubsystem) TrackWorkspace(name string, st *WorkspaceStatus) {
|
|
|
|
|
if s.workspaces != nil {
|
|
|
|
|
s.workspaces.Set(name, st)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Workspaces returns the workspace Registry for cross-cutting queries.
|
|
|
|
|
//
|
|
|
|
|
// s.Workspaces().Names() // all workspace names
|
|
|
|
|
// s.Workspaces().List("core/*") // org-scoped workspaces
|
|
|
|
|
// s.Workspaces().Each(func(name string, st *WorkspaceStatus) { ... })
|
|
|
|
|
func (s *PrepSubsystem) Workspaces() *core.Registry[*WorkspaceStatus] {
|
|
|
|
|
return s.workspaces
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 11:10:33 +00:00
|
|
|
func envOr(key, fallback string) string {
|
refactor(agentic): adopt core.Env() + core.Path() across package
Replace all os.UserHomeDir/os.Getenv/os.Hostname with core.Env().
Replace all filepath.Base/Dir/Glob/IsAbs with core.PathBase/PathDir/
PathGlob/PathIsAbs.
10 files migrated: paths, prep, review_queue, remote, dispatch,
ingest, mirror, plan, verify, watch.
Imports eliminated: 5x os, 7x filepath. All file I/O and path
construction now routes through Core primitives.
Bumps dappco.re/go/core to v0.6.0.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 10:15:15 +00:00
|
|
|
if v := core.Env(key); v != "" {
|
2026-03-16 11:10:33 +00:00
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
return fallback
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 23:14:26 +00:00
|
|
|
// Name identifies the MCP subsystem.
|
|
|
|
|
//
|
|
|
|
|
// prep := agentic.NewPrep()
|
|
|
|
|
// name := prep.Name()
|
|
|
|
|
// _ = name // "agentic"
|
2026-03-16 11:10:33 +00:00
|
|
|
func (s *PrepSubsystem) Name() string { return "agentic" }
|
|
|
|
|
|
2026-03-29 23:14:26 +00:00
|
|
|
// RegisterTools publishes the agentic MCP tools on the server.
|
|
|
|
|
//
|
|
|
|
|
// prep := agentic.NewPrep()
|
|
|
|
|
// prep.RegisterTools(server)
|
2026-03-16 11:10:33 +00:00
|
|
|
func (s *PrepSubsystem) RegisterTools(server *mcp.Server) {
|
|
|
|
|
mcp.AddTool(server, &mcp.Tool{
|
|
|
|
|
Name: "agentic_prep_workspace",
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
Description: "Prepare an agent workspace: clone repo, create branch, build prompt with context.",
|
2026-03-16 11:10:33 +00:00
|
|
|
}, s.prepWorkspace)
|
|
|
|
|
|
|
|
|
|
s.registerDispatchTool(server)
|
|
|
|
|
s.registerStatusTool(server)
|
|
|
|
|
s.registerResumeTool(server)
|
|
|
|
|
s.registerCreatePRTool(server)
|
|
|
|
|
s.registerListPRsTool(server)
|
|
|
|
|
s.registerEpicTool(server)
|
2026-03-17 17:45:04 +00:00
|
|
|
s.registerMirrorTool(server)
|
|
|
|
|
s.registerRemoteDispatchTool(server)
|
|
|
|
|
s.registerRemoteStatusTool(server)
|
|
|
|
|
s.registerReviewQueueTool(server)
|
2026-03-23 16:08:08 +00:00
|
|
|
s.registerShutdownTools(server)
|
2026-03-16 11:10:33 +00:00
|
|
|
|
|
|
|
|
mcp.AddTool(server, &mcp.Tool{
|
|
|
|
|
Name: "agentic_scan",
|
|
|
|
|
Description: "Scan Forge repos for open issues with actionable labels (agentic, help-wanted, bug).",
|
|
|
|
|
}, s.scan)
|
|
|
|
|
|
|
|
|
|
s.registerPlanTools(server)
|
2026-03-17 04:31:19 +00:00
|
|
|
s.registerWatchTool(server)
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-29 23:14:26 +00:00
|
|
|
// Shutdown satisfies mcp.SubsystemWithShutdown for clean server teardown.
|
|
|
|
|
//
|
|
|
|
|
// prep := agentic.NewPrep()
|
|
|
|
|
// _ = prep.Shutdown(context.Background())
|
2026-03-16 11:10:33 +00:00
|
|
|
func (s *PrepSubsystem) Shutdown(_ context.Context) error { return nil }
|
|
|
|
|
|
|
|
|
|
// --- Input/Output types ---
|
|
|
|
|
|
|
|
|
|
// PrepInput is the input for agentic_prep_workspace.
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// One of Issue, PR, Branch, or Tag is required.
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
//
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// input := agentic.PrepInput{Repo: "go-io", Issue: 15, Task: "Migrate to Core primitives"}
|
2026-03-16 11:10:33 +00:00
|
|
|
type PrepInput struct {
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
Repo string `json:"repo"` // required: e.g. "go-io"
|
2026-03-16 11:10:33 +00:00
|
|
|
Org string `json:"org,omitempty"` // default "core"
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
Task string `json:"task,omitempty"` // task description
|
|
|
|
|
Agent string `json:"agent,omitempty"` // agent type
|
|
|
|
|
Issue int `json:"issue,omitempty"` // Forge issue → workspace: task-{num}/
|
|
|
|
|
PR int `json:"pr,omitempty"` // PR number → workspace: pr-{num}/
|
|
|
|
|
Branch string `json:"branch,omitempty"` // branch → workspace: {branch}/
|
|
|
|
|
Tag string `json:"tag,omitempty"` // tag → workspace: {tag}/ (immutable)
|
|
|
|
|
Template string `json:"template,omitempty"` // prompt template slug
|
|
|
|
|
PlanTemplate string `json:"plan_template,omitempty"` // plan template slug
|
|
|
|
|
Variables map[string]string `json:"variables,omitempty"` // template variable substitution
|
|
|
|
|
Persona string `json:"persona,omitempty"` // persona slug
|
|
|
|
|
DryRun bool `json:"dry_run,omitempty"` // preview without executing
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PrepOutput is the output for agentic_prep_workspace.
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
//
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// out := agentic.PrepOutput{Success: true, WorkspaceDir: ".core/workspace/core/go-io/task-15"}
|
2026-03-16 11:10:33 +00:00
|
|
|
type PrepOutput struct {
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
Success bool `json:"success"`
|
|
|
|
|
WorkspaceDir string `json:"workspace_dir"`
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
RepoDir string `json:"repo_dir"`
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
Branch string `json:"branch"`
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
Prompt string `json:"prompt,omitempty"`
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
Memories int `json:"memories"`
|
|
|
|
|
Consumers int `json:"consumers"`
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
Resumed bool `json:"resumed"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// workspaceDir resolves the workspace path from the input identifier.
|
|
|
|
|
//
|
|
|
|
|
// dir := workspaceDir("core", "go-io", PrepInput{Issue: 15})
|
|
|
|
|
// // → ".core/workspace/core/go-io/task-15"
|
|
|
|
|
func workspaceDir(org, repo string, input PrepInput) (string, error) {
|
2026-03-30 07:30:42 +00:00
|
|
|
r := workspaceDirResult(org, repo, input)
|
|
|
|
|
if !r.OK {
|
|
|
|
|
err, _ := r.Value.(error)
|
|
|
|
|
if err == nil {
|
|
|
|
|
err = core.E("workspaceDir", "failed to resolve workspace directory", nil)
|
|
|
|
|
}
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
wsDir, ok := r.Value.(string)
|
|
|
|
|
if !ok || wsDir == "" {
|
|
|
|
|
return "", core.E("workspaceDir", "invalid workspace directory result", nil)
|
|
|
|
|
}
|
|
|
|
|
return wsDir, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// workspaceDirResult resolves the workspace path and returns core.Result.
|
|
|
|
|
//
|
|
|
|
|
// r := workspaceDirResult("core", "go-io", PrepInput{Issue: 15})
|
|
|
|
|
// if r.OK { wsDir := r.Value.(string) }
|
|
|
|
|
func workspaceDirResult(org, repo string, input PrepInput) core.Result {
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
base := core.JoinPath(WorkspaceRoot(), org, repo)
|
|
|
|
|
switch {
|
|
|
|
|
case input.PR > 0:
|
2026-03-30 07:30:42 +00:00
|
|
|
return core.Result{Value: core.JoinPath(base, core.Sprintf("pr-%d", input.PR)), OK: true}
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
case input.Issue > 0:
|
2026-03-30 07:30:42 +00:00
|
|
|
return core.Result{Value: core.JoinPath(base, core.Sprintf("task-%d", input.Issue)), OK: true}
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
case input.Branch != "":
|
2026-03-30 07:30:42 +00:00
|
|
|
return core.Result{Value: core.JoinPath(base, input.Branch), OK: true}
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
case input.Tag != "":
|
2026-03-30 07:30:42 +00:00
|
|
|
return core.Result{Value: core.JoinPath(base, input.Tag), OK: true}
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
default:
|
2026-03-30 07:30:42 +00:00
|
|
|
return core.Result{Value: core.E("workspaceDir", "one of issue, pr, branch, or tag is required", nil), OK: false}
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolRequest, input PrepInput) (*mcp.CallToolResult, PrepOutput, error) {
|
|
|
|
|
if input.Repo == "" {
|
2026-03-22 03:41:07 +00:00
|
|
|
return nil, PrepOutput{}, core.E("prepWorkspace", "repo is required", nil)
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
if input.Org == "" {
|
|
|
|
|
input.Org = "core"
|
|
|
|
|
}
|
|
|
|
|
if input.Template == "" {
|
|
|
|
|
input.Template = "coding"
|
|
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Resolve workspace directory from identifier
|
2026-03-30 07:30:42 +00:00
|
|
|
wsDirResult := workspaceDirResult(input.Org, input.Repo, input)
|
|
|
|
|
if !wsDirResult.OK {
|
|
|
|
|
err, _ := wsDirResult.Value.(error)
|
|
|
|
|
if err == nil {
|
|
|
|
|
err = core.E("prepWorkspace", "workspace path not resolved", nil)
|
|
|
|
|
}
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
return nil, PrepOutput{}, err
|
2026-03-21 16:22:18 +00:00
|
|
|
}
|
2026-03-30 07:30:42 +00:00
|
|
|
wsDir, ok := wsDirResult.Value.(string)
|
|
|
|
|
if !ok || wsDir == "" {
|
|
|
|
|
return nil, PrepOutput{}, core.E("prepWorkspace", "invalid workspace path", nil)
|
|
|
|
|
}
|
2026-03-21 16:22:18 +00:00
|
|
|
|
2026-03-29 20:15:58 +00:00
|
|
|
repoDir := workspaceRepoDir(wsDir)
|
|
|
|
|
metaDir := workspaceMetaDir(wsDir)
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
out := PrepOutput{WorkspaceDir: wsDir, RepoDir: repoDir}
|
2026-03-16 11:10:33 +00:00
|
|
|
|
2026-03-21 17:25:23 +00:00
|
|
|
// Source repo path — sanitise to prevent path traversal
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
repoName := core.PathBase(input.Repo)
|
2026-03-21 17:25:23 +00:00
|
|
|
if repoName == "." || repoName == ".." || repoName == "" {
|
2026-03-26 06:38:02 +00:00
|
|
|
return nil, PrepOutput{}, core.E("prep", core.Concat("invalid repo name: ", input.Repo), nil)
|
2026-03-21 17:25:23 +00:00
|
|
|
}
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
repoPath := core.JoinPath(s.codePath, input.Org, repoName)
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Ensure meta directory exists
|
|
|
|
|
if r := fs.EnsureDir(metaDir); !r.OK {
|
|
|
|
|
return nil, PrepOutput{}, core.E("prep", "failed to create meta dir", nil)
|
2026-03-21 15:59:48 +00:00
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
|
2026-03-29 09:22:58 +01:00
|
|
|
// Check for resume: if repo/ already has .git, pull latest instead of re-cloning
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
resumed := fs.IsDir(core.JoinPath(repoDir, ".git"))
|
|
|
|
|
out.Resumed = resumed
|
2026-03-16 11:10:33 +00:00
|
|
|
|
2026-03-29 09:22:58 +01:00
|
|
|
if resumed {
|
2026-03-29 20:15:58 +00:00
|
|
|
// Preserve the current branch on resume. Pull it only if it exists on
|
|
|
|
|
// origin; otherwise refresh the default branch refs without abandoning the
|
|
|
|
|
// workspace branch.
|
|
|
|
|
currentBranch := s.gitOutput(ctx, repoDir, "rev-parse", "--abbrev-ref", "HEAD")
|
|
|
|
|
defaultBranch := s.DefaultBranch(repoDir)
|
|
|
|
|
if currentBranch == "" || currentBranch == "HEAD" {
|
|
|
|
|
currentBranch = defaultBranch
|
|
|
|
|
}
|
|
|
|
|
if currentBranch != "" {
|
|
|
|
|
s.gitCmd(ctx, repoDir, "checkout", currentBranch)
|
|
|
|
|
if s.gitCmdOK(ctx, repoDir, "ls-remote", "--exit-code", "--heads", "origin", currentBranch) {
|
|
|
|
|
s.gitCmd(ctx, repoDir, "pull", "--ff-only", "origin", currentBranch)
|
|
|
|
|
} else if defaultBranch != "" {
|
|
|
|
|
s.gitCmd(ctx, repoDir, "fetch", "origin", defaultBranch)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-29 09:22:58 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-22 15:20:42 +00:00
|
|
|
// Extract default workspace template (go.work etc.)
|
|
|
|
|
lib.ExtractWorkspace("default", wsDir, &lib.WorkspaceData{
|
|
|
|
|
Repo: input.Repo,
|
|
|
|
|
Branch: "",
|
|
|
|
|
Task: input.Task,
|
|
|
|
|
Agent: input.Agent,
|
|
|
|
|
})
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
if !resumed {
|
|
|
|
|
// Clone repo into repo/
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
if r := s.gitCmd(ctx, ".", "clone", repoPath, repoDir); !r.OK {
|
2026-03-26 06:38:02 +00:00
|
|
|
return nil, PrepOutput{}, core.E("prep", core.Concat("git clone failed for ", input.Repo), nil)
|
refactor(agentic): route file I/O through core.Fs
Replace raw os.* file operations with Core Fs equivalents:
- os.Stat → fs.Exists/fs.IsFile/fs.IsDir (resume, pr, plan, mirror, prep)
- os.ReadDir → fs.List (queue, status, plan, mirror, review_queue)
- os.Remove → fs.Delete (dispatch)
- os.OpenFile(append) → fs.Append (events, review_queue)
- strings.Replace → core.Replace (scan)
Eliminates os import from resume.go, pr.go. Eliminates strings
import from scan.go. Trades os for io in events.go.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:45 +00:00
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Create feature branch
|
|
|
|
|
taskSlug := sanitiseBranchSlug(input.Task, 40)
|
|
|
|
|
if taskSlug == "" {
|
|
|
|
|
if input.Issue > 0 {
|
|
|
|
|
taskSlug = core.Sprintf("issue-%d", input.Issue)
|
|
|
|
|
} else if input.PR > 0 {
|
|
|
|
|
taskSlug = core.Sprintf("pr-%d", input.PR)
|
|
|
|
|
} else {
|
|
|
|
|
taskSlug = core.Sprintf("work-%d", time.Now().Unix())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
branchName := core.Sprintf("agent/%s", taskSlug)
|
2026-03-16 11:10:33 +00:00
|
|
|
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
if r := s.gitCmd(ctx, repoDir, "checkout", "-b", branchName); !r.OK {
|
|
|
|
|
return nil, PrepOutput{}, core.E("prep.branch", core.Sprintf("failed to create branch %q", branchName), nil)
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
|
|
|
|
out.Branch = branchName
|
|
|
|
|
} else {
|
|
|
|
|
// Resume: read branch from existing checkout
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
out.Branch = s.gitOutput(ctx, repoDir, "rev-parse", "--abbrev-ref", "HEAD")
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-27 06:50:54 +00:00
|
|
|
// Overwrite CODEX.md with language-specific version if needed.
|
|
|
|
|
// The default template is Go-focused. PHP repos get CODEX-PHP.md instead.
|
|
|
|
|
lang := detectLanguage(repoPath)
|
|
|
|
|
if lang == "php" {
|
|
|
|
|
if r := lib.WorkspaceFile("default", "CODEX-PHP.md.tmpl"); r.OK {
|
|
|
|
|
codexPath := core.JoinPath(wsDir, "CODEX.md")
|
|
|
|
|
fs.Write(codexPath, r.Value.(string))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 07:37:43 +00:00
|
|
|
// Clone workspace dependencies — Core modules needed to build the repo.
|
|
|
|
|
// Reads go.mod, finds dappco.re/go/core/* imports, clones from Forge,
|
|
|
|
|
// and updates go.work so the agent can build inside the workspace.
|
|
|
|
|
s.cloneWorkspaceDeps(ctx, wsDir, repoDir, input.Org)
|
|
|
|
|
|
2026-03-27 04:39:06 +00:00
|
|
|
// Clone ecosystem docs into .core/reference/ so agents have full documentation.
|
|
|
|
|
// The docs site (core.help) has architecture guides, specs, and API references.
|
|
|
|
|
docsDir := core.JoinPath(wsDir, ".core", "reference", "docs")
|
|
|
|
|
if !fs.IsDir(docsDir) {
|
|
|
|
|
docsRepo := core.JoinPath(s.codePath, input.Org, "docs")
|
|
|
|
|
if fs.IsDir(core.JoinPath(docsRepo, ".git")) {
|
|
|
|
|
s.gitCmd(ctx, ".", "clone", "--depth", "1", docsRepo, docsDir)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 09:22:58 +01:00
|
|
|
// Copy RFC specs from plans repo into workspace specs/ folder.
|
|
|
|
|
// Maps repo name to plans directory: go-io → core/go/io/, go-process → core/go/process/, etc.
|
|
|
|
|
s.copyRepoSpecs(wsDir, input.Repo)
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Build the rich prompt with all context
|
|
|
|
|
out.Prompt, out.Memories, out.Consumers = s.buildPrompt(ctx, input, out.Branch, repoPath)
|
2026-03-16 11:10:33 +00:00
|
|
|
|
|
|
|
|
out.Success = true
|
|
|
|
|
return nil, out, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 09:22:58 +01:00
|
|
|
// --- Spec Injection ---
|
|
|
|
|
|
|
|
|
|
// copyRepoSpecs copies RFC spec files from the plans repo into the workspace specs/ folder.
|
|
|
|
|
// Maps repo name to plans directory: go-io → core/go/io, agent → core/agent, core-bio → core/php/bio.
|
|
|
|
|
// Preserves subdirectory structure so sub-package specs land in specs/{pkg}/RFC.md.
|
|
|
|
|
//
|
|
|
|
|
// s.copyRepoSpecs("/tmp/ws", "go-io") // copies plans/core/go/io/**/RFC*.md → /tmp/ws/specs/
|
|
|
|
|
// s.copyRepoSpecs("/tmp/ws", "core-bio") // copies plans/core/php/bio/**/RFC*.md → /tmp/ws/specs/
|
|
|
|
|
func (s *PrepSubsystem) copyRepoSpecs(wsDir, repo string) {
|
|
|
|
|
fs := (&core.Fs{}).NewUnrestricted()
|
|
|
|
|
|
|
|
|
|
// Plans repo base — look for it relative to codePath
|
|
|
|
|
plansBase := core.JoinPath(s.codePath, "host-uk", "core", "plans")
|
|
|
|
|
if !fs.IsDir(plansBase) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Map repo name to plans directory
|
|
|
|
|
var specDir string
|
|
|
|
|
switch {
|
|
|
|
|
case core.HasPrefix(repo, "go-"):
|
|
|
|
|
// go-io → core/go/io, go-process → core/go/process
|
|
|
|
|
pkg := core.TrimPrefix(repo, "go-")
|
|
|
|
|
specDir = core.JoinPath(plansBase, "core", "go", pkg)
|
|
|
|
|
case core.HasPrefix(repo, "core-"):
|
|
|
|
|
// core-bio → core/php/bio, core-social → core/php/social
|
|
|
|
|
mod := core.TrimPrefix(repo, "core-")
|
|
|
|
|
specDir = core.JoinPath(plansBase, "core", "php", mod)
|
|
|
|
|
case repo == "go":
|
|
|
|
|
specDir = core.JoinPath(plansBase, "core", "go")
|
|
|
|
|
default:
|
|
|
|
|
// agent → core/agent, mcp → core/mcp, cli → core/go/cli, ide → core/ide
|
|
|
|
|
specDir = core.JoinPath(plansBase, "core", repo)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !fs.IsDir(specDir) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Glob RFC*.md at each depth level (root, 1 deep, 2 deep, 3 deep).
|
|
|
|
|
// Preserves subdirectory structure: specDir/pkg/sub/RFC.md → specs/pkg/sub/RFC.md
|
|
|
|
|
specsDir := core.JoinPath(wsDir, "specs")
|
|
|
|
|
fs.EnsureDir(specsDir)
|
|
|
|
|
|
|
|
|
|
patterns := []string{
|
|
|
|
|
core.JoinPath(specDir, "RFC*.md"),
|
|
|
|
|
core.JoinPath(specDir, "*", "RFC*.md"),
|
|
|
|
|
core.JoinPath(specDir, "*", "*", "RFC*.md"),
|
|
|
|
|
core.JoinPath(specDir, "*", "*", "*", "RFC*.md"),
|
|
|
|
|
}
|
|
|
|
|
for _, pattern := range patterns {
|
|
|
|
|
for _, entry := range core.PathGlob(pattern) {
|
|
|
|
|
rel := entry[len(specDir)+1:]
|
|
|
|
|
dst := core.JoinPath(specsDir, rel)
|
|
|
|
|
fs.EnsureDir(core.PathDir(dst))
|
|
|
|
|
r := fs.Read(entry)
|
|
|
|
|
if r.OK {
|
|
|
|
|
fs.Write(dst, r.Value.(string))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 14:15:41 +00:00
|
|
|
// --- Public API for CLI testing ---
|
|
|
|
|
|
|
|
|
|
// TestPrepWorkspace exposes prepWorkspace for CLI testing.
|
|
|
|
|
//
|
|
|
|
|
// _, out, err := prep.TestPrepWorkspace(ctx, input)
|
|
|
|
|
func (s *PrepSubsystem) TestPrepWorkspace(ctx context.Context, input PrepInput) (*mcp.CallToolResult, PrepOutput, error) {
|
|
|
|
|
return s.prepWorkspace(ctx, nil, input)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TestBuildPrompt exposes buildPrompt for CLI testing.
|
|
|
|
|
//
|
|
|
|
|
// prompt, memories, consumers := prep.TestBuildPrompt(ctx, input, "dev", repoPath)
|
|
|
|
|
func (s *PrepSubsystem) TestBuildPrompt(ctx context.Context, input PrepInput, branch, repoPath string) (string, int, int) {
|
|
|
|
|
return s.buildPrompt(ctx, input, branch, repoPath)
|
|
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// --- Prompt Building ---
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// buildPrompt assembles all context into a single prompt string.
|
|
|
|
|
// Context is gathered from: persona, flow, issue, brain, consumers, git log, wiki, plan.
|
|
|
|
|
func (s *PrepSubsystem) buildPrompt(ctx context.Context, input PrepInput, branch, repoPath string) (string, int, int) {
|
|
|
|
|
b := core.NewBuilder()
|
|
|
|
|
memories := 0
|
|
|
|
|
consumers := 0
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Task
|
|
|
|
|
b.WriteString("TASK: ")
|
|
|
|
|
b.WriteString(input.Task)
|
|
|
|
|
b.WriteString("\n\n")
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Repo info
|
|
|
|
|
b.WriteString(core.Sprintf("REPO: %s/%s on branch %s\n", input.Org, input.Repo, branch))
|
|
|
|
|
b.WriteString(core.Sprintf("LANGUAGE: %s\n", detectLanguage(repoPath)))
|
|
|
|
|
b.WriteString(core.Sprintf("BUILD: %s\n", detectBuildCmd(repoPath)))
|
|
|
|
|
b.WriteString(core.Sprintf("TEST: %s\n\n", detectTestCmd(repoPath)))
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Persona
|
|
|
|
|
if input.Persona != "" {
|
|
|
|
|
if r := lib.Persona(input.Persona); r.OK {
|
|
|
|
|
b.WriteString("PERSONA:\n")
|
|
|
|
|
b.WriteString(r.Value.(string))
|
|
|
|
|
b.WriteString("\n\n")
|
|
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Flow
|
|
|
|
|
if r := lib.Flow(detectLanguage(repoPath)); r.OK {
|
|
|
|
|
b.WriteString("WORKFLOW:\n")
|
|
|
|
|
b.WriteString(r.Value.(string))
|
|
|
|
|
b.WriteString("\n\n")
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Issue body
|
|
|
|
|
if input.Issue > 0 {
|
|
|
|
|
if body := s.getIssueBody(ctx, input.Org, input.Repo, input.Issue); body != "" {
|
|
|
|
|
b.WriteString("ISSUE:\n")
|
|
|
|
|
b.WriteString(body)
|
|
|
|
|
b.WriteString("\n\n")
|
|
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Brain recall
|
|
|
|
|
if recall, count := s.brainRecall(ctx, input.Repo); recall != "" {
|
|
|
|
|
b.WriteString("CONTEXT (from OpenBrain):\n")
|
|
|
|
|
b.WriteString(recall)
|
|
|
|
|
b.WriteString("\n\n")
|
|
|
|
|
memories = count
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Consumers
|
|
|
|
|
if list, count := s.findConsumersList(input.Repo); list != "" {
|
|
|
|
|
b.WriteString("CONSUMERS (modules that import this repo):\n")
|
|
|
|
|
b.WriteString(list)
|
|
|
|
|
b.WriteString("\n\n")
|
|
|
|
|
consumers = count
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Recent git log
|
|
|
|
|
if log := s.getGitLog(repoPath); log != "" {
|
|
|
|
|
b.WriteString("RECENT CHANGES:\n```\n")
|
|
|
|
|
b.WriteString(log)
|
|
|
|
|
b.WriteString("```\n\n")
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Plan template
|
|
|
|
|
if input.PlanTemplate != "" {
|
|
|
|
|
if plan := s.renderPlan(input.PlanTemplate, input.Variables, input.Task); plan != "" {
|
|
|
|
|
b.WriteString("PLAN:\n")
|
|
|
|
|
b.WriteString(plan)
|
|
|
|
|
b.WriteString("\n\n")
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// Constraints
|
|
|
|
|
b.WriteString("CONSTRAINTS:\n")
|
|
|
|
|
b.WriteString("- Read CODEX.md for coding conventions (if it exists)\n")
|
|
|
|
|
b.WriteString("- Read CLAUDE.md for project-specific instructions (if it exists)\n")
|
|
|
|
|
b.WriteString("- Commit with conventional commit format: type(scope): description\n")
|
|
|
|
|
b.WriteString("- Co-Authored-By: Virgil <virgil@lethean.io>\n")
|
|
|
|
|
b.WriteString("- Run build and tests before committing\n")
|
|
|
|
|
|
|
|
|
|
return b.String(), memories, consumers
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// --- Context Helpers (return strings, not write files) ---
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
func (s *PrepSubsystem) getIssueBody(ctx context.Context, org, repo string, issue int) string {
|
2026-03-22 14:15:41 +00:00
|
|
|
idx := core.Sprintf("%d", issue)
|
|
|
|
|
iss, err := s.forge.Issues.Get(ctx, forge.Params{"owner": org, "repo": repo, "index": idx})
|
|
|
|
|
if err != nil {
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
return ""
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
2026-03-22 14:15:41 +00:00
|
|
|
return core.Sprintf("# %s\n\n%s", iss.Title, iss.Body)
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
func (s *PrepSubsystem) brainRecall(ctx context.Context, repo string) (string, int) {
|
2026-03-16 11:10:33 +00:00
|
|
|
if s.brainKey == "" {
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
return "", 0
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
body := core.JSONMarshalString(map[string]any{
|
|
|
|
|
"query": core.Concat("architecture conventions key interfaces for ", repo),
|
2026-03-16 11:10:33 +00:00
|
|
|
"top_k": 10,
|
|
|
|
|
"project": repo,
|
|
|
|
|
"agent_id": "cladius",
|
|
|
|
|
})
|
|
|
|
|
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
r := HTTPPost(ctx, core.Concat(s.brainURL, "/v1/brain/recall"), body, s.brainKey, "Bearer")
|
|
|
|
|
if !r.OK {
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
return "", 0
|
2026-03-17 19:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 11:10:33 +00:00
|
|
|
var result struct {
|
|
|
|
|
Memories []map[string]any `json:"memories"`
|
|
|
|
|
}
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
core.JSONUnmarshalString(r.Value.(string), &result)
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
if len(result.Memories) == 0 {
|
|
|
|
|
return "", 0
|
|
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
b := core.NewBuilder()
|
2026-03-16 11:10:33 +00:00
|
|
|
for i, mem := range result.Memories {
|
|
|
|
|
memType, _ := mem["type"].(string)
|
|
|
|
|
memContent, _ := mem["content"].(string)
|
|
|
|
|
memProject, _ := mem["project"].(string)
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
b.WriteString(core.Sprintf("%d. [%s] %s: %s\n", i+1, memType, memProject, memContent))
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
return b.String(), len(result.Memories)
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
func (s *PrepSubsystem) findConsumersList(repo string) (string, int) {
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
goWorkPath := core.JoinPath(s.codePath, "go.work")
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
modulePath := core.Concat("forge.lthn.ai/core/", repo)
|
2026-03-16 11:10:33 +00:00
|
|
|
|
2026-03-22 03:41:07 +00:00
|
|
|
r := fs.Read(goWorkPath)
|
|
|
|
|
if !r.OK {
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
return "", 0
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
2026-03-22 03:41:07 +00:00
|
|
|
workData := r.Value.(string)
|
2026-03-16 11:10:33 +00:00
|
|
|
|
|
|
|
|
var consumers []string
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
for _, line := range core.Split(workData, "\n") {
|
|
|
|
|
line = core.Trim(line)
|
|
|
|
|
if !core.HasPrefix(line, "./") {
|
2026-03-16 11:10:33 +00:00
|
|
|
continue
|
|
|
|
|
}
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
dir := core.JoinPath(s.codePath, core.TrimPrefix(line, "./"))
|
|
|
|
|
goMod := core.JoinPath(dir, "go.mod")
|
2026-03-22 03:41:07 +00:00
|
|
|
mr := fs.Read(goMod)
|
|
|
|
|
if !mr.OK {
|
2026-03-16 11:10:33 +00:00
|
|
|
continue
|
|
|
|
|
}
|
2026-03-22 03:41:07 +00:00
|
|
|
modData := mr.Value.(string)
|
2026-03-26 06:38:02 +00:00
|
|
|
if core.Contains(modData, modulePath) && !core.HasPrefix(modData, core.Concat("module ", modulePath)) {
|
refactor(agentic): adopt core.Env() + core.Path() across package
Replace all os.UserHomeDir/os.Getenv/os.Hostname with core.Env().
Replace all filepath.Base/Dir/Glob/IsAbs with core.PathBase/PathDir/
PathGlob/PathIsAbs.
10 files migrated: paths, prep, review_queue, remote, dispatch,
ingest, mirror, plan, verify, watch.
Imports eliminated: 5x os, 7x filepath. All file I/O and path
construction now routes through Core primitives.
Bumps dappco.re/go/core to v0.6.0.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 10:15:15 +00:00
|
|
|
consumers = append(consumers, core.PathBase(dir))
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
if len(consumers) == 0 {
|
|
|
|
|
return "", 0
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
b := core.NewBuilder()
|
|
|
|
|
for _, c := range consumers {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
b.WriteString(core.Concat("- ", c, "\n"))
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
|
|
|
|
b.WriteString(core.Sprintf("Breaking change risk: %d consumers.\n", len(consumers)))
|
|
|
|
|
|
|
|
|
|
return b.String(), len(consumers)
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
func (s *PrepSubsystem) getGitLog(repoPath string) string {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
return s.gitOutput(context.Background(), repoPath, "log", "--oneline", "-20")
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
func (s *PrepSubsystem) pullWikiContent(ctx context.Context, org, repo string) string {
|
2026-03-22 14:15:41 +00:00
|
|
|
pages, err := s.forge.Wiki.ListPages(ctx, org, repo)
|
|
|
|
|
if err != nil || len(pages) == 0 {
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
return ""
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
b := core.NewBuilder()
|
2026-03-22 14:15:41 +00:00
|
|
|
for _, meta := range pages {
|
|
|
|
|
name := meta.SubURL
|
|
|
|
|
if name == "" {
|
|
|
|
|
name = meta.Title
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
2026-03-22 14:15:41 +00:00
|
|
|
page, pErr := s.forge.Wiki.GetPage(ctx, org, repo, name)
|
|
|
|
|
if pErr != nil || page.ContentBase64 == "" {
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
continue
|
|
|
|
|
}
|
2026-03-22 14:15:41 +00:00
|
|
|
content, _ := base64.StdEncoding.DecodeString(page.ContentBase64)
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
b.WriteString(core.Concat("### ", meta.Title, "\n\n"))
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
b.WriteString(string(content))
|
|
|
|
|
b.WriteString("\n\n")
|
|
|
|
|
}
|
|
|
|
|
return b.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *PrepSubsystem) renderPlan(templateSlug string, variables map[string]string, task string) string {
|
|
|
|
|
r := lib.Template(templateSlug)
|
|
|
|
|
if !r.OK {
|
|
|
|
|
return ""
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
content := r.Value.(string)
|
|
|
|
|
for key, value := range variables {
|
2026-03-26 06:38:02 +00:00
|
|
|
content = core.Replace(content, core.Concat("{{", key, "}}"), value)
|
|
|
|
|
content = core.Replace(content, core.Concat("{{ ", key, " }}"), value)
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
var tmpl struct {
|
|
|
|
|
Name string `yaml:"name"`
|
|
|
|
|
Description string `yaml:"description"`
|
|
|
|
|
Guidelines []string `yaml:"guidelines"`
|
|
|
|
|
Phases []struct {
|
|
|
|
|
Name string `yaml:"name"`
|
|
|
|
|
Description string `yaml:"description"`
|
|
|
|
|
Tasks []any `yaml:"tasks"`
|
|
|
|
|
} `yaml:"phases"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := yaml.Unmarshal([]byte(content), &tmpl); err != nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
plan := core.NewBuilder()
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
plan.WriteString(core.Concat("# ", tmpl.Name, "\n\n"))
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
if task != "" {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
plan.WriteString(core.Concat("**Task:** ", task, "\n\n"))
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
|
|
|
|
if tmpl.Description != "" {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
plan.WriteString(core.Concat(tmpl.Description, "\n\n"))
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(tmpl.Guidelines) > 0 {
|
|
|
|
|
plan.WriteString("## Guidelines\n\n")
|
|
|
|
|
for _, g := range tmpl.Guidelines {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
plan.WriteString(core.Concat("- ", g, "\n"))
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
|
|
|
|
plan.WriteString("\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i, phase := range tmpl.Phases {
|
|
|
|
|
plan.WriteString(core.Sprintf("## Phase %d: %s\n\n", i+1, phase.Name))
|
|
|
|
|
if phase.Description != "" {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
plan.WriteString(core.Concat(phase.Description, "\n\n"))
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
|
|
|
|
for _, t := range phase.Tasks {
|
|
|
|
|
switch v := t.(type) {
|
|
|
|
|
case string:
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
plan.WriteString(core.Concat("- [ ] ", v, "\n"))
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
case map[string]any:
|
|
|
|
|
if name, ok := v["name"].(string); ok {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
plan.WriteString(core.Concat("- [ ] ", name, "\n"))
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
plan.WriteString("\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return plan.String()
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
2026-03-18 14:03:06 +00:00
|
|
|
|
refactor(agentic): workspace = clone, prompt replaces files
Major simplification of the dispatch model:
- Workspace dir: .core/workspace/{org}/{repo}/{pr|task|branch|tag}/
- Clone into repo/ (not src/), metadata in .meta/
- One of issue, pr, branch, or tag required for dispatch
- All context (brain, consumers, git log, wiki, plan) assembled
into prompt string — no TODO.md, PROMPT.md, CONTEXT.md files
- Resume detection: skip clone if repo/.git exists
- Default agent changed to codex
- spawnAgent drops srcDir param, runs from repo/
- No --skip-git-repo-check (repo/ IS a git repo)
- All downstream files: srcDir → repoDir
Track PRs, not workspace iterations.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:41:59 +00:00
|
|
|
// --- Detection helpers (unchanged) ---
|
|
|
|
|
|
2026-03-18 14:03:06 +00:00
|
|
|
func detectLanguage(repoPath string) string {
|
2026-03-21 17:10:43 +00:00
|
|
|
checks := []struct {
|
|
|
|
|
file string
|
|
|
|
|
lang string
|
|
|
|
|
}{
|
|
|
|
|
{"go.mod", "go"},
|
|
|
|
|
{"composer.json", "php"},
|
|
|
|
|
{"package.json", "ts"},
|
|
|
|
|
{"Cargo.toml", "rust"},
|
|
|
|
|
{"requirements.txt", "py"},
|
|
|
|
|
{"CMakeLists.txt", "cpp"},
|
|
|
|
|
{"Dockerfile", "docker"},
|
|
|
|
|
}
|
|
|
|
|
for _, c := range checks {
|
refactor(agentic): route file I/O through core.Fs
Replace raw os.* file operations with Core Fs equivalents:
- os.Stat → fs.Exists/fs.IsFile/fs.IsDir (resume, pr, plan, mirror, prep)
- os.ReadDir → fs.List (queue, status, plan, mirror, review_queue)
- os.Remove → fs.Delete (dispatch)
- os.OpenFile(append) → fs.Append (events, review_queue)
- strings.Replace → core.Replace (scan)
Eliminates os import from resume.go, pr.go. Eliminates strings
import from scan.go. Trades os for io in events.go.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:45 +00:00
|
|
|
if fs.IsFile(core.JoinPath(repoPath, c.file)) {
|
2026-03-21 17:10:43 +00:00
|
|
|
return c.lang
|
2026-03-18 14:03:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return "go"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func detectBuildCmd(repoPath string) string {
|
|
|
|
|
switch detectLanguage(repoPath) {
|
|
|
|
|
case "go":
|
|
|
|
|
return "go build ./..."
|
|
|
|
|
case "php":
|
|
|
|
|
return "composer install"
|
|
|
|
|
case "ts":
|
|
|
|
|
return "npm run build"
|
|
|
|
|
case "py":
|
|
|
|
|
return "pip install -e ."
|
|
|
|
|
case "rust":
|
|
|
|
|
return "cargo build"
|
|
|
|
|
case "cpp":
|
|
|
|
|
return "cmake --build ."
|
|
|
|
|
default:
|
|
|
|
|
return "go build ./..."
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func detectTestCmd(repoPath string) string {
|
|
|
|
|
switch detectLanguage(repoPath) {
|
|
|
|
|
case "go":
|
|
|
|
|
return "go test ./..."
|
|
|
|
|
case "php":
|
|
|
|
|
return "composer test"
|
|
|
|
|
case "ts":
|
|
|
|
|
return "npm test"
|
|
|
|
|
case "py":
|
|
|
|
|
return "pytest"
|
|
|
|
|
case "rust":
|
|
|
|
|
return "cargo test"
|
|
|
|
|
case "cpp":
|
|
|
|
|
return "ctest"
|
|
|
|
|
default:
|
|
|
|
|
return "go test ./..."
|
|
|
|
|
}
|
|
|
|
|
}
|