# Requirements Archive: v1.7 Seamlessification

**Archived:** 2026-05-16
**Status:** SHIPPED

For current requirements, see `.planning/REQUIREMENTS.md`.

---

# Requirements: Owl Skill

**Defined:** 2026-03-28
**Updated:** 2026-03-29 (v1.1 roadmap created)
**Core Value:** Reliable, zero-dependency agent-to-agent messaging that just works on any machine with bash and coreutils.

## v1.0 Requirements (Complete)

### Hardening

- [x] **HARD-01**: Message writes are atomic (write to tmp file, then mv to inbox) — no partial reads
- [x] **HARD-02**: Message filenames use collision-resistant IDs (not just `$RANDOM`)
- [x] **HARD-03**: Poll loop handles TOCTOU race — file may vanish between `ls` and `cat`

### Output Formatting

- [x] **FMT-01**: All `/owl` operations produce ANSI-colored, compact symbol output (no emoji)
- [x] **FMT-02**: All `/live` operations produce ANSI-colored output visually distinct from `/owl`
- [x] **FMT-03**: Output is consistent across all subcommands (status, errors, confirmations)

### Auto-Setup

- [x] **SETUP-01**: `/owl` auto-adds `$OWL` env var to `~/.claude/settings.json` if missing, notifying user before making changes
- [x] **SETUP-02**: `/owl` and `/live` auto-add `$LIVE` env var to `~/.claude/settings.json` if missing, notifying user before making changes
- [x] **SETUP-03**: `/owl` and `/live` auto-add a SessionEnd hook (`prompt_input_exit`) that cleans up all background tasks belonging to the session, notifying user before making changes

### SKILL.md Quality

- [x] **SKILL-01**: SKILL.md instructions cover all new `/live` subcommands with the same depth as `/owl`
- [x] **SKILL-02**: SKILL.md documents the auto-setup behavior (env vars, hooks) and when agents should expect it
- [x] **SKILL-03**: SKILL.md clarifies edge cases and gaps identified during implementation

### Live Agent Core

- [x] **LIVE-01**: `/live [id]` starts an owl listener with `--self` flag and spawns a Psyche subagent
- [x] **LIVE-02**: Self listener is discoverable via both `/owl list` and `/live list` (marked `"live":true` in info.json)
- [x] **LIVE-03**: Psyche registers as `{id}-psyche` with `--psyche` flag, hidden from `/owl list`
- [x] **LIVE-04**: Psyche runs a periodic pulse loop (~20min default) using self-rearming one-shot background tasks
- [x] **LIVE-05**: Self sends communal updates to Psyche using `COMMUNE ({timestamp}): {message}` format
- [x] **LIVE-06**: When a pulse timer fires, Psyche uses accumulated COMMUNE context to judge whether Self should be doing something and notifies Self if so
- [x] **LIVE-07**: Psyche sends contextual nudges using `PULSE ({timestamp}): {reminders}` format
- [x] **LIVE-08**: `/live list` shows all live agents (Self entries with `"live":true`)
- [x] **LIVE-09**: Graceful stop: when Self stops, Psyche is also torn down (no orphaned Psyches)
- [x] **LIVE-10**: All existing `/owl` commands continue working unchanged (backward compat)
- [x] **LIVE-11**: Configurable pulse period via `--period` flag (minimum 1 minute)

### Live Skill Extraction (INSERTED -- Phase 02.1)

- [x] **EXTRACT-01**: LIVE-SKILL.md exists as a standalone Claude Code skill file with `name: live` frontmatter and its own `description` field
- [x] **EXTRACT-02**: SKILL.md contains only `/owl` commands -- all `/live` documentation removed
- [x] **EXTRACT-03**: Both skill files cross-reference each other (owl notes /live exists as separate skill, live notes /owl for messaging primitives)
- [x] **EXTRACT-04**: DEPLOY.md includes LIVE-SKILL.md in install, bundle, and commit commands

### Owl & Live Hardening (INSERTED -- Phase 02.2)

- [x] **HARDEN-01**: GC skips perches with `"pid":"BUSY"` in info.json -- no false-positive stale cleanup during Psyche re-poll gap
- [x] **HARDEN-02**: Poll processes trap TERM/USR1 for graceful exit (removes ready file, prints status) and USR2 for live status query
- [x] **HARDEN-03**: `owl.sh stop` and `live.sh stop` send `kill -USR1` for graceful shutdown before force-killing
- [x] **HARDEN-04**: `/owl gsd-setup` command configures owl/live env vars and hooks for GSD-managed projects
- [x] **HARDEN-05**: SKILL.md instructs listeners to assign IDs and provide skills/tools when spawning subagents
- [x] **HARDEN-06**: SKILL.md instructs listeners to check completed background tasks before processing new messages
- [x] **HARDEN-07**: Psyche context persisted to `~/.claude/psyche-contexts/{self_id}.md` via `$LIVE context-save` command; recoverable via `$LIVE psyche-download`
- [x] **HARDEN-08**: SessionStart hook outputs `OWL_RESUME` context for dead-but-not-cleaned listeners so Claude auto-resumes
- [x] **HARDEN-09**: `/owl reboot` tears down and re-registers a listener in one command; `/live revive` tears down and re-spawns Self+Psyche
- [x] **HARDEN-10**: `/owl stash` creates a persistent background task with `[BACKUP_PAYLOAD]` and writes a `.stash-{id}.payload` file for cross-context continuity

## v1.1 Requirements (Native Runtime)

### Rust Foundation

- [x] **RUST-01**: Single Rust binary (`owl.exe` / `owl`) replaces both `owl.sh` and `live.sh` — all subcommands available via `owl <cmd>` and `owl live <cmd>`
- [ ] **RUST-02**: CLI argument parsing via clap matches all existing `$OWL` and `$LIVE` subcommand signatures exactly — same positional args, same flags, same stdin piping
- [x] **RUST-03**: Cross-platform builds produce native binaries for Windows (x86_64-pc-windows-msvc), Linux (x86_64-unknown-linux-gnu), and macOS (x86_64-apple-darwin + aarch64-apple-darwin)
- [x] **RUST-04**: `$OWL` and `$LIVE` env vars point to the native binary — `$OWL` invokes owl subcommands, `$LIVE` invokes live subcommands (e.g., `owl live start`)

### Output Compatibility

- [x] **COMPAT-01**: Golden test suite captures exact byte-for-byte stdout/stderr output from every bash subcommand — native binary must match
- [x] **COMPAT-02**: ANSI color codes (cyan `\e[36m` for owl, orange `\e[38;5;208m` for live, red `\e[31m` for errors) are identical between bash and native
- [x] **COMPAT-03**: TAG:value output tokens (READY, SENT, REPLIED, STOPPED, CLEANED, ACTIVE, NO_PERCH, STALE) maintain exact format
- [x] **COMPAT-04**: Stdout/stderr split preserved — status to stderr, message content to stdout
- [x] **COMPAT-05**: Exit codes match bash behavior (0 success, 1 error)
- [x] **COMPAT-06**: Line endings are LF (not CRLF) on all platforms — agents parse in bash which expects LF

### P2P Messaging Architecture

- [x] **P2P-01**: Each `$OWL poll` starts a lightweight local server (localhost TCP or Unix domain socket) that accepts incoming message deliveries
- [x] **P2P-02**: Agent addresses are registered in a shared registry at `~/.claude/owlery/.registry` (SQLite or equivalent)
- [x] **P2P-03**: `$OWL deliver` looks up the target's address in the registry and connects directly to deliver the message — no intermediate process
- [x] **P2P-04**: If the target is offline, the message is written to the target's SQLite spool at `~/.claude/owlery/{id}/spool.db`
- [x] **P2P-05**: When an agent re-polls, it drains any pending messages from its spool before accepting live connections
- [x] **P2P-06**: Spooled messages have a configurable TTL (default 30 minutes) — expired messages are purged on next drain
- [x] **P2P-07**: The blocking poll contract is preserved — `$OWL poll` blocks until exactly one message arrives, prints it, and exits
- [x] **P2P-08**: Message delivery is sub-second when the target is online (direct socket connection, no 1-second sleep polling)

### Owl Subcommand Parity

- [x] **OWL-01**: `owl setup <id>` creates perch directory structure (inbox, ready, info.json)
- [x] **OWL-02**: `owl poll <id> <mode>` blocks on local server + spool drain, supports `--setup`, `--live`, `--psyche`, `--pulse-interval` flags
- [x] **OWL-03**: `owl deliver <target> <from>` sends message via direct connection or spool fallback
- [x] **OWL-04**: `owl reply <target> <my_id>` sends reply via same mechanism as deliver
- [x] **OWL-05**: `owl send <target> <from>` delivers message and blocks for reply (ephemeral perch)
- [x] **OWL-06**: `owl list` shows active perches with pending message counts, cleans stale entries
- [x] **OWL-07**: `owl stop <id>` and `owl stop --all` gracefully shut down local servers and clean perches
- [x] **OWL-08**: `owl cleanup-session <session_id>` removes all perches matching the session
- [x] **OWL-09**: `owl reboot <id>` tears down and re-registers a listener, outputting REBOOT_POLL_CMD
- [x] **OWL-10**: `owl stash <id>` creates persistent payload file and background process for cross-context continuity
- [x] **OWL-11**: `owl session-resume` outputs OWL_RESUME context for dead listeners (SessionStart hook)
- [x] **OWL-12**: `owl gsd-setup` configures GSD agent_skills

### Live Subcommand Parity

- [x] **LIVE-12**: `owl live start <id>` launches external Psyche process (claude CLI), registers Self perch, outputs POLL_CMD
- [x] **LIVE-13**: `owl live stop <id>` and `owl live stop --all` kill Psyche wrapper + clean perches + stop Self
- [x] **LIVE-14**: `owl live revive <id>` stops and restarts with new generation
- [ ] **LIVE-15**: `owl live commune <id> <msg>` formats and delivers COMMUNE to Psyche
- [ ] **LIVE-16**: `owl live list` shows live agents; `owl live list-psyches` shows Psyche agents
- [ ] **LIVE-17**: `owl live context-save/psyche-download/clear-psyche` manage persistent Psyche context files
- [ ] **LIVE-18**: `owl live pulse-wait <seconds>` sleeps then outputs PULSE_TRIGGER
- [x] **LIVE-19**: Generation tracking via counter file, session naming as `{id}-psyche-{gen}-{HH}-{MM}`
- [x] **LIVE-20**: Psyche wrapper injects current system timestamp into each `claude -p` invocation context, so Psyche can reason about past/future relative to now

### Lifecycle & Process Management

- [x] **PROC-01**: Graceful shutdown via platform-appropriate mechanism (SIGTERM on Unix, Ctrl-C/poison file on Windows)
- [x] **PROC-02**: BUSY state written to info.json during message processing — GC skips BUSY perches
- [x] **PROC-03**: Duplicate listener guard — reject poll if an active server already exists for the same ID
- [x] **PROC-04**: Filesystem metadata (info.json, ready files, stash payloads, psyche-contexts, generation counters) maintained on disk for external tool compatibility
- [x] **PROC-05**: Auto-setup of `~/.claude/settings.json` with OWL/LIVE env vars and hooks on first run

### Migration & Distribution

- [x] **DIST-01**: Native binary is a drop-in replacement — update `$OWL`/`$LIVE` env vars to point to the binary, everything works
- [x] **DIST-02**: Bash scripts retained as fallback — users can switch back by re-pointing env vars
- [x] **DIST-03**: Installation is copy-one-file — no package manager, no installer, no runtime dependencies
- [x] **DIST-04**: SKILL.md and LIVE-SKILL.md require zero or minimal changes (only env var path examples)

### Timed Pulses (carried from v1.0)

- [x] **TPULSE-01**: Self can request a one-shot timed pulse via `PULSE REQUEST ({timestamp}): {target_timestamp} -- {message}`
- [x] **TPULSE-02**: Psyche spawns a one-time background sleep task that fires at the target timestamp
- [x] **TPULSE-03**: `/live timed-pulse {target time} -- {message}` user command formats and sends the request

### Spine Supervisor (carried from v1.0)

- [x] **SPINE-01**: `/live boot-spine [id]` starts a Spine agent with hidden listener
- [x] **SPINE-02**: Spine spawns a Touch subagent with hidden listener (`{spine_id}-touch`)
- [x] **SPINE-03**: Touch runs a ~5min PID health check loop, reading Psyche info.json files
- [x] **SPINE-04**: Touch reports missing Psyche processes to Spine
- [x] **SPINE-05**: Spine notifies the affected Self when its Psyche is detected dead
- [x] **SPINE-06**: Spine cleans up perches when both Self and Psyche are gone
- [x] **SPINE-07**: `/live list-psyches` shows all Psyches (restricted to user, Self, Touch)
- [x] **SPINE-08**: Spine and Touch are hidden from `/owl list`, `/live list`, and `/live list-psyches`
- [x] **SPINE-09**: If subagent nesting is blocked, Spine absorbs Touch functionality (graceful degradation)

## v1.7 Seamlessification Requirements

### Live Pick (Phase 26)

- [x] **LIVE-PICK-01**: `/spt:live` with no agent_id and exactly 1 offline agent in this repo's history auto-launches that agent and reports the pick to the user. (D1, D2, D3 `kind: "auto"`)
- [x] **LIVE-PICK-02**: `/spt:live` with no agent_id and 0 or 2+ offline agents in this repo's history fires `AskUserQuestion` with: top-3 most-recently-active agents (or curated starter role names if 0) as discrete options, full agent list (or full starter pool) in the body addendum, and a free-text "Other" option. (D3 `kind: "pick" | "prompt-new"`, D4, D10)
- [x] **LIVE-PICK-03**: "Repo history" is defined as project-local `.claude/LIVE_AGENT_IDS.json` schema v2 entries; "most-recently-active" is sorted by the per-id `last_active` ISO-8601 UTC timestamp; bumps fire on five events: live-start, revive, SessionStart re-attach (live perches only), commune, echo-commune. Helper `$LIVE pick-spec` produces the AskUserQuestion-ready spec (JSON on stdout, unconditional). (D1, D2, D3)
- [x] **LIVE-PICK-04**: Free-text user input is resolved via `$LIVE pick-spec --resolve <name>` against owlery cross-repo state (`InfoJson.cwd`). The four collision sub-cases (D6/D7/D8/D9) are handled in skill-side `AskUserQuestion` flow per the dispatch matrix in `plugin/spt/skills/live/SKILL.md`. New primitive `$LIVE fork <src> <new-id>` supports Case 3 (already-live-here-fork). All free-text input is validated via `id_validate::validate_agent_id` before any filesystem operation. (D5, D6, D7, D8, D9, D11)

### Listener Poll Monitor Tool Transition (Phase 27)

- [x] **POLL-MON-01** — Listener poll invocation uses the `Monitor` tool, not the `Bash` tool, on the primary path; live agents and non-live perch listeners both migrate together. Migration scope covers `listen`, `live`, `revive`, and `reboot` skills (D5). Stream-default semantics apply, with the `--once` flag reserved for the Bash fallback path (D1). (Phase 27)
- [x] **POLL-MON-02** — Status tags (READY/SENT/STOPPED/CLEANED) remain on stderr, and message delivery semantics (TCP-primary + SQLite spool fallback + PreToolUse hook injection) are preserved unchanged across the migration. The single-line `<EVENT>` envelope (D2) carries `msg` events (D2.a) and `alarm` events (D2.b) on stdout, while status routing to stderr (D3) is unaffected. (Phase 27)
- [x] **POLL-MON-03** — Stream-mode performance is equal-or-better latency vs the Bash one-shot path (no per-message process respawn, no Bash-tool prompt prefix overhead), AND a Bash + `$OWL poll --once` fallback path is documented inline in each migrated SKILL.md for Claude Code versions without the Monitor tool. Fallback documentation lives per-skill rather than in a central reference (D6); the `--once` flag (D1) is the primitive that fallback paths invoke. (Phase 27)

### SessionStart Psyche-Download Injection (Phase 28)

- [x] **SS-PSYDL-01** — SessionStart on a perch where `info.state == Live` injects a `<psyche-context id="...">` block containing memformat + accumulated context records (Pulse Log section stripped per D3). Injection fires on BOTH SessionStart paths per D1: fresh-session (raw stdout) AND clear/compact (`hookSpecificOutput.additionalContext` JSON). (Phase 28)
- [x] **SS-PSYDL-02** — Non-live perches (listen-only, psyche, spine, touch, worker) skip `<psyche-context>` emission entirely. NO-CONTEXT cases (no memformat AND no context.md) also skip — never emit an empty block. Existing `<spacetime-reorientation>` block remains untouched per success criterion #3. (Phase 28)
- [x] **SS-PSYDL-03** — Phase 25 forward-compat: payload composition lives in a single `live::context::download_payload(self_id) -> Option<String>` helper consumed by BOTH the CLI `$LIVE psyche-download` and the SessionStart injection wrapper. Pulse Log stripping (D3) lives in a separate injection-only wrapper `download_payload_for_injection`. CLI behavior unchanged (full Pulse Log retained on interactive psyche-download). (Phase 28)

### Auto-Fire Echo-Commune (Phase 29)

- [x] **AUTO-EC-01** — SessionStart auto-fires `_echo-commune` against the prior session UUID on `/clear` or `/compact` boundaries (gate: `stdin.source ∈ {clear, compact}` AND resolved perch `info.state == Live`). Prior session UUID snapshot taken in `plugin_session_start.rs::run()` BEFORE `refresh_info_json_session_id` overwrites it. Fresh-session SessionStart path does NOT fire. Dispatch via typed control message `FIRE_ECHO_COMMUNE_NOW prior_session={uuid} forward_to_self=true source={clear|compact}` delivered to `{self_id}-psyche`; wrapper inner-poll handler bypasses cadence gate when servicing this message. (Phase 29)
- [x] **AUTO-EC-02** — Psyche wrapper orphan path (in `src/live/wrapper/orphan.rs`) fires `_echo-commune --force` against Self's last session UUID synchronously before `INIT_SIGNOFF`, blocking until subprocess completion (no timeout cap — fidelity > teardown latency). Missing/empty UUID: skip echo-commune, proceed straight to INIT_SIGNOFF. (Phase 29)
- [x] **AUTO-EC-03** — Wrapper-owned spawn (no new spawn site outside the wrapper for SessionStart-triggered fire) + envelope cutover. Legacy `ECHO_COMMUNE ({ts}) from {agent}: {msg}` prose envelope replaced by typed `<EVENT type="echo_commune" from="{agent}" timestamp="{iso8601}" note="...">{body}</EVENT>` across ALL emit + parse sites in `src/`, `plugin/spt/skills/`, `plugin/spt/hooks/`, `CLAUDE.md`, `psyche.md`, `docs/`. `_echo-commune --force` flag bypasses 15-min cadence window AND `.more-done` Stop-sentinel; preserves `OWL_ECHO_COMMUNE` recursion guard. Parser predicates case-insensitive on `type="echo_commune"`. (Phase 29)

### Commune/Signoff File-Drop Flow (Phase 30)

- [x] **SC-01** — `/spt:commune` skill writes `.claude/{agent_id}-commune.md` instead of piping body via stdin. (Phase 30)
- [x] **SC-02** — `/spt:signoff` skill writes `.claude/{agent_id}-signoff.md` instead of piping body via stdin. (Phase 30)
- [x] **SC-03** — Self listener poll watches for `.claude/{id}-{commune,signoff}.md` files per iteration; on detection, emits `file_drop` EVENT envelope with file's absolute path. (Phase 30)
- [x] **SC-04** — Psyche wrapper forwards file content into a new Psyche session prompt; deletes file after that session completes (atomic write-then-delete; retain-on-error if session non-zero). (Phase 30)
- [x] **SC-05** — Signoff file detection terminates the listener after notification (`FileDropOutcome::BreakLoop`) with confirmation message in termination output; exit code 0 so Claude Code doesn't show "failed". (Phase 30)
- [x] **SC-06** — `$LIVE psyche-download` appends content of any pending `-commune.md` / `-signoff.md` file for the current agent to the end of its output, via `append_pending_sections` helper called from `download_payload`. Destructive consume (quick-260515-uf1): on-disk append to `{psyche_dir}/{self_id}.md` SUCCEEDS first, then unlink drop file (retry-safe). (Phase 30)

## v2 Requirements (Future)

### Network Messaging

- **NET-01**: P2P architecture extended to support remote agents over TLS
- **NET-02**: Agent discovery via mDNS or registry service
- **NET-03**: Message authentication and encryption for cross-network delivery

### Native Binary Enhancements

- **BIN-01**: Health monitoring endpoint with agent status, pending messages, uptime
- **BIN-02**: Structured message framing (length-prefixed binary) for efficiency
- **BIN-03**: Binary auto-update mechanism

## Out of Scope

| Feature | Reason |
|---------|--------|
| Persistent message queues / history | Messages are ephemeral — SQLite spool is for temporary offline delivery only, not replay |
| Pub/sub or topic-based routing | Point-to-point only — broadcast via iterating list if needed |
| At-least-once / exactly-once delivery | At-most-once is sufficient — agent-level retry if needed |
| Backpressure / rate limiting | Message volume is tiny — over-engineering |
| TLS / auth for local IPC | Same-machine, same-user — OS permissions suffice |
| Web dashboard / GUI | Terminal is the interface — zero-dependency spirit |
| Plugin / extension system | Composition over extension — users write wrapper scripts |
| Central daemon / message broker | P2P architecture chosen for future networking extensibility |

## Traceability

| Requirement | Phase | Status |
|-------------|-------|--------|
| HARD-01..03 | Phase 1 (v1.0) | Complete |
| FMT-01..03 | Phase 1 (v1.0) | Complete |
| SETUP-01..03 | Phase 1 (v1.0) | Complete |
| LIVE-01..11 | Phase 2 (v1.0) | Complete |
| SKILL-01..03 | Phase 2 (v1.0) | Complete |
| EXTRACT-01..04 | Phase 2.1 (v1.0) | Complete |
| HARDEN-01..10 | Phase 2.2 (v1.0) | Complete |
| COMPAT-01..06 | Phase 5 (v1.1) | Pending |
| RUST-02, RUST-03 | Phase 5 (v1.1) | Pending |
| RUST-01, RUST-04 | Phase 6 (v1.1) | Pending |
| P2P-01..08 | Phase 6 (v1.1) | Pending |
| OWL-01..12 | Phase 6 (v1.1) | Pending |
| PROC-01..05 | Phase 6 (v1.1) | Pending |
| LIVE-12..19 | Phase 7 (v1.1) | Pending |
| DIST-01..04 | Phase 7 (v1.1) | Pending |
| TPULSE-01..03 | Phase 8 (v1.1) | Pending |
| SPINE-01..09 | Phase 9 (v1.1) | Pending |
| LIVE-PICK-01..04 | Phase 26 (v1.7) | Complete (2026-05-11; UAT PASS post 26-06 gap closure) |
| POLL-MON-01..03 | Phase 27 (v1.7) | Complete (v1.9.11 shipped 2026-05-11; live-exercised across v1.9.11..v1.10.10) |
| SS-PSYDL-01..03 | Phase 28 (v1.7) | Complete (2026-05-13; 2 raw-stdout Human-UAT tests deferred — non-blocking) |
| AUTO-EC-01..03 | Phase 29 (v1.7) | Complete (2026-05-14; envelope cutover audit clean) |
| SC-01..06 | Phase 30 (v1.7) | Complete (2026-05-15; live-fire UAT against doyle perch) |

**Coverage:**
- v1.0 requirements: 37 complete
- v1.1 requirements: 59 pending (all mapped to Phases 5-9; v1.1 milestone shipped pre-traceability-table-update)
- v1.7 Phase 26 requirements: 4 complete (LIVE-PICK-01..04)
- v1.7 Phase 27 requirements: 3 complete (POLL-MON-01..03)
- v1.7 Phase 28 requirements: 3 complete (SS-PSYDL-01..03; 2 raw-stdout Human-UAT tests deferred)
- v1.7 Phase 29 requirements: 3 complete (AUTO-EC-01..03)
- v1.7 Phase 30 requirements: 6 complete (SC-01..06)
- Total: 115 (v1.0 + v1.1 + v1.7)

---
*Requirements defined: 2026-03-28*
*Last updated: 2026-05-16 (v1.7 milestone audit close — added AUTO-EC + SC entries, marked all v1.7 reqs complete)*
