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 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>