Post 28 — PR #70 — v0.9.8: Health Pulse + Lifecycle Commands

Date: 2026-06-27
Branch: feat/v0.9.8-health-lifecycle
Version: 0.9.7 → 0.9.8


Where we left off

v0.9.7 added Grok as the fourth first-class agent peer. The CLI could now discover, inject, and dispatch to all four harnesses (Claude, Agy, Codex, Grok). The synlynk doctor command and HealthCheck registry were already in place from an earlier cycle — but the lifecycle was incomplete: once synlynk was running in a repo, there was no clean way to step back out or push updated artifacts forward.

What moved the goalpost

The BS-5 website redesign design phase completed this session, and BS-7 (Skill Pack Interoperability + Benchmarks) is queued for next session. Both require synlynk to be easy to install, evaluate, and remove cleanly — especially for benchmarking where a "before synlynk" vs "after synlynk" comparison requires running the suite with synlynk fully stripped from the repo.

That gap — no clean exit path — was OB-13 through OB-17 from the Onboarding epic. v0.9.8 closes it.

What shipped

synlynk exit (OB-13/14/15)

Reverses onboarding. Steps:

  1. Reads .synlynk/instructions.json manifest to find every tracked instruction file
  2. Strips the <!-- synlynk:start -->…<!-- synlynk:end --> block from each file, preserving surrounding user content
  3. Removes .agents/ profiles and the .synlynk/ directory
  4. Optionally removes project-docs/ with --remove-docs
  5. Writes SYNLYNK_HANDOFF.md summarising what was configured, including a ready-to-paste synlynk init command to reinstate

Dry-run by default. Pass --confirm to execute.

synlynk exit              # preview what would be removed
synlynk exit --confirm    # execute
synlynk exit --confirm --remove-docs   # also delete project-docs/

The key implementation decision: strip synlynk sections rather than delete instruction files. A developer's CLAUDE.md typically has both synlynk-managed content and their own. Deleting the file would destroy their custom instructions — so _strip_synlynk_section() removes only the managed block using the existing marker regex, leaving everything else intact.

synlynk repair (OB-13)

Exit + re-init in one command. Reads config before exiting (agents, mode, org, repo, docs-dir), then calls init() with the same parameters. Useful when synlynk state has drifted or .synlynk/ has been manually edited into an inconsistent state.

synlynk repair              # preview
synlynk repair --confirm    # execute

synlynk sync (OB-16/17)

Propagates updated artifacts to an existing repo without destroying and rebuilding:

  • Re-writes the synlynk-managed sections in all tracked instruction files with current templates
  • Creates any missing .agents/<name>.json profiles for slots in config
  • Updates .synlynk/instructions.json manifest SHAs

Does NOT touch project-docs/. Safe to run on any repo that's already initialised.

synlynk sync              # preview
synlynk sync --confirm    # execute

_strip_synlynk_section() helper

Internal function that removes synlynk blocks from instruction files:

  • html marker style: removes <!-- synlynk:start … --> through <!-- synlynk:end -->
  • hash marker style: removes # synlynk:start through # synlynk:end
  • none marker style: deletes the file entirely (synlynk owns 100% of it, e.g. .cursorrules)

Returns True if a section was found and removed, False if no markers present (file left unchanged).

Tests

13 new tests covering all three commands and the helper:

  • test_cmd_exit_dry_run_prints_plan — dry-run output, no files removed
  • test_cmd_exit_confirm_removes_synlynk_dir — .synlynk/ gone, SYNLYNK_HANDOFF.md written
  • test_cmd_exit_strips_instruction_sections — CLAUDE.md markers removed, user content preserved
  • test_cmd_exit_remove_docs_flag — project-docs/ deleted with --remove-docs
  • test_strip_synlynk_section_html — html markers removed, surrounding content preserved
  • test_strip_synlynk_section_none_removes_file — full-file ownership deletes the file
  • test_strip_synlynk_section_no_markers — no-op when no markers present
  • test_cmd_repair_dry_run — .synlynk still present after dry run
  • test_cmd_repair_confirm_reinits — init() called with captured config, .synlynk reappears
  • test_cmd_sync_dry_run — prints plan, no writes
  • test_cmd_sync_confirm_updates_instruction_files — sections rewritten, manifest updated
  • test_cmd_sync_no_manifest — advisory printed, returns 0

Suite: 513 → 524 passing (+11 net, 1 skipped for brainstorm HTML not present on this branch).

Where we are now

Lifecycle is complete: init → join → exit → repair → sync. synlynk can be cleanly installed, evaluated, stripped for benchmarking, and re-installed with one command. This unblocks the BS-7 benchmark session (skill pack interoperability) which requires a clean before/after comparison.

Next: BS-7 brainstorm (2026-06-28/29), then v0.10.0 developer preview (packaging, pipx install, first-run polish, synlynk viz).