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
3 changes: 2 additions & 1 deletion .github/workflows/ticketed-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ jobs:
R: ${{ steps.round.outputs.r }}
SINCE: ${{ steps.clock.outputs.since }}
REVIEW_OUTCOME: ${{ steps.review.outcome }}
BONSAI_URL: ${{ vars.BONSAI_URL || 'https://driver-bonsai-mcp.ngrok.app' }}
BONSAI_URL: ${{ vars.BONSAI_URL }}
BONSAI_TOKEN: ${{ secrets.BONSAI_BEARER_TOKEN }}
run: |
set -euo pipefail
Expand Down Expand Up @@ -289,6 +289,7 @@ jobs:
# above the server's lock-acquire timeout so it always returns a verdict; --retry covers a
# transient 503 BROWSER_BUSY (reassign is idempotent). A hard failure fails the step RED
# (visible) rather than silently dropping the handoff.
: "${BONSAI_URL:?set it to a live receiver — the driver-bonsai-mcp bridge that served /tasks/reviewer-handoff is gone (repo archived 2026-09-11)}"
RESP=$(curl -fsS --retry 3 --retry-delay 30 --max-time 130 -X POST "$BONSAI_URL/tasks/reviewer-handoff" \
-H "Authorization: Bearer $BONSAI_TOKEN" -H "Content-Type: application/json" \
-d "$(jq -n --arg uuid "$UUID" '{uuid:$uuid}')")
Expand Down
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ machinery (round-marker prompt arm, actor carve-out, re-request step) looks dead
gone; it is the designed re-entry point for the Macroscope revise loop
(`docs/macroscope-integration-scope.md` — live, not research). Do not strip it.

Sibling repos: `driver-bonsai-mcp` (the dispatcher) and `driver-agents` (private; canonical Shopify
instructions, pinned by `DRIVER_AGENTS_REF`) — README, *How the three repos fit together*.
Sibling repo: `driver-agents` (private; the dispatcher, plus the canonical Shopify instructions
pinned by `DRIVER_AGENTS_REF`) — README, *How the repos fit together*. `driver-bonsai-mcp`, the
dispatcher until 2026-09-10, was archived 2026-09-11 — every mention of it is history.

## Commands

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ an **immutable commit SHA**; a bot (Dependabot/Renovate) bumps the SHAs as new t
**public** so cross-repo reusable calls resolve from any consuming repo (the org enforces a
selected-actions allowlist at the org/enterprise tier).

## How the three repos fit together
## How the repos fit together

- **workflows** (this repo, public) — the reusable GitHub workflows + this onboarding kit. Fleet
repos carry thin SHA-pinned caller stubs; these run the GitHub side (the implementer and the
Dependabot rails) once an issue exists.
- **[driver-bonsai-mcp](https://github.com/DriverDigital/driver-bonsai-mcp)** — the **pipeline
dispatcher**: a scheduled Actions workflow that triages ready Bonsai tasks, opens those GitHub
issues, and polls the Bonsai status back.
- **[driver-agents](https://github.com/DriverDigital/driver-agents)** (private) — the Shopify
admin-tool wrapper and the canonical operator instructions, cloned at the pinned
`DRIVER_AGENTS_REF`; it was also the box's headless `claude -p` cron runner.
`DRIVER_AGENTS_REF`; also the **pipeline dispatcher** (`pipeline-dispatch.yml`, scheduled) that
triages ready Bonsai tasks, opens those GitHub issues, and polls the Bonsai status back. It was
also the box's headless `claude -p` cron runner.
- **driver-bonsai-mcp** — archived 2026-09-11; it held the dispatcher and the Bonsai bridge server
until 2026-09-10. Mentions of it below are history.

Flow: a Bonsai ticket assigned to **Agents** → the dispatcher triages it and opens a GitHub issue →
the target repo's `claude.yml` implements it and opens the PR → the dispatcher moves the Bonsai
Expand Down
7 changes: 4 additions & 3 deletions docs/figma-mcp-in-ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ access token anywhere. Two mechanisms can deliver it, and **the box uses the sec
**`mcp__claude_ai_Figma__*`**. Loads only under an interactive `claude login`.

**The production box already runs the second one — do not "fix" it by adding a local entry.** The job
pack in `driver-bonsai-mcp/pipeline/` has this wired and the reasoning recorded in `triage.job.env`:
pack in `driver-bonsai-mcp/pipeline/` (archived 2026-09-11 — history) has this wired and the
reasoning recorded in `triage.job.env`:

- `STRICT_MCP=0`, so the leg inherits every MCP server on the box's interactive login.
- **No `CLAUDE_CODE_OAUTH_TOKEN`** — deliberate and load-bearing. A setup-token drops every claude.ai
Expand Down Expand Up @@ -86,8 +87,8 @@ to decide whether to install it. No such path exists for a third-party server.

The triage leg reads the design and **writes what it found into the GitHub issue body**; the
implementer then works from that text and never needs Figma. This is implemented — see the
"Figma-bearing tickets" section of `driver-bonsai-mcp/pipeline/orchestrator.md`, which states the
constraint in its own words: "the agent that writes the code CANNOT see Figma … *you* are the only
"Figma-bearing tickets" section of `driver-bonsai-mcp/pipeline/orchestrator.md` (archived
2026-09-11 — history), which states the constraint in its own words: "the agent that writes the code CANNOT see Figma … *you* are the only
step in the chain that can read the design — put what it needs in the issue body. An issue that just
links Figma sends the implementer in blind, which is worse than escalating."

Expand Down
23 changes: 12 additions & 11 deletions docs/fleet-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,23 @@ Written 2026-08-02 from the v1.7.0 → v1.11.0 waves; kept current through the v
## The fleet

**20 repo@branch pairs** carry kit stubs after the v1.13.0 wave (2026-08-22; verified by a live
audit run across the 23 pairs it enumerates — the 20 targets plus the three that carry no pins —
**51 pins at `f6d25d34`, 72 content matches, zero drift**; the drop from v1.12.0's 69/90 is exactly
audit run across the 23 pairs it enumerated then — the 20 targets plus the three that carried no
pins — **51 pins at `f6d25d34`, 72 content matches, zero drift**; the drop from v1.12.0's 69/90 is exactly
the 18 `bonsai-status-sync.yml` copies the wave deleted). The split matters because two different
numbers are correct depending on the question:

| Set | Size | What it is |
|---|---|---|
| **Repin-wave targets** | **20** | Every pair carrying any kit caller stub — the pairs `tools/fleet-pin-audit.sh` finds pins on (it walks all 23) and `tools/fleet-wave.sh` discovers (by `claude.yml` **or** the Dependabot stubs), and what a pin-only wave must cover — miss one and `--stale` never reads clean. |
| **Repin-wave targets** | **20** | Every pair carrying any kit caller stub — the pairs `tools/fleet-pin-audit.sh` finds pins on (it walks all 22) and `tools/fleet-wave.sh` discovers (by `claude.yml` **or** the Dependabot stubs), and what a pin-only wave must cover — miss one and `--stale` never reads clean. |
| **Full-kit targets** | **18** | Pairs carrying `claude.yml`. (Through v1.12.0 they were also the pairs carrying `bonsai-status-sync.yml`, which the v1.13.0 wave deleted — verified branch-by-branch across all 618 org branches beforehand: zero rows where one was present without the other.) |
| **Difference** | **2** | `Team-Laird@develop`, `The-Gathery@develop` — Dependabot stubs only, neither full workflow. They still need the pin repin. |

Three pairs left the repin-target set at the v1.12.0 wave because their **only** pinned stub was
`pr-first-review.yml`: `driver-agents@main`, `driver-engineering-app@main` (repin targets only between
2026-08-02 and the wave), and `driver-bonsai-mcp@main`. They now carry no caller stub — **no pin
rows, but still content-checked** (the audit compares any fleet file whose basename exists in
`templates/`), so drift in what remains (e.g. the kit `lint.yml`) is still visible.
2026-08-02 and the wave), and `driver-bonsai-mcp@main` — archived 2026-09-11, no longer scanned.
The two live ones carry no caller stub — **no pin rows, but still content-checked** (the audit
compares any fleet file whose basename exists in `templates/`), so drift in what remains (e.g. the
kit `lint.yml`) is still visible.

Palmers contributes **8** of the 18 (one per country branch: `main`, `-au`, `-ca`, `-in`, `-ma`,
`-me`, `-sa`, `-uk`); the other 10 are single-branch repos including Avara.
Expand Down Expand Up @@ -201,7 +202,7 @@ Two things worth knowing about check 3:

- **Exactly two things are normalized away.** First, `SHOPIFY_STORE_NAME` — the one difference a
correctly-waved repo is *supposed* to have. Second, trailing blank lines and the final newline:
the three pairs waved without a final newline are otherwise identical, and permanently-red rows
the two pairs waved without a final newline are otherwise identical, and permanently-red rows
for a byte nobody can act on is how a detector stops being read. Internal blank lines *are*
compared. Everything else that differs is reported, third-party action refs
included: a repo whose Dependabot moved `actions/checkout@v7` to `@v8` ahead of the kit is drift
Expand Down Expand Up @@ -259,16 +260,16 @@ the installed stub — the wave covers it anyway.
`enforce_admins` is `false` fleet-wide, which is what makes direct-push waves work. Two live kit
branches have **no protection at all** — `studio-sulzer@main` and `Team-Laird@develop` (404 on the
protection endpoint). Every other kit branch has a protection object — but **having one is not the
same as requiring a human**, and the gap is wider than those two. Surveyed across all 23 pairs
2026-08-02:
same as requiring a human**, and the gap is wider than those two. Surveyed across all pairs
2026-08-02; `driver-bonsai-mcp@main` has since been archived and is dropped from the counts:

| Pairs | `required_approving_review_count` | |
|---|---|---|
| 13 | `1` | Avara, Driver-Digital-Website, Kissy-Kissy, LaPointe, LittleMe, The-Gathery, client-workspaces, driver-agents, driver-bonsai-mcp, driver-engineering-app, foundrae-blackridge, plugins, vite-plugin-shopify-clean |
| 12 | `1` | Avara, Driver-Digital-Website, Kissy-Kissy, LaPointe, LittleMe, The-Gathery, client-workspaces, driver-agents, driver-engineering-app, foundrae-blackridge, plugins, vite-plugin-shopify-clean |
| **8** | **`0`** | **every Palmers branch** — `main`, `-au`, `-ca`, `-in`, `-ma`, `-me`, `-sa`, `-uk` |
| **2** | **no protection at all** | **`studio-sulzer@main`, `Team-Laird@develop`** |

The kit's onboarding steps assume a human-approver rule exists. On **10** of the 23 pairs it does
The kit's onboarding steps assume a human-approver rule exists. On **10** of the 22 pairs it does
not, so a bot signal alone could satisfy a merge — not the 2 this section used to name.

On this repo, `main` requires **`actionlint`** (set 2026-08-02; before that `required_status_checks`
Expand Down
4 changes: 2 additions & 2 deletions docs/identity-unification-scope.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ mode is selected, `checkContainsTrigger` returns false, and `run.ts:212` logs "N

Three things must move in one commit: the four `contains()` clauses
(`templates/github/claude.yml:94,98,102,104`), a `trigger_phrase` input on the action, and **the dispatcher in
`driver-bonsai-mcp`, which writes `@claude` into every issue body it opens**.
`driver-agents`, which writes `@claude` into every issue body it opens**.

Note `trigger_phrase` **does not exist in this repo today** (`git grep` → zero hits) — the action runs on its
default phrase. So it must be *added* in the same commit, not edited. That is a small but real difference: the
Expand Down Expand Up @@ -364,7 +364,7 @@ permission requirement GitHub does not publish. This must be proven in the pilot
set. **Zero UX change** — humans still type `@claude`.

**Wave 2 — trigger phrase.** Flip to `@driver-digital-agents` in one coordinated commit spanning this repo,
the fleet, and the dispatcher in `driver-bonsai-mcp`.
the fleet, and the dispatcher in `driver-agents`.

**Then the reusable conversion**, which is now materially cheaper: Phase 0 (the OIDC spike) **ceases to
exist**, and the stub no longer needs `id-token: write`.
Expand Down
7 changes: 4 additions & 3 deletions docs/macroscope-integration-scope.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ Still unobserved: a formal REQUEST_CHANGES, and the webhook payloads — keep wa

## The build (Phase 2 — not scheduled)

A webhook receiver owned by **driver-bonsai-mcp** (the repo that holds Bonsai access; the
2026-08-21 sketch is a GitHub App on Vercel — that repo's box-retirement spec, §9). Mapping Maria
A webhook receiver owned by **driver-agents** (the repo that holds Bonsai access; the
2026-08-21 sketch is a GitHub App on Vercel — that repo's
`docs/superpowers/specs/2026-08-21-box-retirement-dispatcher-design.md`, §9). Mapping Maria
sketched:

| Macroscope event | Action |
Expand All @@ -104,7 +105,7 @@ Building blocks that already exist — reuse, don't rebuild:
2026-08-21: the bridge server that carried the old `/tasks/*` endpoints is retired. Phase 2 writes
Bonsai status through the public API (PATCH /public-api/v1/tasks/{uuid} with task_status_id) using
the Agents API key, and triggers the dispatcher via workflow_dispatch { task_uuid } in
driver-bonsai-mcp. The Reviewer custom field is not readable through the public API; the reviewer
driver-agents. The Reviewer custom field is not readable through the public API; the reviewer
comes from the issue body's **Reviewer:** line instead.

Open questions for the build: Macroscope's webhook auth/payload shape — moot if the Check Run agents
Expand Down
2 changes: 1 addition & 1 deletion docs/reusable-conversion-scope.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
different content.

*The `bonsai-status-sync.yml` half of this project shipped at `v1.11.0` (waved 2026-08-02) and was
**retired outright at `v1.13.0`** — the dispatcher in `driver-bonsai-mcp` polls Bonsai status now. Its
**retired outright at `v1.13.0`** — the dispatcher in `driver-agents` polls Bonsai status now. Its
sections have been removed from this document; what remains is the `claude.yml` half.*

> ## Decision — Maria, 2026-08-02: TABLED
Expand Down
4 changes: 2 additions & 2 deletions templates/github/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# GitHub pipeline kit (Phase 2)

Drop-in workflows that connect a DriverDigital repo to the Bonsai → PR pipeline. The pipeline
dispatcher (in `driver-bonsai-mcp`) opens a GitHub **issue** from a ready Bonsai task and
dispatcher (in `driver-agents`) opens a GitHub **issue** from a ready Bonsai task and
`@claude`s it; these workflows take it from there. Bonsai status is polled by the dispatcher — no
workflow here touches it.

Expand Down Expand Up @@ -92,7 +92,7 @@ Requested, approved → Ready for QA) were retired with the review leg at v1.12.
report a trip on a rail with no exit code; see the comment in `claude.yml`). The whole value
rides inside a **single-quoted** CLI token: **no apostrophes anywhere in it** — one apostrophe
silently truncates the prompt instead of erroring. `lint.yml` asserts the quote count.
3. **Issue creation:** the pipeline dispatcher (driver-bonsai-mcp, a scheduled Actions workflow)
3. **Issue creation:** the pipeline dispatcher (driver-agents, a scheduled Actions workflow)
opens issues as the driver-digital-agents PAT, which is what lets `claude.yml` fire on
`issues: [opened]` (the default GITHUB_TOKEN cannot retrigger workflows). Bonsai status is
polled by the dispatcher — no per-repo workflow is involved. The PAT is fine-grained — **All
Expand Down
6 changes: 3 additions & 3 deletions tools/fleet-pin-audit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ LATEST_TAG="${LATEST%% *}"; LATEST_SHA="${LATEST#* }"; LATEST_SHA8="${LATEST_SHA
# 1. SHOPIFY_STORE_NAME — the one difference a correctly-waved repo is SUPPOSED to have. The kit
# ships it empty; Avara carries "avara". Anchored to a line that STARTS with the key, so the ten
# other mentions per file (comments, shell) still compare normally.
# 2. Trailing blank lines and the final newline. Three stub-rails-only pairs (Team-Laird@develop,
# The-Gathery@develop, driver-bonsai-mcp@main) were waved without a final newline and are
# 2. Trailing blank lines and the final newline. Two stub-rails-only pairs (Team-Laird@develop,
# The-Gathery@develop) were waved without a final newline and are
# otherwise byte-identical. That is not drift anyone can act on, and a detector that reports
# nine permanent red rows is a detector nobody reads. Internal blank lines ARE still compared —
# permanent red rows is a detector nobody reads. Internal blank lines ARE still compared —
# awk buffers blanks and only emits them once a non-blank line follows.
kit_normalize() {
sed 's/^\( *SHOPIFY_STORE_NAME:\).*/\1 <per-repo>/' \
Expand Down