summaryrefslogtreecommitdiff
path: root/internal/api
AgeCommit message (Collapse)Author
2026-06-03feat: add --base-path flag so UI routes API calls to correct prefixPeter Stone
Allows running multiple instances (e.g. /claudomator and /claudomator-oss) behind a reverse proxy. The server rewrites the base-path meta tag in index.html at request time rather than baking it into the embed. Also adds --branch support to deploy script for isolated branch builds via git worktrees. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03fix: clone from local mirror and sync from GitHub push eventsPeter Stone
- 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>
2026-05-13merge: integrate github/main — LocalRunner, real GeminiRunner, llm clientPeter Stone
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>
2026-05-03fix: prevent SHIPPABLE stories and wrong READY state on failed tasksPeter Stone
Three related bugs fixed: 1. maybeUnblockParent: guard against promoting QUEUED leaf tasks (no subtasks) to READY. The vacuously-true 'all subtasks done' check was advancing tasks that stalled in QUEUED (due to a prior SQLite lock error) to READY on server restart via RecoverStaleBlocked, despite having only failed executions and no commits. 2. checkStoryCompletion: require COMPLETED (not just READY) for all top-level tasks before advancing a story to SHIPPABLE. READY means the checker agent is still pending or the task awaits human review; a story with READY tasks is not ready to ship. 3. handleAcceptTask: call CheckStoryCompletion after a task is accepted so stories with parent tasks (whose subtasks are all done and then the parent is manually accepted) can auto-advance to SHIPPABLE. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03chore: close deferred work — real GeminiRunner, Local UI option, db.go cleanupClaude
Closes the three items left on the deferred queue after the post-epic cleanup. GeminiRunner.execOnce now actually executes the gemini binary instead of writing hardcoded stream data. Mirrors ClaudeRunner.execOnce: - exec.CommandContext with the same env vars (CLAUDOMATOR_API_URL etc.) - process group SIGKILL on context cancel - stdout piped through parseGeminiStream → stdoutFile - stderr to file - exit codes captured, stderr tail surfaced on failure Test infrastructure bug uncovered in passing: testServerWithGeminiMockRunner's mock script used double-quoted echo with literal triple-backticks, which bash interpreted as command substitution. The script always produced empty output. The bug was invisible until now because GeminiRunner ignored the script entirely. Switched to a single-quoted heredoc. Frontend: index.html dropdown gains a "Local" option. No JS branching needed — the value flows through to agent.type verbatim and downstream display reads the type string as-is. storage/db.go: removed stale debug-comment scaffolding (the "TODO: Replace with proper logger" block) that was tracking a dead `fmt.Printf` call. The path it commented on is fine without logging — unmarshal errors are returned wrapped. Test status: `go test -race ./...` green across every package, zero skips, zero excluded tests. https://claude.ai/code/session_017Edeq947TpSm1vQTxMhi1J
2026-05-03chore: post-epic cleanup — green test suite, no skipsClaude
Addresses the cleanup queue captured in docs/plans/local-oss-runner.md after the local-OSS-models epic landed. After this commit `go test -race ./...` is green across every package with zero `t.Skip` calls and no excluded tests. Real bugs fixed: - claude.go setupSandbox callsites used `sandboxDir, err := ...` which shadowed the outer variable, so BlockedError.SandboxDir was always empty. Resume-after-block was broken for both new and stale-sandbox paths. TestBlockedError_IncludesSandboxDir now exercises the right invariant. - TestPool_ActivePerAgent_DeletesZeroEntries flake under -race: the cleanup defer in execute()/executeResume() runs AFTER handleRunResult sends on resultCh, so consumers observing a result could see a still-counted activePerAgent entry. Extracted decActiveAgent(agentType, *cleaned) helper; called explicitly before every resultCh send, defer becomes a no-op via the cleaned flag. Verified clean over `go test -race -count=10`. Test infrastructure made hermetic: - gitSafe now also passes -c commit.gpgsign=false / -c tag.gpgsign=false so sandbox tests pass on hosts whose global config requires signing. - Bare repos in tests initialized with `-b main` (HEAD symbolic ref matched to the branch we push) so `git log` after push works. - TestSandboxCloneSource_FallsBackToOrigin uses a local-FS origin URL, matching sandboxCloneSource's intentional filter against network URLs. - TestGeminiLogs_ParsedCorrectly URL fixed to the actual log route (/api/executions/{id}/log). GeminiRunner gap closed (partial): - parseGeminiStream now walks lines for `result` events, surfacing is_error as an error and total_cost_usd as the float return value. - GeminiRunner.Run propagates parsed cost to Execution.CostUSD. - TestParseGeminiStream_ParsesStructuredOutput unskipped. Notes: - GeminiRunner is still simulated end-to-end (Run writes hardcoded stream data instead of execing the binary). The result/cost parser now exists; finishing the runner is a smaller, contained follow-up. Kept on the deferred queue. - Frontend "Local" agent option and a minor storage.db.go logger TODO remain on the deferred queue, both intentionally — neither blocks anything in flight. https://claude.ai/code/session_017Edeq947TpSm1vQTxMhi1J
2026-05-02feat(api): enrich CI failure task instructions via local LLMClaude
Phase 3 of "local OSS models as agents" plan. When the webhook handler creates a task for a failed CI run AND a local LLM is configured on the server, the hardcoded 4-step investigation template is replaced with a project-aware investigation plan generated by the LLM. Scope adjustment from the original sketch: the original plan said "summarize fetched workflow logs", but fetching logs requires GitHub API auth that isn't wired. Narrowed to project-context triage — recent git log + CLAUDE.md content + webhook metadata, fed to the LLM with a system prompt asking for 6-12 lines of concrete next steps. Deferred GitHub log fetching to post-epic cleanup. Implementation: - New internal/api/webhook_llm.go holds enrichCIInstructions and its helpers (readRecentCommits via `git log`, readProjectDoc). - enrichCIInstructions is truly additive: any failure mode (no client, HTTP error, empty body, 10s timeout) returns the original fallback template unchanged. Existing webhook tests pass byte-for-byte. - Always preserves a metadata header (repo/branch/SHA/check/URL) ahead of the LLM body so investigators don't lose context if the LLM is terse. - Reuses s.llm (set via Server.SetLLM in Phase 2) — no new config knob, no per-feature gating. Asymmetric opt-out (yes-elaborate, no-CI-triage) deferred until there's actual demand. Tests: - enrichCIInstructions: nil client, LLM 500, empty body all return fallback unchanged. - enrichCIInstructions: success path produces enriched body with metadata header preserved; user prompt contains repo/branch/SHA. - enrichCIInstructions: real git repo (init + 2 commits) → recent commits appear in user prompt. - Webhook handler regression guard: no-LLM path produces the exact legacy template substrings. - Webhook handler with LLM stubbed: task instructions contain LLM body + metadata header. Plan: docs/plans/local-oss-runner.md. https://claude.ai/code/session_017Edeq947TpSm1vQTxMhi1J
2026-04-28feat(api): route elaboration through local LLM when configuredClaude
Phase 2 of "local OSS models as agents" plan. Adds a third elaboration path that calls the local OpenAI-compatible LLM via the internal/llm client, and reorders dispatch so the cheap path is tried first: local → claude → gemini, with each next attempt only on hard failure of the prior. Wiring is opt-out, not opt-in: when [local_model].endpoint is set, elaboration prefers local by default. Users with a slow or low-quality local model can disable just elaboration via: [local_model] endpoint = "..." prefer_for_elaborate = false without giving up the runner or the classifier path. Implementation: - Server gains an optional *llm.Client field via SetLLM (matches the existing SetNotifier/SetWorkspaceRoot setter pattern, no NewServer signature break). - elaborateWithLocal() reuses buildElaboratePrompt verbatim and asks for response_format=json_object so we skip markdown-fence cleanup. - handleElaborateTask reorders try chain; existing Claude-first behavior is preserved exactly when SetLLM is not called. - LocalModel.UseForElaborate() encapsulates the default-true gating with a *bool so explicit-false survives TOML parse. Tests: - elaborateWithLocal: parses valid response, errors on nil client, errors on bad JSON. - handler: local preferred when wired; falls back to claude when local fails; unchanged behavior when no LLM is configured. - config: UseForElaborate gating across empty/default/explicit-true/ explicit-false cases. Pre-existing test failures noted in docs/plans/local-oss-runner.md (post-epic cleanup): TestGeminiLogs_ParsedCorrectly returns 404 for gemini execution log fetch — predates this change. Plan: docs/plans/local-oss-runner.md. https://claude.ai/code/session_017Edeq947TpSm1vQTxMhi1J
2026-04-11fix: tie pool submissions to server lifecycle contextClaude Agent
Fix 1 (server.go): Replace context.Background() with s.ctx in handleAnswerQuestion, handleResumeTimedOutTask, and handleRunTask. Add a ctx field to Server (defaulting to context.Background()) and a SetContext method so the serve command can wire in the signal- cancellable lifecycle context. Fix 2 (serve.go): Call srv.SetContext(ctx) before StartHub so all pool submissions use the server's root context (already cancelled on SIGTERM/SIGINT). Pool.Shutdown and its wiring were already present. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11cleanup: remove dead code (QuestionRegistry, changestats wrappers, scanner.Err)Claudomator Agent
Fix 1: Remove QuestionRegistry and related types (QuestionHandler, PendingQuestion) from question.go -- nothing reads Pool.Questions or uses the registry. Remove NewQuestionRegistry() call from NewPool and the Questions field from Pool. Remove the now-superfluous registry tests; keep stream/parse helpers which are still used by the claude runner. Fix 2: Check scanner.Err() after the parseStream loop so I/O errors from the scanner are not silently swallowed when streamErr is still nil. Fix 3: Delete internal/api/changestats.go -- the parseChangestatFromFile and parseChangestatFromOutput wrappers were only needed to support processResult(), which no longer calls them; they are unreachable dead code. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04feat: acceptance_criteria per story task in elaboration and approvalPeter Stone
Add AcceptanceCriteria field to elaboratedStoryTask struct, update buildStoryElaboratePrompt schema and rules, pass the value through handleApproveStory into task.Task, and add a test verifying the field is persisted on approved story tasks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04feat: story ship gate — explicit POST /api/stories/{id}/ship; remove ↵Peter Stone
auto-deploy - checkStoryCompletion now guards against re-running on already-SHIPPABLE stories and no longer auto-triggers triggerStoryDeploy on completion - New Pool.ShipStory method validates SHIPPABLE state then fires triggerStoryDeploy - POST /api/stories/{id}/ship route registered and handleShipStory handler added - Two new tests: 202 for SHIPPABLE story, 409 for non-SHIPPABLE story Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03feat: require repository_url on tasks; fix UpdateTask to persist it; fix ↵Peter Stone
cascade-retry test race Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03fix: remove drain-lock circuit breaker that halted all executions after 3 ↵Peter Stone
consecutive failures Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26feat: graceful shutdown — drain workers before exit (default 3m timeout)Peter Stone
- Add workerWg to Pool; Shutdown() closes workCh and waits for all in-flight execute/executeResume goroutines to finish - Signal handler now shuts down HTTP first, then drains the pool - ShutdownTimeout config field (toml: shutdown_timeout); default 3m - Tests: WaitsForWorkers and TimesOut Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26feat: cascade retry deps when running a task with failed dependenciesPeter Stone
When /run is called on a CANCELLED/FAILED task that has deps in a terminal failure state, automatically reset and resubmit those deps so the task isn't immediately re-cancelled by the pool's dep check. Also update reset-failed-tasks script to handle CANCELLED tasks and clean up preserved sandbox workspaces. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26fix: story branch push to bare repo; drain at 3 consecutive failuresPeter Stone
createStoryBranch was pushing to 'origin' which doesn't exist — branches never landed in the bare repo so agents couldn't clone them. Now uses the project's RemoteURL (bare repo path) directly for fetch and push. Raise drain threshold from 2 to 3 consecutive failures to reduce false positives from transient errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26fix: resolve dep-chain deadlock; broadcast task_started for UI visibilityPeter Stone
With maxPerAgent=1, tasks with DependsOn were entering waitForDependencies while holding the per-agent slot, preventing the dependency from ever running. Fix: check deps before taking the slot. If not ready, requeue without holding activePerAgent. Also accept StateReady (leaf tasks) as a satisfied dependency, not just StateCompleted. Add startedCh to pool and broadcast task_started WebSocket event when a task transitions to RUNNING, so the UI immediately shows the running state during the clone phase instead of waiting for completion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26fix: set RepositoryURL on tasks created via story approvePeter Stone
handleApproveStory was creating tasks without RepositoryURL, causing executions to fail with "task has no repository_url". Now looks up the project's RemoteURL and sets it on all tasks and subtasks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26fix: story tasks get Project field; elaborate reads worklog; deploy chmod ↵Peter Stone
scripts - handleApproveStory: set Project = input.ProjectID on tasks and subtasks so the executor can resolve RepositoryURL from the project registry (was causing "task has no repository_url" on every story task) - elaborate.go: read .agent/worklog.md instead of SESSION_STATE.md for project context injected into elaboration prompts - deploy: explicitly chmod +x all scripts before restart (same root cause as the binary execute-bit loss — chown -R was stripping it) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25chore: replace all master branch references with mainPeter Stone
- executor.go: merge story branch to main before deploy - container.go: error messages reference git push origin main - api/stories.go: create story branch from origin/main (drop master fallback) - executor_test.go: test setup uses main branch Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23feat: Phase 4 — story-aware execution, branch clone, story completion ↵Claudomator Agent
check, deployment status - ContainerRunner: add Store field; clone with --reference when story has a local project path; checkout story branch after clone; push to story branch instead of HEAD - executor.Store interface: add GetStory, ListTasksByStory, UpdateStoryStatus - Pool.handleRunResult: trigger checkStoryCompletion when a story task succeeds - Pool.checkStoryCompletion: transitions story to SHIPPABLE when all tasks done - serve.go: wire Store into each ContainerRunner - stories.go: update createStoryBranch to fetch+checkout from origin/master base; add GET /api/stories/{id}/deployment-status endpoint - server.go: register deployment-status route - Tests: TestPool_CheckStoryCompletion_AllComplete/PartialComplete, TestHandleStoryDeploymentStatus Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22feat: color logo based on build version hashPeter Stone
Adds GET /api/version endpoint and uses the first 6 hex chars of the commit hash to derive an HSL hue for the header h1 logo color. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22feat: Phase 5 — story elaboration endpoint, approve flow, branch creationClaudomator Agent
- POST /api/stories/elaborate: runs Claude/Gemini against project LocalPath to produce a structured story plan (name, branch_name, tasks, validation) - POST /api/stories/approve: creates story + sequentially-wired tasks/subtasks from the elaborate output and pushes the story branch to origin - createStoryBranch helper: git checkout -b + push -u origin - Tests: TestBuildStoryElaboratePrompt, TestHandleStoryApprove_WiresDepends Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22feat: surface error_msg on failed task cards in UIPeter Stone
2026-03-22feat: Phase 3 — stories data model, ValidStoryTransition, storage CRUD, ↵Claudomator Agent
API endpoints - internal/task/story.go: Story struct, StoryState constants, ValidStoryTransition - internal/task/task.go: add StoryID field - internal/storage/db.go: stories table + story_id on tasks migrations; CreateStory, GetStory, ListStories, UpdateStoryStatus, ListTasksByStory; update all task SELECT/INSERT to include story_id; scanTask extended with sql.NullString for story_id; added modernc timestamp format to GetMaxUpdatedAt - internal/storage/sqlite_cgo.go + sqlite_nocgo.go: build-tag based driver selection (mattn/go-sqlite3 with CGO, modernc.org/sqlite pure-Go fallback) so tests run without a C compiler - internal/api/stories.go: GET/POST /api/stories, GET /api/stories/{id}, GET/POST /api/stories/{id}/tasks (auto-wires depends_on chain), PUT /api/stories/{id}/status (validates transition) - internal/api/server.go: register all story routes - go.mod/go.sum: add modernc.org/sqlite pure-Go dependency Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21feat: executor reliability — per-agent limit, drain gate, pre-flight ↵Claudomator Agent
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>
2026-03-21feat: Phase 2 — project registry, legacy field cleanup, credential path fixPeter Stone
- task.Project type + storage CRUD + UpsertProject + SeedProjects - Remove AgentConfig.ProjectDir, RepositoryURL, SkipPlanning - Remove ContainerRunner fallback git init logic - Project API endpoints: GET/POST /api/projects, GET/PUT /api/projects/{id} - processResult no longer extracts changestats (pool-side only) - claude_config_dir config field; default to credentials/claude/ - New scripts: sync-credentials, fix-permissions, check-token Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19feat: add errors, throughput, and billing sections to stats dashboardPeter Stone
- GET /api/stats?window=7d: pre-aggregated SQL queries for errors, throughput, billing - Errors section: category summary (quota/rate_limit/timeout/git/failed) + failure table - Throughput section: stacked hourly bar chart (completed/failed/other) over 7d - Billing section: KPIs (7d total, avg/day, cost/run) + daily cost bar chart Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19feat: agent status dashboard with availability timeline and Gemini quota ↵Peter Stone
detection - Detect Gemini TerminalQuotaError (daily quota) as BUDGET_EXCEEDED, not generic FAILED - Surface container stderr tail in error so quota/rate-limit classifiers can match it - Add agent_events table to persist rate-limit start/recovery events across restarts - Add GET /api/agents/status endpoint returning live agent state + 24h event history - Stats dashboard: agent status cards, 24h availability timeline, per-run execution table Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18fix: address final container execution issues and cleanup review docsPeter Stone
2026-03-18fix: comprehensive addressing of container execution review feedbackPeter Stone
- 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.
2026-03-18feat: implement containerized repository-based execution modelPeter Stone
This commit implements the architectural shift from local directory-based sandboxing to containerized execution using canonical repository URLs. Key changes: - Data Model: Added RepositoryURL and ContainerImage to task/agent configs. - Storage: Updated SQLite schema and queries to handle new fields. - Executor: Implemented ContainerRunner using Docker/Podman for isolation. - API/UI: Overhauled task creation to use Repository URLs and Image selection. - Webhook: Updated GitHub webhook to derive Repository URLs automatically. - Docs: Updated ADR-005 with risk feedback and added ADR-006 to document the new containerized model. - Defaults: Updated serve command to use ContainerRunner for all agents. This fixes systemic task failures caused by build dependency and permission issues on the host system.
2026-03-16fix: prefix SW registration path with BASE_PATHPeter Stone
The app is served at /claudomator/ so the SW and scope must use BASE_PATH + '/api/push/sw.js' and BASE_PATH + '/' respectively. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16feat: expose project field in API and CLIClaudomator Agent
- POST /api/tasks now reads and stores the project field from request body - GET /api/tasks/{id} returns project in response (via Task struct json tags) - list command: adds PROJECT column to tabwriter output - status command: prints Project line when non-empty - Tests: TestProject_RoundTrip (API), TestListTasks_ShowsProject, TestStatusCmd_ShowsProject (CLI) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16fix: serve sw.js from /api/push/sw.js to bypass Apache static file routingPeter Stone
Apache fronts the Go service and only proxies /api/ paths; /sw.js hits Apache's filesystem and 404s. Serve the service worker from /api/push/sw.js with Service-Worker-Allowed: / so the browser allows it to control the full origin scope. Update SW registration URL. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16feat: add web push notifications and file dropPeter Stone
Web Push: - WebPushNotifier with VAPID auth; urgency mapped to event type (BLOCKED=urgent, FAILED=high, COMPLETED=low) - Auto-generates VAPID keys on first serve, persists to config file - push_subscriptions table in SQLite (upsert by endpoint) - GET /api/push/vapid-key, POST/DELETE /api/push/subscribe endpoints - Service worker (sw.js) handles push events and notification clicks - Notification bell button in web UI; subscribes on click File Drop: - GET /api/drops, GET /api/drops/{filename}, POST /api/drops - Persistent ~/.claudomator/drops/ directory - CLAUDOMATOR_DROP_DIR env var passed to agent subprocesses - Drops tab (📁) in web UI with file listing and download links Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16feat: display deployment status badge on READY task cardsClaudomator Agent
Add deployment_status field to task list/get API responses for READY tasks. The field includes deployed_commit, fix_commits, and includes_fix so the UI can show whether the deployed server includes each fix. - internal/api/task_view.go: taskView struct + enrichTask() helper - handleListTasks/handleGetTask: return enriched taskView responses - web/app.js: export renderDeploymentBadge(); add badge to READY cards - web/test/deployment-badge.test.mjs: 8 tests for renderDeploymentBadge - web/style.css: .deployment-badge--deployed / --pending styles - server_test.go: 3 new tests (red→green) for enriched task responses Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16fix: repair test regressions and add pre-commit/pre-push verification gatesPeter Stone
Fix four pre-existing bugs exposed after resolving a build failure: - sandboxCloneSource: accept any URL scheme for origin remote (was filtering out https://) - setupSandbox callers: fix := shadow variable so sandboxDir is set on BlockedError - parseGeminiStream: parse result lines to return execution errors and cost - TestElaborateTask_InvalidJSONFromClaude: stub Gemini fallback so test is hermetic Add verification infrastructure: - scripts/verify: runs go build + go test -race, used by hooks and deploy - scripts/hooks/pre-commit: blocks commits that don't compile - scripts/hooks/pre-push: blocks pushes where tests fail - scripts/install-hooks: symlinks version-controlled hooks into .git/hooks/ - scripts/deploy: runs scripts/verify before building the binary Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16feat: add GitHub webhook endpoint for automatic CI failure task creationClaudomator Agent
Adds POST /api/webhooks/github that receives check_run and workflow_run events and creates a Claudomator task to investigate and fix the failure. - Config: new webhook_secret and [[projects]] fields in config.toml - HMAC-SHA256 validation when webhook_secret is configured - Ignores non-failure events (success, skipped, etc.) with 204 - Matches repo name to configured project dirs (case-insensitive) - Falls back to single project when no name match found - 11 new tests covering all acceptance criteria Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16feat: add deployment status endpoint for tasksPeter Stone
Adds GET /api/tasks/{id}/deployment-status which checks whether the currently-deployed server binary includes the fix commits from the task's latest execution. Uses git merge-base --is-ancestor to compare commit hashes against the running version. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16fix: permission denied and host key verification errors; add gemini ↵Peter Stone
elaboration fallback
2026-03-16feat: add elaboration_input field to tasks for richer subtask placeholderClaudomator Agent
- Add ElaborationInput field to Task struct (task.go) - Add DB migration and update CREATE/SELECT/scan in storage/db.go - Update handleCreateTask to accept elaboration_input from API - Update renderSubtaskRollup in app.js to prefer elaboration_input over description - Capture elaborate prompt in createTask() form submission - Update subtask-placeholder tests to cover elaboration_input priority - Fix missing io import in gemini.go When a task card is waiting for subtasks, it now shows: 1. The raw user prompt from elaboration (if stored) 2. The task description truncated at word boundary (~120 chars) 3. The task name as fallback 4. 'Waiting for subtasks…' only when all fields are empty Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15feat: overhaul auto-refresh system with intelligent polling and differential ↵Peter Stone
updates
2026-03-14feat(Phase4): add file changes for changestats executor wiringClaude Sonnet 4.6
Files changed: CLAUDE.md, internal/api/changestats.go, internal/executor/executor.go, internal/executor/executor_test.go, internal/task/changestats.go (new) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14feat: expose changestats in API responsesClaudomator Agent
- Add parseChangestatFromOutput/File helpers in internal/api/changestats.go to parse git diff --stat summary lines from execution stdout logs - Wire parser in processResult: after each execution completes, scan the stdout log for git diff stats and persist via UpdateExecutionChangestats - Tests: TestGetTask_IncludesChangestats (verifies processResult wiring), TestListExecutions_IncludesChangestats (verifies storage round-trip) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14testClaudomator Agent
2026-03-14feat: add agent selector to UI and support direct agent assignmentPeter Stone
- Added an agent selector (Auto, Claude, Gemini) to the Start Next Task button. - Updated the backend to pass query parameters as environment variables to scripts. - Modified the executor pool to skip classification when a specific agent is requested. - Added --agent flag to claudomator start command. - Updated tests to cover the new functionality.
2026-03-13fix: only write RAW_NARRATIVE.md when user explicitly provides project_dirPeter Stone
Previously appendRawNarrative was called with the server's default workDir (os.Getwd()) when no project_dir was in the request, causing test runs and any elaboration without a project to pollute the repo's own RAW_NARRATIVE.md. The narrative is per-project human input — only write it when the caller explicitly specifies which project they're working in. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13merge: resolve conflicts with local/master (stats tab + summary styles)Peter Stone
Keep file-based summary approach (CLAUDOMATOR_SUMMARY_FILE) from HEAD. Combine Q&A History and Stats tab CSS from both branches. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>