Files
boshu2__agentops/docs/agents-dir-hygiene.md
T
Bo f3c6d0ecf2 Converge retained WIP and harden evidence boundaries (#1065)
Summary:
- lands the audited current WIP lanes and excludes stale/process-only
material
- hardens prune path confinement, probe-v3 evidence binding,
codebase-recon identity, handoff/release/reverse-engineer behavior, and
Codex prompt handling
- truth-labels static skill scoring and regenerates all owning
projections

Validation:
- fresh independent PASS on commit
427098ed10
- full Go suite and full Go race suite
- quick local release CI
- focused Bats, scenario/linkage, native-skill, reverse-engineer,
Cathedral, Ruff, Python ratchet, projection, and diff checks

Residual boundaries:
- final-basename ABA remains unclaimed
- live skill-probe coverage remains honestly 0/12
- release-only cross-build, SBOM, vulnerability, and release-evidence
checks are left to delivery CI
2026-08-16 18:32:26 -04:00

7.1 KiB

title, description, permalink, last_reviewed
title description permalink last_reviewed
.agents/ workspace hygiene Retention conventions for the .agents/ runtime workspace and how ao doctor keeps it clean. /agents-dir-hygiene 2026-08-16

.agents/ workspace hygiene

.agents/ is the per-repository runtime workspace: gitignored local state written by the ao CLI and by skills while they work. It is not committed (except a small pinned config under .agents/ao/), it is not a deliverable, and it is never a source of authority — work belongs to the tracker, source and delivery history to Git, sessions to CASS, curated memory to CM, and rules to docs/ADRs.

The preferred target layout from ADR-0016: ao/ (requested proof), scratch/ (disposable work, scratch/WRITER/DATE-SLUG/), and projections/ (named-consumer, manifest-stamped derived views). This target is not enforced as an exact closed set. A root outside it must have a declared compatibility or exact-path consumer contract; otherwise it is migration debt. Current declared exceptions include read-only .agents/handoff/, live .agents/mto-handoff/, and earlier skill-output roots retained by an explicit consumer contract in their owning skill. Two broad shapes of migration debt exist:

  • Knowledge-shaped directories — postmortems, pre-mortem checks, handoffs, retros, proofs: human-readable records a later session may re-read while they await promotion or expiry.
  • Machine-artifact directories — queue dirs, run scratch, staged outputs: consumed once by tooling and then debris.

Left alone, the second class accumulates. The workspace subsystem of ao doctor detects specific registered failure modes and garbage-collects their debris safely; it does not currently flag every top-level root outside the preferred layout. Where this page and ADR-0016 disagree, the ADR wins.

The ephemeral-dir contract

Any writer that mints a queue- or run-shaped directory under .agents/ MUST follow this contract:

  • Mark abandonment by renaming, never by deleting. A directory that is done or abandoned is renamed to <name>.stale-<timestamp> with a UTC timestamp in YYYYMMDDTHHMMSSZ form, e.g. land-queue-age-h433.19.stale-20260711T221032Z.
  • Retry attempts get -retry<N> suffixes, e.g. land-queue-age-h433.22-native-retry2. A retry directory may itself later be staled; both suffixes can appear on one name.
  • GC is ao doctor's job. Writers never delete workspace directories — they only rename. Doctor collects stale and retry-chain directories whose newest content is older than the TTL.

The GC TTL defaults to 14 days, measured against the newest regular-file modification time inside the directory. Override it with AO_DOCTOR_WS_TTL_DAYS (a positive integer day count; invalid values fall back to the default).

Canonical directory names

Skills and sessions have historically spelled the same top-level directories several ways. Doctor normalizes toward one canonical name per concept:

Canonical Known drift aliases
postmortem post-mortem, post-mortems
pre-mortem-checks pre-mortem, pre-mortems, premortem-checks
ao/handoff handoffs
retro retros
proofs proof
tests test

This table is a projection of workspaceCanonicalAliases in cli/internal/doctor/fix_workspace.go — the Go table is the source of truth. If the two disagree, the Go table wins and this page is stale.

.agents/mto-handoff/ is not a handoff spelling alias. It is a distinct live recurrence protocol consumed at that exact path by scripts/assay/consume-mto-recurrence.sh; Doctor preserves it in place.

How to clean up

ao doctor                       # detect-only: report findings, change nothing
ao doctor --fix                 # apply fixers (routes through mutate())
ao doctor --only fm-ws-empty-dirs   # scope to one detector (repeatable)
ao doctor --only workspace      # or scope to the whole subsystem

The workspace detectors are:

Detector ID Finds Fix behavior
fm-ws-stale-queue-dirs .stale-* / -retry<N> directories past TTL quarantine (rename)
fm-ws-empty-dirs empty top-level dirs (abandoned scaffolding) quarantine (rename)
fm-ws-naming-drift drift-alias directory names (table above) merge/rename to canonical
fm-ws-dual-store learnings split across .agents/learnings and .agents/ao/learnings report-only; defers to ao doctor --fix --only fm-knowledge-orphaned-flywheel-learnings (moves top-level *.md/*.jsonl only)
fm-ws-nested-tree a .agents runtime tree nested under a repo subdirectory report-only; manual review (may be an intentional nested project)
fm-ws-oversize unexpectedly large directories report-only

Every mutating run writes receipts under .doctor/runs/<timestamp>__<runid>/: a report.json describing findings and applied fixes, an actions.jsonl journal of every mutation, and an undo.sh wrapper for reversing them (see the exact undo contract below). .doctor/latest is a symlink to the most recent run.

Safety envelope

  • Doctor has no delete operation by design. What reads as "deletion" is an atomic rename into the run's quarantine/ directory (.doctor/runs/<run>/quarantine/workspace/<dirname>). Final disposal of quarantined content is always the human's call — for old runs, ao doctor gc requires explicit --yes and --before <date>.
  • Ambiguous merges are refused, not guessed. When a drift-alias merge (or the knowledge subsystem's learnings consolidation) would collide with existing content and the right merge is not mechanically certain, the finding lands in a Skipped list with the reason, and nothing moves.
  • What undo can and cannot reverse. Detectors are pure reads; every disk write flows through the audited mutation path and lands as a journal line. FILE mutations are content-hashed and backed up verbatim before they change, and undo restores them from those backups. DIRECTORY renames (quarantines and drift merges) carry no byte backup — the renamed/quarantined tree itself is the preserved copy, byte for byte — and undo reverses them by replaying the rename backwards. A crash in the narrow window between a rename landing and its journal line being written leaves that one mutation invisible to undo; recovery is manual, from the run's quarantine/ directory (the run receipts list what moved, and nothing is ever deleted).
  • Concurrent external writers are bounded, not excluded. Doctor's locks are per-process. A writer outside doctor racing a fix can slip content into a directory in the moment it is quarantined; that content is moved with the directory — journaled, restorable via undo, never destroyed.

What doctor will NOT decide

Disposal of large archives and eval payloads is a judgment call, not a mechanical one. fm-ws-oversize reports them — path, size, file count — and stops there. Doctor never quarantines, moves, or deletes content solely for being big; deciding what a large artifact is worth is the operator's job.