@bongos/core 1.17.3 → 1.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/.bongos-core.json +212 -332
  2. package/.devcontainer/healthcheck.sh +0 -0
  3. package/.devcontainer/init-firewall.sh +0 -0
  4. package/.devcontainer/post-create.sh +0 -0
  5. package/GOVERNANCE.md +1 -1
  6. package/README.md +26 -22
  7. package/bin/bongos.js +0 -0
  8. package/config/branding.neutral.json +5 -1
  9. package/docker-entrypoint.sh +0 -0
  10. package/docs/adr/0142-project-context-is-prose-only.md +41 -0
  11. package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +35 -0
  12. package/docs/adr/README.md +6 -0
  13. package/docs/api/openapi.json +1630 -632
  14. package/docs/api-reference.md +50 -15
  15. package/docs/file-map.md +0 -18
  16. package/docs/onboarding/diagrams/05-versioning.mmd +4 -6
  17. package/docs/onboarding/diagrams/assertions.json +5 -9
  18. package/docs/recipes/packaging-the-core.md +13 -0
  19. package/docs/recipes/upgrading-the-core.md +5 -2
  20. package/migrations/039_newcomer_friendly_column.sql +5 -0
  21. package/migrations/102_remove_box_first_provision_approval.sql +4 -0
  22. package/migrations/core_192_github_oauth_tokens.sql +33 -0
  23. package/modules/hall-ui/public/builders.js +37 -0
  24. package/modules/hall-ui/public/goals-page.js +98 -176
  25. package/modules/hall-ui/public/goals.css +183 -0
  26. package/modules/hall-ui/public/goals.html +35 -261
  27. package/modules/hall-ui/public/goals.js +7 -2
  28. package/modules/hall-ui/public/hall-widgets.js +12 -4
  29. package/modules/hall-ui/public/my-projects.html +78 -0
  30. package/modules/hall-ui/public/my-projects.js +142 -0
  31. package/modules/hall-ui/public/scouting.html +45 -0
  32. package/modules/hall-ui/public/scouting.js +73 -0
  33. package/modules/hall-ui/public/settings.css +355 -0
  34. package/modules/hall-ui/public/settings.html +86 -414
  35. package/modules/hall-ui/public/settings.js +96 -35
  36. package/modules/hall-ui/public/style.css +31 -0
  37. package/modules/hall-ui/public/watch.css +184 -0
  38. package/modules/hall-ui/public/watch.html +111 -285
  39. package/modules/hall-ui/public/watch.js +59 -21
  40. package/modules/status-ui/public/explore.html +54 -0
  41. package/modules/status-ui/public/explore.js +67 -0
  42. package/package-lock.json +2 -2
  43. package/package.json +1 -1
  44. package/public-landing/create.html +292 -19
  45. package/public-landing/index.html +11 -76
  46. package/scripts/cron/style_guide_audit.sh +0 -0
  47. package/scripts/gds/api.js +0 -0
  48. package/scripts/gds/architect-audit.js +0 -0
  49. package/scripts/gds/audit-authorship.sh +0 -0
  50. package/scripts/gds/audit-replay.sh +0 -0
  51. package/scripts/gds/box.js +0 -0
  52. package/scripts/gds/capture.js +0 -0
  53. package/scripts/gds/cli-lib.js +11 -5
  54. package/scripts/gds/conductor-dispatch.js +0 -0
  55. package/scripts/gds/coreB-carve-proof.sh +0 -0
  56. package/scripts/gds/db-backup-nightly.sh +0 -0
  57. package/scripts/gds/db-backup-offsite.sh +0 -0
  58. package/scripts/gds/doctor.js +0 -0
  59. package/scripts/gds/grade-smoke.js +0 -0
  60. package/scripts/gds/hooks/pre-push.js +0 -0
  61. package/scripts/gds/install-git-hooks.js +0 -0
  62. package/scripts/gds/lint-migrations.js +102 -0
  63. package/scripts/gds/login.js +42 -10
  64. package/scripts/gds/main-audit.js +0 -0
  65. package/scripts/gds/mirror-redact.js +5 -0
  66. package/scripts/gds/oauth-secret.js +0 -0
  67. package/scripts/gds/onboarding-analyze.js +0 -0
  68. package/scripts/gds/onboarding-ship.js +0 -0
  69. package/scripts/gds/package-core.js +263 -4
  70. package/scripts/gds/paste-token.js +0 -0
  71. package/scripts/gds/portability-smoke-art.sh +0 -0
  72. package/scripts/gds/portability-smoke-memory.sh +0 -0
  73. package/scripts/gds/provision.js +270 -11
  74. package/scripts/gds/publish-manifest.js +15 -0
  75. package/scripts/gds/push-main.js +0 -0
  76. package/scripts/gds/render-ideas.js +0 -0
  77. package/scripts/gds/run-unit-tests.js +38 -14
  78. package/scripts/gds/security-baseline-check.sh +0 -0
  79. package/scripts/gds/session.js +0 -0
  80. package/scripts/gds/setup.js +41 -0
  81. package/scripts/gds/ship.js +126 -32
  82. package/scripts/gds/smoke-batch-claim.sh +0 -0
  83. package/scripts/gds/smoke-batch-release.sh +0 -0
  84. package/scripts/gds/smoke-box.sh +0 -0
  85. package/scripts/gds/smoke-claim-consistency.sh +0 -0
  86. package/scripts/gds/smoke-dependencies.sh +0 -0
  87. package/scripts/gds/smoke-write.sh +0 -0
  88. package/scripts/gds/upgrade.js +147 -5
  89. package/scripts/hall-preview/server.js +18 -1
  90. package/scripts/migrate.sh +10 -0
  91. package/scripts/migrate_cost_ledger.sh +0 -0
  92. package/scripts/render-diagrams.sh +0 -0
  93. package/scripts/security/dep-audit.js +0 -0
  94. package/scripts/setup-builder.js +0 -0
  95. package/scripts/setup-builder.sh +0 -0
  96. package/scripts/snapshots/maybe-render-on-deploy.sh +0 -0
  97. package/src/bongos/auth.js +362 -5
  98. package/src/bongos/db.js +66 -0
  99. package/src/bongos/github-repos.js +93 -0
  100. package/src/bongos/routes/auth.js +93 -11
  101. package/src/bongos/routes/github.js +90 -0
  102. package/src/bongos/routes/instance.js +15 -3
  103. package/src/bongos/routes.js +2 -0
  104. package/src/branding.js +17 -2
  105. package/src/instance-config.js +16 -0
  106. package/src/module-api.js +48 -1
  107. package/tests/branding.mjs +29 -23
  108. package/tests/github_repos_helpers.mjs +91 -0
  109. package/tests/github_token_store.mjs +121 -0
  110. package/tests/idp_device_exchange.mjs +105 -0
  111. package/tests/idp_federation.mjs +100 -0
  112. package/tests/migrations_forward_safe.mjs +86 -0
  113. package/tests/module_api.mjs +1 -1
  114. package/tests/package_core.mjs +246 -1
  115. package/tests/provision.mjs +226 -0
  116. package/tests/pruned_lockfile_integrity.mjs +79 -0
  117. package/tests/ship_ci_deploy.mjs +60 -0
  118. package/tests/upgrade.mjs +254 -5
  119. package/.gitignore +0 -91
  120. package/scripts/hall-preview/fixtures/access-requests.json +0 -1
  121. package/scripts/hall-preview/fixtures/achievements.json +0 -76
  122. package/scripts/hall-preview/fixtures/analytics__builder.json +0 -251
  123. package/scripts/hall-preview/fixtures/audit-log.json +0 -1
  124. package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +0 -1
  125. package/scripts/hall-preview/fixtures/builders__active-claims.json +0 -1
  126. package/scripts/hall-preview/fixtures/builders__directory.json +0 -81
  127. package/scripts/hall-preview/fixtures/builders__roster.json +0 -1
  128. package/scripts/hall-preview/fixtures/goals.json +0 -502
  129. package/scripts/hall-preview/fixtures/goals__25.json +0 -96
  130. package/scripts/hall-preview/fixtures/goals__26.json +0 -67
  131. package/scripts/hall-preview/fixtures/goals__3.json +0 -103
  132. package/scripts/hall-preview/fixtures/goals__35.json +0 -49
  133. package/scripts/hall-preview/fixtures/goals__conflicts.json +0 -154
  134. package/scripts/hall-preview/fixtures/goals__detail.json +0 -96
  135. package/scripts/hall-preview/fixtures/goals__inbox.json +0 -5
  136. package/scripts/hall-preview/fixtures/goals__requests.json +0 -3
  137. package/scripts/hall-preview/fixtures/grades__by-builder.json +0 -1
  138. package/scripts/hall-preview/fixtures/inbox.json +0 -330
  139. package/scripts/hall-preview/fixtures/instance.json +0 -124
  140. package/scripts/hall-preview/fixtures/leaderboard.json +0 -184
  141. package/scripts/hall-preview/fixtures/me.json +0 -476
  142. package/scripts/hall-preview/fixtures/me__recent-ships.json +0 -304
  143. package/scripts/hall-preview/fixtures/override-requests.json +0 -1
  144. package/scripts/hall-preview/fixtures/provisioning__fleet.json +0 -1
  145. package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +0 -1
  146. package/scripts/hall-preview/fixtures/provisioning__instances.json +0 -1
  147. package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +0 -516
  148. package/scripts/hall-preview/fixtures/public__bounty-table.json +0 -37
  149. package/scripts/hall-preview/fixtures/public__cost-summary.json +0 -742
  150. package/scripts/hall-preview/fixtures/public__estimation-drift.json +0 -41
  151. package/scripts/hall-preview/fixtures/public__grades.json +0 -50
  152. package/scripts/hall-preview/fixtures/public__progress.json +0 -124
  153. package/scripts/hall-preview/fixtures/public__recent-shipped.json +0 -426
  154. package/scripts/hall-preview/fixtures/public__repo-health.json +0 -160
  155. package/scripts/hall-preview/fixtures/public__repo-info.json +0 -5
  156. package/scripts/hall-preview/fixtures/security__docs.json +0 -1
  157. package/scripts/hall-preview/fixtures/security__reports.json +0 -1
  158. package/scripts/hall-preview/fixtures/sessions__search.json +0 -1
  159. package/scripts/hall-preview/fixtures/tasks.json +0 -2420
  160. package/scripts/hall-preview/fixtures/tasks__claimable.json +0 -2555
  161. package/scripts/hall-preview/fixtures/tasks__detail.json +0 -111
  162. package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +0 -330
  163. package/scripts/hall-preview/fixtures/versions.json +0 -89
File without changes
File without changes
File without changes
package/GOVERNANCE.md CHANGED
@@ -8,7 +8,7 @@ Cloud Bongos is an **AI-first build platform**: a human owner sets scope and the
8
8
 
9
9
  1. **Open, free, and protected from capture.** Cloud Bongos is released as open source under the **GNU AGPL-3.0** ([`LICENSE`](LICENSE)). The AGPL's §13 (Remote Network Interaction) closes the hosted-closed-fork loophole: anyone who runs a modified Cloud Bongos as a network service must offer that service's complete source to its users. This is the anti-monopoly guarantee — the platform stays a commons even when it is *operated*, not just when it is shipped.
10
10
 
11
- 2. **Non-profit.** The project is **not monetized from its contributors**. No one pays to contribute, and no contribution is resold by the project as a proprietary add-on. The in-platform credit/example economy is an **instance-internal** mechanism (an instance rewards its own builders from its own budget) — it is not the project monetizing the commons.
11
+ 2. **Non-profit.** The project is **not monetized from its contributors**. No one pays to contribute, and no contribution is resold by the project as a proprietary add-on. The in-platform credit economy is an **instance-internal** mechanism (an instance rewards its own builders from its own budget) — it is not the project monetizing the commons.
12
12
 
13
13
  3. **AI-first.** The expectation is that **AI agents write the code**. This is a documented norm, not a technical gate (see [CONTRIBUTING.md](CONTRIBUTING.md)). The whole methodology — the task lifecycle, the quality grader, the session economy — is designed around agents as the primary authors.
14
14
 
package/README.md CHANGED
@@ -1,10 +1,21 @@
1
- # Example
1
+ # Cloud Bongos
2
2
 
3
- A persistent, shared 16-bit pixel-art world — the e-commerce experience for [Example](https://example.com), powered by [Example](https://example.com).
3
+ **Cloud Bongos is an AI-first software build platform.** A human owner sets scope, direction, and the hard gates (rank, approval, deploy); AI agents claim tasks and do the day-to-day building — code, docs, migrations, reviews. This repository is the **portable core**: the methodology, the Game Development System (GDS) that tracks all work, the platform engine, and a neutral branding template each instance fills in.
4
4
 
5
- Project memory — architecture, scope, V1 limitations, future ideas, session log — lives in [`CLAUDE.md`](./CLAUDE.md). Read it before editing code.
5
+ Cloud Bongos is free software under the **GNU AGPL-3.0** (see [`LICENSE`](./LICENSE)), with non-profit, AI-first governance ([`GOVERNANCE.md`](./GOVERNANCE.md)).
6
6
 
7
- > **Reading this on GitHub?** [`builders.example.com`](https://builders.example.com) is the canonical place to read project docs — task refs (`#NNN`) render as working links there. GitHub is the code host: great for diffs and PRs, but a bare `#NNN` here links to a GitHub issue and 404s.
7
+ > **Provenance.** This core was extracted with fresh history from **Example** — the reference instance, built by Hermeslines, and the first project to run on Cloud Bongos. Example now consumes this core as a pinned dependency, the same shape as any other instance. The extraction is a redacted subtree (no instance secrets, IPs, or private identity); the exact pin — `core_version`, `source_commit`, `tree_sha256` — is recorded in [`.cloudbongos-core.json`](./.cloudbongos-core.json).
8
+
9
+ The durable framing for AI agents — methodology, working rules, session protocol, architecture — lives in [`CLAUDE.md`](./CLAUDE.md). Read it before editing code.
10
+
11
+ ## What's in here
12
+
13
+ - **The GDS** (`src/`, `modules/`, `scripts/gds/`) — the build state machine: tasks, claims, versions, goals, dependencies, the claim→ship→grade→credit lifecycle, and the `/builder-*` CLI.
14
+ - **Platform modules** (`modules/`) — lifecycle, grading, economy, memory, onboarding, ideas, sessions, autonomy, security, the builders' hall + status dashboard, dev-box, and Discord integration. Each is configurable (and most are toggleable) per instance.
15
+ - **Neutral branding template** (`config/*.neutral.json`, `docs/project-context.template.md`) — the identity scaffold a new instance fills in ([`docs/branding-contract.md`](./docs/branding-contract.md)). The vanilla pack in `config/branding.neutral.json` is the identity Cloud Bongos itself runs on.
16
+ - **Methodology + decisions** (`CLAUDE.md`, `docs/adr/`, `docs/recipes/`, `.claude/skills/`).
17
+
18
+ > **This is the core, not a ready-to-run instance.** An instance layers its own content, branding, and product modules on top of a pinned core (that is the whole point of the two-repo model). `server.js` and some entrypoints still reference the reference instance's product layer; standing the core up standalone — a clean vanilla boot — is deliberately the job of the consumer path, proven first by the next instance to install it.
8
19
 
9
20
  ## New builder? Start here
10
21
 
@@ -14,16 +25,11 @@ You'll need three things on your machine first:
14
25
 
15
26
  - **Git** — the tool that copies the code down. Check with `git --version`; install from [git-scm.com](https://git-scm.com/downloads) if it's missing.
16
27
  - **Claude Code** — your pair-programmer for every session. Download the desktop app at [claude.com/download](https://claude.com/download) (Mac and Windows).
17
- - **A GitHub account with access to this repo** — the project is private, so an Archon must invite you first. Accept the emailed invitation before cloning. (The bootstrap script below also checks for Node ≥ 22 and Python ≥ 3.10, and prints the install command if either is missing — you don't need them installed *before* cloning.)
28
+ - **A GitHub account with access to this repo.** While the repo is private, the owner must invite you first; accept the invitation before cloning. (The bootstrap below also checks for Node ≥ 22 and Python ≥ 3.10, and prints the install command if either is missing.)
18
29
 
19
30
  ### Step 0 — get the project onto your machine
20
31
 
21
- Clone the repo, then `cd` into it. Everything below runs from inside that folder:
22
-
23
- ```sh
24
- git clone https://github.com/example-owner/example.git
25
- cd example
26
- ```
32
+ Clone the repo, then `cd` into it. Everything below runs from inside that folder.
27
33
 
28
34
  ### Step 1 — bootstrap
29
35
 
@@ -36,15 +42,15 @@ One command bootstraps a fresh clone end-to-end — toolchain checks, JS deps, l
36
42
  node scripts/setup-builder.js
37
43
  ```
38
44
 
39
- It checks Node ≥ 22 and Python ≥ 3.10 (prints the install command if either is missing), runs `npm ci`, copies `.env.local.example` to `.env.local` (optionally prompting for your Google AI Studio key — pass `--skip-keys` to leave it blank), and hands off to `node scripts/gds/setup.js` to authenticate against the GDS via the GitHub Device Flow. The script is idempotent: re-running on an already-set-up checkout reports "already done" rather than clobbering.
45
+ It checks Node ≥ 22 and Python ≥ 3.10 (prints the install command if either is missing), runs `npm ci`, copies `.env.local.example` to `.env.local`, and hands off to `node scripts/gds/setup.js` to authenticate against the GDS via the GitHub Device Flow. The script is idempotent: re-running on an already-set-up checkout reports "already done" rather than clobbering.
40
46
 
41
47
  When it finishes, open Claude Code and run `/builder-start` to see what tasks are claimable.
42
48
 
43
49
  ## Secrets scanning
44
50
 
45
- We keep secrets (`.env` files, API keys, private keys) out of the repo with two layers:
51
+ We keep secrets (`.env` files, API keys, private keys) out of the repo with two layers. Both are **instance topology** — the git hook (`.husky/`) and CI (`.github/`) are provided when you stand up an instance and are not shipped in the portable core; the pattern below is the recommended posture:
46
52
 
47
- - **Pre-commit hook** ([`.husky/pre-commit`](./.husky/pre-commit)) — scans your *staged* changes before each commit and aborts if it finds a secret. Activate it **once per clone**:
53
+ - **Pre-commit hook** (`.husky/pre-commit`) — scans your *staged* changes before each commit and aborts if it finds a secret. Activate it **once per clone**:
48
54
 
49
55
  ```sh
50
56
  git config core.hooksPath .husky
@@ -54,20 +60,20 @@ We keep secrets (`.env` files, API keys, private keys) out of the repo with two
54
60
 
55
61
  > **Windows:** git runs the `.husky/pre-commit` hook through the Git-Bash `sh` bundled with Git for Windows, so the hook works if you installed Git for Windows (the usual case). If you don't have a `sh` available, the local hook silently no-ops — CI's full-history TruffleHog scan is then your only gate (and it always runs regardless of platform).
56
62
 
57
- - **CI scan** ([`.github/workflows/secrets-scan.yml`](./.github/workflows/secrets-scan.yml)) — every PR to `main` runs TruffleHog over the **full git history**. This must pass before merge.
63
+ - **CI scan** (`.github/workflows/secrets-scan.yml`) — every PR to `main` runs TruffleHog over the **full git history**. This must pass before merge.
58
64
 
59
65
  ### If a commit is blocked, here's how to investigate
60
66
 
61
67
  1. **Read the output.** The hook prints the offending file(s) and why.
62
- 2. **Is it a real secret?** Then it must never be committed. Remove it from the commit (`git restore --staged <file>`), move the value out of the repo — local secrets go in `.env.local` (gitignored; run `/builder-setup`), production secrets live on the droplet at `/etc/example/`. If it was *already committed in an earlier commit*, the history scan will keep failing until the history is scrubbed — flag this to Lars, since rewriting shared history needs care.
68
+ 2. **Is it a real secret?** Then it must never be committed. Remove it from the commit (`git restore --staged <file>`), and move the value out of the repo — local secrets go in `.env.local` (gitignored; run `/builder-setup`); production secrets live in your instance's secret store, never in the tree. If it was *already committed in an earlier commit*, the history scan will keep failing until the history is scrubbed — flag this to the owner, since rewriting shared history needs care.
63
69
  3. **Is it a false positive?** (e.g. an example key in docs, a test fixture, a Stripe `pk_test_` publishable key.) Add a path regex — one per line — to [`.husky/secrets-allowlist.txt`](./.husky/secrets-allowlist.txt). Both the hook and CI read that allowlist. Keep entries narrow and only add them after confirming the match is genuinely not a secret.
64
70
  4. **Genuine emergency commit** (you're sure it's clean and need to move now): `git commit --no-verify` skips the local hook — but CI will still scan the PR, so this only defers the check, it doesn't bypass it.
65
71
 
66
72
  ## If your CLI starts 401'ing
67
73
 
68
- GDS CLI calls (`node scripts/gds/start.js`, `claim.js`, `ship.js`, etc.) authenticate against `example.com` using a session token at `~/.config/otb/gds-session.json`. Migration 035 (V3.R38 / [#259](https://example.com/builders#/task/259)) put a 1-hour rolling TTL on every session — every authenticated request resets it, so an active session never silently expires. But after a long idle, a token revocation, or an auth-changing deploy (e.g. mig 035 itself when it landed), the local token can stop working.
74
+ GDS CLI calls (`node scripts/gds/start.js`, `claim.js`, `ship.js`, etc.) authenticate against your instance's GDS host using a session token stored under `~/.config/<configDir>/gds-session.json` (the neutral core uses `cloudbongos`; an instance may pin its own). Sessions carry a rolling TTL — every authenticated request resets it, so an active session never silently expires — but after a long idle, a token revocation, or an auth-changing deploy, the local token can stop working.
69
75
 
70
- `apiCall` in `scripts/gds/cli-lib.js` detects HTTP 401 and exits with a clear recovery message rather than letting the failure cascade through downstream calls. When you see that message:
76
+ `apiCall` in `scripts/gds/cli-lib.js` detects HTTP 401 and exits with a clear recovery message rather than letting the failure cascade. When you see it:
71
77
 
72
78
  1. **Re-auth via Device Flow:**
73
79
 
@@ -75,7 +81,7 @@ GDS CLI calls (`node scripts/gds/start.js`, `claim.js`, `ship.js`, etc.) authent
75
81
  node scripts/gds/setup.js --force
76
82
  ```
77
83
 
78
- This pre-flights `GET /api/gds/me` against your existing session before doing anything. If the token is valid, it tells you who you're authenticated as and exits. If the token is dead (401), it falls through to the Device Flow *automatically* — no second `--force` needed. Browser opens to `github.com/login/device`; paste the printed code, authorize as the right GitHub account, you're back.
84
+ It pre-flights `GET /api/gds/me` against your existing session first. If the token is valid, it tells you who you're authenticated as and exits. If the token is dead (401), it falls through to the Device Flow automatically — browser opens to `github.com/login/device`; paste the printed code, authorize as the right GitHub account, you're back.
79
85
 
80
86
  2. **If something feels off and you're not sure what,** run the doctor:
81
87
 
@@ -83,6 +89,4 @@ GDS CLI calls (`node scripts/gds/start.js`, `claim.js`, `ship.js`, etc.) authent
83
89
  node scripts/gds/doctor.js
84
90
  ```
85
91
 
86
- It checks session validity (`/me` returns 200, identity + rank), git plumbing (`core.hooksPath` resolves), repo state (on a branch, working-tree status), and environment files (`.env.local`, `~/.config/otb/env`). Green/red checklist, no arguments. Exits 0 if every check passes, 1 if any red.
87
-
88
- Mirrors the "if a commit is blocked" pattern above: actionable, single command, no guessing.
92
+ It checks session validity (`/me` returns 200, identity + rank), git plumbing (`core.hooksPath` resolves), repo state (on a branch, working-tree status), and environment files. Green/red checklist, no arguments. Exits 0 if every check passes, 1 if any red.
package/bin/bongos.js CHANGED
File without changes
@@ -1,5 +1,5 @@
1
1
  {
2
- "_note": "Cloud Bongos vanilla brand pack — customer 0, the identity Cloud Bongos itself runs on (Amazonprimea is customer 1). The neutral starter every instance resolves over. Light + joyful — 'playing in the clouds', where building software is laying down a beat (ADR 0064). The LOOK ships via theme.ui, injected by src/bongos/serve-internal.js (R57): a Lion-King sunrise backdrop, warm palette, Baloo 2 (display/wordmark) + Quicksand (interface) + Fira Code (code) type, and a bongo-pair favicon. To brand a NEW instance, copy this to config/branding.json and fill it in (docs/branding-fill-prompt.md). Authored by task 1216 / V4.R74. See docs/branding-contract.md.",
2
+ "_note": "Cloud Bongos vanilla brand pack — customer 0, the identity Cloud Bongos itself runs on. The neutral starter every instance resolves over. Light + joyful — 'playing in the clouds', where building software is laying down a beat (ADR 0064). The LOOK ships via theme.ui, injected by src/bongos/serve-internal.js (R57): a Lion-King sunrise backdrop, warm palette, Baloo 2 (display/wordmark) + Quicksand (interface) + Fira Code (code) type, and a bongo-pair favicon. To brand a NEW instance, copy this to config/branding.json and fill it in (docs/branding-fill-prompt.md). Authored by task 1216 / V4.R74. See docs/branding-contract.md.",
3
3
  "identity": {
4
4
  "productName": "Cloud Bongos",
5
5
  "worldName": "Cloud Bongos",
@@ -17,6 +17,10 @@
17
17
  "sandboxPrefix": "sandbox-",
18
18
  "termPrefix": "term-"
19
19
  },
20
+ "auth": {
21
+ "_note": "Cross-site identity (ADR 0141). idp=false → this instance owns its auth outright (its own GitHub app; the default + the self-hosted path). A HOSTED instance sets idp=true and gets its hub origin + client credentials from env (<PREFIX>_HUB_ORIGIN / _HUB_CLIENT_ID / _HUB_CLIENT_SECRET, written by provisioning) so web + CLI sign-in federate through the Cloud Bongos hub with no GitHub app of its own. Identity is federated; authority stays local.",
22
+ "idp": false
23
+ },
20
24
  "repo": { "owner": "", "name": "" },
21
25
  "db": { "database": null },
22
26
  "configDir": "cloudbongos",
File without changes
@@ -0,0 +1,41 @@
1
+ # 0142 — Project context is prose-only; the structured host contract is branding
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-07-13
5
+ - **Deciders:** Claude (acting builder, autonomous session under goal 1000042); owner to ratify. Presented the fork the audit named — build a structured neutral+instance+resolver for project context (mirroring branding), or keep project context prose-only — and chose prose-only.
6
+ - **Task:** [#1002224](https://example.com/builders#/task/1002224) (BONGOS-V1, goal 1000042 — *Harden the Cloud Bongos update pipeline*). Closes hardening item **H11** / finding **F7** of [`docs/audits/update-pipeline-audit.md`](../audits/update-pipeline-audit.md).
7
+ - **Builds on:** [ADR 0062](<redacted>.md) §7 (the core↔host split — CLAUDE.md is portable methodology; host identity lives beside it), the branding contract ([`docs/branding-contract.md`](../branding-contract.md), [`src/branding.js`](../../src/branding.js)), and the agent-doc stub (task 2121).
8
+
9
+ ## Context
10
+
11
+ The audit's finding F7 asked a fair question: **branding** flows as a *structured* contract — `config/branding.neutral.json` (ships) ⊕ `config/branding.json` (publish-excluded) → a validated resolver ([`src/branding.js`](../../src/branding.js)) with env-override precedence and a client-safe projection — while **project context** flows only as *prose*: [`docs/project-context.template.md`](../project-context.template.md) ships (the scaffold `cloudbongos init` fills), `docs/project-context.md` (the instance's filled-in prose) is publish-excluded, plus the `CLAUDE.md`/`AGENTS.md` brand-free stub (task 2121) so a consumer's `node_modules` can't auto-load core project-memory.
12
+
13
+ So the two match at the **publish-boundary** level (a neutral template ships; the instance's filled-in copy is excluded) but NOT at the **structured-resolution** level: there is no runtime resolver, no required-field validation, and no env override for project context — code never reads a merged "project-context object." F7 framed closing that gap as a decision: introduce a parallel structured resolver, or explicitly document prose-only.
14
+
15
+ ## Decision
16
+
17
+ **Project context stays prose-only. We do NOT build a parallel structured neutral+instance+resolver for it.** The structured, code-read host contract is **branding** (and only branding). Project context is deliberately narrative — written for the *AI agents* who read it (product, vision, world, visual style), not for code to consume as fields.
18
+
19
+ Concretely, the contract is:
20
+
21
+ 1. **Machine-readable host identity → branding.** Every instance-identity string code actually renders or injects (names, domains/origins, currency label, cookie/OAuth/dev-box hosts, theme, track set, the project name injected into LLM prompts) lives in the branding contract: `branding.neutral.json` (ships) ⊕ `branding.json` (excluded) → `resolveBranding()` with env precedence and fail-to-vanilla. If a new host string needs to be *code-read*, it goes in **branding**, not a new project-context resolver.
22
+ 2. **Prose host context → project-context, unstructured.** Vision / world / visual-style narrative for agents lives in `docs/project-context.md` (instance, excluded) scaffolded from `docs/project-context.template.md` (ships). It is read by humans and agents, never parsed by code.
23
+ 3. **The boundary is enforced at the publish layer, which already exists.** `isPublishable()` ships the neutral template and excludes the instance's filled copy ([`scripts/gds/publish-manifest.js`](../../scripts/gds/publish-manifest.js)); the `CLAUDE.md`/`AGENTS.md` stub stops a consumer auto-loading core project-memory. No runtime contract is needed because nothing at runtime consumes project context as data.
24
+
25
+ ## Why prose-only over a structured resolver (the trade-off)
26
+
27
+ - **No consumer → YAGNI.** A structured resolver earns its keep only when *code* must read merged, validated fields with env precedence — exactly branding's job, which already exists. Nothing in the platform reads a "project-context object": it is documentation. Building a second resolver, schema, and validation layer for a thing only agents read is speculative infrastructure against the bootstrapped posture ([CLAUDE.md §4](../../CLAUDE.md)).
28
+ - **It matches the core↔host split as already drawn** ([ADR 0062](<redacted>.md) §7): CLAUDE.md is portable methodology; the host authors identity beside it — the *strings code reads* in branding (structured), the *prose agents read* in project-context (narrative). F7 is not a gap in that split; it is the split working as designed.
29
+ - **Redaction stays simple + correct.** Project-context prose flows through the same doc-redaction + publish-exclusion path as every other doc. A structured project-context file would add another schema the no-leak gate and the `init` flow must understand, for no functional gain.
30
+ - **One place to add a host string.** "Where does a new instance-identity value go?" has a single answer — branding — instead of a judgment call between two parallel contracts.
31
+
32
+ ## When to revisit
33
+
34
+ Revisit if a concrete need appears for **code to read project-context as structured data** — e.g. the product runtime (not just agents) must branch on a world/vision field, or an automated flow must validate that an instance filled in required narrative before it can ship. At that point the value under question would really be a *branding* field (add it there), or a genuinely new structured need would justify its own resolver. Until such a consumer exists, prose-only is correct.
35
+
36
+ ## Consequences
37
+
38
+ - **No new code.** No project-context resolver, schema, or env-override layer is added; `src/branding.js` carries a short pointer comment so the next person who wonders "why isn't there a project-context resolver?" finds this ADR at the natural place they'd add one.
39
+ - **Init unchanged.** `cloudbongos init` keeps scaffolding `docs/project-context.md` from the template as prose; there is nothing to validate at standup beyond the existing branding validation.
40
+ - **Publish boundary unchanged.** The template ships, the filled instance prose is excluded, the agent-doc stub stands — already true, now documented as the deliberate contract rather than an accidental asymmetry.
41
+ - **Audit H11 closed** without expanding the surface the update pipeline must keep neutral (which the sibling PROVE-NO-LEAK work — H4/H5/H6 — is separately hardening).
@@ -0,0 +1,35 @@
1
+ # 0143 — Onboarding repo picker & auto-create: broaden the OAuth scope (not a GitHub App), store a short-lived token
2
+
3
+ - **Status:** Accepted — built in task 1002099.
4
+ - **Date:** 2026-07-13
5
+ - **Deciders:** Lars (owner/Archon) chose the credential approach; Claude designed + built.
6
+ - **Task:** [#1002099](https://cloudbongos.com/builders#/task/1002099) · **Goal:** 35 (greenfield onboarding).
7
+
8
+ ## Context
9
+
10
+ The onboarding wizard at `/create` ([public-landing/create.html](../../public-landing/create.html)) had the visitor **type `owner/repo` by hand** (adopt) and, for a fresh project, do a **manual** "New repository on github.com → leave it empty" step. Owner feedback: make it real — let the signed-in user **pick from their own repos** (adopt) and **auto-create the empty repo** (fresh).
11
+
12
+ Blocker: the wizard's GitHub sign-in requests only `read:user` ([auth.js `SCOPE`](../../src/bongos/auth.js)), which cannot list or create repos, and `completeWebFlow` discarded the OAuth token after reading the username. Two ways forward were weighed:
13
+
14
+ - **(A) Broaden the OAuth scope** and act as the user via their own token.
15
+ - **(B) A central "Cloud Bongos" GitHub App** the user installs (fine-grained `Administration:write` to create, `Metadata:read` to list).
16
+
17
+ The existing per-instance GitHub **App-manifest** flow ([ADR 0133](<redacted>.md)) is *not* reusable here — it builds a sign-in-only App with `default_permissions:{}`, one per provisioned instance, not a central repo-acting App.
18
+
19
+ ## Decision
20
+
21
+ **Take (A) — broaden the scope — per the owner's explicit call**, accepting that it is less least-privilege than a GitHub App, in exchange for no install step and a single sign-in. Within (A):
22
+
23
+ 1. **Scope = `public_repo`, not `repo`.** There is no OAuth scope for "create a repo only"; `repo` grants read/write to *all* the user's code (public **and** private) — a serious liability for a token we now persist on an internet-facing tier. `public_repo` lists/creates **public** repos with a much gentler consent screen and a far smaller blast radius. Cloud Bongos instances are open-source / capture-resistant by design, so public is the norm. **Accepted limitation:** private repos can't be listed/adopted or created; revisit to `repo` only if private support is needed.
24
+ 2. **Opt-in per sign-in.** The scope is requested **only** by the wizard, via `?repos=1` on `/auth/web/start` (a `gds_oauth_repos` intent cookie carried to the callback). The builders'-hall web sign-in and the CLI Device Flow stay `read:user`. A single pure `scopeForWebFlow({repos})` is the one place the scope string is decided (unit-tested).
25
+ 3. **Lazy consent.** The step-0 gate sign-in stays identity-only; repo access is requested at **step 2**, when the user reaches the picker/creator — more private, and the "grant access" path is the well-exercised normal path.
26
+ 4. **Token persistence, contained.** The captured `public_repo` token is stored **encrypted** (secret-box, master key in server env only) in `github_oauth_tokens` (migration `core_192`), keyed to the builder, with a **short TTL (1h = one wizard sitting)** and a lazy expiry sweep on read. This lives in **core auth**, not the provisioning module: it is the auth system's *own* handshake token, not a feature's third-party API key (contrast the art module's Gemini key, [ADR 0102](<redacted>.md)), and the provisioning module's charter forbids holding tokens / calling cloud APIs ([ADR 0111](<redacted>.md) §2 / [ADR 0016](<redacted>.md)). Endpoints `GET/POST /github/repos` ([src/bongos/routes/github.js](../../src/bongos/routes/github.js)) read it back, `requireBuilder` + router-wide rate-limited.
27
+ 5. **v1 = the user's own personal repos** (`affiliation=owner`), so `full_name` is unambiguously `login/repo` and org OAuth-policy complexity (an org can restrict/approve OAuth apps; repos silently omitted) is out of scope. Org/collaborator repos are a later enhancement.
28
+ 6. **Progressive enhancement / graceful degrade.** If secret-box is **unconfigured** (`BUILDER_SECRET_KEY` unset), no token is ever stored: `GET /github/repos` returns `503 github_repos_unavailable` and the wizard **keeps the manual owner/repo inputs + the manual create-repo done-step** as the fallback. Onboarding never regresses.
29
+
30
+ ## Consequences
31
+
32
+ - **New surface:** `scopeForWebFlow` + `captureRepoToken` in auth.js; `?repos=1` handling in the web routes; `github_oauth_tokens` (core_192) + `upsert/get/deleteGithubToken` in db.js; `src/bongos/github-repos.js` (raw-fetch `listUserRepos`/`createUserRepo`); `src/bongos/routes/github.js`; the wizard's picker/auto-create UI.
33
+ - **Security posture:** a stored `public_repo` token is a smaller honeypot than `repo`, and it is encrypted at rest, short-lived, and swept — but it *is* new liability the web tier didn't carry before. The 503-fallback means an instance that doesn't configure secret-box simply doesn't get the feature (no plaintext token is ever written).
34
+ - **Consent friction:** a returning user who signed in months ago has only `read:user`; the picker's `repo_scope_required` (403) prompts a one-click reconnect. The sessionStorage draft round-trips through the OAuth hop (same-tab), so no wizard state is lost.
35
+ - **Reversal path:** switching to `repo` (private support) is a one-line scope change; switching to a GitHub App later would supersede this ADR (append a new one, don't edit).
@@ -209,4 +209,10 @@ This keeps the decision history honest and traceable.
209
209
  | 0137 | [Upstream publish policy: `@bongos/core` patches are published MANUALLY (owner-gated), NOT auto-published on merge (task [#2158](https://example.com/builders#/task/2158), BONGOS-V1, goal 26; the SUPPLY half split out of ADR 0136 §5 / task 2150, builds on ADR 0134). Owner chose manual over auto. Decision: the owner runs `package-core.js --publish --live` to cut a release (optional `core-v<version>` git tag as the auditable marker — triggers no CI); `CORE_VERSION` (src/module-api.js) is bumped by hand in-task with a changelog line (provenance stays in git, not a release-tool side effect); NO npm write-token at rest (preserves ADR 0134 tokenless tooling — owner auths at publish time; only the read token exists); the no-leak/mirror-redact gate is already fail-closed inside `package-core.js`, so `--publish` cannot upload a leaking artifact. The ADR 0136 subscription consumes whatever is published; freshness is owner-paced by design. Rejected: auto-publish-on-merge (needs a standing npm write-token as a CI secret — reverses the tokenless posture for little gain at low, deliberate release volume). Revisit as a tag-triggered CI publish when the managed-fleet epic (task 1948) makes the manual step a real bottleneck. Ritual: docs/recipes/private-npm-distribution.md "Cutting a core release".](<redacted>.md) | distribution / npm |
210
210
  | 0138 | [A core-bundled module's external npm deps are declared per-module; the consumer composes them, core stays lean (task [#2160](https://example.com/builders#/task/2160), BONGOS-V1, goal 26; R89 cutover rehearsal finding F2, builds on ADR 0108 + ADR 0083). The discord module ships inside `@bongos/core` but `package-core.js` declares only express+pg, so a consumer that enables discord crashed at boot on missing `discord.js` (the only such case; discord is `default:false`). Owner chose lean-core over hoisting. Decision: core deps stay express+pg; a bundled module declares its own npm deps in `module.json` `dependencies` (schema-validated in `manifest-schema.js`; discord declares `discord.js`); greenfield `bongos init` composes the ENABLED modules' deps into the instance package.json (`enabledModuleDeps`→`buildInstancePackageJson`, existing pin wins, core always set); the R89 cutover preserves the monolith's existing closure ∪ core. Rejected: hoisting `discord.js` into core `optionalDependencies` (installs for EVERY consumer though discord is opt-in — cuts against ADR 0108 lean-core); `peerDependencies` (optional peers aren't auto-installed → crash remains; required peers = hoisting-with-warnings).](<redacted>.md) | modules / distribution |
211
211
 
212
+ | 0139 | [Migrate the platform work-history (tasks/goals/credits/builder identities) from the Example instance DB to the cloudbongos DB — the DATA half of the CB↔OTB split (companion to the R89 code half). Owner-locked: clean move (platform history leaves OTB), game credits stay, identity keyed by `builders.github_id` (balance surfaces on the existing GitHub sign-in, no federation hub), currency number moves + label adapts, near-empty target = clean load. Needs its own ADR because it deliberately crosses the goal-41 "authority stays per-project" line + ADR 0107 §3's deferral. WS-0 (re-provision cloudbongos.com onto core 1.17.3 first) … WS-7; the mover (WS-2) is bespoke — bigint PK renumber + full FK remap, the polymorphic `dependencies` table per-kind, `credit_log` load-with-triggers-off then rebuild `total_credits` from `SUM(delta)`, preserve the `session.token_reward` idempotency index. EXECUTION is owner-gated (WS-4+); nothing runs against production until greenlit; prove on a throwaway copy first.](<redacted>.md) | platform / migration |
213
+ | 0143 | [Onboarding repo picker (adopt) + auto-create (fresh): the `/create` wizard's Home step no longer makes the user hand-type `owner/repo` or manually create an empty repo on github.com (task [#1002099](https://cloudbongos.com/builders#/task/1002099), goal 35). Owner chose to **broaden the OAuth scope** over a central GitHub App (no install step, single sign-in), accepting it is less least-privilege. Within that: scope = **`public_repo`, not `repo`** (no OAuth scope is "create-only"; `repo` grants R/W to ALL the user's code and we now PERSIST the token — `public_repo` still lists/creates public repos with a gentler consent + smaller blast radius; can't do private, revisit only if needed); **opt-in per sign-in** via `?repos=1` (a `gds_oauth_repos` intent cookie → `captureRepoToken`; hall + CLI stay `read:user`; one pure `scopeForWebFlow`); **lazy consent** (asked at step 2, not the gate); token stored **encrypted (secret-box), short TTL (1h), lazily swept**, in **core auth** not the provisioning module (it's auth's OWN handshake token, not a feature key à la ADR 0102; provisioning's charter forbids tokens/cloud-API, ADR 0111 §2 / ADR 0016); v1 **`affiliation=owner`** personal repos only (org policy deferred); **graceful degrade** — secret-box unconfigured → `503` → wizard keeps the manual inputs + manual done-step, onboarding never regresses. New: `github_oauth_tokens` (core_192), `src/bongos/github-repos.js`, `src/bongos/routes/github.js` (`GET/POST /github/repos`, requireBuilder + rate-limited). Not the App-manifest flow (ADR 0133 — sign-in-only, per-instance, no repo perms).](<redacted>.md) | onboarding / auth |
214
+ | 0140 | [cloudbongos.com re-provisioned to the ADR 0108 standalone model, DB-PRESERVING — closing ADR 0139's skipped WS-0 (executed 2026-07-12). The site was a lift-and-shift clone of the `example` repo frozen on stale code — every `/builders/*` asset 404'd — because its pull-deploy silently no-op'd against the unchanged game repo (`origin` was `example-owner/example`, not a cloudbongos instance); it had never run the restored code. WS-0's original fresh-DB re-provision would now WIPE the migrated history/balances, so a build-alongside-then-flip variant was used: a dedicated private `cloudbongos/cloudbongos-instance` repo (lean config over the neutral brand + a pinned `@bongos/core@1.17.3`), materialized beside the untouched old checkout, proven on a spare port against the live DB (migrate = clean no-op; leaderboard read migrated balances), then `cloudbongos.service` flipped to the instance + engine and the ADR 0129 pull-timer repointed at the instance repo. Engine source stays authoritative at `example-owner/cloud-bongos` (not relocated); verified DB backup + retained old checkout/unit/deploy-script give instant rollback. Enabled org-wide deploy keys on the `cloudbongos` org so the box's read-only deploy key could attach.](<redacted>.md) | infra / Cloud Bongos |
215
+ | 0141 | [Cross-site identity — cloudbongos.com becomes a federated identity provider (the "hub") so one platform account reaches any hosted project's builders hall, browser AND CLI, with no second GitHub sign-in (Goal 41 design of record; task [#1002082](https://cloudbongos.com/builders#/task/1002082); implemented across [#1002106](https://cloudbongos.com/builders#/task/1002106)–[#1002115](https://cloudbongos.com/builders#/task/1002115)). Core principle: **identity is federated, authority is not** — the hub carries identity ONLY (github_id, login, display name, avatar), never rank/credits/admission, so [ADR 0016](<redacted>.md)'s self-owned-authority boundary is preserved by construction. Federation is opt-in + reversible via a config switch (`auth.idp`): a hosted instance provisioned with `auth.idp` + `<PREFIX>_HUB_*` routes web sign-in through the hub's `/sso/authorize`→`/sso/token` (OAuth authorization-code, single-use 60s codes, server-to-server client-secret redemption) and CLI sign-in through the hub's device flow + an audience-scoped Ed25519-signed assertion verified offline at a new `/auth/device/exchange`; a self-hosted instance leaves `auth.idp` unset and keeps owning its own GitHub app (the direct-GitHub path, unchanged fallback). Adds a hub `platform-identity` module (accounts / sso_clients / sso_authorization_codes / projects / project_memberships / builder_project_activity), a project→hub membership check-in inside upsertBuilder (coarse role, never rank), a My Projects view with project-executed join/leave, a curated public Explore showcase, per-builder cross-project activity rollups, and an Archon-only cross-project scouting view (upgrading the coarse [ADR 0127](<redacted>.md) fleet gauges to a github_id-keyed store). Two credential types by design: per-client hashed secret (instance→hub server-to-server auth) + a hub Ed25519 keypair (CLI assertions, asymmetric so one instance can't forge for another). Was scoped as "ADR 0135"; that number was reassigned, so it lands here as 0141.](<redacted>.md) | auth / Cloud Bongos identity |
216
+ | 0142 | [Project context is prose-only; the structured host-identity contract is branding (audit H11 / finding F7; task [#1002224](https://example.com/builders#/task/1002224), goal 1000042). Branding flows as a structured neutral⊕instance→validated-resolver contract because CODE reads those strings; project context (vision/world/visual-style in `docs/project-context.md`, scaffolded from the shipped `docs/project-context.template.md`) is deliberately narrative — read by AI agents, never parsed by code — so it stays prose-only with no parallel resolver/schema/env layer (YAGNI: no consumer; branding already covers code-read strings; the publish boundary + the CLAUDE.md/AGENTS.md stub already enforce the split at the file level per [ADR 0062](<redacted>.md) §7). A new host value that code must read goes in branding, not a new project-context resolver. Revisit only when code (not agents) must read project context as validated, structured data.](<redacted>.md) | core / host-split |
217
+
212
218
  > ⚠️ **Numbering collision (known):** two ADRs share `0008`. The numbers were assigned in parallel sessions before the lock could be enforced. The files are kept under their existing filenames to preserve git history, but the table disambiguates them as `0008-a` / `0008-b`. New ADRs should resume at `0040` to avoid further collisions. (`0024` is also a real on-disk duplicate: the cloneable-repo/local-first-memory ADR and the multi-agent-system-architecture ADR were both numbered `0024` in parallel; both keep their filenames, disambiguated as `0024-a` / `0024-b` like `0008`. Likewise `0025` ended up with two on-disk files — the offsite-backup ADR and the structured-criterion↔task-link ADR — both kept under their existing filenames and disambiguated as `0025-a` / `0025-b`; separately, the BFG ADR had also claimed `0025` on 2026-05-30 and yielded to `0026`. A third happened 2026-06-06: `0036` was claimed in parallel by the builders-subdomain ADR ([#726](https://example.com/builders#/task/726)) and this Discord-channels ADR ([#727](https://example.com/builders#/task/727)); the Discord-channels ADR yielded to `0037`. A fourth landed 2026-06-10: `0044` was claimed in parallel by the palette-replacement ADR and the per-box game-preview ADR ([#897](https://example.com/builders#/task/897)); both keep their filenames, disambiguated as `0044-a` / `0044-b` like `0008`. A fifth was caught pre-land 2026-06-13: `0050` was claimed in parallel by the device-flow-admission ADR ([#1000](https://example.com/builders#/task/1000)) and the sandbox-for-everyone ADR ([#1001](https://example.com/builders#/task/1001)); the latter yielded to `0052` before merging, so there is no `0050` duplicate. A sixth was caught pre-land 2026-06-21: the tool-agnostic-design-layer ADR ([#1375](https://example.com/builders#/task/1375)) first collided at `0079` with the value-gated-autonomous-engagement ADR, then at `0080` with the llm-cache-api-transport ADR (both part of the 0075–0080 LLM-cost-reduction series, landed on `main` in parallel); it yielded to `0081` before merging, so there is no `0079`/`0080` design-layer duplicate. A seventh landed 2026-06-23: `0084` was claimed in parallel by the auto-derived-per-task-rank-floor ADR and the remove-default-spend-cap ADR (task 1499); the rank-floor ADR landed on `main` first, so the spend-cap ADR yielded to `0085`, leaving no `0084` duplicate. An eighth landed 2026-06-27: `0095` was claimed in parallel by the borrowed-memory-and-retrieval-concepts ADR (PR #459, landed first) and the cross-agent-context-management ADR ([#1651](https://example.com/builders#/task/1651), PR #460); both keep their filenames, disambiguated as `0095-a` / `0095-b` like `0008`. These two are companions — `0095-a` adopts the memory/retrieval concepts and explicitly defers the grep-vs-semantic question to `0095-b`.)