Repository navigation
Detect working/waiting agents in worktrees (reuse worktrunk's activity markers) #86
Description
Depends on #66.
Problem
#66 adds a --check-busy guard that answers one question: is any live
process's cwd inside this worktree? That's necessarily coarse — a process-table
scan can't tell a shell parked at an idle prompt from a coding agent mid-turn,
which is why #66 already has to special-case interactive shells (bash, zsh,
...) to avoid false positives, and still can't distinguish "an agent is
actively generating, uninterruptible" from "an agent finished its turn and is
sitting at a prompt waiting for the next instruction, session still open."
Both look identical from /proc/*/cwd: one live process, agent binary, cwd ==
worktree path.
That distinction matters for git sync: work truly in flight should never be
removed, but a worktree where an agent is idle-but-not-exited is a judgment
call the user could reasonably make differently from "someone's shell happens
to be parked here."
Worktrunk already solves exactly this, without a
process scan: its Claude Code / Codex / OpenCode / Gemini CLI plugins call
wt config state marker set "🤖" on session start/resume and
wt config state marker set "💬" when the agent finishes a turn and waits for
input, clearing it (wt config state marker clear) on session end (see
Activity tracking). The
marker is plain git config — worktrunk.state.<branch>.marker, value
{"marker":"🤖","set_at":<epoch>} — readable without invoking wt at all, and
it degrades predictably: a killed session just leaves a stale marker until
wt config state marker clear runs.
Proposal
Add a WorktreeGuard::Working (next to Locked / TooYoung,
src/cleaner.rs:992-1027) driven by this marker, layered in front of — not
instead of — the #66 busy scan:
- Read
worktrunk.state.<branch>.markervia the existingGit::config_get
(src/git.rs:965). No dependency on thewtbinary or
worktrunk_available()(src/git.rs:209) — only on the git-config
convention, so this works even for repos that never installedwt, as long
as some agent plugin (or a manual hook, per worktrunk's own docs) writes the
marker. 🤖(working) →WorktreeGuard::Working, skipped unconditionally, same as
Locked— not overridden by--force, consistent with "work in flight is
never removed."💬(waiting/idle) → reported distinctly (newItemStatus::Waiting,
src/report.rs:45-62) but not a hard guard: still subject to Skip worktrees with a live process inside them #66's own
busy check and the normal merged/dirty logic. This is the judgment-call
tier — surfaced so the user sees "an agent session is open here, idle"
instead of silence, but it doesn't block-y.- No marker present (repo has no
[worktrunk]section, or none set for this
branch) → fall back entirely to Skip worktrees with a live process inside them #66's process-table scan. The two checks
are complementary: the marker is precise but only present where a plugin is
wired up; the process scan is universal but coarse. - Same flag/config shape as
--worktrunk/--check-busy:--check-agents/
--no-check-agents,sync.checkagentsconfig, enabled by default,
degrading to a no-op (not an error) when the[worktrunk]section is
simply absent. - Document the marker format git-wipe reads (README config table) so the
convention is explicit rather than implicit "we happen to read worktrunk's
format."
Scoped to reading the marker only — git-wipe doesn't run agent sessions, so
it has nothing to set.
Acceptance
-
worktrunk.state.<branch>.marker= 🤖 → worktree skipped unconditionally;
--forcedoes not override. - Marker = 💬 → reported as waiting, not guarded; normal merged/dirty/Skip worktrees with a live process inside them #66
logic still applies. - No
[worktrunk]section, or no marker for this branch → falls back to
Skip worktrees with a live process inside them #66 behaviour at the cost of one extragit config --getper worktree. -
--no-check-agents/sync.checkagents = falseskips marker inspection
entirely. - A stale marker (agent process killed before its session-end hook ran)
does not crash or hang detection. - Unit tests seeding
worktrunk.state.<branch>.markervia git config, JSON
report coverage, README (flags table + config table).
Activity