Skip to content

Releases: LeahyCC/kungfu-kanban

v1.12.0 — A release is cut on every merged PR

Choose a tag to compare

@github-actions github-actions released this 29 Jul 21:23
b994f78

Added

  • A release is cut on every merged PR. Four versions (1.8.0 through 1.10.1)
    reached main without ever being tagged, because cutting the tag and the
    GitHub Release was a manual step nobody owned. Merging to main now runs
    scripts/cut-release.js: it reads the version, and if there is a dated
    ## [X.Y.Z] section for it that isn't tagged yet, creates the annotated tag
    and publishes the Release with that section as the notes. Tag and Release
    only — it never commits, so main's ruleset can't block it. A PR that bumped
    no version, or left its notes under [Unreleased], releases nothing and
    stays green. The convention that makes it work: PRs write their changelog
    section dated
    , not under [Unreleased] (see CLAUDE.md and the PR
    template). Publishing is opt-in when run by hand — a bare
    node scripts/cut-release.js prints what it would do and exits, because the
    first local smoke run of it published a real v1.12.0 that had to be deleted
    from the feed. CI passes CI=true; a human passes --yes. (#113 dated the
    1.11.0 section this builds on; #115 shipped the automation itself.)
  • A release no longer has to cite its own PR. The audit reconciles every PR
    merged since the prior tag against the release section, and the release's own
    merge commit joins that range the instant it lands — so the section had to
    reference the PR that wrote it, which you can only manage by amending a PR
    after opening it. It cost the automation its first run: #115 merged, the audit
    failed on the missing #115, test was skipped, the release job never ran,
    and nothing was tagged. The PR whose merge commit is HEAD is now exempt. On a
    pull_request the checked-out HEAD is a merge preview with no
    "Merge pull request #N" subject, so nothing is exempt there and the PR-time
    audit keeps its full strength.

Fixed

  • The terminal no longer scrambles fast typing. Each keystroke was its own
    POST, and concurrent requests have no ordering guarantee — so typing quickly
    (or holding a key down, or being on a tailnet where the round trip is tens of
    milliseconds) could deliver ls to the shell as sl. Caught in the wild:
    echo "shell=$SHELL… arrived as echo "shell$=HSLEL zs=hZ$SH_VESROIN….
    Sends are now serialized — one request in flight, anything typed meanwhile
    coalesces into the next — so a burst costs fewer requests than before, not
    more, and arrives in order. A failed send no longer wedges the queue or
    raises an unhandled rejection either. Shipped to main as 1.11.1 in #114 but
    never tagged — its notes were undated, which is the exact hole the automation
    above closes, so it is released here instead.

v1.11.0 — built-in terminal, terminal-style transcript

Choose a tag to compare

@LeahyCC LeahyCC released this 29 Jul 19:07

Bookkeeping: this section is four versions wide. 1.8.0, 1.9.x, 1.10.0 and
1.10.1 all merged to main without ever being tagged, so their notes ship
here rather than as releases of their own — the same call the 1.8.0 note made,
applied to everything that piled up behind it. The last tagged release was
1.7.1 (2026-07-28); this one covers the 27 commits since. Individual entries
carry their own (v1.10.0)-style markers where the version mattered.

Added

  • A built-in terminal (⌘J). A real shell on the host — your $SHELL,
    your ~/.zshrc, your starship prompt, your aliases — in a panel at the
    bottom of the board. It is a genuine pty, so colours, job control, and
    full-screen TUIs (vim, lazygit, claude itself) all work, and resizing the
    window resizes the shell. Sessions live on the SERVER: closing the panel or
    reloading the board leaves whatever you started running, and reopening
    reattaches with scrollback — including from your phone over the tailnet.
    Several shells can be open at once (tabs in the panel bar, ⏻ kill ends one
    for good). No native module: the pty comes from Python's stdlib via
    lib/ptyhost.py, so the install stays git pull && npm i.
    Off switch: ⚙ Settings → System → "built-in terminal" (it is a shell behind
    your board token; turning it off also ends any open sessions).
  • The board now says WHY CI is red when it's the GitHub account, not the
    code.
    When a PR's checks settle red, the watcher probes the failed run's
    jobs once; jobs that died with no runner assigned (runner_id 0, zero
    steps) are the Actions billing/spending-limit signature. The card gets a
    "⛔ CI blocked — GitHub account" badge quoting GitHub's own annotation
    ("recent account payments have failed…"), the drawer spells it out, one
    notification fires per red spell, the auto CI fixer stands down (no session
    resumes burned on failures no push can fix), and the Sensei snapshot
    carries infra: true with explicit do-not-retry guidance. (v1.10.0)
  • The empty board is now a composer. A quiet dojo opens with a prompt box
    and the settings that matter — project, model, effort, permissions, and
    worktree+PR — plus four ways out: ✨ Improve prompt (rewrites what you typed
    to be sharper and self-contained, with an undo; it creates nothing),
    ⇪ Split into cards (hands the text to the Sensei's drafting flow with your
    project carried across), ▶ Create & run, and + Add to backlog. ⌘↵ in the box
    creates and runs. Your last-used settings are remembered per device.
  • POST /api/prompt/improve — sharpen one prompt in place. No cards, no board
    side effects.
  • Board defaults for model and effort. ⚙ Settings gains "Default model" and
    "Default effort" — a card left on default now resolves to the board default
    at launch (fresh runs, follow-ups, and the fallback ladder all respect it; an
    explicit card choice always wins). The card editor's default options stop
    being a mystery: they read default (sonnet) / default (CLI picks).
  • Ultracode cards wear the rainbow. Max-effort cards get a rainbow ring
    that shifts continuously through the spectrum, plus a 🌈 max badge, so
    full-power runs are unmissable. The spin animates a registered <angle>, so
    it repaints only the 2px ring and stops under reduced-motion.
  • Appearance settings. A new tab in ⚙ Settings, saved per device: theme
    (night / day / follow the OS), text size, accent colour (seven swatches plus
    a custom picker — the whole vermillion family, including on-accent contrast,
    is derived from your choice), 🌈 rainbow mode for every card, compact
    density, and a per-board reduce-motion switch. A custom accent is never
    allowed to render link text below AA: the derived ink shifts away from the
    card surface only as far as 4.5:1 demands, so a mid-tone or very bright
    pick stays readable on both dojos.

Changed

  • The card transcript reads like a terminal. A tool call used to wrap
    across four or five lines, so a run of gh api … | jq … calls was a wall of
    monospace with the tool name buried in it. Each call is now one line: a
    vermillion prompt, the tool name bright, its argument dimmed and clipped
    with an ellipsis. Hover for the full text, click the row to unclip it.
  • Settings is four short tabs, not one wall. The modal grew past the point
    of being scannable, so it's now Cards / Appearance / Alerts / System, each a
    handful of related fields, opening on Cards.
  • The SHIPPED seal no longer has its top edge clipped (cards carry paint
    containment from content-visibility, so the stamp's overhang was cut off),
    and it straightens as you hover the card.
  • Logged-out guard. When a run or Sensei pass dies on "Not logged in", the
    board trips one deduped ⚠ entry plus a 🔐 chip, pauses auto launches and
    Sensei triggers, and requeues the victim card — instead of spamming the
    activity log on every interval. Every human-initiated run stays ungated as
    the probe (Run button, drawer follow-up, Sensei chat), so after
    claude /login any success clears the gate and resumes the queue.

Fixed

  • A red PR no longer re-fires on every CI attempt. The PR watcher compared
    each sweep's failed checks against the immediately previous sweep, so a new
    CI attempt on a red PR (push or re-run) — which passes through a pending
    phase and re-settles with the same failed set — read as a fresh failure every
    time: a duplicate ci-failing error entry, a notification, and a Sensei
    re-invoke per attempt (~50 duplicates and ~10 sensei runs in 40 minutes while
    Actions was billing-blocked). The watcher now remembers the last settled
    outcome and only fires when a settled state genuinely differs — a different
    failed set, or recovery to green — while pending phases in between are
    no-ops. This is the other half of the v1.10.0 account-block work: that one
    stopped the auto-fixer and the Sensei from acting on a billing block, this
    one stops the watcher from re-reporting the same red set at all. The verified
    infra verdict now also survives the pending phase, so a card keeps its
    "⛔ CI blocked" badge across a re-run instead of losing it the moment the
    counts blank. The 60s hot poll is unchanged. (v1.10.1)
  • A stray second server drove the board for six days. A card's own smoke
    test on 2026-07-22 backgrounded node -e "require('./server.js')" in the
    checkout and leaked it. It never held :4747, so nothing looked wrong — but
    it ran a full automation loop against the real data/: a Sensei pass every
    five minutes whose CLI could not authenticate (1331 Not logged in rows
    in the error tracker), a second inbox watcher racing the first (duplicate
    imports, "could not archive" errors, one duplicate card launched and failed),
    and a second PR watcher. The port was never a lock — a scratch server picks
    its own — so the data dir is one now: a second server against the same
    data/ refuses to start and says who holds it. It waits out a
    launchctl kickstart -k handover, takes over a lock whose process is gone,
    and ignores a garbage lock file, so the board can't be stranded by one.
  • ▶ Run looked broken on a card that couldn't start yet. A card with an
    unmet dependency (or a full board, or a gate up) is parked rather than
    launched — correct, but the drawer's Run button ignored the answer entirely
    and the board only explained the dependency case, so the click just seemed to
    do nothing. Every refusal now carries a reason and every Run path shows it:
    ⛓ queued — waits on <card>, — all 4 run slots are busy, — subscription limits are cooling down. ⚡ Bypass & re-run no longer claims a parked card is
    "running unrestricted".
  • Merged PRs left their cards stuck in Review. When the executing agent
    opened its own PR under its own branch name, the card's gh pr create came
    back "already exists" and the card kept prUrl: null — and the PR watcher
    skips cards with no PR URL, so merging the PR never shipped the card and
    every dependent stayed queued behind it. Six cards sat that way on
    2026-07-28. The sweep now backfills a missing PR URL first: it reads the
    branch out of the card's own worktree and asks GitHub which PR belongs to it,
    so a merge always moves the card to Done no matter who opened the PR.
  • A failing card reported "claude exited with code 1" and nothing else. The
    CLI writes its own failures to stdout (the result event) with stderr empty,
    so stamping the exit code over task.error discarded the only text the
    auth-gate, cooldown, and offline detectors match on. A logged-out CLI failed
    cards one at a time instead of pausing the board once; the real message is
    now kept.
  • The Sensei logged the same unactionable error every five minutes. A CLI
    that answers with its trouble in prose ("Not logged in · Please run /login")
    still reports success, so the decision JSON failed to parse and the run was
    logged as a plain error — 1331 identical entries accumulated over six days,
    and the auth gate was cleared on the way past. Both the errored and the
    unparsable paths now trip the right gate (limit → cooldown, logged out →
    auth gate) and log one pause; the gate clears only on a parsed decision, and
    an errored run reports its stderr.
  • ntfy push spammed the server log. A topic that isn't a legal ntfy topic —
    including the common trick of editing it to disable push — was POSTed anyway
    and earned an HTTP 400 per notification. An invalid topic now means push is
    off.
  • A raced inbox import logged a permanent "could not archive" error. Two
    scans of the same file left the second one unable to move an already-archived
    file, so the tracker carried an open error claiming the card would re-import
    when it never would. Gone-means-archived is no longer an error.
  • ✨ Draft and ↻ Refine killed the agent they had just spawned. The
    cancel-on-disconnect guard hung off the *reques...
Read more

v1.7.1 — Archive tab, command palette, budget enforcement

Choose a tag to compare

@LeahyCC LeahyCC released this 28 Jul 07:54
88fc5a0

Added

  • Archive tab. Done cards swept out of the board by archiveDays are no
    longer gone from sight: a third tab browses data/archive.jsonl newest-first
    with search, per-week throughput, per-repo counts, and token totals
    (GET /api/archive, GET /api/archive/:id). Rows expand to the full prompt
    and result; PR links come along. Read-only — restore can come later if it's
    ever missed.
  • Command palette + global shortcuts. ⌘K (or ?) opens a palette that
    runs commands and jumps to cards by fuzzy title/prompt match; n new card,
    i import, / focus filter, 1/2/3 switch tabs. Shortcuts never fire
    while typing or while a modal/drawer is open, and the empty palette doubles
    as the shortcut cheat-sheet.
  • Usage budget enforcement. The 5-hour ⛽ budget (usageBudgetM) now has
    teeth: when rolling output-token burn meets it, auto launches pause and
    manual runs park in Queued — exactly like the subscription cooldown — and
    the chip shows "5h budget spent · paused". Flow resumes on its own as the
    window slides; the escape hatch is raising or clearing the budget in ⚙
    Settings. The Sensei also sits out while the budget is spent.

Changed

  • Archive tab polish: titles ellipsize so meta columns stay aligned, rows share
    the board's hover/focus treatment, timestamps carry the full date on hover
    (<time>), and empty states now match the rest of the app — distinguishing an
    empty archive from a search with no matches.

Fixed

  • Offline-guard error entries were stored under the wrong kind (run-failed)
    because offline was missing from the error tracker's kind whitelist — so
    they never auto-resolved when the connection came back and sat in the ⚠
    tracker until dismissed by hand. Found while wiring the budget guard's
    entries the same way; both kinds are whitelisted now, with a regression test.

Notes

  • Cards imported from GitHub issues already auto-close their source issue on
    merge (Fixes #N in the PR body) — now locked by a regression test. Known
    limits, accepted: retargeting a card's repo after import can point #N at
    the wrong repo, and PRs into a non-default base don't auto-close (GitHub
    semantics).

v1.6.1 — performance & UX overhaul, Sensei idle gate

Choose a tag to compare

@LeahyCC LeahyCC released this 23 Jul 21:54
1e74adc

Release bookkeeping: the last tagged release is v1.1.0 (1.2–1.5.x were dated
in this changelog but never tagged), so this section formally also accounts for
#90 (release-integrity CI) — already described under [1.5.0] below.

Fixed

  • The Sensei no longer fires scheduled interval runs on an idle board. When
    nothing is queued/running/in review and there are no open errors or pending
    suggestions, the interval check is skipped silently (one explanatory log
    line per idle transition) instead of a "nothing to do — standing by" chat
    message — or a CLI error — every intervalMin. Event-driven triggers (new
    card, card finished, PR checks settled, chat) always run.
  • test/manager.test.js now isolates KFK_DATA_DIR — it previously ran
    against the checkout's real data/, appending fake merged PR of "undefined" entries to data/manager-log.jsonl on every test run.

Changed

  • Full-scope performance & UX overhaul (measured against a seeded 120-card
    board; before/after numbers in the PR):
    • Rendering: the board no longer rebuilds all DOM on every SSE event. A
      keyed reconciler patches only changed cards (server-stamped per-task
      revision v, field-compare fallback), columns/groups persist across
      renders, and listeners are delegated. SSE task/deleted tails are
      rAF-coalesced (N events/frame → one render) and manager/attention
      refreshes are badge-only while their views are hidden.
    • Network: SSE task frames drop heavy text fields (~2.4 KB → ~0.6 KB per
      event) with 250 ms per-id coalescing and slow-client backpressure;
      GET /api/tasks?v=<seq> answers 304 when nothing changed;
      GET /api/tasks/:id returns one full task; text assets are gzip'd and
      images get day-immutable cache headers.
    • Server: task saves no longer rewrite settings.json (and vice versa),
      tasks.json is compact with .bak only at shutdown, transcript appends
      are batched, the auth token is mtime-cached, the manager activity log is
      parse-cached, stream entries are capped at 20 KB, and PR sweeps poll
      with bounded concurrency.
    • Perceived performance: skeleton columns + inline critical CSS on first
      paint, non-blocking webfonts, modulepreloaded module graph, optimistic
      card moves/edits/deletes with rollback toasts, FLIP card motion
      (prefers-reduced-motion aware), and a 120 ms-debounced filter with a
      cached search haystack.
    • CSS paint: full-viewport mix-blend-mode grain replaced by plain alpha,
      the running-card ink stroke now animates transform instead of
      background-position, and cards/transcript/log entries use
      content-visibility: auto.
    • Service worker: the app shell is one versioned, atomically-installed
      cache unit (stale-while-revalidate) — a partial fetch can no longer mix
      module versions; /api/ stays live.
  • Accessibility: drawer is a true modal (focus trap + aria-modal), toasts
    are live-announced, tabs/panels are wired, transcript and chat are
    role="log", columns/cards carry region/list semantics with arrow-key
    navigation and roving tabindex, touch targets are 44 px, and the settings
    modal takes initial focus.

Changed (structure)

  • The frontend public/app.js (one ~2200-line script) is split into native ES
    modules under public/js/state, util, api, deps, markdown,
    board, drawer, modals, chips, manager, sse — with app.js reduced
    to a small entry point. No bundler and no build step: index.html loads it as
    <script type="module"> and Express serves the modules straight from disk, so
    the "frontend serves fresh from disk" rule still holds. Pure structure — no
    behavior change; shared mutable state (tasks/config/drawerId/mgrState) lives on
    one exported state object.

v1.1.0 — the attention popup (plus repos auto-scan, express 5)

Choose a tag to compare

@LeahyCC LeahyCC released this 21 Jul 02:09
d9e2cce

[1.1.0] — 2026-07-20

Added

  • A header 🔔 chip counts Sensei suggestions awaiting your verdict plus cards
    stopped on a permission block, and opens a "Needs your attention" popup
    with per-item and batch Approve/Reject and an Open-card shortcut. It
    auto-opens once on the 0→N transition and never nags after that. (#83)
  • Blocked cards get a one-click "⚡ Bypass & re-run": it re-runs the card
    with bypassPermissions instead of making you raise the permission mode
    and re-launch by hand. This is a deliberate human override, so it isn't
    clamped by the manager's permission ceiling the way auto-picked modes are. (#87)
  • When suggestions are being held by the hourly launch cap, the attention
    popup shows a notice with an "Approve-all now" path and a "Raise cap"
    control, instead of leaving them silently stuck. (#88)

Changed

  • The repos directory now auto-scans the common dev-folder conventions
    (code, src, projects, Documents/Code, …) and picks whichever holds
    the most git repos, falling back to $HOME — instead of defaulting to one
    person's ~/Documents/Code/Git. It's configured by whoever runs the board,
    never baked in. (#82)
  • Upgraded the one runtime dependency from Express 4 to Express 5. (#59)
  • The README now opens with a dark-mode board screenshot that adapts to the
    reader's GitHub theme. (#80)

Fixed

  • Stale Sensei suggestions are now auto-pruned instead of piling up.
    Takes effect after the next board restart on servers already running;
    fresh installs get it immediately. (#81)

Security

  • Transient browser-verification screenshots and .playwright-mcp/ output are
    gitignored, so a board screenshot — which can contain private card content —
    can never ride along in a PR. (#84)

Chore

  • CI: bumped actions/checkout to v7. (#58)

v1.0.1 — heavy tests, contributor gating, humanizer ships

Choose a tag to compare

@LeahyCC LeahyCC released this 20 Jul 18:25
e7722c1

[1.0.1] — 2026-07-20

Added

  • test/server.integration.test.js boots the real server as a child process
    to cover route-level regressions unit tests miss: validation coercions,
    the auth gate, and status-code contracts. parseSchedule/scheduleDue
    moved to lib/schedule.js so they're directly unit-testable. Every
    spawned server gets its own KFK_DATA_DIR (a fresh temp directory), an
    env override honored by lib/store.js and everything that derives its
    data paths from it, so the integration suite never touches this
    checkout's real data/.
  • Split the parser smoke test into per-module suites under test/ with
    decision-table coverage of the importer, deps, models, cooldown, prwatch,
    runner, errlog, auth, and skill install/status logic.
  • CI now runs the suite on ubuntu-latest and macos-latest (matrix) and prints
    node --test coverage on every run (no threshold gate yet).
  • Open-source contribution gating: CODEOWNERS, dependabot, contributor docs.
  • Release tags + GitHub Releases published (v0.13.0–v1.0.0 backfilled), and
    required for future releases.

Changed

  • README: badge row (CI, latest release, MIT license), hero image slot, and a
    tighter positioning paragraph up top for people landing cold.
  • The humanizer skill (MIT, vendored at skills/humanizer/SKILL.md) now ships
    with the board alongside ponytail: installs to ~/.claude/skills at boot,
    pre-selects on new cards, and the kungfu-todo template tells agents to apply
    it to PR titles, PR descriptions, and result summaries.
  • Mobile layout fixes: site manual overflow, masthead CTA wrap, app header under 360px.
  • site: humanizer pass
  • docs: humanizer audit — already clean (README.md, CONTRIBUTING.md, SECURITY.md, lib/skill.js template strings)
  • site: accuracy pass on the manual/FAQ/llms.txt — dependency chains, group
    batching, and the Sensei's diff review/merge/follow-up/error-tracker
    powers were live since 0.12–0.14 but undocumented on kungfu-kanban.com.
  • site: added /compare (honest comparison vs Vibe Kanban, Conductor, and
    Crystal/Nimbalyst) and /docs (linkable reference sections — import
    format, the Sensei's actions/autonomy, dependency/merge-gate semantics,
    groups & lanes), wired into nav, sitemap, and structured data.

v1.0.0 — the board runs its whole loop

Choose a tag to compare

@LeahyCC LeahyCC released this 20 Jul 17:48

Kungfu Kanban hits 1.0: the board now runs its whole intended loop. 0.13.0
cleared a full quality audit — atomic state writes, safe restarts,
merge-gated dependency chains, hardened import/PR plumbing. 0.14.0 closed the
loop on the Sensei — it reviews the actual PR diff, merges green PRs within
its autonomy setting, and sends precise same-session follow-ups instead of
blind retries, with every PR gated by CI. 0.15.0 made batched work flow as
grouped lanes with one-click queueing and group-complete notifications. 1.0.0
declares the surfaces stable: the import format, the HTTP API, the on-disk
data files, and the generated skill.

v0.15.0 — batched work flows as grouped lanes

Choose a tag to compare

@LeahyCC LeahyCC released this 20 Jul 17:48

Added

  • Grouped cards now run one lane at a time: at most one card per group is
    in progress at once, an in-progress group drains before a fresh one
    starts, and a manual run still bypasses the lane when you need it now.
  • A queue-group button on group headers launches every backlog card in
    that group with one click, instead of queuing them one by one.

Changed

  • A group now sends a single notification when it completes instead of one
    per card, and the Sensei prefers finishing an in-progress group over
    starting a new one and reviews a completed group's cards as a batch.

v0.14.0 — the Sensei reviews diffs and merges

Choose a tag to compare

@LeahyCC LeahyCC released this 20 Jul 17:48

Added

  • The Sensei now pulls the actual PR diff (gh pr diff, capped and truncated)
    into its review context for cards under review, instead of judging only
    the agent's self-report — the two serious flaws a human caught in the
    0.13.0 batch were invisible in the self-report and obvious in the diff.
  • The Sensei can now merge a card's PR itself (merge_pr), gated the same way
    as its other powers: a one-click suggestion under suggest, held for
    approval under semi, done alone under auto. It only merges when the
    card is in review, its PR checks are all green (no failing, no pending, no
    unknown/absent checks, right base), and it skips with a note otherwise —
    closing the gap where approve-without-merge left a "done" card still
    blocking its dependents. The 0.13.0 batch stalled at 14 finished cards and
    0 merges for exactly this reason; the human no longer has to be the merge
    button.
  • The Sensei can now followup_task a review card: resume its own agent
    session with precise feedback instead of always reject_tasking into a
    full fresh run. Reserved for small, specific flaws (name the file, name the
    fix); reject_task still handles approach-level failures that need a
    restart. run_task on an already-running/stopping card is now a no-op
    instead of an error, matching the other stale-snapshot races.
  • Import frontmatter now takes queue: true (alias autoqueue) to auto-launch
    every card in the file on import, instead of dropping them in Backlog where
    nothing picks them up. Chained cards (after:/sequential:) park in Queued
    and cascade automatically as their prerequisites ship.
  • Every PR now runs the test suite in CI, so a red run is machine-checkable
    before the Sensei ever considers merging it.

Fixed

  • PR-watch conflict fixer no longer spawns against an already-resolved PR: the
    sweep re-checks state/mergeable right before creating the fix card, and the
    fixer prompt itself re-verifies and bails as a no-op if the PR turns out
    merged, closed, or no-longer-conflicting by the time it starts.

v0.13.0 — quality audit hardens the board

Choose a tag to compare

@LeahyCC LeahyCC released this 20 Jul 17:48

Added

  • Stuck cards are now surfaced with a hung-agent watchdog, so a card whose
    agent silently stops making progress gets flagged instead of sitting idle
    forever.
  • The SSE connection now sends a heartbeat ping, so the board recovers
    cleanly from flaky wifi/sleep instead of silently going stale.
  • Imported cards are grouped by their import batch, making large imports
    easier to scan.
  • Cards held back by an unmet dependency now show their held-until-merge
    state, and the previously-silent 20-dependency cap is now surfaced
    instead of failing quietly.
  • A node test harness now covers the import/markdown parsers, catching
    parser regressions before they ship.

Changed

  • Dependent cards now release only once their prerequisite's PR has actually
    merged, instead of as soon as the card closes.
  • Card drag focus and selection now survive live board re-renders instead of
    resetting.
  • iOS PWA safe-area insets and the home-screen icon got a polish pass.

Fixed

  • A model-fallback retry storm, double-started runners, and double-fired
    card spawns are fixed — cards no longer race or duplicate their own runs.
  • Data file writes are now atomic (write-then-rename, with a safe backup
    ordering), so a crash mid-save can no longer leave the board file missing
    or corrupt.
  • The write API and auth checks are hardened against edge cases, and the
    import markdown parser no longer chokes on malformed input.
  • PR-watch base detection, merge-notification spam, and dead PR watches are
    fixed.
  • The usage scan no longer blocks the UI while it runs.
  • The manager log and imported-inbox no longer grow unbounded.
  • Failed inbox imports are now visible and won't duplicate on retry.
  • Fixed the transcript markdown renderer, drawer/modal state bugs, and
    Sensei actions repeating themselves against stale state.
  • Worktree cards now sync local main before launching, and base-branch sync
    no longer refuses to fetch into the currently-checked-out branch.
  • Server shutdown now stops running agents and flushes state cleanly before
    exiting.