Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ self-fetches its siblings from the same branch, and everything is deployed to
- `tests/` — shell unit tests (`test-*.sh`), Docker e2e suites (`e2e/`),
UX demos (`ux/`)
- `docs/` — user documentation (concepts / how-to / reference), design
records (`design/`), security analyses (`security/`)
records (`design/`), superseded records (`_archive/`)

## Rules

Expand Down
19 changes: 14 additions & 5 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,19 @@ with ddev — see the [README](../README.md) whether the kit fits your setup.

- [Troubleshooting](troubleshooting.md) — symptom → cause → fix

## Evaluations (internal)

- [Evaluations](evaluate/README.md) — third-party tools and addons
assessed against the kit's model, with verdicts (issues #40, #41)

## Design records (internal)

`design/` and `security/` hold the historical planning and analysis records.
They are not user documentation — where wording differs from the code, the
code wins. One exception is living, not historical:
[conventions.md](design/conventions.md) — the binding style guide for
shipped code (prompts, output, language).
`design/` holds planning and analysis records for CURRENT behavior —
where wording differs from the code, the code wins. Notable living
references: [conventions.md](design/conventions.md) — the binding style
guide for shipped code (prompts, output, language) — and
[rootless-backend.md](design/rootless-backend.md) — the provisioning and
selection reference for the rootless container backends. Superseded or
purely historical records live in [`_archive/`](_archive/) (same
subfolder structure: `_archive/design/`, `_archive/security/`) — they
document how the kit got here, not how it works today.
7 changes: 7 additions & 0 deletions docs/_archive/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Archive

Superseded or purely historical documents — they record how the kit got
here, not how it works today. The subfolder structure mirrors the live
tree at the time of archiving (`_archive/design/`, `_archive/security/`).
For current behavior see the [docs index](../README.md); where wording
differs from the code, the code wins.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 3 additions & 1 deletion docs/concepts/wrapper.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ you manage your own `~/.config/opencode/tui.json` (for the opencode
user), the kit leaves it alone — the file is only written when absent
or previously kit-written (marker key `_opencode_permissions_kit`).

Design background: [plan-ui-tui-opencode](../design/plan-ui-tui-opencode.md).
Design background:
[plan-ui-tui-opencode](../_archive/design/plan-ui-tui-opencode.md)
(archived).

## Wrapper-bypass guard (detect, then warn loudly)

Expand Down
7 changes: 4 additions & 3 deletions docs/design/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ purpose, they are not confirmations.

## Script output style

See `docs/design/ux-improvement.md` (decisions): labeled lines
`info`/`success`/`warn`/`error` via `ui.sh`, slim banner, Unicode symbols
with `UI_ASCII=1` fallback, `NO_COLOR` and non-tty honored.
See `docs/_archive/design/ux-improvement.md` (decisions, archived):
labeled lines `info`/`success`/`warn`/`error` via `ui.sh`, slim banner,
Unicode symbols with `UI_ASCII=1` fallback, `NO_COLOR` and non-tty
honored.

## Language

Expand Down
59 changes: 37 additions & 22 deletions docs/design/ddev-e2e-test.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
# PLAN-DDEV-E2E: real-ddev e2e suite with a cached golden container

> Status: **PLANNED — not implemented.** Design record for a third e2e suite
> (`make e2e-ddev`) that runs the REAL ddev against the REAL docker-rootless
> daemon inside the systemd test container, answering the recurring burn-in
> problem: most ddev issues (#18, #20, #21, #25, the §10a TODOs in
> ddev-sandbox.md) only surfaced on productive WSL installs because both
> existing suites exercise ddev through the `fake-ddev` stub — kit plumbing
> only, never ddev itself. The core enabler is a **golden-image cache**: the
> provisioned rootless daemon + ddev + pulled images are snapshotted once via
> `docker commit`, so repeat runs skip the 3–4+ minute download/install phase.
> Where wording differs from the code, the code wins.
> Status: **IMPLEMENTED — shipped with 0.0.21.** `make e2e-ddev` /
> `make e2e-ddev-fresh` run `tests/e2e/run-ddev.sh` (68 checks, full
> DD0–DD14 catalog incl. the camino real-site tier and the bare-origin
> git tier; manual CI workflow since 2026-08-22, first green GitHub run
> 2026-08-23 — §8). The text below is the original design record; where
> wording differs from the code, the code wins. Two deltas since the
> plan: the golden image moved from the §4.2 `docker commit` flow to a
> **save/load tar** flow (the inner docker store on the container
> filesystem produced whiteouts that `docker commit` dropped — golden
> image v2 keeps no inner store and loads images from a tar on boot),
> and the weekly CI `schedule` (§8) is still pending — the workflow is
> `workflow_dispatch`-only.
>
> Original framing, kept for context: a third e2e suite answering the
> recurring burn-in problem — most ddev issues (#18, #20, #21, #25, the
> §10a TODOs in ddev-sandbox.md, archived under
> `docs/_archive/design/`) only surfaced on productive WSL
> installs because both existing suites exercise ddev through the
> `fake-ddev` stub — kit plumbing only, never ddev itself. The core
> enabler is a **golden-image cache**: the provisioned rootless daemon +
> ddev + pulled images are snapshotted once, so repeat runs skip the
> 3–4+ minute download/install phase.

## 1. Problem & goal

Expand All @@ -18,7 +30,7 @@
| `make e2e` (run.sh, 250 checks) | ddev is `tests/e2e/fake-ddev` — a logging stub. Nothing of ddev itself runs: no containers, no mutagen, no chmod behavior, no router. |
| `make e2e-rootless` (run-docker-rootless.sh, 54 checks) | REAL inner docker-rootless daemon (systemd container), but ddev is never installed — only raw `docker` probes (alpine). |

Every issue class from `ddev-as-user-issues.md` §1.1 — settings-dir chmod
Every issue class from `ddev-as-user-issues.md` §1.1 (archived: `docs/_archive/design/`) — settings-dir chmod
(`#25`), the `ddev()` function transports (`#18`), describe-state mismatches,
mutagen, first-start behavior — needs real ddev to reproduce. Goal:

Expand Down Expand Up @@ -173,7 +185,7 @@ Same idioms as `e2e_resolve_cache` (lib.sh): resolve, compare, fall back.

## 7. Test catalog (DD sections)

Mapped to the documented issue classes (ddev-as-user-issues.md §1.1) — each
Mapped to the documented issue classes (ddev-as-user-issues.md §1.1, archived: docs/_archive/design/) — each
row is the regression net for a real burn-in finding:

| Section | Checks | Issue class |
Expand Down Expand Up @@ -248,8 +260,8 @@ re-done per run: `trustedHostsPattern` in `config/system/settings.php`,
to the burn-in commits except three documented deviations: `name:` line
dropped from `.ddev/config.yaml`, `!/public/index.php` gitignore
exception so clones boot, dump as sidecar `db.sql.gz`) plus the fixture
README with the regeneration recipe. Phase 2b fixture intake is done;
the golden-image warm-up integration remains.
README with the regeneration recipe. Phase 2b complete — DD10/DD11 ship
in the runner (shipped 0.0.21).

Location: `tests/e2e/fixtures/camino/` in the repo (shipped — installs
stream from the same repo, and CI needs the files). If the dump ever
Expand Down Expand Up @@ -283,7 +295,8 @@ another baked artifact and keeps branch content in reviewable script form —
the maintainer's real project bare repo is the template for what the
branches must contain). **Status: generator implemented and verified**
(2026-08-22; ShellCheck-clean, clone + all branch switches tested against
the harvested camino fixture) — reconciled with the real burn-in bare repo:
the harvested camino fixture; DD12 shipped 0.0.21) — reconciled with the
real burn-in bare repo:
the tracked set there is `.ddev/config.yaml` + the composer/TYPO3 tree
(11 files, no AGENTS.md), so `feature/top-level` works on README.md/LICENSE
instead. Branch layout:
Expand Down Expand Up @@ -414,15 +427,17 @@ bare-origin flow (DD12).

## 9. Rollout & effort

All phases shipped with 0.0.21; estimates below are the original plan.

| Phase | Content | Estimate |
|---|---|---|
| 1 | runner skeleton + golden-image build/quiesce/commit/boot (§4) + DD0–DD2 | 1–2 d |
| 2 | full catalog DD3–DD9 + `--fresh`/TTL knobs | 1 d |
| 2b | real-site tier: fixture intake (**done 2026-08-22** — `tests/e2e/fixtures/camino/` harvested), remaining: warm-up integration + DD10–DD11 | 1 d |
| 2c | git-flow tier: `make-bare-origin.sh` generator (**done 2026-08-22**, verified) + DD12 | 0.5 d |
| 2d | burn-in findings §7.3: DD13 (config-on-empty-dir tripwires) + DD14 (create-project) — DD13/DD14 need no site fixture, only ddev + composer | 0.5 d |
| 3 | Makefile/CI workflow + test-workflows + docs | 0.5–1 d |
| 4 | burn-in on this workspace (rootful + rootless outer layouts), matrix knob `DDEV_VERSION` for new ddev releases | 0.5 d |
| 1 | runner skeleton + golden-image build/quiesce/commit/boot (§4) + DD0–DD2 | 1–2 d |
| 2 | full catalog DD3–DD9 + `--fresh`/TTL knobs | 1 d |
| 2b | real-site tier: fixture intake (`tests/e2e/fixtures/camino/`, harvested 2026-08-22), warm-up integration + DD10–DD11 | 1 d |
| 2c | git-flow tier: `make-bare-origin.sh` generator + DD12 | 0.5 d |
| 2d | burn-in findings §7.3: DD13 + DD14 (tripwire pairs) | 0.5 d |
| 3 | Makefile/CI workflow + test-workflows + docs | 0.5–1 d |
| 4 | burn-in on this workspace (rootful + rootless outer layouts), matrix knob `DDEV_VERSION` | 0.5 d |

Expected wall times (workspace, rootless outer daemon): first build 5–12 min
(image pulls dominate; real-site warm-up adds `composer install` + import,
Expand Down
14 changes: 8 additions & 6 deletions docs/design/ddev-working.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,11 @@ stays). `DEFAULT_USER` stays auto-detected (`SUDO_USER`), never asked.
model (soft-only)" section with the trade-offs from §2.1; updated install
question walkthrough; migration instructions.
- `README.md`: trim feature list to the four goals in §2.
- `docs/design/docker-rootless.md`: rationale section rewritten (UID
separation, not ACL-holding).
- `docs/design/ddev-sandbox.md` + `docs/security/PROOF-1/2/3.md`: add a
status banner "superseded by ddev-working.md (hard deny layer removed)";
keep as historical records.
- `docs/_archive/design/docker-rootless.md` (archived): rationale section
rewritten (UID separation, not ACL-holding).
- `docs/_archive/design/ddev-sandbox.md` +
`docs/_archive/security/PROOF-1/2/3.md` (archived): superseded by
ddev-working.md (hard deny layer removed); kept as historical records.
- `AGENTS.md`: ddev-shim section, self-block section, and audit-log wording
("documents the restrictions applied against it") all become obsolete —
rewrite after implementation lands.
Expand Down Expand Up @@ -314,7 +314,9 @@ Failed to start pc-database-v2: chmod /var/www/vhosts/pc-database-v2/.ddev/.webi
Linux `chmod` requires ownership (or root), so the group-shared `.ddev`
metadata cannot be written. The wrapper's `sudo -u opencode` has no
passwordless root path. This was the collision inventory in
ddev-sandbox.md:56, now realized in the soft-only world.
ddev-sandbox.md:56 (archived:
`docs/_archive/design/ddev-sandbox.md`), now realized in the soft-only
world.

**Decision: one owner for ddev, everywhere.** ddev runs as `opencode` in
EVERY context — the agent natively, and the developer's terminal through a
Expand Down
3 changes: 3 additions & 0 deletions docs/design/project-history-summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ the linked design docs and commit history.
| 0.0.16 | Third-party UIs (OpenChamber) spawn `opencode serve` non-interactively — banner + `Press Enter` + `[Y/n]` broke the managed startup, and sudo's env reset silently dropped `OPENCODE_SERVER_PASSWORD` | **Headless serve mode** in the wrapper (`serve` subcommand: no banner/prompts, diagnostics on stderr, no project-dir check, silent container attach); sudoers `env_keep` adds `OPENCODE_SERVER_PASSWORD` |
| 0.0.17 | Project review findings: predictable `/tmp` backup path (root writes), incomplete project-path blocklist (`/var/log` etc.), TOCTOU on the get.docker.com download, wrapper died on EOF stdin, status.sh crashed on unknown backend under `set -u`, flags after `--projects` were silently dropped, `~` broke under `sudo bash` | **Hardening + quality pass**: mktemp for backup dir + downloads, `/var/cache\|lib\|log\|mail\|spool` blocked, EOF-safe wrapper reads, `sudo -n` socket probes; install flags in any order with fail-fast validation; `PROJECT_TILDE_HOME` for tilde expansion; ShellCheck gate (`make lint`) + contributor pre-flight (`check-host.sh`) + drift/canary guards in CI; exec bits tracked in git; uninstall/status unit suites; verify.sh retired |
| 0.0.18 → 0.0.19 | First field reports from installed machines (issues #17–#21, #14): agent git failed with "dubious ownership" and could not read `.git` (pruned from every baseline); vendor scripts (`vendor/bin/runTests.sh`) bypassed the `ddev()` shell function → ddev ran as the developer → EPERM on `.ddev/`; `ddev launch`/`mailpit`/`phpmyadmin` died on WSL interop (and a dev-side run restarted the project on every launch); the status hosts scan reported vendored `.ddev` dirs and useless `*.ddev.site` names; the developer's `~/.agents`/`~/.claude` skills never reached the opencode home; group baseline over 500+ repos ran minutes in silence | **Field-feedback batch**: `.git` in the group baseline + `safe.directory '*'` for opencode (agent git works, #17); `ddev()` exported + `BASH_ENV` second transport so bash children — even behind `#!/bin/sh` wrappers — run ddev as opencode (#18); browser-command class (`launch`, `mailpit`, `phpmyadmin`, `adminer`, `xhgui`, extensible via `ddev-browser-cmds.conf`) computes the URL as opencode with `DDEV_DEBUG` and opens it as the developer (#20); hosts bridge skips `vendor/`/`node_modules/` and `*.ddev.site`, per-hostname add commands (#21); install migrates `~/.agents` + `~/.claude` into the opencode home (move/copy/skip, #19); shared `fs-baseline.sh` with live per-pass progress counters (#14) |
| 0.0.20 | ddev's settings management re-chmod'ed team projects on every start — the #25 pain persisted as handover churn; TYPO3 `ext_localconf.php` was caught by the broad `*conf.php` deny (#23); `update.sh --only-binary` deleted its own candidate before verification (#24) | **Dev-owned mode** (design: [ddev-dev-owned-projects.md](ddev-dev-owned-projects.md)): kit writes `disable_settings_management: true` into `.ddev/config.yaml` — settings dirs + project root permanently developer-owned (2775/664), no handover churn; TYPO3 carve-out for `ext_localconf.php`; binary-update fixes + `upgrade-opencode` shorthand (#24); least-privilege CI token |
| 0.0.21 | Both e2e suites exercised kit plumbing only (`fake-ddev` stub / raw docker probes) — ddev bugs (#18/#20/#21/#25 classes) surfaced only on real WSL installs; the kit's state was invisible inside the TUI; the wrapper paused on Press-Enter + `[Y/n]` before every start; dev-owned flag hid behind ddev's comment wall, testdata `.ddev` fixtures tripped scans (#28, #29) | **Real-ddev e2e suite** (design: [ddev-e2e-test.md](ddev-e2e-test.md)): `make e2e-ddev` with golden-image cache, DD0–DD14 catalog, camino real-site tier, bare-origin git tier, manual CI workflow (first green run 2026-08-23); flag insertion at config head + testdata skip (#28, #29); sudoers keeps `OPENCODE_SERVER_USERNAME`; **TUI mode line** (kit version + backend state, red danger theme on bypass) + in-TUI bypass warning; wrapper prompt-free |
| 0.0.22 | Ecosystem tools spawning `opencode run`/`acp`/queries broke on the wrapper — banner polluted parsed stdout, project-dir refusal blocked worktree checkouts (#42); no visibility into root-equivalent surfaces beyond docker (#37); review finding: the #19 migration moved `~/.claude` WHOLE, so Claude Code credentials landed in the agent's group-readable home | **Headless wrapper mode** for `serve`/`run`/`acp`/queries (stdout machine-clean, no CWD check, silent container attach) + ecosystem [compatibility matrix](../reference/compatibility.md); **root-equivalent access audit** in `status.sh` (danger groups, `/mnt/wsl` desktop sockets, interop, sudo rules — report-only); skills-only `.claude` migration (`~/.agents` whole, `~/.claude/skills` only — credentials stay with the developer) |

## Retired / backup branches

Expand Down
Loading