synlynk Changelog
Stay up to date with new features, improvements, and fixes to the multi-agent coordination kernel.
All notable changes to synlynk are documented here.
Format follows Keep a Changelog. Versioning follows Semantic Versioning.
Unreleased
Added
- Charter Content & Structure Schema
- Charters now require YAML frontmatter (
schema_version,role,description,durability,tools,credentials) plus three markdown sections (## Instructions,## Authority & Escalation,## Workflow Ownership), enforced via a newsynlynk/charter_schema.pyvalidator wired intopropose_charter_revision. - Retired the dead
.synlynk/agents/<id>.yamlprojection file andregenerate_agent_projection()— its only field (capability_grants) was write-only, never read. - Added
synlynk agent sync-routing <id_or_alias>to regenerate a charter'sdispatch_routingfrontmatter block from.synlynk/policy.json's task-allocation table. - Migrated all 7 provisioned charters (dev, qa, architect, pm, tpm, designer, marketing) to schema revision 3;
pm's migration restores the competitive-intelligence-sweep / capability-gap-doc content that had been lost in an earlier revision.
- Charters now require YAML frontmatter (
Agent vs Harness Terminology — Phase 0 (design 2026-08-09, plan 2026-08-09)
docs/glossary-agent-vs-harness.md— canonical definition distinguishing Agent (persistent role identity + charter: pm/architect/tpm/dev/designer/qa/marketing/synlynk-bot) from Harness (swappable execution backend: Claude/Agy/Grok/Codex/local).- Auto-generated
## Capability-Based Task Allocationtable (synced into CLAUDE.md/GEMINI.md/AGENTS.md/GROK.md viasynlynk doctor --fix) now reads| Role | Harness | Tasks |instead of the conflated| Role | Agent | Tasks |, with a glossary-link note. - Hand-maintained "Terminology: Agent vs Harness" section added to this repo's own
CLAUDE.md. .synlynk/roles.yaml,README.md,SYNLYNK_GUIDE.mdwording fixed to stop conflating Agent and Harness.- Not yet a shippable milestone: first phase of a 5-phase roadmap (
docs/superpowers/specs/2026-08-09-synlynk-agent-roles-charters-design.md§10). Phase 1 (agent manifests/charter storage) has since shipped — see[0.14.0]below — but Phases 2-4 (memory, capability registry, portability) remain unbuilt. Held out of 0.13.1 and 0.14.0; will ship as its own named release once the full terminology rollout is complete.
Quota-Aware Dispatch Reservation (design 2026-08-08, plan 2026-08-08)
agent_reservationsledger tracks estimated-token reservations per harness from the moment a job is queued/dispatched until it settles, closing the gap where--force-agentand daemon-queued dispatches could bypass quota checks entirely.dispatch_agent()now consults quota unconditionally (including--force-agentcalls) and defers (queued,blocked_reason=quota_exhausted) instead of raising when a harness has no headroom; deferred jobs resume automatically once the harness's quota window resets — no manual re-dispatch needed._dispatch_ready_jobs()no longer falls through to an exhausted harness when a job is blocked; it stays queued for the next poll.synlynk schedule --executeopens real reservations for the whole batch at commit time via_enqueue_plan()._force_exhaust_quota()wires sentinel's existingQUOTA_EXHAUSTEDdetection into the reservation ledger without ever touching already-running jobs.synlynk/tpm_hooks.py— narrow TPM hook surface (tpm_observe_reservations,tpm_reorder_queue,tpm_reallocate) plus a read-onlysynlynk quota --tpm-viewCLI command to inspect open reservations across harnesses.- Not yet a shippable milestone: no active agents currently exercise the reservation ledger or TPM hooks in production dispatch flow. Held out of 0.13.1 and 0.14.0; will ship once agents actually consume it.
Release pitch: a backlog of already-shipped, undocumented work — QA merge-gate authority, the gh-write broker, harness capability registry v2, and a week of dispatch/gh-write reliability fixes — finally gets a version number, and today's own session shows why that matters: a live datetime-comparison crash (#1184) and a per-connection DB backup storm (#1087) both got root-caused and fixed in the same sitting this release closes out.
Added
QA delegated merge-gate authority + completion tracker + merge-restricted classes (design 2026-08-20/22, gh#1079/#1099/#1100/#1101, PRs #1082-#1104)
docs/superpowers/specs/2026-08-20-qa-merge-gate-authority-design.mdand its implementation plan give QA delegated authority to merge PRs that pass verification, instead of every merge requiring a human or PM-role action.- Completion tracker (PR #1100) adds a Vizor panel surfacing verified-but-unmerged PRs.
- Merge-restricted classes (PR #1101) carve out PR categories (e.g. release branches, policy.json changes) that stay outside QA's delegated authority regardless of verification status.
GitHub-write broker design (resolves #865 brainstorm, PR #1075)
- Design spec for a centralized gh-write broker consolidating GitHub App token resolution and write-permission checks behind one interface, replacing scattered per-call-site identity resolution.
Harness capability registry v2 — Plan B (gh#786, PRs #1053-#1066)
harness_models/harness_modes/capability_calibration_*tables replace the old flat capability ledger with per-model, per-mode calibration data.- Stage 0 explore bonus seeds calibration for thin-data models; single-model sweep entry point and diff-and-queue-new-models helper keep the registry current as harnesses add models.
gh-write identity hardening — Phase 1 closeout (gh#423/#426, PR #1110) and Agent-roles Phase 2 — memory-gated capability routing (PR #1030)
- Round out the identity-hardening and capability-routing work referenced but not yet changelogged from earlier in August.
Dispatch and gh-write reliability hardening (2026-08-24 to 2026-08-27, PRs #1140/#1164/#1166/#1172/#1174/#1175/#1177/#1180/#1182/#1183)
- Daemon-owned GitHub App token cache unblocks headless dispatch (#1140, PR #1174); worktree gh-write dispatch now falls back to the main repo's
github_appswhen the worktree has none (PR #1164). - PR-review task type is now inferred from task text (#1166, PRs #1172/#1175); a missing
reviewtask_allocationpolicy entry is added; grok's review-type gh-write authorization is correctly downgraded (PR #1177). - Codex sandbox network access is now gated per #340 (PR #1180).
- gh-write targets are resolved from task text for #860 (PR #1183); a
jobs.pybug in_maybe_open_worktree_pris fixed (PR #1182). - Harness capability baseline + recurring reassessment protocol documented (PR #1178).
PM competitive-intelligence sweep (PR #1159)
- Weekly cron job maintaining a living comparison doc against competitor tooling, feeding a decide-round pipeline for roadmap input.
Fixed
[LIVE issue] jobs --all crash on naive/aware datetime comparison (gh#1184, PR #1187)
_parse_iso8601()insynlynk/gh_verify.pynow normalizes a trailingZand coerces naive timestamps to UTC-aware before comparison, instead of crashing withTypeError: can't compare offset-naive and offset-aware datetimeswhenever a GitHub-sourced timestamp reachedgh_write_verified()._apply_gh_write_verification()insynlynk/jobs.pynormalizessincethrough the same parser before use.
[LIVE-6, gh#1140] branch-protection sync re-enabling enforce_admins, closing #1185 (PR #1186)
cmd_policy_sync_branch_protection()no longer hardcodesenforce_admins=True; a prior sync had silently re-locked the repo's own admin-merge bypass.
[LIVE issue] _migrate_db() backup storm on every connection (gh#1087, PR #1189)
_migrate_db()now returns immediately oncePRAGMA user_versionis current, instead of running the harness-rename migration and full schema executescript unconditionally on every connection. Root-caused as the likely source of intermittentdatabase is lockedfailures seen during full-suite test runs (e.g.test_cmd_agent_add_onboards_agent).
Process notes
- 8 stale
[APPROVAL]GitHub issues closed (gh#1142-#1149): artifacts of the[0.17.0]Task 5 live dogfood verification's temporarytask_dispatch_demopolicy rule, which was fully reverted before merge and never landed onmain. These tickets could never resolve through the normal auto-resume flow; closed asnot plannedwith provenance comments during this release's backlog sweep. - Version-drift note: the
VERSIONfile had drifted to0.16.0despitev0.17.0already being tagged and released — see #1188 for root cause and proposed durable fix (dispatch-time drift warning, defensive schema-version gate). This release's version bump corrects the immediate drift; #1188 remains open for the systemic fix.
Release pitch: an approved [APPROVAL] ticket now actually unblocks the story it was raised for — the last gap between v0.16.0's authority layer and a tpm sweep loop that runs unattended for real, closed and live-verified against this repo's own GitHub tracker.
Added
Ticket-driven approval auto-resume (design/plan 2026-08-24, PRs #1137-#1139, #1141)
- Closes the known gap flagged at the end of
[0.16.0]: resolving an[APPROVAL]ticket now actually unblocks the parked story on the nextsynlynk tpm sweeppass, instead of the story re-parking forever. approval_ticketstable (PR #1137) plus_find_ticket()/_insert_ticket()/_mark_ticket_consumed()helpers insynlynk/db.py(PR #1138) giverun_sweep_pass()(PR #1139) three-way state awareness per story/action: no ticket yet → file one; open ticket → keep parking; resolved ticket → consume it and let dispatch proceed.synlynk/events.py's_scan_approval_tickets()(PR #1141) now writesapproval_tickets.status='resolved'at the same point it emitsapproval_resolved, so the resolution is durable state the next sweep pass can actually query — not just an event log entry nothing consumed.- Live dogfood verification (Task 5, Claude-direct per plan, 2026-08-24): ran the full ticket lifecycle against this repo's real GitHub issue tracker using a temporary, fully-reverted
task_dispatch_demopolicy rule (reverted before merge; never landed onmain). Demo storystory-becf09a5: sweep 1 parked it and filed ticket id 8 → issue #1149; sweep 2 confirmed no duplicate ticket/issue;gh issue comment 1149 --body "approve"+scan_local_events()producedapproval_resolvedevent id 371 referencing issue #1149; sweep 3 dispatched instead of re-parking (jobjob-e8277299, exit 0) and marked the ticketconsumed(consumed_atset). Every claim was verified via direct DB query /gh issue list/synlynk events tail, not sweep's own printed summary. - Process note: Tasks 1-4's implementer stage was dispatched to Codex per the project's PM/review-only split as usual. Task 4 hit a session-level blocker — the Claude Code auto-mode classifier repeatedly denied
synlynk dispatchcalls even with valid role-scoped GitHub App credentials — so Task 4 was implemented directly by Claude as a documented, user-approved workaround. Filed as LIVE-6, #1140 (Sev2) since it degrades the autonomy-design goal; root cause not yet investigated.
Known gaps (carried forward)
- LIVE-6, #1140 — Claude Code auto-mode classifier blocks
synlynk dispatchcalls even with valid role-scoped GitHub App credentials, forcing a manual-implementation fallback. Root cause not yet investigated.
Release pitch: the authority layer v0.15.0 built now actually gates something unattended — synlynk tpm sweep walks ready stories through dispatch end-to-end, pauses on a policy-flagged action with a GitHub approval ticket instead of blocking the whole batch, and a live dogfood run proved both the happy path and the pause+ticket path work — surfacing two real gaps in the process, filed rather than papered over.
Added
GOVERNS awaiting_approval event (Task 10, PR #1125)
- New GOVERNS event type extending the
job_terminal/review_submittedevent-contract pattern (PR #922):emit_awaiting_approval(story_id, action, reason)insynlynk/events.py, recording whichpolicy.jsonapproval_required_forrule matched.
Approval-gate ticket flow (Task 11, PR #1126)
synlynk/approval_gate.py—raise_approval_ticket()files a[APPROVAL] <action> — <story_id>GitHub issue with story context, the matched policy rule, and instructions to replyapproveor act directly on GitHub.synlynk/events.py's_scan_approval_tickets()polls open[APPROVAL]issues and emitsapproval_resolvedfor any that are closed or have anapprove-prefixed comment, wired as the last step ofscan_local_events().
synlynk tpm sweep (Task 12, PR #1127)
- One pass over
readiness='ready'stories: dispatch → verify → PR → review → merge per story, gating every step oncheck_authority(). Arequires_approvalresult parks that story (raises a ticket, emitsawaiting_approval) without blocking the rest of the batch. Per-pass summary surfaced viasynlynk status.
Live dogfood verification (Task 13, Claude-direct per plan)
- Ran
synlynk tpm sweepunattended against this repo's real backlog. To avoid dispatching all 8 pre-existing ready stories for real, the 8 were temporarily parked (synlynk story draft) and restored afterward; only two purpose-built demo stories were swept. - Pass 1 (no approval rule active) proved the normal path:
story-028d26d9dispatched, ran to completion, PR opened. - Pass 2 (a temporary, documented, fully-reverted test-only
policy.jsonrule —task_dispatch:has no default rule that can triprequires_approval, since_matches_approval_rule()explicitly skipssecurity_sensitive_paths:for dispatch actions) proved the pause path:story-7aa0aaecparked, a real[APPROVAL]issue was filed and assigned,approvewas commented, and_scan_approval_tickets()correctly emittedapproval_resolved(event id 272) — independently confirmed viasynlynk events tail --type approval_resolvedandgh issue view --json state,comments. - Every claim was cross-checked directly (
synlynk jobs --all, direct DB queries,gh issue list --search,gh api .../branches/main/protection) rather than trusted from the sweep's own printed summary, per the plan's explicit instruction.
Fixed
/ Known gaps (filed, not patched in this release — Claude is PM/review only; fixes are implementation work for a future dispatch) - **`scan_local_events()` crashes before reaching `_scan_approval_tickets()`** (`sqlite3.OperationalError: table subscriptions has no column named harness_name`), and its only production call site (`workspace_agent.py`'s `cmd_workspace_agent_run`) has no wired CLI subcommand — meaning the documented approval-resolution detection path does not actually run unattended today. Filed as [#1132](https://github.com/nikhilsoman/synlynk/issues/1132). - **`synlynk story done` does not clear `readiness`**, and `_ready_stories()`'s in-flight guard only excludes `queued`/`running` jobs, not `done` ones — so a story whose dispatch already completed gets re-swept and re-parked on the very next pass, observed live with `story-028d26d9`. Filed as [#1133](https://github.com/nikhilsoman/synlynk/issues/1133). - **Resolving an approval ticket does not auto-unblock a re-sweep**: `check_authority()` is purely policy-rule-based with no awareness of ticket-resolution state, so `approval_resolved` firing does not itself let the parked story advance on the next pass. This matches the plan's own scoping (ticket-driven auto-resume was explicitly out of scope for this plan) — a known limitation, not a regression, and the natural next increment once #1132/#1133 are fixed.Release pitch: synlynk's own repo gets a real authority layer — a two-tier policy.json (workspace defaults + per-repo overrides) that turns previously-hardcoded prose tables (who can merge, who can cut a release, who can edit the roadmap, which harness handles which task type) into data, gated by a fail-closed check_authority() resolver, with branch protection now live-verified on main.
Added
Workspace Policy Layer (design 2026-08-23, plan docs/superpowers/plans/2026-08-23-workspace-policy-and-autonomous-loop.md, PR #1122)
synlynk/policy.py— two-tier policy schema: workspace defaults (~/.synlynk/workspaces/<name>/policy.json, falling back toDEFAULT_WORKSPACE_POLICYwhen absent) merged with a repo's sparse.synlynk/policy.jsonoverrides, whole-object-replace-per-top-level-key (not a deep merge).check_authority(action, role, repo_path)→AuthorityResult(allowed, requires_approval, reason), coveringroadmap_edit,goal_create,merge,release_cut, andtask_dispatch:<type>actions, plus anapproval_required_forrule matcher (named releases, roadmap-authority changes, security-sensitive paths, irreversible merges).- Wired fail-closed into four call sites:
dispatch_agent()'s task-allocation resolution,cmd_release,cmd_roadmap_add,cmd_goal_create— each raisesRuntimeErroronallowed=Falserather than proceeding. synlynk policy check-merge,synlynk policy sync-branch-protection,synlynk policy show— new CLI commands;sync-branch-protectioncalls GitHub's branch protection API idempotently, deriving required status checks from.github/workflows/.- This repo's own
.synlynk/policy.jsonmigrates the existing CLAUDE.md prose tables (Capability-Based Task Allocation, PR Review Discipline, Named Release authority) into data — CLAUDE.md now points tosynlynk policy showas the source of truth instead of hand-maintained tables. - Full
check_authority()unit coverage: allow/deny/requires_approval across both tiers, override-merge rule, missing-repo-override inheritance, unknown task_type denial (tests/test_policy.py, 11 tests). - Live-verified: branch protection synced and independently confirmed via
gh api repos/nikhilsoman/synlynk/branches/main/protection—required_status_checks=["test (3.8)", "test (3.10)", "test (3.12)", "qa-gate"],required_reviews=1,enforce_admins=true.
Fixed
- Default `role="dev"` on `cmd_release`/`cmd_roadmap_add`/`cmd_goal_create` didn't match the default policy's `pm`-only authority for these actions, causing unspecified-role calls (including coldstart's own roadmap-row write) to fail closed. Defaulted to `role="pm"`, matching the actions' actual authority scope. - Taxonomy regression: two new `policy` subcommands were missing `COMMAND_TAXONOMY` entries, failing `test_taxonomy_matches_real_cli_surface`.Release pitch: the execution floor gets a truth guarantee — every GitHub-write dispatch now has its claimed outcome independently verified against live GitHub state instead of trusted at face value — and workspace agents get a real identity: a storage-backed charter, a synlynk agent init/list/show/edit/disable onboarding surface, and dispatch integration that resolves role and harness from that identity automatically.
Added
GOVERNS Job-Truth / GH-Write Consolidation (#701, PR #978) — closes #331, #579, #935
synlynk/gh_verify.pygh_write_verified()— an independent delivery-of-effect check that queries live GitHub state via the orchestrator's ownghidentity (not the sandboxed job's), replacing "the job said it succeeded" with "GitHub confirms the write landed."- Wired into
dispatch.py's_check_job_stall(extends timeout on an unverified write, kills the job on a confirmed failure) andjobs.py's_reconcile_daemon_jobs(newsucceeded_gh_write_failedterminal status distinct from a clean success). gh_write_verifiedsurfaced as a column insynlynk jobsoutput.- Regression guard (
tests/test_gh_write_guard.py) asserting every terminal-status-deciding code path for a--requires-gh-writejob consults the check. synlynk doctorTC-7 preflight verifies Agy's localghallow-rules before routing gh-write tasks to it, instead of failing at dispatch runtime.- Codex PR-review tasks now route through the
ghCLI directly instead of the previously-unreliable MCPadd_review_to_pr/add_comment_to_issuetools.
Workspace-Scoped Agent Artifact Storage (design 2026-08-14/15, gh#936, PR #988)
- Mints a real
workspace_id(uuid4, persisted once in.synlynk/config.json) keying a new workspace-level agent artifact store. agent_idregistry (register_agent/resolve_agent_id) mirroring the existingmember_id/member_aliasespattern — loud failure on an unregistered alias, rejects duplicate agent_id/alias.- Canonical
charter.md+ provenance-chainedcharter.revisions.jsonlstorage (read_charter/propose_charter_revision) with stale-parent-revision conflict detection, extended tomemory/andstatements-of-record/entries. regenerate_agent_projection()writes a generated, gitignored.synlynk/agents/<agent_id>.yamlprojection (agent_id/role/overrides only, never charter content) via a stdlib-only flat YAML emitter.
Agent-Roles-Charters Phase 1 — CLI Onboarding + Dispatch Integration (design 2026-08-16, PR #1003)
synlynk agent init/list/show/edit/disable— the CLI onboarding surface for workspace agents (org-chart roles: dev/qa/pm/architect/tpm/designer/marketing/synlynk-bot), built on the storage layer above.dispatch_agent()gainsagent_idsupport: validates the agent is registered/enabled, resolves its role, auto-selects a harness by capability fit when none is forced, and threads the resolved role into GitHub-identity/token resolution (taking precedence overstory_id-derived role when both are present).synlynk dispatch --as-agent <id_or_alias>— makes theharnesspositional argument optional when--as-agenttriggers auto-selection.
Agent → Harness CLI Rename (PR #993)
- Renames
synlynk agent add/configure/run/listtosynlynk harness add/configure/run/list, resolving the naming collision between execution-backend harnesses and the workspace/role-identity agents introduced above. No deprecation shim — pre-1.0 breaking change, decided via a 4/4synlynk decide --panelvote (project-docs/decisions/2026-08-16-synlynk-s-cli-has-a-naming-collision-syn.md). - Frees the
agentCLI verb for the onboarding surface above.dispatch <agent>,open <agent>,probe --agent,quota --agentare untouched — those use "agent" in unrelated senses.
TPM/Session MVP (plan 2026-08-13, PRs #934, #944, #950, #954, #959)
sessionstable +synlynk/session.pyactive-session marker file helpers.devlog_entriesgainssession_id/goal_idcolumns;cmd_devlog_append()auto-inherits the active session when not passed explicitly.session_idthreaded throughdispatch_agent()→daemon_jobs→cost_entries(with inheritance from job to cost row), so every dispatch and its cost are attributable to the session that launched it.synlynk dispatch --session <id>override flag.synlynk session statussurfaces a NUDGE line whendaemon_jobshas rows with nosession_id— the first concrete TPM-facing signal for unattributed work.
Fixed
- Devlog identity re-fork prevented by resolving the devlog path through the `member_id` registry instead of a raw filename match (#956). - Dispatch stall-timeout extended for review-only jobs, which previously could be killed mid-review before posting (#939). - Review-only `synlynk dispatch` jobs no longer get miscounted against implementation-job budgets (#943, closes #937).Housekeeping
- Worktree/job accumulation (#559) audited and closed without new code:
synlynk worktree audit/worktree clean(shipped pre-0.13.1 in PR #676) already covers the core ask;synlynk status's existing staleness hint covers the proactive-warning ask. Re-verified against this repo's own worktree state during the audit.
Release pitch: synlynk gets safer to operate on — init/migrate/upgrade can now roll back on failure, project docs are DB-canonical instead of hand-parsed markdown, the GOVERNS event bus gains job-terminal and review-submitted events plus a synlynk events tail command, and a new doctor check catches invalid GitHub tokens before a dispatch wastes a turn discovering them.
Added
GOVERNS Event-Contract Extension (design 2026-08-12, plan 2026-08-12, #922)
job_terminalevent — emitted synchronously from_reconcile_daemon_jobs()for every daemon job reaching a terminal state, payload{job_id, status, cost_recorded, dispatch_context}.review_submittedevent — emitted fromscan_local_events()for each GitHub PR review not already represented, payload{pr_number, reviewer_login, reviewer_role, verdict}, withreviewer_rolederived from bot-login patterns.synlynk events tail [--type TYPE] [--limit N]— read-only CLI command listing recent events newest-first directly from theeventstable.
Init/Migrate/Upgrade Rollback Mechanism (design 2026-07-22, plan 2026-07-22)
rollback_checkpoint(Leg 1) wrapsinit()andcmd_migrate()in a git-checkpoint + untracked-state backup, auto-restoring on any mid-operation failure.rollback_checkpoint_upgrade(Leg 2) wraps_run_upgrade()in a global install snapshot (pipx reinstall-by-tag / script bin+lib backup), auto-restoring on upgrade failure.synlynk rollback [--last|<op-id>|--clear]— manual rollback CLI, restoring or discarding the most recent (or a specific) checkpoint manifest.--dry-runonsynlynk initandsynlynk upgrade— preview what would be written/changed without touching disk or making network/subprocess calls.- Failure-injection live selftest coverage for both rollback legs, plus dedicated
rollback --last/--clearscenario tests.
State Engine PR1 — DB-canonical roadmap/memory/costs (design 2026-07-20, plan 2026-07-25)
roadmap.md,memory.md, andcosts.mdare now write-through generated fromstate.db(roadmap_arcs/roadmap_phases, memory_entries, cost_entries), with rotation/archive and a warn-and-continue mutation guard for hand-edits.check_budgets()readscost_entriesdirectly instead of regex-parsingcosts.md.synlynk migraterun on this repo itself —project-docs/relocated under.synlynk/,.synlynk_migratedsentinel committed.
synlynk doctor TC-6 — GitHub CLI auth check (#928, closes #577)
- New check across all 4 dispatch harnesses (claude, codex, agy, grok) inspects
gh auth statusoutput for known invalid-token marker strings even when the command exits 0 — the documented false-green failure mode where a dispatch sandbox has a broken GitHub token butghdoesn't report a nonzero exit.
Fixed
- Bumped
linkify-itto 5.0.2 inwebsite/package-lock.json, resolving a high-severity quadratic-complexity DoS (CVE-2026-59887, GHSA-v245-v573-v5vm) in itsmailto:schema validator. Dev-only, transitive viamarkdown-it; fixes GitHub Dependabot alert #6. synlynk jobsnow resolves the repo's real default base branch beforegh pr create, avoiding hardcoded--base mainfailures on repos whose default branch ismasteror another tracked branch.synlynk dispatch agynow warns when no write/run permissions are granted, so headless dispatches do not fail silently when approval-gated tool calls are auto-denied.- Bumped
brace-expansionto 1.1.16 inwebsite/package-lock.json, resolving a high-severity exponential-time DoS (CVE-2026-13149, GHSA-3jxr-9vmj-r5cp) in expansion of consecutive non-expanding{}groups. Dev-only, transitive viaminimatch; fixes GitHub Dependabot alert #7.
Docs
docs/rca/2026-08-13-dispatched-pr-review-cancellation-714.md(#929, closes #714) — RCA concluding Grok'scancelledstopReason on dispatched PR reviews is harness-side, not a synlynk stall/timeout bug; no code change warranted.
Release pitch: synlynk learns to explain itself — every command now has a discoverable taxonomy entry with a maturity-tiered reveal, a live selftest exercises all 59 commands end-to-end, cost accounting gets payment-model awareness and a task-boundary fence around actual spend, and dispatch routing gets capability-aware enough to stop sending GitHub-write work to agents that structurally can't do it.
Added
Command Taxonomy, Maturity-Tiered Reveal, and Trigger Registry (design #303, PRs #304/#305/#309/#310/#311/#312/#316/#319/#320/#321)
COMMAND_TAXONOMYbecomes the single source of truth for all 59 commands —cli.py'sbuild_parser()extracted standalone (#304), taxonomy command surface restored and hardened (#305), defaultfenced_commandsallowlist (#309).- Command reference docs now generate directly from
COMMAND_TAXONOMY(#316) instead of hand-maintained markdown, closing a recurring drift source. - FTUE wizard and the
synlynklaunch picker are now driven by the same taxonomy (#319), so first-run onboarding and the reference docs can never disagree about what a command does or which tier it belongs to. - Tier-scoped trigger phrases wired into
synlynk:start/synlynk:endsession fencing (#320). - Pre-commit hook installed on
synlynk initto gate instructions drift between the taxonomy and generated CLAUDE.md/GEMINI.md/AGENTS.md content (#321).
Task-Boundary Cost Fence (story-615bc8f4, PRs #313/#314/#315/#317)
synlynk exec's actual-cost print now routes through a dedicated cost fence at the task boundary (#313) rather than being computed ad hoc per call site, closing a class of under/over-reporting bugs where a task's real spend diverged from whatcosts.mdrecorded.- Shipped and marked complete in the roadmap (#314); PM session cost for the execution itself logged per the Cost Capture Protocol (#315, #317).
Live Command Selftest (PR #328, follow-ups #335/#337)
synlynk selftest— a taxonomy-driven smoke test that exercises all 59 commands, catching command-surface regressions the unit suite doesn't (drift betweenCOMMAND_TAXONOMYand actual CLI behavior, broken flag wiring, silent crashes on real invocation).- Blog post documenting the design and implementation (#335).
- Follow-up fix: live paid selftest scenarios now rebind
DB_PATHto a scratch workspace instead of touching the real project DB (#337, scenario N6).
Capability Sweep + Industry Taxonomy (PR #367)
synlynk capability sweep— a taxonomy-driven calibration sweep scoring agent capability against NAICS/APQC/SFIA-coded skill axes, seeded fromsynlynk/capability_baseline.jsonand reinforced organically as real PRs land, with a configurable$10cost guardrail (capability_sweep.cost_cap_usd) and independent cross-agent verification scoring.- Legacy free-text
discipline/org_domain/industryvalues are crosswalked to NAICS/APQC/SFIA codes on migration, tagging unmatched valueslegacy_unmappedrather than dropping them.
Payment-Model-Aware Cost/Value Accounting — PMA-1 through PMA-6 (PR #374)
- Cost and value accounting now distinguishes payment model (subscription-seat vs. metered/API) so
costs.mdand budget reporting reflect what was actually spent under each agent's real billing arrangement, instead of a single blended token-rate assumption. - Manual cost entries gained payment-column population (#402); historical entries backfilled with
api_equivalent_usdfor cross-model comparison (#388). - Roadmap and devlog synced for both Capability Sweep (#367) and PMA (#374) landing together (#375).
Story-ID Auto-Provisioning for Dispatch (PR #407)
dispatch_agent()now auto-provisions astory_idwhen a dispatched task has none, closing a gap where ad hoc dispatches (not tied to an existing story) fell outside cost/capability tracking.
can_gh_write Capability Routing (issues #423/#426, PRs #427/#432/#438)
AGENT_CAPABILITY_BASELINESgained acan_gh_writefield so dispatch routing can structurally avoid sending GitHub-write work (gh pr review/merge) to agents that can't complete it headless (Agy, Codex, local) — previously enforced only by SOP convention (#427, #432 codified the convention first; #438 made it structural).- New
--requires-gh-writedispatch flag and enforcement logic indispatch_agent().
Fixed
synlynk watchcrash onCYCLES.index("work")(issue #421, fixed by #301, released here): thev0.12.0tag shippedcmd_watch()still looking up a"work"cycle name that had already been renamed out ofhud.py'sCYCLESlist under the GOVERNS seven-stage vocabulary rollout, raisingValueError: 'work' is not in liston every invocation. The fix (CYCLES.index("execute")) merged tomainvia #301 two days after thev0.12.0tag, but was never shipped in a release until now.synlynk viz --serveexits immediately, nothing binds the port (issue #421, PR #440, merged as #421):_start_server()spawned the HTTP server on adaemon=Truethread and returned immediately with no blocking call, so the process exited (killing the daemon thread with it) right after printing "Serving at...". Not a sandbox/forking artifact — reproduced identically in a real terminal. Fix adds_serve_until_stopped(), which blocks the main thread untilKeyboardInterruptand then cleanly shuts the server down.synlynk migratefalse-positiveMigrationImportErroron idempotent re-runs (#276, #278): natural-key collisions on re-import no longer trip the loud-fail check.- Dispatch auto-PR branch detection re-derives the worktree's actual current branch instead of trusting the pre-recorded name (#280, #283).
synlynk probeclearsHARNESS_VERSION_DRIFTfor the specific agent just re-probed (#281, #284).synlynk agent add <name>retrofits onboarding for a newly available CLI agent already on$PATH(#277, #285), plus lazy daily housekeeping on the firstsynlynk execof a new calendar day.- Token-outlier cost entries now flagged safely instead of silently corrupting averages (#295).
- Stale Cost Visibility / Repo Hygiene SOP text corrected (#290, #296).
- Per-provider model rates with freshness checks across
costs,doctor, andsentinel(#289, #297). - Probe version-token parsing fixed (#294); model version now resolved from agent config files (#287, #292).
agent_quotasnow populated from telemetry, plus a newsynlynk quotaCLI (#291, #293).- Job summary overwrites guarded against clobbering (#387).
- Dispatch worktrees branch from a fresh
origin/maintip instead of a potentially stale local ref (#398, #395). - Headless permission denials correctly classified, avoiding false positives from echoed source text (#399, #404).
- Agy permission dispatch enabled (#417).
- GitHub issue #379 follow-up:
.gfile handling fix (#384). __init__.pymodularisation epic marked shipped, closing stale #380 (#401).
Design specs: docs/superpowers/specs/2026-07-21-command-taxonomy-maturity-reveal-design.md, capability sweep and PMA specs referenced in PRs #367/#374. Roadmap rows synced for Task-Boundary Cost Fence, Command Taxonomy, and Live Command Selftest (#416). State Engine tiered design (single-user/team/enterprise) drafted for a future release (#412) — not shipped in this version.
Release pitch: the operational backbone gets provably reliable and provably accounted for — dispatched jobs finish their own git steps, a 5th zero-cost local agent joins the fleet, story routing gets real capability+quota+cost scoring with a fleet batch scheduler, and every dollar synlynk reports is now either structurally sourced or visibly flagged as an estimate.
Added
Measurement Ledger Hardening — Phase 1 + Phase 2 + display layer (epic #210, PRs #236/#241/#242/#244/#245/#246/#252/#256/#257/#264/#266/#267)
Phase 1 — provenance-tagged cost tracking (PR #236):
cost_entriesgained explicit provenance columns:cost_source TEXT NOT NULL(actual|estimated_token_rate|estimated_tshirt|estimated_manual|legacy_unknown, no default — everyINSERTmust pass it explicitly) andestimate_basis TEXT. Migration rebuilds the table and backfills historical rows aslegacy_unknown._insert_cost_row()(synlynk/db.py) is now the sole sanctioned writer tocost_entries, replacing four independently-drifting direct-SQL write sites indispatch.py,jobs.py(×2), andsupport_engineer.py. Upserts byjob_idwhen present. Enforced by a call-site audit test that fails the suite if any other file writes tocost_entriesdirectly.extract_tokens()now tags a.basis(regex_pair|total_split|none) distinguishing a real per-field token extraction from an 80/20 heuristic guess..synlynk/model_rates.json(scaffolded bysynlynk init) is now the source of truth for per-model rates andbilling_mode, replacing a hardcoded table; falls back to hardcoded rates on missing/invalid file.- New 3-tier t-shirt-size token fallback (
_estimate_tshirt_tokens()) for surfaces with no real token count: story'sestimated_tokenscolumn → historical average fromcost_entries(same discipline+phase, ≥3 samples) → fixed conservative default. synlynk cost log— manually log a cost row for native/unwrapped PM or brainstorming sessions with no CLI token data, taggedestimated_manual.- Cost coverage closed across every surface identified in the design spec's audit:
dispatch_agent()'s exec wrapper (no longer gated onin_tokens > 0),jobs.py's reconcile and daemon-reconcile paths,cmd_launch(), andsupport_engineer.py's investigation runs.synlynk release,synlynk probe, andsynlynk doctoraudited and confirmed correctly out of ledger scope. check_budgets()gained a dedicated sub-line surfacing failed-job placeholder estimates separately from the headline spend total.costs.mdand budget parsers now tolerate[est]/[legacy]/~prefixes.- New "Cost Capture Protocol" section in
CLAUDE.md. [failed job]marker fix:dispatch.py's zero-token-failure cost label now prepends (not appends) the marker so it survivesupdate_costs()'s 20-character command truncation, restoringcheck_budgets()'s failed-job sub-line to live code.
Phase 2 — structured-output token adapters, one per dispatch CLI (PRs #244, #252, #256, #257): replaces the 80/20 heuristic split with a real per-field structured-JSON extraction path for each vendor CLI — Codex, Claude, Agy (Gemini), and Grok all shipped, closing epic #210's adapter scope.
Display layer (PRs #264, #266): Vizor's Effort & Cost tab now visually flags estimated-vs-measured cost rows; synlynk status gained a RATES line (and JSON rates_updated_at key) showing when the model rate table was last updated, warning ⚠ never updated when no rate file exists.
Design spec: docs/superpowers/specs/2026-07-13-measurement-ledger-hardening-design.md. Roadmap arc + epic #210 marked shipped (PR #267). Deferred follow-ups filed as issues, out of scope for this release: #260 (Savings Ledger), #261 (dispatch-path unification), #262 (surface consolidation), #263 (stage constants staleness).
Local Agent — 5th dispatch agent, zero-cost on-device inference (PRs #200/#204/#205/#207/#208/#209)
localjoins claude/codex/agy/grok as a dispatchable agent, running as anaiderCLI subprocess against an on-device oMLX OpenAI-compatible endpoint — zero per-token cost.- Capability envelope seeding + concurrency guard so
localstarts with a conservative starter whitelist that self-widens with verified results. - Real-hardware opt-in pytest tier (
tests/test_local_agent_hardware.py) exercises actual Aider+oMLX end-to-end, correctly skipped when no local hardware is running. - Capability-matrix taxonomy worked example + blog post documenting the integration.
Capability Matrix Hardening — 3-stage routing engine + fleet batch scheduler (epic #137, PRs #139/#140/#141/#147/#148/#150/#151/#152/#154/#156)
_best_agent_for_story()now scores candidates across three real stages: weighted capability score (VERIFIER tier, dead-signal handling,pr_review_cycles/verified_by_cisignals), a hard quota-headroom gate (agent_quotastable across 5h/hourly/daily/weekly/monthly windows, degraded-mode fallback when quota signal is missing), and a cost tie-break (cheaper model wins when top scores are within 0.15).- New
synlynk/scheduler.py:stories.priority/readinesscolumns,synlynk story ready/draftgate, fleet-level in-batch headroom accounting (story N in a batch sees story 1..N-1's projected spend), retry/reassignment capped at 2 attempts,synlynk schedule [--execute] [--max-stories N]CLI. - GOVERNS seven-stage vocabulary rollout replaces the old CYCLES/CYCLE_COLOURS naming across the capability taxonomy and HUD.
- Capability tag enum enforcement + taxonomy reference doc;
cycle_capabilityrow dedup migration fix. - Deferred v2 (reset-timing-aware bin-packing, persistent quota-blocking history, GOVERNS-aware readiness gate) tracked as a goal, gated on 30 days of v1 production data (deadline 2026-08-10) rather than scoped into stories now.
Job Lifecycle Ground-Truth Verification (#126, #127, #128, #129, PRs #130/#131/#132/#133/#135)
dispatch_agent()creates a dedicatedgit worktreeper dispatched job (worktrees/<job_id>, branchdispatch/<agent>/<job_id>) instead of sharing the invoking shell'scwd— concurrent dispatches no longer collide._reconcile_jobs()cross-checks git state when a job's exit sentinel is missing, instead of treating an ambiguous exit as automatic failure; new"failed_unverified"status flags "inspect before discarding."files_touchedis real (viagit diff --name-only <merge-base> HEAD+git status --short --porcelain), no longer hardcoded to[].cmd_migrate()prints the resolvedDB_PATHand fails loud withMigrationImportErroron a 0-row import from a non-empty source, instead of a silent green banner.
Vizor
- Architect Map v2 (PR #167): replaces the static tube-map SVG with a live force-directed graph of workspace repos and typed cross-repo edges, a side drawer (path/stack/GitHub/dispatch/Gantt-jump/active-dream-count), and an IDE-style file-tree sub-view.
- Business Goals Panel (PR #153): surfaces
goals/storiesrollups in the HUD. __init__.pyre-modularized a second pass — 11 focused modules extracted (synlynk/db.py,jobs.py,dispatch.py,context.py,sentinel.py,scheduler.py, etc.), no more single-file monolith (PR #180).
Fixed
Dispatch git-finalization reliability chain (#182/#184/#185/#189/#190/#191/#196/#198, PRs #186/#187/#192/#193/#194/#195/#199/#201)
- Dispatched agents (Codex/Agy) frequently completed real, tested work but didn't reliably finish their own git steps (commit/push/PR). synlynk now performs git finalization itself once, gated on a job's
running→terminal transition (idempotent by construction) — stages everything except a hard-exclusion list, commits, pushes, opens a PR viagh pr createif none exists. - Borrowed-worktree completions attributed via
origin/<branch>state instead of being misread as zero-work. HARNESS_INTERNAL_TIMEOUTjobs now auto-retry (cap 2) instead of landing as a dead failure.- A job that raced its own disk writes and landed
failedwith0 touchedis re-inspected once and reclassifiedfailed_unverifiedrather than staying permanently stale. - Cost accounting no longer bypasses the per-model rate table in 3 places (including a hardcoded
gemini-2.5-pro$0 bug);localgets an explicit $0.0 override regardless of model version. - Capability router now filters on canonical
discipline, not the legacyengg_domaincolumn. - Daemon queue launch unified through
dispatch_agent()so worktree/preflight/permission-flags/concurrency-guard logic isn't duplicated across two divergent paths. - Harness no longer misreports completed jobs as
FAILEDwith fabricated token counts.
Misc dispatch/CI hardening (PRs #163/#164/#165/#171/#173/#238/#240)
- Codex sandbox gets
--add-dir <git-common-dir>so it can write git refs inside a worktree. dispatch --help's agent list now derives fromAGENT_CAPABILITY_BASELINESinstead of a stale hardcoded list.- Stall-killer generalized to detect harness-internal timeouts and checks remote branch activity before hard-failing a silent job.
- 3 baseline CI flakes isolated from runner environment state; Python 3.8 compat fix for a
tuple[str, str]annotation. dispatch --context-mode fullnow warns when used on a task that's already self-contained.
Release pitch: synlynk v0.11.0 is the Agent Ecosystem Operational Layer — every dispatch now carries permissions and recovery paths, your terminal shows a live fleet of agents in real time, and the full workflow discipline is baked into every agent directive file at init.
Added
Agent Autonomy Bridge (BS-12, PR #119)
synlynk dispatch --grant <perm> --revoke <perm>— per-task permission overrides; role defaults in.synlynk/config.jsonmap 12 roles (pm, review, implement, test, css, infra, etc.) to capability tiers. Resolved set translates to--allowedTools(Claude),--ask-for-approval(Codex), or a## Permissionscontext header (Agy).synlynk configure agent <name> [--flag k=v] [--env K=V] [--network-dep host:port]— write per-project harness overrides to.agents/<agent>.json;dispatch_agent()merges at call time: baseline → per-project overrides → per-task grant/revoke.synlynk jobs --stalled— list jobs withHANDOFF_PENDINGsentinel (set when a job accumulates STALL_NO_OUTPUT, FLATLINE, or QUOTA_EXHAUSTED). Shows job ID, agent, failure sentinel, elapsed time, and recommended next agent.synlynk jobs handoff <job_id> [--to <agent>]— transfer a stalled job to a new agent; appends## Handoff Noteto the job context file, incrementshandoff_count, updatesprevious_agents(JSON array), launches new dispatch with full context, clearsHANDOFF_PENDING.synlynk doctorTC-5 — scans each directive file for all 6 required SOP section headers; warns (non-blocking) if any are absent. Interactive fix wizard runs after each TC failure with structured fix paths (TC-1–5) and an "I'm stuck" escape that assembles failure context and dispatches Claude for conversational diagnosis.synlynk sync --repair-sops— re-injects missing SOP sections into directive files without touching existing harness fence content. Idempotent.- 6 SOP blocks written into CLAUDE.md, GEMINI.md, AGENTS.md, and GROK.md at
synlynk initandsynlynk synctime: PR Review Discipline · Brainstorm-First Policy · Design → Plan → Build Sequence · Capability-Based Task Allocation · Cost Visibility · Repo Hygiene. daemon_jobsschema additions:handoff_count INTEGER DEFAULT 0,previous_agents TEXT(JSON array). Migration applied automatically on first access.
Live Job Observatory (BS-13, PR #117)
synlynk watch --live— fullscreen live job board: all running/recent jobs with agent, status, elapsed time, cost, and output tail; auto-refreshes every 3s; Ctrl-C to exit.- Vizor Observatory tab — fifth tab in
synlynk vizbrowser dashboard: real-time job fleet table (JS polling), per-agent status badges, cost rollup, job output drawer.
Vizor Efficiency Enrichment (BS-22, PRs #113, #118)
- R/W/T budget bars — per-agent card shows Read, Write, Test utilisation as percentage of TIER1_CAPACITY.
- Cycle × Agent capability matrix —
6 × 4table (dream/plan/work/ship/maintain/engage × Claude/Agy/Codex/Grok) with full/partial/none badges (cap-full,cap-partial,cap-noneCSS classes). - Per-agent radar hexagon SVGs — 80×80px SVG radar on each agent card; 6-axis polygon filled at 30% opacity with agent theme colour; axis score maps
full→1.0,partial→0.5,none→0.0.
Ecosystem Status + Capacity (BS-16, PR #110)
synlynk status— terminal platform health: harness compliance table, agent availability, budget pulse (R/W/T capacity bars per agent), 6-cycle capability matrix.synlynk status --json— machine-readable ecosystem snapshot consumed by Vizor as its live data contract.- Three dispatch modes:
eco(respects R/W/T budget gates),daily-grind(default),perf(no budget gates). - Three new
_preflight_dispatch()gates:CAPACITY_EXCEEDED_INPUT,CAPACITY_EXCEEDED_OUTPUT,TOOL_PRESSURE. - New
state.dbtables:harness_status,cycle_capability;probecommand extended to seed Tier 1 capacity baselines. synlynk/status.pynew module;HarnessSnapshotdataclass inhud.py.
Modularisation (chore, PRs #103–#109)
- Extracted
synlynk/__init__.py(11,268L) into five focused modules:synlynk/probe.py,synlynk/sentinel.py,synlynk/upgrade.py,synlynk/dispatch.py,synlynk/_constants.py.__init__.pyreduced to ~1,500L of orchestration and CLI surface.
Fixed
TC-2 dispatch fix arc (PRs #114–#116)
- Fixed false-positive TC-2 failures caused by Agy
dispatch_flagsbaseline including--non-interactive(valid for Agy but flagged as invalid by harness validator). Corrected per-agent flag baseline maps. - Fixed
_run_tc2seeding invalid flags into the passed list on first scan, blocking all subsequent Agy dispatches. synlynk logsnow shows exit summary + TC-2 preflight gate result per dispatch.
BS-12 review fixes
--repair-sopsnow merges missing SOP blocks into existing harness fence body instead of replacing the entire fence.- TC-5 result wired into
all_passedincmd_doctor; doctor now exits non-zero when SOPs are missing. - Handoff note included in
handoff_tasksent to new agent (was reading context before append). - TC-5 fix menu scoped to agents with missing sections only (was firing for all agents in loop).
--flag KEY(boolean flag without=) inconfigure agentnow usespartitioninstead of crashing withValueError.
BS-22 review fixes
- Removed
is_placeholdershort-circuit in SVG circles matrix that contradicted the new text capability matrix. - CSS class
cap-{support}now normalised to lowercase; prevents unstyled cells from mixed-case DB values. - Removed unreachable dead-code fallback block in
get_capability_level().
Changed
- `synlynk doctor` interactive fix wizard replaces silent print-and-exit after TC failures. - `_check_job_stall()` now also writes `HANDOFF_PENDING` sentinel on STALL_NO_OUTPUT / FLATLINE / QUOTA_EXHAUSTED. - `dispatch_agent()` merge layer: baseline → `.agents/Release pitch: synlynk v0.10.0 is the Developer Preview — install it via pipx, set up your workspace in 60 seconds with the terminal wizard, and get a live browser dashboard that shows exactly what your agent team is doing.
Added
FTUE + Onboarding
synlynk init --wizard— FTUE typeform-style TUI wizard (6 screens: home harness detection, workspace topology, skills scan, agent fleet, role assignment, launch cheat sheet). Mandatory Phase 0 silent scan; writes workspace config, state.db, and role blocks into each agent's directive file. Ctrl-C before completion leaves no state.synlynk scan— re-runnable repo analysis: detects topology (single/mono/multi), fingerprints stack per repo/package via 14 file-presence heuristics, parses CLAUDE.md/GEMINI.md/AGENTS.md, maps to workspace in state.db, regenerates structured context.md. Flags:--refresh,--add <path>,--remove <path>,--dry-run.synlynk launch— FTUE task picker TUI with 6-cycle SDLC view (Dream · Plan · Work · Ship · Maintain · Engage); 12 scan-triggered launch templates (3 core + 9 stack-aware); dispatch preview screen;synlynk openreplaces oldsynlynk launch <agent>for direct agent open. (BS-19, PR #94)synlynk roles— print current agent role table from.synlynk/config.json;synlynk initandsynlynk doctornow generate per-agent directive role blocks (## Your Rolein CLAUDE.md, GEMINI.md, AGENTS.md). (BS-12a, PR #95)
State + Migration
synlynk migrate— one-shot atomic import ofproject-docs/markdown into state.db (8 steps: import → copy to.synlynk/project-docs/→git rm→.gitignore→ sentinel → commit). After migration, every DB write immediately mirrors to.synlynk/project-docs/as a local backup (write-through). Flags:--dry-run,--recover(re-import from backup after DB loss),--setup-dr(configure cloud-synced DR folder).synlynk memory add/synlynk devlog append— write memory entries and devlog sessions to state.db with immediate flat-file write-through.- 5 new state.db tables:
memory_entries,roadmap_arcs,roadmap_phases,cost_entries,devlog_entries;gh_issuecolumn onstories. - DR sync — configurable
dr_sync_pathin.synlynk/config.json; every write-through copy is also synced to a cloud-synced local folder (iCloud/GDrive/OneDrive). No OAuth, no new deps.
Deep Scan
synlynk scan(deep mode) — 6-stage pipeline: repo fingerprint, dependency graph, test coverage ratio, doc coverage, CI health, churn density. Stage Cards TUI with progress indicators; scan fences written to state.db;synlynk launchtemplates upgrade automatically from scan signal data. 6 new scan fields:test_ratio,readme_word_count,has_ci,has_docs,has_type_hints,has_orm. (BS-20, PR #96)
Daily-Driver Commands
synlynk jobs --summary <id>— after every job closes, print structured summary: files touched, exit status, cost, tokens, duration; append to.synlynk/logs/<job_id>.summary; readable viasynlynk jobs --summary <id>. (PR #97)synlynk release— Ship cycle stub: bump VERSION, generate CHANGELOG entry from merged stories since last tag, write blog post stub indocs/blog/;--dry-runpreviews without writing. (PR #98)synlynk status --platform— infrastructure health view: harness compliance (last probe, any DRIFT sentinels), agent availability table (installed/version/TC status), budget pulse (daily/weekly burn rate). (PR #99)
Browser Dashboard
synlynk viz— 5-view local browser dashboard generated fromstate.db, served athttp://localhost:8721. Views: Gantt (accordion drill-down, stage bars, pencil notes), User Journeys (split-pane,docs/journeys/*.md), Architect Map (tube map SVG fromvizor-tube.json), Effort & Cost (SVG bar charts), Efficiency (agent report cards + sentinel timeline). Sticky note system:POST /note→viz-notes.json→ injected intogenerate_context()(visual annotation → AI context loop). Live JS polling + browser notifications. Zero new deps. (BS-21, PR #101)
Packaging
- pipx packaging —
pyproject.tomlwith[project.scripts]entry point; VERSION is the single source of truth insynlynk/__init__.py(pyproject.toml reads it via dynamic attr). Install viapipx install git+https://github.com/nikhilsoman/synlynk. _detect_install_type()— detects pipx vs pip vs script install;synlynk upgraderoutes topipx upgrade synlynkwhen installed via pipx.
Changed
- **`generate_context()`** routes to `_generate_context_from_db()` when `.synlynk/.synlynk_migrated` sentinel is present; reads from state.db (top story, recent devlog entries, recent memory sections). - **`install.sh`** derives VERSION dynamically from `synlynk/__init__.py` instead of hardcoding. - **Python requirement** raised from 3.8+ to 3.9+. - **Refactor:** `main()` extracted to `synlynk/cli.py`; data-layer functions extracted to `synlynk/db.py`. Single-file `bin/synlynk.py` is now a thin dispatcher. - README fully overhauled: pipx install, badge strip, wizard-first 60-second quickstart, state.db architecture, all new commands documented.Tests
- 747 tests (up from 588 at v0.9.8); 28 new migrate tests, 28 launch/FTUE tests, 21 Vizor tests, 7 packaging tests, 40 deep-scan tests, full E2E round-trips.
Added
- **`synlynk exit`** — reverse all synlynk onboarding: strips managed sections from tracked instruction files (CLAUDE.md, GEMINI.md, etc.), removes `.agents/` profiles and `.synlynk/` directory, writes `SYNLYNK_HANDOFF.md` with re-init instructions. Dry-run by default; `--confirm` to execute. `--remove-docs` optionally removes `project-docs/`. - **`synlynk repair`** — exit + immediate re-init from captured config (agents, mode, org, repo, docs-dir). Dry-run by default; `--confirm` to execute. - **`synlynk sync`** — propagate updated synlynk artifacts (instruction file sections, missing `.agents/` profiles) to an existing repo without full re-init. Dry-run by default; `--confirm` to execute. - **`_strip_synlynk_section(path, marker_style)`** internal helper — removes synlynk-managed block from any instruction file; handles html/hash/none marker styles; leaves surrounding user content intact.Changed
- VERSION bumped `0.9.7 → 0.9.8`Added
- **Grok as a first-class fourth agent peer** alongside claude/agy/codex across all synlynk subsystems - `AGENT_CAPABILITY_BASELINES["grok"]` — cli, non_interactive_flags (`-p`), prompt_via_arg, dispatch_flags (`--always-approve`), roles (builder/architect), strengths - `AGENT_DISCOVERY_DEFAULTS["grok"]` — discovery path `~/.grok` - `_probe_model_version` — `grok -v` probe + `grok-[\w.-]+` version pattern - `GROK.md` template — identity (`Co-Authored-By: GrokFixed
- Stale time-sensitive fixture in `test_collect_capability_drop_returns_finding` — hardcoded 2026-06-21 timestamps replaced with `datetime.now(timezone.utc)`-relative valuesAdded
- `SynlynkDaemon` class — subclasses `WatchDaemon` to add an embedded HTTP server thread on `localhost:27471` and persistent job dispatch on every poll tick; double-fork daemonization inherited from `WatchDaemon`; separate pidfile `.synlynk/daemon.pid` and log `.synlynk/daemon.log` - `daemon_jobs` table in `state.db` — persistent job queue with `priority` (1–10), `depends_on` (JSON array of job IDs), and full status lifecycle `queued → running → done | failed` - `_reconcile_daemon_jobs()` — reaps finished child processes using `os.waitpid(WNOHANG)` (zombie-safe), reads `.exit` files for exit codes, updates `status`/`exit_code`/`completed_at` in state.db - `_dispatch_ready_jobs(max_parallel)` — launches queued jobs respecting concurrency cap and dependency chains; propagates `failed` status to downstream dependents immediately; commits per-job for crash-safe restart semantics - HTTP API on `localhost:27471` — 10 endpoints: `GET /context`, `GET /status`, `GET /jobs`, `GET /jobs/Fixed
- Daemon zombie process detection: replaced `os.kill(pid, 0)` with `os.waitpid(WNOHANG)` so exited child processes are properly reaped rather than staying `running` indefinitely - Dependency deadlock: queued jobs whose dependency fails are immediately marked `failed` rather than staying queued forever - Transaction isolation in dispatch: each launched job is committed individually so a crash mid-loop cannot produce duplicate spawns on restartAdded
- `synlynk join` — new member onboarding: seeds a devlog stub for the joining user, regenerates AI context files (CLAUDE.md, GEMINI.md, AGENTS.md) with the joining member's identity, and prints a team digest showing all active members and their recent focus areas - `synlynk team status` — team digest view: lists all members with devlog presence, current story assignments, token budget consumption, and last-active timestamp; reads `project-docs/devlogs/Fixed
- None in this releaseAdded
- `--docs-dirFixed
- Installed binary (`~/.synlynk/bin/synlynk`) crashed with `ModuleNotFoundError: No module named 'synlynk'` when invoked outside the source repo after the v0.9.0 package split. Fixed by embedding the package `synlynk/` directory in `~/.synlynk/lib/synlynk/` at install time and prepending `$HOME/.synlynk/lib` to `sys.path` in the installed shim. - `synlynk init` in a repo with existing `project-docs/` overwrote the existing docs with blank templates. Fixed by detecting existing files via `_find_existing_doc()` and migrating their content to the new location (or skipping write if no relocation is needed).Added
- Scoped dispatch context: `exec` now injects a per-task section (`## Current Task`) with only the relevant plan block instead of the full devlog, reducing context window usage - `## Relevant Files` injected per dispatch from the source map — derived from the task description matched against `source-map.md` symbols - `## How to Verify` contract injected per dispatch — specifies acceptance criteria the agent should validate before declaring the task done - Per-agent prompt framing: Claude, AGY, and Codex each receive a tailored preamble that matches their CLI interaction model (conversational vs. task-oriented vs. non-interactive) - Ed25519 capability rating signing: every `capability_ratings` row is signed with the project key so ratings cannot be forged across project boundaries - Anti-gaming quality cap: `test_count < 3` stories are capped at quality score 5.0 regardless of other signals, preventing artificially inflated ratings for untested work - `synlynk/` package split: all ~5000 lines of application logic moved from `bin/synlynk.py` into `synlynk/__init__.py`; `bin/synlynk.py` becomes a 5-line import shimFixed
- `capability_ratings` entries were not being attributed to the correct project when multiple synlynk-managed repos shared the same `~/.synlynk/` directory — Ed25519 project key now scopes all ratings correctlyAdded
- `synlynk agent run` — foreground support engineer investigation: collects signals, formats a structured report, and offers to file a GitHub issue or draft a fix PR - Five signal collectors for the support engineer archetype: failing tests, flaky tests, coverage gaps, stale dependencies, open GitHub issues exceeding age threshold - 7-day and 30-day deduplication: signals already filed within the window are suppressed so the agent doesn't file duplicate issues on repeated runs - `synlynk agent --install-cron` — registers a launchd plist (macOS) or systemd timer (Linux) that runs the support engineer agent on a configurable schedule - `.agents/` config directory: `support-engineer.json` defines signal weights, age thresholds, and notification channels per project; read by `synlynk agent run` at startup - GitHub issue filing via `gh issue create` with structured body including signal summary, affected files, and suggested fix skeleton - Draft fix PR creation via `gh pr create` for issues with high-confidence fix candidatesAdded
- `synlynk scan` / `synlynk scan --deep` — language-agnostic source scanner: reads file tree, extracts top-level symbols from Python/JS/TS/Go/Rust/Ruby/Java/C/C++ source, writes `source-map.md` and populates `source_symbols` table in `state.db` - `## Source Architecture` section injected into every `exec` context from the cached scan result, giving agents a structural overview without reading individual files - Passive git-HEAD cache: scan results are keyed to the current git HEAD SHA; a re-scan is only triggered when HEAD changes, not on every `exec` call - `synlynk scan --status` — shows last scan timestamp, HEAD SHA, and symbol count without re-scanning - Dual storage: symbols written to both SQLite `source_symbols` table (queryable) and `source-map.md` (human-readable, injected into agent context) - Language detection by file extension with fallback to content heuristicsFixed
- `synlynk scan` no longer traverses `.git/`, `node_modules/`, or `.synlynk/` directoriesAdded
- Instruction reach to seven additional IDE/editor targets: Cursor (`.cursor/rules/`), GitHub Copilot (`.github/copilot-instructions.md`), Windsurf (`.windsurfrules`), Cline (`.clinerules`), Aider (`.aider.conf.yml`), Continue (`.continue/config.json`), and Sourcegraph (`.sourcegraph/memory.md`) - SHA manifest (`instructions.json`) tracking the synlynk-managed section hash for each generated file; used for drift detection - Runtime drift detection: `exec` warns if any tracked instruction file's section has been externally modified since last generation - `synlynk instructions status / diff / update / ack` — manage instruction file state - Task status model: 5 states (`active`, `done`, `deferred`, `superseded`, `absorbed`); deferred tasks are included in context with reduced weight; `checkpoint` archives resolved states to a separate section - AGY CLI replaces Gemini CLI throughout: all references to `gemini` updated to `agy` - VERSION synced to GitHub releases (was incorrectly stuck at 0.4.x) - `DB_PATH` centralised to `~/.synlynk/projects/Added
- Model version tier-2 probe: `discover_agents()` now probes for Opus/Sonnet/Pro variants in addition to the base model, annotates capability entries with `model_tier` - `synlynk pr check` — validates that the current branch's diff satisfies the story's acceptance criteria before opening a PR; exits non-zero if criteria unmet - `synlynk score attest` — manually attest a story's quality score with a signed reason; appended to `capability_ratings` with `attestation=true` flag - Verifier pipeline output capture: `run --trio` now captures and surfaces the Verifier agent's structured review comment - Tokq `org_domain_tags` capability dimension: stories can be tagged with domain taxonomy labels (`backend/api`, `frontend/ui`, etc.) for cross-project capability aggregation - Constraint propagation: blocking story constraints propagate to child tasks; dispatching a child task for a blocked story emits a warning and requires `--force`Added
- SQLite WAL state database (`~/.synlynk/projects/Added
- Task status model (`active` / `done` / `deferred` / `superseded` / `absorbed`) added to the context schema; deferred tasks included in `context.md` with a `[deferred]` prefix - `checkpoint` archives all resolved-state tasks to a `## Resolved Tasks` section rather than deleting them — preserves decision history while keeping the active list clean - Agent instruction templates updated to explain the 5-state model and checkpoint archivalAdded
- Section marker system: synlynk-managed blocks in instruction files delimited by `` / `` markers so user customisations outside those markers are preserved on regeneration - SHA manifest (`instructions.json`): tracks content hash of the synlynk section in each generated file; used for drift detection - `synlynk instructions status / diff / update / ack` — full CLI for managing instruction file drift - `DB_PATH` centralised: all state now written to `~/.synlynk/projects/Fixed
- `init` no longer regenerates files that already contain a synlynk section — protects user customisations from accidental overwriteAdded
- `AGENT_CAPABILITY_BASELINES` — hardcoded capability dict for claude/gemini/codex/agy with `cli`, `non_interactive_flags`, `roles`, and `strengths` per agent - `discover_agents(config)` — probes each known agent CLI with `--version`, returns functional agents with their roles and capabilities; supports per-project path overrides via config - `_static_scan(root)` — reads git log, README, and file tree to produce a structured project context dict (project name, commit count, languages, recent topics) - `_write_informed_skeleton(scan)` — writes project-docs/ first draft using scan results instead of blank placeholders - `_llm_enrich(agent_name, agent_cli, scan)` — opt-in step that calls the best available agent non-interactively to synthesise an informed `roadmap.md` from scan results - `init()` refactored to a 6-step wizard: scan → **Magic Moment 1** (workgroup discovery table showing all detected agents with roles) → doc bootstrap → LLM enrichment offer → cloud nudge → finalise config - `dispatch_agent(agent, task, story_id)` — launches agent CLI in background using `subprocess.Popen(start_new_session=True)`, captures stdout to `.synlynk/logs/Fixed
- `_reconcile_jobs()`: `PermissionError` from `os.kill(pid, 0)` means the process exists (owned by another user) — no longer crashes the CLI; job correctly stays `running` - `_reconcile_jobs()`: empty `log_file` no longer accidentally reads/deletes an unrelated `.exit` file in the current working directory - `_llm_enrich()`: baselines now indexed by canonical agent name (not CLI binary path), so custom CLI paths still resolve the correct non-interactive flagsInfrastructure
- 5 new reconcile/enrich tests; 4 new E2E tests (dispatch, jobs, logs, reconcile startup)
- 188 tests total (up from 140)
Added
- Enriched agent instruction templates: CLAUDE.md, GEMINI.md, AI_INSTRUCTIONS.md now include Live Issues SOP (Sev1/Sev2/Sev3 with RCA doc path pattern), Git Worktree-First Policy, per-agent branch naming and commit trailers, Mid-Session Anti-Amnesia Protocol (Phase 1/2 cadence), Mandatory 4-Doc Discipline, and GitHub Projects v2 GraphQL integration block with parameterizable `PROJECT_ID` - `AGENTS.md` — new Codex agent instruction file, generated at repo root on `synlynk init` - `synlynk init --agentsChanged
- `synlynk init` now writes `project-docs/.synlynk_config.json` directly (previously missing from init, requiring manual creation)Fixed
- `exec_command()` now returns the child process exit code and `main()` calls `sys.exit()` with it — previously a wrapped command exiting non-zero would cause `synlynk exec` to exit 0, silently swallowing failures - `parse_costs_md()` was reading the wrong column (`parts[6]` = Summary instead of `parts[5]` = Estimated Cost USD), causing `status` and budget checks to always report $0.00 - `install.sh` version corrected from `1.2.0-lite` to `0.2.0` - `conftest.py` fixture schema aligned with real `costs.md` format (6-column) so budget tests exercise the correct parser behaviorRemoved
- Dead functions
log_telemetry(),extract_tokens(), andupdate_costs()— superseded bylog_telemetry_event()and manual cost tracking; removed to prevent confusion
Infrastructure
.gitignoreexpanded to cover.synlynk/,__pycache__/,*.pyc,.DS_Store,test_archive/,test_context_output/,.venv/project-docs/roadmap.mdupdated to reflect v0.2.x reality (was stale with v1.2/v1.3/v1.4 references)- Test added for exit code propagation (47 tests total)
Added
- `synlynk watch start/stop/status` — background daemon that polls `project-docs/` and regenerates `context.md` on any file change, with configurable interval and debounce - `synlynk checkpoint` — archives completed `[x]` tasks from `todo.md` into the user devlog, refreshes context, and emits a structured telemetry event - `synlynk status` — project state dashboard showing active tasks, last checkpoint, sentinel alerts, budget, and watcher state; `--json` flag for machine-readable output - `synlynk init --force` — overwrite existing template files - `set_state()` — writes `.synlynk/state` and updates terminal title with state icon (`●` watching / `⚡` active / `○` stopped) - Helper functions: `get_username()`, `get_mode()`, `load_config()`, `parse_costs_md()` - `log_telemetry_event()` — structured event logging with `schema_version` and `type` fields - `_check_costs_freshness()` — warns when `costs.md` has not been updated within the current session - Devlog archiving: entries older than 30 days moved to `devlogs/archive/YYYY-MM.md`Changed
- `generate_context()` — now compacts output: excludes completed `[x]` tasks, includes only "In Progress" roadmap rows, injects sentinel alerts at top when present, scoped to last 7 days of devlog - `check_budgets()` — now reads cumulative spend from `costs.md` instead of telemetry; request count sourced from telemetry `type=exec` events - `check_flatline()` — now writes alerts to `.synlynk/sentinel.md` in addition to stdout - `exec_command()` — uses `subprocess.Popen` (no stdout capture) for full TTY interactivity with Claude Code and Gemini CLI - `CLAUDE.md` / `GEMINI.md` templates — include full session protocol: startup checklist, during-session rules, session-end steps - `VERSION` bumped to `0.2.0`Fixed
- Type hint `str | None` replaced with `Optional[str]` for Python 3.8 compatibility (union syntax requires 3.10+)Infrastructure
- Added pytest test suite (
tests/conftest.py+tests/test_synlynk.py) with 46 tests andproject_dirfixture - Added GitHub Actions CI workflow (runs pytest on Python 3.8, 3.10, 3.12 on push and PRs)
- Added
LICENSE(MIT),CONTRIBUTING.md, PR template, issue templates
Initial public release.