<feed xmlns='http://www.w3.org/2005/Atom'>
<title>claudomator.git/internal/executor/gemini.go, branch fix/dockersandbox-gitpush-host-security</title>
<subtitle>claudomator — task automation server
</subtitle>
<id>https://git.terst.org/claudomator.git/atom?h=fix%2Fdockersandbox-gitpush-host-security</id>
<link rel='self' href='https://git.terst.org/claudomator.git/atom?h=fix%2Fdockersandbox-gitpush-host-security'/>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/'/>
<updated>2026-05-25T18:59:06+00:00</updated>
<entry>
<title>refactor(executor): delete the dead GeminiRunner stub and its sandbox helpers (Phase 4)</title>
<updated>2026-05-25T18:59:06+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-25T18:59:06+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=c0fabf5a2f4ca371403571b82e29c5073bed24fb'/>
<id>urn:sha1:c0fabf5a2f4ca371403571b82e29c5073bed24fb</id>
<content type='text'>
The production "gemini" agent type is served by ContainerRunner (Docker), not by
the standalone subprocess GeminiRunner, which was never wired into serve.go and
returned canned/simulated output — the dangerous landmine called out in
CLAUDE.md's design debt. Removing it (gemini.go + tests).

The subprocess sandbox helpers (setupSandbox/teardownSandbox/sandboxCloneSource
in sandbox.go), preserved in Phase 2 only because GeminiRunner used them, are now
orphaned — ContainerRunner has its own git/workspace handling — so they go too.

No production behavior change: nothing instantiated GeminiRunner. Build green;
executor tests unchanged except the pre-existing git commit-signing failures.

https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
</content>
</entry>
<entry>
<title>feat(executor): introduce AgentChannel seam for runner signals</title>
<updated>2026-05-24T08:47:07+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-24T08:47:07+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=c7d95f3992d24f86ff71e5f3e18260a8ef8a09f0'/>
<id>urn:sha1:c7d95f3992d24f86ff71e5f3e18260a8ef8a09f0</id>
<content type='text'>
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
</content>
</entry>
<entry>
<title>feat(executor): bring GeminiRunner to sandbox-flow parity with Claude</title>
<updated>2026-05-12T21:03:30+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-12T21:03:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=e7171181fff10c66b2b74eabfb1fc94b3cfbb4fb'/>
<id>urn:sha1:e7171181fff10c66b2b74eabfb1fc94b3cfbb4fb</id>
<content type='text'>
All coding tasks now follow the same flow regardless of runner: when
project_dir is set, the agent runs in a temp clone, not in the user's
working tree. On success, edits are autocommitted and pushed back to
origin/master and the sandbox is removed. On failure or BLOCKED, the
sandbox is preserved and its path surfaces in the error / BlockedError
so the user can inspect partial work or resume in place.

Before this commit, GeminiRunner.Run set cmd.Dir to project_dir
directly, so an agent run could leave half-done edits in the user's
working tree with no rollback. ClaudeRunner has had the full sandbox
flow for a while; this commit closes the gap.

Reused the existing package-level helpers from claude.go verbatim:
setupSandbox, teardownSandbox, sandboxCloneSource, gitSafe, plus the
resume/stale-sandbox/blocked-error patterns. No new shared abstraction
needed — same package.

LocalRunner intentionally not changed. The OpenAI chat path has no
tool use, so the agent can't edit files; sandbox would be theater.

Tests (6 new):
- Run_ProjectDir_RunsInSandbox: cwd captured by fake binary is a
  sandbox path, not project_dir.
- Run_BlockedError_IncludesSandboxDir: when question.json appears,
  BlockedError.SandboxDir is set and the dir exists.
- Run_ExecError_PreservesSandbox: failing exit wraps error with
  "(sandbox preserved at &lt;path&gt;)" and the path exists on disk.
- Run_ResumeUsesStoredSandboxDir: ResumeSessionID + SandboxDir →
  runs in that dir without re-cloning.
- Run_StaleSandboxDir_ClonesAfresh: resume pointing at missing
  dir falls back to a fresh clone from project_dir.
- Run_NoProjectDir_SkipsSandbox: tasks without project_dir don't
  trigger sandbox setup.

https://claude.ai/code/session_017Edeq947TpSm1vQTxMhi1J
</content>
</entry>
<entry>
<title>chore: close deferred work — real GeminiRunner, Local UI option, db.go cleanup</title>
<updated>2026-05-03T08:00:20+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-03T08:00:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=e7b382bf177cbe518af3d86c3ee6c49344d225f4'/>
<id>urn:sha1:e7b382bf177cbe518af3d86c3ee6c49344d225f4</id>
<content type='text'>
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
</content>
</entry>
<entry>
<title>chore: post-epic cleanup — green test suite, no skips</title>
<updated>2026-05-03T03:58:19+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-03T03:58:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=85c3bf4d28b0903a2005356339e6ea56855b8c80'/>
<id>urn:sha1:85c3bf4d28b0903a2005356339e6ea56855b8c80</id>
<content type='text'>
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
</content>
</entry>
<entry>
<title>fix: permission denied and host key verification errors; add gemini elaboration fallback</title>
<updated>2026-03-16T01:46:20+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-16T01:46:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=0e37086ee468e6e3b697c32b7f02280ee06f5116'/>
<id>urn:sha1:0e37086ee468e6e3b697c32b7f02280ee06f5116</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat: add elaboration_input field to tasks for richer subtask placeholder</title>
<updated>2026-03-16T01:10:00+00:00</updated>
<author>
<name>Claudomator Agent</name>
<email>agent@claudomator</email>
</author>
<published>2026-03-16T01:10:00+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=d911021b7e4a0c9f77ca9996b0ebdabb03c56696'/>
<id>urn:sha1:d911021b7e4a0c9f77ca9996b0ebdabb03c56696</id>
<content type='text'>
- 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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: fix task failures via sandbox improvements and display commits in Web UI</title>
<updated>2026-03-15T03:39:49+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-15T03:39:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=6ff67a57d72317360cacd4b41560395ded117d20'/>
<id>urn:sha1:6ff67a57d72317360cacd4b41560395ded117d20</id>
<content type='text'>
- 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.
</content>
</entry>
<entry>
<title>fix: surface agent stderr, auto-retry restart-killed tasks, handle stale sandboxes</title>
<updated>2026-03-14T07:37:20+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-14T07:37:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=4029fdd82bdd657ed862c89f20eb03ff2594cde9'/>
<id>urn:sha1:4029fdd82bdd657ed862c89f20eb03ff2594cde9</id>
<content type='text'>
#1 - Diagnostics: tailFile() reads last 20 lines of subprocess stderr and
appends to error message when claude/gemini exits non-zero. Previously all
exit-1 failures were opaque; now the error_msg carries the actual subprocess
output.

#4 - Restart recovery: RecoverStaleRunning() now re-queues tasks after
marking them FAILED, so tasks killed by a server restart automatically
retry on the next boot rather than staying permanently FAILED.

#2 - Stale sandbox: If a resume execution's preserved SandboxDir no longer
exists (e.g. /tmp purge after reboot), clone a fresh sandbox instead of
failing immediately with "no such file or directory".

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix: enable Gemini file writing by passing --yolo and -p flags</title>
<updated>2026-03-13T05:24:20+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-13T05:24:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=fb0e4b44393bae3c54f099bea87dfea19854d058'/>
<id>urn:sha1:fb0e4b44393bae3c54f099bea87dfea19854d058</id>
<content type='text'>
GeminiRunner.buildArgs was missing --yolo (auto-approve all tools)
so the gemini CLI only registered 3 tools (read_file, write_todos,
cli_help) and write_file was not available. Agents that needed to
create files silently failed (exit 0, no files written).

Also switch instructions from bare positional arg to -p flag, which
is required for non-interactive headless mode.

Update preamble tests to match file-based summary approach
(CLAUDOMATOR_SUMMARY_FILE) kept from the merge conflict resolution.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
