# Phase 25: Perch Nesting (Psyche + Workers) + Wire psyche-download to Forked-Repo Layout - Context

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

<domain>
## Phase Boundary

Two coordinated restructures, no new commands:

1. **Perch nesting.** `owlery/` flattens-out today: Self, Psyche, and workers all
   live as siblings at `owlery/<id>/`. Phase 25 nests Psyche and workers under
   their parent Self's perch dir under a **single** `nested/` subfolder
   (deviation from ROADMAP, see D-01):
   - `owlery/<self>/nested/<self>-psyche/`
   - `owlery/<self>/nested/<self>-w275/`

   Self perch dir (`owlery/<self>/`) stays flat — it IS the parent.

2. **psyche-download wired to Phase 24 forked-repo layout + cwd-awareness.**
   `$LIVE psyche-download` becomes cwd-aware. Output is a concat of
   `agents/<id>/memformat.xml + agents/<id>/live_context.md +
   projects/<cwd_project>/<agent_id>.md` when cwd resolves to a known project;
   memformat + live_context.md only when it doesn't. The split is real:
   commune/signoff now writes two separate payload slices (D-05/D-06).

Pure-restructure-plus-wire-up phase. No new skill surface. The 8 ROADMAP SCs
shape the work; canonical IDs from ROADMAP: NEST-PSYCHE-PERCH-01,
NEST-WORKER-PERCH-01, DOWNLOAD-CWD-01, COMMUNE-PROJECT-ROUTE-01, MIGRATE-PERCH-01.

</domain>

<decisions>
## Implementation Decisions

### Nesting Topology

- **D-01: Single `nested/` subfolder, not two.** Deviation from the ROADMAP
  draft (`owlery/<self>/psyches/<id>/` + `owlery/<self>/workers/<id>/`). Final
  layout:

  ```
  owlery/<self>/                       (Self perch, flat — IS the parent)
  owlery/<self>/info.json
  owlery/<self>/ready
  owlery/<self>/nested/<self>-psyche/  (Psyche perch)
  owlery/<self>/nested/<self>-w275/    (worker perch)
  ```

  Psyche + workers share the same `nested/` namespace. Kind is disambiguated
  by id suffix (`-psyche` vs `-w{digits}`) — same convention already in use
  pre-Phase 25. Single subfolder simplifies enumeration and cleanup rules.

- **D-02: parent_id is path-derived only.** No `parent_id` field added to
  info.json. For any perch at `owlery/<parent>/nested/<child>/`, parent_id
  equals the grandparent directory name. Filesystem is the single source of
  truth. Self perches have no parent_id (path = `owlery/<self>/`).

- **D-03: `is_worker_perch` + `is_psyche_perch` swap to path-aware.**
  - `is_worker_perch(perch_path)` = `perch_path.parent.file_name() == "nested"`
    AND id matches `*-w{digits}` (id suffix retained as the kind discriminator
    inside `nested/`, since psyche siblings also live there).
  - `is_psyche_perch(perch_path)` = `perch_path.parent.file_name() == "nested"`
    AND id ends with `-psyche`.
  - Drop the standalone id-regex-only worker detection from
    `src/common/owlery.rs:351` once all callers route through the path form.
  - Worker-id naming **stays `{parent}-w{N}`** — back-compat with prior phases,
    and the suffix still functions as a fast kind discriminator inside
    `nested/`.

- **D-04: `enumerate_perches` recurses one extra level.** Walk pattern:
  - Layer 1: `owlery/*/` → Self perches (flat) + any legacy flat psyche /
    worker perches (coexist with nested).
  - Layer 2: `owlery/*/nested/*/` → nested psyche + worker perches.
  - Returned tuples carry `(id, info_json, perch_path)` so callers can route
    on path (D-03) without an extra disk hit. `inject_active_perch_context`
    (`src/owl/resume.rs:140`) extends to the nested layer.

### Lifecycle (D-02 from ROADMAP SC2)

- **D-05: Independent lifecycles. Only worker perches ever get fully
  cleaned.** Self + Psyche perches PERSIST on disk after death — they show as
  OFFLINE in listings. Reasons:
  - Psyche must survive parent death to run post-orphan-detection +
    post-signoff ops.
  - Live agent perches carry the agent's identity / Phase 24.1 tracked info
    pointer — destroying them on death loses history.

  Concretely: stale-perch sweepers and `$OWL stop` cascade rules MUST gate
  full-dir-removal on `is_worker_perch` (D-03), not on "child of `nested/`".
  Non-worker offline perches stay on disk indefinitely; doctor reports them
  as OFFLINE.

- **D-06: Cleanup of nested workers cascades when parent removes itself.**
  When a worker perch is removed (graceful exit), only that worker's
  `owlery/<parent>/nested/<worker>/` is unlinked. When a parent Self is
  fully removed (rare — not a normal lifecycle event per D-05), any nested
  workers under it go with the recursive removal; nested psyche stays
  (it lives on as OFFLINE, see D-05). In practice this means `rm -rf`-style
  parent removal is reserved for explicit user intent and tooling that
  understands D-05's "psyche persists" rule.

### Project Identity (Open Q1 → locked)

- **D-07: cwd_project = `derive_current_repo_names()[0]`.** Direct reuse of
  Phase 24.1 D-09 — folder basename when available, falling back to origin
  basename when the helper returns 2 names. Zero new identity logic. Same
  string used for `last_project_name`, `project_history` dedup key, AND the
  new `projects/<cwd_project>/<agent_id>.md` routing key.

- **D-08: On two-name case (folder ≠ origin), write to first name only.**
  Project payload lands at `projects/<folder_basename>/<agent_id>.md` —
  one file, symmetric with `last_project_name`. `project_history` still
  records BOTH names per Phase 24.1 D-10 (display / lookup metadata), but
  exactly one project worktree gets the commune write. No mirror writes, no
  symlinks.

- **D-09: psyche-download project-section lookup uses strict existence
  check. No fallback.** If `projects/<cwd_project>/<agent_id>.md` does not
  exist, the project section is omitted (ROADMAP SC4/SC5 honored literally).
  This is asymmetric with reads on the two-name case: writes use first name,
  reads check first name only. Folder renames or cross-clone usage forfeit
  the project section until the next commune writes it under the new name.
  Chosen for simplicity; revisit if rename-loss bites in practice.

### Commune / Signoff Two-Slice Split (Open Q3 → locked)

- **D-10: Commune + signoff emit TWO payload slices.** Today the whole
  payload lands at `agents/<id>/live_context.md`. Phase 25 splits it:

  - **`agents/<id>/live_context.md`** — cross-project, role-scoped.
    Contains:
      - Agent's role
      - How that role has evolved
      - Agent's latest choices
      - Agent's interactions with the user
      - Agent-to-agent interactions

  - **`projects/<cwd_project>/<agent_id>.md`** — project-scoped.
    Contains:
      - Work done
      - Current state
      - Outstanding priorities
      - Next task
      - "Everything else usually in communes / context" that is project-
        bound

  When cwd has no resolvable project (D-07 yields empty / outside-repo):
  the project slice is dropped — the whole payload collapses back to the
  agent slice (live_context.md).

- **D-11: Split mechanism = envelope tags from the Psyche-child output.**
  The haiku-child prompt is updated to emit the payload as:

  ```
  <live-context>
    [agent slice — role / evolution / user + agent interactions]
  </live-context>
  <project-context>
    [project slice — work done / current state / priorities / next task]
  </project-context>
  ```

  Composer (`echo_commune.rs`, `signoff.rs::compose_init_signoff_payload`,
  related context.rs write helpers) parses the envelope, extracts each
  slice, routes each to its target file. Free-form prose tolerated inside
  each tag. Robust to LLM heading drift; clean contract; one Psyche
  invocation per cycle (no doubled latency).

  Rejected alternatives: fixed-heading routing (fragile), two separate
  Psyche invocations (latency cost), whole-payload mirror writes
  (contradicts D-10 taxonomy).

- **D-12: Psyche receives current state of BOTH files inline in the
  prompt** so it can merge without dropping prior context. Composer reads
  `agents/<id>/live_context.md` AND
  `projects/<cwd_project>/<agent_id>.md` at fire time and inlines them as
  two clearly labelled blocks in the haiku prompt:

  ```
  CURRENT_LIVE_CONTEXT:
  [file contents verbatim]

  CURRENT_PROJECT_CONTEXT:
  [file contents verbatim]
  ```

  No new tool calls. Cost: prompt token size grows with each file. When
  cwd has no project, only `CURRENT_LIVE_CONTEXT` is inlined.

  Rejected: file-path-plus-Read-tool (adds round trips), pre-summarization
  (loses fidelity), hybrid inline+path (premature optimization).

- **D-13: Project worktrees materialize lazily on first commune that
  resolves a cwd_project.** Reuse Phase 24 D-16 lazy creation:
  `tracked::ensure_project_worktree(name)` on the write path; first hit
  for a given project name calls
  `git -C seed worktree add ../projects/<name> p-<name>`.

### psyche-download Payload Shape (ROADMAP SC4/SC5)

- **D-14: Concat order = `memformat + live_context + project` (when present).**
  - Always emit `<memformat>` if `agents/<id>/memformat.xml` exists
    (Phase 28 D-09 preserved).
  - Append `live_context.md` body (front-matter stripped per
    `src/live/context.rs:506` existing pattern).
  - If cwd resolves to a project AND
    `projects/<cwd_project>/<agent_id>.md` exists, append its body
    after `live_context`.
  - The `<psyche-stamp/>` + `<current/>` drift block stays anchored on
    `live_context.md`'s YAML front-matter (Phase 23 D-08). Project file
    does NOT carry its own stamp — drift fields are cwd-scoped and one
    stamp per write is sufficient. Planner confirms this in Plan-time
    research.
  - SC5 fallback (cwd outside any project): memformat + live_context
    only. Already locked by D-09's no-fallback rule.

- **D-15: SessionStart psyche-context injection (ROADMAP SC8) reuses
  `download_payload()`.** Single source of truth for the payload shape:
  `src/live/context.rs::download_payload()` is the only producer; both the
  CLI (`$LIVE psyche-download`) and the SessionStart hook
  (`download_payload_for_injection`) call it. Phase 25's reshape of
  `download_payload` automatically flows into the SessionStart `<psyche-
  context>` block. Phase 28 carryover is one-line.

### Migration (ROADMAP SC6)

- **D-16: Coexist + targeted psyche-only auto-relocate.** Default posture
  is permanent coexist — `enumerate_perches` walks both flat layer
  (`owlery/*/`) and nested layer (`owlery/*/nested/*/`) forever (D-04).
  Two narrow exceptions:

  - **Psyche relocate on `$LIVE start` / `$LIVE revive` only.** When a
    live agent boots, the start path checks for a legacy flat sibling at
    `owlery/<self>-psyche/`. If present AND the nested target
    `owlery/<self>/nested/<self>-psyche/` is absent, move the dir
    (rename) and rewrite any path-bearing state. Bounded to the agent
    being booted — touches one perch at a time, at a moment when that
    agent's psyche is being (re)started anyway. Cleanest transition
    window.
  - **Workers: no migration, but ACTIVE cleanup sweep (D-20).**
    Worker perches are short-lived. Existing flat workers die
    naturally; new workers spawn directly into the nested layout.
    Zero migration code path — but Phase 25 ALSO lands the orphaned-
    worker cleanup sweep (D-20) that the user has observed leaving
    daily debris.

  No first-boot enumerate-everything sweep. No `$LIVE migrate`
  subcommand. Self perches never move (they were always flat and stay
  flat).

- **D-17: Duplicate resolution = nested wins; flat is stale.** If both
  `owlery/<x>-psyche/` AND `owlery/<x>/nested/<x>-psyche/` exist
  simultaneously (partial-migration / botched relocate / external state
  drift), enumeration picks the nested entry. Doctor surfaces the flat
  sibling as `stale-leftover` with a hint to remove it. Auto-cleanup of
  the flat duplicate fires ONLY if its pid is dead (avoids racing a live
  process during binary handoff per Phase 18.4/18.5).

### Orphaned-Worker Cleanup Sweep (folded into Phase 25)

- **D-20: Active worker-perch cleanup sweep on `$LIVE start` AND every
  signoff event.** User-reported defect: daily orphaned worker perches
  accumulate after subagents conclude — neither parent-death cascade
  (D-06) nor the lazy on-removal path catches them, because the worker
  exits without removing its dir and the parent stays alive.

  Sweep contract:
  - **Triggers:** (a) `$LIVE start` (after Self perch readied,
    BEFORE the new boot writes its first commune); (b) signoff event
    (after `compose_init_signoff_payload` completes, AT or near the
    existing INIT_SIGNOFF write site).
  - **Scope:** sweep only worker perches owned by THIS Self
    (`owlery/<self>/nested/<*>-w{N}/` for the current `<self>`) AND
    legacy flat worker siblings whose id matches `<self>-w{N}`
    (`owlery/<self>-w{N}/`). Do NOT sweep other agents' workers
    (cross-agent reach-in is out of scope; each agent cleans its own).
  - **Removal predicate:** `is_worker_perch(perch) AND
    !is_perch_online(perch)` — i.e. the worker's pid is dead OR the
    `ready` file is missing. Reuse existing `is_perch_online`
    (`src/common/owlery.rs:405`) so the predicate matches what
    listings already classify as offline.
  - **Action:** `fs::remove_dir_all` on the perch dir. Best-effort
    silent-on-error (Phase 32 D-05 posture). On success, emit a
    single aggregated stderr line: `cleaned N orphaned worker
    perches`.
  - **Concurrency:** the sweep MUST NOT touch a perch that another
    process is mid-spawning. The `is_perch_online` check covers this
    — a perch with no `ready` file yet is offline-by-predicate, but
    its spawning parent is racing the create call. Mitigation:
    require BOTH (a) `info.json` exists AND (b) pid is unreachable
    (or info.json missing AND mtime older than a small grace
    window, e.g. 30s, to skip just-spawned dirs). Planner
    finalizes the grace heuristic.
  - **Idempotent.** Repeat invocations are no-ops once orphans are
    cleaned.

  Folds into Phase 25 because the sweep needs nested-aware
  enumeration (D-04) and the path-aware `is_worker_perch` (D-03) to
  classify reliably across coexist layouts.

### Doctor + Listings (ROADMAP SC7)

- **D-21 (carry-over from D-20): doctor surfaces orphan-worker
  count.** When the sweep runs (or any time doctor runs), report the
  count of worker perches that would be cleaned in a one-line
  summary. Helps user confirm the sweep is doing its job.

- **D-18: `$OWL list` / `$LIVE list` render tree shape.** Output reflects
  nesting visually — Self perches at top level, nested children indented
  under their parent. Default verbosity stays terse (per Phase 24.1
  decision); `--verbose` reveals path. Doctor adds:
  - A check that every Psyche perch's parent dir exists (orphan psyche
    sitting under a missing Self → warn).
  - D-17 duplicate detection (flat + nested same-id).
  - Surface OFFLINE Self / Psyche perches per D-05 (don't filter them out).

### Binary Handoff (Phase 18.4/18.5 carry-over)

- **D-19: Handoff perch discovery tolerates nested workers.** Phase 18.4
  perch enumeration (binary self-migrate path) consumes
  `enumerate_perches` updated per D-04 — gets nested coverage for free.
  Wrapper-state.json rehydration paths unchanged (Self perch stays flat;
  parent-pid lookup resolves Self at `owlery/<self>/info.json`). Any
  callers in src/live/wrapper/ that walked `owlery/*/` flat-only need a
  one-line bump to use the shared enumerator.

### Claude's Discretion

- Exact directory-rename mechanism for D-16 psyche relocate
  (`fs::rename` vs robocopy on Windows when locked) — researcher /
  planner choice; existing `tracked::ensure_agent_worktree` precedent
  applies.
- Where the D-16 relocate hook lives inside `src/live/start.rs` /
  `src/live/revive.rs` (one site or two helpers) — planner picks.
- Path string vs typed enum for `is_psyche_perch` / `is_worker_perch`
  signatures (`&Path` vs `&PerchEntry`) — code-organization choice.
- `<psyche-stamp/>` placement on project file (D-14) confirmed by Plan
  research — likely no, but verify against drift-detector behavior.
- Whether D-11 envelope tags are emitted by Psyche as XML or
  `<<<live-context>>>` style sentinels — XML matches existing Phase
  18.8 echo envelope; planner finalizes.
- Doctor warning thresholds (how many OFFLINE perches before
  recommending cleanup) — visual polish.
- Test coverage breakdown — golden tests for new payload shapes will
  need fixture regenerate; planner triangulates parallel-safe coverage.
- Exact composer location for the D-12 inline-current-state injection
  (`echo_commune.rs::compose_haiku_prompt` extension vs a new helper) —
  planner's call.

</decisions>

<canonical_refs>
## Canonical References

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

### Source Surfaces (Touchpoints)
- `src/common/owlery.rs` —
  - `perch_dir(id)` (line 153) currently returns `owlery/<id>/`; Phase 25
    needs a parallel `nested_perch_dir(parent, child_id)` returning
    `owlery/<parent>/nested/<child_id>/`.
  - `is_worker_perch(id)` (line 351) — id-regex form; replace with
    path-aware predicate (D-03).
  - `enumerate_perches` (line 370) — recursion bump (D-04).
  - `is_perch_online` (line 405) — extend to accept nested perches.
  - `derive_current_repo_names()` (line 447) — identity source for
    cwd_project (D-07). Reuse unchanged.
  - `agent_worktree_path` / `project_worktree_path` (lines 105 / 111) —
    Phase 24 worktree resolvers; used by D-08 / D-13 / D-14.
  - `tracked_agent_info_path` (Phase 24.1 D-15) — adjacent resolver for
    the tracked info.json path; not directly touched but adjacent.
- `src/owl/resume.rs:140` — `inject_active_perch_context` walks active
  perches; update enumeration path (D-04).
- `src/owl/resume.rs:178` / `:305` — `is_worker_perch` call sites; swap
  to path form (D-03).
- `src/live/start.rs` — boot path; D-16 psyche relocate fires here.
- `src/live/revive.rs` (if separate) / `start.rs` revive branch — same
  D-16 hook applies.
- `src/live/context.rs` —
  - `download_payload` (line 430) — D-14 / D-15 reshape: append project
    section.
  - `append_pending_sections` (line 589) — currently routes Pending
    Commune / Pending Signoff into `live_context.md`; under D-10 the
    project-scoped Pending sections may need routing to the project
    file (planner confirms; otherwise leave on live_context).
  - `run_save` / `run_amend_signoff` — extend to route the project
    slice via D-13 (lazy project worktree).
- `src/live/echo_commune.rs` — composer for the haiku-child prompt;
  D-11 envelope-tag teaching + D-12 inline-current-state injection
  land here.
- `src/live/signoff.rs` (`compose_init_signoff_payload`) — same
  envelope teaching for signoff payloads.
- `src/common/tracked.rs` — Phase 24 worktree primitives
  (`ensure_seed`, `ensure_agent_worktree`,
  `commit_agent_payload`); add `ensure_project_worktree(name)` +
  `commit_project_payload(name, files, msg)` mirrors for D-13.
- `src/owl/doctor.rs` — Phase 24 D-17 doctor surface; extend with D-18
  + D-17 duplicate detection + OFFLINE rendering + D-21 orphan-worker
  count.
- `src/live/signoff.rs` — sweep call site (D-20). After
  `compose_init_signoff_payload` write completes, invoke the worker-
  cleanup sweep scoped to current `<self>`.
- `src/live/start.rs` — sweep call site (D-20). After Self perch is
  readied, before first commune, invoke the worker-cleanup sweep
  scoped to current `<self>`.
- `src/owl/list.rs` (or equivalent rendering) — tree-shape output
  (D-18).
- `src/live/pick_spec.rs:347` — existing `is_worker_perch` call site
  (cross-repo scan); swap to path form (D-03).
- `src/cli.rs` — psyche-download invocations live here; ensure D-14
  payload flows through cli surface unchanged (single composer).
- `psyche.md` (embedded via `include_str!`) — Psyche prompt teaching for
  D-11 envelope output. Rebuild required after edit per
  CLAUDE.md "psyche.md is embedded into the binary".

### Phase Continuity
- `.planning/phases/24-tracked-dir-forked-repo-layout-agents-projects-branches-sess/24-CONTEXT.md`
  — **MUST READ.** Worktree topology (D-03/D-04/D-13), commit-trailer
  format (D-08), missing-git fallback (D-02), lazy worktree creation
  (D-16). Phase 25's project worktree handling is a direct application
  of Phase 24 D-16.
- `.planning/phases/24.1-tracked-agents-info-json-cross-session-activity-index/24.1-CONTEXT.md`
  — **MUST READ.** `derive_current_repo_names()` reuse for cwd_project
  identity (D-07); `last_project_name` / `project_history` semantics
  (D-09 / D-10); `tracked_agent_info_path` resolver (D-15).
- `.planning/phases/23-commune-signoff-project-root-head-sha-stamping/23-CONTEXT.md`
  — Stamp shape, soft-fail posture, suppression markers. D-14 keeps
  `<psyche-stamp/>` on live_context.md.
- `.planning/phases/32-list-overhaul-skill-hint-audit/32-CONTEXT.md` —
  Phase 32 D-03 derive_current_repo_names ordering; Phase 25 D-07
  inherits the "first wins on two-name" rule.

### Project Context
- `.planning/PROJECT.md` — v1.8 Psyche Restructure milestone.
- `.planning/ROADMAP.md` §Phase 25 — 8 Success Criteria; note the
  layout deviation (D-01 collapses `psyches/` + `workers/` into single
  `nested/`).
- `.planning/seeds/SEED-003-relocate-working-perches-nested-under-parent.md`
  — original promotion source. Mark `status: folded` on this CONTEXT.md
  commit.

### Codebase Maps
- `.planning/codebase/ARCHITECTURE.md`
- `.planning/codebase/CONVENTIONS.md`
- `.planning/codebase/STRUCTURE.md`

### Forward-Compat
- ROADMAP Phase 28 — SessionStart `<psyche-context>` injection
  consumes `download_payload()`; D-15 keeps the producer single-sourced
  so Phase 28 reshape work is one line.
- ROADMAP Phase 35 — gh remote sync. Nested layout flows through
  agent / project worktree branches; no Phase 35 code change needed to
  support nesting.

</canonical_refs>

<code_context>
## Existing Code Insights

### Reusable Assets
- `crate::common::owlery::perch_dir(id)` — Self perch path resolver;
  parallel `nested_perch_dir(parent, child_id)` added in Phase 25.
- `crate::common::owlery::derive_current_repo_names()` — single
  identity source for cwd_project (D-07).
- `crate::common::owlery::enumerate_perches()` — already returns
  `Vec<(id, InfoJson)>`; bump to recurse one level via D-04. Callers
  that classify perches need access to the resolved path — extend
  return shape to `Vec<(id, info, path)>` OR add a sibling
  `enumerate_perches_with_paths()` helper.
- `crate::common::tracked::ensure_agent_worktree` / `commit_agent_payload`
  (Phase 24) — clone the contract for project worktrees (D-13).
- `crate::live::context::download_payload` — single CLI + SessionStart
  producer; D-14/D-15 amend this one function.
- `crate::common::types::InfoJson` — no schema change in Phase 25
  (D-02 path-derived parent_id).

### Established Patterns
- **Pure path composition in `common/owlery.rs`** — all path helpers
  return `PathBuf` without filesystem side effects; lifecycle (mkdir,
  rename) lives in `common/tracked.rs` or call sites. Phase 25's
  `nested_perch_dir` follows the same posture.
- **Best-effort silent-on-error writes** (Phase 32 D-05; Phase 24
  D-02; Phase 24.1 D-12) — D-16 psyche relocate inherits: failed move
  emits a single-line stderr warning, boot continues with the perch
  resolved at its current location.
- **`#[serde(default)]` + `skip_serializing_if`** — no new info.json
  fields in Phase 25 (D-02), so no new defaults needed; preserves
  forward/back compat across coexisting flat + nested perches.
- **Stream / event envelope parsing** (Phase 18.8 message envelopes)
  — D-11 envelope-tag parsing pattern can mirror the existing
  `<EVENT type="..." ...>` parser shape for consistency.

### Integration Points
- **Phase 18.4/18.5 binary handoff** — handoff sweeps existing perches
  to migrate listeners; with D-04 the sweeper covers nested workers
  automatically. Live transition window during handoff is the highest-
  risk moment for D-16 psyche relocate; D-16 fires on `$LIVE start /
  revive` (not first-boot enumeration), narrowing the window.
- **Phase 24 D-13 commit pipeline** — project payload writes
  (D-08/D-13) feed the same `git add` → `git commit` chain inside the
  project worktree. Same D-07 subject format
  (`commune: <self_id> <kind> — <short>`) and D-08 trailer block apply,
  scoped to the project worktree's commit (which omits the redundant
  `Project` trailer per Phase 24 D-08).
- **Phase 24.1 tracked info.json** — `last_project_name` /
  `project_history.branch` already updated by the existing call sites
  (Phase 24.1 D-09 / D-10). Phase 25's project-routing logic does
  not double-update — it lives downstream of the same
  `derive_current_repo_names()` call.

### What Phase 25 Does NOT Touch
- `info.json` schema (D-02 path-derived parent linkage).
- Phase 24 worktree topology / branch naming (`a-` / `p-` prefixes,
  bare `seed/`) — reused unchanged.
- Phase 35 sync conflict policy — explicitly deferred.
- Self perch dir lifecycle / identity — Self stays at flat
  `owlery/<self>/`.

</code_context>

<specifics>
## Specific Ideas

- **Single `nested/` subfolder is the ROADMAP deviation worth
  flagging.** Roadmap text says `psyches/` + `workers/`; D-01 collapses
  both to `nested/`. Planner / executor should not re-litigate.
- **Worker-id naming stays `{parent}-w{N}` even when nested.** The
  prefix becomes path-redundant but back-compat with all prior
  worker-id call sites is preserved. The suffix is the kind
  discriminator inside `nested/`.
- **Self perches NEVER move.** Migration is one-directional and
  bounded: legacy flat psyche → `owlery/<self>/nested/<self>-psyche/`,
  triggered only on `$LIVE start / revive`. Self stays at
  `owlery/<self>/` always.
- **Only worker perches get full removal cleanup.** Self + Psyche
  perches persist post-mortem as OFFLINE — this is a hard rule (D-05).
  All sweepers gate on `is_worker_perch` (D-03), not on "child of
  `nested/`".
- **Two-slice taxonomy is locked.** D-10 enumerates exactly what goes
  to `live_context.md` vs `projects/<X>/<agent>.md`. Planner does not
  re-derive the split; psyche.md prompt edits reflect this taxonomy
  verbatim.
- **`download_payload()` is the SINGLE producer.** CLI + SessionStart
  share it. Phase 25 reshape is one function's signature/body change
  + the project-section append. Phase 28 forward-compat is preserved
  (D-15).
- **D-16 psyche relocate is bounded to one perch per boot.** No
  first-boot enumeration sweep; no migrate subcommand; no worker
  migration. Minimum blast radius.
- **D-20 orphan-worker sweep is the active counterpart to D-05's
  "workers get cleaned" rule.** Lazy on-removal alone leaves daily
  debris in real use; the sweep fires at the two natural lifecycle
  punctuation points (`$LIVE start`, signoff). Self-scoped — each
  agent reaps its own worker corpses.

</specifics>

<deferred>
## Deferred Ideas

- **Truncation cap on project section in psyche-download** — Open Q2
  from ROADMAP. Current decision: stream the project file in full.
  Project files grow with commune cadence and may eventually need a
  size cap or LRU rollover. Revisit only if real agents see prompt
  bloat hurting Psyche latency / cost. Mirrors Phase 24.1 D-11
  unbounded-history posture.
- **Folder-rename graceful read fallback** — D-09 chose strict
  no-fallback. If clone-under-different-folder-name becomes a
  real-world pain point, revisit by adding a tiered lookup
  (project_history scan) on read.
- **Symlink / pointer for two-name case writes** — D-08 chose
  first-name-only. Symlink approach was rejected for Windows
  portability; revisit only if real users complain about discovery
  asymmetry.
- **`<psyche-stamp/>` on project file** — D-14 keeps stamp on
  live_context.md only. If cwd / branch / head-sha needs project-level
  granularity later, planner can add a second stamp block.
- **Hybrid prompt input (inline live + path for project)** — D-12
  picked full inline for both. Revisit if prompt-size cost hurts real
  users.
- **Doctor visual polish** — tree-shape rendering, dim/bold of
  OFFLINE entries, column widths. Planner's call within Phase 25;
  further tuning is future cosmetic work.
- **`$LIVE migrate` opt-in subcommand** — D-16 chose targeted
  in-line relocate. Manual subcommand can be added later if forensic
  / batch relocate ever proves needed.
- **`parent_id` field in info.json** — D-02 chose path-derived. If
  cross-machine relocate ever needs parent linkage to survive moves,
  add field then.
- **Phase 35 sync conflict policy for nested layout** — explicitly
  Phase 35 territory.
- **Phase 28 SessionStart payload deeper integration** — D-15 keeps
  the wiring single-line. Any richer SessionStart treatment of the
  three-section payload is Phase 28's territory.
- **Sessions-log ↔ live_context.md / project file consistency
  checks in doctor** — additive future doctor enhancement (Phase
  24.1 deferred carryover).

</deferred>

---

*Phase: 25-perch-nesting-psyche-workers-wire-psyche-download-to-forked-*
*Context gathered: 2026-05-21*
