# Phase 35: Psyche Sync — Cross-Machine Context Backup via Private gh Repo - Context

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

<domain>
## Phase Boundary

Wire Phase 24's `psyches/tracked/seed/` (currently a local-only bare repo) to a
private GitHub remote (`{user}/spt-agent-storage`) so that every commune /
signoff commit on the active agent + active project branches replicates across
machines.

Two trigger points:

1. **Pull** fires on `UserPromptSubmit` (fire-and-forget async) — remote-machine
   updates land before the next local turn.
2. **Pull-then-push** fires after every commune / signoff commit (the local
   commit is pushed against a freshly-pulled remote).

Two entry points to enable sync:

1. **Auto path** — every `$LIVE start` boot with `gh` CLI present checks
   settings.json state; if sync is `unset` or `remind-later` cooldown is up,
   fires `AskUserQuestion` (Yes / No-never / Remind-later-12h).
2. **Manual path** — `/psyche-sync-setup` skill drives the same accept-flow
   (with prereq-install handling if `gh` or `git` are missing).

Either entry point runs the same end-to-end accept flow: create
`spt-agent-storage` via `gh repo create --private` (or fallback to a
browser-opened creation URL when scope insufficient), wire `git remote add
origin` into every existing worktree, `git push --all` to seed, then flip
`sync.state = enabled`. Future Phase 24 D-16 lazy-created worktrees inherit
the remote automatically.

Runtime sync uses plain `git push` / `git pull`. `gh` is **setup-only** —
authentication for runtime sync rides on `gh`'s credential helper (HTTPS) or
the user's SSH keys (set via `gh repo create --remote ...`).

Pure additive phase. Phase 24's `seed/` topology, branch naming (`a-{id}` /
`p-{name}`), and commit-trailer format are unchanged. Phase 35 adds: one
remote, two trigger hooks, one settings.json namespace, two doctor surfaces,
and one new skill.

</domain>

<decisions>
## Implementation Decisions

### Conflict Resolution Policy

- **D-01: Pull strategy = rebase + file-level last-write-wins.** Every pull
  uses `git pull --rebase`. On any file conflict during rebase, the resolution
  is `-X theirs` (where "theirs" during a rebase = the side being replayed, i.e.
  local commits). Because payload files (`live_context.md`, `memformat.xml`,
  `projects/<name>/<id>.md`) are full-rewrites per commune/signoff cycle, the
  semantic effect is "newest commit's content wins" — matches user intent
  (most-recent commune is the canonical state).

- **D-02 (revised 2026-05-22): `sessions.log` IS synced along with everything else.**
  The original D-02 proposed gitignoring `sessions.log`, but that premise
  was incompatible with shipped Phase 24 behavior — `commit_agent_payload`
  at `src/common/tracked.rs:1262` explicitly stages `sessions.log` via the
  D-12 seal pipeline, and explicit-path `git add` does not honor
  gitignore. Rather than rework the seal mechanism in Phase 35, accept
  that `sessions.log` syncs across machines. Conflict resolution rides on
  D-01 (`-X theirs` last-write-wins per file). Acceptable consequences:
  - Each machine sees other machines' boot/pulse/commune/signoff rows in
    its local `sessions.log` history (via git log).
  - Rare same-second commits on two machines may produce duplicate-UUID
    rows after rebase; Phase 24 D-18 dedup-on-update mostly prevents this
    but does not guarantee absence.
  - In single-user SPT ecosystems (the entire deployment surface),
    cross-machine forensic visibility is a feature, not a defect.
  Deferred idea (renamed from former D-02 mechanism): if multi-user or
  custom-merge-driver semantics are ever needed, see Deferred Ideas.

- **D-03: Broken rebase state auto-recovers.** Every sync cycle starts with
  a defensive `git rebase --abort` (silently swallows the
  "no rebase in progress" exit). If working tree is dirty after abort,
  `git stash --include-untracked` saves outstanding writes; next commit
  cycle's payload write re-stages them naturally. Idempotent — retries are
  safe. Doctor surfaces a `recovered-N-aborts` counter so persistent
  breakage is visible without nagging the user.

### Sync Trigger Timing

- **D-04: Two trigger points, asymmetric work.**
  - **UserPromptSubmit** (handler in `src/owl/hook_prompt.rs`):
    fire-and-forget async `git pull --rebase` on `a-{self_id}` and (if
    `cwd_project` resolves) `p-{cwd_project}`. Detached subprocess; hook
    returns immediately. Pull result lands by next turn at latest.
  - **Post-commune/signoff commit** (call site inside
    `src/common/tracked.rs::commit_agent_payload` /
    `commit_project_payload`): synchronous `git pull --rebase` (defensive
    fresh-state guarantee) + `git push origin {branch}`. Blocks commune
    completion only by the push duration, not the pull (which was already
    pre-warmed by the prompt hook).

- **D-05: No client-side throttling on UserPromptSubmit.** Fire every
  prompt. Async + detached means prompt latency is unaffected.
  Self-coalescing happens naturally — if the previous async pull is still
  running when the next prompt fires, the new one races but each branch
  pull is idempotent. (Phase 18.4 binary-handoff machinery has the same
  posture for similar reasons.)

- **D-06: Sync scope = active agent + active project only.** Per cycle:
  - Always sync `a-{self_id}` (the wrapper's own agent).
  - Sync `p-{cwd_project}` IFF `derive_current_repo_names()` resolves a
    project (Phase 25 D-07 reuse).
  - Other agents' branches and other projects sync lazily — only when
    THAT agent boots or THAT project becomes the cwd. Aligns with Phase
    24 D-16 lazy worktree creation.
  - No `git push --all` on the hot path (one initial `--all` push during
    setup is the only exception; see D-12).

- **D-07: 30s subprocess timeout on gh/git sync ops.** Generous for slow
  networks, mobile tethers, corporate VPNs. On timeout, kill child,
  increment failure counter (D-19 backoff), doctor reports last-timeout
  ts + count. Phase 24 D-01's 500ms standard timeout DOES NOT apply to
  sync ops — those carry an extended-budget variant of
  `run_git_checked`.

### Setup UX

- **D-08: Auto-detect on every `$LIVE start` (gated by state).** Boot path
  in `src/live/start.rs` (and revive) checks:
  1. `gh --version` exit 0 (CLI installed).
  2. `settings.json` → `sync.state` is `unset` OR (`remind-later` AND
     `now() >= remind_after_ts`).
  3. If both true: queue an `AskUserQuestion` injection for the next
     SessionStart hook (Phase 28 D-15 reuse — `download_payload_for_injection`
     pattern for additionalContext).
  - States `enabled` and `declined` short-circuit the check — no prompt
    ever fires once user has answered definitively.

- **D-09: AskUserQuestion options = Yes / No (never) / Remind later (12h).**
  - **Yes** → run the accept flow (D-10).
  - **No** → set `sync.state = declined`. Never re-prompt unless user
    manually runs `/psyche-sync-setup`.
  - **Remind later** → set `sync.state = remind-later`,
    `last_prompted_ts = now()`, `remind_after_ts = now() + 12h`. Next
    `$LIVE start` after `remind_after_ts` re-asks.

- **D-10: Accept flow (run from either auto or manual entry, single
  implementation):**
  1. `gh repo create {user}/spt-agent-storage --private --description
     "SPT agent context backup — cross-machine sync"`.
     If `gh` returns scope-insufficient (missing `repo` write scope),
     fall back to opening
     `https://github.com/new?name=spt-agent-storage&visibility=private`
     in the user's browser + an `AskUserQuestion` "tell me when the repo
     is created" continuation gate.
  2. For every existing worktree under `seed/`:
     `git -C {worktree} remote add origin {ssh_or_https_url}` (gh picks
     the protocol via `gh auth setup-git`).
  3. `git -C seed push --all origin` — single push seeds every existing
     branch on the remote.
  4. Persist `sync.state = enabled`, `sync.remote_url = {url}`,
     `sync.acked_ts = now()` to `$SPT_HOME/settings.json`.
  5. Future Phase 24 D-16 lazy-created worktrees automatically inherit
     `remote add origin` (the helper `ensure_agent_worktree` /
     `ensure_project_worktree` gains a one-line "if sync enabled, add
     remote" extension).

- **D-11: Settings.json schema — nested `sync` namespace, enum state.**
  ```json
  {
    "sync": {
      "state": "unset|enabled|declined|remind-later|failing",
      "remote_url": "git@github.com:user/spt-agent-storage.git",
      "last_prompted_ts": "2026-05-22T09:00:00Z",
      "remind_after_ts": "2026-05-23T09:00:00Z",
      "acked_ts": "2026-05-22T09:05:00Z",
      "consecutive_failures": 0,
      "last_failure_ts": null,
      "last_failure_reason": null,
      "next_retry_after_ts": null
    }
  }
  ```
  - `failing` is the auto-disable state (D-19).
  - Cooldown for `remind-later` = 12h (locked).
  - All timestamps ISO-8601 UTC.
  - Fields `consecutive_failures` / `last_failure_*` / `next_retry_after_ts`
    drive the exponential backoff (D-19).

- **D-12: Initial seeding pushes `--all` once during accept flow.** This
  is the ONLY use of `--all`. After setup, runtime sync per D-06 is
  per-branch. Rationale: first-time setup needs to seed the remote with
  every existing worktree's history in one shot; ongoing sync only cares
  about active branches.

- **D-13: `/psyche-sync-setup` is the unified front door.** The skill is
  the canonical entry for the accept flow. Auto-detect path on `$LIVE
  start` invokes the same code with a different `AskUserQuestion`
  framing. Skill responsibilities:
  1. Check `gh --version` and `git --version`.
  2. If either missing: `AskUserQuestion` →
     `agent handles it` (run bash/powershell installer — winget on
     Windows, brew/apt on Unix) / `show download links` (print URLs,
     wait for user to confirm) / `cancel`.
  3. Check `gh auth status`; if not logged in, run `gh auth login`
     (interactive — user follows prompts).
  4. Run D-10 accept flow.
  5. Idempotent: if `sync.state == enabled` already, surface
     `already configured — last sync OK at <ts>` instead of running
     setup again.

### Failure Visibility & Recovery

- **D-14: Hot-path silent; doctor + stderr trace are the only surfaces.**
  Matches Phase 24 D-02 soft-fail posture. Hot-path failures (pull,
  push, timeout) DO NOT emit stderr by default — `SPT_TRACE=1` env var
  gates a per-event trace line (Phase 18.7.1 D-04 pattern). User-facing
  surface is `$LIVE doctor` / `$OWL doctor`.

- **D-15: Doctor table columns for sync.**
  Per-branch row format under a new `## Sync` section:
  ```
  branch           state    last-ok            last-err          retry-after
  a-doyle          enabled  2026-05-22 09:15Z  -                 -
  p-claude_skill_owl  failing  2026-05-22 08:50Z  network/timeout   2026-05-22 09:30Z
  ```
  Global row at top: `sync.state` from settings.json + `remote_url`.

- **D-16: Runtime auth failures collapse to ordinary git failures.**
  `gh` is setup-only; runtime sync runs plain `git push/pull` against
  the configured remote. An expired token, missing SSH key, or revoked
  scope manifests as a non-zero `git` exit with stderr — same backoff
  path as a network error or 5xx. No special `auth-failing` state. User
  notices via doctor's `last-err` column and re-runs the setup skill or
  the host's auth tool (`gh auth refresh`, `ssh-add`).

- **D-17: 404 on push/fetch short-circuits to `failing` state.** Repo
  deleted (or never created — corrupted setup) is NOT transient. Skip
  backoff; set `sync.state = failing` with
  `last_failure_reason = "remote-404"`. Doctor instructs:
  `run /psyche-sync-setup to re-create the remote`. No automatic
  re-create (honors user intent if they deliberately deleted).

- **D-18: Exponential throttle backoff for transient failures.**
  Algorithm:
  - On every failed sync (timeout, network error, push reject,
    non-404 git error): increment `consecutive_failures`, set
    `next_retry_after_ts = now() + delay(consecutive_failures)`.
  - Delay schedule: 1m → 5m → 15m → 1h → 6h → 24h, capped at 24h.
  - All sync attempts (UserPromptSubmit pull AND post-commit
    pull-then-push) check `now() < next_retry_after_ts` and skip
    silently if so.
  - On success: reset `consecutive_failures = 0`, clear
    `last_failure_*` / `next_retry_after_ts`.
  - Backoff is a **gate**, not a retry timer — SPT does NOT
    spontaneously retry. The next natural sync trigger (next prompt
    or next commit) is what attempts the retry, only if past the gate.

- **D-19: `failing` state is a hard stop, not a backoff state.** D-17
  (404) and explicit user action (`/psyche-sync-setup` with a
  `--disable` or doctor-driven disable) transition to `failing`.
  Backoff (D-18) keeps `state = enabled` and uses
  `next_retry_after_ts` as the gate.

### Claude's Discretion

- Exact `AskUserQuestion` framing strings on auto-detect vs manual paths
  (researcher / planner can polish wording).
- Whether `gh auth setup-git` is invoked once globally vs per-worktree
  (depends on gh credential helper scope — researcher confirms).
- Backoff delay schedule tunable defaults (1m/5m/15m/1h/6h/24h is a
  starting point; could be 30s/2m/10m/1h/12h/24h based on real-world
  latency observations).
- Subprocess detachment mechanism for fire-and-forget async pull
  (Windows `CREATE_NO_WINDOW` + `DETACHED_PROCESS` vs Unix `setsid`) —
  reuse existing `crate::common::win_spawn` helper where applicable
  (Phase 18.3 precedent).
- Where in `tracked::commit_agent_payload` the post-commit sync hook
  fires (after the commit returns, before the helper returns) —
  planner picks.
- Doctor row collapse rules (don't list every branch if all are clean —
  one summary row) — visual polish.
- Whether to add a `$LIVE list` indicator (e.g. cloud icon / `sync↑`
  suffix) per-agent showing sync state — planner decides; Phase 32
  list-format precedent applies.

</decisions>

<canonical_refs>
## Canonical References

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

### Phase Continuity (MUST READ)

- `.planning/phases/24-tracked-dir-forked-repo-layout-agents-projects-branches-sess/24-CONTEXT.md`
  — D-01 (system git CLI), D-02 (missing-git soft-fail posture extends to
  sync), D-03 (bare seed + worktrees topology), D-04 (`a-{id}` / `p-{name}`
  branch naming — Phase 35's sync scope keys off this), D-13 (Phase 24
  commits skip push; Phase 35 adds it), D-14 (cross-machine conflict
  policy explicitly deferred to Phase 35 — now answered by D-01..D-03
  above), D-16 (lazy worktree creation — Phase 35 D-10 step 5 extends
  this).
- `.planning/phases/25-perch-nesting-psyche-workers-wire-psyche-download-to-forked-/25-CONTEXT.md`
  — D-07 (`derive_current_repo_names()` for cwd_project — Phase 35 D-06
  active-project scope keys off this); D-13 (lazy project worktree
  creation — same hook gets remote-add extension).
- `.planning/phases/23-commune-signoff-project-root-head-sha-stamping/23-CONTEXT.md`
  — Soft-fail subprocess posture; commit-trailer Stamp shape unchanged
  in Phase 35.

### Source Surfaces (Touchpoints)

- `src/common/tracked.rs` — Phase 24 worktree lifecycle. Phase 35 adds:
  - `sync::pull_branch(branch)` / `sync::push_branch(branch)` —
    per-branch primitives, called from D-04 trigger sites.
  - `sync::accept_flow(remote_url, worktrees)` — D-10 one-shot setup.
  - `ensure_agent_worktree` / `ensure_project_worktree` — one-line
    extension: if `sync.state == enabled`, `git remote add origin` on
    creation (D-10 step 5).
- `src/common/owlery.rs` —
  - `settings_path()` / new helpers `read_sync_settings()` /
    `write_sync_settings()` — D-11 nested namespace persistence.
  - `derive_current_repo_names()` — reused for active-project scope
    (D-06).
- `src/owl/hook_prompt.rs` — UserPromptSubmit handler; add fire-and-
  forget async pull dispatch (D-04 first trigger point). Phase 18.4
  `crate::common::win_spawn` detached-spawn precedent applies.
- `src/live/start.rs` (+ `src/live/revive.rs` if separate) — boot path;
  add D-08 auto-detect check + `AskUserQuestion` injection queue.
- `src/owl/doctor.rs` — D-15 sync table + global state row; D-03
  recovered-aborts counter; D-17 / D-18 / D-19 state surface.
- `src/common/auto_setup.rs` — existing `~/.claude/settings.json`
  manipulation helpers; pattern reused for `$SPT_HOME/settings.json`
  sync namespace.
- `src/common/git.rs` — Phase 23 `run_git_checked` + Phase 24 git
  helpers. Phase 35 adds an extended-budget variant
  `run_git_checked_with_timeout(cmd, 30s)` for sync ops (D-07).
- `plugin/spt/skills/` — new `psyche-sync-setup/SKILL.md` (D-13
  unified entry).
- `plugin/spt/hooks/hooks.json` — no schema change; reuses existing
  `UserPromptSubmit` and `SessionStart` registrations.

### Project Context

- `.planning/PROJECT.md` — v1.8 Psyche Restructure milestone; Phase 35
  is the cross-machine wire-up that completes the milestone.
- `.planning/ROADMAP.md` §Phase 35 — 7 Success Criteria + the 4 open
  questions now resolved (SC4/SC5 trigger points, SC3 settings
  schema, plus the conflict / throttle / failure questions).

### Codebase Maps

- `.planning/codebase/ARCHITECTURE.md`
- `.planning/codebase/CONVENTIONS.md`
- `.planning/codebase/STRUCTURE.md`
- `.planning/codebase/INTEGRATIONS.md` — external CLI integration
  patterns (gh fits here).

### External References

- `gh` CLI docs: `gh repo create --private` flow; `gh auth login` for
  prereq; `gh auth setup-git` for git credential helper wiring.
- GitHub API: 404 contract on push/fetch against non-existent repo
  (drives D-17 detection logic).

### Forward-Compat

- No phases queued after Phase 35 in v1.8 — this seals the milestone.
- Sync semantics deliberately leave room for future "sync everyone's
  branches via --all sweep on `$LIVE start`" (currently scoped out;
  D-06 active-only).

</canonical_refs>

<code_context>
## Existing Code Insights

### Reusable Assets

- `crate::common::tracked` — Phase 24 worktree lifecycle. Add a
  sibling `sync` module (`src/common/sync.rs` or
  `src/common/tracked/sync.rs`) for pull/push primitives. Same
  soft-fail posture, same `run_git_checked` plumbing.
- `crate::common::git::run_git_checked` — Phase 23/24 subprocess
  wrapper. Phase 35 needs an extended-timeout variant for sync ops
  (D-07).
- `crate::common::win_spawn` — Phase 18.3/18.4 detached-spawn helper.
  Reused for fire-and-forget async pull on UserPromptSubmit (D-05).
- `crate::common::owlery::derive_current_repo_names` — Phase 24.1/25
  identity source. Reused for `cwd_project` scope (D-06).
- `crate::common::auto_setup::*` — existing settings.json manipulation
  patterns (env-var injection into `~/.claude/settings.json`); same
  read-modify-write pattern for `$SPT_HOME/settings.json` sync block.
- `crate::owl::plugin_session_start` — Phase 28 SessionStart hook
  + AdditionalContext injection. Reused for D-08 auto-detect
  AskUserQuestion injection (queued from boot, rendered by hook).
- `crate::owl::hook_prompt::run` — UserPromptSubmit handler; D-04
  first trigger lives as an addition here, ordered AFTER the existing
  spool-drain logic (do not block message delivery on sync).

### Established Patterns

- **Soft-fail subprocess with stderr warn** (Phase 23 D-13, Phase 24
  D-02): all sync subprocess calls follow this. Stderr is gated on
  `SPT_TRACE=1` per Phase 18.7.1 D-04 (D-14).
- **Per-event state file under `$SPT_HOME`** (Phase 18.3 sentinel
  pattern, Phase 18.4 wrapper-state.json) — sync state lives in
  `$SPT_HOME/settings.json` per ROADMAP SC3 + D-11.
- **Pure helpers in `common/`; lifecycle wires in `owl/` or `live/`**:
  Phase 35's `sync` module exposes pure pull/push/accept-flow
  primitives; call sites in `hook_prompt.rs` and `tracked.rs` do the
  wiring.
- **`AskUserQuestion` via SessionStart additionalContext injection**
  (Phase 28 D-15 precedent) — D-08 auto-detect path uses the same
  mechanism.
- **Fire-and-forget detached subprocess** — Phase 18.3 echo-commune
  spawn and Phase 18.4 binary handoff both detach via `win_spawn` /
  `setsid`. D-04 prompt-hook async pull reuses this exactly.

### Integration Points

- **Phase 24 `tracked::commit_agent_payload` / `commit_project_payload`** —
  post-commit sync hook (D-04 second trigger) fires immediately after
  the existing commit subprocess returns. Same call-site for both
  agent and project payloads.
- **Phase 24 `tracked::ensure_agent_worktree` /
  `ensure_project_worktree`** — D-10 step 5 adds a one-line
  conditional `git remote add origin` for newly-created worktrees
  when `sync.state == enabled`.
- **Phase 28 SessionStart `<psyche-context>` injection** — D-08
  auto-detect prompt rides on the same hook's additionalContext path.
  No new hook registration needed.
- **Phase 24.1 `agents/{id}/info.json`** — lives inside the agent
  worktree; gets synced along with everything else under D-06's
  active-agent scope. No special-case.
- **Phase 18.4/18.5 binary handoff** — handoff happens BETWEEN sync
  cycles. wrapper-state.json rehydration is unaffected; sync state in
  `$SPT_HOME/settings.json` is process-shared and survives handoff
  naturally.

### What Phase 35 Does NOT Touch

- Phase 24 branch naming (`a-` / `p-` prefixes), worktree topology,
  commit-trailer format, missing-git fallback semantics.
- Phase 25 nesting layout, two-slice commune split, perch lifecycle.
- Phase 23 Stamp shape, soft-fail posture.
- Existing hook registrations in `hooks.json` (reused, not changed).
- `sessions.log` semantics — Phase 24 D-09..D-12 unchanged on local disk.
  Per revised D-02, `sessions.log` IS synced across machines via the same
  commit/push pipeline as every other tracked file; D-01 last-write-wins
  applies on conflicts.

</code_context>

<specifics>
## Specific Ideas

- **`gh` is setup-only.** After `gh repo create` + `gh auth setup-git`
  during accept-flow, ALL runtime sync uses plain `git push` / `git
  pull` against the configured remote. Auth rides on gh's credential
  helper or user SSH keys. No runtime `gh` invocations on hot path.
  This simplifies D-16 (no auth-state machine needed).
- **Single-user assumption is load-bearing for the revised D-02.**
  `sessions.log` syncs across machines under D-01 last-write-wins. The
  single-user-per-machine deployment surface makes simultaneous
  same-agent activity on two machines rare; same-second commits could
  produce duplicate-UUID rows post-rebase, but Phase 24 D-18
  dedup-on-update mostly prevents this. If multi-user / shared-agent
  scenarios appear later, revisit via a custom merge driver (deferred
  idea).
- **D-04 asymmetry is intentional.** UserPromptSubmit is the
  user-experience-hot path → async/non-blocking. Post-commit is the
  data-integrity hot path → sync/blocking. Two different latency
  budgets, two different mechanisms.
- **Backoff is a gate, not a timer.** D-18's `next_retry_after_ts` is
  checked by every natural sync trigger and silently skipped. SPT
  never spontaneously fires a retry — saves cron complexity, keeps
  behavior predictable.
- **404 is special, all other failures collapse.** D-17 (remote
  deleted) is the only failure mode that bypasses backoff and locks
  state to `failing`. Auth, timeout, network, push-reject all share
  the D-18 backoff path.
- **`/psyche-sync-setup` is idempotent.** Running it when
  `sync.state == enabled` reports current status; running when
  `sync.state == declined` re-asks (user-driven override of the No
  answer); running when prereqs missing routes through the
  install-flow AskUserQuestion.

</specifics>

<deferred>
## Deferred Ideas

- **Custom merge driver for sessions.log union semantics.** D-02
  chose accept-loss. If multi-user / cross-machine simultaneous
  same-agent activity ever becomes real, add a `jsonl-union` merge
  driver registered via `.gitattributes` in agent worktrees. Driver
  reuses Phase 24 D-10 dedup function.
- **`--all` sweep on `$LIVE start` boot.** D-06 chose active-only;
  if dormant-agent staleness becomes a real pain point, add a
  once-per-boot full-sweep. Out of scope for this phase.
- **Smart pull-coalescing on UserPromptSubmit.** D-05 chose
  fire-every-prompt. If gh-rate-limit or network cost becomes
  observable, add a "skip if pull-in-flight" flock.
- **Per-machine UUID** — for future "this branch was last touched by
  machine X" doctor surface. Hostname (Phase 23) is the locked source
  for now; UUID is a future identity refinement.
- **GitHub Enterprise / self-hosted remote support.** Setup flow
  assumes github.com; `gh repo create` against an enterprise host
  works but the URL fallback assumes the github.com URL pattern.
  Tunable later.
- **Repo name customization.** Locked to `spt-agent-storage` for now
  (ROADMAP SC1/SC2 literal). User could want to pick their own name;
  add a settings override later if asked.
- **Re-enable after `failing` via doctor command.** D-19 routes
  through `/psyche-sync-setup` to recover; a future `$LIVE doctor
  --repair-sync` shortcut could short-circuit common cases (e.g.
  re-create deleted remote without re-running the full skill).
- **Multi-account gh support.** If user has multiple GitHub accounts,
  the auto-detect "look for spt-agent-storage on the current gh
  account" doesn't know which account is intended. Defer until a
  real user complaint surfaces.
- **`$LIVE list` sync-state indicator.** Visual polish — show a sync
  state glyph per-agent in the list output. Planner's call within
  Phase 35 if cheap; otherwise a follow-up cosmetic phase.

</deferred>

---

*Phase: 35-psyche-sync-cross-machine-context-backup-via-private-gh-repo*
*Context gathered: 2026-05-22*
