Confirmed defects that are understood well enough to describe but are not yet fixed or covered by an OpenSpec change. Each entry records the symptom, what diagnosis has already ruled out (so it isn't redone), and the suggested next step. Remove an entry when a fix lands; if a fix becomes an OpenSpec change, note the change name here until it archives.
Issues 1 and 2 below were discovered during the 2026-07-07 live QA of the
subagent-ui-party-frames change (archived in openspec/changes/archive/).
Neither was introduced by that change.
Symptom: a cmd subagent finishes its work (TUI back at the idle prompt)
but its tracker record stays running indefinitely. The Stop hook — cmd's
lifecycle-end sentinel writer — fails with:
Stop hook error: /home/dev/Local/personal/tmux-pilot/.commandcode/.pi-tmux-hook.sh: No such file or directory
Observed live 2026-07-07 (~18:26): two cmd agents spawned at ~18:23 (which
rewrites the hook script — CmdHarness.setupEnvironment() always rewrites it)
hit a missing hook at Stop time ~2–3 minutes later. Both
.commandcode/.pi-tmux-hook.sh AND .commandcode/settings.json were gone,
while user-owned files in .commandcode/ (skills/, taste/) survived —
a surgical deletion of exactly the two files tmux-pilot writes.
Impact: without the sentinel, harness.isComplete() never becomes true,
and with staleness-timeout-ms: 0 and max-runtime-ms: 0 (both disabled by
default) nothing else bounds the agent — the record is a permanent zombie.
Auto-cleanup never runs; the GC command won't reap it either (window still
alive ⇒ not a zombie by isReapable()'s definition).
Widget symptom now contained (not the root cause): these zombie running
records used to bleed into a NEW parent session's widget as stale frames. The
subagent-ui-theming-and-style change scopes the widget to the owning parent
(selectVisibleAgents's ownership predicate + the reconciler adopt policy — see
AGENTS.md), so
a foreign or unverifiable zombie no longer renders in an unrelated session. The
underlying sentinel loss below is still open — the record itself remains a
zombie until reaped.
Recovery: steer_subagent with kill: true (→ interrupted, teardown
runs normally).
Ruled out by inspection (don't re-check):
CmdHarness.cleanup()— restoressettings.jsononly when it pre-existed (hasOriginalSettings === "true"), explicitly never deletes the hook script.teardownSubagent()— config-dir removal is gated byisOwnedConfigDir(), which refuses.commandcode; temp-file removal is gated to/tmppi-*files.- Worktree bootstrap (
worktree-bootstrap.ts) — only creates/removes symlinks on the worktree side; skips when a real file/dir occupies the link path.
Next step: root cause is unknown. Run an inotify audit (e.g.
inotifywait -m .commandcode/) during a cmd QA session with overlapping
spawns/teardowns and catch the deleting process. Separately worth considering
as a robustness fix regardless of root cause: have the Stop-hook registration
verify the script exists (or make the hook self-healing / embed the sentinel
write inline in settings.json instead of dispatching to a shared script).
Symptom: cmd subagents never show a cast bar (⟪ tool ⟫) in party frames
or a tool hint in raid cells, even during a long-running bash command. The
pi path works (verified live: ⟪ bash ⟫ during a 30s sleep).
Three independent defects, all required for a fix:
src/status-poller.ts—poll()doesif (!record.statusFilePath) continue;before the hooks-audit branch. Cmd records never have astatusFilePath(cmd doesn't usePI_TMUX_SUBAGENT_STATUS_FILEby design), sopollHooksAudit()is unreachable for every cmd agent.src/tracker.ts—createTask()copiespartial.statusFilePathbut dropspartial.hooksAuditPath; it is never persisted (same defect class as thepartial.harnessdrop fixed in the party-frames change).src/spawner.ts—createTask()runs at Phase 4 (window creation), but cmd only discoversenv.hooksAuditPathduringwaitForReady()at Phase 5 (it needs the cmd session ID). The value passed tocreateTaskis alwaysundefined, and nothing back-fills it afterward.
Impact: presentation-only — lifecycle, completion, and turn counting are unaffected (those come from the session file and the Stop-hook sentinel).
Next step: small dedicated change: reorder the poll() guard so the
hooks-audit branch runs independently of statusFilePath, persist
hooksAuditPath in createTask(), and add a tracker back-fill setter called
after waitForReady() resolves the path. Needs a regression test that a
running cmd record with only hooksAuditPath gets currentTool set.
Symptom: the widget's # in Q: N row may not visibly appear even when a
subagent tool call is made. The party/raid frame appears directly instead.
Diagnosis: SpawnQueue is populated at UUID allocation and is correctly
removed once a tracker record exists. Pi schedules extension-widget redraws
asynchronously (next-tick, with a 16 ms minimum cadence), while the spawner
can create that tracker record in the same event-loop turn before a paint
occurs. The queue is therefore a best-effort pre-tracker cue, not a guaranteed
observable state.
Impact: presentation-only. The tracker frame immediately provides the
agent's identity and running state; the spawn tool also retains one compact
▸ spawning <role> chat line per call.
Next step: no change currently planned. A guaranteed visible queue would require a short post-handoff presentation linger, deliberately overlapping the queue and tracker frame.
The isolated live QA run found and fixed two integration issues before the change was completed:
- Pi invokes extension-widget component factories synchronously during
setWidget(). The extension originally attached the widget before installing the hover factory, leaving the first controller unmounted. The factory is now installed beforewidget.attach(). - The live Pi and cmd TUIs on this host render on tmux's primary screen, so
capture-pane -a -e -preturnsno alternate screen. The tmux capture path retains the alternate-screen attempt and falls back only for that explicit response; the regression is covered by the real-tmux capture test.
There is no unresolved known issue from this QA run.