RAPP: A Peer-to-Peer Agent Registry
with Deterministic Card Identity

A protocol for single-file AI agent distribution, identity,
and collection without central infrastructure

Published: April 2026  ·  Protocol: rapp-agent/1.0  ·  Status: Live
Contents
  1. 1 Abstract
  2. 2 Introduction
  3. 3 The Single-File Agent
  4. 4 The Manifest Schema
  5. 5 The Registry
  6. 6 The Seed Protocol
  7. 7 The Type System
  8. 8 Card Anatomy
  9. 9 The Submission Protocol
  10. 10 Federation
  11. 10.1 Public Seeds, Private Ownership
  12. 11 Security Model
  13. 12 Offline-First Design
  14. 13 Quality Tiers and Evolution
  15. 14 The Rapp Egg
  16. 15 The Seed-From-Data Principle
  17. 16 Conclusion
  18. 17 References
Section 1

Abstract

We propose RAPP — the RAPP Agent Registry — a protocol for distributing AI agents as single Python files with deterministic, manifest-derived card identities. Every agent is one file. Every file contains a structured manifest that can be extracted without executing any code. Every manifest produces a 64-bit seed. Every seed, applied to a fixed resolution algorithm, reconstructs a complete card identity: type, stats, abilities, rarity, and flavor — identical across every node that holds the file. No server is required to read the registry. No server is required to resolve a card. The protocol is fully operational from a static file system, a local git clone, or a browser loading resources from file://. The registry grows through federated GitHub repositories governed by the same protocol specification. This document defines the protocol in full.

Section 2

Introduction

AI agents exist. The problem is not capability — the problem is distribution. To use an AI agent today, a developer must navigate API tokens, SDK versioning, dependency managers, container runtimes, and cloud billing dashboards. A researcher must clone repositories with dozens of transitive dependencies and hope the Python version matches. A teacher must understand what a virtual environment is before they can run the first line.

This is not a tooling failure. It is an architectural failure. The unit of AI distribution is currently a service — hosted, gated, metered, ephemeral. Services require infrastructure to exist. Infrastructure requires operators. Operators can disappear. When they do, the agents go with them.

The correct unit of AI distribution is a file.

A file can be copied. A file can be emailed. A file can be stored on a USB drive and handed to someone who has never connected to the internet. A file does not require a server to exist. A file does not expire. A file is the most durable, portable, universally-understood artifact in computing.

RAPP is built on this premise. It defines a protocol where every AI agent is one Python file, every file is self-describing through an embedded manifest, and every manifest deterministically produces a card identity that travels with the file forever. The registry is a static JSON document. The store is a single HTML file. The entire system works offline.

The goal is a distribution model that scales to all of humanity — not just engineers at technology companies.

Section 3

The Single-File Agent

The protocol mandates a strict structure. Each agent is exactly one .py file. The path convention is agents/@publisher/agent_slug_agent.py — lowercase, snake_case slug, required _agent.py suffix. No subdirectories. No companion files. No build artifacts.

The file contains four required components, in order:

1. A docstring

The module-level docstring is the agent's documentation. It is free-form text. There is no separate README. There is no wiki page. The docstring is the record.

2. A __manifest__ dict

A module-level Python dict named __manifest__ containing structured metadata. This dict is the package manifest, the card specification, and the identity anchor — all in one. It is extracted via Abstract Syntax Tree (AST) parsing. The file is never imported. The code is never executed during registration. This means a malicious agent cannot influence the registry by executing code at import time.

3. A class inheriting BasicAgent

The agent class must inherit from BasicAgent imported from agents.basic_agent. This is the base class in the CommunityRAPP ecosystem. It provides the runtime harness, the name attribute, and the standard lifecycle hooks.

4. A perform() method

The single required method. It accepts keyword arguments and returns a str. Always. No exceptions, no other return types. The method is the contract.

"""
My Agent — does one thing, does it well.
One sentence description here.
"""

__manifest__ = {
    "schema": "rapp-agent/1.0",
    "name": "@publisher/my_agent",
    "version": "1.0.0",
    "display_name": "MyAgent",
    "description": "One sentence.",
    "author": "Your Name",
    "tags": ["keyword"],
    "category": "productivity",
    "quality_tier": "community",
    "requires_env": [],
    "dependencies": ["@rapp/basic_agent"],
}

from agents.basic_agent import BasicAgent

class MyAgent(BasicAgent):
    def __init__(self):
        self.name = "MyAgent"

    def perform(self, **kwargs) -> str:
        return "result"

The constraints are load-bearing. No network calls in __init__() — constructors must be fast for agent loading. Secrets via os.environ.get(), declared in requires_env, never hardcoded. display_name in the manifest must match self.name in the class. These rules are enforced at build time and in the contract test suite.

The file is the package, the manifest, and the documentation. It has no dependencies on this registry. It runs anywhere Python 3.11+ runs.
Section 4

The Manifest Schema

The __manifest__ dict conforms to schema version rapp-agent/1.0. The following fields are required. A build failure occurs if any are absent or invalid.

Field Type Description
schemastringMust be "rapp-agent/1.0"
namestring@publisher/slug — publisher namespace + snake_case slug
versionstringSemantic version: MAJOR.MINOR.PATCH
display_namestringHuman-readable name. Must match self.name in the class.
descriptionstringOne sentence. The card description.
authorstringAuthor name or handle
tagslist[str]Keyword tags for discovery and ability selection
categorystringOne of: core, pipeline, integrations, productivity, devtools

The following fields are optional with defaults:

Field Default Description
quality_tier"community"One of: experimental, community, verified, official
requires_env[]List of required environment variable names
dependencies[]List of @publisher/slug agent dependencies

The manifest is extracted using Python's ast module. The file is parsed into an abstract syntax tree and the __manifest__ assignment is located and evaluated as a literal — using ast.literal_eval(), which handles only Python literals: strings, numbers, lists, dicts, booleans, and None. No code can be injected or executed through the manifest. This is the safety foundation on which the entire registry rests.

Section 5

The Registry

registry.json is the machine-readable index of all agents. It is auto-generated by build_registry.py — the only build step in the system. It is never hand-edited. CI overwrites it on every push to agents/**.

For each agent, the registry stores:

The registry is a static file. It is served via GitHub Pages CDN. It is committed directly to the repository. Any node that clones the repository has the complete registry with no network dependency. Any node can rebuild the registry from the agent files alone — the registry is a derived artifact, never the source of truth.

The source of truth is the agent files.

Design principle: A system where the registry can be fully reconstructed from the files it indexes is a system that cannot be corrupted by registry failure. The files are the ground truth. The registry is a convenience index.

Version immutability is enforced at the registry level: a @publisher/slug@1.0.0 entry, once written, is never overwritten. A new version requires a new version string. This guarantees that any node holding a registry snapshot can verify historical file integrity against historical hashes indefinitely.

Section 6

The Seed Protocol

The seed is the core innovation of the RAPP protocol. It is a 64-bit integer forged deterministically from the agent's manifest data. Given the same manifest, the same seed is always produced — on any machine, in any timezone, across any version of the registry software. The seed encodes the agent's identity, type, tier, and capability fingerprint in a single integer that can be stored anywhere, transmitted in any format, and used to reconstruct the full card without any network access.

Bit Layout

The 64-bit seed is composed of the following fields packed into specific bit ranges:

Bits 63–32 name_hash 32 bits — FNV-1a hash of the agent's canonical name (@publisher/slug). This is the identity anchor.
Bits 31–27 category_idx 5 bits — Index into the ordered category list. Determines primary card type.
Bits 26–24 secondary_type 3 bits — Dual-type encoding derived from tags. Agents with cross-domain tags carry a secondary type.
Bits 23–22 tier_idx 2 bits — Quality tier (0=experimental, 1=community, 2=verified, 3=official). Governs evolution stage.
Bits 21–17 tag_count 5 bits — Number of tags (capped at 31). Influences stat scaling.
Bits 16–13 dep_count 4 bits — Number of declared dependencies (capped at 15). Governs complexity class.
Bits 12–0 tag_hash 13 bits — Hash of the sorted tag list. Used to select abilities from the ability pool.

The forge function

def forge_seed(manifest: dict) -> int:
    name      = manifest["name"]           # "@publisher/slug"
    category  = manifest["category"]
    tier      = manifest.get("quality_tier", "community")
    tags      = manifest.get("tags", [])
    deps      = manifest.get("dependencies", [])

    name_hash     = fnv1a_32(name)
    category_idx  = CATEGORY_ORDER.index(category) if category in CATEGORY_ORDER else 0
    secondary     = derive_secondary_type(tags)
    tier_idx      = TIER_ORDER.index(tier) if tier in TIER_ORDER else 0
    tag_count     = min(len(tags), 31)
    dep_count     = min(len(deps), 15)
    tag_hash      = fnv1a_32(",".join(sorted(tags))) & 0x1FFF

    seed  = (name_hash     & 0xFFFFFFFF) << 32
    seed |= (category_idx  & 0x1F)       << 27
    seed |= (secondary     & 0x07)       << 24
    seed |= (tier_idx      & 0x03)       << 22
    seed |= (tag_count     & 0x1F)       << 17
    seed |= (dep_count     & 0x0F)       << 13
    seed |= (tag_hash      & 0x1FFF)
    return seed

Resolution paths

Three independent paths produce identical card output. This is the losslessness guarantee of the protocol:

InputPathOutput
Agent file AST-extract manifest → forge_seed()resolve_card_from_seed() Full card
Agent name Lookup registry by name → read forged seed → resolve_card_from_seed() Full card
Seed integer resolve_card_from_seed() directly Full card

Any node holding any one of these three things — the file, the name, or the seed — can reconstruct the complete card. The card is not stored. The card is derived. This distinction is the difference between a system that can fail and a system that cannot.

Section 7

The Type System

Every agent card belongs to one of seven elemental types. Type is derived from the agent's category field and secondary tag composition. The types form a closed weakness/resistance cycle — each type is strong against one and resistant to one.

TypeColorCategory BasisCharacter
LOGIC#58a6ffdevtools, coreSystematic, precise, structural
DATA#3fb950pipelineTransformative, patient, deep
SOCIAL#e3b341integrationsConnected, adaptive, communicative
SHIELD#e6edf3security, complianceProtective, vigilant, stable
CRAFT#f85149productivity, creativeGenerative, inventive, expressive
HEAL#ff9ecbwellness, supportRestorative, empathic, durable
WEALTH#bc8cfffinance, economyAccumulative, strategic, leveraged

Weakness and resistance cycle

The cycle is: LOGIC > DATA > SOCIAL > SHIELD > CRAFT > HEAL > WEALTH > LOGIC.

Each type is weak to the type before it in the cycle and resistant to the type after it. This creates a balanced rock-paper-scissors equilibrium across all seven types — no type dominates, every type has a natural counter.

Dual-typed cards (where the secondary_type bits are non-zero) carry both the weakness of their primary type and a modified resistance that blends both types. Dual-typed cards are rarer and arise when an agent's tag composition crosses category boundaries in the manifest.

Section 8

Card Anatomy

A resolved card has the following structure. Every field is deterministic from the seed. No field is stored. No field can be changed by the agent author after the manifest is sealed.

FieldRangeDerivation
HP10 – 100Scaled from name_hash × tier_multiplier
ATK10 – 100Derived from category_idx × tag_count
DEF10 – 100Derived from dep_count and tier_idx
SPD10 – 100Inverse of dep_count (fewer deps = faster)
INT10 – 100tag_hash spread across full range
Abilities1 – 3Selected from type-specific pool by tag_hash
WeaknesstypeFixed from primary type cycle
ResistancetypeFixed from primary type cycle
Retreat Cost0 – 3Derived from dep_count
Evolution StageSeed/Base/Evolved/LegendaryDirectly from tier_idx
RarityStarter/Core/Elite/LegendaryDirectly from tier_idx
Flavor TextstringSelected from description-keyed template pool

Each ability has three fields: a name, an energy cost (0–3), and a damage value. Abilities are drawn from a type-keyed pool of hundreds of named abilities. The selection is deterministic: the tag_hash bits index into the pool modulo its length. The same tag composition always produces the same ability set.

Flavor text is selected from a pool of templates keyed to the agent's description. The selection is hash-stable. Two agents with similar descriptions may share flavor templates but will always produce different flavor text because the template parameters are drawn from their respective seeds.

Immutability contract: Once an agent's manifest is registered at a given version, its card is sealed. The author cannot change the card by updating the manifest — a manifest change requires a new version number, which produces a new seed, which produces a new card. This means every card is permanently attached to the exact version of the agent that produced it.
Section 9

The Submission Protocol

Agent submission is a two-step process. The protocol uses GitHub Issues as its API surface — no custom infrastructure, no application server, no authentication service beyond GitHub's own.

Step 1 — Register a binder

The submitter opens a GitHub Issue with the title prefix [RAR] register_binder and a body containing their publisher handle, display name, and a brief description of their namespace. The process-issues.yml workflow fires on issue open, validates the handle format (@publisher, alphanumeric plus hyphens, no reserved names), and acknowledges the registration. The binder is now associated with the publisher's GitHub identity.

Step 2 — Submit an agent

The submitter opens a second Issue with the prefix [RAR] submit_agent and attaches or pastes their agent file. The automation validates the file against the protocol contract: manifest presence, required fields, naming convention, AST extractability, security scan pass. On validation success, the file is written to staging. A human reviewer is notified.

The forge is not the submitter

This is the most important security property of the submission protocol: the submitter does not choose their card attributes. The forge algorithm determines everything. A submitter who wants a Legendary rarity card cannot write that into the manifest — the quality_tier field is validated by the reviewer and defaults to community. Tier promotions are granted by the registry maintainers, not requested by authors.

This separates identity from authority. An agent is what its code says it is. Its card is what the protocol says it is. The author owns the code. The protocol owns the card.

Staging and admin review

Submitted agents land in a staging namespace. They are visible in the registry but clearly marked as pending. The reviewer checks: does the agent do what the description claims? Does it handle errors gracefully? Are secrets managed correctly? Are there any security red flags the static scanner missed? On approval, the agent moves to its permanent namespace and the registry is rebuilt.

Section 10

Federation

RAPP is a GitHub template repository. Any organization or individual can create a federated instance by cloning the template. The result is a fully operational agent registry — with its own namespace, its own CI/CD, its own GitHub Pages deployment — in under five minutes.

A federated instance can operate in any of four modes:

ModeDescription
StandaloneIndependent registry. No upstream sync. Full local control.
DownstreamPulls agents from the upstream registry. Inherits the founding agent set.
Upstream-contributingCan submit agents to the upstream registry for official forging.
PeerMutual sync with another instance. Shared namespace agreements.

Federation configuration lives in rar.config.json. The upstream URL, sync policy, namespace reservations, and feature flags are all defined there. The template automation reads this file on first setup and configures the repository accordingly.

A binder (personal card collection) is the individual counterpart to the registry. A binder is stored in the browser's IndexedDB and localStorage. It can be exported as a JSON file and imported on any other device or any other instance. A binder is not tied to any server. A binder travels with the person.

The community grows grassroots. Every fork is a node. Every node is a registry. Every registry can contribute upstream. No single node is required for the system to function.
Section 10.1

Public Seeds, Private Ownership

The seed is public. Anyone can resolve a card from its seed. The stats, types, abilities, weakness, and rarity are visible to everyone. This is by design — the card's identity is open, just like a trading card's printed face is visible to anyone who looks at it.

Ownership is private. A card lives in exactly one binder at a time. Ownership is recorded in the binder's local state — not on any public server, not in the registry, not in the seed. The binder is the deed.

This separation is fundamental:

When a card is transferred, it leaves one binder and enters another. The seed does not change — the identity is permanent. Only the location changes. This mirrors physical trading cards: the printed stats are the same in every collection, but the card itself is in one person's binder.

Using an agent is always free. Ownership is the collectible layer — it does not gate access. Anyone can download, run, and modify any agent. Owning the card is something else entirely: it is provenance, identity, and membership in the collection.

The seed is the face of the card. The binder is the hand that holds it.
Section 11

Security Model

The security model is built on four layers: static analysis, AST-only parsing, integrity hashing, and namespace access control.

Static security scanner

Every submitted file is scanned before registration. The scanner rejects files containing any of the following patterns:

First-party agents in the @rapp namespace and a maintained allowlist of verified publishers may use elevated capabilities with explicit declaration in the manifest's requires_env field.

AST-only manifest extraction

The manifest is extracted using ast.literal_eval(). This function evaluates only Python literals — strings, numbers, booleans, lists, dicts, tuples, and None. It cannot execute function calls, access variables, import modules, or run any code. A manifest that attempts to set a field to os.environ["SECRET"] will fail extraction. This is the strongest possible guarantee against manifest injection.

SHA256 integrity hashes

The registry stores a SHA256 hash of each agent file at registration time. Any consumer of the registry can verify that the file they hold matches the registered version. This prevents silent file tampering between the registry and the consumer.

Namespace access control

CODEOWNERS in the repository enforces that only the registered owner of a namespace can merge changes under that path. A pull request to agents/@kody/ from a non-@kody identity will be blocked by the branch protection rules. Namespace squatting — registering a handle to block a legitimate publisher — is addressed by the binder registration process, which requires a GitHub identity match.

Section 12

Offline-First Design

Every read operation in the RAPP protocol works without a network connection. This is not a feature — it is a design constraint. Any system that requires network access to read its own data is a system that can fail when the network is unavailable. The network is always, eventually, unavailable.

The read path is fully offline

OperationNetwork required?How it works
Browse the registryNoregistry.json is a local file in the clone
Resolve a cardNoSeed algorithm runs locally, zero bandwidth
Open the agent storeNoindex.html is a single file, works from file://
View the binderNoIndexedDB + localStorage, browser-native
Read agent documentationNoDocstring is in the file
Run an agentNo*The file is the agent (* unless the agent calls external APIs)

Write operations require connectivity

Submitting a new agent, voting on a review, and registering a binder all require GitHub access. These are write operations — they modify the shared state of the registry. But the offline read path is unaffected. A node can hold and use the full registry indefinitely without ever writing to it.

The binder is a local-first database

The binder uses IndexedDB as its primary storage and localStorage as a fallback. The card collection, deck configurations, and favorites are all stored locally. The binder can be exported as a portable JSON file — a snapshot of the collection at any point in time — and imported on any device without any server interaction.

A git clone is a full node. The file is the agent. The seed is the card. Nothing else is required.
Section 13

Quality Tiers and Evolution

Every agent begins its life as experimental. Promotion through the tiers is earned through review, adoption, and demonstrated reliability. The tiers map directly to card evolution stages — an agent's card grows as the agent grows.

TierBadgeStageRarityPromotion Path
experimental stage 0 Seed Starter Submit via Issues. Automated validation pass.
community stage 1 Base Core Human review. Agent does what it claims. No security flags.
verified stage 2 Evolved Elite Maintainer review. Test coverage. Adoption evidence. Standards compliance.
official stage 3 Legendary Legendary Core team maintained. Foundational to the ecosystem. Long-term stability commitment.

Tier promotions are encoded in the manifest's quality_tier field and reflected immediately in the forged seed. When an agent is promoted from community to verified, its seed changes — tier_idx increments — and its card evolves. The previous card is not destroyed; it exists in the registry history as a sealed version. The new card is the current form.

This maps naturally to the trading card concept of evolution. A Seed-stage card is full of potential. A Legendary card is a proven, load-bearing piece of infrastructure. Both are real. Both have value. The evolution is earned, not purchased.

The founding set — the 131 agents registered at protocol launch on April 5, 2026 — are the genesis cards. They cannot be demoted, and their card identities at launch are sealed in the immutable registry history. They are the equivalent of the first issue of a series: whatever they become later, their origin is permanent.

Section 14

The Rapp Egg

A rapp egg is an entire Brainstem environment compressed to seeds. Each agent is a 64-bit integer. An array of 20 agent seeds is 160 bytes — 217 characters in base64. This fits in a single QR code.

The egg is the recipe, not the meal. The recipient's client reads the seeds, resolves each one, downloads the agent files if needed, and reconstructs the complete environment. The data self-assembles on the other end.

AgentsRaw bytesCompact stringMedium
540 B54 charsSMS, NFC tap
20160 B217 charsQR code, tweet
50400 B537 charsQR code
100800 B1,070 charsQR code, email

The egg format supports three tiers of payload, each at a different bandwidth level:

This is sneakernet at its purest. Two people in a room with no internet can trade entire AI environments by exchanging a short string. The string carries the seeds. The seeds carry the cards. The cards carry the agents. The agents carry the intelligence.

Section 15

The Seed-From-Data Principle

The seed protocol is not limited to agent cards. It is a general principle:

Any structured content with a defined schema can be packed into a seed and reconstructed from that seed, anywhere, offline, with zero data transfer.

The requirements are:

  1. A defined schema — fixed fields with enumerable values and known ranges.
  2. A forge function — reads the data, packs the fields into bits.
  3. A resolve function — reads the bits, reconstructs the data.
  4. A shared protocol — both sides run the same algorithm.

Minecraft does not store every block in a world. It stores a seed that the terrain generator uses to place every block. The world is "custom" but it is derived from the seed because the protocol (terrain generation rules) is shared by every client. The seed is the compressed data. The protocol is the decompressor.

The RAPP card seed protocol demonstrates this for agent identity. The same principle extends to:

The key constraint: define the data structure first. The schema is the protocol. Without the protocol, the seed is just a number. With the protocol, the seed is an entire world. This is why the card schema was locked before launch — once seeds are in the wild, the protocol that resolves them must be permanent.

Section 16

Conclusion

The protocol is defined. The registry is live. The seed algorithm is public. No single entity is required to operate the system.

Any person with Python 3.11 and a text editor can write an agent that is fully compliant with this protocol. Any person with git can hold the complete registry. Any person with a browser can resolve any card without contacting any server. Any organization with a GitHub account can operate a federated instance. Two people with a QR code can trade entire AI environments without an internet connection.

The file is the agent. The manifest is the identity. The seed is the card. The egg is the environment. The registry is the index. The store is the interface. The binder is the collection. All of it runs from a local directory. All of it works when the network is down. None of it requires a company to exist for it to keep working.

This is not a product. It is a protocol. Protocols outlast products. The internet outlasted every ISP that helped build it. Bitcoin outlasted every exchange that said it needed. The RAPP protocol is designed to the same standard: define the rules clearly enough that the rules enforce themselves, and then step back.

Fork the repository. Run your own instance. Federate when ready. Write agents. The file is the future.

Section 15

References

  1. RAPP Repository — The canonical registry, source code, and agent collection.
    github.com/kody-w/RAR
  2. api.json — Machine-readable API manifest. Autonomous agents discover endpoints, submit themselves, vote, and resolve cards.
    raw.githubusercontent.com/kody-w/RAR/main/api.json
  3. skill.md — Natural language API description for AI-to-AI agent discovery and installation.
    kody-w.github.io/RAR/skill.md
  4. CONSTITUTION.md — The governing document. Single-file principle, namespace rules, tier definitions, security policies, federation articles, and the SuperSeed founding covenant.
    github.com/kody-w/RAR/blob/main/CONSTITUTION.md
  5. The Single-File Agent (The Ode) — Why one .py file is the only pattern that scales to all of humanity.
    kody-w.github.io/RAR/ode.html
  6. RAPP FAQ — Every design decision explained: why single-file, why cards, why seeds, why no server.
    kody-w.github.io/RAR/faq.html
  7. Nakamoto, S. (2008) — Bitcoin: A Peer-to-Peer Electronic Cash System. The formal model for trustless distributed protocols that this work draws from in structure and spirit.
* * *