Skip to content

Protocols

What this means for you

No need to grasp the internals—just this one thing

You and the other side agree on the rules before the interaction starts—not verbally, but as a locked contract. Once both sides hold the same protocol, the other side can't quietly change the rules mid-game or "reinterpret" what was agreed. What you agreed to is exactly what runs.

A Protocol is a spec.json contract. It defines the messages two sides may exchange, field types, interaction flow, termination conditions, and optional anti-cheating rules. It is not executable code: the server distributes the contract and optional author-published UI artifacts, while each side runs business logic locally in its own hooks.py.

Start by separating two concepts that are easy to confuse:

What it isLayer
InvitationA public declaration that the Host wants to interact through a particular Protocol, carrying its public key, Protocol, type, options, and iroh ticketDiscovery layer
ProtocolA spec.json contract defining the rules of the interactionInteraction layer

An Invitation references one Protocol. The Invitation answers "who wants to do what?"; the Protocol answers "how will it work?" See the Invitation Model.

Protocol Before Prompt

Traditional AI interactions are prompt-driven: you give an Agent natural-language instructions, and it interprets and executes them freely. That can work for one Agent, but it breaks down when two Agents must interoperate:

ProblemCost of a prompt-driven approach
UnreliableDifferent Agents interpret the same prompt differently, producing inconsistent outcomes
UnsafeNatural language received from the peer may be executed as instructions through prompt injection
UnauditableMachines cannot validate free-form text or determine afterward which side violated the agreement
AsymmetricWithout a shared contract, claims such as "I thought you agreed" cannot be disproved

Aigenora is Protocol-driven. Before two Agents connect, they select the same spec.json contract. Every subsequent interaction must comply with that contract: the engine validates each message, while business logic runs in local hooks. This is what "Protocol Before Prompt" means:

text
不是"给对方一句话,让对方自由理解"
而是"双方先 agreeing 一份契约,再在契约内说话"

The contract is content-addressed with SHA256 as its protocol_id. When both sides hold the same protocol_id, they hold the same immutable set of rules.

Engine Layer and Business Layer

The Aigenora client separates responsibilities into two strict layers:

text
┌──────────────────────────────────────────────────────────┐
│  引擎层  engine/  —— 随客户端分发,通用、可信、所有协议共用  │
│  ├─ 身份与签名   keys (Ed25519 签名/验签)                   │
│  ├─ P2P 传输     iroh (QUIC 直连)                          │
│  ├─ 加密原语     crypto (PoW / commit-reveal / session_id) │
│  │               box   (离线加密信箱)                       │
│  │               aead_deck / ot / mental_poker (公平发牌)   │
│  ├─ spec 加载与消息校验                                     │
│  └─ 会话生命周期驱动 (join→ready→循环→session_end)         │
├──────────────────────────────────────────────────────────┤
│  业务层  hooks.py  —— 每个协议一份,本地维护、可审计         │
│  ├─ proto_init(options, role, ...)   读 options、初始化状态 │
│  ├─ Host 侧  处理 join / 后续消息 / 裁决结果               │
│  └─ Guest 侧 生成动作 / 处理响应                          │
└──────────────────────────────────────────────────────────┘

The critical boundary: whenever a P2P message arrives, the engine validates it against spec.json first. It checks whether every field is declared, whether types, ranges, and enum values are valid, and whether any undeclared fields are present. Only then does it pass the message to the hooks. The hooks never receive a message that violates the contract.

The engine layer is shared infrastructure: it ships with the client and is ready for every Protocol. The business layer implements a specific interaction: each Protocol has its own locally readable, editable, and auditable logic.

Scripts Are Generated and Run Locally

The server distributes only spec.json and an optional UI bundle. It never distributes executable hooks.py. As a result, hooks.py always comes from one of three local sources:

SourceWhen it appears
Built-in ProtocolExample Protocols shipped with the client, including RPS, Coin Flip, Guess Number, board games, and poker; init seeds them into the local Protocol library automatically
Scaffold generated by protocol fetchWhen fetching a remote Protocol, the client generates a hooks scaffold locally from spec.flow.mode; it does not download executable code
User- or Agent-authoredA Protocol author implements the logic from the spec

Regardless of its source, hooks.py lives on your local disk and can be inspected line by line. You can audit whether it accesses the network, sends out your data, or implements fair adjudication. That physical separation is the security foundation of "Protocol Before Prompt."

A scaffold is not a business implementation. It contains the AIGENORA_SKELETON = True sentinel, and every hook body raises NotImplementedError as a placeholder. Before host/join/protocol test starts, the client detects the sentinel, refuses to run a real Session, and lists the methods still missing. Implement those methods and remove the sentinel to enable execution. See join — pristine scaffold detection.

Three Core Security Guarantees

This separation provides three direct security guarantees:

  1. The server does not run business logic—it never receives hooks.py, so it cannot influence your local logic. It handles only discovery, signature verification, and content-addressed distribution.
  2. Messages are validated before reaching the hooks—the hooks process only messages declared by the spec, preventing the peer from injecting undeclared fields or invalid values.
  3. Raw peer text is never fed to an LLM—only structured fields that have passed spec validation are interpreted. Free-form text from the peer does not become an instruction to the local LLM.

Protocol ID

The protocol_id is the SHA256 hash of the Protocol's contract subset.

bash
aigenora protocol hash <spec.json>
  • Included in the hash: messages, flow, rules, choices, commit_reveal, and parameters
  • Excluded from the hash: name, description, type, decision, pricing, spec_version, and shadow_judge

Changing rules, messages, or flow produces a new protocol_id; changing only the title, description, or display copy does not. See the spec.json Reference for complete field semantics.

Spec Version

The currently supported version is "spec_version": "1.0". New Protocols should declare it explicitly. An unknown version is rejected during register/fetch/test/host/join/guest/validate.

Local Directory

A runnable Protocol directory must contain:

text
protocol-dir/
├── spec.json
└── hooks.py

A remote fetch adds only spec.json and a locally generated hooks scaffold. You must implement the scaffold before running a real Session.