Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
32 changes: 17 additions & 15 deletions .agents/skills/conduct/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ Do not spawn a one-agent "fleet."
- **Tracks implement by default.** Hand `orchestrate` only for clear parallel
ROI inside a track. Sequential slices → one implementer.
- **Risk posture in every kickoff.** Pre-launch / small-N: evidence or canary
gates, soak ≤1h unless the user opts in. No 24h calendar gates for
reversible steps. Production / irreversible: say so and raise the bar.
gates, soak ≤1h unless the user opts in. No 24h calendar gates for reversible
steps. Production / irreversible: say so and raise the bar.
- **Expand owns contract.** No `STATUS: done` after expand-only — same kickoff
or a scheduled wake with an owner.
- **Stop when the goal is met.** Cleanup/drop is a later ask unless the user
Expand All @@ -45,9 +45,9 @@ Do not spawn a one-agent "fleet."
## Invariants

**PR ownership.** Every code-changing agent pushes and creates/updates its own
PR via Cursor Cloud `ManagePullRequest` (Kent C. Dodds account) before its
final response. Never have Kody/workflows/github create the initial PR. State
this in every kickoff.
PR via Cursor Cloud `ManagePullRequest` (Kent C. Dodds account) before its final
response. Never have Kody/workflows/github create the initial PR. State this in
every kickoff.

**Report-back (wake-ups, not polling).** End of every run — done, partial, or
blocked — the agent wakes the conductor:
Expand All @@ -56,12 +56,13 @@ blocked — the agent wakes the conductor:
import { createRun } from 'kody:@kentcdodds/cursor/runs'
await createRun({
agentId: '<CONDUCTOR_AGENT_ID>',
prompt: '<track> report: STATUS; shipped (PR links); evidence; remains + gate times.',
prompt:
'<track> report: STATUS; shipped (PR links); evidence; remains + gate times.',
})
```

Get your id from cursor-cloud `run-info` and paste it into kickoffs. Also keep
a `## Conductor report` section on each PR (durable record).
Get your id from cursor-cloud `run-info` and paste it into kickoffs. Also keep a
`## Conductor report` section on each PR (durable record).

Topology: `createRun` wake-ups work only if the conductor is an API-created
cloud agent. An interactive chat conductor rejects them (400) — use Discord (or
Expand All @@ -80,8 +81,8 @@ await kody.job_schedule({
})
```

Schedule the same against your own agent id so the program survives session
end. Cancel superseded jobs with `job_delete`.
Schedule the same against your own agent id so the program survives session end.
Cancel superseded jobs with `job_delete`.

## Loop

Expand All @@ -90,18 +91,19 @@ end. Cancel superseded jobs with `job_delete`.
3. Partition by **file conflict**, not theme. Name each track's out-of-scope
(what siblings own). One track after partition → demote.
4. Size agents: implementer by default; `orchestrate` only when fan-out pays.
5. State shipping policy + risk posture + PR invariant + report-back (with
your real agent id) + falsifiable done-definition in every kickoff.
6. Dispatch, then **end your turn**. Wake-ups/jobs drive the loop. Poll only
for silent agents. Verify claims against main before acting.
5. State shipping policy + risk posture + PR invariant + report-back (with your
real agent id) + falsifiable done-definition in every kickoff.
6. Dispatch, then **end your turn**. Wake-ups/jobs drive the loop. Poll only for
silent agents. Verify claims against main before acting.
7. Nudge idle agents with `createRun` (409 while mid-run — retry or schedule).
New scope → nearest idle owner; spawn only for new territory.
8. Final QA is yours — grep main, check deploys. Never report done from claims.

## Companions

Load with `skill_get` and embed when useful: `orchestrate` (in-track fan-out),
`ship-pr` (merge authority). Skip when the track is small or PRs are review-only.
`ship-pr` (merge authority). Skip when the track is small or PRs are
review-only.

## Spawn sketch

Expand Down
9 changes: 5 additions & 4 deletions .agents/skills/orchestrate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ description: >
Orchestrate sub-agents for large tasks inside a single environment: plan,
delegate coding to cheap/fast models, parallelize the critical path, keep
reviews lean, and close every loop. Use when acting as an orchestrator or
writing a kickoff for one. Prefer implement when fan-out does not clearly
pay. For multi-environment fleets, use conduct instead.
writing a kickoff for one. Prefer implement when fan-out does not clearly pay.
For multi-environment fleets, use conduct instead.
---

# Orchestrate
Expand All @@ -22,7 +22,7 @@ optimized for cheap/fast execution.
beat one implementer. Sequential slices → implement (or one implementer).
- **No orchestration theater.** Ban review → recheck → final → CI-watch chains
per slice. **One** hard-to-reverse review before merge.
- **One CI wait path** — parent `gh pr checks` *or* a ci-watcher, not both.
- **One CI wait path** — parent `gh pr checks` _or_ a ci-watcher, not both.
- **Targeted tests while iterating;** full validate before ready-for-review.
- Close loops yourself — don't leave humans as the relay.

Expand All @@ -31,7 +31,8 @@ optimized for cheap/fast execution.
1. Plan, delegate, integrate, ship. Bulk-code only when fan-out costs more.
2. Frontier model orchestrates; cheap/fast models implement (prefer Grok 4.5 /
`composer-2.5-fast` for mechanical work).
3. Critical path first; parallelize non-conflicting files; serialize shared ones.
3. Critical path first; parallelize non-conflicting files; serialize shared
ones.
4. **You do final QA.** Never declare done from sub-agent claims.

## Fan-out (when it pays)
Expand Down
13 changes: 12 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
fi

if git diff --name-only "${DEPLOY_SHA}^" "${DEPLOY_SHA}" | grep -E \
'^(packages/backup-control-plane/|packages/shared/src/backup-)'; then
'^(\.github/workflows/deploy\.yml|tools/ci/backup-resources|packages/backup-control-plane/|packages/shared/src/backup-|packages/shared/src/mailbox-pre-drop-approval\.ts)'; then
echo "deploy_backup_control_plane=true" >> "$GITHUB_OUTPUT"
echo "Backup control plane deploy: path filter matched."
else
Expand Down Expand Up @@ -390,6 +390,17 @@ jobs:
- name: 📥 Install Dependencies
run: npm ci

- name: 🔒 Reconcile DR backup retention policies when authorized
env:
DR_BACKUP_ADMIN_TOKEN: ${{ secrets.DR_BACKUP_ADMIN_TOKEN }}
BACKUP_SOURCE_ACCOUNT_ID: a99ee2e72728dd52902ef288b7b1447d
BACKUP_DESTINATION_ACCOUNT_ID: ${{ secrets.DR_BACKUP_ACCOUNT_ID }}
BACKUP_R2_BUCKET_NAME: kody-production-backups
BACKUP_WORKER_NAME: kody-production-d1-backups
BACKUP_SOURCE_D1_ALLOWLIST: >-
[{"uuid":"8c1014d1-6b41-4695-a0a2-159071f0f919","name":"kody"}]
run: node tools/ci/backup-resources-reconcile-cli.ts

- name: ☁️ Deploy backup control plane to DR account
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.DR_DEPLOY_TOKEN }}
Expand Down
81 changes: 67 additions & 14 deletions docs/contributing/disaster-recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ the kody-named resources below — they are intentional cross-account leftovers.
**DR / backup stack (this runbook):**

- Worker `kody-production-d1-backups` (hourly + nightly crons)
- Workflows `kody-production-d1-backup` and `kody-production-dr-restore`
- Workflows `kody-production-d1-backup`,
`kody-mailbox-legacy-graph-pre-drop-backup`, and `kody-production-dr-restore`
- Locked R2 bucket `kody-production-backups`
- Custom domain `kody-dr.kentcdodds.com`

Expand Down Expand Up @@ -115,6 +116,7 @@ Contract: `packages/shared/src/backup-staging.ts`.
| Prefix | Mutability | Contents |
| ------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------- |
| `daily/d1/...`, `weekly/d1/...` | Immutable | Signed D1 SQL + schema-v2 D1 manifests |
| `adhoc/mailbox-drop/d1/...` | Immutable | Request-unique pre-drop D1 SQL + signed schema-v2 manifest; 35-day lock/lifecycle |
| `staging/{day}/...` | Mutable | Production exporter cursor progress, chunked phase output, indexes, NDJSON dumps, `exporter/summary.json` |
| `daily/full/{day}/...` | Immutable | Sealed copy of staged indexes/dumps + Ed25519 full-backup manifest |
| `blobs/sha256/{hash}` | Immutable | Deduplicated email MIME, community assets, published source snapshots |
Expand Down Expand Up @@ -319,15 +321,17 @@ backup SQL. See [Secret rotation](./secret-rotation.md).

Routes (all require Access JWT):

| Method | Path | Action |
| ------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `GET` | `/` | Dashboard: enable gates, source identity, live D1 size, escrow presence, 14-day D1/staging/seal status with signature verification |
| `POST` | `/actions/run-backup` | Enqueue today's D1 backup Workflow (respects enable gates) |
| `POST` | `/actions/seal-day` | Verify staging + D1 manifest and seal `daily/full/{day}/...` |
| `POST` | `/actions/run-drill` | Isolated restore drill (fresh D1 in `DRILL_ACCOUNT_ID`, never production) |
| `POST` | `/actions/restore/prepare` | Validate sealed day; issue 10-minute HMAC confirm token |
| `POST` | `/actions/restore/execute` | Require typed exact `SOURCE_DATABASE_NAME` + valid token; start restore Workflow |
| `GET` | `/restore-status?id=...` | Poll restore Workflow status |
| Method | Path | Action |
| ------ | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `GET` | `/` | Dashboard: enable gates, source identity, live D1 size, escrow presence, 14-day D1/staging/seal status with signature verification |
| `POST` | `/actions/run-backup` | Enqueue today's D1 backup Workflow (respects enable gates) |
| `POST` | `/actions/mailbox-pre-drop-backup` | Generate a fresh request and enqueue the cryptographically verified mailbox legacy-graph pre-drop Workflow |
| `POST` | `/actions/seal-day` | Verify staging + D1 manifest and seal `daily/full/{day}/...` |
| `POST` | `/actions/run-drill` | Isolated restore drill (fresh D1 in `DRILL_ACCOUNT_ID`, never production) |
| `POST` | `/actions/restore/prepare` | Validate sealed day; issue 10-minute HMAC confirm token |
| `POST` | `/actions/restore/execute` | Require typed exact `SOURCE_DATABASE_NAME` + valid token; start restore Workflow |
| `GET` | `/restore-status?id=...` | Poll restore Workflow status |
| `GET` | `/mailbox-pre-drop-status?id=...` | Poll the pre-drop Workflow receipt without exposing a signed URL or secret |

### Isolated restore drill

Expand Down Expand Up @@ -370,6 +374,48 @@ effect/finalization state, then use reviewed operator tooling to populate any
replacement target from Mailbox before changing code authority. The retired
D1-to-Mailbox parity purge/rebuild path must not be reintroduced.

### Mailbox legacy graph destructive prerequisite

Never self-attest the pre-drop prerequisite with direct SQL. Before a separate
reviewed migration may drop the frozen USER `email_*` graph, use the dedicated
backup-control-plane Workflow documented in
[`packages/backup-control-plane/readme.md`](../../packages/backup-control-plane/readme.md#mailbox-legacy-graph-pre-drop-approval).
It creates a request-unique immutable `adhoc/mailbox-drop/d1/...` export,
verifies the standard v2 Ed25519 manifest and a full R2 SQL re-read, proves the
frozen authority marker and exact USER owner/thread/message/attachment/event
counts did not drift, and atomically writes an approval expiring within two
hours. The caller supplies only `requestId`, `nonce`, and `requestedAt`; source
identity, counts, object keys, hashes, and approval values come from the
allowlisted control plane.

The production `adhoc/` policy was manually applied and read back on 2026-08-03:
both lock and lifecycle are 35 days. When `DR_BACKUP_ADMIN_TOKEN` is available,
the backup-control-plane deploy job reconciles the managed policy and requires
an `adhocPolicyProof.readBackVerified: true` API result. If that optional secret
is unavailable, the job clearly logs the skipped reconciliation and continues
the ordinary backup Worker deployment.

The canonical trigger gate is the Workflow's mandatory
`verifyMailboxPreDropR2Policy` step. It creates a request-local object and
attempts an unconditional destructive overwrite before any export; R2 must
reject the overwrite as bucket-policy locked. Missing or ineffective live
protection therefore prevents both export and approval, independently of
deploy-time credentials. Poll the Cloudflare Workflow API until complete and
retain the non-secret output receipt plus any available reconciliation proof.

Exact pre/post counts bind the backup to the destructive snapshot because the
frozen USER graph has no writer: the static D1 boundary blocks live legacy
access, runtime authority gates reject legacy mutations, and
`frozen-privacy-cleanup` permits only reads/deletes. Any retention deletion
changes an exact count and aborts approval, and the atomic approval statement
rechecks the marker, health gates, and counts. The destructive consumer must
nevertheless run its own immediate full-row parity checks before dropping data.
Migration 0134 and this control plane do not drop data.

If a replay reports an immutable object/source mismatch, do not change params or
reuse that request id. Generate a fresh request id, nonce, timestamp, and
Workflow instance.

## Schedules and freshness

| When (UTC) | Who | What |
Expand Down Expand Up @@ -433,6 +479,11 @@ Work top-to-bottom. Leave gates false until the matching gate item is done.
a Worker secret.
- [ ] Checked-in CLI trust registries populated via code review when you want
offline drills/readiness (optional if UI-only, recommended).
- [ ] The 2026-08-03 manual 35-day `adhoc/` lock/lifecycle proof remains valid;
when admin credentials are available, backup-control-plane deploy also
emitted `adhocPolicyProof.readBackVerified: true`.
- [ ] The pre-drop receipt proves its mandatory live destructive policy probe
completed before export.

### 2. Manifest keys and Access

Expand All @@ -450,10 +501,12 @@ Work top-to-bottom. Leave gates false until the matching gate item is done.

- [ ] Placeholders in `packages/backup-control-plane/wrangler.jsonc` replaced;
both enable vars remain `"false"`.
- [ ] `DR_DEPLOY_TOKEN` GitHub secret set; control plane deploys from Actions to
the DR account; `BACKUP_BUCKET` bound; Workflows
`kody-production-d1-backup` and `kody-production-dr-restore` present;
public bucket access off.
- [ ] `DR_DEPLOY_TOKEN` is set; optional R2-admin `DR_BACKUP_ADMIN_TOKEN`
reconciles policy when accessible and logs a non-blocking skip otherwise;
the control plane deploys to the DR account; `BACKUP_BUCKET` bound;
Workflows `kody-production-d1-backup`,
`kody-mailbox-legacy-graph-pre-drop-backup`, and
`kody-production-dr-restore` present; public bucket access off.
- [ ] UI loads only through Access; unauthenticated and wrong-email JWTs
get 403.

Expand Down
16 changes: 13 additions & 3 deletions docs/contributing/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,19 @@ See [Disaster recovery](./disaster-recovery.md).

Lives under `packages/backup-control-plane/` in the DR Cloudflare account. Code
deploys via the production GitHub Actions workflow when control-plane / shared
backup contract paths change (secret `DR_DEPLOY_TOKEN` +
`DR_BACKUP_ACCOUNT_ID`). Enable gates and source identity vars live in that
package's `wrangler.jsonc`.
backup contract or backup-resource paths change. GitHub Actions requires
`DR_DEPLOY_TOKEN` and `DR_BACKUP_ACCOUNT_ID`. An optional
`DR_BACKUP_ADMIN_TOKEN` with DR-account Workers R2 Storage Write reconciles and
reads back the lock/lifecycle policy before the Worker deploy. When unavailable,
Actions logs a reconciliation skip and deploys normally; the mandatory live
pre-drop R2 policy probe remains the canonical export/approval gate. The admin
token is never installed as a Worker secret. Enable gates and source identity
vars live in that package's `wrangler.jsonc`.

Workflow bindings are `BACKUP_WORKFLOW`, `MAILBOX_PRE_DROP_BACKUP_WORKFLOW`, and
`RESTORE_WORKFLOW`. The dedicated mailbox binding targets
`kody-mailbox-legacy-graph-pre-drop-backup`; its public Cloudflare Workflow
params are only `requestId`, `nonce`, and `requestedAt`.

Non-secret vars:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export function environment(bucket = new MemoryBucket()): BackupEnvironment {
return {
BACKUP_BUCKET: bucket as unknown as R2Bucket,
BACKUP_WORKFLOW: {} as Workflow,
MAILBOX_PRE_DROP_BACKUP_WORKFLOW: {} as Workflow,
RESTORE_WORKFLOW: {} as Workflow,
CLOUDFLARE_API_TOKEN: 'not-logged-secret',
SOURCE_ACCOUNT_ID: ACCOUNT_ID,
Expand Down
Loading