Skip to content

Detect working/waiting agents in worktrees (reuse worktrunk's activity markers) #86

Open

Description

@noirbizarre

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:

  1. Read worktrunk.state.<branch>.marker via the existing Git::config_get
    (src/git.rs:965). No dependency on the wt binary or
    worktrunk_available() (src/git.rs:209) — only on the git-config
    convention, so this works even for repos that never installed wt, as long
    as some agent plugin (or a manual hook, per worktrunk's own docs) writes the
    marker.
  2. 🤖 (working) → WorktreeGuard::Working, skipped unconditionally, same as
    Locked — not overridden by --force, consistent with "work in flight is
    never removed."
  3. 💬 (waiting/idle) → reported distinctly (new ItemStatus::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.
  4. 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.
  5. Same flag/config shape as --worktrunk/--check-busy: --check-agents /
    --no-check-agents, sync.checkagents config, enabled by default,
    degrading to a no-op (not an error) when the [worktrunk] section is
    simply absent.
  6. 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;
    --force does 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 extra git config --get per worktree.
  • --no-check-agents / sync.checkagents = false skips 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>.marker via git config, JSON
    report coverage, README (flags table + config table).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions