# Phase 32: List Overhaul + Skill Hint Audit - Context

**Gathered:** 2026-05-16
**Status:** Ready for planning

<domain>
## Phase Boundary

Two coordinated surfaces, batched into one phase because new list flags require new argument-hints on the list-* skills (avoids a second DEPLOY cycle):

1. **List overhaul** — `$OWL list` and `$LIVE list` default to online-only, with a unified `--all` / `--offline` / `--here` flag surface. `--here` filters by repo-name membership (NOT by `info.json.cwd` path equality — see D-01 below; this is a deliberate departure from REQUIREMENTS.md LIST-04 wording).
2. **Skill hint audit** — every `/spt:*` skill ships an accurate `argument-hint:` YAML frontmatter field, and a regression-guard test enforces it for future skills.

Touches:
- `src/owl/list.rs`, `src/live/list.rs` — flag plumbing + filter behavior.
- `src/common/list_filter.rs` (NEW) — extracted `ListMode` enum + filter logic.
- `src/common/owlery.rs` — new `perch_has_repo_history` helper + repo-name derivation helpers.
- `src/common/types.rs` — extend `InfoJson` with new `project_history: Vec<String>` field.
- `src/live/start.rs`, `src/owl/listen.rs` (and equivalents) — append current repo names to `project_history` on every start/listen.
- `plugin/spt/skills/*/SKILL.md` — 14 skills × `argument-hint` audit; 3 new (list-ready/live/psyche), 3 corrections (commune/psyche-download/whoami), rest verified.
- `tests/skill_hints.rs` (NEW) — regression guard reading every skill frontmatter at `cargo test` time.

**REQUIREMENTS.md amendment required** — LIST-04 must be reworded from "info.json.cwd does not match the current working directory (canonicalized)" to "current repo name is not in info.json.project_history". Doc-only commit at the top of Plan 01.

</domain>

<decisions>
## Implementation Decisions

### `--here` Semantics (replaces LIST-04 wording)

- **D-01: Match by repo-name membership, not cwd-path equality.** `--here` filters perches by whether the current repo name(s) appear in the perch's `info.json.project_history` array. Path equality (Phase 31 D-12 style) is rejected because `cwd` represents a current/momentary working directory — an agent may have history with the current repo but be momentarily active elsewhere. Repo-name membership captures the durable "has been active here" relationship.
- **D-02: New `project_history: Vec<String>` field on `InfoJson`.** Stores repository NAMES only — never working-directory paths. Examples: `["claude_skill_owl", "rebno", "wit-what"]`. Additive schema change (existing `cwd` field stays unchanged for other uses).
- **D-03: Repo-name derivation = local basename ∪ remote origin basename.** When computing "current repo name(s)" for a `--here` query (and for `project_history` appends), derive BOTH: (a) basename of the directory containing `.git` (walk parents), AND (b) basename of `git remote get-url origin` (if `git` CLI is available; fall back to `gh` CLI if present). De-duplicate. Local-name and remote-name can diverge (e.g. forked repo cloned under a renamed dir), so capture both.
- **D-04: `--here` match = OR-overlap.** A perch matches if ANY of the current-context repo names appears in its `project_history`. Set-intersection non-empty.
- **D-05: Append-on-start trigger.** `project_history` is appended to on every `$LIVE start` AND every `$OWL listen`. Derive current repo names per D-03, append any missing entries to the perch's `info.json.project_history`. De-dupe. Idempotent. NOT updated on poll cycles (avoids write contention and is unnecessary — once a name is appended, it stays).
- **D-06: No-git-repo fallback.** If `.git` is not found by walking parents (user is in a non-repo directory), fall back to using `Path::new(cwd).file_name()` as the single repo name. `--here` still works; user just gets directory-basename semantics.
- **D-07: Helper name = `perch_has_repo_history(perch_dir, repo_name)`.** Lives in `src/common/owlery.rs`. Takes a perch dir path and a repo NAME (not a cwd path), returns bool. Caller computes the current repo name set per D-03 and tests each via this helper (or a wrapping `perch_has_any_repo_history(perch_dir, names: &[String])`).
- **D-08: Legacy perch handling.** Perches whose `info.json` predates this phase have NO `project_history` field. Deserialize as empty `Vec<String>` (serde default). Such perches will NOT match `--here` for any repo until they next run `start` / `listen`, which appends the current name. Acceptable — legacy perches simply don't show under `--here` until refreshed. No migration script.

### Flag Conflict + Discovery Hint

- **D-09: `--all` / `--offline` mutex = clap `conflicts_with`.** Declare `#[arg(conflicts_with = "all")]` on `--offline`. Clap rejects at parse with a standard error and exit code 2. No custom owl-styled error; matches stock CLI conventions and keeps `run()` clean.
- **D-10: `$LIVE list` gets a parallel discovery hint.** When `$LIVE list` (no flags) returns zero online live agents, emit: `No online live agents. Pass --all to include offline.` Mirrors LIST-05 for symmetry.
- **D-11: `--here` empty-result hint mentions the filter.** When `--here` filters online results to zero (but the unfiltered list WOULD have non-zero online perches), emit: `No online listeners here. Drop --here or pass --all to widen.` Smart hint — tells the user the filter caused the empty state, not the underlying registry. Equivalent variant for `$LIVE list`. Pre-compute the "would-have-non-zero" check by counting online perches once before applying `--here`.

### Argument-Hint Values (HINT-03 corrections)

- **D-12: `/spt:commune` → `argument-hint: ""`.** Commune messages are composed by the live agent (not the user) and fire automatically. Slash invocation takes no user arg. Overrides the current `<msg>` value.
- **D-13: `/spt:psyche-download` → `argument-hint: "[<id>]"`.** Optional positional id; defaults to current Self when omitted. Bracketed form matches `listen-stop`'s `[<id>] | --all` convention.
- **D-14: `/spt:whoami` → `argument-hint: ""`.** Replaces current verbose `(no arguments)`. Matches `clear-psyche` / `signoff` empty-string convention.
- **D-15: HINT-02 new hints (list-ready, list-live, list-psyche) = `[--all] [--offline] [--here]`.** Order: all → offline → here. Quoting per HINT-04 YAML safety: the brackets require double-quoting → `argument-hint: "[--all] [--offline] [--here]"`.

### Refactor Scope + Plan Split

- **D-16: Full extraction to `src/common/list_filter.rs`.** Move `ListMode` enum, perch-filter predicate, and the online/offline two-pass collection logic to a new common module. `src/owl/list.rs` and `src/live/list.rs` become thin wrappers selecting which `PerchState` values pass through and which output formatter to use. Per LIST-06.
- **D-17: Three plans.**
  - **Plan 01** — REQUIREMENTS.md/ROADMAP.md doc amendment (LIST-04 rewording) + `project_history` schema addition to `InfoJson` + repo-name derivation helpers in `common/owlery.rs` + write-site updates on `$LIVE start` / `$OWL listen`. Foundational.
  - **Plan 02** — `src/common/list_filter.rs` extraction + flag plumbing (`--all` / `--offline` / `--here` on owl & live) + discovery hints (D-10/D-11) + clap mutex (D-09) + golden test regen (LIST-08).
  - **Plan 03** — Argument-hint audit across all `plugin/spt/skills/*/SKILL.md` (HINT-01 sweep + HINT-02 additions + HINT-03 corrections + HINT-04 YAML quoting) + `tests/skill_hints.rs` regression guard (HINT-05).
- **D-18: HINT-05 regression guard = Rust integration test.** `tests/skill_hints.rs` enumerates `plugin/spt/skills/*/SKILL.md`, parses YAML frontmatter, asserts every file has an `argument-hint` key. Runs under `cargo test`. Single enforcement point; no DEPLOY.ps1 hook needed.

### Claude's Discretion

- **Repo-name derivation exact code path** — pick between shelling out to `git` (simpler, requires git on PATH) and walking parents for `.git` in-process (no external dep, more code). User said "check both basename where .git is, but also if `git` or `gh` CLI is available, also check against the remote origin name". Recommendation: in-process `.git` walk for the local basename (zero-dep, always works) + try-shell-out to `git remote get-url origin` for the remote basename (gracefully skip if `git` absent or no origin). `gh` is a last-resort fallback if `git` fails. Finalize during planning.
- **Plan 01 vs Plan 02 boundary** — write-site updates for `project_history` append could live in Plan 01 (closer to schema) or Plan 02 (closer to filter implementation). Recommendation: Plan 01 (schema + writers ship as one coherent change so Plan 02's filter has data to filter on). Decide during planning.
- **`live_dim_status` vs `eprint!` alignment** — `src/live/list.rs` uses `output::live_dim_status`; `src/owl/list.rs` uses raw `eprint!` with manual ANSI codes for offline rows. The extraction in D-16 should reconcile to one shared helper. Pick during Plan 02.
- **Sort order within `--here` results** — alphabetical (matches current owl/list.rs `dirs.sort_by_key`) is the default; an alternative would be "most recently active first" using `info.json` timestamps. Keep alphabetical unless planning surfaces a reason to change. Phase 31 chose `last_active` desc for picker; list can stay alphabetical because list is exhaustive enumeration, not selection.
- **`gh` CLI as second-tier remote-name source** — only invoked if `git remote get-url origin` returns nothing. Pick the exact `gh` command during planning (likely `gh repo view --json name -q .name`). May be deferred entirely if `git` is reliably available.

</decisions>

<canonical_refs>
## Canonical References

**Downstream agents MUST read these before planning or implementing.**

### Phase requirements + planning artifacts
- `.planning/REQUIREMENTS.md` LIST-01..LIST-08, HINT-01..HINT-05 — 13 requirements. **LIST-04 to be re-worded per D-01/D-02** (cwd-path-match → project_history repo-name match). Plan 01 begins with the amendment commit.
- `.planning/ROADMAP.md` Phase 32 — goal + success criteria. Success criterion 2 references `info.json.cwd` — must be revised in lockstep with REQUIREMENTS.md LIST-04 wording change.
- `.planning/phases/31-picker-correctness/31-CONTEXT.md` D-09, D-12 — cross-references for cwd-handling pattern (intentionally diverged from in Phase 32 per D-01).

### Core list code surfaces
- `src/owl/list.rs` — current implementation with `online_only: bool` flag and two-pass online/offline display. Lines 70-84 = current online-check pattern. Lines 156-168 = output formatting.
- `src/live/list.rs` — currently flag-less. Must be refactored to share filter logic with owl/list.rs per LIST-06.
- `src/common/list_filter.rs` (NEW per D-16) — destination for extracted `ListMode` enum + filter behavior.
- `src/common/outcomes.rs` — `ListOutcome` and `PerchInfo` structs used by `list_result`. Confirm `--here` and `--offline` propagate correctly through structured-result variant.

### `info.json` schema surface
- `src/common/types.rs` — `InfoJson` struct (`cwd` at :51). Phase 32 adds `project_history: Vec<String>` with `#[serde(default)]`.
- `src/common/owlery.rs` — destination for new `perch_has_repo_history` helper (D-07) and repo-name derivation helpers (D-03). Existing helpers: `is_perch_online`, `perch_dir`, `enumerate_perches`.
- `src/common/agent_ids.rs` — neighbour for any agent-id-style storage decisions; not directly touched.

### `project_history` write sites
- `src/live/start.rs` — `$LIVE start` perch creation. Add repo-name append-on-start per D-05.
- `src/owl/listen.rs` (and the listen-once / monitor-mode equivalents) — `$OWL listen` perch creation. Same append-on-start logic.
- Any other code path that writes/refreshes `info.json` — audit during Plan 01 implementation.

### Skill frontmatter surfaces
- `plugin/spt/skills/{clear-psyche,commune,context-save,list-live,list-psyche,list-ready,listen,listen-stop,live,live-stop,new-alarm,psyche-download,reboot,revive,send,signoff,whoami}/SKILL.md` — 17 skills total. Current `argument-hint` audit grep at conversation start covered 14; the 3 list-* skills currently have no hint and must gain one per HINT-02.
- `tests/skill_hints.rs` (NEW per D-18) — regression-guard integration test.

### Pick-spec interaction surface (informational)
- `src/live/pick_spec.rs:250-298` — `build_resolve_spec` cwd-canonicalization pattern. **NOT reused by Phase 32** (D-01 chose repo-name semantics instead) but documented here so downstream agents understand the deliberate divergence.

</canonical_refs>

<code_context>
## Existing Code Insights

### Reusable Assets
- `owlery::is_perch_online` — current online check, reused by both list flows post-refactor.
- `owlery::enumerate_perches` — directory walk pattern; the extracted filter in `list_filter.rs` can build on this.
- `types::get_pid_from_info` / `types::is_process_alive` / `types::get_parent_pid_from_info` — liveness check chain duplicated verbatim across owl/list.rs (:70-84) and live/list.rs (:85-105). Extraction collapses this duplication.
- `spool::pending_count` — pending-message count per perch; used by both list flows unchanged.
- `output::owl_status` / `output::live_status` / `output::live_dim_status` — status emitters. The extracted `list_filter.rs` should remain agnostic; output stays in owl/list.rs and live/list.rs.

### Established Patterns
- **Two-pass collect-then-print** (owl/list.rs:46-153, live/list.rs:45-117) — online entries first, offline second. Preserve this pattern in the extracted module.
- **PerchState filtering** (owl/list.rs:63-68, live/list.rs:64-66) — owl hides Psyche/Spine/Touch/Working; live shows only Live. The extracted filter takes a `passes_state: fn(&PerchState) -> bool` predicate.
- **Soft-cleanup of stale online perches** (owl/list.rs:114-141, live/list.rs:85-105) — when ready file exists but PID + parent both dead, remove `ready` and treat as offline. Behavior preserved post-refactor.
- **Serde default for additive schema** — `InfoJson` already uses `Option<...>` for optional fields (e.g. `parent_pid`). New `project_history` uses `#[serde(default)]` on `Vec<String>` for the same forward-compat reason.

### Integration Points
- `src/cli.rs` — clap derive structs for `list` subcommands on both owl and live dispatchers. Add `--all`, `--offline`, `--here` args with `conflicts_with` annotation (D-09).
- `tests/golden_owl.rs`, `tests/golden_live.rs` — golden fixtures will break under new defaults (LIST-08). Regen via `scripts/capture_golden.sh` after code lands; tests asserting offline visibility under default-mode must be updated to pass `--all`.
- `tests/native_owl.rs` — non-golden integration tests for owl subcommands; audit for any list-default assumptions.
- `docs/DEPLOY.ps1` — no direct change required (HINT-05 enforced via cargo test per D-18, not at deploy time).

</code_context>

<specifics>
## Specific Ideas

- **D-02 exact field shape** — `project_history: Vec<String>` (NOT `Option<Vec<String>>`). Default empty vec via `#[serde(default)]`. Element values are repo NAMES like `claude_skill_owl`, `rebno`, `wit-what` — never paths, never URLs.
- **D-03 derivation order** — local basename first (always available via parent-walk), then remote basename (best-effort via `git`/`gh`). De-dupe before write/compare. If remote basename equals local basename (common case), only one entry stored.
- **D-15 exact YAML form** — `argument-hint: "[--all] [--offline] [--here]"` (double-quoted, square brackets, single spaces between groups). Identical string in all three list-* skills.
- **HINT-04 YAML quoting verification** — current `live-stop` and `listen-stop` use `"[<id>] | --all"` (double-quoted because of `|`). Confirm the audit doesn't accidentally unquote these. The Rust regression test should also flag improperly-quoted YAML-significant chars.
- **REQUIREMENTS.md amendment text** — replace LIST-04 with: "`--here` filter excludes perches whose `info.json.project_history` does not contain any of the current repo names (derived from local `.git` basename and remote origin basename). Composes orthogonally with `--all` / `--offline`."
- **ROADMAP.md amendment** — Phase 32 success criterion 2 changes `info.json.cwd` reference to `info.json.project_history`.

</specifics>

<deferred>
## Deferred Ideas

- **Backfill / migration script for legacy perches without `project_history`** — D-08 chose no-migration. If a concrete user complaint surfaces (e.g. a long-lived perch never gets refreshed), add a one-shot `$OWL backfill-history` subcommand in a future phase.
- **`project_history` pruning** — once a perch has been active in 20+ repos, the array could grow. No pruning logic in Phase 32; revisit if real-world data shows array bloat (likely never).
- **Per-repo branch tracking** — `project_history` only stores repo names. Branch-level filtering (`--here --branch main`) would be a Phase 32+ extension. Not in scope.
- **`gh` CLI as second-tier remote-name source** — listed in D-03 but may not be implemented in Phase 32 if `git remote get-url origin` proves reliable. Decide during planning; if deferred, log explicitly.
- **Symmetrize body_addendum across kinds (Phase 31 deferred idea)** — unrelated to Phase 32 scope; carried in 31-CONTEXT.md deferred section. Re-cross-referenced here so it doesn't get lost.
- **`--here` for cross-repo `$LIVE pick-spec`** — Phase 31 D-12 deliberately treats cwd-match as informational, not gating. Once `project_history` exists, pick-spec could gate on repo-history too — that's a Phase 33+ design consideration tied to AUTO/FRESH flows. Not in Phase 32 scope.

</deferred>

---

*Phase: 32-list-overhaul-skill-hint-audit*
*Context gathered: 2026-05-16*
