Commit graph

242 commits

Author SHA1 Message Date
Snider
d9e7fa092b feat: complete DI migration — IPC pipeline + Config + Locks
Phase 4 complete:
- Auto-PR handler emits PRCreated message
- Verify handler listens for PRCreated, emits PRMerged/PRNeedsReview
- findWorkspaceByPR() for workspace lookup from PR events
- Remove legacy inline fallback from dispatch goroutine

Phase 5 complete:
- agents.yaml loaded once at startup into c.Config()
- canDispatchAgent reads from c.Config() (no re-parsing)
- drainQueue uses c.Lock("drain") when Core available

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 16:44:19 +00:00
Snider
4e69daf2da feat: replace initServices() with core.New() service conclave
Services are now registered during Core construction:
  core.New(
      core.WithService(agentic.Register),
      core.WithService(monitor.Register),
      core.WithService(brain.Register),
  )

- Remove initServices() closure — services created once in conclave
- Commands use c.ServiceStartup()/c.ServiceShutdown() for lifecycle
- Service instances retrieved via c.Config() for MCP tool registration
- run/orchestrator reduced to ServiceStartup + block + ServiceShutdown
- run/task uses conclave's agentic instance

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 16:33:04 +00:00
Snider
9f8a63ae21 feat: Register() factories + consume new core.New() API
Each package exposes Register(c *Core) Result for core.WithService():
- agentic.Register: creates PrepSubsystem, wires IPC handlers, lifecycle
- monitor.Register: creates Subsystem, wires IPC handler, lifecycle
- brain.Register: creates Direct, registers service

main.go updated for core.New() returning Result.
Ready for core.New(WithService(agentic.Register)) pattern.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 16:23:44 +00:00
Snider
cdb29a2f75 feat(ipc): replace CompletionNotifier callbacks with Core IPC messages
Phase 3 of Core DI migration:
- Remove CompletionNotifier interface from pkg/agentic
- dispatch.go emits messages.AgentStarted/AgentCompleted via c.ACTION()
- monitor registers IPC handlers in SetCore() — handleAgentStarted/handleAgentCompleted
- Remove circular callback wiring (SetCompletionNotifier) from main.go
- Export ReadStatus for cross-package use
- Update run/orchestrator to use SetCore() instead of SetCompletionNotifier()

Services now communicate through typed messages, not direct references.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 14:46:59 +00:00
Snider
bb88604045 feat(core): wire Core framework into agentic + monitor subsystems
Phase 2 of Core DI migration:
- Add *core.Core field + SetCore() to PrepSubsystem and monitor.Subsystem
- Register agentic/monitor/brain as Core services with lifecycle hooks
- Mark SetCompletionNotifier and SetNotifier as deprecated (removed in Phase 3)
- Fix monitor test to match actual event names
- initServices() now wires Core refs before legacy callbacks

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 14:44:53 +00:00
Snider
781a5b414e feat(messages): define IPC message types for inter-service communication
12 message types covering: agent lifecycle (Started/Completed),
QA+PR pipeline (QAResult/PRCreated/PRMerged/PRNeedsReview),
queue orchestration (QueueDrained/PokeQueue/RateLimitDetected),
monitor events (HarvestComplete/HarvestRejected/InboxMessage).

These replace the CompletionNotifier and ChannelNotifier callback
interfaces with typed broadcast messages via c.ACTION().

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 14:44:23 +00:00
b5873a8f31 Merge pull request 'fix(monitor): agent.completed events + nested concurrency config' (#16) from feat/monitor-notifications-and-concurrency into dev
Reviewed-on: #16
2026-03-24 14:44:02 +00:00
Snider
53acf4000d feat(concurrency): nested per-model limits under agent pools
Concurrency config now supports both flat and nested formats:

  claude: 1                    # flat — 1 total
  codex:                       # nested — 2 total, per-model caps
    total: 2
    gpt-5.4: 1
    gpt-5.3-codex-spark: 1

canDispatchAgent checks pool total first, then per-model limit.
countRunningByModel added for exact agent string matching.
ConcurrencyLimit custom YAML unmarshaler handles both int and map.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 13:05:41 +00:00
Snider
04e3d492e9 fix(monitor): emit agent.completed per task, verify PIDs for queue.drained
- Export ReadStatus (was readStatus) for cross-package use
- AgentCompleted now emits agent.completed with repo/agent/workspace/status
  for every finished task, not just failures
- queue.drained only fires when genuinely empty — verified by checking
  PIDs are alive via kill(0), not just trusting stale status files
- Fix Docker mount paths: /root/ → /home/dev/ for non-root container
- Update all callers and tests

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 13:02:41 +00:00
d305663573 Merge branch 'main' into dev 2026-03-24 10:24:09 +00:00
Snider
dba621c108 feat(update): version injection via ldflags, park update command
- var version set by build ldflags (-X dappco.re/go/agent.version=X)
- Channel detection (stable/prerelease/dev) from version string
- Update command parked until version moves to module root
- Add Makefile with build/install/test targets + VERSION support

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-23 16:50:54 +00:00
Snider
50c06dc4df chore: align binary version with plugin (0.15.0)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-23 16:09:25 +00:00
Snider
9bdd47d9d5 feat(agent): v0.3.0 — dispatch control, run task CLI, quiet notifications, spark pool
- Add agentic_dispatch_start / shutdown / shutdown_now MCP tools
- Queue frozen by default, CORE_AGENT_DISPATCH=1 to auto-start
- Add run task CLI command — single task e2e (prep → spawn → wait)
- Add DispatchSync for blocking dispatch without MCP
- Quiet notifications — only agent.failed and queue.drained events
- Remove duplicate notification paths (direct callback + polling loop)
- codex-spark gets separate concurrency pool (baseAgent routing)
- Rate-limit backoff detection (3 fast failures → 30min pause)
- Review agent uses exec with sandbox bypass (not codex review)
- Bump: core-agent 0.3.0, core plugin 0.15.0, devops plugin 0.2.0

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-23 16:08:08 +00:00
Snider
6d4b92737e feat(agent): background runner, slim status, Docker dispatch, stopwatch, CLI fixes
- Add background queue runner (runner.go) — 30s tick + poke on completion
- drainQueue now loops to fill all slots per tick
- Add run orchestrator command — standalone queue runner without MCP
- Slim agentic_status — stats only, blocked workspaces listed
- Docker containerised dispatch — all agents run in core-dev container
- Forge stopwatch start/stop on issue when agent starts/completes
- issue create supports --milestone, --assignee, --ref
- Auto-PR targets dev branch (not main)
- PR body includes Closes #N for issue-linked work
- CLI usage strings use spaces not slashes
- Review agent uses exec with sandbox bypass (not codex review subcommand)
- Local model support via codex --oss with socat Ollama proxy

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-23 12:53:33 +00:00
Snider
9b225af2f9 refactor(monitor): direct event push, no filesystem polling
CompletionNotifier interface now has AgentStarted() and
AgentCompleted() instead of Poke(). Dispatch pushes notifications
directly to monitor with agent/repo/status data. Monitor pushes
MCP channel events immediately — no scanning, no dedup maps,
no filesystem polling latency.

Events.jsonl kept as audit log only, not notification mechanism.
Timer-based scan kept for startup seeding and stale detection.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 16:19:13 +00:00
Snider
c04d3442dd fix(monitor): use full workspace path as dedup key
filepath.Base gave just "main" — every branch-based workspace
collided in seenCompleted map. Now uses relative path like
"core/go/main" for unique deduplication.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 16:11:38 +00:00
Snider
a3ca68e2bd fix(status): scan new workspace layout for agentic_status
Status MCP tool only scanned one level deep (*/status.json).
New workspaces at */*/*/status.json were invisible. Now scans
both layouts. Also removed unused os/filepath imports.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 16:03:11 +00:00
Snider
c484eab2fc fix(monitor): restore sync helpers lost in rebase
monitorAPIURL, monitorBrainKey, monitorHomeDir, monitorPath were
added by Codex on remote dev but lost when we force-pushed after
rebase conflict. Restored with simplified Core.Env() usage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:52:10 +00:00
Snider
39255b1766 fix(queue): scan new workspace layout for concurrency counting
countRunningByAgent only scanned one level deep (*/status.json)
but new workspaces are at */*/*/status.json. Concurrency limits
weren't enforced — all agents dispatched as running instead of
queuing. Now scans both old and new layouts.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:32 +00:00
Snider
e9224b18b8 refactor(devops): convert operational skills to agent tasks
Skills I trigger (not the user) become agent tasks:
- clean-workspaces, repair-core-agent, merge-workspace, health-check

Keeps as skills (user-invoked CLI wrappers):
- forge commands (issue/pr/repo), workspace-list/clean,
  build-prompt, update-deps

Agent tasks use haiku/sonnet for fast autonomous execution.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:32 +00:00
Snider
73cac920ce refactor(devops): convert install-core-agent from skill to agent task
Agent tasks can be triggered proactively by Claude without slash
commands. Uses haiku model for fast execution. Same rules — go
install from the right directory, never touch binaries directly.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:32 +00:00
Snider
24fdaa3bad fix: extract default workspace template for go.work
QA gate failed because cloned repos weren't in a Go workspace.
Extract default template (including go.work with use ./repo)
into workspace dir before cloning. Fixes go test isolation.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:32 +00:00
Snider
4bcc04d890 feat(monitor): agent.started + agent.complete channel notifications
- emitStartEvent fires when agent spawns (dispatch.go)
- Monitor detects new "running" workspaces and pushes agent.started
  channel notification with repo and agent info
- agent.complete already included blocked/failed status — no change
- Both old and new workspace layouts supported

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:32 +00:00
Snider
abe5ef342a fix(monitor): scan new workspace layout for channel notifications
workspaceStatusPaths scans both old (*/status.json) and new
(*/*/*/status.json) workspace layouts. Fixes agent.complete
channel notifications not firing for org/repo/identifier paths.

Replaces filepath.Glob with core.PathGlob in harvest.go.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:32 +00:00
Snider
69f0acce0d fix(dispatch): model flag splice broke -o argument ordering
When model variant was specified, the splice inserted --model
between -o and its value, making Codex see -o with no file path.
Fixed by appending --model and prompt sequentially instead of
splicing into the middle of the args slice.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:16 +00:00
Snider
c73ea6ad7a fix(dispatch): strip model variant from log filename
Agent name like "codex:gpt-5.3-codex-spark" contains a colon which
breaks file paths. Use base name (before ":") for the log file.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:16 +00:00
Snider
d6864eb37c feat(dispatch): QA gate before auto-PR
After agent completes, run build + vet + test before creating PR.
If QA fails, mark workspace as failed with "QA check failed" —
bad code never gets PR'd.

Supports Go (build/vet/test), PHP (composer install/test),
and Node (npm install/test). Unknown languages pass through.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:16 +00:00
Snider
7e30f336cc feat(devops): 13 CLI-backed skills for forge, workspace, and diagnostics
Thin skill wrappers over core-agent CLI commands:
- workspace-list, workspace-clean
- issue-get, issue-list, issue-comment
- pr-get, pr-list, pr-merge
- repo-get, repo-list
- build-prompt, health-check

Each skill calls core-agent directly — no raw API calls,
no remembering flags. Edge cases fixed in the skill.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:16 +00:00
Snider
f416948660 feat: workspace CLI commands — list, clean, dispatch stub
workspace/list shows all workspaces with status/agent/repo.
workspace/clean removes completed/failed/blocked/merged workspaces.
workspace/dispatch stub for future CLI-driven dispatch.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:16 +00:00
Snider
7f84ac8348 refactor(agentic): use go-forge library instead of raw HTTP
Replace raw http.Client calls with go-forge typed API:
- prep.go: getIssueBody via forge.Issues.Get, pullWikiContent
  via forge.Wiki.ListPages/GetPage
- pr.go: forgeCreatePR via forge.Pulls.Create, commentOnIssue
  via forge.Issues.CreateComment, listRepoPRs via forge.Pulls.ListAll
- scan.go: listOrgRepos via forge.Repos.ListOrgRepos

Eliminates manual JSON marshalling, auth headers, pagination loops,
and anonymous struct declarations. One Forge client, one auth,
type-safe responses.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:16 +00:00
Snider
bfe70871a2 feat: Forge CLI commands — issue, PR, and repo operations
New commands via go-forge library:
  issue/get, issue/list, issue/comment
  pr/get, pr/list, pr/merge
  repo/get, repo/list

Enables CLI-driven Forge interaction for dispatch automation.
Agent can now read issues, create PRs, merge, and list repos
without MCP.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:16 +00:00
Snider
6e03287178 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 15:45:16 +00:00
Snider
6e37bd22f0 feat: devops plugin, CLI commands, Codex dispatch fixes, AX sweep
DevOps plugin (5 skills):
- install-core-agent, repair-core-agent, merge-workspace,
  update-deps, clean-workspaces

CLI commands: version, check, extract for diagnostics.

Codex dispatch: --skip-git-repo-check, removed broken
--model-reasoning-effort, --sandbox workspace-write via
--full-auto. Workspace template extracts to wsDir not srcDir.

AX sweep (Codex-generated): sanitise.go extracted from prep/plan,
mirror.go JSON parsing via encoding/json, setup/config.go URL
parsing via net/url, strings/fmt imports eliminated from setup.

CODEX.md template updated with Env/Path patterns.
Review workspace template with audit-only PROMPT.md.
Marketplace updated with devops plugin.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:16 +00:00
Snider
98baa1b08f feat: inline tests + Fs zero-value fix + coverage 76.9% → 82.3%
Move all tests from tests/ to package root for proper coverage.
Fix Fs zero-value: path() and validatePath() default empty root
to "/" so &Fs{} works without New().

New tests: PathGlob, PathIsAbs, CleanPath, Cli.SetOutput,
ServiceShutdown, Core.Context, Fs zero-value, Fs protected
delete, Command lifecycle with implementation, error formatting
branches, PerformAsync completion/no-handler/after-shutdown,
Extract with templates, Embed path traversal.

Coverage: 76.9% → 82.3% (23 test files, 82 new test cases).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 15:45:04 +00:00
7f87e4d52c Merge pull request '[agent/codex] Fix ALL high-severity AX findings in pkg/monitor/ (monitor.g...' (#10) from agent/fix-all-high-severity-ax-findings-in-pkg into dev 2026-03-22 13:41:29 +00:00
Snider
9aac4c19dd refactor(monitor): adopt core helpers
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:40:14 +00:00
850ff4bc03 Merge pull request '[agent/codex] Fix ALL AX findings in pkg/brain/direct.go. Read CODEX.md. O...' (#9) from agent/fix-all-ax-findings-in-pkg-brain-direct into dev 2026-03-22 13:03:19 +00:00
Snider
ed842122a2 fix(brain): resolve direct AX findings
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 13:02:37 +00:00
Snider
a422eb1b6b feat(lib): add go.work.tmpl to workspace template
Codex agents are sandboxed to src/ and don't get ~/Code/go.work.
This template creates a go.work with `use .` so the Go toolchain
works in workspace mode inside the sandbox.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 10:18:57 +00:00
Snider
6393bfe4da 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
Snider
3022f05fb8 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
Snider
ede5d6f561 feat(lib): migrate to Core Embed system with Result returns
- All public functions return core.Result instead of (string, error)
- Mount scopes basedir — no path prefix needed in ReadString calls
- Add Bundle struct replacing (string, map, error) anti-pattern
- listDir takes *core.Embed not embed.FS
- ListTasks/ListPersonas use FS() + BaseDirectory() for WalkDir
- Remove bytes, os, text/template imports
- 22 tests: Prompt, Task, TaskBundle, Flow, Persona, Template,
  List functions, ExtractWorkspace (Good/Bad patterns)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:35 +00:00
Snider
3c5e6d6498 fix(lib): ExtractWorkspace now recurses into subdirectories
Was skipping directories entirely (`if entry.IsDir() { continue }`),
so .core/reference/ and its contents were never extracted.
Replaced fs.ReadDir loop with fs.WalkDir to handle nested dirs.

Added tests: CreatesFiles, CreatesSubdirectories, TemplateSubstitution.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 08:10:56 +00:00
Snider
e8ca0d856f feat(lib): embed Core documentation in workspace template
18 doc files from core/go/docs — getting-started, primitives,
services, commands, configuration, errors, lifecycle, messaging,
subsystems, testing. Agents can read full Core documentation
without network access.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 07:19:20 +00:00
Snider
5417f547ca feat(lib): add Core struct reference to CODEX.md template
Documents all subsystem accessors (App, Fs, Config, Data, Drive, Log,
Error, Cli, IPC, I18n, Options, Context), service lifecycle with
Startable/Stoppable interfaces, error logging (LogError/LogWarn/Must),
and async tasks (Perform/PerformAsync/Progress).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 07:17:27 +00:00
Snider
71ee6124b7 feat(lib): complete CODEX.md with all Core patterns
Added: Embed/Mount/Extract, error wrapping/codes/introspection,
Print, Array[T], Config, IPC (Action/Query/Perform), Services,
Commands, Drive, I18n. Every Core primitive documented with
WRONG/CORRECT examples.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 07:15:20 +00:00
Snider
99e1d06fda feat(lib): add CODEX.md template to default workspace
Inline instructions for Codex agents — no spec references,
just the actual rules with code examples. Extracted into every
workspace automatically.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 07:13:12 +00:00
Snider
b9c30138fb fix(lib): rename .gitignore to .gitignore.tmpl in workspace template
Prevents git from ignoring template contents. ExtractWorkspace strips
the .tmpl suffix during extraction.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 07:02:32 +00:00
Snider
6f5b239da6 feat(lib): embed AX spec + Core source in default workspace template
Reference files (.core/reference/) are now part of the embedded
workspace template. ExtractWorkspace extracts them automatically —
no hardcoded filesystem paths, ships with the binary.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:59:52 +00:00
Snider
4f66eb4cca fix: resolve final AX audit findings
- cmd/main.go: keyed core.Result literals (go vet clean)
- pkg/brain/direct.go: compile-time mcp.Subsystem assertion
- pkg/monitor/monitor.go: compile-time Subsystem + CompletionNotifier assertions
- pkg/agentic/prep.go: alias stdlib io as goio
- pkg/agentic/remote_client.go: UK English (initialise/initialised)
- pkg/monitor/monitor_test.go: updated inbox tests for current contract

AX audit now returns 0 convention findings.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:42:42 +00:00