handoffs-tidy — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited handoffs-tidy (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Keep ~/.agents/handoffs/ focused through four review groups. Only the first three have completion/staleness evidence; the fourth is explicitly uncertain:
its Jira ticket is Done. These are usually never re-wrapped, so nothing supersedes them — they just sit in the picker looking 🟢 live until you notice the work is long gone.
question; it never makes the handoff an automatic archive candidate.
This command finds all four and archives the ones you confirm. A recent handoff is retained even when finished or stale; superseded rows are the sole immediate exception. Nothing is deleted — archived files move to ~/.agents/handoffs/archive/ and stay greppable.
Run it ad-hoc whenever the picker feels noisy, or right after a /wrap-up. It is the standalone twin of /handoffs's opt-in archive step (§3b): same list.sh classification, same archive flow — shared verbatim via REFERENCE.md — but with no full table, no picker, and no resume step. It only ever archives explicit selections. Automatic candidate groups exclude live/unknown rows; §Trunk-review and §Age-review separately allow assisted judgement of uncertain rows, never by age alone.
Earlier versions only found _superseded_ handoffs (it ran list.sh with no flags and looked at one field). That's why it rarely found anything — supersede is the narrowest signal. From v0.2.0 it runs the full liveness pass, so finished-but-never-re-wrapped handoffs finally surface./wrap-up whose handoff continued an earlier thread, or whose work has now shipped./handoffs shows entries you've moved past — merged PRs, closed beads, dead branches.MUST use the helper scripts. Never construct ad-hocls/grep/git/gh/bdpipelines against~/.agents/handoffs/— they bypass the per-script permission allowlist and miss the repo-matching and liveness logic. Classification and the archive flow are specified once in~/.agents/skills/handoffs/REFERENCE.md; read it rather than re-deriving the rules here, including
§Age-review for old rows with no usable signals.
Read ~/.agents/skills/handoffs/REFERENCE.md. It defines how to read list.sh's output, classify each row, and run the archive flow — the same definitions /handoffs uses, so the two never drift.
~/.agents/skills/handoffs/scripts/list.sh --check-branches [--stale-days N]Forward --stale-days N when the user supplied it; otherwise let the script match the age-review floor to the recent window (3 days, or 4 on Tuesday). Shorter values are clamped to that window. The threshold only controls the assisted age-review group and never changes archive-class.
--check-branches is what makes this command capable: it fills branch-state and (when gh is present) pr-state, so the script can mark merged PRs, landed branches, and closed PRs. Bead-closure (beads-done, keyed off the **Deliverable:** field when present) and supersede are computed regardless. See REFERENCE §Run and §Fields for the flag semantics and the 24-field line format. Degrades cleanly offline (REFERENCE §Run / the failure modes below).
Parse the ---HANDOFFS--- lines and the ---SUMMARY--- counts. For each current-repo row, derive its Status (REFERENCE §Status) and archive-class (safe / keep / empty — REFERENCE §Fields). Also note current-repo rows with needs-review=Y (step 5b) and needs-age-review=Y (step 5c), plus workspace-member rows with needs-age-review=Y (step 5e). These are assisted judgement groups, never automatic archive candidates.
Follow REFERENCE §Jira-Done for any current-repo row without another done/stale/supersede signal that names a Jira ticket. This catches handoffs whose only finished signal is a closed ticket (no merged PR, no closed beads). It's gated exactly as REFERENCE describes and degrades silently if the Jira MCP isn't configured — skip it freely if you want to stay network-light; PR/bead/branch/supersede classification still stands.
If current_repo_superseded == 0 and current_repo_stale == 0 and §Jira-Done promoted no older row to safe and no current-repo row has needs-review=Y or needs-age-review=Y and no member row is archivable (step 5d's gate) or has needs-age-review=Y (step 5e), report nothing and stop at step 6 — the picker is already tidy:
_No archivable handoffs — remaining rows are live, unknown, or still inside the recent grace window._Check step 5d's gate before stopping. In a multi-repo workspace the current repo can be perfectly tidy while its members hold many finished handoffs — member rows deliberately never feed current_repo_stale. Stopping on the current-repo counts alone reports "nothing to tidy" while archivable handoffs sit one level away, which is precisely the blind spot this command exists to close. When only member candidates exist, skip to step 5d rather than stopping.If there are auto-classified candidates, render them as a table, grouped by regret (REFERENCE §Archive-flow defines the groups). When only an assisted flag is present, skip straight to step 5b for current-repo needs-review, step 5c for current-repo needs-age-review, or step 5e for member needs-age-review.
## 🗂️ Archive candidates ({count})
| Archive? | Date | Slug | Branch | Status | Group |
|----------|------|------|--------|--------|-------|Superseded / Done / Stale. A row that is both superseded and otherwise archivablegoes in Superseded (the safest reason to archive). Order the table Superseded → Done → Stale.
safe as a recommendation and keep as requiring care, not selected choices.Stale rows may be the only record of an abandoned thread; confirmation follows the shared spec.
Run the archive flow exactly as REFERENCE §Archive-flow specifies: prompt with AskUserQuestion (multiSelect, one option per candidate, grouped and described per that section), then archive the selected filenames in one archive.sh call and parse ---ARCHIVED--- / ---SKIPPED---. Follow REFERENCE prompt bounds; leave all choices unselected. Surface every ---SKIPPED--- line verbatim with its reason. Never offer a 🟢 live, 🟠 PR open, or unknown row. archive.sh only moves — never deletes.
✅ Archived {N} handoff(s) to `~/.agents/handoffs/archive/`.If any current-repo row has needs-review=Y, run the assisted prompt per REFERENCE §Trunk-review — a separate, clearly-labelled prompt (not mixed into the step-5 groups) for legacy trunk-parked handoffs the script couldn't auto-classify: partial bead closure (beads-progress like 1/4), no **Deliverable:** marker, so it can't tell finished own-work from never-closing context. Present the {beads-progress} and bead list per row and let the user decide; archive any they confirm via the same archive.sh call. Skip entirely when no row is flagged. This prompt goes quiet on its own as old handoffs age out and new ones carry **Deliverable:**.
If any current-repo row still has needs-age-review=Y after §Jira-Done promotion, run the assisted prompt exactly as REFERENCE §Age-review specifies. Keep it separate from the safe/done/stale and §Trunk-review groups. Age is not evidence of doneness: leave every option unselected, make skipping trivial, and archive only filenames the user explicitly confirms. Skip when no row is flagged.
Run the member archive flow exactly as REFERENCE §Archive-flow-members specifies, after the current-repo steps. In a multi-repo workspace, member repos are where finished handoffs accumulate — the root itself often holds one or two.
Read the member rows from ---WORKSPACE-MEMBER-HANDOFFS--- (26 fields: the usual 24 plus {member-display}|{member-path}) and the per-repo totals from ---WORKSPACE-MEMBER-REPOS---. Classify each with the same §Status / §Archive-glyph rules as current-repo rows — member rows are already classified against their own repo when --check-branches was passed.
Key points from that section, so they aren't missed:
--check-branches was passed, and at least one member row is archive-class=safe; recent non-superseded member rows have an empty class and are not offered here.keep-class member rows (PR closed unmerged, branchgone with no merge evidence) are higher-regret — name them and point at cd {path} && /handoffs-tidy rather than offering them.
AskUserQuestion caps at 4 options and asingle repo can hold more candidates than that.
archive.sh call; it takes bare filenames and isrepo-agnostic.
Skip the step entirely when the gate doesn't pass.
If any workspace-member row has needs-age-review=Y, run the separate assisted prompt exactly as REFERENCE §Age-review-members specifies. These old unknown rows are not safe member candidates: leave every option unselected, offer per-row choices grouped by member repo, and archive only explicit selections. Skip entirely when workspace_member_age_review == 0.
If nothing was archivable or reviewable (steps 4–5e), or the user selected none, say so plainly and stop. This command never executes the saved work or deletes files. Uncertain handoffs are archived only through the separate assisted confirmation; no selection means no mutation.
and stop — this command is a thin driver over the handoffs skill's scripts and shared spec.
gate. Render the candidate groups once as a read-only preview (label each row's {source}), say archiving stays disabled until ~/.claude/handoffs is migrated or the unreadable location is fixed, and stop without any archive question or archive.sh call (it refuses while the legacy location exists). For partial, name the locations ---SOURCES--- reports as not readable.
cd into therepo and re-run.)
safe rows and step 5e for oldsignal-less rows. keep-class and partial-bead trunk-review rows still require cding into that member and re-running.
branch-state degrades to local-only (merged still detectedagainst the local default tip; no false gone). The Done/Stale groups just shrink. Don't retry.
pr-state reports unknown and classificationfalls back to branch-state + beads-done. No error, no retry. Squash-merged branches may show as ⚪ branch gone (keep?) rather than ✅ merged (safe) unless a closed bead or Jira-Done marks them done.
beads-done is always empty — finished work then relies onPR/branch/supersede (and §Jira-Done) signals alone.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.