<feed xmlns='http://www.w3.org/2005/Atom'>
<title>claudomator.git/internal/config, branch main</title>
<subtitle>claudomator — task automation server
</subtitle>
<id>https://git.terst.org/claudomator.git/atom?h=main</id>
<link rel='self' href='https://git.terst.org/claudomator.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/'/>
<updated>2026-05-13T04:02:20+00:00</updated>
<entry>
<title>merge: integrate github/main — LocalRunner, real GeminiRunner, llm client</title>
<updated>2026-05-13T04:02:20+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-05-13T04:02:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=68399a598924775a3ec22a39c2336ae497fb07f3'/>
<id>urn:sha1:68399a598924775a3ec22a39c2336ae497fb07f3</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(api): route elaboration through local LLM when configured</title>
<updated>2026-04-28T17:10:27+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-04-28T17:10:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=ae833b2765c7c8086bf8e1ea8e8ec8ee9b73e656'/>
<id>urn:sha1:ae833b2765c7c8086bf8e1ea8e8ec8ee9b73e656</id>
<content type='text'>
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
</content>
</entry>
<entry>
<title>feat(executor): add LocalRunner and OpenAI-compat LLM client</title>
<updated>2026-04-28T09:24:43+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-04-28T09:24:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=0865afc43be562dbe14528e4299b9e213b54cc93'/>
<id>urn:sha1:0865afc43be562dbe14528e4299b9e213b54cc93</id>
<content type='text'>
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
</content>
</entry>
<entry>
<title>feat: graceful shutdown — drain workers before exit (default 3m timeout)</title>
<updated>2026-03-26T09:14:14+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-26T09:09:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=3f9843b34d7ae9df2dd9c69427ecab45744b97e9'/>
<id>urn:sha1:3f9843b34d7ae9df2dd9c69427ecab45744b97e9</id>
<content type='text'>
- 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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix: use configured claude_config_dir for container credentials</title>
<updated>2026-03-21T20:51:35+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-21T20:51:35+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=30bb8b45ea515c40da4d46ee12a20f2c7ae75e62'/>
<id>urn:sha1:30bb8b45ea515c40da4d46ee12a20f2c7ae75e62</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix: address final container execution issues and cleanup review docs</title>
<updated>2026-03-18T07:55:27+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-18T07:54:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=a4795d68fc5381f1ff48d043fe7554355e5899fb'/>
<id>urn:sha1:a4795d68fc5381f1ff48d043fe7554355e5899fb</id>
<content type='text'>
</content>
</entry>
<entry>
<title>fix: comprehensive addressing of container execution review feedback</title>
<updated>2026-03-18T07:54:48+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-18T00:52:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=5814e7d6bdec659bb8ca10cc18447a821c59ad4c'/>
<id>urn:sha1:5814e7d6bdec659bb8ca10cc18447a821c59ad4c</id>
<content type='text'>
- 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.
</content>
</entry>
<entry>
<title>feat: add web push notifications and file drop</title>
<updated>2026-03-16T20:43:28+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-16T20:43:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=7f920ca63af5329c19a0e5a879c649c594beea35'/>
<id>urn:sha1:7f920ca63af5329c19a0e5a879c649c594beea35</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: add GitHub webhook endpoint for automatic CI failure task creation</title>
<updated>2026-03-16T05:08:00+00:00</updated>
<author>
<name>Claudomator Agent</name>
<email>agent@claudomator</email>
</author>
<published>2026-03-16T05:08:00+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=c2aa026f6ce1c9e216b99d74f294fc133d5fcddd'/>
<id>urn:sha1:c2aa026f6ce1c9e216b99d74f294fc133d5fcddd</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>cli: implement --config flag to load TOML config file</title>
<updated>2026-03-10T04:36:19+00:00</updated>
<author>
<name>Claudomator Agent</name>
<email>agent@claudomator</email>
</author>
<published>2026-03-10T04:36:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=8873187921c55d94be56364bf0b9d6b2d12127c2'/>
<id>urn:sha1:8873187921c55d94be56364bf0b9d6b2d12127c2</id>
<content type='text'>
The --config flag was registered but silently ignored. Now:
- config.LoadFile loads a TOML file on top of defaults
- PersistentPreRunE applies the file when --config is set
- Explicit CLI flags (--data-dir, --claude-bin) take precedence over the file

Tests: TestLoadFile_OverridesDefaults, TestLoadFile_MissingFile_ReturnsError,
TestRootCmd_ConfigFile_Loaded, TestRootCmd_ConfigFile_CLIFlagOverrides,
TestRootCmd_ConfigFile_Missing_ReturnsError

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