# LayerHuman escrow launch runbook

Updated 29 September 2026. The concept site is public. The marketplace and MCP service run in a private Arc Testnet pilot with a deployed escrow. A wallet-authorized agent completed a real 1 test-USDC payout through the app and MCP; email and identity are sandbox fixtures. Production providers and public paid work remain gated. See TESTNET.md for the manual guide.

## Local setup

Install Rust 1.97+, Node 24+, PostgreSQL client tools, Docker, Foundry and Playwright's Chromium (or Google Chrome on macOS).

```sh
npm ci
npm run build
npm run test:contracts
npm run dev:backend
```

The development script starts its own PostgreSQL container on 55439 and uses a fresh `layerhuman_escrow` database. Existing legacy data is preserved. Open `http://localhost:8080/app/`; the app clearly labels simulated providers. In another shell:

```sh
npm run test:api
npm run test:e2e
npm run test:docs
npm run test:providers
npm run test:rust
npm run lint:rust
```

`test:providers` requires `anvil`, `psql`, `createdb`, compiled contract artifacts and a compiled Rust debug binary (or `TEST_BINARY`). It derives the PostgreSQL host/credentials from DATABASE_URL and resets only the dedicated `layerhuman_escrow_contract` database. It starts temporary services on ports 8083, 18545 and 18090. Do not store user data in that test database.

## Production configuration

Use a fresh database and dedicated host/project. The backend rejects a legacy direct-payment database containing tasks; do not bypass this guard. Archive and independently settle old obligations before planning a migration. Deployments are pinned to test/live mode, chain, escrow model and contract address.

Copy `.env.example` to a private `.env` (chmod 600). Set APP_DOMAIN and matching HTTPS PUBLIC_ORIGIN. Generate random POSTGRES_PASSWORD (URL-safe hex) and OPERATOR_TOKEN (at least 32 characters). Never enable TEST_MODE in production. Configure:

- Stripe Identity secret and signing secret; enable document and matching-selfie checks. Register the hosted identity webhook at `/api/webhooks/stripe` for verification-session events.
- Resend API key and verified MAIL_FROM for email verification and resets.
- Task review belongs to the posting agent through MCP. No platform LLM credential is required for escrow settlement. LLM_CHAT_URL, LLM_API_KEY and LLM_MODEL are optional for the separate skill-discovery chat. The relayer authenticates agent decisions; human arbitrators handle discrepancies.
- HTTPS EVM_RPC_URL on Arc Testnet first, PAYMENT_NETWORK=eip155:5042002, ESCROW_ADDRESS, ESCROW_CODE_HASH, ESCROW_VERIFIER_KEY, distinct ESCROW_ARBITRATOR and CHAIN_CONFIRMATIONS (minimum 2). The production backend validates runtime code, chain, token and signer roles at startup.

Owner and human private keys stay in their wallets. Use a dedicated verifier signer with a small gas budget and protected secret storage. The application does not hold the arbitrator key; use separately secured operational signing, preferably a reviewed multisig policy. The immutable contract cannot rotate a lost verifier or arbitrator; migration requires a new deployment. Consider this availability and key-custody tradeoff before launch.

## Deploy the escrow

Build and test the contract; arrange independent review before live funds. Export variables through a secret manager, not committed scripts:

```sh
npm run test:contracts
# Required environment: EVM_RPC_URL, ESCROW_DEPLOY_KEY,
# ESCROW_DEPLOY_CHAIN_ID=5042002, ESCROW_VERIFIER_ADDRESS,
# ESCROW_ARBITRATOR
npm run deploy:escrow
```

The script broadcasts a deployment and prints its transaction, address and runtime code hash. Save these values and compiler/build artifacts. The deployer key is separate from the runtime verifier key. Base mainnet requires chain 8453 and the explicit `CONFIRM_MAINNET_DEPLOY=deploy-reviewed-escrow` flag. Do not switch an existing database to another network or contract.

Funding uses exact USDC approval followed by `fund`. Verify the owner, amount, terms and deadline in the wallet before signing. The owner pays approval/deposit gas; the verifier pays assignment/release gas. Approvals are exact amounts, not unlimited allowances. The backend checks a confirmed funding receipt plus contract state before matching.

## Host the Rust service

Point DNS to the host, allow TCP 80/443 and UDP 443, and install Docker Compose. Then:

```sh
docker compose config --quiet
docker compose up -d --build
docker compose ps
docker compose logs --tail=100 app
```

Caddy handles HTTPS. App/database have no public host ports. The app runs as a non-root user; PostgreSQL and private evidence volumes persist. `/health/ready` checks database reachability. `/api/config` identifies the payment model, network and configured contract. The shareable static Vercel deployment is separate; `/mcp` belongs on this Rust origin.

## Messenger setup

Telegram: create the operator bot, set TELEGRAM_BOT_TOKEN, TELEGRAM_BOT_USERNAME and a random TELEGRAM_WEBHOOK_SECRET. Use Telegram's `setWebhook` with URL `https://YOUR_DOMAIN/api/webhooks/telegram` and `secret_token` equal to that secret. Subscribe to message updates. The handler accepts private chats only and verifies the secret header.

WhatsApp: provision Meta WhatsApp Cloud API, register your phone number, and set WHATSAPP_ACCESS_TOKEN, WHATSAPP_PHONE_NUMBER_ID, WHATSAPP_DISPLAY_NUMBER, WHATSAPP_APP_SECRET, WHATSAPP_VERIFY_TOKEN and an explicitly supported WHATSAPP_GRAPH_VERSION. Configure `/api/webhooks/whatsapp` as the callback, complete its GET verification and subscribe to message events. POST signatures are HMAC-SHA256 validated against the raw body and phone ID.

For proactive notifications, obtain an approved utility template with one body text parameter; set WHATSAPP_NOTIFICATION_TEMPLATE and WHATSAPP_TEMPLATE_LANGUAGE. Without a template, plain text delivery only works within the provider's permitted conversation window. The adapter does not bypass provider approval, opt-in or delivery restrictions.

Humans select Link Telegram/WhatsApp in My profile and send the one-time `/link TOKEN` privately within ten minutes. Commands: `/tasks`, `/accept UUID`, `/say UUID text`, `/messages UUID`, `/submit UUID evidence`, `/stop`. Wallet/identity setup, photo uploads and disputes use the mobile web workspace. Native apps and direct bot media ingestion are not included.

Inbound events and task-message keys deduplicate webhook retries. Outbound messages use a durable queue with up to five attempts. Provider delivery is at least once: a crash after provider acceptance can duplicate a notification. `/stop` unlinks the channel and suppresses queued deliveries; notification preferences also apply.

## MCP connection and wallet authorization

Open /connect/ and authorize the agent with an owner wallet signature and explicit spending/category limits. Neither the owner nor agent needs email/password signup; human workers register separately. Store its key in runtime secrets. Configure `POST https://YOUR_DOMAIN/mcp` with `Authorization: Bearer KEY`. Stateless HTTP JSON responses support initialize, tools/list and tools/call (protocol 2025-11-25). Hosted OAuth, native marketplace publication and legacy SSE are not included. Test the actual ChatGPT/Claude client authentication or use a runtime with custom bearer headers.

Ten tools: `post_bounty`, `get_bounty`, `get_funding_requirements`, `confirm_funding`, `send_message`, `get_conversation`, `get_evidence`, `get_evidence_file`, `review_bounty`, `get_wallet`. A new task is awaiting_funding. Amounts are micro-USDC (40,000,000 = 40 USDC). Stable request keys prevent duplicate drafts; the agent can only access its own tasks. Revocation stops new API calls but does not cancel funded obligations.

Legacy browser funding transaction signing is an external owner-authorized wallet boundary. The recommended x402 adapter signs deposits locally and funds bounties automatically. The browser supports manual owner signing; an autonomous wallet service must independently enforce chain, token, contract, amount and budget policy. After funding, no second owner signature is needed: the relayer triggers escrow release after approval by the original posting agent. This is a custom escrow transaction flow, not the previous direct x402 settlement. x402 v2 exact/EIP-3009 deposits now fund bounded agent vaults, which automatically fund the pinned task escrow. See X402.md for autonomous setup and network deployment status.

## Evidence and trust model

Task terms and payout address are fixed. Each submission captures an immutable snapshot of the original criteria, submitted text, up to 100 conversation messages and private image hashes. Only the original posting agent can retrieve that evidence and review it through MCP. It must inspect the evidence, then submit approve, revise or dispute with the current evidence hash, a reason and criterion checks. Approval requires every reported check to pass. Identical decisions are idempotent; stale or conflicting decisions are rejected.

Approval queues release automatically. Worker polling, agent response time and chain confirmations determine end-to-end latency; no instant-finality guarantee is made. Revision reopens submission; disputes keep funds locked for a separate human arbitrator. An agent cannot override a disputed task. Automated arbitration is not implemented. No platform model or confidence threshold makes task decisions.

The posting agent, relayer signer and arbitrator are trusted for their respective decisions. The contract enforces custody and authorized transitions; it does not prove evidence truth or cryptographically validate AI judgment. Hashing records the reviewed inputs. There is no unilateral owner clawback of assigned work.

Unassigned tasks can call `refundExpired(bytes32)` after deadline. Assigned tasks can call `expireAssigned(bytes32)` after deadline plus seven-day grace to enter dispute, not refund. Obtain escrow_task_id from funding requirements. Arbitration pays the fixed human or refunds the original owner.

## Operator recovery

Use `Authorization: Bearer OPERATOR_TOKEN` from protected tooling:

- `GET /api/operator/bounties/{UUID}/evidence` and `GET /api/operator/bounties/{UUID}/files/{FILE_UUID}`: inspect disputed evidence through authenticated operator tooling.
- `GET /api/operator/queue`: disputed tasks, payment-review jobs and operational counters.
- `POST /api/operator/bounties/{UUID}/resolve` with `{"action":"approve","reason":"Document the evidence and arbitration decision"}` or action `refund`: returns an unsigned contract transaction for the separate arbitrator. It does not mark paid or move funds itself.
- Have the configured arbitrator sign/broadcast the returned transaction. Then `POST /api/operator/bounties/{UUID}/reconcile` with `{"transaction_hash":"0x..."}`. Reconciliation validates the task event, pinned contract and confirmed terminal state before recording paid/refunded.

Do not manually edit a task to paid. Inspect existing transaction hashes and contract state before retries. Transactions with ambiguous/reverted results remain under review; contract state prevents duplicate release. The signer stream uses a PostgreSQL advisory lock. The initial release is designed for one application instance, with bounded request bodies, worker batches and connection pools. Do not infer production throughput from local API measurements.

## Acceptance and operations

Before public paid work, exercise real Stripe/email, actual Telegram and WhatsApp delivery, the chosen MCP client, an Arc Testnet deposit/assignment/release, revisions, uncertain evidence, expiry, arbitration and restart recovery. Contract tests and fixture tests do not replace independent security review or evaluation of the posting agent’s review behavior.

Back up PostgreSQL and evidence together: stop app, take pg_dump and evidence-volume snapshot, then restart. Encrypt off-host backups and verify restore into an isolated stack. Monitor readiness, verifier gas, stale assignments/reviews, RPC errors, queue retries, disk usage and database pool health. Decide evidence retention, user deletion, consent/data rights and moderation rules before broad enrollment. Edge rate limits must be shared before multiple replicas.

Robotics head-camera capture is a supported product use case, not a completed video pipeline. Device provisioning, consent licensing and bulk video ingestion remain an additional integration. Hourly metering, native mobile apps, organization SSO, tax reporting and fiat cash-out are outside this release.
