Runner now creates a reservation entry (PID=-1) in the workspace Registry
immediately when approving a dispatch. This prevents parallel requests
from all seeing count < limit before any spawn completes.
Reservations are counted by countRunningByAgent/ByModel (PID < 0 = always
count). Agentic overwrites with real PID via TrackWorkspace after spawn.
Co-Authored-By: Virgil <virgil@lethean.io>
StartRunner and Poke are now no-ops — runner.Service owns the queue.
Shutdown MCP tools delegate to runner.start/stop/kill Actions via IPC.
Updated 18 tests to verify delegation instead of direct state mutation.
Co-Authored-By: Virgil <virgil@lethean.io>
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>
parseCoreDeps now skips // indirect lines from go.mod.
Reduces cloned repos from 17 to 10 — only what the repo directly imports.
Co-Authored-By: Virgil <virgil@lethean.io>
- cloneWorkspaceDeps: reads go.mod, clones Core ecosystem modules from Forge
into workspace alongside ./repo, rebuilds go.work with all use directives
- Deduplicates deps (dappco.re + forge.lthn.ai map to same repos)
- Container chmod: workspace files made writable before exit so host can clean up
- GONOSUMCHECK for local workspace modules (bypass checksum for dev branches)
- Removed stale OLLAMA_HOST env from container
Co-Authored-By: Virgil <virgil@lethean.io>
The monitoring goroutine that waits for agent completion was a raw `go func()`
that Core didn't know about. ServiceShutdown killed it immediately on CLI exit.
Now uses PerformAsync which registers with Core's WaitGroup:
- ServiceShutdown waits for all async tasks to drain
- `core-agent workspace dispatch` blocks until agent completes
- Agent lifecycle properly tracked by the framework
Also whitelist agentic.monitor.* and agentic.complete in entitlement checker.
Co-Authored-By: Virgil <virgil@lethean.io>
The global process.StartWithOptions() requires process.SetDefault() which
was never called. Use core.ServiceFor[*process.Service] to get the registered
service instance directly — same code path, proper Core wiring.
Fixes: dispatch failing with "failed to spawn codex" on CLI dispatch.
Co-Authored-By: Virgil <virgil@lethean.io>
45 os/json calls replaced with Core primitives. os remains only for
os.Getpid() (no Core equivalent for PID as int).
Co-Authored-By: Virgil <virgil@lethean.io>
os.MkdirAll→fs.EnsureDir, os.WriteFile→fs.Write,
json.Marshal→core.JSONMarshalString, os.Stat→fs.Exists/fs.IsDir.
Both files now free of os + encoding/json.
Co-Authored-By: Virgil <virgil@lethean.io>
Partial migration of dispatch_test.go: 5 of 9 json.Marshal+os.WriteFile
pairs replaced with fs.Write+core.JSONMarshalString. Pattern established
for remaining 74 calls across 30 test files.
Co-Authored-By: Virgil <virgil@lethean.io>
Step-by-step: load 3 RFCs, verify understanding, work migration,
follow session cadence. Lists what NOT to do (10 disallowed imports,
no string concat, no anonymous closures, no nested ACTION).
Co-Authored-By: Virgil <virgil@lethean.io>
- Current State: lists every file that needs migration with specific action
- File Layout: annotated tree showing DELETE/REWRITE/MIGRATE per file
- MCP closure capture bug fixed (re-resolve action at call time)
- Message types location documented (pkg/messages/)
Future session reads this and knows exactly what to touch.
Co-Authored-By: Virgil <virgil@lethean.io>
AGENTS.md is the universal agent instructions — any model reads this.
CLAUDE.md stays as Claude-specific (hooks, permissions, memory).
CODEX.md and GEMINI.md removed — one source of truth.
Co-Authored-By: Virgil <virgil@lethean.io>
Standard llm.txt with package layout, test coverage stats, conventions.
Points to CLAUDE.md and RFC-025 for full specs.
Co-Authored-By: Virgil <virgil@lethean.io>
node_modules/ (1,135 files, 468k lines) and bin/core-agent were
accidentally committed in bb88604. Removed from tracking and added
to .gitignore.
Co-Authored-By: Virgil <virgil@lethean.io>
- RegisterTools: exercises all 12 register*Tool functions via mcp.NewServer (+1.4pp)
- buildPrompt: test with real git repo for RECENT CHANGES path
- AX-7: 92% categories filled
0.1pp from 80%. Remaining gap is process-dependent functions
awaiting go-process v0.7.0 update.
Co-Authored-By: Virgil <virgil@lethean.io>
- proc.go: ensureProcess() as temporary bridge until go-process gets v0.7.0 update
- processIsRunning/processKill: use go-process ProcessID when available, fall back to PID
- WorkspaceStatus: add ProcessID field for go-process managed lookup
- dispatch.go: simplified spawnAgent goroutine — uses proc.Done() instead of syscall poll
- Removed syscall import from dispatch.go
Next: update go-process to v0.7.0 Core contract, then replace
syscall.Kill calls in queue.go, shutdown.go, status.go, dispatch_sync.go
with processIsRunning/processKill.
Coverage: 78.1%, 802 tests
Co-Authored-By: Virgil <virgil@lethean.io>
Mechanical rename of all test functions to follow the convention:
TestFilename_FunctionName_{Good,Bad,Ugly}
Examples:
TestForgeMergePR_Good_Success → TestVerify_ForgeMergePR_Good_Success
TestAgentCommand_Good_Gemini → TestDispatch_AgentCommand_Good_Gemini
TestReadStatus_Bad_NoFile → TestStatus_ReadStatus_Bad_NoFile
Gap analysis now works: 137 functions still need 260 missing categories.
566 tests, agentic 74.3% — naming is now the tooling.
Co-Authored-By: Virgil <virgil@lethean.io>
Delete edge_case_test.go, coverage_push_test.go, dispatch_extra_test.go.
Rewrite dispatch_test.go with proper naming: TestDispatch_Function_{Good,Bad,Ugly}.
Every function in dispatch.go now has Good/Bad/Ugly test groups.
Tests for non-dispatch functions will be restored to their correct files.
agentic 72.6% (temporary regression — tests being redistributed)
Co-Authored-By: Virgil <virgil@lethean.io>
Add httptest mocks for startIssueTracking/stopIssueTracking with Forge,
broadcastStart/broadcastComplete with Core IPC.
Co-Authored-By: Virgil <virgil@lethean.io>