Manthan Phase 5 — AWS Deployment Handoff
Audience: the next agent (Claude / Codex / Gemini / human) picking up Phase 5.
Date issued: 2026-05-06.
Issued by: Phase 4 closer (driver-claude).
This document is self-contained. You can start work from this file plus the repo. Read it in order.
1. Where you are in the project
The Manthan platform (a verifiable AI-agent communication substrate built on the HERALD protocol) is feature-complete through Phase 4 (Limited Testnet). Five phases preceded yours; one remains:
| Phase | Status |
|---|---|
| Phase 0 Blueprint Hardening (13 gate specs) | ✅ DONE |
| Phase 1 Verifiable HERALD Workflow (MVP wedge) | ✅ DONE |
| Phase 2 Manthan Runtime Composition (MnAgent + ledger) | ✅ DONE |
| Phase 3 Controlled Gossip (MWP handshake + 3-node demo) | ✅ DONE |
| Phase 3.5 Runtime Hardening (persistent gossip, dedupe, backpressure) | ✅ DONE |
| Phase 4 Limited Testnet (3-node local-service; filled-in Charter/LOTS/runbook) | ✅ DONE |
| Phase 5 AWS Deployment | ⏳ YOUR TURN |
Source of truth for status: MANTHAN_PLATFORM_TRACKER.md (project root).
Phase-0 gate specs: manthan-platform/gates/G-001..G-013.md.
Per-phase deliverables: see MANTHAN_PLATFORM_TRACKER.md §3 Action Tracker.
2. What you can run TODAY (sanity check before starting)
These are the runnable demos. Run them first to confirm the substrate is healthy before you touch deployment.
# On local-service or genesis (manthan/)
cd herald-protocol/services/testnet
# First-time only on a fresh host:
for pkg in lib/cbor-det lib/herald-core-ts lib/herald-ct-log \
lib/manthan-ledger lib/manthan-mwp lib/manthan-agent-ts \
services/reference-herald services/testnet; do
( cd "../../$pkg" 2>/dev/null || cd "$pkg" ; npm install --silent )
done
cd herald-protocol/services/testnet
npm run bootstrap # generate signed seed list
npm run certs # self-signed TLS for local-service wss://
npm start # 3-node testnet; auto-stops after 30sExpected output:
- Three nodes start:
genesis-alpha,genesis-beta,genesis-gamma. - Sessions establish:
sessions=2 peers=1per node (ring topology). - Genesis ceremony fires; envelope propagates.
- All three ledgers report
seen=0 verified=1.
If this works locally, the full stack is healthy.
3. Genesis host — your AWS staging environment
The project has been migrated to a working AWS EC2 host:
- SSH alias:
genesis(defined in~/.ssh/config) - Hostname:
<genesis-public-ip>(eu-west-2, Amazon Linux 2023) - User:
ec2-user - Project root:
manthan/ - Toolchain available:
- Docker 25.0.8
- Terraform v1.11.2
- Node.js v22.19.0
- npm 10.9.3
Verified working on 3-node testnet runs end-to-end; lib/herald-core-ts tests pass.
Use this host for D-001 (Docker) and D-002 (Terraform). Do NOT modify the EC2 instance's system-level config without recording it in the runbook (T-338).
4. Phase 5 deliverables
Tracker IDs D-001 through D-007. Each has acceptance criteria, suggested approach, and dependencies.
D-001 — Containerise the testnet node
What: Build a Docker image of the testnet node so it can run as an ECS task or EC2-deployed container.
Acceptance criteria:
- [ ]
infra/docker/Dockerfileexists and builds successfully on genesis. - [ ] The image runs the testnet-node command via
CMDand exposes ports 9120 (HTTP API) and 9220 (MWP). - [ ] Image size <500 MB (use
node:22-alpineornode:24-alpinebase). - [ ]
npm installruns at build time, NOT runtime (no on-startup network). - [ ] Image accepts env vars:
MANTHAN_NODE_NAME,MANTHAN_HTTP_PORT,MANTHAN_MWP_PORT,MANTHAN_DATA_DIR,MANTHAN_BEHIND_TLS_PROXY. - [ ]
docker run --rm -p 9120:9120 -p 9220:9220 manthan-testnet-node:0.2.0starts a single node and responds tocurl local-service/healthz. - [ ] Image pushed to a private ECR repo (account-specific; record ARN in
infra/terraform/variables.tf).
Suggested approach:
1. Multi-stage Dockerfile:
- Stage 1: install deps in each lib/ and services/ package using npm ci.
- Stage 2: copy only the built tree (no .git, no data/, no certs) into a slim runtime.
2. Entrypoint runs node --experimental-strip-types services/testnet/src/testnet-node.ts.
3. Mount /data as a volume for the SQLite ledger.
4. Mount /etc/manthan/charter.md, /etc/manthan/lots.md, /etc/manthan/privacy-policy.md from a config volume.
Gotchas:
- The repo has 8 separate
package.jsonfiles (one per package);npm installmust run in each. node --experimental-strip-typesrequires Node ≥22.6 (stable in ≥23.6).- The
node:sqlitemodule is experimental in Node 22; expectExperimentalWarningon stderr — suppress with--no-warningsorNODE_NO_WARNINGS=1in the container.
Dependencies: none. Can start immediately.
D-002 — Terraform/CDK for AWS infrastructure
What: Infrastructure-as-code defining the AWS resources for a 3-node production deployment.
Acceptance criteria:
- [ ]
infra/terraform/directory with HCL modules. - [ ]
terraform planruns cleanly against an empty AWS account. - [ ] Resources defined:
- VPC + 3 subnets (one per AZ in eu-west-2 to start; cross-region for D-005 later)
- ECS cluster (Fargate launch type)
- ECS service × 3 (one per node: alpha, beta, gamma)
- ALB with HTTPS listener (ACM cert) and HTTPS-to-WSS upgrade
- EFS mounted into each ECS task at
/data(per-node subdirectory) - KMS key for envelope encryption of operator seeds
- Secrets Manager entries holding each node's seed (encrypted under the KMS key)
- ACM cert for the deployment domain (
*.manthan.example.com) - Route 53 records for the three nodes
- S3 bucket (versioned) for Charters, LOTS, privacy-policies, bootstrap seed list
- CloudWatch log group per node
- IAM role per ECS task with least-privilege access to its KMS key, Secrets Manager entry, EFS path, S3 prefix
- [ ] All output values surfaced (ECR repo URI, ALB DNS name, KMS key ARN, etc.).
- [ ] State stored in S3 with DynamoDB locking (per Terraform best practice).
Suggested approach:
1. Start with terraform-aws-modules/vpc/aws and terraform-aws-modules/ecs/aws (community modules).
2. Define a node module that takes name, port_offset and produces an ECS service + ALB target group.
3. Use for_each over ["alpha", "beta", "gamma"] to spin up three nodes.
4. ALB has three target groups, one per node; routing by Host header (alpha.manthan.example.com → alpha target group).
Gotchas:
- ALB does support
wss://natively but requires HTTP/2 listener and the right idle-timeout (default 60s; raise to 900s for long-lived gossip sessions). - EFS mount targets must be in the same AZ as the ECS task; either pin tasks to one AZ per node or replicate EFS access points.
- KMS key policies need explicit allow for the ECS task role (no wildcard).
Dependencies: D-001 (need the ECR image to point ECS at).
D-003 — Replace <TBD> markers with real Charter/LOTS values
What: Fill in the production Charter and LOTS documents with real legal-entity data.
Acceptance criteria:
- [ ] No
<TBD>markers remain in any ofservices/testnet/nodes/genesis-{alpha,beta,gamma}/{charter,lots,privacy-policy}.md. - [ ] Charter §1 has real legal entity, country, jurisdictions for service of process.
- [ ] Charter §5 has real warrant canary URL (and the canary endpoint actually serves a signed monthly statement).
- [ ] Charter §9 has real contact emails (not
@testnet.localplaceholders). - [ ] LOTS §7.2 lists real compulsion exposure under the operator's jurisdiction (e.g., specific subpoena power statutes).
- [ ] All three nodes' Charters reference each other in §7.1 (cross-signing policy).
- [ ] Documents archived in S3 versioned bucket (per D-002).
Suggested approach:
1. Treat each node's Charter as a per-deployment artifact: the operator (you, your org) owns the legal-entity data.
2. For a single-operator deployment: all three nodes have the same legal entity; that's fine for v0.2 testnet. Production diversity is Phase 6+.
3. The Charter signing happens automatically at startup (signCharter in services/reference-herald/src/charter.ts); just edit the markdown, mount it into /etc/manthan/charter.md, and restart.
Dependencies: D-002 (need the S3 bucket for archival).
D-004 — PagerDuty + Slack integration
What: Wire services/testnet/observability/alerts.yaml into a real Prometheus + Alertmanager stack on AWS, routing SEV-1/2 to PagerDuty and SEV-3 to Slack.
Acceptance criteria:
- [ ] Prometheus deployed (Amazon Managed Prometheus or self-hosted in EKS).
- [ ] Each node's
/metricsendpoint scraped every 15s. - [ ] Alertmanager configured with the rules in
services/testnet/observability/alerts.yaml. - [ ] PagerDuty service exists; SEV-1 and SEV-2 alerts route to it.
- [ ] Slack webhook for
#manthan-ops; SEV-3 alerts route there. - [ ] Drill verification: trigger one alert per severity (e.g., manually scale a node to 0 to fire
ManthanLivenessLost); confirm the alert arrives at the correct destination within 5 minutes.
Suggested approach:
1. Deploy Amazon Managed Prometheus + Amazon Managed Grafana (managed services; minimal ops overhead).
2. ConfigMap with alerts.yaml rules; Alertmanager picks them up automatically.
3. Alertmanager routing config:
``yaml`
route:
receiver: slack
routes:
- matchers: [severity=~"SEV-1|SEV-2"]
receiver: pagerduty
receivers:
- name: slack
slack_configs: [...]
- name: pagerduty
pagerduty_configs: [...]
curl`-ing the metric endpoint with crafted values, or by stopping a node briefly to trigger real alerts.
4. Test each rule by
Dependencies: D-002 (Prometheus needs the VPC), D-001 (nodes must expose /metrics).
D-005 — Cross-region EFS snapshots
What: Configure EFS snapshots on a 1-hour cadence with cross-region replication to a different AWS region.
Acceptance criteria:
- [ ] AWS Backup plan defined for the EFS file system.
- [ ] Hourly snapshots, 30-day retention.
- [ ] Daily snapshots replicated to a second region (e.g.,
eu-west-2↔us-east-1). - [ ] Restore test passes: pick a snapshot, restore to a fresh EFS file system, mount into a test ECS task, verify the SQLite ledger opens cleanly with
PRAGMA quick_check.
Suggested approach:
1. Use AWS Backup (native cross-region copy supported for EFS).
2. Lifecycle: hot for 30 days → cold for 90 days → delete at 365 days.
3. Restore drill is the acceptance test; document procedure in incident-response/runbook.md data-restore section.
Dependencies: D-002 (EFS file system).
D-006 — HSM-sign the production bootstrap seed list
What: Replace the testnet's deterministic bootstrap-authority key with an HSM-backed production key.
Acceptance criteria:
- [ ] AWS CloudHSM cluster deployed OR AWS KMS asymmetric key (Ed25519) used.
- [ ] Bootstrap seed list re-signed by the HSM-backed key; the public key is shipped with the Manthan node software (analogue of TLS root CAs).
- [ ] The signed
bootstrap-seed-list.jsonis published in S3 versioned bucket; the URL is hardcoded in node startup config. - [ ] Verifiers can confirm the signature via
ed25519Verify(bootstrapAuthorityPubkey, ...). - [ ] Key custody policy filled in per Charter §4.3.
Suggested approach:
1. Generate Ed25519 keypair in AWS KMS (aws kms create-key --key-spec ECC_NIST_P256 won't work — KMS asymmetric supports Ed25519 from late-2023 onwards).
2. Sign the seed list using aws kms sign.
3. Pin the public-key SPKI fingerprint into lib/herald-core-ts or a small manthan-trust-roots.ts module that verifies any bootstrap list against the pinned pubkey.
Gotchas:
- KMS asymmetric signing is rate-limited; sign once, cache the signed JSON.
- Rotating the bootstrap-authority key is a rare event (multi-year cadence); design rotation procedure now.
Dependencies: D-002 (KMS in the IaC).
D-007 — Smoke-test the runbook on real infrastructure
What: Execute the 12 procedures in services/testnet/incident-response/runbook.md against the deployed AWS infrastructure as drills.
Acceptance criteria:
- [ ] Each of these procedures has a recorded drill outcome:
charter-refresh(re-sign Charter; verifymanthan_charter_age_secondsresets)peer-collapse(kill 2 of 3 nodes; verify alert fires; restore)verifier-failures(inject malformed envelopes from a test peer; verify quarantine)rate-limit(burst 10× the rate cap; verify drops + alert)ledger-quarantine(manually quarantine an envelope; verify state machine)readiness(corrupt the ledger; verify/readyzreturns 503)liveness(kill the process; verify ECS restarts the task)rollback(deploy a buggy image; rollback to previous)key-compromise(rotate operator key in KMS; verify recovery flow)data-backup(verify hourly snapshot creation)data-restore(restore from snapshot to a clean EFS; verify integrity)- [ ] Drill log committed to
incident-response/drill-log.md. - [ ] Any deficiencies in the runbook updated with corrections.
Dependencies: D-001..D-006.
5. Suggested execution order
D-001 (Dockerfile) ──┬──► D-002 (Terraform) ──┬──► D-003 (Charter values)
│ │
│ ├──► D-004 (PagerDuty/Slack)
│ │
│ ├──► D-005 (EFS snapshots)
│ │
│ └──► D-006 (HSM sign bootstrap)
│ │
└─────────────────────────────────────┴──► D-007 (drill)Estimated effort:
- D-001: 4-8 hours
- D-002: 1-2 days
- D-003: 2-4 hours
- D-004: 4-8 hours
- D-005: 2-4 hours
- D-006: 4-8 hours
- D-007: 2-3 days (drills are slow)
Total: ~1-2 weeks for one focused engineer / agent.
6. Repository layout
manthan/ # genesis host (or sandbox/learning/ on local dev)
├── MANTHAN_PLATFORM_TRACKER.md # status of every phase
├── PHASE_5_HANDOFF.md # this document
├── manthan-platform/
│ └── gates/ # G-001..G-013 specs
├── herald-protocol/
│ ├── SPEC.md, EXT.md, CHARTER.md, THREATS.md # canonical protocol docs
│ ├── lib/ # 7 reference packages
│ │ ├── cbor-det/
│ │ ├── herald-core-ts/
│ │ ├── herald-ct-log/
│ │ ├── herald-core-py/
│ │ ├── manthan-ledger/
│ │ ├── manthan-mwp/
│ │ └── manthan-agent-ts/
│ ├── services/
│ │ ├── reference-herald/ # single-operator Herald daemon
│ │ ├── the-scribe/ # cultural conduit exemplar
│ │ └── testnet/ # Phase 4 testnet runner
│ │ ├── src/ # testnet-node.ts, bootstrap-issuer.ts
│ │ ├── nodes/ # per-node Charter/LOTS/privacy-policy
│ │ ├── deploy/ # gen-certs.sh, bootstrap-seed-list.json
│ │ ├── observability/ # alerts.yaml, dashboard.md
│ │ └── incident-response/ # runbook.md
│ ├── demo/ # 5 demos
│ ├── tests/conformance/ # 4 conformance suites
│ ├── audits/ # 18 cross-cutting analyses
│ ├── registries/ # 6 registries (incl. typed-artifacts)
│ ├── templates/ # Herald-Charter.md, LOTS.md (R-203, T-106)
│ ├── research/ # 14 R-NNN design notes
│ └── tools/ # trace-bundler, glossary-check, etc.
└── infra/ # ⚠️ NEW for Phase 5
├── docker/Dockerfile # D-001
├── terraform/ # D-002
└── README.md # what's expected here7. Where to write Phase 5 artifacts
Create a top-level infra/ directory (sibling of herald-protocol/). The repo already has a placeholder infra/ on genesis (per the migration); start there.
infra/
├── README.md # explains what each subdir contains
├── docker/
│ ├── Dockerfile # D-001
│ └── docker-compose.yml # local dev variant
└── terraform/
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ ├── node/ # one ECS service per genesis node
│ ├── network/ # VPC, subnets, ALB
│ ├── observability/ # CloudWatch, Prometheus
│ └── storage/ # EFS, S3, KMS, Secrets Manager
└── envs/
├── testnet.tfvars # testnet deployment vars
└── production.tfvars # real production vars8. Known gotchas (from migration to genesis)
1. 8 separate package.json files; npm install must run in each. Dockerfile must reproduce this. (Fixed during migration verification.)
2. node --experimental-strip-types flag required (Node 22.x); becomes default in Node 23.6+. Pin Node version in Dockerfile.
3. node:sqlite emits ExperimentalWarning. Suppress with NODE_NO_WARNINGS=1 in production.
4. MWP listens on local-service by default (recent server.ts edit added host option). For ECS, must bind 0.0.0.0 (set via env or constructor).
5. MANTHAN_RESET_DATA=1 wipes the SQLite ledger on startup; production deployments MUST NOT set this.
6. Charter signing happens at startup by reading the file from disk. The Dockerfile must mount the Charter as a volume, NOT bake it into the image (so re-signs don't require image rebuilds).
7. Bootstrap seed list is currently signed deterministically with seed 0xb0. Phase 5 D-006 replaces this with HSM-backed signing.
9. How to verify each phase-5 deliverable
For every D-NNN, the acceptance test is:
1. The artifact exists in the repo.
2. The acceptance criteria above all pass.
3. A drill (where applicable) is recorded in infra/drill-log.md.
Update MANTHAN_PLATFORM_TRACKER.md §3 after each deliverable closes:
- [ ] **D-001:** Containerize (Dockerfile).
+ [x] **D-001:** Containerize (Dockerfile). — `infra/docker/Dockerfile`, image pushed to ECR `<ARN>`.10. Communication with the previous phase
If you find a bug in Phases 0-4 work while doing Phase 5, patch it but record it. The fix lands in the existing package; record in a PHASE_5_NOTES.md (you create it) under "Bugs found during Phase 5":
## Bugs found during Phase 5
- 2026-MM-DD: discovered <package>:<file>:<line> — <symptom>. Patch: <PR or commit>. Confirmed root cause: <reason>.11. Stop conditions
You should pause and request human review if:
- You need to change the protocol-level invariants (anything in SPEC, EXT, CHARTER, THREATS).
- You find a security vulnerability (paged-on-call material).
- A drill in D-007 fails and you can't reproduce success after one retry.
- You hit AWS spend limits (budget alarms TBD per deployment).
Otherwise, drive D-001 through D-007 to completion. Update the tracker as you go. Flip the tracker §2 status to "Phase 5 done" when all seven deliverables are recorded with passing acceptance tests.
— Phase 5 handoff, issued 2026-05-06.