Docs infrastructure reorganization plan¶
Goal: migrate the flat docs/ directory to a structured
MkDocs + Material site with ADR conventions, topic-grouped
hierarchy, link-checked build, and a private-visibility GitHub
Pages deploy, without losing any git history and without
breaking the Stage S2 Phase C research queue.
This file is the authoritative execution plan. It is designed to be fully self-contained so that after a context compaction the executor can open this file, the related Q1-Q5 tracker, and the current Stage 2 plan, and proceed without re-deriving anything.
Status and safety net¶
Before the reorganization started the following already existed:
plan-stage2-phase-c-queue.md— the standalone Q1-Q5 research tracker (committed as7d1ae8c). This file must not be lost, merged, or rewritten during the reorganization. It can be moved to a new path (see Appendix A: git-mv map) with history preserved, but its contents are owned by the research track, not by this plan.research/s2c-self-experiment/— the self-experiment artifacts and FINDINGS. These are also moved bygit mvonly.patches/pymobiledevice3/— the pymobiledevice3 upstream-plus-patches overlay. Left untouched in place (the directory already sits at the correct place in the target hierarchy).
Every phase below ends with a commit and a push. Any phase can be interrupted cleanly at that point without leaving the repo in an inconsistent state.
Constraints (in priority order)¶
- Git is the source of truth. Everything lives in the repo; the rendered MkDocs site is a derived artifact.
- Markdown is the format. No format translations.
git mv, notcp + rm. History must be followable across the reorganization viagit log --follow.- No broken links. mkdocs
--strictbuild must pass on every commit from Phase 1 onward. Old paths get 301-redirected viamkdocs-redirectsplugin. - Python venv for docs in
/home/op/venvs/iosmux-docs/, per the user rule that all Python venvs live under/home/op/venvs/. - No personal data in committed docs. UDIDs, serials, hostnames, MAC-derived IPv6 addresses are swept before every commit that adds new research output.
- No guessing. Structural choices are either explicit in this plan or deferred to the user before execution.
Target directory hierarchy¶
docs/
├── index.md # Landing (was docs/README.md)
├── stylesheets/
│ └── extra.css # Custom admonitions, status badges
│
├── architecture/ # How the system works NOW (current state)
│ ├── .pages # awesome-pages ordering
│ ├── index.md # Overview + top-level diagram
│ ├── connection.md # was architecture-connection.md
│ └── protocol/
│ ├── .pages
│ ├── rsd-remotexpc.md # was research/remotexpc-protocol.md
│ ├── coredevice-xpc.md # was research/coredevice-xpc-protocol.md
│ ├── l2-bridge.md # was research/l2-bridge.md
│ └── os-remote-device.md # was research/os-remote-device-api.md
│
├── adr/ # Architecture Decision Records (immutable)
│ ├── .pages
│ ├── index.md # ADR conventions + list
│ ├── template.md # copy-to-create shape
│ ├── 0001-use-pymobiledevice3-not-goios.md
│ ├── 0002-tunneld-on-vm-not-host.md
│ ├── 0003-pymob-patches-overlay-not-fork.md
│ ├── 0004-stage2-option-delta-shim.md
│ ├── 0005-phase-d-go-only-no-new-python.md
│ ├── 0006-empirical-only-no-guessing.md
│ └── 0007-mkdocs-material-docs-site.md
│
├── plans/ # Forward planning
│ ├── .pages
│ ├── index.md # Active plans + archive link
│ ├── stage1.md # was plan-stage1-rebuild.md
│ ├── stage2.md # was plan-stage2-pair-flow.md
│ ├── stage2-phase-c-queue.md # was plan-stage2-phase-c-queue.md
│ ├── docs-reorganization.md # this file (was plan-docs-reorganization.md)
│ └── archive/
│ ├── .pages
│ ├── 2026-03-forward-roadmap.md # was plan-forward-roadmap.md
│ ├── 2026-03-full-xcode-integration.md # was plan-full-xcode-integration.md
│ ├── 2026-03-cds-rsd-inject.md # was plan-cds-rsd-inject.md
│ └── 2026-03-next-steps.md # was plan-next-steps.md
│
├── research/ # Empirical work, grouped by TOPIC
│ ├── .pages
│ ├── index.md # Research index with status per entry
│ ├── protocol/ # Wire captures and RemoteXPC analysis
│ │ ├── .pages
│ │ ├── s2b-pair-attempt-log.md
│ │ ├── s2c-self-experiment/
│ │ │ ├── index.md # was README.md
│ │ │ ├── FINDINGS.md
│ │ │ ├── iosmux-spike-listener.py
│ │ │ └── results/ # raw pcaps / logs (personal-data-swept)
│ │ └── rsd-info-ios2641-reference.json
│ ├── coredevice-internals/ # CoreDevice.framework disasm
│ │ ├── .pages
│ │ ├── coredevice-injection.md
│ │ ├── coredevice-representation.md
│ │ ├── rsd-wrapper-init-analysis.md
│ │ ├── s1a-properties-audit.md
│ │ ├── s1c-static-browser-disasm.md
│ │ ├── s1c-managed-service-devices-registration.md
│ │ ├── action-interception-full-picture.md
│ │ └── pair-button-and-cfnetwork.md
│ └── environment/ # Bridge, USB, audits, wrapper test results
│ ├── .pages
│ ├── code-audit-findings.md
│ ├── phase2-behavior-analysis.md
│ └── phase2-wrapper-fix-test-results.md
│
├── patches/ # UNCHANGED
│ └── pymobiledevice3/...
│
└── runbooks/ # How-to guides
├── .pages
├── index.md # Runbook index
└── restore-environment.md # refers to scripts/iosmux-restore.sh
Notes on the hierarchy:
- Topic-grouped research (user preference), no session-based
split. The filename prefixes (
s1a-,s1c-,s2b-,s2c-) still carry the provenance, so git blame plus those prefixes preserve temporal ordering without a dedicatedsession-N/directory. session8-five-questions.mdmoves toplans/archive/because it is historically a planning / five-questions doc, not an empirical research output. Filename becomes2026-03-session8-five-questions.mdfor date-prefix consistency with other archived plans.plan-stage2-phase-c-queue.mdand this file both move intoplans/as active plans alongside stage1.md and stage2.md.patches/pymobiledevice3/is already underdocs/, so no move needed.
Plugin list (final, pinned in docs/requirements.txt)¶
mkdocs >= 1.6, < 2
mkdocs-material >= 9.5
mkdocs-material-extensions
pymdown-extensions
mkdocs-git-revision-date-localized-plugin
mkdocs-git-authors-plugin
mkdocs-awesome-pages-plugin
mkdocs-macros-plugin
mkdocs-glightbox
mkdocs-redirects
Lint tooling (added in Phase 5):
Admonition set (final, 4 types)¶
Custom admonition styles configured in
docs/stylesheets/extra.css with icons + colors:
| Type | Purpose | Color hint |
|---|---|---|
verified |
Empirically confirmed fact with cited evidence. Strongest claim. | green |
hypothesis |
Plausible but unconfirmed. Must link to the research task that would confirm or refute it. | yellow |
gap |
Known empirical gap — we know we don't know this. Halts any downstream decision that would require the missing data. | red |
superseded |
This section / claim has been replaced; points at the replacement. | grey |
These supplement (do not replace) the standard MkDocs Material
admonitions (note, info, tip, warning, danger,
success, question, failure, bug, example, quote).
Status frontmatter (applied per file)¶
Every markdown file under docs/ gains a YAML frontmatter block
at the top:
---
status: verified | reviewed | draft | hypothesis | superseded | archived
last-verified: YYYY-MM-DD
evidence:
- path: research/protocol/s2c-self-experiment/results/iosmux_wire.log
what: sandbox probe errno=0
---
status: verified— empirical or primary-source confirmedstatus: reviewed— derived logically from verified facts, ran through reviewstatus: draft— in progressstatus: hypothesis— unconfirmed, needs an empirical taskstatus: superseded— replaced; includessuperseded-byfieldstatus: archived— historical, no longer active
Not every file gets every field. Evidence list is optional but
mandatory when status: verified on a research finding.
ADR list (7 retrospective records)¶
Each ADR is short — the pattern is Michael Nygard's "Documenting Architecture Decisions": Title, Status, Context, Decision, Consequences, Evidence, References. Immutable after acceptance.
- 0001 — Use pymobiledevice3, not go-ios. Go-ios was rejected
for iOS 17+ instability. Context from
CLAUDE.md("Key Decisions"). Status: accepted. - 0002 — tunneld runs inside the VM, not on the host. Context
from
architecture-connection.md"Historical note: why host-side tunneld was wrong". Status: accepted. - 0003 — pymobiledevice3 patches live as an overlay in iosmux, not as a GitHub fork. Context: temporary Python dependency, avoid long-lived fork inertia before the Go port. Status: accepted.
- 0004 — Stage 2 uses Option δ shim, not α/β/γ. Context from
plan-stage2-pair-flow.mdandresearch/s2b-pair-attempt-log.md. Status: accepted. - 0005 — Phase D backend is Go only, no new production Python.
Context: project is Go-based; Python is contained to the existing
pymobiledevice3 remote tunneldsubprocess; new long-lived Python introduces removal debt. Status: accepted. - 0006 — Empirical-only discipline: no guessing in research or planning. Every claim either has evidence or is explicitly marked UNKNOWN/hypothesis/gap. Status: accepted.
- 0007 — Documentation engine is MkDocs + Material for MkDocs. Context: this file and the preceding research on docs engines. Status: accepted.
Execution phases¶
Each phase ends with one commit + push. Phases can be executed back-to-back in one session or split across sessions.
Phase 1 — Bootstrap MkDocs + Material (flat layout, no reorg yet)¶
Goal: working mkdocs serve and mkdocs build --strict on
the current flat docs/ layout. Reorganization comes in Phase 2.
Steps:
- 1.1 Create venv:
python3 -m venv /home/op/venvs/iosmux-docs - 1.2 Create
docs/requirements.txtwith the plugin list above (without lint tooling, that comes in Phase 5). - 1.3 Install:
/home/op/venvs/iosmux-docs/bin/pip install --upgrade pip && /home/op/venvs/iosmux-docs/bin/pip install -r docs/requirements.txt - 1.4 Create
mkdocs.ymlat the repo root (see Appendix B for the template). - 1.5 Create
docs/stylesheets/extra.csswith custom admonition definitions (see Appendix C). - 1.6 Create
scripts/docs-venv-setup.sh— idempotent venv bootstrap (see Appendix D). - 1.7 Create
scripts/docs-serve.sh—mkdocs servewrapper (see Appendix D). - 1.8 Create
scripts/docs-build.sh—mkdocs build --strictwrapper (see Appendix D). - 1.9 Add
site/to.gitignore. - 1.10 Run
./scripts/docs-build.sh. Expect broken-link errors from existing docs — fix them inline by updating relative paths. Iterate until the build is clean. - 1.11 Run
./scripts/docs-serve.sh, openhttp://127.0.0.1:8000, visually check: landing, Mermaid diagrams onarchitecture-connection.md, hex code blocks onresearch/s2c-self-experiment/FINDINGS.md, search works. -
1.12 Commit + push:
Bootstrap MkDocs + Material docs site (flat layout) Adds mkdocs.yml, docs/requirements.txt, docs/stylesheets/extra.css (custom verified/hypothesis/gap/superseded admonitions), and scripts/docs-{venv-setup,serve,build}.sh. Docs render from the existing flat docs/ layout; reorganization to the target hierarchy is Phase 2. Build passes with mkdocs --strict after fixing N pre-existing broken relative links in <list of files>.
Done criteria:
./scripts/docs-build.shexits 0 with--strict./scripts/docs-serve.shserves on:8000- All existing docs render correctly (Mermaid, code blocks, tables, internal links)
- Commit pushed
Phase 2 — Reorganize docs/ to target hierarchy¶
Goal: move every file to its target location per the hierarchy above. Redirects preserve old URLs.
Steps:
- 2.1 Create the target directory skeleton:
cd docs
mkdir -p architecture/protocol
mkdir -p adr
mkdir -p plans/archive
mkdir -p research/protocol/s2c-self-experiment
mkdir -p research/coredevice-internals
mkdir -p research/environment
mkdir -p runbooks
- 2.2 Execute the
git mvoperations per Appendix A. Do them in dependency order: destination parent dir exists, then move. - 2.3 Rename landing page:
git mv docs/README.md docs/index.md. - 2.4 For each subdirectory with an index, rename to
index.mdwhere needed (e.g.research/protocol/s2c-self-experiment/README.md → .../s2c-self-experiment/index.md). - 2.5 Create
.pagesfiles in each new directory with logical ordering (see Appendix E for templates). Key directories needing.pages: docs/.pagesdocs/architecture/.pagesdocs/architecture/protocol/.pagesdocs/adr/.pagesdocs/plans/.pagesdocs/plans/archive/.pagesdocs/research/.pagesdocs/research/protocol/.pagesdocs/research/coredevice-internals/.pagesdocs/research/environment/.pagesdocs/runbooks/.pages- 2.6 Create stub
index.mdfiles where missing so thatawesome-pageshas a landing for each directory: docs/architecture/index.mddocs/architecture/protocol/index.mddocs/adr/index.md(the ADR conventions doc)docs/plans/index.mddocs/research/index.mddocs/research/protocol/index.mddocs/research/coredevice-internals/index.mddocs/research/environment/index.mddocs/runbooks/index.md- 2.7 Update all internal links to point at the new paths. Approach:
- Grep for each old path referenced in any markdown file
- Replace with the new path
- Run
mkdocs build --strict— any leftover broken link fails the build
Specifically the following files have many internal links
that need rewriting:
- docs/index.md (landing, lots of refs)
- docs/plans/stage2.md (was plan-stage2-pair-flow.md)
- docs/plans/stage2-phase-c-queue.md
- docs/architecture/connection.md
- docs/research/protocol/s2c-self-experiment/FINDINGS.md
- docs/research/protocol/s2c-self-experiment/index.md
- CLAUDE.md — check for any docs/... refs
- Root README.md — check for any docs/... refs
8. 2.8 Configure mkdocs-redirects in mkdocs.yml with the
full old→new path map from Appendix A. Every old path returns
a 301 to the new path when the site is served.
9. 2.9 Run ./scripts/docs-build.sh — must pass with
--strict. Fix any missed refs.
10. 2.10 Run ./scripts/docs-serve.sh, click through every
section: architecture, adr (still sparse), plans, research
subtrees, patches, runbooks. Confirm navigation tree looks
sensible. Visit a few old URLs to confirm redirects fire.
11. 2.11 Commit + push:
```
Reorganize docs/ into architecture / plans / research / adr / runbooks
Topic-grouped layout, per the user-approved target hierarchy in
plan-docs-reorganization.md. Every file moved via git mv so
--follow history is preserved. mkdocs-redirects plugin
301-redirects every old path to its new location; mkdocs build
--strict is clean.
Also moves README.md → index.md (MkDocs landing convention) and
adds stub index.md + .pages files for all new directories.
```
Done criteria:
git log --follow docs/architecture/connection.mdshows the full pre-rename historydocs-build.sh --strictpassesmkdocs-redirectsconfig includes every old path- Navigation tree matches the target hierarchy
- Commit pushed
Phase 3 — Status frontmatter + custom admonitions¶
Goal: make every key doc carry explicit status metadata; introduce the 4 custom admonitions rendered by extra.css.
Steps:
- 3.1 The extra.css for custom admonitions was added in Phase 1. Phase 3 adds actual usage.
- 3.2 Write
docs/index.mdsection "How to read these docs" explaining: - The status frontmatter values
- The 4 custom admonitions (
verified,hypothesis,gap,superseded) and when to use each - Hard rule: empirical evidence or explicit UNKNOWN, never guessing (pointer to ADR 0006)
- 3.3 Apply status frontmatter to these key files (not all at once, prioritize the ones readers will hit first):
docs/index.md— status: verifieddocs/architecture/connection.md— status: verifieddocs/plans/stage1.md— status: archived (stage is done)docs/plans/stage2.md— status: revieweddocs/plans/stage2-phase-c-queue.md— status: draft (already has this frontmatter)docs/plans/docs-reorganization.md— status: draft (this file)docs/research/protocol/s2b-pair-attempt-log.md— status: verifieddocs/research/protocol/s2c-self-experiment/FINDINGS.md— status: verifieddocs/research/protocol/s2c-self-experiment/index.md— status: verifieddocs/research/coredevice-internals/*.md— status: archived or reviewed case by case (they are historical)docs/research/environment/*.md— samedocs/plans/archive/*.md— status: archived- 3.4 Use the new admonitions in 2-3 places as examples (don't spray everywhere — prove the mechanism works, let future content adopt them organically):
- In
FINDINGS.md:!!! verified "Blocker Z closed"wrapping the sandbox probe results - In
plans/stage2.md:!!! hypothesis "Expected pymobiledevice3 pair flow behavior"wrapping any unverified assumption - In
plans/stage2-phase-c-queue.md:!!! gap "Post-TLS server responses"wrapping the friend-capture fallback paragraph - 3.5 Verify with
./scripts/docs-serve.shthat frontmatter renders as a badge and custom admonitions have the expected color / icon. -
3.6 Commit + push:
Add status frontmatter + custom admonitions on key docs Every key doc now carries a YAML frontmatter block with status (verified/reviewed/draft/hypothesis/superseded/archived), last-verified date, and optional evidence list. Four custom admonitions (verified, hypothesis, gap, superseded) are defined in docs/stylesheets/extra.css and demonstrated in three places. Landing page gains a "How to read these docs" section wiring the metadata convention together with ADR 0006's empirical-only rule.
Done criteria:
docs/index.mddocuments the metadata convention- At least 10 files have
status:frontmatter - Visual check: badges render, admonitions look right
- Commit pushed
Phase 4 — ADR framework + 7 retrospective records¶
Goal: the docs/adr/ skeleton and 7 backfilled ADRs that
capture decisions the project already made implicitly.
Steps:
- 4.1 Write
docs/adr/index.md— ADR conventions, index of current ADRs, link to template, filing rules (immutable, superseded-by only, numeric prefix). - 4.2 Write
docs/adr/template.md— the Nygard pattern. - 4.3 Write each ADR 0001..0007 per the list above. Each ADR is 1-2 pages max, heavily evidence-linked. Context for each ADR:
- 0001 — reference
CLAUDE.md"Key Decisions: go-ios REJECTED (unstable iOS 18+) → pymobiledevice3 tunneld as subprocess" - 0002 — reference
docs/architecture/connection.md"Historical note: why an earlier design with host-side tunneld was wrong" - 0003 — reference
docs/patches/pymobiledevice3/README.mdand the user's decision rationale in this session - 0004 — reference
docs/research/protocol/s2b-pair-attempt-log.md(Phase B findings that killed α/γ and promoted δ) - 0005 — reference
docs/research/protocol/s2c-self-experiment/FINDINGS.md(Shape B confirmed viable) and the Go pivot section indocs/plans/stage2.md - 0006 — empirical-only rule, no direct file quote — this
is a meta-decision. Reference
plan-stage2-phase-c-queue.mdas a concrete instance of the rule being applied. - 0007 — this very reorganization plan + the options research that preceded it
- 4.4 Each ADR gets
status: acceptedin frontmatter + adate:field. - 4.5 Update
mkdocs.yml/.pagesso ADRs appear in the top-level navigation. - 4.6
./scripts/docs-build.sh— check no broken links in the new ADR cross-references. -
4.7 Commit + push:
Add ADR framework + 7 retrospective decision records docs/adr/ now holds: - index.md with conventions and list - template.md (Nygard pattern) - 0001..0007 backfilled from already-made decisions Each ADR is short, heavily cross-referenced to the evidence (previous commits, research docs, plan files). Future decisions follow the same pattern; once an ADR is accepted it is immutable — changes come as new ADRs with superseded-by.
Done criteria:
- 9 files under
docs/adr/(index + template + 7 ADRs) - Every ADR cross-links to its evidence
- ADR section visible in site navigation
- Commit pushed
Phase 5 — Link hygiene, lint, Makefile targets¶
Goal: tooling to keep docs from rotting. Fails builds on broken links and style issues.
Steps:
- 5.1 Add
pymarkdownlntandlinkcheckertodocs/requirements.txt. - 5.2
scripts/docs-venv-setup.shupgrades so the new deps install. - 5.3 Create
.pymarkdown.ymlat the repo root with reasonable defaults (MD013 line-length off, MD033 HTML off, MD041 first-line-h1 off for frontmatter files). -
5.4 Create
scripts/docs-lint.sh:
Add linkcheck as a separate step (heavy, optional):
- 5.5 Create
Makefile(or extend if present) at repo root with targets:
.PHONY: docs-setup docs-serve docs-build docs-lint docs-clean
docs-setup:
./scripts/docs-venv-setup.sh
docs-serve:
./scripts/docs-serve.sh
docs-build:
./scripts/docs-build.sh
docs-lint:
./scripts/docs-lint.sh
docs-clean:
rm -rf site/
- 5.6 Run
make docs-lint. Fix cosmetic warnings. - 5.7 Run
make docs-build. Must pass. -
5.8 Commit + push:
Done criteria:
make docs-lintandmake docs-buildboth exit 0- Commit pushed
Phase 6 — GitHub Pages deploy via Actions¶
Goal: on every push to main that touches docs, rebuild
the site and deploy to GitHub Pages (private visibility, GH Pro
account).
Steps:
- 6.1 Create
.github/workflows/docs.ymlper Appendix F. - 6.2 In
mkdocs.yml, setsite_urltohttps://staticwire.github.io/iosmux/(confirm the exact path once the first deploy succeeds — for an organization repo it is typicallyhttps://<owner>.github.io/<repo>/). - 6.3 User action: in the GitHub repo web UI:
- Settings → Pages → Build and deployment → Source: GitHub Actions
- Settings → Pages → Privacy: keep the default (organization-private for GH Pro)
- Confirm the repo is private (already true)
- 6.4 Push the commit; watch the Actions tab for the workflow run. First run often fails on environment differences between local and runner — the most common:
fetch-depth: 0missing →mkdocs-git-revision-dateplugin errors- Python version mismatch → pin in workflow
strictbuild catching a link that onlyawesome-pagesintroduced- 6.5 Iterate on the workflow until the build and deploy jobs both succeed.
- 6.6 Open the returned Pages URL. Log in as a repo collaborator. Confirm the site is visible and looks identical to local.
- 6.7 Update
docs/index.mdlanding with a "View this site at" link, replacing the placeholder. -
6.8 Commit + push:
Add GitHub Actions workflow to deploy docs to GitHub Pages Triggered on pushes to main that touch docs/, mkdocs.yml, docs/requirements.txt, or the workflow itself. Uses the official actions/deploy-pages@v4 path. Private visibility via GH Pro; only repo collaborators can view the rendered site. site_url in mkdocs.yml now points at the deployed location; docs/index.md landing links to the live site.
Done criteria:
- Workflow run green
- Rendered site visible at the Pages URL for a logged-in collaborator
docs/index.mdlinks to it- Commit pushed
Phase 7 — Final polish + cross-refs in root README and CLAUDE.md¶
Goal: tie the docs site into the project's main entry points.
Steps:
- 7.1 Walk the deployed site. For each top-level section
(architecture, adr, plans, research, patches, runbooks), read
the
index.md. Fix any typos, stale claims, broken refs. - 7.2 Root
README.md: add a## Documentationsection with: - Link to the GH Pages URL
- Pointer to
docs/as the source - Link to the current Stage 2 plan
- Link to the Q1-Q5 queue
- 7.3
CLAUDE.md(project instructions): add a## Documentation disciplinesection enforcing: - New empirical findings go under
docs/research/withstatus: verifiedand evidence - New decisions go as ADRs under
docs/adr/, never inline in plans - Plans may be rewritten freely but old versions get
date-prefixed and moved to
docs/plans/archive/ - No guessing — any claim not backed by evidence is either
status: hypothesisor named as a gap -
7.4 Commit + push:
Done criteria:
- Root README has a Documentation section
- CLAUDE.md has a Documentation discipline section
- Site is fully walked and polished
- Commit pushed
Appendix A — git mv map¶
Execute in this order. Destination parent directories must exist (created in step 2.1).
# landing
docs/README.md → docs/index.md
# architecture
docs/architecture-connection.md → docs/architecture/connection.md
docs/research/remotexpc-protocol.md → docs/architecture/protocol/rsd-remotexpc.md
docs/research/coredevice-xpc-protocol.md → docs/architecture/protocol/coredevice-xpc.md
docs/research/l2-bridge.md → docs/architecture/protocol/l2-bridge.md
docs/research/os-remote-device-api.md → docs/architecture/protocol/os-remote-device.md
# plans (active)
docs/plan-stage1-rebuild.md → docs/plans/stage1.md
docs/plan-stage2-pair-flow.md → docs/plans/stage2.md
docs/plan-stage2-phase-c-queue.md → docs/plans/stage2-phase-c-queue.md
docs/plan-docs-reorganization.md → docs/plans/docs-reorganization.md
# plans (archive)
docs/plan-forward-roadmap.md → docs/plans/archive/2026-03-forward-roadmap.md
docs/plan-full-xcode-integration.md → docs/plans/archive/2026-03-full-xcode-integration.md
docs/plan-cds-rsd-inject.md → docs/plans/archive/2026-03-cds-rsd-inject.md
docs/plan-next-steps.md → docs/plans/archive/2026-03-next-steps.md
docs/research/session8-five-questions.md → docs/plans/archive/2026-03-session8-five-questions.md
# research/protocol
docs/research/s2b-pair-attempt-log.md → docs/research/protocol/s2b-pair-attempt-log.md
docs/research/s2c-self-experiment/ → docs/research/protocol/s2c-self-experiment/
docs/research/s2c-self-experiment/README.md → docs/research/protocol/s2c-self-experiment/index.md
docs/research/rsd-info-ios2641-reference.json → docs/research/protocol/rsd-info-ios2641-reference.json
# research/coredevice-internals
docs/research/coredevice-injection.md → docs/research/coredevice-internals/coredevice-injection.md
docs/research/coredevice-representation.md → docs/research/coredevice-internals/coredevice-representation.md
docs/research/rsd-wrapper-init-analysis.md → docs/research/coredevice-internals/rsd-wrapper-init-analysis.md
docs/research/s1a-properties-audit.md → docs/research/coredevice-internals/s1a-properties-audit.md
docs/research/s1c-static-browser-disasm.md → docs/research/coredevice-internals/s1c-static-browser-disasm.md
docs/research/s1c-managed-service-devices-registration.md → docs/research/coredevice-internals/s1c-managed-service-devices-registration.md
docs/research/action-interception-full-picture.md → docs/research/coredevice-internals/action-interception-full-picture.md
docs/research/pair-button-and-cfnetwork.md → docs/research/coredevice-internals/pair-button-and-cfnetwork.md
# research/environment
docs/research/code-audit-findings.md → docs/research/environment/code-audit-findings.md
docs/research/phase2-behavior-analysis.md → docs/research/environment/phase2-behavior-analysis.md
docs/research/phase2-wrapper-fix-test-results.md → docs/research/environment/phase2-wrapper-fix-test-results.md
# patches — NO MOVE (already correct)
# docs/patches/pymobiledevice3/* — unchanged
Nested s2c-self-experiment/ children (FINDINGS.md,
iosmux-spike-listener.py, results/) move with the parent
git mv.
The mkdocs-redirects config (mkdocs.yml) gets one entry per
row in this map, in the form
'old/path.md': new/path.md.
Appendix B — mkdocs.yml template¶
site_name: iosmux
site_description: iOS 17+ remote device proxy — research and implementation notes
site_author: staticwire
site_url: https://staticwire.github.io/iosmux/ # confirmed in Phase 6
repo_url: https://github.com/staticwire/iosmux
repo_name: staticwire/iosmux
edit_uri: edit/main/docs/
docs_dir: docs
site_dir: site
strict: true
theme:
name: material
language: en
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: indigo
accent: indigo
toggle:
icon: material/weather-sunny
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: indigo
accent: indigo
toggle:
icon: material/weather-night
name: Switch to light mode
features:
- navigation.tabs
- navigation.sections
- navigation.top
- navigation.indexes
- navigation.tracking
- toc.follow
- toc.integrate
- search.suggest
- search.highlight
- search.share
- content.code.copy
- content.code.annotate
- content.action.edit
- content.action.view
- content.tabs.link
icon:
repo: fontawesome/brands/github
extra_css:
- stylesheets/extra.css
plugins:
- search
- awesome-pages
- git-revision-date-localized:
enable_creation_date: true
type: iso_date
fallback_to_build_date: true
- git-authors
- glightbox
- macros
- redirects:
redirect_maps:
# filled in Phase 2 with the full Appendix A map
# 'README.md': index.md
# 'architecture-connection.md': architecture/connection.md
# ... etc
markdown_extensions:
- abbr
- admonition
- attr_list
- def_list
- footnotes
- md_in_html
- tables
- toc:
permalink: true
toc_depth: 4
- pymdownx.arithmatex:
generic: true
- pymdownx.betterem
- pymdownx.caret
- pymdownx.critic
- pymdownx.details
- pymdownx.emoji
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.keys
- pymdownx.mark
- pymdownx.smartsymbols
- pymdownx.snippets
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
- pymdownx.tabbed:
alternate_style: true
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tilde
Appendix C — docs/stylesheets/extra.css template¶
Custom admonition definitions. Material convention: each custom
type needs a CSS class and an SVG icon reference via
.md-typeset .admonition.<type> + --md-admonition-icon--<type>.
/* ---- Custom admonitions ---- */
/* verified — strongest factual claim */
:root {
--md-admonition-icon--verified: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>');
}
.md-typeset .admonition.verified,
.md-typeset details.verified {
border-color: #2e7d32;
}
.md-typeset .verified > .admonition-title,
.md-typeset .verified > summary {
background-color: rgba(46, 125, 50, 0.1);
border-color: #2e7d32;
}
.md-typeset .verified > .admonition-title::before,
.md-typeset .verified > summary::before {
background-color: #2e7d32;
-webkit-mask-image: var(--md-admonition-icon--verified);
mask-image: var(--md-admonition-icon--verified);
}
/* hypothesis — unconfirmed, needs research */
:root {
--md-admonition-icon--hypothesis: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2zm1 17h-2v-2h2zm2.07-7.75-.9.92A3.4 3.4 0 0 0 13 15h-2v-.5a4.2 4.2 0 0 1 1.17-2.83l1.24-1.26a2 2 0 0 0 .59-1.41 2 2 0 0 0-4 0H8a4 4 0 0 1 8 0 3.23 3.23 0 0 1-.93 2.25z"/></svg>');
}
.md-typeset .admonition.hypothesis,
.md-typeset details.hypothesis {
border-color: #f9a825;
}
.md-typeset .hypothesis > .admonition-title,
.md-typeset .hypothesis > summary {
background-color: rgba(249, 168, 37, 0.1);
border-color: #f9a825;
}
.md-typeset .hypothesis > .admonition-title::before,
.md-typeset .hypothesis > summary::before {
background-color: #f9a825;
-webkit-mask-image: var(--md-admonition-icon--hypothesis);
mask-image: var(--md-admonition-icon--hypothesis);
}
/* gap — known empirical unknown, halts downstream */
:root {
--md-admonition-icon--gap: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>');
}
.md-typeset .admonition.gap,
.md-typeset details.gap {
border-color: #c62828;
}
.md-typeset .gap > .admonition-title,
.md-typeset .gap > summary {
background-color: rgba(198, 40, 40, 0.1);
border-color: #c62828;
}
.md-typeset .gap > .admonition-title::before,
.md-typeset .gap > summary::before {
background-color: #c62828;
-webkit-mask-image: var(--md-admonition-icon--gap);
mask-image: var(--md-admonition-icon--gap);
}
/* superseded — content replaced, links forward to new version */
:root {
--md-admonition-icon--superseded: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17.65 6.35A7.958 7.958 0 0 0 12 4a8 8 0 1 0 7.73 10h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>');
}
.md-typeset .admonition.superseded,
.md-typeset details.superseded {
border-color: #546e7a;
}
.md-typeset .superseded > .admonition-title,
.md-typeset .superseded > summary {
background-color: rgba(84, 110, 122, 0.1);
border-color: #546e7a;
}
.md-typeset .superseded > .admonition-title::before,
.md-typeset .superseded > summary::before {
background-color: #546e7a;
-webkit-mask-image: var(--md-admonition-icon--superseded);
mask-image: var(--md-admonition-icon--superseded);
}
Appendix D — scripts/ templates¶
All three scripts have the SPDX header and set -euo pipefail.
scripts/docs-venv-setup.sh:
#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-or-later
set -euo pipefail
VENV="/home/op/venvs/iosmux-docs"
REQS="$(git rev-parse --show-toplevel)/docs/requirements.txt"
if [[ ! -d "$VENV" ]]; then
python3 -m venv "$VENV"
fi
"$VENV/bin/pip" install --quiet --upgrade pip
"$VENV/bin/pip" install --quiet -r "$REQS"
echo "docs venv ready at $VENV"
scripts/docs-serve.sh:
#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-or-later
set -euo pipefail
VENV="/home/op/venvs/iosmux-docs"
[[ -d "$VENV" ]] || { echo "run scripts/docs-venv-setup.sh first" >&2; exit 1; }
source "$VENV/bin/activate"
cd "$(git rev-parse --show-toplevel)"
exec mkdocs serve --dev-addr 127.0.0.1:8000 "$@"
scripts/docs-build.sh:
#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-or-later
set -euo pipefail
VENV="/home/op/venvs/iosmux-docs"
[[ -d "$VENV" ]] || { echo "run scripts/docs-venv-setup.sh first" >&2; exit 1; }
source "$VENV/bin/activate"
cd "$(git rev-parse --show-toplevel)"
exec mkdocs build --strict --clean "$@"
scripts/docs-lint.sh (Phase 5):
#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-or-later
set -euo pipefail
VENV="/home/op/venvs/iosmux-docs"
[[ -d "$VENV" ]] || { echo "run scripts/docs-venv-setup.sh first" >&2; exit 1; }
source "$VENV/bin/activate"
cd "$(git rev-parse --show-toplevel)"
exec pymarkdown --config .pymarkdown.yml scan docs/
Appendix E — .pages templates¶
mkdocs-awesome-pages-plugin reads a .pages file per
directory to control nav order and titles.
docs/.pages:
docs/architecture/.pages:
docs/architecture/protocol/.pages:
docs/plans/.pages:
nav:
- index.md
- stage1.md
- stage2.md
- stage2-phase-c-queue.md
- docs-reorganization.md
- archive
docs/plans/archive/.pages:
(Ellipsis = "everything else alphabetical".)
docs/research/.pages:
docs/research/protocol/.pages:
docs/research/coredevice-internals/.pages:
docs/research/environment/.pages:
docs/adr/.pages:
nav:
- index.md
- template.md
- 0001-use-pymobiledevice3-not-goios.md
- 0002-tunneld-on-vm-not-host.md
- 0003-pymob-patches-overlay-not-fork.md
- 0004-stage2-option-delta-shim.md
- 0005-phase-d-go-only-no-new-python.md
- 0006-empirical-only-no-guessing.md
- 0007-mkdocs-material-docs-site.md
docs/runbooks/.pages:
Appendix F — .github/workflows/docs.yml template¶
name: docs
on:
push:
branches: [main]
paths:
- 'docs/**'
- 'mkdocs.yml'
- 'docs/requirements.txt'
- '.github/workflows/docs.yml'
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: docs
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # required by mkdocs-git-revision-date plugin
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r docs/requirements.txt
- name: Build site
run: mkdocs build --strict --clean
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: site
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Running the plan¶
Open this file in docs/plans/docs-reorganization.md (after
Phase 2) or docs/plan-docs-reorganization.md (before). Work
each Phase in order, top to bottom. Each Phase ends with a
commit + push; the repo is safe to interrupt at any phase
boundary.
Reference files the executor should keep open alongside this plan:
plan-stage2-phase-c-queue.md— never forget this exists; it must survive every reorg stepplan-stage2-pair-flow.md— the Stage 2 plan; gets moved toplans/stage2.mdin Phase 2research/s2c-self-experiment/FINDINGS.md— the empirical basis for the current architecture; referenced by multiple ADRs in Phase 4
Resume point after the current context compaction: start of
Phase 1 (Bootstrap MkDocs). All of Phase 0 (standalone Q1-Q5
file extraction) is already committed as 7d1ae8c.