| Age | Commit message (Collapse) | Author |
|
Remove the dead stories/checker backend tracked as design debt in CLAUDE.md:
- Delete internal/api/stories.go, stories_test.go, elaborate.go
- Delete internal/task/story.go, story_test.go
- Remove story/checker columns from storage schema and all CRUD methods
- Remove checkStoryCompletion, spawnCheckerTask, triggerStoryDeploy,
createValidationTask, checkValidationResult, ShipStory, CheckStoryCompletion
from executor; simplify handleRunResult
- Remove story/checker fields from task.Task (StoryID, AcceptanceCriteria,
CheckerForTaskID, CheckerReport)
- Remove story routes and geminiBinPath from API server
- Move claudeJSONResult/extractJSON from elaborate.go to validate.go
- Rename ensureStoryBranch -> ensureBranch in ContainerRunner
- Fix git identity in bare-repo tests; fix initial-branch to use main
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
loopback-only bind
Key features from OSS branch:
- Budget gating: rolling per-provider spend caps with BUDGET_EXCEEDED task state
- Agent MCP back-channel: runners mint tokens; /mcp endpoint resolves them
- Chatbot MCP server at /chatbot/mcp (requires api_token in config)
- Event timeline: unified event stream replacing ad-hoc question/summary flows
- Loopback-only default bind (127.0.0.1:8484); external_bind_allowed=true to expose
- repository_url required on task creation (enforces traceability)
- Auto-checker: spawns verification task after each execution
Conflict resolutions:
- serve.go: keep cfg.Runners.XEnabled() conditional registration from main + agentRegistry from oss
- config.go: keep RunnersConfig from main + BudgetConfig/ExternalBindAllowed from oss
- server.go: handleStaticFiles (base-path rewrite) kept; deduplicated duplicate from both sides
- executor/claude.go: accepted oss deletion (ClaudeRunner replaced by ContainerRunner)
- container_test.go: added noopChannel + AgentChannel parameter to Run call
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- ContainerRunner now resolves local project path for non-story (CI)
tasks, cloning from the local bare repo instead of the HTTPS GitHub
URL to avoid auth failures on the host.
- CI failure tasks now use SSH URLs (git@github.com:...) instead of
HTTPS to avoid credential prompts even when no local path is found.
- GitHub push webhook events now trigger an async git fetch into the
local bare repo, keeping the local mirror in sync when work happens
directly on GitHub.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
With the MCP agent channel validated (the spike confirmed real claude calls
ask_user/report_summary through it), the container runner no longer needs the
pre-MCP file fallback that read question.json/summary.txt after the agent
exited. Removes that block and the now-orphaned isCompletionReport/
extractQuestionText helpers and their test. The MCP path
(channelPendingQuestion) is now the sole question/summary transport.
https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
|
|
The spike found that `claude --permission-mode bypassPermissions` (emitted by
buildInnerCmd) is rejected when the process runs as root, and buildDockerArgs
maps the container --user to the host uid — which is 0 when claudomator runs as
root, breaking all claude tool execution in production.
The container is an isolated sandbox, exactly the case the claude CLI gates
behind IS_SANDBOX=1; setting it in the container env makes bypassPermissions
work regardless of the host uid. Verified empirically against claude 2.1.150
(rejected as root without it; succeeds with it). Harmless for gemini containers.
https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
|
|
ContainerRunner previously skipped the MCP back-channel for gemini agents, so
they ran tool-less. It now mints a per-task token for gemini too and registers
the agent MCP server in the gemini CLI's user settings
(agentHome/.gemini/settings.json → $HOME/.gemini in-container) using the
gemini-cli mcpServers/httpUrl schema with a bearer header. With MCP enabled,
gemini also receives the planning preamble that points at the ask_user/
report_summary/spawn_subtask/record_progress tools.
Config generation is unit-tested (TestWriteGeminiMCPSettings) and the write is
in the run setup path. CAVEAT: whether the gemini CLI actually invokes these
tools in non-interactive (-p) mode — and how it handles tool auto-approval —
is NOT verified against a live gemini binary in this environment; this lands
the plumbing for a follow-up spike. No regression risk for gemini runs: a
config issue degrades to the prior tool-less behavior.
https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
|
|
(Phase 2)
Rewrites the planning preamble to point the agent at the four MCP tools
(ask_user/report_summary/spawn_subtask/record_progress) instead of the
CLAUDOMATOR_QUESTION_FILE / CLAUDOMATOR_SUMMARY_FILE conventions: ask_user ends
the turn, report_summary replaces the summary file, spawn_subtask replaces the
POST-to-/api/tasks planning step. Git discipline is retained.
ContainerRunner previously applied no preamble at all; it now prepends this
preamble (via buildAgentInstructions) when the MCP back-channel is active and
skip_planning is false, so the in-container agent is actually guided to use the
tools. Gemini agents (no MCP) are unaffected.
https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
|
|
ContainerRunner now mints a per-task MCP token (from an injected Registry),
writes a claude mcp-config into the workspace pointing at the host agent MCP
server over host.docker.internal with that bearer, and adds --mcp-config to the
in-container claude invocation. The token is revoked when the run ends. After
the run, a buffered ask_user (PendingQuestion on the channel) is converted into
a BlockedError — the MCP path to BLOCKED — with the file-based question.json
kept as a fallback for in-flight tasks started on the old wire.
The API server mounts the StreamableHTTP MCP handler at POST/GET/DELETE /mcp
when a registry is provided; serve.go constructs one Registry shared by the
runners (mint) and the server (resolve). Minting is skipped for gemini agents.
Tests: writeMCPConfig output shape, buildInnerCmd flag presence/absence, and an
api-level end-to-end MCP tool call through NewServer/Handler proving the route
is mounted (and absent without a registry).
https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
|
|
Adds the agent-facing MCP transport foundation: a Registry that mints a
per-task bearer token bound to a freshly built MCP server exposing the four
agent tools (ask_user, report_summary, spawn_subtask, record_progress), and
an HTTP handler (StreamableHTTP) that resolves the token to that server. The
server never trusts an agent-supplied task ID — context comes from the token.
The default storeChannel now buffers summary and question signals under a
mutex (an MCP tool call lands on an HTTP-handler goroutine mid-run), exposing
ReportedSummary/PendingQuestion. The pool flushes the buffered summary onto
the execution after the run, replacing the runner's direct exec.Summary write
and keeping the read race-free.
ask_user follows the record-and-resume model: it buffers the question, returns
ErrAgentBlocked, and the tool tells the agent to end its turn; the run blocks
and resumes later via claude --resume (no live slot held).
Tests cover registry lifecycle, in-memory tool dispatch, and HTTP end-to-end
with bearer auth (valid token dispatches; invalid token rejected).
Not yet wired into the runners or mounted on the API server — next increment.
https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
|
|
Defines AgentChannel — the normalized interface by which a runner reports
agent-originated signals (AskUser, ReportSummary, SpawnSubtask,
RecordProgress) — plus a default storeChannel implementation backed by
storage. Runner.Run now takes an AgentChannel; the pool constructs one
per execution.
The file transport routes its post-exit summary detection through
ch.ReportSummary (buffered onto the execution so the pool still applies
its extract/synthesize fallbacks, no double-write). AskUser returns
ErrAgentBlocked since write-and-exit cannot answer in-session; question
persistence stays with the pool's BlockedError handling. SpawnSubtask
and RecordProgress are implemented and tested, ready for the MCP
transport in Phase 2 where the channel becomes fully load-bearing.
Store gains CreateEvent so the channel can emit agent_message events.
https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
|
|
Merges 12 commits from github/main (formerly master) that were developed
independently. Key additions:
- LocalRunner: OpenAI-compatible local LLM execution (Ollama, LM Studio)
- Real GeminiRunner with full sandbox parity to ClaudeRunner
- llm.Client for enriching CI failures and elaboration via local model
- retry.ParseRetryAfter moved to shared package
- tokens_in/tokens_out columns in executions table
Conflict resolutions:
- Kept local main's VAPID/push, stories, projects, agent events schema
- Merged both sets of Config fields (local + LocalModel from github/main)
- Unified activePerAgent accounting (decActiveAgent helper)
- Removed duplicate helpers from claude.go (now in helpers.go)
- Fixed double-decrement bug in handleRunResult vs decActiveAgent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Add ensureStoryBranch() that runs git ls-remote to check, then clones
into a temp dir to create and push the branch if missing. Called before
the task's own clone so checkout is guaranteed to succeed.
Removes the post-checkout fallback hack added in the previous commit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Agent added: Store on ContainerRunner (direct story/project lookup), --reference
clone for speed, explicit story branch push, checkStoryCompletion → SHIPPABLE.
My additions: BranchName on Task as fallback when Store is nil, tests updated
to match checkout-after-clone approach.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Add BranchName field to task.Task (populated from story at execution time)
- Add GetStory to executor Store interface; resolve BranchName from story in both
execute() and executeResume() parallel to RepositoryURL resolution
- Pass --branch <name> to git clone when BranchName is set; default clone otherwise
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
creds, auth recovery
- maxPerAgent=1: only 1 in-flight execution per agent type at a time; excess tasks are requeued after 30s
- Drain gate: after 2 consecutive failures the agent is drained and a question is set on the task; reset on first success; POST /api/pool/agents/{agent}/undrain to acknowledge
- Pre-flight credential check: verify .credentials.json and .claude.json exist in agentHome before spinning up a container
- Auth error auto-recovery: detect auth errors (Not logged in, OAuth token has expired, etc.) and retry once after running sync-credentials and re-copying fresh credentials
- Extracted runContainer() helper from ContainerRunner.Run() to support the retry flow
- Wire CredentialSyncCmd in serve.go for all three ContainerRunner instances
- Tests: TestPool_MaxPerAgent_*, TestPool_ConsecutiveFailures_*, TestPool_Undrain_*, TestContainerRunner_Missing{Credentials,Settings}_FailsFast, TestIsAuthError_*, TestContainerRunner_AuthError_SyncsAndRetries
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
After a successful run with no commits pushed, detectUncommittedChanges
checks for modified tracked files and untracked source files. If any
exist the task fails with an explicit error rather than silently
succeeding while the work evaporates when the sandbox is deleted.
Scaffold files written by the harness (.claudomator-env,
.claudomator-instructions.txt, .agent-home/) are excluded from the check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- ContainerRunner replaces ClaudeRunner/GeminiRunner; all agent types run
in Docker containers via claudomator-agent:latest
- Writable agentHome staging dir (/home/agent) satisfies home-dir
requirements for both claude and gemini CLIs without exposing host creds
- Copy .credentials.json and .claude.json into staging dir at run time;
GEMINI_API_KEY passed via env file
- Fix git clone: remove MkdirTemp-created dir before cloning (git rejects
pre-existing dirs even when empty)
- Replace localhost with host.docker.internal in APIURL so container can
reach host API; add --add-host=host.docker.internal:host-gateway
- Run container as --user=$(uid):$(gid) so host-owned workspace files are
readable; chmod workspace 0755 and instructions file 0644 after clone
- Pre-create .gemini/ in staging dir to avoid atomic-rename ENOENT on first
gemini-cli run
- Add ct CLI tool to container image: pre-built Bash wrapper for
Claudomator API (ct task submit/create/run/wait/status/list)
- Document ct tool in CLAUDE.md agent instructions section
- Add drain-failed-tasks script: retries failed tasks on a 5-minute interval
- Update Dockerfile: Node 22 via NodeSource, Go 1.24, gemini-cli,
git safe.directory=*, default ~/.claude.json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
- Fix push failure swallowing and ensure workspace preservation on push error
- Fix wrong session ID in --resume flag and BlockedError
- Implement safer shell quoting for instructions in buildInnerCmd
- Capture and propagate actual Claude session ID from stream init message
- Clean up redundant image resolution and stale TODOs
- Mark ADR-005 as Superseded
- Consolidate RepositoryURL to Task level (removed from AgentConfig)
- Add unit test for session ID extraction in parseStream
|
|
- Fix host/container path confusion for --env-file
- Fix --resume flag to only be used during resumptions
- Fix instruction passing to Claude CLI via shell-wrapped cat
- Restore streamErr return logic to detect task-level failures
- Improve success flag logic for workspace preservation
- Remove duplicate RepositoryURL from AgentConfig
- Fix app.js indentation and reformat DOMContentLoaded block
- Restore behavioral test coverage in container_test.go
|
|
- Fix Critical Bug 1: Only remove workspace on success, preserve on failure/BLOCKED.
- Fix Critical Bug 2: Use correct Claude flag (--resume) and pass instructions via file.
- Fix Critical Bug 3: Actually mount and use the instructions file in the container.
- Address Design Issue 4: Implement Resume/BLOCKED detection and host-side workspace re-use.
- Address Design Issue 5: Consolidate RepositoryURL to Task level and fix API fallback.
- Address Design Issue 6: Make agent images configurable per runner type via CLI flags.
- Address Design Issue 7: Secure API keys via .claudomator-env file and --env-file flag.
- Address Code Quality 8: Add unit tests for ContainerRunner arg construction.
- Address Code Quality 9: Fix indentation regression in app.js.
- Address Code Quality 10: Clean up orphaned Claude/Gemini runner files and move helpers.
- Fix tests: Update server_test.go and executor_test.go to work with new model.
|