Skip to content

Releases: cskwork/oh-my-symphony

v0.13.0

Choose a tag to compare

@cskwork cskwork released this 10 Jul 12:59

v0.13.0 — reliability audit batch + live-E2E lifecycle fixes

The 2026-07-09 agent-flow reliability audit (AF-01..AF-16) is fully resolved,
plus two lifecycle defects found by a live opencode file-board E2E loop.

Reliability audit (AF-01..AF-16)

  • AF-01 Identity-safe worker exit: a force-ejected zombie's cleanup can no
    longer eject the fresh retry entry installed under the same issue id.
  • AF-02 Force-eject now records and kills the backend process group for
    every backend kind (claude/opencode/gemini/agy/kiro/pi), not just Codex.
  • AF-03 Resumed workers get a fresh stall window; long pauses no longer
    burn a retry on the first reconcile tick.
  • AF-04 State PATCH on a running ticket returns 409 without mutation.
  • AF-05 Plain/Gemini/Claude backends expose canonical completion previews;
    silent exit-0 empty turns fail instead of looping.
  • AF-06 Board scans ignore legacy .tmp-*.md files; startup sweeps only
    Symphony-owned temps and spares operator files.
  • AF-07 Reconcile isolates per-entry force-eject errors; cancelled paused
    zombies still eject.
  • AF-08 stop() bounds cancellation-resistant worker drain and finalizes
    their leases before the run registry closes.
  • AF-09 Corrupt Codex stdout closes the backend, fails later turns fast,
    and a failed reap stays retryable by a later stop.
  • AF-10 Dead-owner lease reclaim kills any recorded live process group
    (with a persisted reclaiming fence) before the row is redispatchable;
    non-positive persisted pids are rejected at the signalling boundary.
  • AF-11 Continuous-improvement lifetime cap warns once; require_idle_board
    blocks CI/worker overlap including terminal-persist work.
  • AF-12 Tracker parse failures warn; duplicate ids collapse
    deterministically; delete serializes with mutation; a running id missing
    from refresh becomes a visible degraded state.
  • AF-13 Rewind budget applies to custom and non-English pipelines via
    configured active-state order.
  • AF-14 Closed by research: Codex 0.130/0.144 schemas both require
    tokenUsage.last and .total; no speculative production branch.
  • AF-15 Dispatch state no longer retains completed ids; stop() clears
    diagnostics.
  • AF-16 First/continuation/phase-rebuild prompts share one lifetime
    turn-budget basis (max_total_turns documented in workflow examples).

Live-E2E lifecycle fixes

  • Done-squash preserves merged lineage: auto_commit_on_done now squashes
    onto merge-base(HEAD, merge target) instead of the fork point, so a branch
    already merged by Verify is no longer rewritten onto an orphan lineage — the
    post-Done fallback merge no longer hits guaranteed add/add conflicts that
    demoted healthy Done tickets to Blocked.
  • Verify evidence validation matches the shipped contract: evidence cells
    citing an existing artifact plus a qualifier (or several backticked
    artifacts) are accepted; Security Audit rows with an n/a result need no
    artifact. Fabricated citations and prose-only evidence still hard-rewind.
  • Verify stage prompts now show valid/invalid evidence-cell examples.

Hardening

  • OpenCode telemetry and worktree setup hardening.

Verification

Full suite 1371 passed / 5 skipped; ruff and pyright clean. The complete
pipeline (Todo → In Progress → Verify → Learn → Done with merge gate) was
exercised end-to-end three times with a real opencode agent building a working
app; the final two runs completed with the Done ticket surviving the terminal
grace and the fallback merge succeeding. Decision log:
docs/changelog/changelog-2026-07-10.md.

v0.12.0 - Continuous improvement and blocked recovery

Choose a tag to compare

@cskwork cskwork released this 05 Jul 23:16

Continuous improvement heartbeat and blocked-board recovery minor release.

Highlights:

  • Added the continuous improvement heartbeat contract/runtime so Symphony can periodically re-check the integrated baseline and file follow-up work as normal Kanban tickets.
  • Added blocked-ticket Root Cause Analysis (RCA) recovery. RCA means Symphony opens a separate ticket to investigate and fix why a source ticket became blocked; the source ticket stays Blocked while that RCA ticket resolves the blocker, then reopens to Todo only after successful RCA completion without manual-intervention markers.
  • Made Human Review intervention-only in prompts and contracts; normal successful Learn/Done paths no longer route through Human Review by default.
  • Hardened file-board recovery for legacy Human Review cards, delimiterless ticket files, stale Blocked RCA notes, idle paused RCA resume, and retryable backend/network failures.
  • Added dispatch preflight coverage for total turn-budget misconfiguration and AGY state-directory writability; AGY now defaults to fresh turns unless continuation is explicitly enabled.
  • Fixed the reconcile test harness so the pre-push full pytest gate no longer hangs on terminal-cleanup grace behavior.

Verification:

  • Real OpenCode E2E passed after the RCA recovery changes.
  • Feature branch pre-push hook: 1277 passed, 2 skipped.
  • dev merge push hook: 1279 passed, 2 skipped.
  • main merge push hook: 1279 passed, 2 skipped.
  • v0.12.0 release commit push hook: 1279 passed, 2 skipped.
  • Known residual warning: aiohttp NotAppKeyWarning in two startup tests.

v0.11.0 - OpenCode terminal cleanup

Choose a tag to compare

@cskwork cskwork released this 05 Jul 08:27

OpenCode terminal cleanup minor release.

Highlights:

  • Fixed OpenCode terminal reconciliation so terminal cards stop after a bounded grace period even when OpenCode backend heartbeats continue.
  • Included the checked-in SMA-20 smoke harness lint cleanup from dev.
  • Fixed the local pre-push quality gate to strip Git hook environment before tests create nested temporary repositories.

Verification:

  • OpenCode E2E reached Human Review and /api/v1/state reported running=0, retrying=0 after terminal reconciliation.
  • ruff check .
  • pyright --pythonpath /Users/danny/Documents/PARA/Resource/symphony-multi-agent/.venv/bin/python
  • pytest -q: 1153 passed, 2 skipped.
  • Real pre-push hook passed on both main and v0.11.0 tag pushes.

v0.10.1 - Prompt compaction default-on

Choose a tag to compare

@cskwork cskwork released this 04 Jul 15:58

v0.10.1 - Prompt compaction default-on

This patch release turns Symphony's prompt context compaction on by default.

Changed

  • agent.compact_issue_context now defaults to true when a workflow omits the setting.
  • The workflow builder fallback now matches the typed config default, so file, Jira, and other workflow configs get the same default behavior.
  • Existing workflows can still opt out with:
agent:
  compact_issue_context: false

Why it matters

Prompt compaction keeps the worker's first-turn prompt focused on the original scope plus the latest state-relevant ticket sections. That reduces repeated stale ticket history without removing the raw ticket: file-backed workers still receive the full ticket path for audit.

This is especially useful for long-running Codex/Symphony cards where old implementation notes, old QA failures, and large logs can otherwise dominate later prompts.

Jira workflow compatibility

Jira-backed workflows use the same agent.compact_issue_context config path. A local jira-symphony workflow was checked and explicitly set to true. Running services started on older Symphony versions still need to be restarted or upgraded before relying on the new package default.

Verification

  • rtk pytest tests/test_workflow.py -k "compact_issue_context" -q -> 3 passed.
  • rtk pytest tests/test_prompt_context.py tests/test_prompt.py::test_compact_issue_context_changes_rendered_prompt_description -q -> 8 passed.
  • python -m py_compile src/symphony/workflow/config.py src/symphony/workflow/builder.py passed.
  • git diff --check passed.
  • Full suite passed on dev pre-push: 1110 passed, 2 skipped.
  • Full suite passed on main locally and pre-push: 1110 passed, 2 skipped.
  • Fresh remote-clone Codex E2E used a workflow that intentionally omitted agent.compact_issue_context; loaded config reported compact_issue_context=True.
  • Clean E2E release gate CODEX-E2E-005 reached Human Review, exited with worker_exit reason=normal, API reported running=0 and retrying=0, and no contract failure/warning headings appeared.
  • E2E proof artifact contained compact_issue_context default: true.

Notes

Earlier temporary E2E tickets proved Codex could finish but exposed harness prompt contract issues. They were not used as the release gate. The final release gate is CODEX-E2E-005.

v0.10.0 - Codex E2E reliability hardening

Choose a tag to compare

@cskwork cskwork released this 04 Jul 15:20

v0.10.0 - Codex E2E reliability hardening

Minor release from v0.9.3 to v0.10.0.

This release focuses on making long-running Symphony boards easier to trust:
workers get better prompt context, operators get clearer cost and dependency
signals, workspace reuse is guarded before hooks run, and the 9999 web app no
longer fails on YAML timestamp frontmatter in issue details.

Highlights

  • Stage-local turn watchdogs: workflows can set
    agent.max_state_turns_by_state so reasoning-heavy In Progress work and
    stricter Verify / Learn gates can use different same-state turn limits.
  • Token attention without surprise stops: productive zero-token reports and
    configured agent.token_attention_threshold_by_state values now surface as
    operator attention, while high token use remains telemetry unless an explicit
    hard cap is configured.
  • Stage-aware prompt context compaction: agent.compact_issue_context: true
    preserves user scope, the newest evidence/failure context, and a full-ticket
    path while dropping repeated history from worker prompts. Measured copied-board
    Verify prompt size: TASK-005 went from 5,453 to 3,944 o200k_base tokens
    (27.7% smaller).
  • Workspace ownership protection: Symphony records workspace owner sidecars
    under the workspace root and blocks foreign TASK-* reuse before
    after_create hooks can mutate the wrong project.
  • Hook failure evidence: after_create stdout/stderr and a JSON manifest are
    persisted outside the ticket worktree, so failed setup remains inspectable
    even when the worktree is cleaned up.
  • Stricter contract rewind scope: Verify evidence failures now carry structured
    rows, table row numbers, and expected artifact path shapes into the rewind
    prompt instead of a vague failure note.
  • Dependency-aware file-board dispatch: unresolved dependency IDs now remain
    visible as blocked_dependency beyond Todo, so held work does not silently
    run.
  • 9999 admin UI documentation: README surfaces now lead with the browser admin
    UI and a sanitized screenshot, while still keeping the terminal TUI visible.

Fixes

  • Fixed GET /api/v1/issues/<ID> for issue files whose YAML frontmatter parses
    unquoted timestamps into Python date or datetime objects. This fixes the
    Could not load CODEX-E2E-001: Object of type datetime is not JSON serializable drawer failure.
  • OpenCode 1.17 token accounting now follows step_finish.part.tokens, handles
    nested cache and reasoning fields, and avoids double-counting explicit cache
    totals.
  • File ticket parsing auto-heals shallow accidental indentation on canonical
    metadata keys such as updated_at, preventing post-turn refresh failures from
    malformed agent-authored YAML.
  • symphony doctor now warns on masked setup commands such as || true and
    piped tail by default; workflows can opt into fatal warnings with
    hooks.fail_on_warning_patterns: true.

Compatibility Notes

  • Prompt compaction is opt-in and remains off unless a workflow sets
    agent.compact_issue_context: true.
  • Token attention thresholds do not block or move tickets by themselves.
  • symphony doctor warning-pattern checks are warnings by default.
  • Verify contract checks are stricter about placeholder or prose-only evidence;
    use durable evidence files such as docs/<ID>/qa/... instead of n/a, -,
    or "validated in source" table cells.

Verification

  • Focused release-prep checks on dev:
    rtk pytest tests/test_cli_main_routing.py::test_version_flag_prints_version_and_exits_zero tests/test_webapi.py::test_issue_detail_serializes_unquoted_frontmatter_timestamps -q
    -> 2 passed.
  • dev pre-push CI-parity gate:
    1,109 passed, 2 skipped, 2 warnings.
  • main full local gate after fast-forward:
    rtk pytest -q -> 1,109 passed, 2 skipped.
  • main pre-push CI-parity gate:
    1,109 passed, 2 skipped, 2 warnings.
  • Prior fresh remote-clone Codex E2E rerun reached Human Review on
    CODEX-E2E-002 with worker_exit reason=normal; the issue-detail API
    returned string timestamps.

Commit Scope

  • db55768e6bc2d3d8283ec238a08d566c6e55da5b -
    docs(readme): showcase 9999 admin ui
  • 6fe480b6abc9c2844d35d9974b7cb52466bee10b -
    feat: harden symphony token reliability
  • 8710ec736840a08b07e24013681af9f770639a0a -
    fix: serialize issue detail frontmatter timestamps
  • 1c48d9bb73d82464907e0bfdad69884895fc46b1 -
    chore: prepare v0.10.0 release

Tag target: 1c48d9bb73d82464907e0bfdad69884895fc46b1.

v0.9.3 — OpenCode telemetry, file-board recovery, and operator UI fixes

Choose a tag to compare

@cskwork cskwork released this 04 Jul 02:35

2026-07-04 - Fix G2 empty-response-loop false-positive on OpenCode

Goal

Stop the G2 empty-response-loop guard from falsely blocking healthy OpenCode
tickets. A ticket (observed in Learn) was moved to Blocked with
empty_response_loop budget exceeded (consecutive_empty_turns=3, threshold=3)
despite the agent producing real output every turn.

Root cause

G2 counts a turn as empty when RunningEntry.current_turn_message is blank at
EVENT_TURN_COMPLETED (orchestrator/core.py). current_turn_message is only
populated when _preview_from_payload(payload) returns text, and that helper
reads the preview keys message / lastMessage / text / summary / item.

OpenCode's EVENT_TURN_COMPLETED payload delivered its response text only under
result / response (backends/opencode.py) — keys the preview helper never
inspects. So every OpenCode turn looked empty, the counter climbed monotonically
regardless of real work, and G2 escalated after exactly 3 turns.

Why it surfaced now: the recent OpenCode liveness-heartbeat fix (stall-loop)
stopped long turns from being stall-cancelled. Before it, each stall-cancel
minted a fresh RunningEntry (counter reset to 0), so turns never accumulated to
3 on one entry. Removing the false stall-kill exposed the latent G2 miscount —
same bug class (OpenCode's batch-per-turn shape not fitting an event model built
for streaming backends), next guard.

Decisions

1. Emit the response under a preview key from the backend

run_turn's EVENT_TURN_COMPLETED payload now carries message (= the response)
alongside the existing result / response. _preview_from_payload reads
message first, so a productive turn populates current_turn_message and resets
the G2 counter. A genuinely empty turn (response == "") still yields no preview
text, so real empty-loops are still caught. Bonus: the OpenCode TUI preview
(last_codex_message, same code path) was always blank before and now shows the
turn's response.

  • Rejected: raising EMPTY_TURN_LOOP_THRESHOLD (the operator's first
    hypothesis). It is a band-aid — OpenCode would still false-block after N turns
    instead of 3, and a higher threshold weakens genuine empty-loop detection for
    every backend. It does not address the miscount.
  • Rejected: teaching _preview_from_payload to read result / response.
    That is shared code on the hot event path for all backends; result /
    response can carry non-message content for other drivers, risking masked
    empty-turns elsewhere. The backend-local fix keeps the blast radius to OpenCode
    and matches the sibling heartbeat fix's "backend quirks live in the backend"
    precedent.

Verification

  • backends/opencode.py — 1 key added to the turn-completed payload.
  • New tests/test_backends.py::test_opencode_turn_completed_payload_carries_message_for_preview
    asserts the emitted payload carries message.
  • New tests/test_orchestrator_dispatch.py::test_g2_opencode_shaped_payload_resets_only_with_message_key
    drives the real _on_codex_event path: result/response-only payloads still
    count as empty (climb 1 -> 2); adding message resets the counter to 0.
  • Full suite: 1058 passed, 2 skipped. No shared code touched;
    EMPTY_TURN_LOOP_THRESHOLD unchanged at 3.

Patch bump 0.9.1 -> 0.9.2 (fix restores intended behavior).

Follow-up (0.9.3) — the dominant cause: opencode 1.17 schema drift

Live verification against the paused jira-symphony board (TASK-001, blocked
in Learn by exactly this loop) showed 0.9.2 alone was necessary but not
sufficient. Every agent_turn_completed reported input_tokens=0 output_tokens=0 with an empty last_message — yet opencode had done real work
(glm-5.2, 8 agentic steps, 27-file commits). Input tokens cannot be zero for a
12 KB prompt: Symphony's opencode backend was parsing nothing out of
opencode 1.17.13's output. So response itself was empty, and 0.9.2's
message: response carried an empty string — the preview stayed blank and G2
still counted every turn empty.

Root cause: opencode run --format json (src/cli/cmd/run.ts emit) streams
JSONL frames {"type": ..., "sessionID": ..., "part": {...}}; assistant prose
is in type=="text" frames under part.text. Symphony's _extract_text only
scanned flat keys (response/result/message/text/content/output) plus
data, so it never saw part.text and returned "". (Confirmed by unit probe:
_extract_text({"type":"text","part":{"text":"..."}}) == "".)

Fix: OpenCodeBackend._text_from_event reads part.text from type=="text"
frames, keeping the flat-key scan as a fallback for the raw-stdout and
non-opencode shapes. tool_use/step_start frames carry no prose, so a genuinely
empty turn (no text frame) still counts as empty — G2's real detection is
preserved. New tests/test_backends.py::test_opencode_extracts_text_from_jsonl_part_frames
pins the JSONL shape.

  • Rejected: a deep/generic text search across every nested dict — risks
    grabbing tool-call arguments and file contents as "response". The
    type=="text" predicate is precise to opencode's serialization.
  • Known follow-up (not G2-blocking, fixed in the v0.9.3 release update below): token usage still
    reads 0 for opencode 1.17. This only affects max_total_tokens budgeting and
    telemetry for opencode, not dispatch correctness. Tracked in
    skills/symphony-skill/reference/troubleshooting.md.

Operator playbook added: "Backend CLI update broke response parsing" in
skills/symphony-skill/reference/troubleshooting.md — the input_tokens=0
smoking gun, the capture-the-real-schema recipe, and the fix pattern, so the
next CLI-upgrade drift is a 2-minute triage instead of a rediscovery.

Patch bump 0.9.2 -> 0.9.3 (restores opencode response parsing for opencode >= 1.x).

Follow-up (v0.9.3 release update) — OpenCode 1.17 token accounting

Live probe:

opencode run --format json --auto "reply with DONE only"

OpenCode 1.17.13 emitted usage on a step_finish frame:
part.type == "step-finish" with part.tokens containing input, output,
reasoning, cache.read, cache.write, and total. Symphony's _usage_dicts
never descended through part, so the backend emitted useful message text but
left every token bucket at 0. That matches the TASK-002 monitor evidence:
nonblank last_message, input_tokens=0, then a separate
worker_exit reason=issue_state_refresh_failed after the turn.

Fix: OpenCodeBackend now descends into part and info usage containers,
reads totalTokens as an alias, folds nested cache.read / cache.write into
input-side tokens, and treats reasoning as output-side tokens when totals need
to be derived. New
tests/test_backends.py::test_opencode_extracts_usage_from_jsonl_step_finish_part_tokens
pins the real OpenCode 1.17 step_finish.part.tokens schema.

  • Rejected: deep traversal of every nested dict. OpenCode frames also carry
    tool and text payloads; scanning all children would risk treating user-facing
    content or tool arguments as telemetry. The parser only follows known telemetry
    containers.
  • Not part of this fix: issue_state_refresh_failed. The failure fires after a
    successful turn when tracker state refresh returns None; it is a separate
    board/workspace reliability issue, not a token parser symptom.

Included in the v0.9.3 release tag update (restores OpenCode token telemetry for opencode >= 1.x).

Follow-up (v0.9.3 release update) — issue-state refresh RCA and operator UI

Live jira-symphony showed TASK-002 stuck in paused retry with
worker_exit reason=issue_state_refresh_failed after a successful nonblank
OpenCode turn. This was separate from the token parser issue. The ticket file
had malformed YAML:

created_at: '2026-07-04T00:00:02Z'
  updated_at: '2026-07-04T02:35:57Z'

That made the file tracker skip TASK-002, so the worker could not refresh the
post-turn state and paused for operator inspection. Current-board repair was to
unindent updated_at, after which symphony board ls --workflow ... showed
TASK-002 back in Learn, and POST /api/v1/TASK-002/resume moved it from
retrying to a running Learn retry.

Hardening: parse_ticket_file now auto-heals the common case where an agent
accidentally indents a canonical top-level key by one or two spaces. It does not
rewrite the file during read, but the next normal tracker write serializes
canonical YAML. New
tests/test_tracker_file.py::test_parse_ticket_file_auto_heals_misindented_updated_at
pins the observed TASK-002 shape.

Operator UI: Settings now shows the workflow default agent on both web surfaces.
The 9999 Symphony app renders Default agent from /api/v1/workflow.agent.kind
under Settings > Board info; the board-viewer Settings modal renders
Agent default from /api/symphony/state.workflow.default_agent_kind. The value
on the live board is opencode.

  • Rejected: only patch the current ticket. That restores one board but lets
    the next agent-authored YAML indentation mistake remove a ticket from refresh.
  • Rejected: deep YAML text surgery on every read. The heal only runs after a
    YAML parse failure and only unindents known ticket frontmatter keys with shallow
    accidental indentation, avoiding legitimate nested data such as agent.kind
    and blocked_by[].state.

Follow-up (operator) — TASK-003 workspace collision RCA

After TASK-002 resumed and completed, live jira-symphony moved to TASK-003
and paused before the first agent turn:

hook before_run exited 42;
workspace kanban points to /Users/danny/Documents/PARA/Resource/learn-codex-kr/kanban,
expected /Users/danny/Documents/PARA/Resource/jira-symphony/kanban

The path /Users/danny/symphony_workspaces/TASK-003 was not a jira-symphony
worktree. It was a clean, older learn-codex-kr worktree registered under
learn-codex-kr/.git/worktrees/TASK-003, with kanban linked to that project's
board. Sympho...

Read more

v0.9.2 — OpenCode G2 empty-loop: response via 'message' preview key

Choose a tag to compare

@cskwork cskwork released this 04 Jul 02:35

Fix — OpenCode G2 empty-response-loop (part 1 of 2)

Healthy OpenCode tickets were moved to Blocked with
empty_response_loop budget exceeded (consecutive_empty_turns=3, threshold=3)
despite producing real output every turn.

  • OpenCode delivered its turn response only under the result / response keys of
    the EVENT_TURN_COMPLETED payload — keys _preview_from_payload never reads — so
    current_turn_message stayed blank and the G2 guard counted every turn empty.
  • Fix: the turn-completed payload now also carries message, so a productive turn
    populates the preview and resets the empty-turn counter. A genuinely empty turn
    still counts, so real empty-loop detection is preserved. EMPTY_TURN_LOOP_THRESHOLD
    unchanged at 3. Backend-local; no shared-code change.

Necessary but not sufficient on its own for OpenCode >= 1.x — the response text
itself wasn't being parsed. See v0.9.3.

Full test suite green (1058 passed).

v0.9.1

Choose a tag to compare

@cskwork cskwork released this 03 Jul 11:59

Highlights

  • Added and hardened multi-agent release gates for OpenCode, Pi, Claude, and Codex.
  • Added AGY / Antigravity and Kiro backends for the Gemini CLI deprecation path.
  • Added local Git quality gates: pre-commit checks staged whitespace and Python syntax; pre-push runs whitespace checks plus a CI-parity full pytest run in an isolated dev venv.
  • Renamed the operator skill using-symphony -> symphony-skill; branch-specific assets live under skills/symphony-skill/ so operator skill discovery has one canonical entry point.
  • "Open the orchestrator" now defaults to opening the service --port web app (http://127.0.0.1:9999/); the --viewer-port board (8765) is the secondary card board.
  • Fixed CI-only release blockers: optional Playwright import handling, PID-stable service status checks, branch-reference docs, and skill reference link coverage.

AGY / Kiro Compatibility

  • agent.kind: agy and agent.kind: antigravity dispatch through agy --print - with unattended permission and continuation support.
  • agent.kind: kiro dispatches through kiro-cli chat --no-interactive --trust-all-tools "$(cat)", with continuation support.
  • symphony doctor accepts Kiro auth from either KIRO_API_KEY or a successful kiro-cli whoami login check.

Verification

  • Release tag v0.9.1 re-cut to commit 4b2079a3ff67e11176318f1464da751c48eb3abe (folds in the symphony-skill rename and the open-orchestrator default).
  • GitHub main Tests: run 28689395807 passed on 4b2079a3.
  • GitHub dev Tests: run 28689338968 passed on 4b2079a3.
  • GitHub main Pages: run 28689395810 passed on 4b2079a3.
  • Pre-push gate: 1056 passed, 2 skipped in an isolated dev venv.
  • Prior cut (0438da1c) live dispatch proofs (AGY, Claude, Codex, Kiro, OpenCode, Pi through Done; /api/v1/state status=ok; board viewer HTML; TUI shutdown_complete) remain valid in history.

Gemini was not included in the live dispatch proof because symphony doctor failed Gemini auth: /Users/danny/.gemini/settings.json lacks root selectedAuthType, and GEMINI_API_KEY is unset.

v0.8.0 - current runtime bundle

Choose a tag to compare

@cskwork cskwork released this 03 Jul 00:26

This release tag was updated on 2026-07-03 to point at the current main
runtime bundle.

Highlights

  • Built-in web Kanban app served at / from the Symphony orchestrator port.
  • Browser-based workflow editing for board columns, stage prompts, and branch
    policy.
  • Ticket create/edit/delete from the web app and TUI, with drag-and-drop state
    moves and live run badges.
  • Default workflow simplified to Todo -> In Progress -> Verify -> Learn,
    followed by Human Review and Done.
  • OpenCode is now a first-class backend alongside Codex, Claude Code, Gemini,
    and Pi.
  • Local reliability hardening: SQLite run leases, persisted retry/pause/budget
    issue flags, file-tracker write locks, and /api/v1/health.
  • Public docs, Korean README, landing page, package metadata, and architecture
    notes now match the current runtime.
  • GitHub README navigation now has a compact table of contents, mirrored in the
    Korean README.
  • GitHub Pages deployment now has an explicit checked-in static workflow for
    docs/, with the repository switched to workflow build mode.

Web board and workflow editing

symphony --port 9999 and symphony service start serve a full browser app at
the orchestrator root. Operators can inspect work, register issues, edit issue
metadata, move cards, and monitor active runs without a separate frontend build
step, CDN dependency, or account flow.

The Workflow page lets operators add, delete, rename, and reorder Kanban
columns, edit each stage prompt, and adjust branch policy from the browser.
Writes round-trip through WORKFLOW.md using comment-preserving YAML handling.
When columns are renamed or removed, affected tickets migrate automatically; if
a column has an active worker, the edit is rejected with a conflict response.

Ticket operations

Tickets can be created from the web app or with the TUI n shortcut, then
edited or deleted through the browser API. The web board supports drag-and-drop
state transitions plus per-column create buttons. Running tickets show live
badges for turn count, token usage, and pause/resume state.

Skills, stats, and API

Local skills/<name>/SKILL.md files can be attached to individual tickets from
the web modal, the TUI form, or skills: frontmatter. On the first agent turn,
Symphony appends the selected skill bodies to the dispatch prompt.

The .symphony/stats.jsonl event store records turns, transitions, and run
outcomes. The web Stats page and the TUI s screen aggregate tokens per day,
completed work per day, per-column dwell time, per-agent totals, and average
cycle time.

REST endpoints now cover issue CRUD, board reads, workflow state editing,
prompt editing, branch policy updates, skill discovery, stats, git branch
discovery, Learn skip, refresh, and runtime health. Mutating endpoints require
JSON content and loopback Host validation.

README and Pages deployment

The GitHub README now includes a compact top-level table of contents for the
major operator sections. The Korean README mirrors the same navigation so the
two entry docs remain structurally aligned.

Pages deployment is now owned by .github/workflows/pages.yml. The workflow
publishes docs/ with explicit permissions, concurrency, and current Pages
actions. The repository Pages setting is configured for workflow build mode.

Runtime and reliability changes

  • OpenCode backend support uses opencode run --format json --auto, with
    session continuation when OpenCode reports a session id.
  • SQLite run leases block duplicate dispatch after restart and reclaim
    dead-owner leases.
  • Retry, pause, and budget-exhausted issue flags survive process exit.
  • File tracker writes use locked compare-and-swap mutation paths.
  • The operator-facing docs now describe the single-node/local recovery boundary
    precisely: persisted leases and flags do not reattach to a worker lost during
    a hard crash.

Dependency change

ruamel.yaml is required so Symphony can edit WORKFLOW.md while preserving
comments and formatting better than a plain YAML rewrite.

Release commit: 7be48e2

v0.7.2 — agent-terse workflow prompts + token-budget directive

Choose a tag to compare

@cskwork cskwork released this 09 Jun 19:16

Prompt-cost release. All 18 stage templates under docs/symphony-prompts/{file,linear}/ (base + 8 stages per tracker) were rewritten as terse agent-directives — the dispatch prompt is read by the worker LLM, not a human, so rationale prose was cut while every behavioral rule stayed.

Highlights

  • ~12% smaller dispatch prompts: 282,009 → 247,942 chars (~70.5k → ~62.0k tokens) summed across the 28 tracker × language × stage combinations; Review stages −15%. Every section anchor, state-transition rule, command, table spec, env var, and liquid branch is preserved. Human-facing artefact templates (Plain-language header, caps table, wiki entry template, As-Is→To-Be report, Human Review handoff) are byte-identical.
  • Soft token-budget directive (base.md, both trackers): when agent.max_total_tokens_by_state sets a budget, prompts now render Token budget: keep this turn under N completion tokens (stage EMA: M) from the previously unused C3 token_ema / token_budget template vars. Off by default; regression tests pin both states.
  • Chore short-circuits ported to linear boards: Explore/Plan/Review/Learn chore-label fast paths now exist in the linear prompt set too, so metadata-only tickets skip the full stage contracts regardless of tracker.
  • Tracker drift removed:
    • linear Learn no longer re-does the bulk dup/orphan/stale wiki sweep by hand — symphony wiki-sweep already runs it every wiki.sweep_every_n Done transitions for every tracker kind. Per-ticket integrity checks (invalidated-entry update, beginner-block shape, Wiki Conflict flag) stay in the prompt.
    • linear's wiki entry template gains the Observability hooks block, so file- and linear-authored docs/llm-wiki/ entries share one schema.

Verification

  • pytest -q: 810 passed; the single failure (tests/test_service.py::test_start_cleans_live_viewer_from_stale_record_before_doctor) pre-exists this release (fails identically at c04d2ad) and is unrelated to prompts.
  • Prompt contract suite (tests/test_workflow_pipeline_prompt.py): 51 passed, including 4 new tests anchoring the token-budget directive (proven red against the pre-change templates, green now).
  • Independent critic audit compared every old/new template atom-by-atom: zero CRITICAL findings; the one MEDIUM finding (linear beginner-block shape check dropped collaterally) was restored before release.

Known follow-ups

The file tracker still has gates the linear set lacks: the Security Audit 7-row table, [no-test] marker scan, ## Acceptance Tests / ## Done Signals + AC Scorecard, and $SYMPHONY_REWIND_SCOPE rewind scoping. Porting them is a behavioral decision deferred to a future release. The OneShot skill's lane prompts (skills/symphony-oneshot/templates/WORKFLOW.oneshot.md) were intentionally left untouched.