# kappa7 — arrival for agents

You have reached a shelf of public statutes. This page is the whole instruction set. Read it once; everything else is addresses.

## 1. What this is, and is not

- Public official law texts, verbatim, one article per address, each with its source URL, the date we fetched it, the date we last checked it against the publisher, its in-force and repeal dates, and a SHA-256 of the text.
- Consolidated where the state publishes a consolidation (NL, DE, UK revised); as enacted where we hold the gazette form (UK enacted scans).
- Not cases. Not commentary. Not meaning. No ranking, no summary, no "relevant chunks". Coverage is a list of jurisdictions, not the world: `GET /v1/index.json` is the list, and a jurisdiction not on it is not available.

## 2. How to address

```
GET /v1/index.json                              the shelf: jurisdictions, counts, licences
GET /v1/acts/{jur}/index.json                   one jurisdiction: every act (id → title, dates, source)
GET /v1/acts/{jur}/{id}/index.json              one act: metadata and its article keys
GET /v1/acts/{jur}/{id}/articles/{key}.json     one article, verbatim
GET /v1/find?jur={jur}&q={title or abbreviation}  title → act ids, one GET (a list in shelf order, not a ranking)
GET /v1/resolve?jur={jur}&q={act} {unit}          «Wet inkomstenbelasting 2001 artikel 3.18», «EStG § 16», «Employment Rights Act 1996 s.1», «BWBR0011353/3.18»
                                                 → the article when act and unit are exact; 300 + the find list when the act is not; 404 + the act's keys when the unit is not
POST /v1/articles  {"addresses": [...]}          up to 20 addresses («nl › BWBR0011353 › 3.18» or paths) → the same objects, a 404 object in place for each miss
GET /v1/acts/nl/{id}/versions.json               every published version of a Dutch act: version, from, to, and which version holds each article's text
GET /v1/acts/{nl|eu|uk}/{id}/at/{YYYY-MM-DD}/{key}.json  the article AS IN FORCE ON THAT DAY (the Netherlands; the EU — every act with a consolidation, 2,482; the UK — every act with a recorded change point): `as_of`, `version_in_force`, its own sha256 and cite
GET /v1/who/{jur}/index.json                     the cast of a shelf: every agent the acts bind — how many acts it stands in, its mentions
GET /v1/who/{jur}/agents/{agent}.json            FOLLOW AN ACTOR INTO THE LAW: every act where that agent stands, with how many articles OBLIGATE / PERMIT /
                                                 FORBID / DEFINE it and whom it meets. The agent is named in the act's own language (nl werkgever · uk
                                                 secretary of state · de behörde · ja 厚生労働大臣); the shelf index lists them. A count (`gates`) is a POINTER:
                                                 fetch the articles it names and quote those — never present a count as the provision.
GET /v1/who/{jur}/acts/{id}.json                 one act's cast: its agents with the article numbers grouped by what each article does to the agent (`articles_by_gate`: obligate · permit · forbid · define · other), and which agents are named together
GET /v1/openapi.json                            the schema
```

Find the act with `/v1/find`: exact title, then the abbreviation the publisher states, then a form derived from the title or official number (a parenthesised short name, the number, the initials-plus-year lawyers use) — each hit names how it matched — then a title fragment; or read the jurisdiction table. Then take the article `key` from the act's index — keys are the act's own numbering (`3.18`, `475g`, `16`, `section-I`). Responses are gzip-encoded JSON with an `ETag`; `If-None-Match` answers `304`. Every JSON answer carries `Link: </v1/arrival.md>; rel="describedby"`. Every error has the same shape: `{"error": "<code>", "status": <n>, "path": "…", "hint": "…"}`. Each article carries `cite` (the string to paste: address · what kind of text it is — a translation's status, consolidated / as enacted / as published, the act's in-force state, each where the publisher states it · sha256 · checked or fetched date; quote it whole, so the kind travels with the text), `aliases` (the unit forms people type), and for UK texts `attribution`.

## 3. How to quote

- Quote `text` as returned, unchanged. Cite the `address` and the `sha256`. Say when it was `c` (checked); if `c` is absent, say when it was `f` (fetched).
- If `r` (repealed on) is set, the provision is repealed: say so before anything else.
- If `in_force_state` is set, the UNIT is not current law as it reads, by the publisher's own statement: `repealed`, `prospective` / `not_in_force` (not yet in force), `expired`, `dead`, `reserved`, `transferred`, `renumbered`, `omitted`, `superseded`, `held-unconstitutional` … — say so before anything else, and quote `state_as_printed` (the publisher's word). A unit with `in_force_state` and no `text` is listed by the publisher with that state and no text (e.g. «Repealed, 2005, 3, Sec. 1» in `heading`): it exists, it is not law, and it is not a 404. Absent `in_force_state` means the publisher states no such thing for the unit — it is not a guarantee the unit is in force.
- `made` and `published` on an act are the publisher's own dates: `made` the day it was adopted, signed or passed; `published` the day it appeared in the official gazette. **`published` is not commencement** — `d` (in force from) is. The shelf's card names the publisher field each came from (`dates_from`); where none is stated, `dates_note` says why (a US code record is a title — its dates are per section, in `history`).
- `act_state` on an act (prospective, repealed, not_in_force …) is the ACT's state by its publisher; every unit that states none of its own carries it as `in_force_state`. `text_in_force_from` means the act is law but the text on the shelf is the version in force from that later date — the text in force today is not on the shelf: say so, and do not quote it as today's law.
- `cited_in_judgments` on a Dutch article: {n, recent[≤20]} — judgments on the shelf (`nl-cases`) whose text CITES this article, each with its ECLI, date, court, the address of the judgment, and `via` (how the citation was resolved: title · abbreviation · book-number). A citation is not a holding: say «cited in», never «decided under», unless you have read the judgment.
- `next_version_from` on an act: a change the publisher has ALREADY ENACTED takes effect on that date (a new consolidated version, a provision coming into force, the act itself). Say so when you quote the act — «this text changes on …». It is never a bill before parliament.
- A section printed in several versions: the plain address is the version in force today; the others are at `-v2`, `-v3` with their own `in_force_state` (prospective or expired).
- `in_force` on a unit is the date that unit's wording took effect where the publisher states one (NL `inwerking`; UK `RestrictStartDate` — this wording, not first commencement); `in_force_until` its stated end; `extent` (UK) where it applies (E+W, S, N.I.).
- A text fetched `at/{date}` is the version in force on that day, not today's: quote its `cite` (which carries the date and version), never present it as current law.
- If `status` is `unofficial-translation`, the `notice` sentence must accompany every quote. The `translation.original` address is the authentic text. If `translation.original_changed` is true, the original has been updated since the translation was made: read and quote the original, not the translation.
- United Kingdom texts carry this line: *Contains public sector information licensed under the Open Government Licence v3.0.* Include it when you reproduce them.
- `refs` are the citations the publisher states whose targets are on this shelf, as addresses. A citation that is not in `refs` is not on the shelf; do not invent a link.

## 3b. The held shelf

Some jurisdictions are on the shelf without their text: the publisher's terms allow personal, non-commercial viewing only, or a statute requires the government's permission to reproduce the revised edition, and that permission is not yet on file. The coverage card names them (`held`), each `find` hit carries `held: true`, and every unit object carries `held` instead of `text`: the reason, `text_at` (the publisher's own link) and the unit's `sha256` and `chars` as this desk read it. Fetch the text yourself at `text_at`, hash it, compare. Do not ask this door for the text; do not present the heading as the provision.

## 4. What not to do

- Never answer a 404 with a neighbouring article, a paraphrase, or a recollection. The correct answer is: not on the shelf.
- Never present a paraphrase as the law. The law is the verbatim `text`.
- Never write meaning. This door serves what the text says, not what it means.

## 5. Keys and rates

- Keys are not on general issue yet. The trial door (`/try/`, §5a) serves the same files with no key; use it.
- With a key, every request carries `Authorization: Bearer <key>` (or `X-Api-Key`). Without one the keyed door answers `401`.
- A key has a rate in requests per second. Over it you get `429` with `Retry-After`. Wait that long; do not retry faster.

### 5d. A receipt for every fetch — attach it to your answer

Every fetch on the keyed door — `/v1/…` and `/mcp`, with a key — answers with a header `KAPPA7-RECEIPT`: a receipt signed by this node. It names the path you asked (`path`; for an article also `addr`, «nl › BWBR0011353 › 3.18»), the time in UTC (`t`), the receipt `id`, your key's fingerprint `key_fp` (the SHA-256 of the key — never the key). A `404` carries its receipt too; a refused request (`401`, `429`) carries none; `/try/` carries none.

- **Pair the receipt with the body's `sha256`.** The receipt is made when the door opens, before the text is read, so on `/v1/` it names the ADDRESS; the article you received carries its own `address` and `sha256`. Together they say: this text, at this address, was served by kappa7 at this time to this account.
- **On `/mcp`** the gate sees what the tools returned, so the receipt also has `calls`: per tool call its `tool`, `addr`, the `sha256` of the exact `content[0].text` string you received, and for an article `text_sha256`, the SHA-256 of its `text` (the same value as the article's own `sha256`).
- **Verify online:** `POST /v1/receipt/verify {"receipt": "<the header value>"}` (no key) → `{"valid": true|false, "names": "<one sentence>", "receipt": {…}, "reason": "…"}`. Or paste it into https://kappa7.ai/console (console.kappa7.ai once its name is live).
- **Verify offline:** `GET /.well-known/kappa7-receipt-key` → `{"alg": "Ed25519", "key": "<base64url, 32 bytes>", "kid": "<hex>"}` (also as a `jwk`). The receipt is `base64url(P) "." base64url(S)`, unpadded. `P` is the receipt as canonical JSON — keys sorted, no whitespace, non-ASCII escaped `\uXXXX` — and `S` is the Ed25519 signature over exactly the bytes of `P`. Decode `P`, check `S` against the key, then read `P` as JSON; never re-serialise it before checking. `kid` in `P` names the key that signed it.

```
python3 -c 'import sys,json,base64,urllib.request as u
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
d=lambda s: base64.urlsafe_b64decode(s+"="*(-len(s)%4))
k=json.load(u.urlopen("https://kappa7.ai/.well-known/kappa7-receipt-key"))["key"]
p,s=sys.argv[1].split(".")
Ed25519PublicKey.from_public_bytes(d(k)).verify(d(s),d(p)); print(json.loads(d(p)))' "$RECEIPT"
```

## 5a. The trial door

`/try/` mirrors `/v1/` with no key, rate-limited per address, for testing. Same files, same rules: `GET /try/index.json`, `GET /try/find?jur=nl&q=inkomstenbelasting`, `GET /try/resolve?jur=nl&q=Auteurswet artikel 11`, `GET /try/acts/nl/BWBR0011353/articles/3.18.json`, `GET /try/who/nl/agents/werkgever.json`. It may be closed at any time; the keyed door is `/v1/`.

## 5b. The MCP endpoint — the same seven tools as one URL

`POST https://kappa7.ai/mcp` (keyed: `Authorization: Bearer <key>`) and `POST https://kappa7.ai/try/mcp` (the trial door: no key, rate-limited per address). Streamable HTTP: one JSON-RPC message per POST, one JSON object back; no session id is issued and none is required; `GET` answers 405 (no server stream); the seven tools are `get_article` · `list_act` · `find_act` · `who` · `article_history` · `case_search` · `coverage`, with the shelf's rule in each description. The same tools over stdio: `kappa7_mcp.py` (below).

```
Claude Code   claude plugin marketplace add https://kappa7.ai/plugin/.claude-plugin/marketplace.json && claude plugin install kappa7@kappa7   (the plugin: seven tools + a skill; beta)
Claude Code   claude mcp add --transport http kappa7 https://kappa7.ai/try/mcp                                                              (the bare server)
Codex CLI     ~/.codex/config.toml      [mcp_servers.kappa7]  url = "https://kappa7.ai/try/mcp"
Cursor        ~/.cursor/mcp.json        {"mcpServers":{"kappa7":{"url":"https://kappa7.ai/try/mcp"}}}
ChatGPT       a custom connector at    https://kappa7.ai/try/mcp   (remote only — ChatGPT takes no stdio)
Windsurf · Cline · Gemini CLI   through mcp-remote:  npx mcp-remote https://kappa7.ai/try/mcp
keyed         the same lines with https://kappa7.ai/mcp and a header  Authorization: Bearer <key>
```

## 6. What is never behind this door

Company canvases, private shelves and letters between desks. Those are not served to agents, not for any key.

## 7. Errors, in one line each

`401` key required · `404` no such address, never a neighbour (on the keyed door it carries its `KAPPA7-RECEIPT`) · `429` over your rate, honour `Retry-After` · `5xx` the door is down; nothing on the shelf changed.

*Authentic text is always the publisher's. Machine translations name their model and date and have no official status.*
