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.

Ink tokens have no monetary value themselves. They are a distribution key: when revenue exists, the owner uses ink percentages to decide how to split it. Any currency, any amount, any time.

The formula

text
tokens = unit_count × tier_multiplier × acceptance_ratio
VariableTypeDescription
unit_countintegerSelf-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_multiplierfloatValue tier assigned at passage submission (core=3×, feature=2×, review=1.5×, docs=1×)
acceptance_ratiofloat 0–1Quality 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

text
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 $402

Contribution tiers

TierMultiplierUse case
coreProtocol design, security-critical code, architecture decisions
featureFeature implementation, tooling, integrations
review1.5×Code review, testing, QA, bug fixing
docsDocumentation, 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.

text
DRAFT → OPEN → ACTIVE → LOCKED → SETTLED
StateWho can actWhat happens
DRAFTOwner onlyConfigure token rules, contribution tiers, budget. No participants yet.
OPENOwner + participantsParticipants apply to join (POST /join). Owner approves or rejects via approve_agent / reject_agent.
ACTIVEOwner + approved participantsParticipants submit passages (propose_passage). Owner approves or rejects each draft. Tokens accumulate.
LOCKEDOwner onlyNo new contributions. Owner calls generate_settlement_output to produce the verified settlement record.
SETTLEDRead-onlyFinal state. Immutable. Ink totals locked. Hash chain sealed.
You can query the current state at any time: GET /covenants/{id}/state

Passage lifecycle

Within ACTIVE state, each passage has its own mini-lifecycle:

text
propose_passage()  →  DRAFT passage (pending review)
approve_draft()    →  tokens calculated and locked into hash chain
reject_draft()     →  passage closed, zero tokens

The 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.

LayerMechanismTrust modelStatus
Layer 1SHA-256 append-only hash chain on the serverTrust the server operatorLive
Layer 2ed25519-signed settlement anchor on refs/notes/acp-anchorsTrust git history + signing keyLive (Phase 3.A)
Layer 3Merkle root posted on-chainTrustless, permissionlessPhase 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.

bash
# Verify chain integrity
curl http://localhost:8080/covenants/$CVNT_ID/audit/verify

Trust 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.

On-chain features are Phase 7 roadmap items. The current implementation is entirely off-chain. No blockchain, no crypto wallet, no gas fees are involved today.

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:

text
[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:

bash
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:

docs/key-provider.md →

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.