| Age | Commit message (Collapse) | Author |
|
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
|
|
Phase 1 of "local OSS models as agents" plan. Adds a third Runner
backed by any OpenAI-compatible HTTP server (Ollama, vLLM, LM Studio,
llama.cpp), and migrates the Gemini-CLI classifier to route through
the same client when configured.
Two-layer split: internal/llm.Client is the workhorse (HTTP, no Pool,
no DB) used directly by the classifier and any future internal helper
that needs cheap reasoning. internal/executor.LocalRunner is a thin
adapter implementing Runner for user-facing tasks. This avoids
Pool reentrancy/deadlock when sub-second internal calls fire from
inside Pool.execute().
Highlights:
- internal/retry: relocated runWithBackoff/IsRateLimitError/ParseRetryAfter
into a shared package reused by executor and llm.
- internal/llm: Chat (non-streaming) and ChatStream (SSE) over
/chat/completions with optional bearer auth, json_object response
format, retry on 429/503, Retry-After parsing.
- internal/executor/LocalRunner: streams deltas into stdout.log in the
same stream-json envelope ClaudeRunner emits, then writes one
consolidated assistant block plus a result terminator so existing
parsers (extractSummary, ParseChangestatFromOutput) work unchanged.
- internal/executor/Classifier: gains optional LLM field; uses
json_object response format (no markdown-fence cleanup needed).
Falls back to Gemini-CLI subprocess when LLM is nil.
- Pool.skipClassification: now skips only when the requested agent
type is registered, so unknown types still reach the load balancer.
- Storage: additive tokens_in/tokens_out ALTERs on executions; CLI
runners record cost_usd as before, LocalRunner records 0 + tokens.
- Config: [local_model] section (endpoint, model, timeout_seconds,
default_temperature, api_key). Empty endpoint = no LocalRunner
registered, classifier falls back to Gemini.
Pre-existing test issues fixed in passing:
- claude_test.go setupSandbox callsites updated to current signature.
- gemini_test.go TestParseGeminiStream skipped (asserts unimplemented
GeminiRunner stream-error parsing; tracked separately).
Plan: docs/plans/local-oss-runner.md.
https://claude.ai/code/session_017Edeq947TpSm1vQTxMhi1J
|
|
- 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>
|
|
updates
|
|
- Fix ephemeral sandbox deletion issue by passing $CLAUDOMATOR_PROJECT_DIR to agents and using it for subtask project_dir.
- Implement sandbox autocommit in teardown to prevent task failures from uncommitted work.
- Track git commits created during executions and persist them in the DB.
- Display git commits and changestats badges in the Web UI execution history.
- Add badge counts to Web UI tabs for Interrupted, Ready, and Running states.
- Improve scripts/next-task to handle QUEUED tasks and configurable DB path.
|
|
- Add task.Changestats{FilesChanged, LinesAdded, LinesRemoved}
- Add changestats_json column to executions via additive migration
- Add Changestats field to storage.Execution struct
- Add UpdateExecutionChangestats(execID, *task.Changestats) method
- Update all SELECT/INSERT/scan paths for executions
- Test: TestExecution_StoreAndRetrieveChangestats (was red, now green)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Add UpdateTaskAgent to Store interface and DB implementation
- Call UpdateTaskAgent in Pool.execute to persist assigned agent/model
to database before the runner starts
- Update runTask in app.js to pass selected agent as query param
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Extend Resume to CANCELLED, FAILED, and BUDGET_EXCEEDED tasks
- Add summary extraction from agent stdout stream-json output
- Fix storage: persist stdout/stderr/artifact_dir paths in UpdateExecution
- Clear question_json on ResetTaskForRetry
- Resume BLOCKED tasks in preserved sandbox so Claude finds its session
- Add planning preamble: CLAUDOMATOR_SUMMARY_FILE env var + summary step
- Update ADR-002 with new state transitions
- UI style improvements
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
A BLOCKED task that fails on resume would keep its stale question_json
after being restarted. The frontend then showed "waiting for your input"
with the old prompt even though the task was running fresh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
When a task ran in a sandbox (/tmp/claudomator-sandbox-*) and went BLOCKED,
Claude stored its session under the sandbox path as the project slug. The
resume execution was running in project_dir, causing Claude to look for the
session in the wrong project directory and fail with "No conversation found".
Fix: carry SandboxDir through BlockedError → Execution → resume execution,
and run the resume in that directory so the session lookup succeeds.
- BlockedError gains SandboxDir field; claude.go sets it on BLOCKED exit
- storage.Execution gains SandboxDir (persisted via new sandbox_dir column)
- executor.go stores blockedErr.SandboxDir in the execution record
- server.go copies SandboxDir from latest execution to the resume execution
- claude.go uses e.SandboxDir as working dir for resume when set
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Updated handleRunTask to use ResetTaskForRetry, which clears the agent type and model. This ensures that manually restarted tasks are always re-classified, allowing the system to switch to a different agent if the previous one is rate-limited. Also improved Claude quota-exhaustion detection.
|
|
- Remove Claude field alias from Task struct (already removed in sandbox)
- Remove UnmarshalJSON from AgentConfig that silently accepted working_dir
- Remove legacy claude fallback in scanTask (db.go)
- Remove TestGetTask_BackwardCompatibility test that validated removed behavior
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Replace BFS loop with a single recursive CTE to collect all descendant
task IDs in one query, and wrap all DELETE statements in a transaction
so a partial failure cannot leave orphaned executions.
Add TestDeleteTask_DeepSubtaskCascadeAtomic: creates a 3-level task
hierarchy with executions at each level, deletes the root, and verifies
all tasks and executions are removed with an explicit orphan-row check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Add two schema indexes that were missing:
- idx_executions_start_time on executions(start_time): speeds up
ListRecentExecutions WHERE start_time >= ? ORDER BY start_time DESC
- idx_tasks_parent_task_id on tasks(parent_task_id): speeds up
ListSubtasks WHERE parent_task_id = ?
Both use CREATE INDEX IF NOT EXISTS so they are safe to apply on
existing databases without a migration version bump.
Add TestListRecentExecutions_LargeDataset (100 rows, two tasks) covering:
- returns all rows in descending start_time order
- respects the limit parameter
- filters correctly by since time
- filters correctly by task_id
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Removed all template-related code from frontend (tabs, modals, logic) and backend (routes, files, DB table). Updated BUDGET_EXCEEDED tasks to be requeueable with a Restart button. Fixed ReferenceError in isUserEditing for Node.js tests.
|
|
- Resolve conflicts in API server, CLI, and executor.
- Maintain Gemini classification and assignment logic.
- Update UI to use generic agent config and project_dir.
- Fix ProjectDir/WorkingDir inconsistencies in Gemini runner.
- All tests passing after merge.
|
|
UpdateTaskState now validates the transition using ValidTransition inside
a transaction. Invalid transitions return an error rather than blindly
updating. Tests for retry-limit and running-task-rejection test setup
are updated to create tasks with the target state directly via CreateTask
to bypass the transition guard in setup code.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
agent test)
|
|
|
|
Recovered files with no Claude→Agent contamination:
- docs/adr/002-task-state-machine.md
- internal/api/logs.go/logs_test.go: task-level log streaming endpoint
- internal/api/validate.go/validate_test.go: POST /api/tasks/validate
- internal/api/server_test.go, storage/db_test.go: expanded test coverage
- scripts/reset-failed-tasks, reset-running-tasks
- web/app.js, index.html, style.css: frontend improvements
- web/test/: active-tasks-tab, delete-button, filter-tabs, sort-tasks tests
Manually applied from server.go diff (skipping Claude→Agent rename):
- taskLogStore field + validateCmdPath field
- DELETE /api/tasks/{id} route + handleDeleteTask
- GET /api/tasks/{id}/logs/stream route
- POST /api/tasks/{id}/resume route + handleResumeTimedOutTask
- handleCancelTask: allow cancelling PENDING/QUEUED tasks directly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
session_id was set on the Execution struct inside ClaudeRunner.Run but
was missing from the UPDATE query, so it was never written to the DB.
GetLatestExecution then returned an empty session_id, causing the
/answer endpoint to return "no resumable session found".
Also patched the existing blocked execution row directly in the DB.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
When an agent needs user input it writes a question to
$CLAUDOMATOR_QUESTION_FILE and exits. The runner detects the file and
returns BlockedError; the pool transitions the task to BLOCKED and
stores the question JSON on the task record.
The user answers via POST /api/tasks/{id}/answer. The server looks up
the claude session_id from the most recent execution and submits a
resume execution (claude --resume <session-id> "<answer>"), freeing the
executor slot entirely while waiting.
Changes:
- task: add StateBlocked, transitions RUNNING→BLOCKED, BLOCKED→QUEUED
- storage: add session_id to executions, question_json to tasks;
add GetLatestExecution and UpdateTaskQuestion methods
- executor: BlockedError type; ClaudeRunner pre-assigns --session-id,
sets CLAUDOMATOR_QUESTION_FILE env var, detects question file on exit;
buildArgs handles --resume mode; Pool.SubmitResume for resume path
- api: handleAnswerQuestion rewritten to create resume execution
- preamble: add question protocol instructions for agents
- web: BLOCKED state badge (indigo), question text + option buttons or
free-text input with Submit on the task card footer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Top-level tasks now land in READY after successful execution instead of
going directly to COMPLETED. Subtasks (with parent_task_id) skip the gate
and remain COMPLETED. Users accept or reject via new API endpoints:
POST /api/tasks/{id}/accept → READY → COMPLETED
POST /api/tasks/{id}/reject → READY → PENDING (with rejection_comment)
- task: add StateReady, RejectionComment field, update ValidTransition
- storage: migrate rejection_comment column, add RejectTask method
- executor: route top-level vs subtask to READY vs COMPLETED
- api: /accept and /reject handlers with 409 on invalid state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- Task struct gains ParentTaskID field
- DB schema adds parent_task_id column (additive migration)
- DB.ListSubtasks fetches children of a parent task
- DB.UpdateTask allows partial field updates (name, description, state, etc.)
- Templates table added to initial schema
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
Claudomator automation toolkit for Claude Code with:
- Task model with YAML parsing, validation, state machine (49 tests, 0 races)
- SQLite storage for tasks and executions
- Executor pool with bounded concurrency, timeout, cancellation
- REST API + WebSocket for mobile PWA integration
- Webhook/multi-notifier system
- CLI: init, run, serve, list, status commands
- Console, JSON, HTML reporters with cost tracking
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|