summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
5 daysfeat: populate RepositoryURL from project registry in executor (ADR-007)Peter Stone
- Add GetProject to Store interface used by executor - Resolve RepositoryURL from project registry when task.RepositoryURL is empty - Call SeedProjects at server startup so the project registry is populated - Add GetProject stub to minimalMockStore in executor tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6 dayschore: unify and centralize agent configuration in .agent/Peter Stone
6 daysfeat: 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>
6 daysfeat: 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>
6 daysfeat: surface error_msg on failed task cards in UIPeter Stone
6 daysfeat: 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>
7 daysfix: make requeueDelay configurable to fix test timeout in ↵Peter Stone
TestPool_MaxPerAgent_BlocksSecondTask
7 daysfeat: 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>
7 daysfix: set credentials readable by www-data (group 640) in sync-credentialsPeter Stone
7 daysfix: copy .claude.json (account settings) alongside credentialsPeter Stone
ClaudeConfigDir moved from /root/.claude to credentials/claude/, but container.go was still deriving .claude.json from filepath.Dir which no longer pointed anywhere useful. Claude CLI needs .claude.json for OAuth account info or it says "Not logged in". Also update sync-credentials to copy /root/.claude.json into the credentials dir so it stays fresh alongside the token. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7 daysfeat: fail loudly when agent leaves uncommitted work in sandboxPeter Stone
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>
7 dayschore: gitignore .claude/, credentials/, scripts/.claude/Peter Stone
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7 daysfeat: 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>
7 daysfeat: add cancel and cancel-all-failed to ct-taskPeter Stone
Adds ct-task cancel <prefix> (works from any state, falls back to direct DB update for terminal states) and ct-task cancel-all-failed to clear out stuck FAILED tasks in bulk. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7 dayschore: delegate permissions and credential sync to scripts in deployPeter Stone
Replace hardcoded chown/chmod lines with fix-permissions and sync-credentials scripts, keeping deploy DRY and ensuring credentials are always fresh after each deploy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7 daysfix: use configured claude_config_dir for container credentialsPeter Stone
The server runs as www-data whose HOME is /var/www — deriving credentials from $HOME/.claude always produced an empty path. Now reads from ClaudeConfigDir (default: /workspace/claudomator/credentials/claude), which sync-credentials keeps populated with fresh OAuth tokens. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8 daysdocs: update ADR-007 with validation pipeline and nav projectPeter Stone
- Story state machine: SHIPPABLE → DEPLOYED → VALIDATING → REVIEW_READY | NEEDS_FIX - Merge-first strategy: no branch review phase, tests are the confidence mechanism - Elaborator owns validation spec (type, steps, success_criteria) - Validation types: curl | tests | playwright | gradle - Nav project (Android): deploy = push to GitHub, validate = gradle test/lint - Project registry: type + deploy_script fields, initial claudomator + nav entries - Out of scope: branch review deferred, CI polling out of band for nav Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
9 dayschore: improve debug-execution script and add ADR-007Peter Stone
- debug-execution: default to most recent execution when no ID given - docs/adr/007: planning layer and story model design decisions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
9 daysfeat: 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>
9 daysfeat: 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>
10 daysMerge branch 'master' of /site/git.terst.org/repos/claudomatorPeter Stone
10 daysMerge feat/container-execution into masterPeter Stone
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
10 daysfeat: containerized execution with agent tooling and deployment fixesPeter Stone
- 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>
10 daysdocs: add REFACTOR_PLAN.md with codebase analysis findingsClaudomator Agent
Analyzed claudomator for architectural integrity, test coverage gaps, and bugs. Documents 1 critical race condition (QuestionRegistry.Answer panics on closed channel), 2 medium issues (sandbox leak, VAPID private key validation), and 8 minor issues covering error handling, test coverage gaps, and code duplication. 11 discrete subtasks created in Claudomator for each actionable item. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
10 daysfix: address final container execution issues and cleanup review docsPeter Stone
10 daysfix: address round 3 review feedback for container executionPeter Stone
- 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
10 daysfix: address round 2 review feedback for container executionPeter Stone
- 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
10 daysfix: 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.
10 daysfeat: 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.
10 daysfix: unsubscribe stale push subscription before re-subscribingClaudomator Agent
When the VAPID key changes (e.g. after the key-swap fix), the browser's cached PushSubscription was created with the old key. Calling PushManager.subscribe() with a different applicationServerKey then throws "The provided applicationServerKey is not valid". Fix by calling getSubscription()/unsubscribe() before subscribe() so any stale subscription is cleared. Adds web test covering both the stale and fresh subscription paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
11 daysfeat: persist active main tab to localStorageClaudomator Agent
On tab click, store the tab name under 'activeMainTab' in localStorage. On DOMContentLoaded, restore the previously active tab instead of always defaulting to 'queue'. Exported getActiveMainTab/setActiveMainTab for testability, following the same pattern as getTaskFilterTab/setTaskFilterTab. Tests: web/test/tab-persistence.test.mjs (6 tests, all green). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
11 dayschore: autocommit uncommitted changesClaudomator Agent
11 daysfix: unsubscribe stale push subscription before re-subscribingClaudomator Agent
When the VAPID key changes (e.g. after the key-swap fix), the browser's cached PushSubscription was created with the old key. Calling PushManager.subscribe() with a different applicationServerKey then throws "The provided applicationServerKey is not valid". Fix by calling getSubscription()/unsubscribe() before subscribe() so any stale subscription is cleared. Adds web test covering both the stale and fresh subscription paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
11 daysfix: validate VAPID public key on load, regenerate if swappedClaudomator Agent
The DB may contain keys generated before the swap fix, with the private key stored as the public key. Add ValidateVAPIDPublicKey() and use it in serve.go to detect and regenerate invalid stored keys on startup. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
11 daysfix: swap VAPID key return order in GenerateVAPIDKeys wrapperClaudomator Agent
webpush.GenerateVAPIDKeys() returns (privateKey, publicKey) but the claudomator wrapper declared (publicKey, privateKey), causing the 32-byte private key to be sent to browsers as the applicationServerKey. Browsers require a 65-byte uncompressed P256 point, so they rejected it with "The provided applicationServerKey is not valid." Adds a regression test that asserts public key is 87 chars/65 bytes with 0x04 prefix and private key is 43 chars/32 bytes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 daysfix: wait for service worker to activate before subscribing to pushPeter Stone
navigator.serviceWorker.register() returns before the SW is active. Use navigator.serviceWorker.ready which resolves only once a SW is controlling the page, so pushManager.subscribe() always has an active SW. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 daysfix: 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>
12 daysfix: hide deployment badge when not deployed and trim notification button labelPeter Stone
- Deployment badge now returns null (hidden) when includes_fix is false instead of showing "Not deployed" noise - Badge also suppressed when fix_commits is empty (no tracked commits to check) - Notification button label trimmed to just the bell emoji - Preamble: warn agents not to use absolute paths in git commands (sandbox bypass) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 daysdocs: update SESSION_STATE.md for project field featureClaudomator Agent
12 daysfeat: 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>
12 daysfeat: display project field in web UIClaudomator Agent
Show task.project as a badge in task card meta row and as a field in the task detail overview grid. Both display conditionally only when project is non-empty. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 daysfix: 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>
12 daysfix: persist VAPID keys in DB instead of config filePeter Stone
The service runs as www-data which cannot write to the root-owned config file. VAPID keys are now stored in the settings table in SQLite (which is writable), loaded on startup, and generated once. Removes saveVAPIDToConfig and the stale warning on every restart. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 daysfeat: 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>
12 daysfeat: add project column to storageClaudomator Agent
Adds project TEXT column to tasks table via additive migration, updates CreateTask INSERT, all SELECT queries, and scanTask to persist and retrieve Task.Project. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 daysfeat: 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>
12 daysfeat: add Project field to Task struct and YAML parsingClaudomator Agent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 daysfix: clean up activePerAgent before sending to resultChClaudomator Agent
Move activePerAgent decrement/deletion out of execute() and executeResume() defers and into the code paths immediately before each resultCh send (handleRunResult and early-return paths). This guarantees that when a result consumer reads from the channel the map is already clean, eliminating a race between defer and result receipt. Remove the polling loop from TestPool_ActivePerAgent_DeletesZeroEntries and check the map state immediately after reading the result instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 daysfix: deploy script skips scripts/hooks/ subdirectory when copyingPeter Stone
cp without -r fails on directories. Use find -maxdepth 1 -type f to copy only files, since hooks/ is for local dev only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 daysfix: eliminate flaky race in TestPool_ActivePerAgent_DeletesZeroEntriesPeter Stone
The deferred activePerAgent cleanup in execute() runs after resultCh is sent, so a consumer reading Results() could observe the map entry before it was removed. Poll briefly (100ms max) instead of checking immediately. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>