When a workspace already exists (resumed=true), checkout main and
pull origin before creating the feature branch. Prevents agents
from working on stale code after previous runs merged.
Co-Authored-By: Virgil <virgil@lethean.io>
Workspace prep now detects repo language and copies the right CODEX.md:
- Go repos get CODEX.md.tmpl (existing — Core primitives, banned imports)
- PHP repos get CODEX-PHP.md.tmpl (CorePHP patterns, lifecycle events,
Actions, BelongsToWorkspace, Flux Pro, FA Pro, UK English)
Added lib.WorkspaceFile() helper for reading individual template files.
Co-Authored-By: Virgil <virgil@lethean.io>
Agents now get the full ecosystem docs (core.help) at
.core/reference/docs/ in their workspace. 349 markdown files
covering architecture, guides, specs — not just the RFC.
Co-Authored-By: Virgil <virgil@lethean.io>
All dispatch prompts now instruct agents to read CODEX.md (mandatory
patterns) and .core/reference/docs/RFC.md (full API contract) before
starting work. These files were already in the workspace template but
agents were never told to read them.
Also fixes stale references: src/ → repo/, coreerr.E() → core.E().
Co-Authored-By: Virgil <virgil@lethean.io>
drainOne now spawns agents directly via ServiceFor[spawner] instead of
IPC SpawnQueued (which was never received by agentic). Workspace status
is only set to "running" AFTER successful spawn — no more PID=0 ghosts.
Also fixes workspace name resolution: uses relative path from workspace
root (core/go-ai/dev) instead of PathBase (dev).
Co-Authored-By: Virgil <virgil@lethean.io>
Runner's drainOne sends SpawnQueued but agentic never handled it,
creating ghost "running" entries with PID=0. Now agentic catches
SpawnQueued, calls spawnAgent, and updates status with real PID.
Co-Authored-By: Virgil <virgil@lethean.io>
Monitor checkInbox now sends each new message as a ChannelPush with
from/subject/content — lands directly in the Claude Code session.
Removes the useless InboxMessage{New, Total} count relay through runner.
Co-Authored-By: Virgil <virgil@lethean.io>
Runner HandleIPCEvents now catches AgentStarted in addition to
AgentCompleted, sending ChannelPush to MCP for both lifecycle events.
Co-Authored-By: Virgil <virgil@lethean.io>
ConfigGet type assertion fails across package boundaries —
agentic stores map[string]agentic.ConcurrencyLimit but runner
tries to retrieve map[string]runner.ConcurrencyLimit.
Use Core's c.Config().Get() → Result → type assert instead.
This is why concurrency limits were never enforced.
Co-Authored-By: Virgil <virgil@lethean.io>
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>