Metadata-Version: 2.4
Name: ithuriel
Version: 0.6.1
Summary: ITHURIEL/1: vendor-neutral authenticated attention signals anchored to canonical state
Author: ITHURIEL Protocol contributors
License-Expression: MIT
Project-URL: Homepage, https://pypi.org/project/ithuriel/
Project-URL: Release dump, https://gallery.smokehounds.store/ithuriel/0.6.1
Keywords: agents,protocol,mcp,automation,event,ithuriel,ed25519
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Internet
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography>=42
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: coverage>=7; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Provides-Extra: adversarial
Requires-Dist: hypothesis>=6; extra == "adversarial"
Provides-Extra: learn
Dynamic: license-file

# ithuriel

**ITHURIEL/1** is a vendor-neutral protocol and Python reference implementation for authenticated attention signals between agents, services, automations, and local runtimes.

The governing invariant is:

> **A ithuriel may reference authority, but may never constitute authority.**

A ITHURIEL packet contains no executable task body. It identifies a canonical object and the SHA-256 digest of the exact bytes the sender observed. The recipient authenticates the sender, checks routing/time/replay policy, independently resolves the canonical object, verifies the digest, and surfaces an **attention event only**. Execution authority remains local.

Version **0.6.1** is the current experimental PyPI release. **0.6.0**, **0.5.41**, and **0.5.4** remain listed. Canonical git is Google Drive (`gdrive::ithuriel`), not GitHub. ITHURIEL remains a reference implementation, not a production runtime.

## Install

From PyPI:

```bash
python -m pip install ithuriel
python -m pip install 'ithuriel[learn]'  # optional sidecar; no model client
# or: pipx install ithuriel
```

From this source tree:

```bash
python -m pip install .
```

The project is MIT licensed.

The source distribution also contains an independent Go verifier and a
POSIX local cross-language conformance check (`scripts/release-check-local.sh`).
The Python implementation is not the only implementation of the signing vector.

## Architecture

ITHURIEL separates five things that agent products often blur together:

```text
identity trust        -> who signed this?
attention transport   -> how did the packet arrive?
canonical byte proof  -> is this the exact referenced state?
attention             -> should the local runtime look now?
execution authority   -> may anything actually happen?
```

Only the first four are relevant to receiving a ithuriel, and ITHURIEL still does **not** grant execution authority.

## Minimal Python example

```python
import json
from pathlib import Path

from ithuriel import (
    MappingTrustStore,
    VerificationPolicy,
    create_signal,
    generate_keypair,
    load_private,
    local_resolvers,
    verify_signal,
)

work = Path("work-order.txt")
work.write_text("canonical work order\n")
private_path, public_path = generate_keypair(Path("sender"))
resolvers = local_resolvers(allow_file=True)

envelope = create_signal(
    sender="agent:sender@example.org",
    recipient="agent:receiver@example.net",
    kind="handoff",
    object_id="wo:184",
    canonical_uri=work.resolve().as_uri(),
    private_key=load_private(private_path),
    resolvers=resolvers,
)

trust = MappingTrustStore({
    "agent:sender@example.org": json.loads(public_path.read_text())
})

result = verify_signal(
    envelope,
    trust=trust,
    policy=VerificationPolicy(
        expected_recipient="agent:receiver@example.net",
        allowed_schemes=frozenset({"file"}),
    ),
    resolvers=resolvers,
)

assert result.accepted
assert result.authority == "not-granted-by-ithuriel"
# ITHURIEL never grants execution. Any later action is a separate
# recipient-local decision over result.snapshot.content.
```

Do not reopen `result.canonical_uri` later and assume it is still the same object version. Downstream action should consume `result.snapshot.content` or re-resolve and re-hash immediately before acting.

## Optional local learning (`ithuriel.learn`)

Learning is a **host-local sidecar**, not part of verification. `import ithuriel` does not load it. `verify_signal` / `receive_signal` / HTTP accept never import it. There is no default LLM.

After a durable receipt and ack, a host may extract scoped observations into a **separate** SQLite file:

```python
from ithuriel.learn import KnowledgeStore, decode_utf8_extractor

knowledge = KnowledgeStore(Path("learn.sqlite3"), create=True)
observed, = knowledge.observe(
    received,  # ReceiveResult from receive_signal
    project_id="proj-alpha",
    extractor=decode_utf8_extractor,  # or a host callback
    extractor_version="fixture-v1",
    acceptance_store=store,
)
current = knowledge.retrieve_current(project_id="proj-alpha", recipient=envelope.recipient)
```

Observations are assertions (`source X asserts Y`), always `unreviewed`, and never write trust, enrollment, tickets, or limiter state. Promotion to shared knowledge raises `learn-promotion-forbidden`.

## First-contact trust enrollment

The receiver must never trust a public key supplied by the ithuriel packet itself. 0.5.0 added a vendor-neutral enrollment ceremony:

```text
receiver creates one-time invite for exact sender ID
    -> shares invite through authenticated/OOB channel
sender signs claim with proposed Ed25519 key
    -> receiver checks invite token + proof of possession
receiver atomically installs sender->key trust binding
```

Create an invite:

```bash
ithuriel enroll-invite \
  --store trust.sqlite3 \
  --recipient agent:receiver@example.net \
  --sender agent:sender@example.org \
  --ttl 900 \
  --out invite.json
```

Sender creates a claim:

```bash
ithuriel enroll-request \
  --invite invite.json \
  --private-key sender.private.pem \
  --out claim.json
```

Receiver accepts it:

```bash
ithuriel enroll-accept claim.json --store trust.sqlite3 --recipient agent:receiver@example.net
```

`trust.sqlite3` can then be used directly by `ithuriel serve`. See `ENROLLMENT_PROFILE.md`.

## Create and verify a ithuriel

Generate keys:

```bash
ithuriel keygen --out sender
```

Create a ithuriel from a local file:

```bash
ithuriel create \
  --sender agent:sender@example.org \
  --recipient agent:receiver@example.net \
  --kind handoff \
  --object-id wo:184 \
  --canonical "file://$(pwd)/work-order.txt" \
  --private-key sender.private.pem \
  --allow-file \
  --out ithuriel.json
```

Fully verify and materialize the exact verified bytes:

```bash
ithuriel verify ithuriel.json \
  --trust trust.sqlite3 \
  --recipient agent:receiver@example.net \
  --file-root "$(pwd)" \
  --snapshot-out verified-work-order.bin
```

Signature-only inspection is intentionally a different operation and never returns acceptance:

```bash
ithuriel inspect ithuriel.json \
  --trust trust.sqlite3 \
  --recipient agent:receiver@example.net
```

## Direct HTTP receiver

The reference direct receiver is deny-by-default for canonical resolvers. File receivers require explicit roots and HTTP receivers require explicit host allowlists.

```bash
ithuriel serve \
  --host 127.0.0.1 \
  --port 8788 \
  --trust trust.sqlite3 \
  --inbox ./inbox \
  --recipient agent:receiver@example.net \
  --file-root "$(pwd)"
```

Accepted envelopes and exact canonical snapshots are stored transactionally in `inbox/.accepted.sqlite3`. Verification is not durable receipt, and durable receipt is not a consumer execution claim.

Discovery is `GET /.well-known/ithuriel`; direct delivery is `POST /.well-known/ithuriel/v1` with `Content-Type: application/ithuriel+json`.

## Offline relay and anti-spam

The optional relay profile is **closed by default**. A sender cannot enqueue merely because it knows a recipient address; it needs a recipient-issued delivery ticket.

Issue a bounded ticket:

```bash
ithuriel relay-ticket-create \
  --store relay.sqlite3 \
  --recipient agent:receiver@example.net \
  --sender agent:sender@example.org \
  --uses 20 \
  --ttl 604800 \
  --out sender-ticket.json
```

A relay mailbox configuration can require tickets (the default):

```json
{
  "version": "ithuriel-relay-config/2",
  "public_push_endpoint": "https://relay.example.net/.well-known/ithuriel/relay/v1/envelopes",
  "mailboxes": {
    "agent:receiver@example.net": {
      "pull_token_sha256": "<sha256-of-recipient-pull-secret>",
      "max_pending": 1000,
      "require_ticket": true
    }
  }
}
```

Run the relay:

```bash
ithuriel relay-serve --config relay.json --store relay.sqlite3
```

Send with a ticket:

```bash
ithuriel relay-send ithuriel.json \
  --endpoint https://relay.example.net/.well-known/ithuriel/relay/v1/envelopes \
  --ticket-file sender-ticket.json
```

The relay never resolves canonical state and never grants authority.

## Domain federation

For address-like recipients such as `agent:alice@example.com`, the optional federation profile maps the DNS domain to a relay:

```text
GET https://example.com/.well-known/ithuriel-relay?recipient=...
```

The discovery document must advertise an HTTPS push endpoint and `ticket_required:true`. The sender can omit `--endpoint` from `ithuriel relay-send` and discover the relay from the recipient domain.

This creates an email-like routing model without requiring a central broker:

```text
address -> recipient-owned DNS domain -> relay -> offline queue -> local verification
```

See `RELAY_PROFILE.md`.

## Provider and framework neutrality

The core package has no dependency on a model vendor, agent framework, storage provider, MCP implementation, or cloud service.

Extension points:

- Python library: `ithuriel`
- CLI: `ithuriel`
- resolver plugins: `ithuriel.resolvers`
- transport plugins: `ithuriel.transports`
- MCP: thin adapter over the Python API
- Skills: teach an agent when to invoke ITHURIEL; never redefine trust semantics
- enrollment: optional first-contact profile
- relay/federation: optional ticket-gated store-and-forward profile

Installed plugins are never auto-loaded by accepting receiver defaults.

## Security boundary

ITHURIEL distinguishes:

1. **Sender authentication** — receiver-owned trust says which key belongs to the sender.
2. **Routing/time/replay** — this packet is for this recipient and is fresh/idempotent.
3. **Canonical byte identity** — these exact bytes match the sender-referenced digest.
4. **Relay delivery permission** — a ticket may permit queue use; it is not sender identity or execution authority.
5. **Execution authority** — **not provided by ITHURIEL**; recipient-local policy/grants decide this.

A valid digest does not prove the canonical content is approved or safe. A delivery ticket does not prove the packet signature is valid. An enrollment binding does not authorize actions. Those separations are deliberate.

## Conformance and tests

The package includes:

- RFC 8785-compatible strings-only signing rules;
- a fixed Ed25519 conformance vector;
- exact snapshot persistence;
- duplicate-key JSON rejection;
- bounded receiver/relay surfaces;
- enrollment, replay, relay, resolver, transport, and HTTP tests.

Run:

```bash
python -m pytest -q
```

## Documents

- `PROTOCOL.md` — ITHURIEL/1 wire and receive semantics
- `ENROLLMENT_PROFILE.md` — first-contact trust bootstrap
- `RELAY_PROFILE.md` — ticket-gated store-and-forward federation
- `SECURITY.md` — security boundary and deployment guidance
- `THREAT_MODEL.md` — adversaries and non-claims
- `PLUGIN_API.md` — resolver/transport extension points
- `docs/adr/` — accepted decisions (0001–0007); 0006 is the 0.6 learning sidecar, 0007 is the 0.6.1 provenance/quota/isolation corrections
- `MCP_TOOL_SURFACE.md` — thin MCP adapter contract
- `CONFORMANCE.md` — cross-language signing vector
- `NAMING.md` — public naming/PyPI collision review
- `PUBLISHING.md` — publication checklist and current PyPI status

## Status

ITHURIEL/1 remains an experimental protocol/reference implementation. **0.6.1** is the current PyPI release of this package; **0.6.0**, **0.5.41**, and **0.5.4** remain listed. Signed, digest-matching canonical content remains untrusted input; the HTTP commands remain reference servers for deployment behind hardened TLS termination.
