Services can now push channel events to Claude Code by sending a
ChannelPush message via Core IPC. The MCP service catches it in
HandleIPCEvents and calls ChannelSend to the stdio transport.
- ChannelPush{Channel, Data} message type in subsystem.go
- HandleIPCEvents on Service catches ChannelPush → ChannelSend
- Enables runner→mcp→Claude Code notification pipeline
Co-Authored-By: Virgil <virgil@lethean.io>
Error classification uses string match on unmarshal errors instead of
stdlib json.SyntaxError/UnmarshalTypeError type assertions. No exceptions.
Co-Authored-By: Virgil <virgil@lethean.io>
encoding/json stays for SyntaxError/UnmarshalTypeError type assertions.
net/http stays — transport boundary.
Co-Authored-By: Virgil <virgil@lethean.io>
MCP Service now embeds *core.ServiceRuntime[McpOptions] like all v0.8.0
services. OnStartup uses s.Core() instead of casting coreRef.
Co-Authored-By: Virgil <virgil@lethean.io>
Was returning error — Core didn't recognise it as Startable so mcp/serve
commands were never registered. One-line fix per method.
Co-Authored-By: Virgil <virgil@lethean.io>
Service stores Core ref, registers transport commands during lifecycle.
Commands use Service methods directly — no external wiring.
Co-Authored-By: Virgil <virgil@lethean.io>
MCP SDK doesn't support nested struct slices in schema generation.
Pipeline orchestration will be handled at a higher level.
Co-Authored-By: Virgil <virgil@lethean.io>
DispatchInput now accepts Pipeline []PipelineStep for follow-up steps.
On agent completion, the next step auto-dispatches with {{.Findings}}
replaced by the previous agent's output. Enables:
dispatch(review) → auto(fix with findings) → auto(verify)
WorkspaceStatus stores NextSteps for the completion handler.
Co-Authored-By: Virgil <virgil@lethean.io>
Reference files are now embedded in core-agent's workspace template
(pkg/lib/workspace/default/.core/reference/). No hardcoded paths needed.
Co-Authored-By: Virgil <virgil@lethean.io>
prepWorkspace now copies RFC-025-AGENT-EXPERIENCE.md and all Core .go
files into .core/reference/ in every dispatched workspace. Agents can
read the AX conventions and Core API without network access.
Co-Authored-By: Virgil <virgil@lethean.io>
writeStatus("running") was after cmd.Start(), so rapid sequential
dispatches all saw 0 running. Now writes status immediately after
the concurrency check passes, before spawning. Updates with PID
after start. Reverts to "failed" if spawn fails.
Co-Authored-By: Virgil <virgil@lethean.io>
- UK English in transport_e2e_test.go comments and error strings
- Replace fmt.Printf with coreerr.Error/Warn in brain-seed for errors/skips
- Alias stdlib io as goio in transport_tcp, brain/direct, agentic/prep, bridge, brain-seed
- Add var _ Notifier = (*Service)(nil) compile-time assertion
- Add TestRegisterProcessTools_Bad_NilService for nil-service error path
- Add webview handler tests beyond nil-guard (disconnect success, validation paths)
- Guard tools_process_ci_test.go with //go:build ci (pre-existing build failure)
- Document circular-import exception in EXCEPTIONS.md
Co-Authored-By: Virgil <virgil@lethean.io>
listWorkspaceDirs() now recurses one level into subdirectories
(e.g. workspace/core/go-io-123/) so countRunningByAgent and
agentic_status find workspaces regardless of directory structure.
Co-Authored-By: Virgil <virgil@lethean.io>
The hardcoded host-uk/core path doesn't exist on the homelab,
causing countRunningByAgent to always return 0 (no concurrency limiting)
and agentic_status to miss workspaces.
Co-Authored-By: Virgil <virgil@lethean.io>
ChannelSend now writes raw JSON-RPC notifications with method
notifications/claude/channel directly to stdout, bypassing the
SDK's Log() method which uses notifications/message/log.
The official Go SDK doesn't expose a way to send custom
notification methods, so we write the JSON-RPC notification
directly to the stdio transport. This is the format Claude Code
channels expect for --channels to surface events in session.
Co-Authored-By: Virgil <virgil@lethean.io>
Port 9101 conflicts with running core-agent serve. OS-assigned
port avoids the conflict and still tests the 0.0.0.0 warning.
Co-Authored-By: Virgil <virgil@lethean.io>
Backend clamps 0 to 1, returning only one memory. Default to 50
for a sensible batch when callers omit the limit field.
Co-Authored-By: Virgil <virgil@lethean.io>
DirectSubsystem pushes brain.recall.complete and brain.remember.complete
events via OnChannel callback. Avoids circular import by using func-based
wiring instead of interface-based SubsystemWithNotifier.
New() auto-detects subsystems with OnChannel() and wires them to
ChannelSend via closure.
Co-Authored-By: Virgil <virgil@lethean.io>
process.start on successful spawn, process.exit on stop/kill.
Events include process ID, PID, command, and signal type.
Co-Authored-By: Virgil <virgil@lethean.io>
Connections now register on the shared server via Server.Connect()
instead of creating per-connection servers. All sessions (stdio,
HTTP, TCP, Unix) are now visible to Sessions() and notification
broadcasting.
Co-Authored-By: Virgil <virgil@lethean.io>
Replace all fmt.Errorf and errors.New in production code with
coreerr.E("caller.Method", "message", err) from go-log. Replace all
os.ReadFile/os.WriteFile/os.MkdirAll/os.Remove with coreio.Local
equivalents from go-io. Test files are untouched.
24 files across pkg/mcp/agentic/, pkg/mcp/brain/, pkg/mcp/ide/,
pkg/mcp/, and cmd/brain-seed/.
Co-Authored-By: Virgil <virgil@lethean.io>
Dispatches to local-agent.sh which reads workspace context files
and calls Ollama API with Qwen3-Coder-Next. No quota, no rate limits.
Co-Authored-By: Virgil <virgil@lethean.io>
When an agent completes, if the output contains file:line references
(indicating real findings), automatically creates an issue via the
lthn.sh API. Scans → issues → sprints → PRs → release. The loop closes.
Co-Authored-By: Virgil <virgil@lethean.io>
gemini:flash, gemini:pro now match the "gemini" concurrency limit.
Strips model variant before checking config. Prevents unlimited
spawning when using model variants.
Co-Authored-By: Virgil <virgil@lethean.io>
Set TERM=dumb, NO_COLOR=1, CI=true on spawned agents to prevent
terminal control sequences and colour output bleeding into parent.
Combined with Setpgid + /dev/null stdin.
Agent now supports model variants via colon syntax:
gemini:flash, gemini:pro, claude:haiku, claude:sonnet
Co-Authored-By: Virgil <virgil@lethean.io>
Reads rates config from agents.yaml per agent type. Calculates delay
based on time-of-day relative to quota reset window:
- Sustained mode: steady pacing across the full day
- Burst mode: faster pacing when close to reset (quota about to refill)
Gemini resets 06:00 UTC. Start at 09:00 = pace slower (sustained_delay).
Start at 03:00 = burst mode (burst_delay) since reset is 3 hours away.
Co-Authored-By: Virgil <virgil@lethean.io>
Redirect stdin to /dev/null so spawned agents don't inherit the
terminal. Prevents agents from stealing input/output during git
commits or interactive operations.
Co-Authored-By: Virgil <virgil@lethean.io>
Separate concurrency control per agent type: claude: 1, gemini: 3,
codex: 1. Gemini can grind through audit batches without blocking
Claude from doing fix work. Config in agents.yaml under concurrency.
Co-Authored-By: Virgil <virgil@lethean.io>
Strengthen phase enforcement: 'Each phase = one commit. This is not optional.'
Agents were batching all phases into a single commit. Now the prompt
explicitly requires stopping and committing after each phase.
Co-Authored-By: Virgil <virgil@lethean.io>
Dispatch and prep accept a persona field (e.g. "engineering/backend-architect").
Copies persona markdown into workspace as PERSONA.md. Coding prompt updated
to read PERSONA.md first and adopt that identity.
Co-Authored-By: Virgil <virgil@lethean.io>
When an agent process exits, the completion goroutine updates status
to completed then calls drainQueue(). drainQueue finds the oldest
queued workspace, spawns it if under concurrency limit, and monitors
it recursively. Self-sustaining work pipeline.
Co-Authored-By: Virgil <virgil@lethean.io>
Reads max_concurrent from config/agents.yaml. If at limit, workspace
is created with status "queued" instead of spawning immediately.
Counts running agents by checking PID liveness.
Co-Authored-By: Virgil <virgil@lethean.io>