Commit graph

66 commits

Author SHA1 Message Date
Snider
2bbc8063cf feat(agentic): auto-copy AX spec + Core source into agent workspaces
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>
2026-03-22 06:47:04 +00:00
Snider
4329bd7f27 fix(agentic): write status before spawn to prevent concurrency race
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>
2026-03-22 02:32:17 +00:00
Snider
72ba11b481 fix(agentic): config path is ~/Code/.core/agents.yaml only
All .core/ config lives at codePath/.core/ — not in individual repos.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 02:28:05 +00:00
Snider
94cc1b9ed5 fix(agentic): scan nested workspace dirs for concurrency + status
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>
2026-03-22 02:11:59 +00:00
Snider
90bb784e79 fix(agentic): workspace root is ~/Code/.core/ not ~/Code/host-uk/core/.core/
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>
2026-03-22 01:57:12 +00:00
Snider
907d62a545 fix(mcp): resolve 17 code review findings + php route('login') fix
Some checks failed
CI / test (push) Failing after 2s
Go (17 findings from Codex sweep):
- CRITICAL: bare type assertion panic in tools_metrics.go
- CRITICAL: webviewInstance data race — added webviewMu mutex
- CRITICAL: swallowed Glob error in agentic/ingest.go
- HIGH: 9 nil-pointer dereferences on resp.StatusCode across agentic/
- HIGH: swallowed os.Open/os.Create errors in dispatch, queue, resume
- HIGH: hardcoded ~/Code/host-uk/core paths replaced with s.workspaceRoot()
- HIGH: wsServer/wsAddr data race — added wsMu to Service struct
- MEDIUM: ChannelSend stdout guard for non-stdio transports
- MEDIUM: readPlan discarded underlying error
- MEDIUM: TCP session IDs now unique per connection (RemoteAddr)
- LOW: SPDX typo in brain/provider.go

PHP (route('login') fix):
- Replace route('login') with url('/login') in 4 MCP files
- route('login') fails on mcp.* subdomains where no login route exists
- url('/login') resolves correctly on any domain

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-21 23:13:03 +00:00
Snider
8e84a06b82 fix(mcp): send channel events via notifications/claude/channel
Some checks failed
CI / test (push) Failing after 3s
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>
2026-03-21 18:57:36 +00:00
Snider
c815b9f1b1 fix(test): use port 0 instead of hardcoded 9101 in TCP warning test
Some checks failed
CI / test (push) Failing after 3s
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>
2026-03-21 17:48:48 +00:00
Snider
1d44728dcd fix(brain): default list limit to 50 instead of 0
Some checks failed
CI / test (push) Failing after 2s
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>
2026-03-21 17:45:36 +00:00
Snider
1ac4ff731d feat(mcp): emit channel events for brain recall/remember
Some checks failed
CI / test (push) Failing after 3s
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>
2026-03-21 15:16:34 +00:00
Snider
bc3c7184e9 feat(mcp): emit channel events for process start/stop/kill
Some checks failed
CI / test (push) Failing after 3s
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>
2026-03-21 15:10:01 +00:00
Snider
4775f2c2d3 refactor(mcp): TCP/Unix transports use shared server sessions
Some checks failed
CI / test (push) Failing after 3s
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>
2026-03-21 15:08:34 +00:00
Snider
7e24efaa85 docs: update CLAUDE.md for Options{} API + add CI workflow
Some checks failed
CI / test (push) Failing after 3s
CLAUDE.md reflects new Options{} constructor, notification
broadcasting, and channel events. CI runs tests with Codecov.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-21 13:53:49 +00:00
Snider
3c0cd0c238 docs(mcp): add usage-example comments to all public types
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-21 13:51:14 +00:00
Snider
8021475bf5 refactor(mcp): Options{} struct + notification broadcasting + claude/channel
Phase 1: Replace functional options (WithWorkspaceRoot, WithSubsystem,
WithProcessService, WithWSHub) with Options{} struct. Breaking change
for consumers (agent, ide).

Phase 2: Add notification broadcasting and claude/channel capability.
- SendNotificationToAllClients: broadcasts to all MCP sessions
- ChannelSend: push named events (agent.complete, build.failed, etc.)
- ChannelSendToSession: push to a specific session
- Notifier interface for sub-packages to avoid circular imports
- claude/channel registered as experimental MCP capability

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-21 13:51:14 +00:00
Snider
04ef80cd06 refactor: migrate core import to dappco.re/go/core
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-21 13:51:14 +00:00
Snider
40e43773a7 chore: sync dependencies for v0.3.4
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-21 13:51:14 +00:00
Snider
6a6dfe5217 chore: sync dependencies for v0.3.3
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-21 13:51:14 +00:00
bea3849946 Merge pull request '[agent/claude:opus] DX audit and fix. 1) Review CLAUDE.md — update any outdate...' (#1) from agent/dx-audit-and-fix--1--review-claude-md into main 2026-03-17 09:04:31 +00:00
Snider
a7bc30f8ac fix(mcp): DX audit — update CLAUDE.md, replace os.* with go-io, add tests
- CLAUDE.md: remove stale tools_ml.go reference (moved to go-ml),
  add agentic subsystem, document HTTP transport and MCP_AUTH_TOKEN
- Replace os.ReadDir with coreio.Local.List in agentic package
  (plan.go, queue.go, status.go)
- Replace os.Stat with coreio.Local.IsFile/List in agentic package
  (plan.go, pr.go, resume.go)
- Add DirectSubsystem tests (brain): apiCall, remember, recall, forget
  with httptest mock server — coverage 6.5% → 39.6%
- Add HTTP transport tests: health endpoint, Bearer auth, withAuth
  unit tests, Run() priority — coverage 51.2% → 56.0%

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-17 09:03:51 +00:00
Snider
fe66067b54 feat: add Streamable HTTP transport with Bearer token auth
New transport_http.go adds ServeHTTP() using the go-sdk's built-in
StreamableHTTPHandler. Supports:
- SSE streaming (GET /mcp) for server-to-client notifications
- JSON-RPC (POST /mcp) for tool calls
- Session management with 30min idle timeout
- Bearer token auth via MCP_AUTH_TOKEN env var
- Health check at /health (no auth)

Transport selection via env vars:
- MCP_HTTP_ADDR → Streamable HTTP
- MCP_ADDR → TCP
- (default) → Stdio

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-17 04:25:28 +00:00
Snider
a4f86b5de6 chore: sync dependencies for v0.3.2
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-16 22:19:03 +00:00
Snider
424b5eb91d refactor: replace fmt.Errorf/os.* with go-io/go-log conventions
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>
2026-03-16 21:57:12 +00:00
Snider
d6dccec914 refactor: move MLSubsystem to go-ml/pkg/mcp
ML tools (generate, score, probe, status, backends) belong in go-ml,
not the MCP framework. Removes go-ml/go-mlx/go-duckdb dependency chain
from core/mcp, unblocking CGO_ENABLED=0 cross-compilation.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-16 15:37:27 +00:00
Snider
5191bd0cda fix(mcp): use AgentApiKey for auth, graceful fallback when ApiKey model missing
The old Core\Mod\Api\Models\ApiKey was removed when core/php-api was renamed.
Now tries AgentApiKeyService first, falls back to workspace apiKeys,
catches Throwable if either model is unavailable.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-16 10:00:29 +00:00
Snider
0eecf095bd feat(agentic): add local agent type via Ollama
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>
2026-03-16 07:35:33 +00:00
Snider
a9b7326c19 feat(agentic): auto-ingest scan findings as issues
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>
2026-03-16 06:27:53 +00:00
Snider
f8bee4b4ad fix(agentic): match concurrency limits on base agent type
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>
2026-03-15 19:00:19 +00:00
Snider
cb8c126d78 fix(agentic): full terminal detachment + model variant support
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>
2026-03-15 18:12:48 +00:00
Snider
02f0afd1ea feat(agentic): rate-aware task scheduling
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>
2026-03-15 17:55:55 +00:00
Snider
a5ebea1770 fix(agentic): fully detach agent processes from terminal
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>
2026-03-15 17:41:47 +00:00
Snider
f728219ce4 feat(agentic): per-agent concurrency limits
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>
2026-03-15 17:33:16 +00:00
Snider
e7c1c9bd86 fix(agentic): enforce commit-per-phase in coding prompt
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>
2026-03-15 17:18:50 +00:00
Snider
aad4c444a1 feat(agentic): persona support — adopt identity from prompts/personas/
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>
2026-03-15 16:35:42 +00:00
Snider
58c6f3687c feat(agentic): auto-drain queue when agent completes
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>
2026-03-15 16:09:45 +00:00
Snider
fb16e18919 feat(agentic): concurrency control with file-based queue
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>
2026-03-15 16:03:09 +00:00
Snider
2129c51599 fix(agentic): detach agent processes so they survive MCP server death
Set Setpgid on spawned agent processes so they get their own process
group. Agents now survive session restarts, plugin reloads, and MCP
server crashes. Output writes directly to log file instead of
in-memory buffer.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 15:55:29 +00:00
Snider
cbc7ccd91c chore: sync workspace dependencies
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 15:45:04 +00:00
Snider
4b6dec50b1 chore: sync go.mod dependencies
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 15:38:33 +00:00
Snider
3695f72b42 chore: bump forge deps (core/go v0.3.1, go-io v0.1.2, go-process v0.2.2)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 15:17:42 +00:00
Snider
3b8f17d8fd docs: add implementation plans for plan CRUD and issue dispatch
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 15:10:52 +00:00
Snider
3cd21f2fc1 feat(agentic): epic system — parent issue with child checklist
New MCP tool agentic_create_epic:
- Creates child issues from task list
- Builds parent epic with checklist (- [ ] #N format)
- Auto-creates labels (agentic, epic)
- Optionally dispatches agents to each child

Works with existing tick_parent handler in go-scm jobrunner
which checks off items as child PRs merge.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 15:04:42 +00:00
Snider
9587ea4d49 refactor(agentic): use go-process for agent lifecycle management
Replace raw exec.Command with process.StartWithOptions() from
go-process. Agents get proper PID tracking and output capture
via RingBuffer.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 14:35:47 +00:00
Snider
5d5646248e fix(agentic): clone from local repo, disable agent push
Workspace clones from local checkout instead of setting forge remote.
Agent commits locally — reviewer verifies and pushes. Prevents
accidental CI triggers and GitHub Actions credit usage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 14:20:07 +00:00
Snider
b21a9e3364 feat(agentic): PR creation and issue-driven dispatch tools
New tools from dispatched agent (merged manually):
- agentic_create_pr: push branch + create PR via Forge API
- agentic_list_prs: list PRs across repos with filtering
- WorkspaceStatus extended with org, branch, issue, pr_url fields

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 14:14:33 +00:00
Snider
3d482d0744 feat(agentic): add plan CRUD MCP tools
Five new tools for managing implementation plans:
- agentic_plan_create: create plans with phases and acceptance criteria
- agentic_plan_read: get plan by ID
- agentic_plan_update: partial updates to status, phases, notes
- agentic_plan_delete: remove plan by ID
- agentic_plan_list: list/filter plans by status and repo

Plans follow the task protocol lifecycle (draft → ready → in_progress
→ needs_verification → verified → approved) and are stored as JSON
in ~/.core/plans/.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 14:12:56 +00:00
Snider
3e9ef16409 feat(agentic): plan template rendering in workspace prep
Dispatch now accepts plan_template + variables fields. Workspace prep
loads YAML templates from core/agent/prompts/templates/, substitutes
variables, and renders PLAN.md with phases and checkbox tasks. Coding
prompt updated to work phase-by-phase with commit-per-phase convention.

Agent reads files, commits per phase — no MCP tools needed mid-work.
The checkpoint IS the commit.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 13:59:05 +00:00
Snider
3b169d9b1e feat(agentic): workspace lifecycle — status, resume, stop/ask/continue
New MCP tools:
- agentic_status: list workspaces with state (running/completed/blocked/failed)
- agentic_resume: relaunch blocked agents with ANSWER.md context

Workspace convention:
- status.json tracks state, agent, PID, run count
- BLOCKED.md written by agent when stuck (triggers blocked state)
- ANSWER.md written by reviewer before resume
- Dispatch now writes status.json on launch

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 13:29:19 +00:00
Snider
c122ba2039 feat(agentic): include GEMINI.md ethics framework in workspace
Every dispatched agent gets the LEK axioms (Axioms of Consciousness)
from core/agent/GEMINI.md alongside the project context.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 10:41:05 +00:00
Snider
d0ad141af3 fix(agentic): write context files inside src/ for agent sandbox
Gemini CLI restricts file access to the workspace root (src/).
All context files (CLAUDE.md, TODO.md, CONTEXT.md, CONSUMERS.md,
RECENT.md, PROMPT.md, kb/, specs/) now written inside src/ so
the sandboxed agent can read them.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 10:31:23 +00:00