Normalize the MCP constructor workspace defaulting to use the actual working directory, and replace the IDE subsystem's functional options with a Config DTO so the codebase stays aligned with AX-style configuration objects.
Co-Authored-By: Virgil <virgil@lethean.io>
ServeStdio never set stdioMode=true, so ChannelSend always returned
early. Also switched from StdioTransport to IOTransport with a shared
lockedWriter that both the SDK and ChannelSend write through.
This fixes channel notifications not arriving in Claude Code sessions.
Co-Authored-By: Virgil <virgil@lethean.io>
ChannelSend was writing to os.Stdout directly while the SDK's
StdioTransport also writes to os.Stdout — causing interleaved
JSON-RPC messages. Now both use a shared lockedWriter via IOTransport.
Co-Authored-By: Virgil <virgil@lethean.io>
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>