diff --git a/README.md b/README.md index 53e1c92d4..af2c5bafb 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ capabilities, three outputs, one shared library, one build. | **One app nests every map** — and each stays embeddable on its own | [capability 5](#capability-5--app-shell-the-research-gallery) · `bun run check:composite-reg` | | **5 capabilities, every one shippable in every output** | `bun run verify:5-caps` | | **Shared library, private plugins** — reuse without breaking each other | `bun run check:library-index` | -| **One owner per plugin, a second reader for every change, one landing at a time** | [agent swarm](#build-it-with-an-agent-swarm) | +| **One owner per plugin, a second reader for every change, one merge at a time** | [agent swarm](#build-it-with-an-agent-swarm) | ## For vibe coders: build, open the Studio, embed a map @@ -695,50 +695,63 @@ your own page, set `"locale"` in its `profile-config`. Arabic reads right to lef ## Build it with an agent swarm **Many AI agents can build many plugins at once without breaking each other's work.** Every plugin -has one agent that owns it, and changes are added to `development`, the shared working version, one -at a time. `main` is the production version: it moves only when you publish a release. +has one agent that owns it, and the work moves through three kinds of branch: + +- **The pilot branch (`development`)** is the shared working version. A development server with hot + reload follows it, so each change that lands can be seen there within about 15 seconds. +- **The landing branch (`main`)** is production. It moves only when you publish, and the production + server rebuilds from it. +- **PR branches** hold one feature each. They start from the landing branch and land on the pilot + branch, one at a time, after the checks pass. **Bring your own harness.** dx-maps works with whatever AI coding agent or agent harness you already use. The repo gives you the branch strategy below, the checks (`bun run gates:pre`) and the Plugin -Studio; it does not ship a harness. Roles such as a coordinator that puts the landings in order, or a +Studio; it does not ship a harness. Roles such as a coordinator that puts the merges onto the pilot in order, or a gate-keeper that reads each change before it lands, are jobs your harness gives to its agents. -![The delegation model: development at the centre behind a landing lock, inside the Plugin Studio; eight plugins around it, each owned by one agent; a coordinator and a gate-keeper over the agents; below, how a change lands in four steps, and the three outputs](documentation/readme-images/delegation-model.png) +![The delegation model: the pilot branch (development) at the centre behind the pilot lock; publishing to the landing branch (main) and its outputs below it; inside the Plugin Studio; eight plugins around it, each owned by one agent; a coordinator and a gate-keeper over the agents; below, how a change lands in four steps, and the three outputs](documentation/readme-images/delegation-model.png) [Open the diagram full size](documentation/readme-images/delegation-model.png): on a phone its small text needs it. ### Set up the branch strategy -1. **`main` is production.** It moves only when you publish a release (step 7). -2. **`development` is the shared working branch.** Create it once, from `main`: +1. **The landing branch (`main`) is production.** It moves only when you publish (step 7). +2. **The pilot branch (`development`) is the shared working branch.** Create it once, from `main`: ```bash git fetch origin && git switch -c development origin/main && git push -u origin development ``` -3. **One branch and worktree per plugin agent**, from `origin/development`, then install once in each: +3. **One PR branch and worktree per feature**, each started from the landing branch, then install + once in each: ```bash - git worktree add -b regions/work ../dx-maps-regions origin/development - git worktree add -b upg100/work ../dx-maps-upg100 origin/development + git worktree add -b regions/work ../dx-maps-regions origin/main + git worktree add -b upg100/work ../dx-maps-upg100 origin/main cd ../dx-maps-regions && bun install --frozen-lockfile ``` -4. **One preview server per agent, each on its own port:** +4. **One preview server per agent on your own machine, each on its own port** (in the cloud, the one + pilot server below takes this role): ```bash bun x vite --port 5301 --strictPort # the next agent uses 5302, and so on ``` -5. **Land one at a time, through a lock.** Catch up with `development`, run the checks, and push only - if nothing fails (`gates:pre` exits non-zero when a check fails, so the push never runs then): +5. **Land on the pilot one at a time, through a lock.** Inside the lock, merge your PR branch into a + throwaway copy of the pilot branch, run the checks, and push that merge only if nothing fails + (`gates:pre` exits non-zero when a check fails, so the push never runs then). Your PR branch itself + stays one feature on the landing branch; only the pilot gets the merge: ```bash flock /tmp/dx-maps-development.lock sh -c ' - git fetch origin && git rebase origin/development && - bun run gates:pre && git push origin HEAD:development' + git fetch origin && git switch --detach origin/development && + git merge --no-edit regions/work && + bun run gates:pre && git push origin HEAD:development + git switch regions/work' ``` - `flock` guards one machine. Agents on several machines need a shared lock, such as one your + If the merge stops on a conflict, run `git merge --abort`, fix the clash on your PR branch and land + again. `flock` guards one machine. Agents on several machines need a shared lock, such as one your harness provides. 6. **One agent owns the full build**; the others build only their own plugin: ```bash BUILD_ALLOW=1 bun run build # the build owner: every plugin BUNDLE= bun x vite build && bun run tree && bun run fix:sri # everyone else: one plugin ``` -7. **Release:** fast-forward `main` to a `development` commit that passed the checks, tag it, and +7. **Publish:** fast-forward the landing branch to a pilot commit that passed the checks, tag it, and deploy from the tag: ```bash git fetch origin && git switch main && git merge --ff-only origin/main @@ -749,6 +762,20 @@ gate-keeper that reads each change before it lands, are jobs your harness gives The tag's `public/dx-maps/` folder is the built site: deploy that ([how to deploy](./documentation/DEPLOY.md)). +### Developing in the cloud with a swarm + +Keep the repository on a forge you host yourself: a swarm pushes often, and on a public host one wrong +push publishes work you did not mean to share. Give each app two servers: a **pilot server** that +follows the pilot branch with hot reload, and a **landing server** that rebuilds from the landing +branch. The cloud container in `deployment/cloud/` runs both today (`BRANCH=development` for the pilot server, +`PRODUCTION_BRANCH=main` for the landing server; `BRANCH` defaults to `main`). One pilot server per app, rather +than one per pull request, keeps the memory the same however many pull requests are open. Each +developer can still build on their own machine with the Plugin Studio and push their branch. + +Planned, not built yet: switching the pilot server to show one pull request at a time (with a table of +the open pull requests under it), and rebuilding the landing branch from the accepted pull requests in +order, so a rejected one is simply left out of the next rebuild. + How to contribute, and the bar for shared code: [documentation/CONTRIBUTING.md](./documentation/CONTRIBUTING.md). Taking contributions from a contributor's own forge into your GitHub repository: [documentation/contribute/TUTORIAL.md](./documentation/contribute/TUTORIAL.md). Diagram source: [`delegation-model.svg`](./documentation/readme-images/src/delegation-model.svg). @@ -766,13 +793,13 @@ So the project works like a busy kitchen: 1. **Each agent works in its own branch and copy of the project** — its own counter, so nobody bumps anybody. One owner per plugin, and one per shared file. -2. **Only one change lands at a time.** Whoever holds the *landing lock* first catches up with - everyone else's latest work, fixes any clash itself and runs every check; the change goes into - `development` only if nothing fails. `development` always works. -3. **Someone keeps order.** A coordinator can put the landings in order, and a gate-keeper can read +2. **Only one change lands at a time.** Whoever holds the *pilot lock* first catches up with + everyone else's latest work, fixes any clash itself and runs every check; the change goes into the + pilot branch only if nothing fails. The pilot branch always works. +3. **Someone keeps order.** A coordinator can put the merges onto the pilot in order, and a gate-keeper can read each change by its content before it lands. Your harness gives these jobs to its agents. -4. **`main` moves only when you publish a release**, after the checks pass on that exact version. - A preview can follow `development`; the published site follows `main`. +4. **The landing branch moves only when you publish**, after the checks pass on that exact version. + The pilot server follows the pilot branch; the production server rebuilds from the landing branch. That's how many plugins get built at the same time, in one project, without the maps breaking. @@ -784,12 +811,12 @@ That's how many plugins get built at the same time, in one project, without the | Word | In plain terms | |---|---| | **repo** | the project folder, with its full history | -| **development** | the shared working version: every agent's change is added here, one at a time | -| **main** | the production version: it moves only when `development` is published | +| **development** (the pilot) | the shared working version: every agent's change is added here, one at a time | +| **main** (the landing) | the production version: it moves only when `development` is published | | **worktree** | a private copy of the project for one agent to work in | | **merge conflict** | two changes touched the same lines; someone has to decide how to combine them | -| **rebase** | catching your work up with everyone else's latest before adding it | -| **landing lock** | only one change lands on `development` at a time; its holder catches up and runs every check first | +| **merge** | combining your branch with everyone else's latest work; here it happens inside the pilot lock, in a throwaway copy of the pilot | +| **pilot lock** | only one change merges onto `development` at a time; its holder catches up and runs every check first | | **tag** | a fixed name for one release commit, such as `v1.0.0`, so you can always deploy exactly it | diff --git a/documentation/readme-images/delegation-model.png b/documentation/readme-images/delegation-model.png index 3711c69b1..ad16d0da6 100644 Binary files a/documentation/readme-images/delegation-model.png and b/documentation/readme-images/delegation-model.png differ diff --git a/documentation/readme-images/src/delegation-model.svg b/documentation/readme-images/src/delegation-model.svg index 8e8e63e5e..a773495cc 100644 --- a/documentation/readme-images/src/delegation-model.svg +++ b/documentation/readme-images/src/delegation-model.svg @@ -10,7 +10,7 @@ -How dx-maps is built: one owner per plugin, one landing at a time +How dx-maps is built: one owner per plugin, one merge at a time @@ -29,8 +29,8 @@ -LANDING LOCK -ONE LANDING AT A TIME +PILOT LOCK +ONE MERGE AT A TIME @@ -38,9 +38,10 @@ -development -every change -lands here +pilot +development +every change +lands here PLUGINS AGENTS @@ -121,14 +122,14 @@ coordinator gate-keeper -a coordinator puts the landings in order; +a coordinator puts the merges in order; a gate-keeper checks each one by its content one owner per plugin, in its own branch · a second reader for every change -development — shared branch +pilot branch (development) -landing lock — one at a time +pilot lock — one at a time Plugin Studio — the one repo @@ -138,9 +139,9 @@ agent — owns one plugin -coordinator — orders landings +coordinator — orders merges -gate-keeper — checks landings +gate-keeper — checks each merge How a change lands — one at a time, so many plugins can be built at once @@ -163,21 +164,21 @@ 3 One at a time -in the lock: merge development, +in the lock: merge the pilot, rebuild, run every check; push only if nothing fails → 4 -Promote to main -main is production: it moves -only when the owner approves, +Publish to landing +landing (main), production: +moves only when the owner approves, after full checks on that version -main → ONE build → one web folder → three outputs -the dev preview follows development · the published site follows main +landing (main) → ONE build → one web folder → three outputs +the pilot server follows development · the production server rebuilds from main OUTPUT 1 The web folder