# HAP-1 Live — reference implementation 0.10.0

Human Authority Protocol: a portable, bounded, revocable authority gate running on devices you control. Money Musk authors this reference implementation. It is not a permission server, a token, an identity oracle, or a claim to be the first such protocol.

Download [the complete runtime](https://moneymusk.space/hap1-runtime.zip), [the source manifest](https://moneymusk.space/hap1-manifest.json), or [the browser/Node core](https://moneymusk.space/hap1/runtime.mjs). After downloading, the core, Room 1, and receipt verification require no Money Musk domain, account, wallet, hosted service, or network access. The core and adapters have no third-party runtime dependencies. The archive is bounded below 4 MB by the build.

Version 0.10 adds experimental [Echo portable fork evidence](FORK-EVIDENCE.md).
An observer can compare two retained HAP histories and export two authentic,
conflicting records at one journal position. Separate JavaScript and Python
implementations verify the evidence offline against an independently retained
issuer key. Reports never grant authority, select a winning branch, restore state
or prove key compromise. Detection requires both branches; automatic enforcement
and independent review remain outside this evidence profile.

Presence compatibility reports support an [optional versioned detached
attestation](PRESENCE-ATTESTATION.md). A local Ed25519 signer can bind exact report
bytes, corpus/runner digests, implementation source/revision and profile to its
key. Verification uses a separately retained trust pin and never grants authority
or certifies truthful execution, independence or security review. The unsigned
runner and its deterministic report bytes remain unchanged.

Version 0.9.1 closes two PULSE final-dispatch races. A newer authenticated pulse
fences an older pending callback before its acceptance write is acknowledged.
An authenticated revoke inside another permit bundle also stops that ticket's
callback, even when the enclosing action refuses. The last synchronous check
enforces both fences after storage acknowledgement. Invalid pulse inputs cannot
cancel a valid claim; unrelated tickets keep their own pulse fences. Consumption
is never refunded. Regression tests reproduce both races, including delayed and
failed writes, and Chromium exercises them with actual IndexedDB transactions.
Signed grammars, HAP core bytes and the inspection corpus are unchanged.

Version 0.9 adds the [external PULSE verifier runner](PULSE-ADAPTER.md). Other
implementers can run all 110 pinned inspection cases locally through a versioned
adapter and retain a reproducible report. Protocol errors, crashes, fake success
fields, skipped cases and stale responses cannot count as successful inspection.
Reports never grant authority or certify independence, execution safety or
physical presence. The reference adapters remain project implementations.

Version 0.8 adds the [PULSE-1 inspection compatibility kit](PULSE-INTEROP.md):
110 public hostile fixtures, golden signing bytes, JavaScript and separate Python
verifiers, and cross-language tests. Inspection never grants, consumes or persists
authority. This is project conformance evidence; independent implementations and
physical-device validation remain separate milestones. All signed profiles stay
unchanged.

Version 0.7 adds [PULSE-1 and optional Human Heartbeat](PULSE.md), a separate
execution gate and [3D local lab](pulse.html). Pay/send routes configured for it
require a durable, one-use five-second signed lease. A fresh connection nonce,
strict counters, received revokes and final dispatch checks prevent replay and
silence recovery. An optional owner-local Bluetooth reading supplies only
pass/fail, time and a salted hash; no waveform or BPM reaches the executor.
The paired WebRTC adapter needs no authority server. Legacy signed bytes, letters,
Horizon and WebAuthn policy remain intact. The lab simulates its device link and
money; physical sensor/radio validation remains outstanding. A borrowed watch
can pass. These gates establish neither legal identity nor biological liveness.

Version 0.7.1 distinguishes internet loss from radio silence. Losing radio contact
retains an accepted pulse only until its original five-second deadline, usable
once with an already issued exact-action permit. Explicit stop and received revoke
still block immediately. The lab demonstrates prepared intents, two-second cached
dispatch, expired-window refusal and receipt inspection that never renews authority.

Version 0.6.1 adds a [local presence interoperability kit](PRESENCE-INTEROP.md):
a separate Python verifier, shared adversarial vectors, and cross-language
conformance tests. Its [external adapter runner](PRESENCE-ADAPTER.md) lets other
teams test their own verifier and produce a local, reproducible compatibility
report. The [review guide](PRESENCE-REVIEW.md) defines the additional evidence for
independent implementations, security review and operation. Other networks can
reproduce verification without a Money Musk service and retain their evidence
locally. Inspection never issues permits
or replaces the stateful replay/revocation gate. This is a second implementation
by this project, not a third-party audit or proof of independent adoption.

Version 0.6 adds an optional [WebAuthn presence profile, HAP-1/WA-1](PRESENCE.md)
and a separate [browser presence lab](presence.html). Each permit requires a fresh
assertion bound to the exact ticket, executor challenge, action digest and deadline,
with registered-key, RP/origin, UP/UV, counter and durable replay checks. Its atomic
wrapper preserves all HAP-1/1 signed bytes. WebAuthn user verification is stronger
evidence of local user interaction, not legal identity or guaranteed biological
liveness. It is opt-in; legacy receipts alone do not prove a presence ceremony.

Version 0.5 adds an optional [checkpoint witness and recovery drill](WITNESS.md).
A separately runnable operator retains signed history and answers a fresh client
challenge. Inspection refuses history that conflicts with the witness or a
separately retained client checkpoint. It never restores a database, resets spent
authority, authorizes execution or rotates keys. Existing HAP-1/1 signed bytes and
payment behavior are unchanged; independent operation remains a deployment check.

## Run Room 1 outside the site

Version 0.4 adds an optional [OpenClaw test-payment pilot](external/README.md):
a separate durable executor, signed outcome receipts, read-only reconciliation,
and a network-disabled agent container. Its pinned OpenClaw dependencies are
installed separately; they are not part of the small source archive. Automated
provider tests are synthetic; independent adoption and real Stripe validation
remain separate checks. The HAP-1/1 wire format and browser core are unchanged.

Version 0.4.2 binds the optional external Stripe profile's outcome to the exact
concrete payment-method ID authorized in the payload. It rejects test aliases
before authorization or dispatch; mismatched or missing provider method IDs
cannot resolve an uncertain payment. The optional provider check now also needs
`STRIPE_TEST_PAYMENT_METHOD`. See the external guide for setup and legacy outcomes.

Version 0.4.3 preserves final signed payment outcomes when POST completion and
read-only reconciliation race. Late responses cannot overwrite a final receipt;
a late transport error cannot erase an observed pending result. The guard runs
inside the durable journal transaction, including retries after competing writes.
The HAP-1 core and signed wire formats are unchanged.

With Node 22.13+ (built-in SQLite; Node 24 recommended), unzip the archive and run:

```sh
node hap1/room1.mjs
```

The demonstration creates an isolated human-device process and an executor, each with its own private directory, persisted state, and encrypted device key. It grants EUR 20.00, simulates EUR 12.00, delivers a signed revoke over local IPC, restarts both devices, and proves the previous permit cannot dispatch again. All money movement is simulated. It prints the location of synthetic public evidence. Demo key passphrases are random and are discarded when the process exits; the example is not a personal vault.

For an independent implementation of evidence verification, install `cryptography==46.0.0` in your Python environment, then:

```sh
python3 hap1/verify.py hap1/echo-law-vectors.json --vectors
python3 hap1/verify.py PATH_TO_REVOCATION_JSON --key INDEPENDENTLY_PAIRED_PUBLIC_KEY
```

The Python verifier does not import the JavaScript SDK. It is a second implementation by this project, **not a third-party implementation or independent security audit**. Public keys are chosen through pairing; a key included in an untrusted file never supplies its own trust.

## The ticket: eight fields

This wire profile is `proof.schema = HAP-1/AO-1`. It does not reinterpret the site's earlier local `AO-1` demonstration or the profile 0.2 Authority SDK.

The exact encoding, domain-separated signature grammar, and state-transition rules are in [SPEC.md](./SPEC.md).

| Field | Meaning |
| --- | --- |
| `human` | Hash of the independently paired human-device public key |
| `delegate` | Hash of the delegate's separate public key |
| `capability` | One exact action verb |
| `scope` | One executor identity and one exact resource reference |
| `constraints` | Aggregate integer amount, unit, use count, and freshness bound |
| `expiry` | Mandatory device-clock expiry, at most 24 hours after issuance |
| `reversibility` | `irreversible` or `compensatable`; descriptive, never a promise to undo an effect |
| `proof` | Profile, random ticket ID, issuance time, and Ed25519 signature |

There are no embedded private keys, wallet keys, personal biographies, wildcard scopes, or token requirements. The issuer, delegate, and executor use different device identities. References must be opaque identifiers, not private data. Amounts are integer minor units: EUR 20 is `2000` with unit `eur`. A ticket is bound to one executor; copying it to another rail does not copy its budget.

## The act: fresh challenge, durable commit

1. The executor signs a random single-use challenge for the exact ticket, action, payload digest, and retained checkpoint. Its lifetime is 100–5000 ms, bounded by the ticket.
2. The delegate signs that challenge with its own key. The human device verifies both signatures, the exact scope, expiry, cumulative spend, use count, and revocation state.
3. `authority.check()` atomically **consumes** budget and a use and returns a signed permit plus journal continuity evidence. It is not a read-only preview. Calling it does not send money or move a machine.
4. The executor validates the permit, pinned issuer, full chain, exact pending challenge, payload hash, and deadline. It durably consumes the pending challenge before invoking the effect.
5. A crash, timeout, or downstream failure remains consumed. There is no automatic retry or refund; reconcile uncertain external results before seeking a new human grant.

`verifyReceipt()` only verifies a historical statement. It never authorizes an act. A previously valid receipt, a timestamp, and yesterday's ticket cannot substitute for a pending fresh executor challenge. `DISPATCHED` means the configured adapter returned; it does not mean payment settled or a physical outcome occurred.

## API and integration

```js
import { createAuthority, createExecutor, verifyReceipt } from './runtime.mjs';
import { createGate, stripePaymentGate, registerOpenClawPaymentTool } from './adapters.mjs';

// These values are provisioned by the operator. Keep the authority on the human device.
const authority = await createAuthority({ identity: humanIdentity, store: humanStore });
const executor = await createExecutor({ identity: executorIdentity, issuerPublicKey: pairedHumanKey, store: executorStore });

const gate = createGate({
  executor, ticket, delegate: agentIdentity,
  requestPermit: nearbyTransport.requestPermit,
});
const sendValue = stripePaymentGate({ gate, stripe: serverSideStripeSdk, merchantAccount: 'acct_OPERATOR' });
registerOpenClawPaymentTool(openClawApi, sendValue);

// Owner-only interface on the human device. Never expose this object or its key to an agent.
const kill = await authority.revoke(ticket);
await nearbyTransport.sendRevocation(kill); // receiver awaits executor.revoke(kill) and acknowledges
const historyOnly = await verifyReceipt(kill.receipts.at(-1), pairedHumanKey);
```

The transport exchanges canonical JSON using `canonical()` and `parseWire()`. It must not expose `grant()`, `revoke()`, the signing identity, or raw effect credentials to the delegate. `requestPermit` receives `{ticket, request, delegatePublicKey, executorPublicKey}`; the owner-side handler calls `authority.check(ticket, request, keys)`. The executor signs its own audience challenges, and the delegate must prove possession of its key. Pair issuer keys independently before any grant. Do not accept a network response as a new trust root.

The OpenClaw function registers an optional `hap1_send_value` tool through the documented `registerTool` contract. This is an integration adapter, not an installed or certified OpenClaw plugin. An integrating plugin declares `contracts.tools: ["hap1_send_value"]` and `toolMetadata.hap1_send_value.optional: true` in its manifest; the operator allowlists it. Disable alternate raw payment/shell tools that can reach the same credentials. A library cannot constrain an adversarial host that bypasses it.

The Stripe adapter binds integer amount, currency, payment method, and the operator-configured connected account, then calls `paymentIntents.create` with `confirm: true` and a challenge-derived idempotency key. This is real dispatch code when supplied the official authenticated Stripe SDK. Tests use a recording double, never a live charge. It is not a published Stripe marketplace plugin and does not implement payment settlement/reconciliation.

`robotMotionGate` demonstrates the same gate for a bounded motion command and a synchronous local interlock. Its driver must enforce the passed `notAfter` deadline and command ID at the actual actuator, reject queued stale commands, and provide its own emergency stop. The tests use a simulated driver. This adapter is not a certified robot safety controller, and revocation cannot undo motion already committed.

## Persistence and phones

`node-store.mjs` uses SQLite WAL, FULL synchronization, and compare-and-swap transactions. `node-identity.mjs` stores encrypted PKCS#8 keys in private directories and imports a nonextractable Web Crypto signing key. Supply a strong passphrase through the owner's input flow or secret manager; never argv, a ticket, or agent context. File and directory permissions are checked. `memoryStore()` is explicitly for tests only.

`browser-store.mjs` provides `browserDevice(name)`, nonextractable Ed25519 keys persisted through IndexedDB structured cloning, and strict IndexedDB transactions shared across tabs. Import it from an independently hosted, trusted secure origin:

```js
import { browserDevice } from './browser-store.mjs';
import { createAuthority } from './runtime.mjs';
const device = await browserDevice('owner-device');
const authority = await createAuthority(device);
```

Use an isolated origin for the owner application and ask the owner to grant persistent browser storage through the host's normal flow. Browser eviction, unsupported crypto/storage, or quota failure must be treated as loss of availability, never a reason to fall back to a fresh permission server. Protect the owner interface against XSS and untrusted agents. The optional [WebAuthn wrapper](PRESENCE.md) adds a user-verification ceremony; the base browser storage adapter and original phone lab remain device-only. This release does not provide a native phone app, BLE/QR transport, or a completed two-phone airplane-mode test. A device signature proves control of a paired key, not that a living person is present at that instant.

The reference profile bounds an identity to 128 grants, 128 uses per grant, and 4096 journal events, reserving the final 128 event slots for revocation. It is intentionally small. A full journal refuses new grants/permits; re-pair a new identity through the owner flow. Do not silently reset state, clone an active identity onto two writers, or restore an old database and treat it as the latest authority.

## Kill and checkpoint semantics

`authority.revoke()` immediately stops that device from issuing further permits. `executor.revoke()` persists an authentic received revoke and clears its pending challenges. Wait for the receiver's acknowledgment before presenting “stopped on that executor.”

A disconnected executor cannot know a revocation it has not received. A previously issued permit can still commit within its maximum five-second challenge window until the kill arrives. If the human device is unreachable, it cannot issue a fresh permit. The boundary is the executor's durable consumption commit: revocation ordered after that commit cannot cancel or reverse the external action. Longer-running actuators need their own continuously enforced lease and emergency stop.

Every journal event signs its sequence and predecessor hash. Executor checkpoints survive normal restarts; `verifyContinuity()` detects missing, reordered, duplicated, or conflicting histories relative to a retained pin. Retain signed checkpoints independently and compare/gossip them between observers. A hash chain alone cannot discover an unseen alternate history, prove global non-equivocation, or resist restoration of *all* device state plus *all* witness checkpoints. The runtime also retains clock high-water marks, including refused expired requests, but has no hardware monotonic clock guarantee.

Version 0.4.1 rechecks the clock and signed deadlines after durable permit consumption,
immediately before calling an effect. If storage completion takes too long, the action
refuses, the challenge stays consumed and the allowance is not refunded. A late expiry
observation is retained across normal restarts. The effect context and HAP-1/1 signed
wire format are unchanged. An adapter that awaits further work before its irreversible
operation must also enforce the deadline at that operation, as the external payment
executor does. Existing offline web-tool tabs must close before the updated service
worker activates; previously downloaded runtimes and native app builds need updating.

This reference exchanges full journal segments, including amounts, times, and opaque references from other grants under the same issuer. It does not implement selective disclosure or zero-knowledge proofs. Use separately paired issuer identities for trust domains that must not share this metadata.

## Optional Bitcoin evidence

`clockEvidence()` verifies that a signed revocation is included in the exact signed checkpoint and emits canonical `HAP-1/BT-1` bytes. It never calls a calendar or labels a hash as a Bitcoin proof.

```sh
node hap1/clock-cli.mjs prepare BUNDLE_JSON CHECKPOINT_JSON PAIRED_PUBLIC_KEY revocation.bt1
node hap1/clock-cli.mjs stamp revocation.bt1
# After the official OpenTimestamps calendar has completed the proof:
node hap1/clock-cli.mjs upgrade revocation.bt1.ots
node hap1/clock-cli.mjs verify revocation.bt1.ots
```

The last three commands explicitly invoke the separately installed official `ots` client. Stamping and upgrading require its calendar connectivity; a pending `.ots` is not a Bitcoin confirmation. Verify the BT-1 evidence with the independent verifier **and** the completed timestamp with OpenTimestamps. Offline Bitcoin verification requires completed proof data and an independently trusted local Bitcoin chain/node. This release does not include a mined timestamp or a fake block height. A valid timestamp establishes prior existence of those bytes, not their truth, latestness, receipt by every executor, or a physical kill.

## Interoperability and release evidence

`echo-law-vectors.json` contains 26 synthetic positive/negative vectors: tickets, signature pins, extra fields, blank cheques, tampering, stale permits, checkpoint conflict, deletion/reordering/duplication, and rollback. JavaScript and Python run the same vectors. `scripts/hap1-regressions.mjs` additionally tests concurrency, durable restart, missing transport, failed dispatch, clock rollback, and the three adapters. Three browser-store cases use the IndexedDB API implementation `fake-indexeddb@6.2.5` to test concurrent creation, shared budgets, persisted keys/kills, and refusal on storage errors. This is a test-only dependency. Real phones, an installed OpenClaw host, authenticated Stripe test mode, hardware robots, zero-knowledge proofs, a third-party implementation, and a Trust Center signing ceremony have **not** been verified by these tests.

`hap1-manifest.json` publishes reproducible source and archive SHA-256 digests. It is an unsigned content manifest, not a Trust Center attestation; authenticate it against the repository release/commit or another retained source. CI regenerates every public file, compares exact bytes, checks the archive size, and runs the regressions and Python vectors. New reference files in `hap1/` use the included 0BSD license so other stacks can copy them. Other Money Musk source retains its existing terms.

No token purchase, meme wallet, token wallet signature, or Money Musk API enters the authority path. Wallet assets and authority-device keys are separate systems.

Primary integration references: [OpenClaw tool registration](https://docs.openclaw.ai/plugins/building-plugins), [Stripe PaymentIntent creation](https://docs.stripe.com/api/payment_intents/create), [Stripe idempotency](https://docs.stripe.com/api/idempotent_requests), [Node SQLite](https://nodejs.org/api/sqlite.html), [OpenTimestamps client](https://github.com/opentimestamps/opentimestamps-client).

## Phone lab (0.2.1)

Open `/hap1/phone.html` over HTTPS, or serve this directory from localhost for development. The web tool is also linked from Echo and Authority Preview. The runtime ZIP is still a developer download; extracting it does not install an iPhone app.

**This phone:** grant 20 test units, use 12, revoke, attempt replay, export the signed evidence. The human, delegate and executor have separate nonextractable Ed25519 keys in IndexedDB. This mode uses one physical browser and simulated effects. Reloads keep keys, limits, checkpoints and kills. No money moves.

**Two phones:** keep both awake on the same local Wi-Fi. Choose Human on one and Executor on the other. Exchange the offer and answer text using a trusted nearby method. Compare all six groups of the 96-bit comparison code in person, then confirm on both screens. The code binds both identities and both WebRTC descriptions, including DTLS fingerprints. Do not confirm a mismatch. The executor cannot remotely grant or revoke. The human grants the ticket; each use requests a fresh permit over the authenticated data channel. Pairing text may disclose local IP addresses. No STUN, TURN, signaling server or Money Musk authority API is contacted. Networks with client isolation, backgrounded phones, browsers without local WebRTC, or radio-off airplane mode can prevent connection. There is no internet relay fallback.

A kill is durable on the human phone before delivery. The UI reports remote delivery only after the executor acknowledges persistence on the paired channel. A disconnected peer cannot receive a new kill. Reconnect, compare again and resend the saved revocation. Existing permits have at most a five-second lifetime; the runtime still checks the actual deadline at dispatch. Actions already dispatched cannot be undone. Delivery acknowledgement demonstrates peer software response, not physical hardware compliance.

**Verify a receipt:** obtain the human public key separately, then select the exported JSON file. Verification checks the ticket, full signed chain and ending checkpoint locally. The public key inside the file is never automatically trusted. A historical receipt cannot authorize another action. Evidence contains test amounts, times and other tickets from the same issuer journal; this is not a zero-knowledge proof or a Bitcoin confirmation.

**Prepare offline use:** explicitly installs a service worker scoped to this directory, caching only the public tool assets listed in `sw.js`. No private keys, records, APIs, Echo conversations or external assets enter that cache. Open the tool on each phone before disconnecting internet. Keep local Wi-Fi enabled. Updates wait for old tool tabs to close so code does not switch mid-session. Browser data eviction can remove keys and the offline copy; clearing data does not recover or transfer a device identity. IndexedDB is browser storage, not secure hardware isolation or human-presence attestation.

The phone lab adds no real payment connector, installed agent plugin, robot driver, Bitcoin anchor or independent audit. Automated tests cover cryptographic and transport behavior using isolated browser stores and a data-channel test double. Actual two-phone, iOS backgrounding, local Wi-Fi, WebRTC and offline-reload behavior must also be validated on the target devices before calling this production-ready.

Version 0.2.1 reports missing local ICE candidates explicitly and preserves disconnected status. Public-browser verification passed grant/use/revoke/replay/reload; the cloud browser exposed no host candidates, so no live peer-channel claim is made.

## Version 0.3 verification tools

See [ADOPTION.md](ADOPTION.md) for the runnable Stripe sandbox check, offline retained-checkpoint recovery check, and deployment evidence requirements. SQLite provisioning is now explicit: `sqliteStore(path, {create:true})` creates a new store exclusively; `sqliteStore(path)` only reopens existing state and refuses a missing or empty database. These tools do not constitute independent adoption or audit.

## Offline QR transport

[PULSE QR v1](PULSE-QR.md) carries unchanged signed pulses using a fresh,
executor-authenticated session challenge and strict one-use scanning. Try the
[two-role mobile lab](pulse-qr.html). Scanning never grants authority or proves
proximity/biological presence. Physical-device QR tests remain outstanding.
