Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
7d83f79
agentkeys: stage 7+ — issue #74 step 1 (dev_key_service signer + boot…
WildmetaAgent May 8, 2026
5792f71
agentkeys: stage 7+ — issue #74 step 1b (signer-server split + JWT au…
WildmetaAgent May 9, 2026
6d36a7b
docs: address review-questions Q1-Q8 (PoP, cold-start ordering, per-i…
WildmetaAgent May 9, 2026
3822d85
docs: cleanup pass on review-questions edits (renumber, PoP consisten…
WildmetaAgent May 9, 2026
d2103c1
docs: master/agent split + WebAuthn-uniform binding ceremony (v0.2 ta…
WildmetaAgent May 9, 2026
396ceb1
docs: arch.md — fix stage-0 device-key generation contradiction (§5 v…
WildmetaAgent May 10, 2026
dc12fc8
docs: arch.md §5a.1.M — fill J0 → J1 bridge gap referenced by §5a.1.A
WildmetaAgent May 10, 2026
50a0ffa
docs: adopt HDKD per-agent omni model + arch.md compaction (709 lines…
WildmetaAgent May 10, 2026
bf445dc
docs(demo): align stage7 demo doc with new architecture vocabulary
WildmetaAgent May 10, 2026
d1ff6f8
docs(signer): document signer setup + add SIGNER_HOST/AGENTKEYS_SIGNE…
WildmetaAgent May 10, 2026
637d590
docs(cloud-setup): extract signer setup into §6 — fix $EIP ordering bug
WildmetaAgent May 10, 2026
d6242c8
docs(cloud-setup): §6.2 — derive SIGNER_HOST on broker host, not from…
WildmetaAgent May 10, 2026
a3a0a84
fix(setup-broker-host): default WITH_NGINX/CERTBOT auto → yes (was: a…
WildmetaAgent May 10, 2026
c2a5a60
docs(cloud-setup): §6.1 — warn against re-deriving EIP from local res…
WildmetaAgent May 10, 2026
4407ab4
docs(cloud-setup): deslop §1.3 + §6 — drop duplicated prose, keep table
WildmetaAgent May 10, 2026
3770798
fix(setup-broker-host): drop --with-nginx / --with-certbot — defaults…
WildmetaAgent May 10, 2026
0799147
docs(claude+stage7): runbook-fix-fold-back policy + absorb session fixes
WildmetaAgent May 10, 2026
a2f7c6e
docs(stage7): §0 install — drop conflicting aliases + verify $PATH wins
WildmetaAgent May 10, 2026
11e59ce
docs(stage7): §0.2 — pin BACKEND_URL inline + bail-loud on stale value
WildmetaAgent May 10, 2026
02790b9
Revert "docs(stage7): §0.2 — pin BACKEND_URL inline + bail-loud on st…
WildmetaAgent May 10, 2026
48b613d
docs(stage7): fix --json position — global flag, must precede subcommand
WildmetaAgent May 10, 2026
d260153
docs(stage7): §0.4 — inline `agentkeys init --email` step before derive
WildmetaAgent May 10, 2026
d3f669b
feat(broker): real SES email sender — Pass 1 of Option B
WildmetaAgent May 10, 2026
0b6616e
fix(broker): SesEmailSender verify — fall back from address to domain…
WildmetaAgent May 10, 2026
1379814
feat(ses): explicit per-address verify + ses-verify-sender.sh helper
WildmetaAgent May 10, 2026
637ed76
fix(ses-verify-sender): drop FROM-grep prereq — never matched QP-enco…
WildmetaAgent May 10, 2026
8f84e9c
fix(ses-test): CleanupGuard Drop — block_in_place to allow nested blo…
WildmetaAgent May 10, 2026
8bf06bd
fix(ses-test): unbuffered per-attempt logging + bounded object scan
WildmetaAgent May 10, 2026
2dc32a1
fix(ses-test): explicit async cleanup via catch_unwind — no more Drop…
WildmetaAgent May 10, 2026
5f63fa8
perf(ses-test): cleanup fast-path — single DeleteObject vs 415-object…
WildmetaAgent May 10, 2026
8ef973a
feat(broker): Pass 2 of Option B — wire SesEmailSender end-to-end
WildmetaAgent May 11, 2026
b7fa15a
docs: backfill issue #80 reference in setup-broker-host.sh comment
WildmetaAgent May 11, 2026
8cb576e
docs(stage7): §0.4 + §2.0 — add Pass-2 prereqs (ses-verify-sender + a…
WildmetaAgent May 11, 2026
b8481fe
refactor(email_link): drop vestigial HMAC key — magic-link is statefu…
WildmetaAgent May 11, 2026
4824b64
docs(policy): add no-hardcoded-values policy + hardcoded.md audit log
WildmetaAgent May 11, 2026
6864a64
docs(hardcoded): cross-link HMAC trade-off to issue #81 — bidirection…
WildmetaAgent May 11, 2026
c016308
fix(ses-verify-sender): fail loud on wrong AWS profile + fold profile…
WildmetaAgent May 11, 2026
2e92f8e
fix(setup-broker-host): die loud with journal on healthz failure post…
WildmetaAgent May 11, 2026
8c84614
deslop(setup-broker-host): drop dead helpers + dedupe + fix latent cr…
WildmetaAgent May 11, 2026
6d75599
fix(setup-broker-host): cargo multi-package + --features footgun stri…
WildmetaAgent May 11, 2026
c235373
fix(setup-broker-host): assert via cargo --message-format=json + carg…
WildmetaAgent May 11, 2026
5c0315b
docs(stage7): fold-back build-time vs boot-time auth-email-link failu…
WildmetaAgent May 11, 2026
f35e68f
fix(setup-broker-host): trust cargo's JSON assertion; demote strings/…
WildmetaAgent May 11, 2026
37999b3
fix(setup-broker-host): incremental builds by default; clean only whe…
WildmetaAgent May 11, 2026
8b19e9b
fix(setup-broker-host): when cargo cache-hits, verify binary exists o…
WildmetaAgent May 11, 2026
e23357e
docs(cloud-setup,stage7): grant ses:SendEmail to broker-host role for…
WildmetaAgent May 11, 2026
1024b94
fix(cloud-setup,stage7): grant ses:SendEmail with role discovery, not…
WildmetaAgent May 11, 2026
9c07a38
feat(demo): auto-click magic-link helper + least-privilege broker IAM
WildmetaAgent May 11, 2026
d20168a
fix(demo): fast-fail in poll loop when agentkeys init dies early
WildmetaAgent May 11, 2026
529ed44
fix(demo): die loud if invoked under sudo (env vars get stripped)
WildmetaAgent May 11, 2026
2f82982
fix(demo): O(1) hash-set membership for new-key detection (was always…
WildmetaAgent May 11, 2026
e5205b1
fix(demo): bash-3.2 compat — drop declare -A (macOS /bin/bash freeze)
WildmetaAgent May 11, 2026
fc2b5d3
fix(demo): operator precedence — '|| true | tr' parsed wrong, tr neve…
WildmetaAgent May 11, 2026
ad1b089
fix(init_flow): thread session JWT to signer derive + SIWE sign calls
WildmetaAgent May 11, 2026
a97bb53
fix(demo): handle both literal '=' and QP-encoded '=3D' in URL extrac…
WildmetaAgent May 11, 2026
d471781
fix(docs+scripts): always pass --region "$REGION" — agentkeys-admin p…
WildmetaAgent May 11, 2026
6b2103d
docs: drop legacy "S3-full-access" framing — broker role rename compl…
WildmetaAgent May 12, 2026
722a990
fix(broker): wire SES sender-verify probe to populate readiness cache
hanwencheng May 12, 2026
8fc8cae
docs(stage7 §0.4): canonicalize on agentkeys-broker-host + fold in Ge…
WildmetaAgent May 12, 2026
ee1c2e7
docs(stage7 §0.3/§0.4): make demo work with strict JWT-omni signer + …
WildmetaAgent May 12, 2026
398e0e4
feat(stage7): multi-tenant --session-id + one-shot demo-show.sh + §0.…
WildmetaAgent May 12, 2026
e9cf009
fix(stage7): preflight stale-binary loud + fold install-check into §0…
WildmetaAgent May 12, 2026
705e834
fix(stage7): unique recipient per --session-id + show SHA256 inputs +…
WildmetaAgent May 12, 2026
3dc2d0b
docs(stage7 §0.4): doc the deterministic recipient + --export modes; …
WildmetaAgent May 13, 2026
930c58c
docs(stage7 §2): fold-back AGENTKEYS_SESSION_ID stickiness + §14.8 Ex…
hanwencheng May 13, 2026
d8267a4
docs(stage7): make every section multi-tenant aware
hanwencheng May 13, 2026
218b682
docs(stage7 §2): make automation-vs-manual path explicit + warn again…
hanwencheng May 13, 2026
e99936c
fix(stage7): init-email-demo prints eval hint; §14.4 covers ADDRESS D…
hanwencheng May 13, 2026
84df1fe
docs(stage7 §2.4): explicit eval --export B bob requirement + 401 cro…
hanwencheng May 13, 2026
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
60 changes: 60 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ See `docs/spec/plans/development-stages.md` for the 8-stage build plan.
See `docs/spec/plans/execution-plan.md` for the orchestration runbook (ralph, team, ultraqa).
Do not read folder `docs/archived`

## Architecture-as-source-of-truth policy
[`docs/spec/architecture.md`](docs/spec/architecture.md) is the **single source of truth** for component inventory, key inventory (K1–K11), trust boundaries, identity model (HDKD actor tree), and per-actor binding ceremonies. **After editing any architectural doc** (broker plans, signer-protocol, demo doc, runbooks, plan files in `docs/spec/plans/`, heima-gaps), re-open `architecture.md` and verify it still matches; if it diverges, update arch.md in the same change. If the per-doc detail outgrows arch.md, link from arch.md outward — never duplicate. The wiki page at [`.omc/wiki/agent-role-and-usage-hdkd-per-agent-omni.md`](.omc/wiki/agent-role-and-usage-hdkd-per-agent-omni.md) is a focused operator reference for the agent role; it defers to arch.md.

## Version Control
Use `jj` (Jujutsu) for all version control. Never use raw `git` commands.

Expand All @@ -19,9 +22,66 @@ Before changing any file in response to a reported failure, **reproduce the fail
## Land-the-fix policy
Once a local repro proves a fix is correct, **land it the same turn**: edit every affected file (search repo-wide — never assume one file), commit, push to `origin/evm`. Do not stop at "verified locally" or "fixed in one place" — the next operator running the docs will hit the same bug if the fix isn't on `origin/evm`. Pair this with the diagnosis-before-edit policy: diagnose once, fix everywhere, push immediately.

## Runbook-fix-fold-back policy
When the user is walking through a runbook (`docs/cloud-setup.md`, `docs/stage7-demo-and-verification.md`, `docs/operator-runbook-stage7.md`, etc.) and hits a step that fails, **two things must land in the same turn**:

1. The targeted fix to whatever broke (script default, env var, doc command, code).
2. **A revision to the runbook itself** so the next operator running it top-to-bottom will not hit the same failure. The fix lives wherever the bug was; the runbook revision lives wherever the operator first encounters the broken step.

Examples of revisions to land alongside the underlying fix:
- A failing prerequisite check → upgrade the prereq sanity-check step to catch the same case (not just fix the missing prereq once).
- A wrong env var on the wrong machine → call out the laptop-vs-broker-host scope explicitly in the runbook step that uses it.
- A silent skipped action that downstream commands rely on → add a verify-and-fail-loud sanity check in the runbook between the action and its dependent.
- A confusing diagnostic that took two rounds to resolve → fold the diagnosis steps inline into the runbook (one-shot lookup table, not 3 round-trips with the operator).

The goal: every operator-encountered failure makes the runbook strictly more robust before we move on. Never leave the runbook in a state where the same operator (or the next one) will hit the same trap.

## No-hardcoded-values policy
**Do not bake hardcoded values (paths, hostnames, addresses, account IDs, ports, magic numbers) into scripts, code, or runbooks.** Use one of:

- env var with default + override (preferred for operator-facing config)
- CLI flag with default
- config file (env file, TOML, etc.) sourced at startup
- constant in a single source-of-truth file with a clear name

If a hardcoded value is genuinely temporary — e.g. you're sketching a fix and don't yet know how to parameterize it — **log it in [`hardcoded.md`](hardcoded.md)** with: file path + line number, what's hardcoded, why it's hardcoded today, and the concrete change that would unblock making it dynamic. The doc is the audit trail; if a value is hardcoded but not in `hardcoded.md`, the next operator (or future-you) can't tell it was deliberate vs an oversight.

Hardcoded values that go unrecorded compound: each new operator adds defaults baked into a different layer, the runbook drifts from reality, and the project becomes un-deployable to anyone but the original author. The audit log is the cure — it forces an explicit decision instead of an accumulating series of "I'll fix it later"s.

## Plan-completion policy
When the user references a plan (e.g. `docs/spec/plans/issue-XX-*.md`), **complete every numbered step in the plan's implementation-order table — not a self-selected subset**. If you cannot complete a step (interactive flow needs human, scope explosion, prerequisites missing), say so up front before starting work and get explicit approval to defer. Never silently drop steps and ship a partial plan as "done."

The end-of-PR summary is mandatory and has two sections in this exact order:

1. **What landed** — bulleted list of every plan step you finished, with file paths.
2. **What did NOT land** — every plan step you skipped, with the reason and what unblocks it. If the section is empty, say so explicitly ("All plan steps shipped.").

Do not bury skipped work in a footnote, in a note partway through prose, or in a doc that the user has to dig for. The summary is the authoritative answer to "is this PR plan-complete?" — make it answerable from a glance.

Also: never gloss over a partial implementation in a demo doc or runbook. If the demo walks through a flow that is only half-shipped, the doc must state which half is shipped and which still requires manual setup or a follow-up PR. Operators reading the doc cannot tell which is which from prose alone.

## Remote broker host (single entry point)
All remote-host changes (binary upgrades, systemd edits, nginx/certbot, env tweaks, mock-server redeploys) MUST go through `bash scripts/setup-broker-host.sh` — it's idempotent and auto-detects bootstrap vs upgrade. No ad-hoc `systemctl` edits or hand-built `scp`.

## AWS local-profile ↔ remote-IAM mapping
Operator workstations use lowercase AWS profile names; the access key/secret inside each profile authenticates as the corresponding remote IAM user (case differences like `agentKeys-admin` on AWS vs `agentkeys-admin` locally are cosmetic — the key is the binding, not the name). Source-of-truth (`awsp` output):

| Local profile (laptop) | Remote IAM principal (AWS) | Use for |
|------------------------|---------------------------|---------|
| `agentkeys-admin` | `user/agentKeys-admin` | Account-owner ops: SES verify, S3 bucket admin, IAM put-role-policy, EC2 describe-instances, OIDC provider mgmt |
| `agentkeys-broker` | `user/agentkey-broker` | Broker-runtime-equivalent perms (rarely used from laptop; the broker EC2 has its own instance profile) |
| `agentkeys-daemon` | `user/agentkey-daemon` | Daemon-side AssumeRoleWithWebIdentity-equivalent (rarely used from laptop) |

Switch with `awsp <profile>`; verify with `aws sts get-caller-identity`.

### Per-profile default region is NOT uniform — always pass `--region "$REGION"` explicitly
**Critical trap (real 2026-05-12 incident):** `agentkeys-admin` defaults to `us-west-2` while `agentkeys-broker` / `agentkeys-daemon` default to `us-east-1` (where the broker EC2 + SES + S3 actually live). A bare `aws ec2 describe-instances --filters "Name=ip-address,Values=$EIP"` under `agentkeys-admin` searches `us-west-2`, the EC2 isn't there, the JMESPath returns empty, and the CLI exits 0 with no stderr — silently corrupting the downstream `--role-name ""` or `--instance-profile-name ""` call.

**Rule for all operator-facing docs, scripts, and copy-paste blocks:** every regional AWS API call (`aws ec2`, `aws ses`, `aws s3api`, `aws sts assume-role-*`, `aws logs`, etc.) MUST pass `--region "$REGION"` explicitly. `$REGION` comes from `scripts/operator-workstation.env` (us-east-1). Never rely on the profile's default region — they're not consistent across the three profiles. Global IAM calls (`aws iam`) are region-less and don't need the flag.

### Caller-ARN matching in scripts must be case-insensitive
Lowercase the caller_arn before matching, since the remote IAM user is `agentKeys-admin` (capital K) but operator scripts canonicalize on `agentkeys-admin`. Use `tr '[:upper:]' '[:lower:]'` (portable to /bin/bash 3.2) — not `${var,,}` (bash 4+).

## Development Workflow (Anthropic Harness Pattern)

On every session start:
Expand Down
Loading
Loading