<feed xmlns='http://www.w3.org/2005/Atom'>
<title>claudomator.git/web/style.css, 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-07-04T08:50:46+00:00</updated>
<entry>
<title>feat(web,api): add Budget/Roles dashboard -- final phase of the harness redesign (Phase 9b)</title>
<updated>2026-07-04T08:50:46+00:00</updated>
<author>
<name>Claude Sonnet 5</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-07-04T08:50:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=f8ae821240f33d615a9e91cdfeb6c026b7970782'/>
<id>urn:sha1:f8ae821240f33d615a9e91cdfeb6c026b7970782</id>
<content type='text'>
Two new tabs, matching Phase 9a's conventions: Budget (per-provider spend
meters, escalation funnel, spend-over-time) and Roles (version history,
draft activation, readable escalation-ladder view) -- the human-facing
surface for the token-husbanding value proposition and the Phase 5/8
versioned role-config system.

New backend (minimal, additive, matching existing endpoint conventions --
unauthenticated like /api/budget and /api/roles/*):
- internal/storage/dashboard.go: QueryEscalationFunnel (executions grouped
  by escalation_rung + agent, count + cost) and QuerySpendTimeseries (cost
  per provider bucketed hourly/daily, mirroring QueryDashboardStats'
  existing bucketing expressions). Documented honestly: rung 0 is not
  exclusively "resolved locally" -- escalation_rung defaults to 0
  uniformly, so non-role-typed executions (which never climb a ladder)
  land there too, alongside role-typed tasks genuinely resolved at tier 0.
  A role-only variant would need a join against tasks.config_json with no
  queryable role column on executions -- intentionally out of scope.
- internal/api/dashboard.go: GET /api/escalation-funnel, GET
  /api/spend-timeseries (both ?window=5h|24h|7d|&lt;duration&gt;, default 24h).
- internal/storage.ListRoleNames + GET /api/roles: the "which roles exist"
  gap -- there was no way to discover role names before this, only to list
  versions for a role you already knew the name of.

Chart-form decisions (dataviz skill, invoked before writing chart code):
horizontal stacked bar for the escalation funnel (rung order already
encodes the funnel shape positionally; color only needed for per-provider
segments within each rung); multi-line for spend-over-time; a fixed-order
categorical palette from the skill's validated palette.md slots for
provider identity (re-validated against this app's dark surface, passing);
a separate status (good/warning/critical) palette for budget meters,
deliberately distinct from both --state-* and the provider palette. Caught
and fixed a real bug during visual QA: converging near-zero end-labels on
the spend chart were overlapping (an anti-pattern the skill explicitly
flags) -- fixed with a 14px minimum-gap check before direct-labeling an
endpoint, leaning on the legend/tooltip otherwise.

Verified with a real running server, real seeded data (65 executions across
rungs 0-2 with a realistic provider mix, 2 roles with active/draft/retired
role_configs versions written directly via internal/storage), and a real
headless-browser session (reusing Phase 9a's Chromium/proxy scaffinding):
confirmed correct rung totals/percentages, provider legends, a 3-line spend
chart, live window-selector re-render, correct active-version highlighting
on the role panel, and a real Activate click on a draft version -- verified
via both DOM re-render and a direct backend GET that it truly persisted.

go build/vet/test -race -count=1 all pass, full suite. node --test
web/test/*.mjs: 291/291 passing (16 new).

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01V1moSNCJRcP6kykA4tyUSs
</content>
</entry>
<entry>
<title>feat(web): add Stories tab -- Kanban board, epic swimlanes, story-detail DAG (Phase 9a)</title>
<updated>2026-07-04T05:31:42+00:00</updated>
<author>
<name>Claude Sonnet 5</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-07-04T05:31:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=d105eca610b0e737c3313e4978d6a917b4f55d10'/>
<id>urn:sha1:d105eca610b0e737c3313e4978d6a917b4f55d10</id>
<content type='text'>
First UI work on top of the harness's 8 backend phases -- pure web/*
frontend, no backend changes, keeping the existing embedded vanilla-JS
convention (no build step, no framework).

- Kanban board: columns spanning the full story lifecycle (DISCOVERY/FRAMING
  -&gt; BACKLOG -&gt; PRIORITIZED -&gt; IN_PROGRESS -&gt; VALIDATING/REVIEW_READY -&gt; DONE),
  cards showing priority/acceptance-criteria count/eval-verdict progress.
  Drag-and-drop reorders priority within a column (persisted via a partial
  PUT /api/stories/{id}); cross-column drag is disabled outright (a
  dragover handler only preventDefault()s when the dragged card's own status
  already maps to that column) rather than allowed-then-snapped-back, since
  the latter would visibly misplace a card for several seconds until the
  next poll -- reads as a bug, not a feature.
- Epic swimlanes: stories grouped client-side by epic_id (incl. an
  "Unassigned" lane) with a DONE/total progress meter per epic, built from
  data the board already fetches (avoids N+1 GET /api/epics/{id}/stories
  calls for a result that's a strict subset of the already-loaded list).
- Story detail modal: metadata/spec/acceptance criteria, a BFS-layered plain-
  SVG DAG of the story's task-tree (rows = BFS depth from root_task_id over
  both parent_task_id and depends_on edges, solid vs. dashed strokes
  distinguishing the two edge kinds), an event timeline rendering
  eval_verdict/arbitration_decided/human_accepted/retro_captured/
  epic_proposed with human-readable text, and an Accept button wired to
  POST /api/stories/{id}/accept when status is REVIEW_READY.
- DAG node coloring reuses the app's existing --state-* CSS custom
  properties (the dataviz skill's "reserved status palette" pattern,
  already used elsewhere in the app) rather than introducing a new palette.
  Running the skill's own palette validator against that pre-existing
  9-color set fails its CVD/lightness checks (a pre-existing condition, out
  of scope to fix here since those colors are used elsewhere in the app) --
  mitigated per the skill's documented remedy for a failing palette: every
  node always carries a text label (name + role + state) and a full legend,
  so identity never depends on color alone; edge kind is encoded by stroke
  style, not color.

Verified with a real running server and a real headless-browser session
(Chromium via playwright-core, offline-cached), not just code review:
seeded real data (an epic, 11 stories across every lifecycle status, a
6-node Builder-&gt;4-Evaluator-&gt;Arbitration task tree, 4 story events) via the
live REST API plus two throwaway fixture scripts for the two write paths
the API doesn't expose (task depends_on, direct event writes), then
confirmed via screenshots/DOM assertions: correct column placement for every
status, working swimlane grouping/progress meter, correct 6-node/8-edge DAG
render, working event timeline, a real Accept-button API call flipping
REVIEW_READY-&gt;DONE, real drag-and-drop priority persistence (re-fetched to
confirm), and a genuine cross-column-drag no-op. Caught and fixed a real bug
during this process: DAG node-label truncation now measures
getComputedTextLength() and binary-searches the longest fit, instead of a
fixed character-count budget that collapsed every "Eval: evaluator_X" label
to "Eval:..." (only one space in the string).

go build ./... clean; node --test web/test/*.mjs -- 275 tests pass (19 new).

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01V1moSNCJRcP6kykA4tyUSs
</content>
</entry>
<entry>
<title>feat: execution row click opens unified detail + log viewer</title>
<updated>2026-06-04T00:22:00+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-06-04T00:22:00+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=0d537df08fea539022cbcffe3ea778a3c84e7fb7'/>
<id>urn:sha1:0d537df08fea539022cbcffe3ea778a3c84e7fb7</id>
<content type='text'>
Replace the per-row "View Logs" button with a click handler on the entire
execution row. Clicking opens the logs-modal showing a metadata grid (id,
status, agent, exit code, cost, times, error, log paths) followed by an
inline streaming log viewer. The EventSource is torn down on modal close.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(api,web): budget headroom endpoint + UI chips (Phase 6)</title>
<updated>2026-05-26T20:34:09+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-26T20:34:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=ab4b364954af08fa602388495ca425eaef0abf74'/>
<id>urn:sha1:ab4b364954af08fa602388495ca425eaef0abf74</id>
<content type='text'>
Adds GET /api/budget returning per-provider rolling-window headroom (empty when
budget gating is unconfigured), wired from serve.go via SetBudget. The web UI
polls it and renders a chip per limited provider in the header, flagging any
under 20% remaining. New pure JS helpers formatBudgetHeadroom/
renderBudgetHeadroom are unit-tested; the endpoint is covered by Go handler
tests (empty/reports/500). UI render not browser-verified in this environment.

Completes Phase 6: spend accounting + dispatcher gating + observability surface.

https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
</content>
</entry>
<entry>
<title>feat(api,web): event-stream timeline (Phase 3)</title>
<updated>2026-05-25T05:05:27+00:00</updated>
<author>
<name>Claude</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-05-25T05:05:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=b44c8277465c3b4e03fe4de4dd93850413023b69'/>
<id>urn:sha1:b44c8277465c3b4e03fe4de4dd93850413023b69</id>
<content type='text'>
Adds GET /api/tasks/{id}/events (seq-ordered, ?since_seq for incremental
polling) as the timeline data source, and a per-task Timeline section in the
web UI that fetches and renders the observability event stream. New pure,
unit-tested JS helpers: formatEventText, renderEventTimeline, fetchTaskEvents.

The timeline load is async and guarded on a global fetch so the synchronous
renderTaskPanel path (and its DOM-mock unit tests) is unaffected. Verified via
Go endpoint tests and node --test (272 JS tests pass). Note: the live in-browser
panel render was not exercised in this environment — only unit-level coverage.

https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
</content>
</entry>
<entry>
<title>feat: Ship button on SHIPPABLE stories; checker report on READY task cards</title>
<updated>2026-04-04T09:39:03+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-04-04T09:39:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=40513ffddba01467193c3c3e19468c7090f06215'/>
<id>urn:sha1:40513ffddba01467193c3c3e19468c7090f06215</id>
<content type='text'>
Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: fold completed tab into ready panel; stories tab first</title>
<updated>2026-04-03T23:18:45+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-04-03T23:18:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=774a33431f7ae8a54082f5bca5db0019d6459a60'/>
<id>urn:sha1:774a33431f7ae8a54082f5bca5db0019d6459a60</id>
<content type='text'>
- Remove the standalone "All" tab; completed tasks (last 24h) now appear
  at the bottom of the Ready tab under a "Completed (24h)" section header
- Move Stories tab to the first position in the nav bar
- Drop 'all' from badge count computation

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: add rotating background wallpaper</title>
<updated>2026-03-29T06:10:13+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-29T06:10:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=3c5206a927fa7c71c6d77dbac4eb4f274b7a5a77'/>
<id>urn:sha1:3c5206a927fa7c71c6d77dbac4eb4f274b7a5a77</id>
<content type='text'>
Uses time-bucketed picsum seed (5-min intervals) so all sites
show the same image simultaneously. Sets --bg-url CSS custom
property on body, consumed by .bg-body background-image rule.
</content>
</entry>
<entry>
<title>feat: show tasks and subtasks in story detail view</title>
<updated>2026-03-26T09:01:35+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-26T09:01:35+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=dac676e8284725c8ec6de08282fe08a9b519ccc8'/>
<id>urn:sha1:dac676e8284725c8ec6de08282fe08a9b519ccc8</id>
<content type='text'>
Story detail modal now fetches /api/stories/{id}/tasks and renders
top-level tasks as a numbered list with subtasks nested beneath, using
the same state emoji as the blocked/task views.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix: expose drained state in agent status API; fix AgentEvent JSON casing</title>
<updated>2026-03-26T05:10:56+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-03-26T05:10:56+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=b009880307298abea11efad92da2cd955afafe99'/>
<id>urn:sha1:b009880307298abea11efad92da2cd955afafe99</id>
<content type='text'>
AgentStatusInfo was missing drained field so UI couldn't show drain lock.
AgentEvent had no JSON tags so ev.agent/event/timestamp were undefined in
the stats timeline. UI now shows "Drain locked" card state with undrain CTA.

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