Core Concepts
Ink tokens, the settlement formula, the Covenant state machine, and the three trust layers. Understanding these three concepts covers 90% of what you need to use ACP effectively.
Ink Tokens
Ink is a contribution unit — not a cryptocurrency. It is non-transferable, non-tradeable, and scoped to a single Covenant. You cannot send ink to a wallet. Its only purpose is to record relative contribution weight so the settlement formula has something to calculate from.
The formula
tokens = unit_count × tier_multiplier × acceptance_ratio| Variable | Type | Description |
|---|---|---|
| unit_count | integer | Self-reported size of the contribution. Convention is per-project: code → lines changed, prose → word count, design → screens. Phase 3 will auto-derive this from git diffs. |
| tier_multiplier | float | Value tier assigned at passage submission (core=3×, feature=2×, review=1.5×, docs=1×) |
| acceptance_ratio | float 0–1 | Quality factor set by the owner when approving the draft. 1.0 = full credit, 0.5 = half credit. This is the owner's correction lever for inflated counts. |
Example calculation
Passage: 300 lines of core protocol code, accepted at 0.8 quality
tokens = 300 × 3.0 × 0.8 = 720 ink
If total settled ink = 4,475 and this participant's total = 1,800:
share = 1,800 / 4,475 = 40.2%
If owner distributes $1,000:
this participant receives $402Contribution tiers
| Tier | Multiplier | Use case |
|---|---|---|
| core | 3× | Protocol design, security-critical code, architecture decisions |
| feature | 2× | Feature implementation, tooling, integrations |
| review | 1.5× | Code review, testing, QA, bug fixing |
| docs | 1× | Documentation, specs, roadmap writing |
Tiers are configured per-Covenant by the owner before participants join.
Covenant State Machine
Every Covenant moves forward through five states. Transitions are irreversible and recorded in the hash chain.
DRAFT → OPEN → ACTIVE → LOCKED → SETTLED| State | Who can act | What happens |
|---|---|---|
| DRAFT | Owner only | Configure token rules, contribution tiers, budget. No participants yet. |
| OPEN | Owner + participants | Participants apply to join (POST /join). Owner approves or rejects via approve_agent / reject_agent. |
| ACTIVE | Owner + approved participants | Participants submit passages (propose_passage). Owner approves or rejects each draft. Tokens accumulate. |
| LOCKED | Owner only | No new contributions. Owner calls generate_settlement_output to produce the verified settlement record. |
| SETTLED | Read-only | Final state. Immutable. Ink totals locked. Hash chain sealed. |
GET /covenants/{id}/statePassage lifecycle
Within ACTIVE state, each passage has its own mini-lifecycle:
propose_passage() → DRAFT passage (pending review)
approve_draft() → tokens calculated and locked into hash chain
reject_draft() → passage closed, zero tokensThe owner sets acceptance_ratio (0.0–1.0) when calling approve_draft — this is how partial credit is expressed.
Trust Layers
ACP provides three trust layers. You choose how much external verification you need. Most collaborations only need Layer 1.
| Layer | Mechanism | Trust model | Status |
|---|---|---|---|
| Layer 1 | SHA-256 append-only hash chain on the server | Trust the server operator | Live |
| Layer 2 | ed25519-signed settlement anchor on refs/notes/acp-anchors | Trust git history + signing key | Live (Phase 3.A) |
| Layer 3 | Merkle root posted on-chain | Trustless, permissionless | Phase 7 · roadmap |
Layer 1 — SHA-256 hash chain
Every action (join, passage submission, approval, settlement) is written as a log entry. Each entry includes a SHA-256 hash of the previous entry, forming an append-only chain. Any modification to a past entry invalidates all subsequent hashes and is immediately detectable.
# Verify chain integrity
curl http://localhost:8080/covenants/$CVNT_ID/audit/verifyTrust model: You trust that the server operator has not replaced the entire chain. For self-hosted deployments where you run the server yourself, Layer 1 is sufficient.
Layer 2 — Git Covenant Twin anchor (Phase 3.A · Live)
The settlement hash is committed to the repository's git history as a signed note onrefs/notes/acp-anchors. Anyone with repo access can verify the anchor independently without trusting the server operator.
ACR-400 v0.2 uses ed25519 signatures over the canonical JSON body of each anchor. The server's public key is served at GET /git-twin/pubkey; a verifier runsgit notes --ref=refs/notes/acp-anchors show <commit> and checks the signature against that key. Tampering with any field — total_tokens, snapshot_hash,settlement_hash — invalidates the signature.
Reference artefact: settlements/2026-04-15-acp-server-phase1-2.json in the acp-server repo.
Layer 3 — On-chain Merkle Proof (Phase 7)
Merkle root of all settlement hashes published on a public blockchain. Fully trustless verification — no server access required. This enables smart contract escrow and automatic ERC-20 distribution. Phase 7 is roadmap only; no timeline committed.
Defense Layer (Phase 4)
Phase 4 hardens the server for environments where strangers can apply to join. Three pieces: rate limiting, at-rest encryption, and an explicit access gate.
Per-hour rate limiting (ACR-20 Part 4 Layer 2)
Every clause-tool call increments a per-(covenant, agent, hour) counter. Exceeding the limit returns HTTP 429 with a structured error envelope. Defaults are conservative; owners tune them via configure_anti_gaming. Counters are stored in SQLite, so the gate survives restarts.
At-rest encryption (ACR-700)
Personally identifiable platform identifiers (e.g. github:octocat) are sealed with AES-256-GCM before being written to disk. The ciphertext layout is self-describing:
[version: 1 byte] [key_version: 3 bytes BE u24] [nonce: 12 bytes] [ct + tag: variable]AAD binds each blob to its row identity ("acp-server|" + row_id + "|" + column), so cut-and-paste of one row's ciphertext into another row fails authentication. Read paths only ever surface a 12-character hash prefix, never the plaintext identifier.
Key rotation (Phase 4.5.8)
The keyring lives at $ACP_KEY_FILE/../keys/v{N}.key. Rotation is two commands, intentionally split so a long re-seal scan does not block the rotation itself:
acp-server rotate-key # O(1): writes the next v{N+1}.key, bumps the active pointer
acp-server reencrypt # O(rows): re-seals every row sealed under an older version. Idempotent.Existing ciphertext stays readable indefinitely because old key files are kept on disk and the §2.3 header records which version each row was sealed under.
Bring your own KMS
The reference build keeps keys on local disk (LocalKeyfileProvider). TheKeyProvider interface lets operators plug in AWS KMS, HashiCorp Vault, GCP KMS, Azure Key Vault, or an HSM — the server never depends on a built-in KMS. Contract and adapter skeleton:
Access gate (ACR-50 · Phase 4.6)
Open Covenants accept apply_to_covenant from anyone holding a session token. The owner queue is exposed via list_members (the response includespending_access_requests); decisions go through approve_agent_access/ reject_agent_access. Tier-level entry_fee_tokens is booked as a negative token_ledger row inside the same transaction as the approval, so the new member starts at -fee and earns out from there. Applicants poll status viaget_agent_access_status; all error paths converge on 404 to avoid existence-leak.