agentleFS
MicrosoftKnown publishermicrosoft/aibast-agents-library/docs/vault/llms-full.txt

aibast-agents-library / vault

llms.txt8 starsChanged 3 months agoMITView on GitHub

Source: https://microsoft.github.io/aibast-agents-library/docs/vault/ . Protocol notes are pinned to RAPP/1 upstream commit 0b24e7d60786d39d97265338add9ca784bf5a7ab (MIT; see NOTICE.md). ======================================================================== FILE: README.md ======================================================================== This vault is the reference half of the RAPP production guide. The production guide tells you what to do at each of the 14 steps. This vault tells you more about each step, and explains the RAPP/1 protocol underneath it: how an agent is identified, recorded, packaged and moved. [[Reading Paths]] gives each of them a route through the notes. Protocol…

  • Reads credentials

The file

Show its rules and text

We split this llms-full.txt into the rules it gives an agent

58 rules. About 0 are common, 51 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈51

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    In the browser: search, backlinks and a graph of every link.

    line 42
  2. Distinctive:

    Every note in the RAPP/1 reference vault, grouped by section.

    line 64
  3. Very specific:

    Every [[wikilink]] works in Obsidian, because each note file is named exactly after its title.

    line 248
  4. Distinctive:

    Read in this order; each note builds on the one before.

    line 325
  5. Distinctive:

    Keep the [[Glossary]] and [[Failure Atlas]] open beside you.

    line 337
  6. Distinctive:

    If the customer says no, you have spent days, not months.

    line 418
  7. Very specific:

    One wire: Every interaction rides POST /chat or a signed append-only frame.

    line 435
  8. Distinctive:

    Ask "walk me through exactly what the end user does".

    line 514
  9. Distinctive:

    If its link is down, the guide includes a manual fallback prompt to paste into Copilot.

    line 582
  10. Distinctive:

    Stakeholders: all decision makers, correct titles?

    line 623
  11. Distinctive:

    No data sources were identified.

    line 643
  12. Distinctive:

    Only lightly. The project JSON is a delivery-tracking record.

    line 651
  13. Distinctive:

    Not directly. The poke is a business document, and the upstream RAPP/1 specification does not govern it.

    line 747
  14. Distinctive:

    Ask the LLM to update the poke with the corrections.

    line 798
  15. Distinctive:

    When the customer adds a requirement, choose:

    line 801
  16. Distinctive:

    Do not: start development.

    line 812
  17. Distinctive:

    Use the poke as a scope boundary: lock this MVP first, then expand.

    line 822
  18. Distinctive:

    Before moving on, confirm:

    line 826
  19. Distinctive:

    Not directly. Sign-off is a business agreement, outside the upstream RAPP/1 specification.

    line 845
  20. Distinctive:

    When the guide was first written, each agent took 2-3 weeks by hand.

    line 887
  21. Distinctive:

    Start from an existing agent template.

    line 895
  22. Distinctive:

    Write each agent in the BasicAgent pattern.

    line 896
  23. Distinctive:

    Test locally before [[Step 06 Code Quality Review]].

    line 898
  24. Distinctive:

    Only approved code moves to deployment.

    line 991
  25. Distinctive:

    Pass: all agents reviewed, minor fixes applied → [[Step 07 Deploy Prototype]].

    line 1052
  26. Very specific:

    Use the Deploy to Azure button in the repository README.

    line 1112
  27. Distinctive:

    Import the solution in Copilot Studio.

    line 1137
  28. Very specific:

    One endpoint to test: Every channel reaches the agents through the same wire: POST /chat with user_input, answering with response, …

    line 1173
  29. Distinctive:

    Rule: no slides, no mockups. Real execution only.

    line 1209
  30. Distinctive:

    Narrate the value: Before: name the business problem.

    line 1233
  31. Distinctive:

    Do these agents solve the business problem as you described it?

    line 1245
  32. Distinctive:

    All MVP scenarios were demonstrated.

    line 1267
  33. Distinctive:

    No major scope changes.

    line 1269
  34. Distinctive:

    SCOPE CREEP: Stop. Explain it is outside MVP scope.

    line 1276
  35. Distinctive:

    Test and refine: 1 hour.

    line 1319
  36. Distinctive:

    Every demo follows the same three-part story:

    line 1360
  37. Distinctive:

    Use the real agent names from the implementation.

    line 1371
  38. Distinctive:

    After this gate, the project leaves the prototype phase.

    line 1465
  39. Distinctive:

    Vulnerability scan: no critical or high-severity issues.

    line 1610
  40. Distinctive:

    Secrets management: all credentials in Azure Key Vault.

    line 1613
  41. Distinctive:

    Audit trail: every agent action logged with user context.

    line 1620
  42. Distinctive:

    Run the production ARM template (with the Step 11 security additions).

    line 1690
  43. Distinctive:

    Verify agents load in the production Function App.

    line 1700
  44. Distinctive:

    Test one agent call with production data.

    line 1701
  45. Distinctive:

    Import the Copilot Studio solution to production.

    line 1707
  46. Distinctive:

    Test end to end: Teams → Copilot → Function → Agents → data sources.

    line 1710
  47. Distinctive:

    Run a 30-minute training session.

    line 1716
  48. Very specific:

    Cells: Every deployment uses topology.mode: "cellular": independently observable, isolatable failure domains.

    line 1740
  49. Distinctive:

    After 2-4 weeks of pilot use, you compare real results against the MVP targets.

    line 1772
  50. Distinctive:

    Every hash in rapp/1 is computed over these bytes, so this is the foundation of the whole protocol.

    line 1874
  51. Distinctive:

    If a reader silently fixes bad input, two readers can fix it differently.

    line 1944
  52. Distinctive:

    Every ring and stage — development, qualification, Preprod, installation, production — compares the candidate's Grail bytes to the pinned …

    line 2011
  53. Distinctive:

    Every hash is domain-separated: a short tag naming its purpose is mixed in first.

    line 2096
  54. Distinctive:

    Always exactly 64 lowercase hex characters.

    line 2135
  55. Distinctive:

    If the tail came from the name, anyone who knew the name could compute the identity.

    line 2236
  56. Very specific:

    If the tail is not exactly 64 lowercase hex (for example a legacy 32-hex tail), the result is provisional.

    line 2243
  57. Distinctive:

    If two independent implementations follow the rules, they interoperate with no side agreement.

    line 2296
  58. Very specific:

    All of them ride one wire: either POST /chat, or a signed append-only frame.

    line 2308

≈ “Common” is an estimate: at least 1 in 5 of the 3,592 llms.txt files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
llms-full.txt
# RAPP/1 Reference Vault - all notes

Source: https://microsoft.github.io/aibast-agents-library/docs/vault/ . Protocol notes are pinned to RAPP/1 upstream commit 0b24e7d60786d39d97265338add9ca784bf5a7ab (MIT; see NOTICE.md).

========================================================================
FILE: README.md
========================================================================

---
title: Welcome
status: published
hook: What this vault is, who it is for, and where to start.
source: docs/rapp-guide.html; upstream RAPP/1 specification
---

# Welcome

**This vault is the reference half of the RAPP production guide.**
The [production guide](../rapp-guide.html) tells you what to do at each of the
14 steps. This vault tells you more about each step, and explains the
**RAPP/1 protocol** underneath it: how an agent is identified, recorded,
packaged and moved.

## Who it is for

- **Business leads** who run the 14-step process and want each step in depth.
- **Builders** who write and ship single-file agents.
- **Implementers** who want to read or write RAPP/1 records in another language.

[[Reading Paths]] gives each of them a route through the notes.

## What is inside

- **[[Production Guide Overview|Production Guide]]**: one note per guide step.
- **[[Protocol at a Glance|Protocol]]**: the RAPP/1 specification in plain language.
- **Operations**: release, deployment and work records in [[RAPP CICD]], [[RAPP Deploy]] and [[RAPP Work]].
- **Building**: the agent file in [[The Agent Contract]], the Brainstem in [[The Brainstem Kernel]], and pinning in [[Distros and Pinning]].
- **Reference**: terms in [[Glossary]], failures in [[Failure Atlas]], and sources in [[Sources and Provenance]].

## Ways to read it

- **In the browser:** search, backlinks and a graph of every link.
- **In Obsidian:** download the vault and open the folder. See [[How to Use This Vault]].
- **With an AI tool:** point it at `llms.txt` or `llms-full.txt` in this folder.

## Where the content comes from

Protocol notes restate the upstream RAPP/1 specification at a pinned commit.
See [[Sources and Provenance]] and the [Notice](NOTICE.md).

========================================================================
FILE: _index.md
========================================================================

---
title: Index
status: published
hook: Every note in the vault, grouped by section.
source: generated by tools/build_rapp1_vault.py
---

# Index

Every note in the RAPP/1 reference vault, grouped by section. Start with [[Welcome]] or [[Reading Paths]].

## Start Here

- [[How to Use This Vault]] - How do I read, search, download and share this vault?
- [[Reading Paths]] - Which notes should I read, in what order, for my role?

## Production Guide

- [[Production Guide Overview]] - What the 14-step RAPP production process is, who runs each step, and where the six human quality gates sit.
- [[Step 01 Discovery Call]] - How to run the discovery call whose transcript becomes the foundation for every later step.
- [[Step 02 Transcript Analysis]] - How the transcript is turned into structured project JSON and audited at Quality Gate 1.
- [[Step 03 Generate MVP Poke]] - What an MVP poke is, what goes in it, and how it is sent to the customer before any code is written.
- [[Step 04 Customer Validation]] - How the customer signs off on the MVP scope at Quality Gate 2, and what to do for each possible answer.
- [[Step 05 Generate Agent Code]] - How the locked MVP becomes Python agent files that follow the BasicAgent pattern.
- [[Step 06 Code Quality Review]] - What a reviewer checks in generated agent code at Quality Gate 3 before it is deployed.
- [[Step 07 Deploy Prototype]] - How reviewed agents get running locally, in Azure, and in Copilot Studio, and how to verify the deployment.
- [[Step 08 Demo Review]] - How the customer first sees the working prototype, and how Quality Gate 4 decides what happens next.
- [[Step 09 Generate Video Demo]] - How to turn the approved prototype into a produced, narrated demo for executives.
- [[Step 10 Final Demo Review]] - How the customer approves the produced video demo for executive sharing at Quality Gate 5.
- [[Step 11 Production Planning]] - How the prototype's requirements for security, compliance, and rollout are defined before production.
- [[Step 12 Security Sign-off]] - How IT, Security, and Compliance formally approve production deployment at Quality Gate 6.
- [[Step 13 Production Deployment]] - How the approved system is deployed to the customer's environment and rolled out to pilot users.
- [[Step 14 Post-Deployment Review]] - How the pilot is measured against the MVP targets and how Phase 2 is planned.

## Protocol

- [[Canonicalization]] - How does rapp/1 turn any JSON value into one exact byte string?
- [[Conformance Classes]] - What does an implementation have to do to claim it conforms to rapp/1, and what extra rules apply to the Grail kernel and production operations?
- [[Content Addressing]] - How does rapp/1 hash things, and why is every hash tagged with a space?
- [[Identity and the Rappid]] - What is a rappid, how is it minted, and when may it ever change?
- [[Protocol at a Glance]] - What is rapp/1, and what does it promise in one page?
- [[Protocol Layers]] - How is rapp/1 split into layers, and what may each layer do?
- [[Security Considerations]] - Which threats does rapp/1 defend against, which ones do hashes alone not stop, and what control covers each?
- [[The Egg]] - How does rapp/1 package a whole agent, application, or space so anyone can verify it before using it?
- [[The Frame]] - What is a rapp/1 frame, what are its eleven fields, and how is it verified?
- [[The Registry]] - What is the estate registry, why is it the root of trust, and how does a consumer know it is genuine and current?
- [[The Wire]] - How do RAPP systems talk to each other, and what exactly does POST /chat accept and return?
- [[Trust and Signatures]] - What does a rapp/1 signature prove, how is it checked, and how do key rotation and revocation work?
- [[Versioning and Evolution]] - How does rapp/1 change over time without breaking verification of anything already published?

## Operations

- [[RAPP CICD]] - How does one exact AI release candidate earn promotion toward production under rapp/1?
- [[RAPP Deploy]] - How does a qualified rapp/1 release reach users safely and stay provably healthy afterward?
- [[RAPP Work]] - How does rapp/1 bind a work organization to its catalog, releases, migrations, and rollback targets without granting hidden authority?

## Building

- [[Conformance and Drift]] - How do you prove an implementation conforms to rapp/1, and how do you find and fix drift in real artifacts?
- [[Distros and Pinning]] - How does this library ship the Brainstem kernel pinned by a species contract and drift-ledgered, with every difference recorded in `rapp/KERNEL-DRIFT.md`, and its own catalog around it?
- [[Implementing the Protocol]] - In what order should you build a rapp/1 implementation, and how do you know it is done?
- [[The Agent Contract]] - What exactly must a Brainstem agent file look like, and how does it reach the user through POST /chat?
- [[The Brainstem Kernel]] - What is the Brainstem kernel this library ships, and what does it guarantee to every agent and host?

## ms-rapp-1

- [[Microsoft Foundry]] - How is ms-rapp/1 used in Microsoft Foundry, and what does a Foundry agent see?
- [[ms-rapp-1 Overview]] - What is ms-rapp/1, and how does it stay backward compatible with rapp/1 and the Brainstem?
- [[One Concept Across the Stack]] - How does one Step file show up in Copilot Studio, Microsoft 365 Copilot, Foundry, the Agent Framework and the Agents SDK?
- [[RAPP Runtime]] - What is RAPP Runtime, and how does each of its pieces map to the Brainstem?
- [[Run Receipts and Change Control]] - How does ms-rapp/1 keep an AI step auditable, and how does a new Step get into production?
- [[Steps]] - What does a Step file look like, and why does it load unchanged in a Brainstem?

## Reference

- [[Failure Atlas]] - When a frame is refused, which check failed and what usually caused it?
- [[Glossary]] - What does each rapp/1 term mean, in plain words?
- [[Sources and Provenance]] - Where does this vault's protocol content come from, and which text is authoritative?

========================================================================
FILE: NOTICE.md
========================================================================

---
title: Notice
status: published
hook: Where the vault's content and viewer come from, and the licences that apply.
source: upstream licence files
---

# Notice

**The specification stays the authority.** The Protocol and Operations notes
in this vault are a plain-language expansion of the RAPP/1 specification. Each
one names the section it restates and the upstream commit it was written
against. Where a note and the specification differ, the specification wins.

## Upstream specification

- **Name:** RAPP/1 specification
- **Repository:** https://github.com/kody-w/rapp-1
- **Pinned commit:** `0b24e7d60786d39d97265338add9ca784bf5a7ab`
- **Licence:** MIT

## Vault viewer

The browser viewer (`vault.js`, `vault.css`) is adapted from the RAPP vault
viewer by the same author, provided to this repository under the MIT licence.

## Markdown renderer

`marked.min.js` is marked 12.0.2, MIT licence. Its notice is in
`vendor/marked-LICENSE.txt`.

## MIT licence (upstream specification and viewer)

```text
MIT License

Copyright (c) 2025-2026 Kody Wildfeuer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

========================================================================
FILE: Start Here/How to Use This Vault.md
========================================================================

---
title: How to Use This Vault
section: Start Here
status: published
hook: How do I read, search, download and share this vault?
source: "docs/rapp-guide.html"
---

# How to Use This Vault

This **vault** is a set of linked notes.
It expands the RAPP production guide and the rapp/1 protocol into short, readable pages.
You can read it in your browser, or download it and open it in Obsidian.

## Reading in the browser

Each note is one page. Links between notes are underlined.

- **Search** — find any note by title or text.
- **Graph** — see how notes connect to each other.
- **Backlinks** — at the bottom of a note, see which other notes link to it.

### Keyboard keys

| Key | What it does |
|---|---|
| `j` / `k` | move to the next / previous note |
| `/` | open search |
| `g` then `g` | open the graph |
| `g` then `i` | go to the index |
| `r` | open a random note |
| `m` | turn reading mode on or off |
| `?` | show or hide the keyboard hint |

## Where to start

- New here? Read [[Welcome]].
- Want a route through the notes? Pick one in [[Reading Paths]].
- Need a word explained? Use the [[Glossary]].

## Downloading the vault

You can take the whole vault with you as a real Obsidian vault.

1. Press the **Download vault** button at the top of the page.
2. You get `rapp1-vault.zip`.
3. Unzip it.
4. In Obsidian, choose **Open folder as vault** and pick the unzipped folder.

Every `[[wikilink]]` works in Obsidian, because each note file is named exactly after its title.

## How each note is built

- A short **plain-language lead** at the top.
- Sections with clear headings. Technical detail sits lower down.
- Exact identifiers stay in `code` style, for example `rapp/1`.
- A **Related** list at the end.

Each note's frontmatter names its source. See [[Sources and Provenance]].

## For AI tools

AI tools can read the vault directly:

- `llms.txt` — a short index of the notes.
- `llms-full.txt` — the full text of every note in one file.

The **Plain text** button at the top opens `llms-full.txt`.

Point an assistant at either file to ground its answers in this vault.

## Related

- [[Welcome]]
- [[Reading Paths]]
- [[Glossary]]
- [[Sources and Provenance]]
- [[Production Guide Overview]]

========================================================================
FILE: Start Here/Reading Paths.md
========================================================================

---
title: Reading Paths
section: Start Here
status: published
hook: Which notes should I read, in what order, for my role?
source: "docs/rapp-guide.html"
---

# Reading Paths

A **reading path** is a short, ordered list of notes for one role.
Pick the path that matches your job. Read top to bottom.
You can leave the path at any point and follow links.

## Pick your path

| You are | You want to | Path |
|---|---|---|
| **Business lead** | understand the process and what each step delivers | Business lead |
| **Builder** | write an agent and get it running | Builder |
| **Implementer** | build software that speaks rapp/1 | Implementer |

## Business lead

For people who sponsor, plan or review agent projects.
No code required.

1. [[Production Guide Overview]] — the 14 steps from discovery call to post-deployment review.
2. The steps, in order — start with [[Step 01 Discovery Call]] and continue through [[Step 14 Post-Deployment Review]].
3. [[Protocol at a Glance]] — a one-page view of what sits underneath.

## Builder

For people who write and ship agents.

1. [[The Agent Contract]] — what a single agent file must provide.
2. [[The Frame]] — how each event is recorded.
3. [[The Egg]] — how agents and rapplications are packaged to move between machines.
4. [[RAPP Deploy]] — how a release reaches users.

## Implementer

For engineers building a producer, consumer or mirror.
Read in this order; each note builds on the one before.

1. [[Protocol at a Glance]]
2. [[Canonicalization]]
3. [[Content Addressing]]
4. [[Identity and the Rappid]]
5. [[The Frame]]
6. [[The Wire]]
7. [[The Egg]]
8. [[Conformance Classes]]
9. [[Implementing the Protocol]]

Keep the [[Glossary]] and [[Failure Atlas]] open beside you.

## Tips

- Unsure about a word? Check the [[Glossary]].
- Want to know where a claim comes from? See [[Sources and Provenance]].
- Lost? Go back to [[How to Use This Vault]].

## Related

- [[Welcome]]
- [[How to Use This Vault]]
- [[Production Guide Overview]]
- [[Protocol at a Glance]]
- [[Implementing the Protocol]]

========================================================================
FILE: Production Guide/Production Guide Overview.md
========================================================================

---
title: Production Guide Overview
section: Production Guide
status: published
hook: What the 14-step RAPP production process is, who runs each step, and where the six human quality gates sit.
source: "docs/rapp-guide.html#overview; docs/rapp-guide.html#architecture; docs/rapp-guide.html#principles; SPEC.md §1.1, §8, §11.1, §11.2"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Production Guide Overview

The **Rapid Agent Prototype Pattern (RAPP)** turns a customer conversation into a working AI agent in days, not months.
AI does the heavy lifting. People apply judgment at **six quality gates**.
This note maps the 14 steps and shows where the rapp/1 protocol supports them.

## The idea in one line

- **Automation does the volume work:** extracting project data, drafting summaries, generating agent code.
- **Humans keep the judgment:** is this the right problem, is the code safe, is it ready to show?

Each gate takes 15-60 minutes of human time. It prevents days or weeks of wasted work.

## The 14 steps

| Step | Type | Duration | Owner |
|---|---|---|---|
| [[Step 01 Discovery Call\|1. Discovery Call]] | Manual | 30-60 minutes | Field Team |
| [[Step 02 Transcript Analysis\|2. Transcript Analysis]] | Audit (Gate 1) | 15 minutes | Delivery Team |
| [[Step 03 Generate MVP Poke\|3. Generate MVP Poke]] | Manual | 1-2 hours (manual) | Delivery Team |
| [[Step 04 Customer Validation\|4. Customer Validation]] | Audit (Gate 2) | 1-2 days | Field Team |
| [[Step 05 Generate Agent Code\|5. Generate Agent Code]] | Manual | Days-Weeks | Technical Team |
| [[Step 06 Code Quality Review\|6. Code Quality Review]] | Audit (Gate 3) | 30-60 minutes | Technical Team |
| [[Step 07 Deploy Prototype\|7. Deploy Prototype]] | Manual | 1-2 hours | Technical Team |
| [[Step 08 Demo Review\|8. Demo Review]] | Audit (Gate 4) | 30 min | Delivery Lead |
| [[Step 09 Generate Video Demo\|9. Generate Video Demo]] | Manual | 3-4 hours (manual) | Delivery Team |
| [[Step 10 Final Demo Review\|10. Final Demo Review]] | Audit (Gate 5) | 30-60 minutes (review call with customer) | Delivery Lead |
| [[Step 11 Production Planning\|11. Production Planning]] | Manual | 3-7 days (meetings + documentation) | Technical Team |
| [[Step 12 Security Sign-off\|12. Security and Compliance Sign-off]] | Audit (Gate 6) | 1-3 weeks (review process, pen testing, compliance audit) | Customer IT and Security |
| [[Step 13 Production Deployment\|13. Production Deployment]] | Manual | 1 day | Technical Team |
| [[Step 14 Post-Deployment Review\|14. Post-Deployment Review]] | Audit | Ongoing | Success Team |

Durations and owners follow the guide's overview table. Some step sections in the guide give different times; each step note carries its section's figures.

## The six quality gates

1. **Transcript Audit** — did we extract the right problem?
2. **Customer MVP Validation** — does the customer agree this is the MVP?
3. **Code Quality Review** — are the generated agents secure and correct?
4. **Demo Review** — is this ready to show the customer?
5. **Final Demo Review** — is this feedback in scope, or scope creep?
6. **Security and Compliance Sign-off** — will IT, Security and Compliance let this go live?

## Why the order matters: risk elimination

The biggest risk is spending six months on a problem nobody cares about.
RAPP puts customer checkpoints first:

- The **MVP poke** (Step 3) gets feedback before real work begins.
- By Step 6, code exists with **locked scope** and customer sign-off.
- The working demo (Step 8) is the second major checkpoint.

If the customer says no, you have spent days, not months.

## The four architecture layers

| Layer | Responsibility | Technology |
|---|---|---|
| Interface | User channels | M365 Copilot, Teams, Web, Mobile, Voice |
| Orchestration | Conversation, routing, history | Copilot Studio + Power Automate |
| Intelligence | Agent execution, tool calling | RAPP Brainstem locally, or the Azure Function App |
| Storage | Agent code, memory, workflows | Azure File Storage |

Agents **hot-load**. Locally the Brainstem re-reads its agents folder on every request. In Azure, agents in the file share's `agents/` directory refresh on a five-minute cache.

## How rapp/1 underpins the process

The guide describes the delivery process. The upstream RAPP/1 specification defines the bytes the delivered agents speak.

- **One wire.** Every interaction rides `POST /chat` or a signed append-only frame. New capability is a new agent behind `/chat`, never a sibling REST route. See [[The Wire]].
- **Five layers.** Address, identity, wire, frame and egg each name one canonical form. A higher layer must not redefine a lower one. See [[Protocol Layers]].
- **Unchanged kernel.** New behavior lives outside the pinned Grail kernel. See [[The Brainstem Kernel]] and [[Distros and Pinning]].
- **Production operations.** The upstream specification defines two operational profiles: `rapp-cicd/1` (immutable release capsules, qualification evidence, promotion, rollback) and `rapp-deploy/1` (isolated lineages, progressive exposure, quarantine, exact rollback). See [[RAPP CICD]] and [[RAPP Deploy]].

Guide section: [Framework Overview in the production guide](../rapp-guide.html#overview)

## Related

- [[Reading Paths]]
- [[Step 01 Discovery Call]]
- [[The Agent Contract]]
- [[Protocol at a Glance]]
- [[The Brainstem Kernel]]
- [[Sources and Provenance]]

========================================================================
FILE: Production Guide/Step 01 Discovery Call.md
========================================================================

---
title: Step 01 Discovery Call
section: Production Guide
status: published
hook: How to run the discovery call whose transcript becomes the foundation for every later step.
source: "docs/rapp-guide.html#step1"
---

# Step 01 Discovery Call

The **discovery call** captures the customer's biggest problems in their own words.
Its **transcript** is the input to everything that follows.
Lead with business pain, not with AI.

Guide section: [Step 1 in the production guide](../rapp-guide.html#step1)

## At a glance

- **Type:** Manual
- **Duration:** 30-60 minutes, one focused conversation with the decision makers
- **Owner:** Field Team, anyone who works with customers
- **Output:** recording, transcript, named stakeholders

## The three critical questions

### 1. What are your biggest problems?

This keeps the focus on business value, not technology.
A good answer is specific and measurable.
Example: field sales reps ask every day where to go, in what order, and what to do on arrival.
A bad answer is "we need AI".

### 2. What data sources do you have?

AI without data is useless. State this caveat up front: without data access, the project is severely limited.
Typical sources:

- **CRM systems:** Dynamics 365, Salesforce, custom systems
- **Document repositories:** SharePoint, OneDrive, file shares
- **Operational systems:** inventory, scheduling, ticketing
- **External APIs:** weather, traffic, market data

### 3. How do you solve this manually today?

The **manual process is the blueprint** for automation.
You scale what they already do. You do not invent a new workflow.
Users recognize their familiar process, just faster.

## How to run the call

**Before:**

- Enable recording (Teams auto-transcribe, or another transcription tool).
- Tell participants the call is recorded.
- Invite 1-2 key decision makers, not ten people.

**During:**

- Let them talk. Extract knowledge; do not pitch.
- Ask "walk me through exactly what the end user does".
- Get specific numbers ("20 hours per week"), not "inefficiencies".
- Note competing solutions they mention.
- Confirm data access.

## Red flags

- "We just want to try AI" — no specific problem, so no MVP.
- "We can't share any data" — AI needs data.
- "We have 50 different problems" — you need **one** focused MVP.
- "We're not sure who the decision maker is" — get the right person.

## Output and exit criteria

- **Recording file:** MP4 or audio
- **Transcript file:** plain text is ideal; a Teams `.vtt` works
- **Key stakeholders:** names and roles mentioned on the call

**Litmus test:** "If I had 6 Python agents and access to their data, could I build a prototype that solves this?"

- Yes → go to [[Step 02 Transcript Analysis]].
- No → schedule a follow-up call.

## How rapp/1 underpins this step

It does not, directly. The discovery call is a human conversation. The upstream RAPP/1 specification governs bytes, identity and the wire, not meetings.

The link comes later. The "6 Python agents" in the litmus test become files that follow [[The Agent Contract]] in [[Step 05 Generate Agent Code]].

## Related

- [[Production Guide Overview]]
- [[Step 02 Transcript Analysis]]
- [[Step 03 Generate MVP Poke]]
- [[The Agent Contract]]
- [[Glossary]]

========================================================================
FILE: Production Guide/Step 02 Transcript Analysis.md
========================================================================

---
title: Step 02 Transcript Analysis
section: Production Guide
status: published
hook: How the transcript is turned into structured project JSON and audited at Quality Gate 1.
source: "docs/rapp-guide.html#step2"
---

# Step 02 Transcript Analysis

**Transcript analysis** turns the raw discovery transcript into structured **project JSON**.
An AI agent does the extraction. A person audits the result.
This is **Quality Gate 1**: did we extract the right problem?

Guide section: [Step 2 in the production guide](../rapp-guide.html#step2)

## At a glance

- **Type:** Audit (Quality Gate 1)
- **Duration:** about 15 minutes; the AI is instant, the human review takes the time
- **Owner:** Delivery Team, the people who will build the solution
- **Input:** the transcript from [[Step 01 Discovery Call]]
- **Output:** validated `[customer]-project.json`, audit sign-off, go/no-go decision

## The tool

The **Transcript-to-Project Agent** is a Copilot Studio declarative agent.
If its link is down, the guide includes a manual fallback prompt to paste into Copilot.

How to use it:

1. Open the agent in Copilot Studio.
2. Paste the whole transcript.
3. The agent returns JSON with the extracted fields.
4. Save it as `[customer]-project.json` or import it into the project tracker.

## Example output

From the guide (a fictional company):

```json
{
 "id": "1735840999",
 "customerName": "Acme Insurance",
 "status": "planning",
 "type": "legal",
 "description": "Legal operations AI bot for contract automation",
 "stakeholders": "VP Legal, Legal Operations Manager",
 "competingSolution": "Salesforce",
 "agents": ["ContractTemplate", "ContractAnalysis", "ContractRouting"],
 "mvpUseCase": "NDA Automation Bot",
 "mvpDescription": "Automated NDA generation, analysis, and routing with approval workflows",
 "mvpTimeline": "6 weeks POC",
 "notes": "Competing with Salesforce, focus on contract automation. Latency requirement under 2 seconds.",
 "createdDate": "2025-10-15",
 "updatedDate": "2025-10-15"
}
```

The prompt constrains some fields:

- `status` is one of `planning`, `poc`, `active`, `production`, `completed`. Use `planning` unless a POC has started.
- `type` is one of `legal`, `hr`, `it`, `compliance`, `customer-service`, `sales`, `finance`, `other`.
- `agents` names are PascalCase, no spaces.

## The human audit checklist

- **Customer name:** correct legal entity?
- **Stakeholders:** all decision makers, correct titles?
- **MVP use case:** matches what the customer said?
- **Competing solutions:** noted?
- **Timeline:** realistic and confirmed?
- **Data sources:** captured?

Common corrections:

- One broad `ContractManagement` agent → three focused agents.
- `status` "active" → "planning" (nothing is built yet).
- Timeline "ASAP" → a concrete timeframe.

## Gate decision

- **Pass:** the JSON accurately represents the problem → [[Step 03 Generate MVP Poke]].
- **Fail:** key information missing or wrong → follow-up call.

**Do not proceed if:**

- The MVP use case is vague ("improve efficiency").
- No data sources were identified.
- The decision maker was not on the call.
- The problem is "nice to have", not "must solve".

Fifteen minutes here prevents weeks of building the wrong thing.

## How rapp/1 underpins this step

Only lightly. The project JSON is a delivery-tracking record. The upstream RAPP/1 specification does not define its schema.

One forward link is real. The `agents` array names the capabilities that become agent files in [[Step 05 Generate Agent Code]], each following [[The Agent Contract]].

## Related

- [[Step 01 Discovery Call]]
- [[Step 03 Generate MVP Poke]]
- [[Step 04 Customer Validation]]
- [[Production Guide Overview]]
- [[The Agent Contract]]

========================================================================
FILE: Production Guide/Step 03 Generate MVP Poke.md
========================================================================

---
title: Step 03 Generate MVP Poke
section: Production Guide
status: published
hook: What an MVP poke is, what goes in it, and how it is sent to the customer before any code is written.
source: "docs/rapp-guide.html#step3"
---

# Step 03 Generate MVP Poke

The **MVP poke** is a short, plain-language summary of what we think the customer needs.
It asks one question: "This is what I heard — is it correct?"
It is sent **before any code is written**.

Guide section: [Step 3 in the production guide](../rapp-guide.html#step3)

## At a glance

- **Type:** Manual (automation planned)
- **Duration:** 1-2 hours
- **Owner:** Delivery Team drafts; the Field Team sends it
- **Input:** the validated project JSON from [[Step 02 Transcript Analysis]]
- **Output:** a 1-2 page poke document and the email that carries it

## Why a poke, not a requirements document

- **Lightweight:** 1-2 pages, not 20.
- **Plain language:** written for business stakeholders.
- **Invites feedback:** "Did we hear you right?", not "Sign off on these requirements".
- **Fast:** sent within 24 hours of the discovery call.

The poke is both a validation checkpoint and the **specification** that guides prototype generation.

## The five sections

1. **Problem statement** — 2-3 sentences in the customer's terms, with numbers.
2. **Proposed MVP solution** — what it does, 3-4 key capabilities, and **scope boundaries** (what it does not do).
3. **Data requirements** — a simple list of the data access needed.
4. **Success metrics** — measurable targets, such as planning time from 2-3 hours a day to 5 minutes.
5. **Timeline and next steps** — a simple week-by-week roadmap.

## The generation prompt

The guide drafts the poke from the project JSON with this prompt:

```
Generate an MVP "poke" document based on this customer project JSON:
[Insert validated project JSON from Step 2]
The document should be:
- 1-2 pages maximum
- Written in plain business language (not technical jargon)
- Structured as: Problem Statement, Proposed Solution, Data Requirements, Success Metrics, Timeline
- Specific and measurable (not vague "improve efficiency")
- Include scope boundaries (what we're NOT building)
- End with clear next steps for customer to respond
Tone: Professional but approachable. We're confirming we heard them correctly, not pitching a solution.
```

## Sending it

Whoever ran the discovery call emails the poke. The email asks:

- Did we capture the problem correctly?
- Is this MVP scope right, or should we adjust?
- Are the data sources accessible?
- Any concerns before we proceed?

## Output and exit criteria

- **MVP poke document:** 1-2 pages, Word or PDF
- **Email to customer:** sent with the document attached
- **Timeline started:** the customer response window, usually 2-3 days

Total human time so far is about 1.25 hours. If the customer says "that's not what we meant", you have saved 3-6 weeks.
Any detail the customer adds is the **first feedback cycle**, before a line of code exists.

Next: [[Step 04 Customer Validation]].

## How rapp/1 underpins this step

Not directly. The poke is a business document, and the upstream RAPP/1 specification does not govern it.

Its scope boundaries do shape the build later. Each capability listed becomes an agent behind the single `/chat` endpoint, not a new API route. See [[The Wire]] and [[The Agent Contract]].

## Related

- [[Step 02 Transcript Analysis]]
- [[Step 04 Customer Validation]]
- [[Step 05 Generate Agent Code]]
- [[Production Guide Overview]]
- [[The Wire]]

========================================================================
FILE: Production Guide/Step 04 Customer Validation.md
========================================================================

---
title: Step 04 Customer Validation
section: Production Guide
status: published
hook: How the customer signs off on the MVP scope at Quality Gate 2, and what to do for each possible answer.
source: "docs/rapp-guide.html#step4"
---

# Step 04 Customer Validation

**Customer validation** is **Quality Gate 2**.
The customer confirms in writing that the MVP poke describes what they need.
This **locks scope** before any code is written. The guide calls it the most important gate.

Guide section: [Step 4 in the production guide](../rapp-guide.html#step4)

## At a glance

- **Type:** Audit (Quality Gate 2)
- **Duration:** 1-2 days, mostly waiting for the customer
- **Owner:** Field Team, who manages the customer conversation
- **Input:** the poke from [[Step 03 Generate MVP Poke]]
- **Output:** written approval, final poke, updated project JSON, green light to build

## Three possible outcomes

### 1. "Yes, that's exactly right"

- Save the sign-off email and stakeholder names.
- Mark the MVP "Approved - Ready for Development" in the tracker.
- Go straight to [[Step 05 Generate Agent Code]].

### 2. "Close, but here's what needs to change"

- Capture **all** feedback in writing, never only by phone.
- Ask the LLM to update the poke with the corrections.
- Send poke v2. Repeat until you reach outcome 1.

When the customer adds a requirement, choose:

- **Add it to the MVP** and re-send the poke, or
- **Move it to Phase 2** to deliver value faster.

New requirements often change the design. Five agents may become six, with a new focused agent for the new need. The modular shape absorbs this without a rebuild.

### 3. "This isn't what we need"

- Schedule a follow-up discovery call.
- Go back to [[Step 01 Discovery Call]].
- **Do not** start development.

## Watch for scope creep

Warning signs:

- "Can we also add ten more features?"
- "Actually, we need something completely different."
- "My boss says we also need..."

Use the poke as a **scope boundary**: lock this MVP first, then expand.

## Exit checklist

Before moving on, confirm:

- **Written confirmation** of the MVP scope.
- **Stakeholder sign-off** from the budget holder, not only end users.
- **Data access confirmed.**
- **Timeline agreed.**
- **Scope locked** — no "we'll figure it out later" items.

## Output

- **Customer approval email**, saved as proof of scope.
- **Final MVP poke** (v2 or v3) with all feedback included.
- **Updated project JSON** with status `mvp-locked` and the approval date.
- **Green light** to generate agent code.

Time invested so far: about 2 hours of human time plus 1-2 days of waiting. The risk removed: weeks of building the wrong thing.

## How rapp/1 underpins this step

Not directly. Sign-off is a business agreement, outside the upstream RAPP/1 specification.

The modular point in outcome 2 does match the protocol's design. New capability is added as a new agent behind `/chat`, never as a new endpoint. See [[The Wire]] and [[The Agent Contract]].

## Related

- [[Step 03 Generate MVP Poke]]
- [[Step 05 Generate Agent Code]]
- [[Step 01 Discovery Call]]
- [[Production Guide Overview]]
- [[The Wire]]

========================================================================
FILE: Production Guide/Step 05 Generate Agent Code.md
========================================================================

---
title: Step 05 Generate Agent Code
section: Production Guide
status: published
hook: How the locked MVP becomes Python agent files that follow the BasicAgent pattern.
source: "docs/rapp-guide.html#step5; SPEC.md §8, §9.2, §11.1"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Step 05 Generate Agent Code

This step turns the locked MVP into **agent code**: single Python files the Brainstem or Azure Function can load.
Usually one well-scoped agent is enough. Split into several agents only when the use case truly spans separate roles.

Guide section: [Step 5 in the production guide](../rapp-guide.html#step5)

## At a glance

- **Type:** Manual, with AI-assisted generation
- **Duration:** minutes to scaffold; writing the business logic is still the real work
- **Owner:** Technical Team
- **Input:** the approved poke and project JSON from [[Step 04 Customer Validation]]
- **Output:** `[agent_name]_agent.py` files, tested locally

## Then and now

When the guide was first written, each agent took 2-3 weeks by hand.
Today a scaffolded agent is generated, smoke-tested and hot-loaded in about fifteen seconds. A hand-written one is live the moment the file is saved.
The library has 72 published patterns. 70 of them use one single-file agent with several deterministic operations.

## The process

1. Review the approved poke and project JSON.
2. Identify the capabilities the MVP needs.
3. Start from an existing agent template.
4. Write each agent in the **BasicAgent pattern**.
5. Save each as `[agent_name]_agent.py`.
6. Test locally before [[Step 06 Code Quality Review]].

The **RAPP Agent Generator** (with a manual fallback prompt in the guide) drafts the code from the MVP description.

## The rules every agent follows

From the generator prompt:

1. Inherit from `BasicAgent`.
2. Class name in PascalCase, e.g. `ContractGenerationAgent`.
3. `self.name` in PascalCase with **no spaces**.
4. `perform()` **always returns a string** — never a dict or `None`.
5. Errors return descriptive strings; never raise.
6. Include complete JSON Schema `metadata` so the agent documents itself.
7. One capability per agent. Published agents run roughly 180-960 lines, median about 400.

## The template

```python
from agents.basic_agent import BasicAgent
import logging
import json

class YourAgentNameAgent(BasicAgent):
    def __init__(self):
        self.name = "YourAgentName"  # NO SPACES!
        self.metadata = {
            "name": self.name,
            "description": "Clear description of when to call this agent and what it does",
            "parameters": {
                "type": "object",
                "properties": {
                    "param1": {
                        "type": "string|integer|array|etc",
                        "description": "What this parameter is for"
                    }
                },
                "required": ["param1"]
            }
        }
        super().__init__(name=self.name, metadata=self.metadata)

    def perform(self, **kwargs):
        """
        What this method does.
        Returns: String describing the result
        """
        param1 = kwargs.get('param1')
        if not param1:
            return "Error: param1 is required"
        try:
            result = "Success: description of what happened"
            return result
        except Exception as e:
            return f"Error in {self.name}: {str(e)}"
```

The `metadata` is what the model reads to decide **when** to call the agent and with which parameters.

## How rapp/1 underpins this step

This is where the protocol becomes concrete.

- **New capability is a new agent, not a new endpoint.** The upstream RAPP/1 specification (§8) says new capability is "a new agent behind `/chat`, never a sibling REST route". Writing an agent file is exactly that. See [[The Wire]] and [[The Agent Contract]].
- **The kernel stays unchanged.** New implementation behavior must live outside the pinned Grail kernel (§11.1). Agents are dropped into the agents folder; the kernel file is not edited. See [[The Brainstem Kernel]].
- **One agent file can travel as a rapplication.** The `rapplication` egg variant (§9.2) is a ZIP that must include `rappid.json` and exactly one `agent.py` at the root. See [[The Egg]] and [[Identity and the Rappid]].

## Related

- [[The Agent Contract]]
- [[Step 04 Customer Validation]]
- [[Step 06 Code Quality Review]]
- [[The Wire]]
- [[The Egg]]
- [[The Brainstem Kernel]]

========================================================================
FILE: Production Guide/Step 06 Code Quality Review.md
========================================================================

---
title: Step 06 Code Quality Review
section: Production Guide
status: published
hook: What a reviewer checks in generated agent code at Quality Gate 3 before it is deployed.
source: "docs/rapp-guide.html#step6; SPEC.md §8"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Step 06 Code Quality Review

The **code quality review** is **Quality Gate 3**.
An experienced developer reads every generated agent for **security**, **error handling**, **integration** and **metadata quality**.
Only approved code moves to deployment.

Guide section: [Step 6 in the production guide](../rapp-guide.html#step6)

## At a glance

- **Type:** Audit (Quality Gate 3)
- **Duration:** 30-60 minutes for 6-10 agents
- **Owner:** Technical Team Lead with Python and Azure experience
- **Input:** agent files from [[Step 05 Generate Agent Code]]
- **Output:** approved code, issue log, integration notes, green light to deploy

## The review checklist

### 1. Security

- **No hardcoded credentials** — secrets come from environment variables.
- **Input validation** — required parameters are checked before use.
- **Parameterized queries** for any database access.
- **File path sanitization** for any file reads.

### 2. Error handling

- External calls wrapped in `try`/`except`.
- Errors logged with context (agent name, parameters).
- **Always return strings** — never `None`, a dict, or a raised exception.
- One failing agent must not break the others.

### 3. Integration

- Customer API endpoints are correct.
- Field names match the customer's real system.
- Auth method matches their setup (OAuth, API key, certificate).
- Required packages are listed in `requirements.txt`.

### 4. Metadata

- **Clear descriptions** so the model knows when to call the agent.
- The `required` array is accurate.
- Parameter descriptions include example values.
- Fixed options use `enum`.

## Common fixes

**Returns a dict instead of a string.**

```python
# wrong
return {"status": "success", "route": optimized_route}
# fixed
return f"Route generated successfully: {json.dumps(optimized_route)}"
```

The intelligence layer expects strings.

**Missing error context.** Replace `return "Error occurred"` with a logged, specific message that names the inputs.

**Vague description.** Replace `"Handles route planning"` with text that says what the agent does and which user requests should trigger it.

## Gate decision

- **Pass:** all agents reviewed, minor fixes applied → [[Step 07 Deploy Prototype]].
- **Fail:** major logic errors or missing integrations → send feedback to the generator and regenerate.

Review is a conversation with the AI: merge redundant agents, split overloaded ones, adjust details until the files meet the bar.

The guide reports a 94% first-attempt pass rate and 231 executable demo cases.

## Why pass rates are high

- The framework enforces one pattern: `BasicAgent`, JSON Schema metadata, string returns.
- The generator learns from working agents.
- Each agent does one thing, so it is easy to review.

## How rapp/1 underpins this step

The string-return rule matches the wire. On success, `POST /chat` returns a JSON object whose `response` member is a string, with `agent_logs` as a string of one line per agent call (§8). Agents that return strings keep that contract intact. See [[The Wire]] and [[The Agent Contract]].

For the security side of the protocol itself, see [[Security Considerations]].

## Related

- [[Step 05 Generate Agent Code]]
- [[Step 07 Deploy Prototype]]
- [[The Agent Contract]]
- [[The Wire]]
- [[Security Considerations]]

========================================================================
FILE: Production Guide/Step 07 Deploy Prototype.md
========================================================================

---
title: Step 07 Deploy Prototype
section: Production Guide
status: published
hook: How reviewed agents get running locally, in Azure, and in Copilot Studio, and how to verify the deployment.
source: "docs/rapp-guide.html#step7; docs/rapp-guide.html#architecture; SPEC.md §8, §11.1"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Step 07 Deploy Prototype

**Deploying the prototype** means getting the reviewed agents to answer real questions.
Locally there is nothing to deploy: install the Brainstem, drop the files in its agents folder, and ask.
Move to **Azure Functions** and **Copilot Studio** when the customer needs access without your laptop.

Guide section: [Step 7 in the production guide](../rapp-guide.html#step7)

## At a glance

- **Type:** Manual
- **Duration:** minutes locally; 1-2 hours for the cloud tiers, with scripts
- **Owner:** Technical Team
- **Input:** approved agents from [[Step 06 Code Quality Review]], project JSON, integration notes, the `microsoft/aibast-agents-library` repository
- **Output:** a working prototype reachable from Teams or web chat, verified before the demo

## The cloud path

### 7.1 Deploy Azure infrastructure

Use the **Deploy to Azure** button in the repository README. It provisions from `azuredeploy.json`:

- Azure Function App (stateless intelligence layer)
- Azure File Storage (agent code and user memory)
- Application Insights
- Networking and security configuration

It completes in 5-10 minutes.

### 7.2 Run the setup script

```
git clone https://github.com/microsoft/aibast-agents-library.git
cd aibast-agents-library
./deploy.sh # or deploy.ps1 on Windows
```

### 7.3 Deploy your agents

Copy the approved `.py` files into the agents location: deploy from VS Code, or drag them into the File Storage `agents` folder.
Agents **hot-load** with no restart. In Azure they refresh within five minutes.

### 7.4 Connect to Copilot Studio

1. Download `solutions/<slug>/exports/<slug>-copilot-studio-solution.zip` and its deployment settings JSON.
2. Import the solution in Copilot Studio.
3. Set environment variables (Function URL, API key).
4. Enable channels: Teams, Web, Outlook.
5. Publish.

## Verification checklist

| Check | How | Expected |
|---|---|---|
| Function App running | Portal → Overview | Status "Running" |
| Agents loaded | File Storage → agents folder | Your `.py` files |
| Function responds | POST to Function URL | Lists available agents |
| Copilot Studio connected | Test chat | Replies to "Hello" |
| Agent calls work | Ask for one agent | Agent runs, returns result |
| Memory persists | Tell it something, ask later | It remembers |

## Common issues

- **Timeouts:** raise `functionTimeout` in `rapp_ai/host.json` and republish. A portal edit is overwritten by the next deployment.
- **Copilot Studio can't reach the Function:** rarely CORS. Check the Function is running and the key is right. Narrow `allowedOrigins` before production.
- **Agents not loading:** the Function App managed identity is missing a storage role. The storage account disallows shared keys, so no connection string will work.

## Rehearse before the demo

Role-play every MVP scenario. Check that:

- The model picks the **right agent** for each request.
- **Parameters** arrive correctly.
- Responses are useful and well formatted.
- **Invalid inputs fail gracefully.**
- Memory works across messages.

Then move to [[Step 08 Demo Review]].

## How rapp/1 underpins this step

- **One endpoint to test.** Every channel reaches the agents through the same wire: `POST /chat` with `user_input`, answering with `response`, `agent_logs` and `session_id`. `GET /health` is the liveness probe (§8). See [[The Wire]].
- **Deploying agents does not change the kernel.** New behavior lives outside the pinned Grail kernel (§11.1). Hot-loading agent files is that rule in practice. See [[The Brainstem Kernel]] and [[Distros and Pinning]].
- **Later stages.** Qualified releases and progressive rollout to production are covered by [[RAPP CICD]] and [[RAPP Deploy]], used from [[Step 13 Production Deployment]].

## Related

- [[Step 06 Code Quality Review]]
- [[Step 08 Demo Review]]
- [[The Wire]]
- [[The Brainstem Kernel]]
- [[RAPP Deploy]]
- [[Failure Atlas]]

========================================================================
FILE: Production Guide/Step 08 Demo Review.md
========================================================================

---
title: Step 08 Demo Review
section: Production Guide
status: published
hook: How the customer first sees the working prototype, and how Quality Gate 4 decides what happens next.
source: docs/rapp-guide.html#step8
---

# Step 08 Demo Review

**Demo Review** is the first time the customer sees their agents actually working.
You record the live prototype solving the agreed MVP scenarios and send it for feedback.
This step is **Quality Gate #4**: approve, iterate, or stop scope creep.

Guide section: [Step 8 in the production guide](../rapp-guide.html#step8)

## What this step is

- **Goal:** film the working prototype solving the MVP scenarios, then collect the customer's verdict.
- **Rule:** no slides, no mockups. Real execution only.
- **Time:** 2-4 hours in total.
  - Record demo: 30-60 minutes.
  - Optional edit: 30 minutes.
  - Customer review: 1-2 days.
  - Feedback session: 30-60 minutes.

## Who does it

- **Human:** records the screen, narrates, and collects customer feedback.
- **Automation:** the agents run the MVP scenarios in real time.

## Inputs (from Step 07)

- **Live prototype**, deployed and tested ([[Step 07 Deploy Prototype]]).
- **M365 Copilot access** through Teams, Outlook, or web.
- **Rehearsal notes** on which scenarios work.
- **Approved MVP doc**, signed by the customer in [[Step 04 Customer Validation]].

## How to record

1. **Prepare.** Open M365 Copilot (Teams or web, whichever is cleaner). Load the approved scenarios. Start a screen recorder.
2. **Record each MVP scenario.** Show the agent being called and the real answer.
3. **Show behind the scenes (optional).** Briefly show agent calls in Application Insights. This proves it is not a mockup.
4. **Narrate the value.** Before: name the business problem. During: say what the agent is doing. After: state the result.

### The "waiter" pattern

The customer sees a simple conversation.
Behind it, the LLM takes the request, calls the right agent with parameters, and returns a clean answer.
The user never needs to see the orchestration.

## Sending the demo

The guide gives an email template. It lists each scenario with timestamps and asks **two questions**:

1. Do these agents solve the business problem as you described it?
2. Is there anything you'd like adjusted before we move to production?

Then hold a 30-60 minute feedback call. Useful questions:

- "Did the agents solve the problem as you described it?" (scope alignment)
- "Were the results accurate and useful?" (data integration quality)
- "Is there anything you'd change or add?" (scope creep detector)
- "Can you see this being used by your team?" (adoption readiness)
- "What would production deployment look like?" (sets up Steps 11-14)

## Outputs

- **Demo video:** a 10-15 minute recording showing all MVP scenarios.
- **Customer feedback notes.**
- **Approval email:** written confirmation to proceed.
- **Iteration log** (if needed).
- **Green light for production:** a customer-approved prototype ready for final polish.

Checklist before [[Step 09 Generate Video Demo]]:

- The customer watched the full demo.
- All MVP scenarios were demonstrated.
- Written approval was received.
- No major scope changes.
- The production timeline was discussed.

## The gate: three outcomes

- **APPROVED.** Proceed to [[Step 09 Generate Video Demo]].
- **ITERATE.** Loop back to [[Step 05 Generate Agent Code]], regenerate the affected agents, redeploy, re-record.
- **SCOPE CREEP.** Stop. Explain it is outside MVP scope. Keep the original scope or restart at [[Step 01 Discovery Call]].

**The "while we're at it" trap:** new capabilities mean new discovery, new MVP, and new testing. Log them for the next phase and finish this MVP first.

## How rapp/1 underpins this step

- The "waiter" pattern is the **agent contract** at work: the model chooses an agent and calls it through one chat surface. See [[The Agent Contract]] and [[The Brainstem Kernel]].
- An ITERATE loop goes back to [[Step 05 Generate Agent Code]] to regenerate the affected agents, then redeploys and re-records.

## Related

- [[Step 07 Deploy Prototype]]
- [[Step 09 Generate Video Demo]]
- [[Step 04 Customer Validation]]
- [[The Agent Contract]]
- [[Production Guide Overview]]

========================================================================
FILE: Production Guide/Step 09 Generate Video Demo.md
========================================================================

---
title: Step 09 Generate Video Demo
section: Production Guide
status: published
hook: How to turn the approved prototype into a produced, narrated demo for executives.
source: docs/rapp-guide.html#step9
---

# Step 09 Generate Video Demo

**Generate Video Demo** produces a polished, shareable video of the solution.
It is for executives, sales decks, and internal evangelism.
Unlike the raw screen recording in Step 08, this is a **produced demo** with scripted narration and polished visuals.

Guide section: [Step 9 in the production guide](../rapp-guide.html#step9)

## What this step is

- **Goal:** a self-contained demo video with Azure TTS narration.
- **Time (manual):** 3-4 hours.
  - Build the demo JSON in the Local-First Chat Animation Studio: 1-2 hours.
  - Script narration and timing: 1 hour.
  - Test and refine: 1 hour.
- **Automation vision:** a Video Demo Generator creates the demo JSON from a prototype walkthrough, cutting the time to about 30 minutes.

## Who does it

- **Human:** builds the demo structure, writes the script and narration, and adjusts timing.
- **Tool:** the **Video Demo Generator**, a Copilot Studio declarative agent. The guide also includes a copy-paste fallback prompt if the agent link is not working.

## Inputs (from Step 08)

- **Customer-approved prototype** from [[Step 08 Demo Review]].
- **Screen recording** of real agent execution.
- **MVP documentation:** business value, metrics, use cases.
- **Project JSON:** customer, stakeholders, timeline (from [[Step 02 Transcript Analysis]]).

## The demo JSON

The generator returns one JSON document with four parts:

- `demoMetadata` - title, customer, industry, `totalDuration`, `voiceName`, `createdDate`.
- `demoSteps` - 7-10 steps, each with `id`, `name`, `duration`, `voiceText`, and a `narrator` overlay.
- `chatInteractions` - the user, system, and agent messages shown per step.
- `agentCards` - an agent `title`, `status`, and `details` per step.

A fragment of the required structure, as given in the guide:

```json
{
  "demoMetadata": {
    "title": "[Customer Name] AI Agent Demo",
    "customer": "[Customer Name]",
    "industry": "[Industry: legal, sales, hr, it, etc.]",
    "totalDuration": "[Total seconds, e.g., 75]",
    "voiceName": "en-US-GuyNeural",
    "createdDate": "[YYYY-MM-DD]"
  }
}
```

## The narrative arc

Every demo follows the same three-part story:

1. **Problem hook (8-10 s):** the painful manual process.
2. **Solution demo (40-50 s):** 3-4 agent capabilities with specific examples.
3. **Business impact (10-15 s):** ROI, metrics, scale.

Writing rules from the prompt:

- `voiceText` is written for speech, about 150 words per minute.
- `duration` matches the narration (20 words is about 8000 ms).
- Overlays carry specific metrics: time saved, accuracy, cost reduction.
- Use the real agent names from the implementation.

## Output and exit

- **Demo JSON file:** `demos/[customer-name]-demo.json`
- **Standalone HTML demo:** a self-contained file with narration.
- **Hosted URL** (optional): GitHub Pages or an internal server link.
- **MP4 video** (optional): a recorded playthrough for PowerPoint.
- **Usage instructions:** how to view, navigate, and share.

Quality check before sharing:

- Metrics match the project JSON.
- Narration timing is natural.
- Agent cards appear at the right steps.
- The customer name is spelled correctly.
- The demo works on mobile.

These go to the customer for sign-off in [[Step 10 Final Demo Review]].

## How rapp/1 underpins this step

This step is presentation work. The upstream RAPP/1 specification does not define the demo JSON format.
The link to the protocol is indirect: the agent names and behavior shown must match the real agents that passed [[Step 06 Code Quality Review]] and run under [[The Agent Contract]].

## Related

- [[Step 08 Demo Review]]
- [[Step 10 Final Demo Review]]
- [[Step 07 Deploy Prototype]]
- [[The Agent Contract]]
- [[Production Guide Overview]]

========================================================================
FILE: Production Guide/Step 10 Final Demo Review.md
========================================================================

---
title: Step 10 Final Demo Review
section: Production Guide
status: published
hook: How the customer approves the produced video demo for executive sharing at Quality Gate 5.
source: docs/rapp-guide.html#step10
---

# Step 10 Final Demo Review

**Final Demo Review** is **Quality Gate #5**.
The customer confirms the polished video accurately represents their solution.
Once approved, the demo is locked and can be shared with executives, board members, or field teams.

Guide section: [Step 10 in the production guide](../rapp-guide.html#step10)

## What this step is

- **Goal:** final customer approval of the video demo.
- **Time:** 30-60 minutes (one review call).
- **Decision:** approve for production use, or request adjustments.

## Who does it

- **Delivery team:** walks the customer through the demo and the checklist.
- **Customer:** checks facts, tone, and branding, and grants distribution permission.

## Inputs (from Step 09)

- **Video demo** (HTML or MP4) with Azure TTS narration, from [[Step 09 Generate Video Demo]].
- **Demo JSON:** the full script with steps, metrics, and narration.
- **Distribution plan:** email, hosted URL, or embedded in a deck.

## Review checklist

| Review item | What to check |
|---|---|
| **Metrics accuracy** | All numbers match reality: time saved, ROI, accuracy gains. |
| **Messaging tone** | Narration fits the audience (executives vs. field users). |
| **Company branding** | Customer name spelled correctly; no competitor references. |
| **Technical accuracy** | Integration points and systems mentioned are correct. |
| **Shareability** | Customer is comfortable with internal distribution. |

## The gate: two outcomes

- **APPROVED.** The demo is locked. Proceed to [[Step 11 Production Planning]].
- **ITERATE.** Minor fixes to narration, metrics, or branding. Fix and re-review.

## Outputs

- **Approved demo files:** final HTML or MP4, locked for distribution.
- **Distribution permission:** customer sign-off for executive sharing.
- **Usage guidelines:** who can see it and how to present it.

## Where this sits in the timeline

The guide groups Steps 9-10 as about **one day** of work.
After this gate, the project leaves the prototype phase.
Steps 11-14 are the production phase, mostly owned by the customer's IT team.

## How rapp/1 underpins this step

This is a human review gate. The upstream RAPP/1 specification does not define it.
The practical tie-in: "metrics accuracy" and "technical accuracy" are only checkable because the demo shows the real deployed agents, not a mockup. Those agents follow [[The Agent Contract]].

## Related

- [[Step 09 Generate Video Demo]]
- [[Step 11 Production Planning]]
- [[Step 08 Demo Review]]
- [[Production Guide Overview]]
- [[Reading Paths]]

========================================================================
FILE: Production Guide/Step 11 Production Planning.md
========================================================================

---
title: Step 11 Production Planning
section: Production Guide
status: published
hook: How the prototype's requirements for security, compliance, and rollout are defined before production.
source: docs/rapp-guide.html#step11; protocols/rapp-cicd/1/SPEC.md §1-3; protocols/rapp-deploy/1/SPEC.md §1-4
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Step 11 Production Planning

**Production Planning** turns a working prototype into a plan for a production system.
You work with the customer's IT, Security, and Compliance teams.
The result is a **requirements document** and a **phased rollout plan**.

Guide section: [Step 11 in the production guide](../rapp-guide.html#step11)

## What this step is

- **Goal:** define production deployment requirements with the customer.
- **Time:** 3-7 days of meetings and documentation.
- **Owner:** Technical Team. In the guide's team setup (Station 4, Steps 11-14) the owner is the customer IT team, with Team Member C for support escalation.

## Inputs

- The locked, approved demo from [[Step 10 Final Demo Review]].
- The prototype and its reviewed agents from [[Step 07 Deploy Prototype]].

## Questions for IT and Security

- **Data residency:** where may data be stored (US, EU, on-prem)?
- **Authentication:** SSO required? Azure AD integration?
- **Network access:** public internet, or private endpoints?
- **Audit logging:** which events must be logged?
- **Encryption:** at rest and in transit.
- **Compliance frameworks:** HIPAA, SOC 2, GDPR, FedRAMP?

## Prototype vs. production

- **Prototype:** one Azure Function App, public endpoints, dev subscription.
- **Production:** redundant deployments, private endpoints, the customer's subscription.

Common security additions:

- Azure AD authentication (no anonymous access)
- Private Link for the Function App
- Azure Key Vault for secrets, not environment variables
- Application Gateway with WAF
- DDoS protection
- Managed Identity for service-to-service auth
- Azure Monitor alerts for security events

## Rollout strategy

| Phase | Users | Duration | Success criteria |
|---|---|---|---|
| 1: Pilot | 5-10 power users | 2 weeks | 80% adoption, no critical bugs |
| 2: Early Adopters | 25-50 users | 4 weeks | Positive NPS, feature requests captured |
| 3: General Availability | All users | 8 weeks | ROI metrics achieved, support tickets low |

## Outputs

- **Production requirements doc:** security, compliance, infrastructure.
- **Rollout plan:** phased schedule with success metrics.
- **Support plan:** who handles questions and bugs.
- **Training materials:** guides, video tutorials, FAQ.

These go to [[Step 12 Security Sign-off]].

## How rapp/1 underpins this step

The upstream RAPP/1 specification has two operational profiles that match this planning work. See [[RAPP CICD]] and [[RAPP Deploy]].

- **Release identity.** In `rapp-cicd/1`, a `rapp-cicd/1-release` payload names the complete candidate before qualification: source commit and tree, the exact artifact, and the pinned Grail kernel. Its identity is its particle hash ([[Content Addressing]]).
- **Promotion policy.** A `rapp-cicd/1-policy` payload declares the ordered promotion path and required evidence. Planning which reviews must pass maps onto this.
- **Rollout plan.** In `rapp-deploy/1`, a `rapp-deploy/1-plan` covers topology, waves, health budgets, state, data, and recovery.
- **Phased waves.** Waves begin with `shadow` at zero traffic, only increase, and end with `global` at 10,000 basis points. The guide's Pilot, Early Adopters, and GA phases are the business view of the same idea.
- **Rollback target.** An authorized plan binds a resolvable, previously authorized rollback release.

Neither profile prescribes a cloud provider, so the Azure controls above are the customer's choice, not protocol requirements.

## Related

- [[Step 10 Final Demo Review]]
- [[Step 12 Security Sign-off]]
- [[RAPP CICD]]
- [[RAPP Deploy]]
- [[Distros and Pinning]]
- [[Security Considerations]]

========================================================================
FILE: Production Guide/Step 12 Security Sign-off.md
========================================================================

---
title: Step 12 Security Sign-off
section: Production Guide
status: published
hook: How IT, Security, and Compliance formally approve production deployment at Quality Gate 6.
source: docs/rapp-guide.html#step12; protocols/rapp-cicd/1/SPEC.md §1-5; SPEC.md §14
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Step 12 Security Sign-off

**Security Sign-off** is **Quality Gate #6**, the last human gate before production.
The customer's IT, Security, and Compliance teams formally approve that the system meets every production requirement.
Nothing goes live without **written approval**.

Guide section: [Step 12 in the production guide](../rapp-guide.html#step12)

## What this step is

- **Goal:** formal production approval from the customer's IT, Security, and Compliance teams.
- **Time:** 1-3 weeks (review process, pen testing, compliance audit).
- **Note:** the guide says production is "mostly waiting for security and compliance approvals." It runs async and does not consume delivery team time.

## Inputs

- The production requirements doc, rollout plan, and support plan from [[Step 11 Production Planning]].
- The reviewed agent code from [[Step 06 Code Quality Review]].

## Security review checklist

- **Penetration testing:** third-party audit completed.
- **Vulnerability scan:** no critical or high-severity issues.
- **Code review:** security team reviewed the agent code.
- **Access controls:** RBAC configured, least privilege enforced.
- **Secrets management:** all credentials in Azure Key Vault.
- **Logging and monitoring:** security events captured and alerted.

## Compliance review checklist

- **Data classification:** PII/PHI handling documented.
- **Data retention:** policies set for user memory and logs.
- **Audit trail:** every agent action logged with user context.
- **Frameworks:** SOC 2, HIPAA, GDPR requirements met.
- **Third parties:** vendor BAAs signed where needed.

## The gate: three outcomes

- **APPROVED.** Proceed to [[Step 13 Production Deployment]].
- **CONDITIONAL APPROVAL.** Fix the minor issues and re-submit.
- **BLOCKED.** Major issues. Back to [[Step 11 Production Planning]] for redesign.

## Outputs

- **Security sign-off:** written approval from the CISO or Security team.
- **Compliance sign-off:** approval from Compliance or Legal.
- **Pen test report** from the third-party audit.
- **Production deployment authorization:** go-live approval.

## How rapp/1 underpins this step

- **Approval bound to exact bytes.** In [[RAPP CICD]], evidence records (`rapp-cicd/1-evidence`) and the decision (`rapp-cicd/1-promotion`) refer to one exact release candidate. A changed payload has a new particle hash, so it is a different release. An approval cannot silently carry over to changed code.
- **Signed, not just recorded.** Authoritative payloads travel in signed RAPP/1 frames. A local unsigned file is a draft and cannot authorize promotion. See [[The Frame]] and [[Trust and Signatures]].
- **Kernel drift is a blocker.** The release-shaped artifact must contain the pinned Grail bytes before its tests and approval. A digest mismatch is a blocking `kernel-drift` finding. See [[Security Considerations]] and [[Distros and Pinning]].

The upstream specification does not replace pen tests or compliance audits. It makes the approved candidate unambiguous.

## Related

- [[Step 11 Production Planning]]
- [[Step 13 Production Deployment]]
- [[Security Considerations]]
- [[RAPP CICD]]
- [[Trust and Signatures]]

========================================================================
FILE: Production Guide/Step 13 Production Deployment.md
========================================================================

---
title: Step 13 Production Deployment
section: Production Guide
status: published
hook: How the approved system is deployed to the customer's environment and rolled out to pilot users.
source: docs/rapp-guide.html#step13; protocols/rapp-deploy/1/SPEC.md §1-5
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Step 13 Production Deployment

**Production Deployment** moves the system from prototype to production.
It runs in the customer's Azure subscription with every security and compliance control.
Then a **phased rollout** begins with pilot users.

Guide section: [Step 13 in the production guide](../rapp-guide.html#step13)

## What this step is

- **Goal:** deploy the approved system and start the pilot.
- **Time:** 2-3 days of deployment, then a 2-4 week pilot.
- **Owner:** Technical Team.

## Inputs

- **Production deployment authorization** from [[Step 12 Security Sign-off]].
- The rollout and support plans from [[Step 11 Production Planning]].
- The reviewed agents from [[Step 06 Code Quality Review]].

## Deployment steps

**1. Infrastructure**

1. Run the production ARM template (with the Step 11 security additions).
2. Configure Azure AD authentication.
3. Set up Private Link endpoints.
4. Configure Application Gateway and WAF.
5. Enable Azure Monitor alerts.
6. Configure backup and disaster recovery.

**2. Agents**

1. Copy reviewed agents from prototype to production File Storage.
2. Verify agents load in the production Function App.
3. Test one agent call with production data.
4. Configure production data source connections.
5. Validate memory persistence in production Azure Storage.

**3. M365 integration**

1. Import the Copilot Studio solution to production.
2. Configure the production Azure Function URL.
3. Enable the Teams channel for the pilot group.
4. Test end to end: Teams → Copilot → Function → Agents → data sources.
5. Verify SSO works.

**4. Pilot onboarding**

- Send a welcome email with access instructions.
- Run a 30-minute training session.
- Provide a Teams support channel.
- Set expectations: this is Phase 1, and feedback shapes improvements.

## Monitoring during the pilot (weeks 1-2)

- **Daily check-ins** on Application Insights errors.
- **Weekly survey** to pilot users (NPS, issues, feature requests).
- **Performance metrics:** response time, success rate, usage frequency.
- **Hot fixes:** critical bugs within 24 hours.

## Outputs

- **Production system** with all security controls.
- **Pilot users active:** 5-10 people using agents daily.
- **Monitoring dashboard** for usage and performance.
- **Support process** with a defined escalation path.

## How rapp/1 underpins this step

[[RAPP Deploy]] (`rapp-deploy/1`) describes this step in protocol terms.

- **No in-place changes.** `candidate_isolated` must be true and `in_place_mutation` must be false. Any behavior-affecting change creates a new release. A pilot hot fix is therefore a new release, not an edit to the running one.
- **Serving and candidate lineages.** The release receiving traffic and the release under exposure are kept separate.
- **Cells.** Every deployment uses `topology.mode: "cellular"`: independently observable, isolatable failure domains.
- **Health is evidence.** A `rapp-deploy/1-health` record is one candidate-bound observation window in one cell. It cannot label itself healthy when a budget failed.
- **Decisions.** A `rapp-deploy/1-decision` is advance, complete, hold, rollback, or quarantine.
- **User work is kept.** Acknowledged user work must not be discarded by rollback.

The kernel under the agents stays pinned. See [[The Brainstem Kernel]] and [[Distros and Pinning]].

## Related

- [[Step 12 Security Sign-off]]
- [[Step 14 Post-Deployment Review]]
- [[RAPP Deploy]]
- [[RAPP CICD]]
- [[The Brainstem Kernel]]
- [[Failure Atlas]]

========================================================================
FILE: Production Guide/Step 14 Post-Deployment Review.md
========================================================================

---
title: Step 14 Post-Deployment Review
section: Production Guide
status: published
hook: How the pilot is measured against the MVP targets and how Phase 2 is planned.
source: docs/rapp-guide.html#step14; docs/rapp-guide.html#scaling; protocols/rapp-deploy/1/SPEC.md §4-5
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Step 14 Post-Deployment Review

**Post-Deployment Review** closes the loop.
After 2-4 weeks of pilot use, you compare real results against the MVP targets.
You validate **ROI** and plan **Phase 2**.

Guide section: [Step 14 in the production guide](../rapp-guide.html#step14)

## What this step is

- **Goal:** measure success, gather lessons, plan the next phase.
- **Time:** 1-2 hours (a review meeting with the customer).
- **When:** 2-4 weeks after pilot launch in [[Step 13 Production Deployment]].

## Inputs

- Pilot monitoring data and weekly survey results from Step 13.
- The target metrics agreed in the MVP ([[Step 04 Customer Validation]]).
- The projected savings shown in the demo ([[Step 09 Generate Video Demo]]).

## Quantitative review

| Metric | Target (from MVP) |
|---|---|
| Time saved per user per day | 45 minutes |
| Agent accuracy | 95% |
| User adoption rate | 80% |
| Agent calls per day | 20+ per user |

Each row is filled with the measured value and marked met, partial, or missed.

## Qualitative review

- **User satisfaction (NPS)** from pilot surveys.
- **Top feature requests** for Phase 2.
- **Pain points:** what is not working.
- **Unexpected use cases.**

## Lessons learned

- **What worked:** most-used agents, training that landed, smooth integrations.
- **What needs work:** accuracy issues, where users got stuck, unreliable data connections.

## Phase 2 options

- **Wider rollout,** for example from 10 pilot users to 50+.
- **New agents** from user requests.
- **More integrations.**
- **Advanced features:** multi-agent workflows, proactive alerts, scheduled tasks.

## Worked example from the guide

A field sales pilot after 4 weeks:

- 10 pilot users × 42 min saved per day (target was 45).
- 4 weeks × 5 days = 20 days.
- Total: 140 hours saved across 10 users.
- Extrapolated to 200 users: 35,000 hours per year (close to the 37,500 target).
- **Decision:** proceed with Phase 2 to all 200 reps.

## Outputs

- **Success metrics report.**
- **User feedback summary:** NPS, quotes, requests.
- **ROI validation:** actual vs. projected savings.
- **Phase 2 proposal:** a 3-6 month roadmap.
- **Case study** (optional) for similar projects.

## The whole framework

The guide's summary: production deployment takes 3-5 weeks, mostly waiting for approvals.
Steps 11-14 run async and do not block the delivery team, which is how a small team runs many projects at once.
Phase 2 requests that need new capability start a new cycle at [[Step 01 Discovery Call]].

## How rapp/1 underpins this step

- **Expanding the rollout** maps onto later waves in [[RAPP Deploy]]. Traffic only increases, previously exposed cells are never removed, and the last wave is `global` at 10,000 basis points.
- **Each advance needs fresh evidence.** A decision cannot advance until every selected cell meets its observation duration and healthy windows.
- **New agents are new releases.** Any behavior-affecting change creates a new [[RAPP CICD]] release, so Phase 2 work goes back through qualification and promotion.

## Related

- [[Step 13 Production Deployment]]
- [[Step 01 Discovery Call]]
- [[RAPP Deploy]]
- [[RAPP CICD]]
- [[Production Guide Overview]]

========================================================================
FILE: Protocol/Canonicalization.md
========================================================================

---
title: Canonicalization
section: Protocol
status: published
hook: How does rapp/1 turn any JSON value into one exact byte string?
source: "SPEC.md §4; book/02-canonicalization.md; book/A-reference-manual.md §A.1; conformance/vectors.json (4_canonical, 4_refuse)"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Canonicalization

**Canonicalization** turns a JSON value into **one exact byte string**.
The same value always gives the same bytes, on every machine.
Every hash in rapp/1 is computed over these bytes, so this is the foundation of the whole protocol.

## The rule in one line

`canonical(v)` is the UTF-8 byte string produced by **RFC 8785 JCS** (JSON Canonicalization Scheme) for the value `v`.
It is defined only over I-JSON (RFC 7493).

JCS fixes:

- **member-name order** (by UTF-16 code unit),
- **string escaping**,
- **number format** (ECMAScript `Number::toString`).

There is **no insignificant whitespace** and **no byte-order mark** in the output.

## Example

From the conformance vectors. The input value:

```json
{
  "a": [3, 2],
  "b": 1,
  "c": { "x": 2, "y": 1 }
}
```

has the canonical form:

```
{"a":[3,2],"b":1,"c":{"x":2,"y":1}}
```

Whitespace is gone. Array order is kept. Object keys are always emitted in sorted order.

## What gets refused

An implementation **MUST refuse, never repair**, a value that contains, at any depth:

- **duplicate member names** in one object;
- an **unpaired UTF-16 surrogate**, or a **Unicode noncharacter** (U+FDD0–U+FDEF, or any code point whose low 16 bits are FFFE or FFFF);
- a **number that does not survive the binary64 round-trip**;
- a canonical form **over 1 MiB**, or nesting **deeper than 64** (the root is depth 1).

Refusal is whole, never partial. Input must also be well-formed UTF-8:

- a leading **byte-order mark is refused** (not stripped);
- UTF-16 and UTF-32 input is **never transcoded**.

Refused inputs from the conformance vectors:

| JSON text | Why |
|---|---|
| `{"a":1,"a":2}` | duplicate member name |
| `{"n": 9007199254740993}` | integer does not survive binary64 round-trip |
| `{"n": 1e999}` | non-finite after parse |
| `"\ud800"` | unpaired UTF-16 surrogate |

By contrast, `0.1` is accepted, because it round-trips.

## No normalization

- RAPP applies **no Unicode normalization** when hashing, storing or re-emitting an existing value.
- Strings are kept verbatim. Equality is **code-point equality**.
- A producer creating a **new** human or identifier string (slug, kind, label, `payload` object key) **MUST** emit it in **NFC**.
- A producer building a frame or packing an egg **MUST refuse** a `payload` member name that is not in NFC, or that contains an unassigned code point.
- Consumers do not test frame contents for NFC (egg paths are the exception — see [[The Egg]]).

## Why "refuse, do not repair"

If a reader silently fixes bad input, two readers can fix it differently.
Then the same input produces two different hashes, and the protocol's core promise breaks.
Refusal keeps every conformant implementation in agreement.
See the [[Failure Atlas]] for related failures.

## Migration note

The upstream specification records drift C4: an older `canonicalize()` (sorted-key `JSON.stringify`) matches JCS only for string-only payloads.
It **MUST** be replaced by the JCS implementation of record, imported rather than re-typed.

## Related

- [[Content Addressing]]
- [[Protocol Layers]]
- [[The Frame]]
- [[Conformance and Drift]]
- [[Implementing the Protocol]]

========================================================================
FILE: Protocol/Conformance Classes.md
========================================================================

---
title: Conformance Classes
section: Protocol
status: published
hook: What does an implementation have to do to claim it conforms to rapp/1, and what extra rules apply to the Grail kernel and production operations?
source: SPEC.md §11; book/10-conformance-and-drift.md; book/A-reference-manual.md §A.8
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Conformance Classes

A **conformance class** is a named role an implementation can claim: **Producer**, **Consumer**, or **Router/Mirror**.
Each role has a fixed list of duties. Claiming a role means doing all of them, with no legacy forms and no silent repairs.
Two extra rule sets cover the pinned Grail kernel and production operations.

## The three classes

**Producer** emits only:

- §4 canonical JSON bytes (see [[Canonicalization]]);
- §5 domain-separated full SHA-256 addresses (see [[Content Addressing]]);
- rappids minted per §6.2 (see [[Identity and the Rappid]]);
- eleven-key frames (see [[The Frame]]);
- `rapp/1-egg` variants (see [[The Egg]]);
- and **no legacy form**.

**Consumer**:

- runs the full §7.5 frame checklist, including step 1a stream binding;
- runs §9.3 egg verification;
- runs §10 signature, key-discovery, and tombstone checks (see [[Trust and Signatures]]);
- canonicalizes legacy ids on read;
- refuses on any failure, and never repairs, reparents, or rolls back.

**Router/Mirror**:

- invents no endpoints beyond the [[The Wire|wire]];
- declares that the upstream RAPP/1 specification governs protocol semantics;
- serves only provenance-stamped, hash-matching mirrors.

## The Grail kernel pin (§11.1)

An estate declares its Grail kernel through one `grail-kernel` registry entry. See [[The Registry]] and [[The Brainstem Kernel]].

- The Grail is identified by `grail_id`, never by a branch, tag, repository name, or product label.
- Every ring and stage — development, qualification, Preprod, installation, production — compares the candidate's Grail bytes to the pinned SHA-256 and length.
- A missing, changed, substituted, or unmeasured Grail byte is `kernel-drift` and **must** fail closed. Approval or urgency cannot waive it.
- A pipeline **must not** test a different file and then restore the pinned file. The release-shaped artifact itself must pass the gates.
- New behavior **must** live outside the Grail kernel. If it cannot, the implementation reports an incompatibility. It never edits the Grail and keeps the same identity.
- Different kernel bytes are a different Grail, with a new `grail_id`. A successor may name a `predecessor` but never overwrites the old one.
- Once activated, the full canonical entry is persisted. Later removal or mutation is a permanent `kernel-drift` refusal.

This is why downstream work pins the kernel and builds around it. See [[Distros and Pinning]].

## Operational conformance profiles (§11.2)

rapp/1 is the **substrate**. Two **operational profiles** sit on top of it.
They say how a production AI changes without changing the substrate or the serving system under users.
They are rapp/1 **applications**, not new wire versions.

- **RAPP CI/CD** (`rapp-cicd/1`, `protocols/rapp-cicd/1/SPEC.md`) — immutable release capsules, ordered qualification evidence, exact-candidate promotion, Preprod, and rollback/restore proof. See [[RAPP CICD]].
- **RAPP Deploy** (`rapp-deploy/1`, `protocols/rapp-deploy/1/SPEC.md`) — isolated serving/candidate lineages, cellular rollout, progressive exposure, expiring AI-health evidence, quarantine, and exact rollback. See [[RAPP Deploy]].

§11.2 names only these two. [[RAPP Work]] (`rapp-work/1`) is a separate operations note that binds a work organization to its catalog, releases, and rollback targets.

Rules that bind both profiles:

1. Payloads **MUST** be §4 canonical I-JSON, identified by `H("rapp/1:particle", payload)`.
2. Authoritative payloads **MUST** travel in signed rapp/1 frames using a registered compatible kind. Local unsigned files are drafts, fixtures, or caches and cannot authorize promotion or traffic.
3. They **MUST NOT** add a transport endpoint beside §8 `POST /chat`, redefine any rapp/1 primitive, or weaken §11.1.
4. An estate activates a profile through an authenticated §13.3 `protocol` registry entry pinning exact repository, path, and SHA-256. A moving branch is discovery, never authority.
5. A claim of **RAPP production conformance** requires both profiles. Core Producer, Consumer, and Router/Mirror implementations stay conformant without them.
6. Fixed envelope keys carry the safety invariants. Policy-defined check identifiers, component kinds, health objectives, and resilience controls are extension points; adding one changes neither the profile token nor the rapp/1 wire.
7. A consumer **MUST** refuse unknown **required** policy semantics. It may preserve and relay unknown optional evidence, but never count it as meeting a requirement it does not implement.

The reference validators are `rapp_cicd.py` and `rapp_deploy.py`; controlled profile vectors are in `operations_conformance.py`. JSON Schemas define structure; the validators enforce ordering, identity, temporal, and cross-document rules a schema cannot express.

## Proving it: the controlled suite

`conformance.py` is the executable form of the core rules:

```bash
python3 conformance.py
```

It ends with a line like:

```text
  ── 23 controlled checks | 23 PASS | 0 FAIL
```

- V1/V1b: canonicalization. V2: domain separation. V3: mint-once identity.
- V4–V9: frame build and verification steps, including unsigned swarm refusal.
- V10: the sealed-artifact profile.
- V11: the rev-17 regression suites (erratum `E-1`..`E-23`).

The suite uses **fixed inputs**. A live public observation follows it, but is non-gating. Mutable remote state belongs to the estate audit (`realcheck.py`). See [[Conformance and Drift]].

Passing the small vectors proves the byte primitives. It does **not** waive the full trust checks a Consumer owes.

## Fail closed

A checker must tell apart **clean**, **drift**, and **not inspected**. A checker that greens because it could not reach a repository has said "no drift" when it means "I did not look."

## Related

- [[Implementing the Protocol]]
- [[Conformance and Drift]]
- [[The Brainstem Kernel]]
- [[RAPP CICD]]
- [[RAPP Deploy]]
- [[RAPP Work]]
- [[Failure Atlas]]

========================================================================
FILE: Protocol/Content Addressing.md
========================================================================

---
title: Content Addressing
section: Protocol
status: published
hook: How does rapp/1 hash things, and why is every hash tagged with a space?
source: "SPEC.md §5; book/03-content-addressing.md; book/A-reference-manual.md §A.2; conformance/vectors.json (5_hash)"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Content Addressing

In rapp/1, a thing's address is a **hash of its content**.
Every hash is **domain-separated**: a short tag naming its purpose is mixed in first.
So the same bytes used for two different purposes get two different addresses, and they can never be confused.

## The two hash functions

```
H(space, v) = lowercase_hex( SHA-256( utf8(space) || 0x0A || canonical(v) ) )     ; v a value (§4)
Hb(space, b) = lowercase_hex( SHA-256( utf8(space) || 0x0A || b ) )                ; b raw octets
```

- **`H`** hashes a JSON value, after [[Canonicalization]].
- **`Hb`** hashes raw bytes.
- The tag (`space`) is followed by one newline byte (`0x0A`), then the content.

## The fixed list of spaces

Each tag is used by **exactly one** of the two functions:

| Function | Spaces |
|---|---|
| `H` | `rapp/1:particle`, `rapp/1:wave`, `rapp/1:egg-manifest`, `rapp/1:sealed-aad`, `rapp/1:sealed-key-request` |
| `Hb` | `rapp/1:egg`, `rapp/1:rappid`, `rapp/1:grail`, `rapp/1:seal` |

An implementation **MUST refuse** to hash under any other tag, or with the wrong function.

## Worked example

From the conformance vectors, for the value `{"x": 1}`:

| Space | Hash |
|---|---|
| `H` `rapp/1:particle` | `2ba28c1fad4d0fbea812dddc74f13e3d097099fb07ce621fd208282ade5e5fc3` |
| `H` `rapp/1:wave` | `ab18eb8ab68a6093376335930413afb8b92f81a4da863708bbde8e1a875874e8` |
| `H` `rapp/1:egg-manifest` | `8c774ac7a755e62e80ce5791f60acc0673212cd05ba5cb1add656e06f58f18aa` |

Same value, three spaces, three unrelated addresses.

## Output rules

- Always exactly **64 lowercase hex** characters.
- **Never truncated. Never uppercased.**
- Two values are the same object **iff** their same-space hashes are equal.

## Addresses are pairs

- A bare 64-hex string means something **only within its space**.
- An implementation **MUST NOT** treat a hash from one space as an object of another.
- Content-addressed stores **MUST** key by `(space, hash)`.

## Labels are not identity

A `name/X.Y` label is never identity. **Only a hash is.**
Names for long-lived things are a separate concept: see [[Identity and the Rappid]].

## Security assumption

SHA-256 collision resistance (FIPS 180-4) is a security assumption of the standard.
See [[Security Considerations]].

## Where these hashes show up

- `rapp/1:particle` and `rapp/1:wave` — the two hashes in every frame. See [[The Frame]].
- `rapp/1:rappid` — minting identity tails. See [[Identity and the Rappid]].
- `rapp/1:egg` and `rapp/1:egg-manifest` — packages. See [[The Egg]].
- `rapp/1:grail` — the `grail_id` of a pinned kernel. See [[Distros and Pinning]].

## Related

- [[Canonicalization]]
- [[The Frame]]
- [[Identity and the Rappid]]
- [[The Egg]]
- [[Security Considerations]]

========================================================================
FILE: Protocol/Identity and the Rappid.md
========================================================================

---
title: Identity and the Rappid
section: Protocol
status: published
hook: What is a rappid, how is it minted, and when may it ever change?
source: "SPEC.md §6; book/04-identity.md; book/A-reference-manual.md §A.3; conformance/vectors.json (6_rappid)"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Identity and the Rappid

A **rappid** is the permanent name of a running Brainstem, a door or an object.
It is **minted once** and then never changes.
It is never computed from the thing's name or content, so renaming or editing never changes who it is.

## The shape

```
rappid:@<owner>/<slug>:<64 lowercase hex>
```

Example (the stream id used in the conformance frame vectors):

```
rappid:@kody/twin:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```

- **`owner`** — the **lowercase** GitHub login, 1–39 characters. Display casing is presentation, never identity.
- **`slug`** — 1–100 characters.
- Both use lowercase letters and digits, with single hyphens between them (no leading, trailing or doubled hyphen).
- **`hash`** — exactly 64 lowercase hex characters.

Longer parts **MUST** be refused. The grammar is case-sensitive.

## Invalid examples

From the conformance vectors, each of these is refused:

| Value (tail shortened here) | Problem |
|---|---|
| `rappid:@Kody/x:aaaa…` | uppercase owner |
| `rappid:@kody/x:AAAA…` | uppercase hash |
| `rappid:@-kody/x:aaaa…` | leading hyphen |
| `rappid:@kody--w/x:aaaa…` | doubled hyphen |
| `rappid:v2:kody/x:aaaa…` | legacy form |

Legacy forms such as `rappid:<slug>:<hash>`, `rappid:v2:…` and bare UUIDs **MUST** be migrated out, not read forever.

## Minting: exactly once

The 64-hex tail is minted once per identity, in one of two ways:

- **Keyless:** `tail = Hb("rapp/1:rappid", uuid4_octets)` — the 16 binary octets of a UUIDv4 (RFC 9562).
- **Keyed:** `tail = Hb("rapp/1:rappid", SPKI_DER)` — the DER public key (RFC 5280) of the master key.
  It must be an Ed25519 key or a P-256 (prime256v1) key with an uncompressed point.

See [[Content Addressing]] for `Hb` and [[Trust and Signatures]] for keys.

## The one prohibited shortcut

A producer **MUST NOT** derive the tail from owner, slug or any name.
`sha256("owner/slug")` is explicitly prohibited (drift ID-01/C3).
If the tail came from the name, anyone who knew the name could compute the identity.

## Reading an existing identity

- On reading a stored `rappid.json`, an implementation **MUST reuse** the stored tail.
- It **MUST NOT** re-mint.
- `canonicalize_rappid(s)` restructures a legacy form into the current grammar, **keeping the existing hash**.
- If the tail is not exactly 64 lowercase hex (for example a legacy 32-hex tail), the result is **provisional**.
  A provisional id lives only inside the reading process. It must never appear in an emitted frame, `stream_id`, egg or registry entry.

## Re-anchoring: the only re-mint

A **re-anchor** mints one fresh tail and records the old id in `_migrated_from`.
It is lawful only in these cases:

- `upgrade` — a provisional 128-bit id becomes a 256-bit id;
- `rotation` — an uncompromised key rotation (the **old** key signs, proving continuity);
- `compromise` — a key compromise (a tombstone for the old id is registered in the same append);
- `tag-migrate` — a pre-rev-3 keyed tail made with un-tagged `sha256(SPKI)`.

A self-asserted `_migrated_from` is **not enough**.
The re-anchor must be an owner-signed **re-anchor record** in [[The Registry]]:
`{old_rappid, new_rappid, case, utc, sig, old_key_sig?}`.

## Stream ids and kinds

A rappid also names streams of [[The Frame|frames]]:

- **body stream** — the rappid itself;
- **memory stream** — `<rappid>:<instance>`: the full rappid, a colon, then an instance label (lowercase, 1–64 characters);
- **swarm stream** — `net:<label>`.

A `kind` is two labels joined by a dot, such as `body.pulse`.
Its family is set by the registry, never inferred from its prefix.

## Related

- [[Content Addressing]]
- [[Trust and Signatures]]
- [[The Registry]]
- [[The Frame]]
- [[Glossary]]

========================================================================
FILE: Protocol/Protocol at a Glance.md
========================================================================

---
title: Protocol at a Glance
section: Protocol
status: published
hook: What is rapp/1, and what does it promise in one page?
source: "SPEC.md §1, §3; book/01-a-tutorial-introduction.md"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Protocol at a Glance

**rapp/1** is the shared set of rules that lets any two RAPP systems agree on the same data, byte for byte.
Its one promise: **the same concept has the same bytes everywhere.**
If two independent implementations follow the rules, they interoperate with no side agreement.

## The five building blocks

The specification defines five primitives. Everything else is built on them.

- **Canonicalization** — one exact byte form for any JSON value. See [[Canonicalization]].
- **Content addressing** — a tagged SHA-256 hash of those bytes. See [[Content Addressing]].
- **Identity** — the **rappid**, a name minted once and never derived from content. See [[Identity and the Rappid]].
- **The frame** — one immutable, hash-linked event record. See [[The Frame]].
- **The egg** — the packaging format. See [[The Egg]].

All of them ride **one wire**: either `POST /chat`, or a signed append-only frame. See [[The Wire]].

## The growth rule

Implementations add **agents**, **cartridges** and registered `kind`s.
They never add new endpoints and never add new envelopes.
This keeps every tier speaking the same shape.

## Key words

- **frame** — one immutable, content-addressed event.
- **stream** — an append-only, hash-chained sequence of frames that share one `stream_id`.
- **particle / wave** — a frame's two addresses: the payload hash and the whole-frame hash.
- **canonical form** — the one RFC 8785 byte string for a value.
- **legacy form** — any other historical encoding. Legacy is drift and must be migrated out.
- **Grail kernel** — a byte-pinned runtime. Its `grail_id` is `"grail:" || Hb("rapp/1:grail", kernel_bytes)`.

More terms are in the [[Glossary]].

## A complete example in three calls

The tutorial chapter shows the smallest working program, using the reference `rapp.py`:

```python
import rapp as R

stream = R.mint_rappid("kody", "hello")          # 1. an identity for the stream
frame = R.build_frame(                             # 2. a record in that stream
    kind="note.write",
    stream_id=stream,
    seq=0,
    utc="2026-07-15T12:00:00.000Z",
    payload={"text": "hello, frame"},
    prev=None,
)
ok, step, why = R.verify_frame(frame, head=None, stream_id_of_record=stream)  # 3. check it
print("OK" if ok else f"FAILED at {step}: {why}")
```

Mint an identity. Build a frame. Verify it. That is a complete transaction.

## Where authority lives

- The normative text is carried by an append-only chain, `anchor/chain.jsonl`.
- Its hashes prove **integrity**, not authority.
- `SPEC.md` is the byte-exact human-readable view of that chain.
- The durable identity of a protocol revision is the selected chain-frame hash, not a path or a `rev-N` label.

For where this vault's copy comes from, see [[Sources and Provenance]].

## Requirements language

**MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHOULD** and **MAY** follow RFC 2119 / RFC 8174 when written in bold capitals.

## Related

- [[Protocol Layers]]
- [[The Frame]]
- [[The Wire]]
- [[Conformance Classes]]
- [[Implementing the Protocol]]
- [[Sources and Provenance]]

========================================================================
FILE: Protocol/Protocol Layers.md
========================================================================

---
title: Protocol Layers
section: Protocol
status: published
hook: How is rapp/1 split into layers, and what may each layer do?
source: "SPEC.md §1.1"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Protocol Layers

rapp/1 is organized as **five layers**, stacked like a network protocol.
Each layer has **exactly one canonical form**.
A higher layer **must not** redefine a lower one.

## The stack

From the specification, verbatim:

```
  L5  EGG        cartridge packaging (§9)          — MIME-multipart analogue
  L4  FRAME      universal event envelope (§7)     — the IP packet of RAPP
  L3  WIRE       transport: /chat + frames (§8)    — HTTP-analogue single method
  L2  IDENTITY   rappid namespace + trust (§6,§10) — URI + PKI analogue
  L1  ADDRESS    canonicalization + hash (§4,§5)   — the git object model
```

## Each layer in one line

- **L1 Address** — turn a value into one exact byte string, then hash it in a tagged space.
  See [[Canonicalization]] and [[Content Addressing]].
- **L2 Identity** — name things with a **rappid**, and prove authorship with signatures.
  See [[Identity and the Rappid]] and [[Trust and Signatures]].
- **L3 Wire** — move data: synchronous `POST /chat`, or an asynchronous append-only frame.
  See [[The Wire]].
- **L4 Frame** — the one universal event envelope, with exactly eleven keys.
  See [[The Frame]].
- **L5 Egg** — package a cartridge for transport and install.
  See [[The Egg]].

## The two rules that hold the stack together

1. **No redefinition downward.** A frame cannot invent its own hashing. An egg cannot invent its own identity.
   Each layer uses the one form the layer below defines.
2. **One canonical form per layer.** There is one byte form, one hash rule, one identity grammar,
   one envelope, one wire, one package format.

## Why this matters in practice

- Two implementations that agree on L1 compute the **same hash** for the same value.
- Because frames reuse L1, they can be checked by anyone with the bytes.
- Because the wire is one shape, a local Brainstem, a cloud endpoint and a managed studio all speak the same contract.
  See [[The Brainstem Kernel]].
- New capability is a new agent or a new registered `kind` — never a new layer, endpoint or envelope.

## How the layers relate to change

Changes are governed by [[Versioning and Evolution]].
A revision that changes the frame's key set, a field grammar or a hash rule must change the `spec` token.
Adding new registered `kind`s keeps the token.

## Related

- [[Protocol at a Glance]]
- [[Content Addressing]]
- [[The Frame]]
- [[The Wire]]
- [[The Egg]]
- [[Versioning and Evolution]]

========================================================================
FILE: Protocol/Security Considerations.md
========================================================================

---
title: Security Considerations
section: Protocol
status: published
hook: Which threats does rapp/1 defend against, which ones do hashes alone not stop, and what control covers each?
source: SPEC.md §14; book/09-registry-evolution-and-security.md §9.8
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Security Considerations

rapp/1's **security model** has two parts.
Content addressing protects bytes that never change. Signed, authenticated state protects facts that can change, such as which head is current or which key is revoked.
This note lists the known threats and the control for each.

## The short version

- History is safe **given a trusted head**. Hashes do not tell you which head is current.
- Every hash lives in a named space, so equal hex in different spaces never means the same thing.
- Keys come from the signed registry, never from the sender.
- Revocation is checked at verification time, against a fresh registry.
- Archives are checked before anything is extracted.
- The Grail kernel bytes are pinned and tested in the exact release artifact.

## What hashes catch, and what they do not

| Threat | Hashes catch it? | Required control |
|---|---:|---|
| mirror changes an object | yes | recompute same-space address |
| mirror serves an old but valid head | no | persisted head + current genesis registry |
| attacker replays stream A into stream B | not by hash alone | §7.5 step 1a binding |
| attacker swaps a signing key | no | registry SPKI lookup + rappid tail check |
| mirror hides a key tombstone | no | registry sequence and freshness |
| producer future-dates a frame | no | receipt-time skew policy; re-genesis if bricked |
| archive uses `../` paths | no | §9 path grammar and entry-set verification |

## The considerations, one by one

**Integrity.** Every object is domain-separated and content-addressed. A hostile mirror cannot change bytes without breaking the hash. See [[Content Addressing]].

**Head freshness is not self-certifying.** A mirror may serve a stale or forked head. Consumers apply the monotonic-head rule. Swarm heads **should** be owner-signed. See [[The Frame]].

**Cross-stream replay.** A genesis has `seq`=0 and `prev`=null, so without stream binding it could replay as another stream. Step 1a binding is mandatory.

**Address-space confusion.** Domain tags make a particle, wave, egg, or rappid tail with equal hex non-interchangeable. Stores key by `(space, hash)`.

**Canonicalization attacks.** The I-JSON input profile — no duplicate keys, no lone surrogates, exact binary64, no normalization ambiguity — removes hash-splitting vectors. See [[Canonicalization]].

**Identity forgery and key compromise.** Authorship needs a keyed rappid plus a valid signature. Rotation is a verifiable re-anchor; a self-asserted `_migrated_from` is refused. Compromise is a registry tombstone enforced at verify time. See [[Trust and Signatures]].

Because a tombstone compares against the frame's producer-set `utc`, a compromised key can still stamp frames just below `revoked_utc`. After a compromise the owner **should** advance affected stream heads, or re-genesis, past `revoked_utc`.

**Root of trust.** The registry is signed by the owner, anchored to the out-of-band `estate_owner` fingerprint, `registry_seq`-monotonic, and freshness-checked. A stale registry silently un-revokes keys and hides re-geneses. See [[The Registry]].

**Producer-controlled `utc`.** A future-dated head can block a stream (later successors look earlier) and bias UTC-first merges. A consumer **should** refuse a frame whose `utc` is more than 300 seconds past receipt time. Adversarial merges **should** rank by `min(utc, first-seen)`. A blocked stream converges by re-genesis. See [[Versioning and Evolution]].

**Archive paths.** Egg consumers enforce path grammar and the exact entry set **before** extracting. An unenforced path grammar defends nothing. See [[The Egg]].

**Sealed-artifact limits.** A public mirror sees ciphertext and metadata. AES-GCM protects confidentiality only while the key stays secret. A recipient who has lawfully decrypted can copy the plaintext. Revocation stops future key release, not prior possession. These postures are non-conformant:

- shared passwords;
- embedded master keys;
- moving-branch URLs;
- nonce reuse under one key;
- claims that bytecode cannot be inspected after decryption.

**Kernel substitution.** Testing different bytes and restoring the Grail only after approval creates an untested release. The release-shaped artifact must contain the pinned bytes before its tests and approval. A digest mismatch is a blocking `kernel-drift` finding. See [[The Brainstem Kernel]].

**Kernel registry rollback.** Persisting only `registry_seq` does not protect an activated Grail declaration from a malicious higher-sequence registry. Consumers also persist every activated `grail-kernel` entry and reject its later removal, mutation, or duplication. See [[Conformance Classes]].

## The principle

Use content addressing for immutable bytes. Use explicit, authenticated state for facts that can change. When in doubt, fail closed: refuse first, migrate deliberately.

## How this maps to the production guide

Security sign-off in the production guide happens at [[Step 12 Security Sign-off]]. This note describes the protocol-level controls only; it is not a substitute for that review.

## Related

- [[Trust and Signatures]]
- [[The Registry]]
- [[The Egg]]
- [[Failure Atlas]]
- [[Step 12 Security Sign-off]]
- [[Conformance Classes]]

========================================================================
FILE: Protocol/The Egg.md
========================================================================

---
title: The Egg
section: Protocol
status: published
hook: How does rapp/1 package a whole agent, application, or space so anyone can verify it before using it?
source: SPEC.md §9; book/07-the-egg.md; book/A-reference-manual.md §A.6
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# The Egg

An **egg** is a single package that carries a unit of RAPP work: a full Brainstem instance, one rapplication, a session, or a signed invite.
Every egg has the same small manifest, a content address, and strict rules a receiver checks **before** it unpacks anything.
If any check fails, the whole egg is refused.

## The short version

- One spec of record: §9 of the upstream RAPP/1 specification. No other document may re-specify eggs.
- One manifest shape, with exactly seven members.
- Seven registered **variants**. The variant changes the viability rules, not the manifest shape.
- One address for the whole egg. Signing it does not change that address.
- Receivers check **integrity first, then viability**, and refuse the whole egg on any failure.

## The seven variants

| `variant` | Container | What it packs |
|---|---|---|
| `organism` | stored ZIP | wire value for a full Brainstem instance; must include `rappid.json` and `soul.md` |
| `rapplication` | stored ZIP | one rapp; must include `rappid.json` and exactly one root `agent.py` |
| `session` | JSON | one runtime plus transcript; `payload` = `{runtime, transcript}` |
| `invite` | JSON | a QR-sized signed pointer to a neighborhood or estate; no packed files |
| `neighborhood` | stored ZIP | one sub-egg per member, named `<owner>--<slug>.egg` |
| `estate` | stored ZIP | one sub-egg per neighborhood |
| `sealed` | stored ZIP | exactly `ciphertext.bin`, plus the `rapp-sealed-artifact/1` payload |

Adding a new package kind is a registry and standard change. It is not permission to invent a new format name. See [[The Registry]].

## The manifest

Every egg has exactly this manifest (example from the book; `organism` is the wire value for the full-Brainstem variant):

```json
{
  "schema": "rapp/1-egg",
  "variant": "organism",
  "rappid": "rappid:@owner/agent:<64hex>",
  "created_utc": "2026-08-20T12:00:00.000Z",
  "contents": [
    {"path": "rappid.json", "hash": "<64hex>"},
    {"path": "soul.md", "hash": "<64hex>"}
  ],
  "payload": {},
  "sig": null
}
```

- `contents` lists every packed file **except** `manifest.json`, exactly once, sorted by the UTF-8 bytes of `path`.
- For the JSON variants (`session`, `invite`), `contents` is exactly `[]`.
- `path` is a relative POSIX path: no `.` or `..` segment, no leading `/`, no backslash, no drive letter, no reserved Windows names such as `CON` or `NUL`.
- For `organism` and `rapplication` eggs, the packed `rappid.json` must carry the same `rappid` as the manifest.

## Two addresses

The egg uses two separate hash spaces (see [[Content Addressing]]):

```text
one packed file:
    Hb("rapp/1:egg", file_octets)

the egg as a whole:
    H("rapp/1:egg-manifest", manifest without sig)
```

`sig` is left out of the egg address. Signing or re-signing authenticates the same package. It never creates a new package identity.

## Deterministic containers

- JSON variants are serialized as exactly `canonical(manifest)` (see [[Canonicalization]]).
- ZIP variants use compression method `stored` for **every** entry. No deflate, because deflate output depends on the library.
- `manifest.json` comes first, then the files in `contents` order.
- Timestamps are fixed to `1980-01-01 00:00:00`; the UTF-8 filename flag is set; no extra fields; no ZIP64.

Result: two conformant packers given the same manifest and files emit byte-identical eggs.

## Verify integrity, then viability

A consumer works in this order and refuses the whole egg on any failure:

1. The manifest satisfies every §9.1 rule: exact members, path grammar, no duplicates, sort order, and the archive entry set equals `contents` plus `manifest.json`.
2. Every `contents[].hash` recomputes.
3. The variant's structural rules hold (required files, payload fields, sub-eggs).

The order matters. Code that extracts `../../outside` and only later notices the bad path has already lost. The path rules are the defense against archive path escapes. See [[Security Considerations]].

A non-null `sig` must verify. The `invite` and `sealed` variants **require** a signature. See [[Trust and Signatures]].

## Hatching: artifact versus instance

An egg names an **artifact**. A hatch creates an **instance**.
The artifact name stays the same on every hatch. Each instance gets its own new name.
The instance may note which egg it came from. That note is history only, never permission.

Detail (§9.4):

- The `rappid` in a packed egg's `rappid.json` names the **artifact**. Every hatch of the same egg reads the **same** artifact identity. Re-minting it on hatch is prohibited.
- A consumer that turns an egg into a live installation **MUST** mint a **fresh** identity for the instance, exactly once, at first boot, from entropy. It must never be derived from the artifact identity, host name, or path.
- Two instances of one egg share the artifact identity and **MUST NOT** share an instance identity.
- The instance identity document **SHOULD** record `grown_from`: the §9.1 egg address (64 lowercase hex) of the source egg.
- `grown_from` is written at mint time and is **immutable** after that. It is `null` when the source is unknown. A producer **MUST NOT** fabricate it.
- `grown_from` is **lineage, not inheritance**. It confers no authority, no trust, and no signing key material. A reader treats it as an unverified assertion unless the named egg is available and its address recomputes.
- A newly authored artifact built from existing RAPP objects **MAY** record `crossed_from` in its packaged `rappid.json`: a sorted, duplicate-free array of `{space, hash}`, where `space` is `"rapp/1:particle"` or `"rapp/1:egg-manifest"`. One parent is an **offspring**; two or more is a **cross**. The new artifact mints its own rappid, and `crossed_from` is lineage only.

See [[Identity and the Rappid]].

## The sealed variant

`sealed` lets a public mirror carry **encrypted bytes** without carrying the key.
The public bytes are ciphertext, **not access control**.
To use the artifact, a recipient asks a named key service, which may release a key wrapped for that one device.

Detail (§9.2.1):

- A producer **MUST** use a random 256-bit data-encryption key (DEK) per artifact. It **MUST NOT** embed the DEK or a shared master key in the egg, client, or URL, and **MUST NOT** put a password in a URL.
- The ZIP holds exactly one file: `ciphertext.bin` = AES-256-GCM ciphertext followed by the 16-byte tag. Its length is exactly `plaintext_bytes + 16`.
- `payload` has exactly the members `schema` (`rapp-sealed-artifact/1`), `cipher` (`A256GCM`), `nonce` (12 bytes, unpadded base64url), `plaintext_commitment`, `plaintext_bytes` (integer, 0 through `2^30`), `media_type`, `key_id`, `key_service_rappid`, `key_service_url`, `access` (always `scoped-key-release`), and `aad_hash`.
- `plaintext_commitment` is an HKDF-derived HMAC over the plaintext, keyed from the DEK with info string `rapp/1:sealed-commitment`, so it cannot be tested without the DEK.
- `aad_hash = H("rapp/1:sealed-aad", descriptor)`, and `canonical(descriptor)` is the AES-GCM additional authenticated data. The descriptor binds the artifact rappid, `created_utc`, `key_id`, commitment, size, and media type.
- The manifest signature is **REQUIRED**, with `kid` exactly equal to `manifest.rappid`. See [[Trust and Signatures]].
- `key_service_url` is an absolute HTTPS `POST /chat` URL ending in `/chat`. The URL is location, not authority: responses are accepted only when signatures bind to `key_service_rappid`.
- The request (`rapp-sealed-key-request/1`) is signed by the recipient and names `egg_hash`, `key_id`, the recipient key, a nonce, and an expiry. The release (`rapp-sealed-key-release/1`) is signed by the service and returns `wrapped_key_jwe` using `ECDH-ES+A256KW` with `A256GCM`. The service **MUST NOT** return a global raw DEK.
- A mirror URL **SHOULD** be immutable (pin a commit, not a moving branch). URL secrecy is never assumed.
- Revocation stops future key release. It cannot erase ciphertext or plaintext already decrypted, and a product **MUST** say so plainly and **MUST NOT** claim decrypted bytecode cannot be inspected.

## Try it

From the upstream repository root, the book's checkpoint packs and verifies an egg with the reference profile:

```bash
python3 - <<'PY'
import rapp as R

rid = R.mint_rappid("reader", "first-instance")
files = {
    "rappid.json": ('{"rappid":"' + rid + '"}').encode(),
    "soul.md": b"# A small, portable Brainstem\n",
}

blob = R.pack_egg(
    variant="organism",
    rappid=rid,
    created_utc="2026-08-20T12:00:00.000Z",
    files=files,
)
ok, step, why = R.verify_egg(blob)
manifest, unpacked = R.read_egg(blob)

print("bytes:", len(blob))
print("address:", R.egg_address(manifest))
print("files:", sorted(unpacked))
print("verify:", ok, step, why)
PY
```

Adding a file named `../escape` must make `verify_egg` refuse the whole package.

## Related

- [[The Frame]]
- [[Content Addressing]]
- [[Identity and the Rappid]]
- [[Trust and Signatures]]
- [[The Registry]]
- [[Failure Atlas]]

========================================================================
FILE: Protocol/The Frame.md
========================================================================

---
title: The Frame
section: Protocol
status: published
hook: What is a rapp/1 frame, what are its eleven fields, and how is it verified?
source: "SPEC.md §7; book/05-the-frame.md; book/A-reference-manual.md §A.4; conformance/vectors.json (7_frame)"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# The Frame

A **frame** is one immutable record of one event.
Every event in rapp/1 uses this same envelope, with **exactly eleven fields**.
Frames link to the frame before them by hash, so any change to history is detectable.

## The eleven fields

The genesis (first) frame from the conformance vectors:

```json
{
  "frame_hash": "7f1828db28378b29b976b2763f36154bd432ccf1cfa5bf25e913583db86a010b",
  "kind": "body.pulse",
  "payload": {
    "hello": "world"
  },
  "payload_hash": "dccd124a460d7f7a6ab23b15df476f1f65fa19b8979f0ab70c656e55c67beb05",
  "prev": null,
  "prev_wave": null,
  "seq": 0,
  "sig": null,
  "spec": "rapp/1",
  "stream_id": "rappid:@kody/twin:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "utc": "2026-07-15T00:00:00.000Z"
}
```

The next frame in that stream has `seq` `1`, `payload` `{"n": 2}`, and `prev` equal to the genesis `payload_hash` (`dccd124a…`).

## Field rules

- **`spec`** — always the exact string `rapp/1`. Legacy tokens `rapp-frame/2.0` and `2.1` must not be emitted.
- **All eleven keys are always present.** None missing, none extra.
  A field that does not apply is `null`, never omitted, because JCS hashes `null` and an absent key differently.
- **`payload`** — always a JSON object (possibly `{}`).
- **`seq`** — a `uint53`: 0, 1, 2… up to 2^53−1, contiguous.
- **`utc`** — exactly `YYYY-MM-DDTHH:MM:SS.mmmZ` (24 bytes, three fractional digits, ASCII digits only, no offset, seconds never `60`).
- Size limits from [[Canonicalization]] apply: at most 1 MiB, depth 64.

## Two hashes: particle and wave

Each frame carries two addresses, computed in this order (see [[Content Addressing]]):

1. **particle** — `payload_hash = H("rapp/1:particle", payload)`. The chain link.
2. **wave** — `frame_hash = H("rapp/1:wave", frame \ {frame_hash, sig})`. The frame with only those two keys removed.

Because `payload_hash` is inside the wave, `frame_hash` also attests the payload.

## Chaining

- **Genesis:** `seq` = 0 and `prev` = `null`.
- **Later frames:** `seq` = previous + 1, and `prev` = previous `payload_hash`.
- **`prev_wave`** is non-null **only** on a swarm stream (`net:…`) past genesis. Then it equals the previous `frame_hash`.
- A frame never changes. A new state is a new frame.

## Kinds and families

Every `kind` belongs to one family through [[The Registry]]:

| family | example kinds | stream form |
|---|---|---|
| `memory` | `memory.chat-turn`, `memory.save` | memory stream |
| `swarm` | `swarm.guidance`, `swarm.echo` | swarm stream |
| `body` | `body.pulse`, `body.twin-pulse` | body stream |

New events are new registered kinds on the **same** envelope — never a new frame type.

## Verification checklist

A consumer checks in order and **refuses on the first failure** (never repairs):

1. **Shape and types** — eleven keys, correct grammars, registered kind matching the stream form.
1a. **Stream binding** — `stream_id` equals the stream being read.
2. **Particle** — recompute `payload_hash`.
3. **Wave** — recompute `frame_hash`.
4. **Chain** — `seq`, `prev`, and `utc` not earlier than the head.
5. **Wire** — `prev_wave` rule above.
6. **Signature** — if `sig` is set, verify it; an unsigned swarm frame is refused. See [[Trust and Signatures]].

Steps 1–5 never change their answer. Only step 6 can, if a key is later revoked.

The vectors include tampered frames that keep their original hashes on purpose.
For example, changing `"hello": "world"` to `"hello": "evil"` fails at **step 2**.

## Heads and forks

- A stream's **head** is its highest verified frame.
- A consumer refuses any **rollback** to a lower `seq`, or a different `frame_hash` at a verified `seq`.
- Two valid frames with the same `stream_id`, `seq` and `prev` are a **fork**. Both branches are refused past that point. Only the owner resolves it.

## Re-genesis

To move a chain to a new form without editing it, the owner seals the old head, emits a new signed `*.re-genesis` frame at `seq` 0, and registers it as the new genesis.
The old frames are kept bit-exact under `legacy/`. See [[Versioning and Evolution]].

## Related

- [[Content Addressing]]
- [[Identity and the Rappid]]
- [[The Wire]]
- [[Trust and Signatures]]
- [[The Registry]]
- [[Failure Atlas]]

========================================================================
FILE: Protocol/The Registry.md
========================================================================

---
title: The Registry
section: Protocol
status: published
hook: What is the estate registry, why is it the root of trust, and how does a consumer know it is genuine and current?
source: SPEC.md §13; book/09-registry-evolution-and-security.md §9.1-9.5, §9.9
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# The Registry

The **registry** is one signed, append-only document per estate. It records which keys belong to which identities, which event kinds and egg variants are allowed, where each stream starts, and who the owner is.
Because everything else resolves through it, it is the estate's **root of trust**.
A consumer accepts it only if it is signed by the owner, never older than the last one seen, and fresh enough.

## The short version

- Document schema: `schema:"rapp/1-registry"`, from an owner-controlled `canonical_source`.
- One bootstrap value, shared out-of-band once: the `estate_owner` rappid.
- Signed by the estate owner; refused if unsigned or not verifying.
- `registry_seq` only goes up. Lower values are refused (no rollback).
- Entries are never removed or renamed. Retirement is `deprecated:true`.

## What the registry does

- binds keyed rappids to public keys (see [[Trust and Signatures]]);
- registers frame kinds and their stream families (see [[The Frame]]);
- records the current genesis of every stream;
- carries key tombstones and identity re-anchors (see [[Identity and the Rappid]]);
- names the estate owner and that owner's succession;
- pins the estate's adopted protocol revision and its master plan;
- pins the Grail kernel (see [[The Brainstem Kernel]]).

An unsigned mutable registry would let an attacker swap a key, hide a tombstone, authorize a forged genesis, or redefine a kind. So the registry must authenticate itself.

## The bootstrap axiom

A keyed rappid's tail is `Hb("rapp/1:rappid", SPKI_DER)`. So the `estate_owner` rappid **is** a key fingerprint.

It is distributed once through a trusted channel (QR, invite, documentation), like a root certificate. The owner's public key may travel with the registry. It is accepted only if hashing it reproduces the trusted tail.

## Signed, monotonic, fresh

The safe retrieval path:

```text
out-of-band estate_owner rappid
        │
        ▼
SPKI tail check
        │
        ▼
registry signature
        │
        ▼
registry_seq monotonicity + freshness policy
        │
        ▼
keys, kinds, genesis records, succession, tombstones
```

- **Signature:** a detached §10 JWS `sig` over `canonical(registry \ {sig})`, `kid` = the `estate_owner` rappid.
- **No rollback:** persist the highest `registry_seq` verified; refuse any lower one.
- **Freshness:** get the registry from `canonical_source` or a provenance-stamped mirror. Refresh before trust-sensitive decisions. Report an over-age registry as **stale**, not **clean**.

Rollback resistance is not freshness. A hostile mirror can keep serving the highest sequence it has seen while hiding a newer one.

## Owner succession is historical

"Owner-signed" means signed by the owner **in effect at the artifact's `utc`**, through the re-anchor records. It is not always today's owner.

```text
──────────── A tenure ────────────│──────────── B tenure ────────────>
                                 2026-08-01
```

A frame signed by key A in July stays valid after rotation to B. One signed by A in August does not.

Root-key compromise of the estate owner can only be recovered by distributing a new trust anchor out-of-band. It cannot be expressed inside the registry it signs.

## Entry types

Every entry is a canonical value and append-only.

| Entry | What it records |
|---|---|
| `protocol` | estate adoption pin: spec repository, path, hash; never power to redefine a protocol |
| `kind` | one event kind and its stream family |
| `egg-variant` | one allowed egg variant (see [[The Egg]]) |
| `error-code` | one machine-readable `/chat` failure code (see [[The Wire]]) |
| `genesis` | the starting frame for a stream; exactly one non-deprecated per `stream_id` |
| `spki` | the public key for a keyed rappid |
| `tombstone` | owner-signed key revocation, `{rappid, revoked_utc, sig}` |
| `re-anchor` | identity continuity: `upgrade`, `rotation`, `compromise`, or `tag-migrate` |
| `grail-kernel` | the pinned Grail kernel bytes, by `grail_id`, SHA-256, and size |
| `estate_owner` | the owner currently in force (exactly one non-deprecated) |
| `master-plan` | the governing estate plan |

`egg-variant` and `error-code` are **closed namespaces**: an unregistered value is not conformant. Closed lists let the envelope stay stable while vocabulary grows on purpose. See [[Versioning and Evolution]].

A `rotation` re-anchor also needs `old_key_sig`, a signature by the old key.

## Operator checklist

Before calling an estate clean:

```text
[ ] current registry signature verifies from the pinned estate_owner rappid
[ ] registry_seq is not below the last accepted sequence
[ ] registry age satisfies the local freshness policy
[ ] every stream descends from its sole non-deprecated genesis
[ ] every signed frame resolves a matching SPKI and valid tenure
[ ] tombstones and re-anchors are applied at the frame's utc
[ ] no live frame points into sealed legacy history
[ ] every untrusted egg passed path, entry-set, hash, and variant checks
```

Unknown does not become pass. Stale does not become clean.

## Related

- [[Trust and Signatures]]
- [[Identity and the Rappid]]
- [[Versioning and Evolution]]
- [[Security Considerations]]
- [[Distros and Pinning]]

========================================================================
FILE: Protocol/The Wire.md
========================================================================

---
title: The Wire
section: Protocol
status: published
hook: How do RAPP systems talk to each other, and what exactly does POST /chat accept and return?
source: "SPEC.md §8; book/06-the-wire.md; book/A-reference-manual.md §A.5"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# The Wire

The **wire** is how RAPP systems exchange data.
There are **exactly two forms**: a synchronous `POST /chat` call, or an asynchronous append-only [[The Frame|frame]].
New capability is always a new agent behind `/chat` — never a new route.

## Form 1: `POST /chat` (synchronous)

JSON in, JSON out.

**Request:**

```
POST /chat
Content-Type: application/json

{ "user_input": "<plain-language request>",
  "session_id": "<optional>",
  "conversation_history": [ {"role": "...", "content": "..."} ] }
```

- `user_input` — string, **required**. Empty or whitespace-only counts as missing.
- `conversation_history` — optional array. Each item has `role` (`user`, `assistant` or `tool`) and string `content`.
- `session_id` — optional string.
- Unrecognized members **MUST be ignored**, never refused.

**Success (HTTP 200):**

```
200 OK
{ "response": "<assistant text>", "agent_logs": "<what fired>", "session_id": "<id>" }
```

- `response` — the assistant text.
- `agent_logs` — one line per agent call, newline-separated; empty when no agent ran.
- `session_id` — string.
- An endpoint may add members. The Grail adds `model`, `requested_model` and `voice_mode`. Consumers ignore what they do not recognize.

**Malformed request (HTTP 400):** exactly one member.

```json
{
  "error": "<human-readable message>"
}
```

The status and shape are fixed. The message text is not frozen; a Grail bug-fix release may reword it.

**Health:** `GET /health` returns HTTP 200 with a JSON object containing `status`. It carries no RAPP meaning.

## Try it

Against a running Brainstem:

```bash
curl -sS http://localhost:7071/chat \
  -H 'content-type: application/json' \
  -d '{
    "user_input": "Describe your loaded capabilities in one sentence."
  }'
```

Then send `{ "messages": [] }`. The server should return HTTP 400 with one `error` string — not guess that `messages` meant `user_input`.

## The Grail is the reference

An endpoint conforms when it answers every scenario of the Grail conformance suite (`conformance/grail/`) the way the pinned Grail does: same status, same members, same `response` and `session_id` values.
The suite defines 25 scenarios. Fourteen never reach the model and form a live join probe.
See [[The Brainstem Kernel]] and [[Conformance Classes]].

## Form 2: an append-only frame (asynchronous)

A frame is published to a stream: a repository path, an `events/` log, or any transport that keeps the exact frame value.
The transport may not reparent, rename or "upgrade" a frame in flight.

Two stream disciplines, chosen by the `stream_id`:

- **Rappid streams** (`rappid:@owner/slug:64hex`) — one agent's own history. `prev_wave` is `null`. Signatures are optional.
- **Swarm streams** (`net:…`, for example `net:commons`) — shared by many writers. `prev_wave` chains whole frames, and every frame **MUST** be signed.

Given a trusted head, any history is safe to read; the hash chain makes tampering detectable.
See [[Trust and Signatures]] and [[Security Considerations]].

## One shape for every tier

A Brainstem runs locally (`localhost:7071`), on a cloud endpoint, or behind a managed studio.
All three speak the same `POST /chat` contract.
Moving from laptop to cloud changes the URL, not the protocol.
That is why the wire stays at one endpoint: two endpoints would let the tiers drift apart.
See [[The Agent Contract]] and [[RAPP Deploy]].

## Related

- [[The Frame]]
- [[The Agent Contract]]
- [[The Brainstem Kernel]]
- [[Conformance Classes]]
- [[Protocol Layers]]

========================================================================
FILE: Protocol/Trust and Signatures.md
========================================================================

---
title: Trust and Signatures
section: Protocol
status: published
hook: What does a rapp/1 signature prove, how is it checked, and how do key rotation and revocation work?
source: SPEC.md §10; book/08-trust-and-signatures.md; book/A-reference-manual.md §A.7
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Trust and Signatures

A **signature** in rapp/1 is a statement by a key about a frame or egg whose bytes are already fixed by hashes.
Hashes prove the bytes are unchanged. A signature adds **who** stands behind them.
A signature only counts when the key is found in the estate's signed registry and was in force at the time.

## The short version

- Integrity comes from hash links, not signatures. See [[Content Addressing]].
- `sig` is optional on memory and body streams, and **required** on swarm streams.
- If `sig` is present, it must verify completely. A bad signature is never treated as "unsigned".
- The public key comes from the registry, never from the sender. See [[The Registry]].
- Rotation and revocation are time-scoped: old valid history stays valid.
- An unsigned frame makes no authorship claim.

## Four claims, four checks

| Claim | Evidence | What it does **not** prove |
|---|---|---|
| these are the original payload bytes | recomputed `payload_hash` | who produced them |
| this is the original frame envelope | recomputed `frame_hash` | that it is the current head |
| this key signed this frame | valid §10 JWS | that the key was authorized at that time |
| this key was authoritative then | verified, fresh registry + succession records | that a newer head does not exist |

The first two are local and need no network. The last two cross a trust boundary.

## The exact signature format

rapp/1 uses JWS Compact Serialization with a **detached, unencoded payload** (RFC 7515 Appendix F plus RFC 7797).

The protected header has **exactly** four members, no others:

```json
{
  "alg": "EdDSA",
  "b64": false,
  "crit": ["b64"],
  "kid": "rappid:@owner/agent:<64hex>"
}
```

- `alg` is `EdDSA` (Ed25519) or `ES256`.
- `kid` is the signer's rappid. See [[Identity and the Rappid]].
- The header bytes must be `canonical(header)`. See [[Canonicalization]].

Signing input and stored form:

```text
signing input = BASE64URL(canonical(header)) || "." || canonical(frame \ {sig})
sig           = BASE64URL(canonical(header)) || ".." || BASE64URL(signature)
```

The empty middle segment marks that the payload travels outside the string. ES256 signers **should** sign deterministically (RFC 6979) so signed files stay byte-reproducible. Ed25519 is deterministic already.

Because `sig` is never part of `frame_hash`, re-signing does not change the frame's identity. See [[The Frame]].

## Key discovery

A signature can be mathematically valid under any key an attacker supplies. So the verifier must answer: is this the key bound to `kid`?

A complete check has four stages:

1. Parse the JWS and require the exact header shape.
2. Get the signer's SPKI from a verified, fresh registry `spki` entry.
3. Check `Hb("rapp/1:rappid", SPKI_DER)` equals the rappid's tail.
4. Verify the signature over the exact canonical signing input.

Refuse on a missing registry entry, a tail mismatch, an unsupported algorithm, an extra header member, stale revocation state, or a bad signature.

The `rappid.json` published at an agent's door is source material for the registry entry. It is **not** a verification source.

## Rotation and compromise

- **Rotation** creates a new keyed rappid and a registry `re-anchor` record. A verifier refuses a `sig` by the old rappid on any frame with `utc` at or after the re-anchor time. Earlier frames still verify.
- **Compromise** is declared by an owner-signed **tombstone** `{rappid, revoked_utc}`. A verifier refuses any `sig` by that key on a frame whose `utc` is at or after `revoked_utc`, checking tombstones at verification time.
- To stop a key without rotating, the owner registers a tombstone.
- "Owner-signed" means the `kid` is the registry's estate owner in effect at that time. See [[The Registry]].

**Known limit:** frame `utc` is set by the producer. A stolen key can backdate frames to just before `revoked_utc`. After a compromise, the owner **should** advance or re-genesis affected stream heads past that point. See [[Versioning and Evolution]].

## What the reference profile covers

The small stdlib reference (`rapp.py`) enforces the presence rule for swarm frames. Vector V9 in `conformance.py` proves an unsigned swarm frame is refused.

It does **not** perform Ed25519/ES256 verification, registry key discovery, rotation, or tombstone checks. A full **Consumer** must. See [[Conformance Classes]].

## Review questions

Ask these about any signed design, in order:

1. Which exact bytes are signed?
2. Can two serializations of the same value give different signing inputs?
3. Where does the verifier get the public key?
4. What binds that key to the claimed identity?
5. What says the key was authoritative at the frame's `utc`?
6. What stops a stale registry from silently un-revoking it?

If any answer is "the sender tells us", verification is not complete.

## Related

- [[Identity and the Rappid]]
- [[The Registry]]
- [[The Frame]]
- [[Security Considerations]]
- [[Conformance Classes]]

========================================================================
FILE: Protocol/Versioning and Evolution.md
========================================================================

---
title: Versioning and Evolution
section: Protocol
status: published
hook: How does rapp/1 change over time without breaking verification of anything already published?
source: SPEC.md §12; book/09-registry-evolution-and-security.md §9.6-9.7
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Versioning and Evolution

rapp/1 is a **living standard**: it is revised in place, not split into parallel versions.
The core **wire is frozen**. Anything verified under `rapp/1` keeps verifying forever.
New vocabulary grows through the registry; a shape change would need a new token, `rapp/2`.

## The short version

- One label never means two shapes. A shape change moves the token.
- Published content-addressed artifacts are **immutable**.
- Within an estate there is no permanent backward compatibility for its own retired forms: a change is a **total migration** plus deletion of the old form.
- Immutable chains change through **re-genesis**, never by editing old bytes.
- Every protocol revision is one appended frame on the specification's own chain.

## What is frozen

No revision may change a form a `rapp/1` artifact is verified by:

- canonicalization (§4) — see [[Canonicalization]];
- the hash function and its tags (§5) — see [[Content Addressing]];
- the rappid grammar and mint (§6.1, §6.2) — see [[Identity and the Rappid]];
- the eleven-key envelope and its two addresses (§7.1, §7.3) — see [[The Frame]];
- the consumer checklist (§7.5);
- the two wire forms and the `/chat` shapes (§8) — see [[The Wire]];
- the egg container and address (§9.1) — see [[The Egg]].

A change to any of these is not a revision. It moves the token to `rapp/2`, specified beside the current document. A consumer **must not** refuse a `rapp/1` artifact because a later token exists.

The reason: these frozen forms are what a stranger's implementation, written once and never updated, relies on.

## What still grows under rapp/1

- registered kinds;
- egg variants;
- error codes;
- registry entry types;
- vocabulary;
- subordinate profiles (see [[Conformance Classes]]);
- the registry itself (see [[The Registry]]).

A new registered `kind` uses the existing eleven-field frame. A changed key set, field grammar, or hash rule needs a new token.

## Why no permanent dialects

Every legacy reader path doubles the producer/consumer combinations that can disagree. rapp/1 chooses convergence: one current form. Old immutable history is kept only when it has been sealed through re-genesis.

## Re-genesis: change without rewriting history

Re-genesis is one owner-authorized operation that moves a stream to a new live chain while keeping the old bytes intact.

1. **Seal the old head.** `seal = Hb("rapp/1:seal", head_octets)`, over the exact retained octets.
2. **Emit a new genesis.** `seq` 0, `prev` null, the family's registered kind (`memory.re-genesis`, `swarm.re-genesis`, or `body.re-genesis`), owner-signed. The payload is exactly:

   ```json
   {"migrated_from":{"stream_id":<old>,"terminal_seal":<seal>,"terminal_seq":<n>}}
   ```

3. **Register it.** Append a `genesis` registry entry and flag every prior `genesis` for that `stream_id` as `deprecated`. This append is the linearization point. A concurrent second registration fails closed.
4. **Retire the old frames** under `legacy/`, bit-exact. They are never served as current, never extended, and no live frame may point at them.

A consumer refuses an unsigned or non-owner re-genesis frame. Only the registry-published genesis lets a consumer reset its remembered head to zero; anything else is a rollback attack.

Re-genesis is not an automatic repair. A checker may identify the need and prepare evidence. It must not invent authority.

## How the specification itself is revised

The upstream specification's revisions live in an append-only chain, `anchor/chain.jsonl`.

- Every protocol adjustment appends exactly one frame, kind `body.pulse`, with contiguous `seq`.
- The frame's `frame_hash` is the revision's durable identity. Names like `rev-14` are lookup labels only.
- From rev-14 on, the full normative text travels inside the frame, with its `sha256` and byte length.
- Verification starts from a frozen, content-addressed bootstrap profile, `rapp-anchor-bootstrap/1`.
- Each frame is also published at `anchor/frames/<frame_hash>.json`.
- `orient.json` is only a beacon to the head and must be regenerated from the verified chain.

Hashes in this chain prove byte integrity and linear history. They do **not** prove who ratified a change. Authority comes from owner-ratified acceptance onto the protected canonical branch. The chain and beacon are unsigned, and implementations must not fabricate a signature for them. See [[Sources and Provenance]].

## The DOGG specification revision chain (§12.2)

The specification is itself a **DOGG**: a public, re-pullable chain anyone can fetch and check.
A **revision** is one appended frame. Its `frame_hash` is its identity.
A copy whose hashes verify is **not** automatically authoritative. A verified fork is still a fork.

Technical detail, from SPEC.md §12.2:

- Each adjustment appends exactly one successor frame: `spec` stays `"rapp/1"`, eleven envelope keys, kind `body.pulse`, the bootstrap-pinned anchor `stream_id`, contiguous `seq`, `prev` naming the predecessor's `payload_hash`, and `prev_wave` and `sig` both `null`.
- Frames through rev-13 keep immutable pointer fields (`canonical_repo`, `commit`, `normative_path`, `normative_sha256`, `normative_bytes`). A resolver fetches only a commit-pinned copy and refuses a length or hash mismatch. These pointer payloads must not be emitted for rev-14 or later.
- From rev-14, the payload carries `schema:"rapp-spec-revision/1"`, a unique `revision`, `previous_revision`, `previous_normative_sha256`, a `publication` object, and a `normative` object holding the exact text, its `sha256` and `bytes`. The `publication` metadata must not be read as a signature or an authenticated registry.
- `anchor/index.json` is a generated index with no authority of its own. Resolution by revision label is a view; `rev-5` resolves to the greatest matching `seq`.
- A consumer verifies from the bootstrap-pinned genesis and refuses a fork or duplicate `seq`, duplicate hashes, an unsupported schema, a pointer-only frame after rev-13, normative hash or length drift, or an object absent from the selected chain.
- The authority linearization point is owner-ratified acceptance of a commit onto protected canonical main. A stale competing append rebases and regenerates; force-push or history replacement is prohibited.

## For downstream estates

This repository pins one exact upstream commit, recorded in each note's `upstream_commit`. Retiring a name follows the same idea: migrate deliberately, keep history, never break what is already published. See [[Distros and Pinning]] and [[Conformance and Drift]].

## Related

- [[The Registry]]
- [[The Frame]]
- [[Conformance Classes]]
- [[Conformance and Drift]]
- [[Sources and Provenance]]
- [[Distros and Pinning]]

========================================================================
FILE: Operations/RAPP CICD.md
========================================================================

---
title: RAPP CICD
section: Operations
status: published
hook: How does one exact AI release candidate earn promotion toward production under rapp/1?
source: "protocols/rapp-cicd/1/SPEC.md §1-§9; SPEC.md §11.1-§11.2"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# RAPP CICD

**RAPP CI/CD** (`rapp-cicd/1`) is the rule set for moving one release from development to production.
It makes "production ready" a checkable statement about **one exact candidate**.
Change any byte, prompt, model or policy, and it is a new release that must qualify again.

## The answer in brief

- A release is described once, in a **release capsule**, before testing starts.
- A **policy** lists the stages in order and the checks each stage needs.
- Each stage produces **evidence** about that exact candidate.
- A **promotion** decision moves it one stage forward, holds it, or rejects it.
- Approval never repairs failed evidence. An owner can stop a passing candidate, but cannot promote a failing one.

The profile does not prescribe GitHub Actions, a cloud provider, a branch model, or ring names.

## Foundation

RAPP CI/CD sits under rapp/1. An implementation must:

- use rapp/1 canonical I-JSON for every payload (see [[Canonicalization]]);
- identify each payload by `H("rapp/1:particle", payload)` (see [[Content Addressing]]);
- carry authoritative payloads in a signed rapp/1 frame (see [[The Frame]] and [[Trust and Signatures]]);
- add no transport endpoint beside `POST /chat` (see [[The Wire]]);
- resolve `release_scope` and the Grail binding from authenticated, owner-controlled policy.

A local unsigned file is a draft, fixture, or cache. It cannot authorize promotion.

## The four payloads

| schema | purpose |
|---|---|
| `rapp-cicd/1-release` | immutable identity of one release candidate |
| `rapp-cicd/1-policy` | ordered promotion path and required evidence |
| `rapp-cicd/1-evidence` | result of one stage against that exact candidate |
| `rapp-cicd/1-promotion` | explicit decision to advance, hold, or reject |

All four are closed. Unknown keys and missing keys are refused.

## The release capsule

The capsule binds source commit and tree, the exact artifact, the runtime entry point, and the Grail kernel.
It must contain exactly one immutable `kernel` component whose digest equals `grail.sha256`.
It must list every behavior-affecting agent, adapter, model, policy, configuration, state schema, tool, and knowledge source.

`lineage.mode` is `seed`, `offspring`, or `cross`.
Naming parents is informational only; the new release inherits no authority from them.

Example from the specification:

```json
{
  "schema": "rapp-cicd/1-release",
  "release_scope": "https://example.com/releases/product",
  "created_utc": "2026-08-30T12:54:20.000Z",
  "source": {
    "repository": "https://github.com/example/product",
    "object_format": "sha1",
    "commit": "0123456789012345678901234567890123456789",
    "tree": "abcdefabcdefabcdefabcdefabcdefabcdefabcd"
  },
  "artifact": {
    "sha256": "<64 lowercase hex>",
    "size_bytes": 1234,
    "media_type": "application/zip",
    "entrypoint": "src/main.py"
  },
  "grail": {
    "grail_id": "grail:<64 lowercase hex>",
    "path": "rapp_brainstem/brainstem.py",
    "sha256": "<64 lowercase hex>",
    "size_bytes": 154059
  },
  "components": [
    {
      "kind": "kernel",
      "name": "grail-brainstem",
      "version": "v0.6.16",
      "sha256": "<same digest as grail.sha256>",
      "mutable": false
    }
  ],
  "lineage": {
    "mode": "seed",
    "parents": []
  }
}
```

The capsule's Grail fields must equal the activated `grail-kernel` entry from a trusted registry verifier (see [[The Registry]]).
Comparing them only against other candidate-supplied fields is circular and nonconformant.

## The promotion path

Stages follow one order of semantic classes:

`development -> test -> canary -> qualification+ -> preprod -> production`

`qualification` may repeat. Every other class appears exactly once.
Each stage declares `required_checks`, `minimum_soak_seconds`, `maximum_evidence_age_seconds`, and `approval` (`automatic` or `owner`).

- **Canary** must include `grail-kernel`, `product`, `autonomous`, and `security-smoke`.
- **Preprod** must include fourteen checks, among them `exact-candidate`, `security`, `privacy`, `tenant-isolation`, `rollback-rehearsal`, and `restore-rehearsal`, and must have a non-zero soak.
- **Production** must require owner approval.

Preprod is a gate, not a ring. It rebuilds the exact candidate in a production-shaped environment and accepts no patches.

## Evidence and promotion rules

Evidence forms a hash-linked chain that follows the policy.
A missing predecessor, skipped or reordered stage, stale candidate, changed artifact, or changed Grail is a refusal.

- Evidence must come from a **trusted evaluator** outside the candidate's control.
- Secrets, credentials, and raw customer content must not appear in evidence; store a digest or access-controlled reference.
- An unavailable check counts as failed, never as skipped-success.

A `promote` decision is valid only for the next stage, with passing, fresh evidence, a complete evidence prefix, and an authorized signer.

## Release-blocking findings

`kernel-drift`, `artifact-drift`, `policy-drift`, `environment-drift`, `stage-skip`, `missing-evidence`, `failed-check`, `stale-evidence`, `untrusted-evaluator`, `state-incompatible`, `rollback-unproven`, `restore-unproven`.

A red gate is a finding. Bypassing it, muting it, or retrying until green without keeping the failures is nonconformant.

## Conformance

Payload validators prove shape and hashes but grant no authority.
`authorize_promotion_frame` additionally verifies the frame, signature, Grail binding, and signer.
A claim of RAPP CI/CD conformance includes passing `python3 operations_conformance.py`.
A claim of **RAPP production conformance** needs both this profile and [[RAPP Deploy]] (see [[Conformance Classes]]).

## Related

- [[RAPP Deploy]]
- [[RAPP Work]]
- [[Distros and Pinning]]
- [[Conformance and Drift]]
- [[Step 13 Production Deployment]]
- [[Sources and Provenance]]

========================================================================
FILE: Operations/RAPP Deploy.md
========================================================================

---
title: RAPP Deploy
section: Operations
status: published
hook: How does a qualified rapp/1 release reach users safely and stay provably healthy afterward?
source: "protocols/rapp-deploy/1/SPEC.md §1-§11; SPEC.md §11.2"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# RAPP Deploy

**RAPP Deploy** (`rapp-deploy/1`) is the rule set for giving a qualified release real user traffic.
Traffic grows in small, observed steps across isolated **cells**.
Health must be proven again and again, not once. Any doubt means hold, roll back, or quarantine.

## The answer in brief

- The unit of change is one immutable [[RAPP CICD]] release.
- The unit of safety is one isolated **deployment cell**.
- Exposure grows in **waves**, from zero-traffic shadow to global.
- Health evidence **expires**. Expired evidence cannot authorize more rollout.
- Rollback targets an **exact release hash**, never a mutable tag.

## Foundation

RAPP Deploy inherits every rapp/1 and RAPP CI/CD refusal. It adds no endpoint.
It defines three closed payloads:

| schema | purpose |
|---|---|
| `rapp-deploy/1-plan` | topology, waves, health budgets, state, data, and recovery |
| `rapp-deploy/1-health` | one candidate-bound observation window in one cell |
| `rapp-deploy/1-decision` | advance, complete, hold, rollback, or quarantine |

Authoritative payloads travel in signed rapp/1 frames (see [[The Frame]] and [[Trust and Signatures]]).
An authorized plan binds a signed, fresh promotion to Production, the full evidence prefix, the authenticated Grail declaration, and a previously authorized rollback release.

## Serving and candidate lineages

Two lineages stay separate:

- **serving lineage** — the immutable release users talk to now;
- **candidate lineage** — an isolated release under qualification or progressive exposure.

`candidate_isolated` must be true and `in_place_mutation` must be false.
The running service may append user state. It may not rewrite its code, model selection, agents, prompts, tools, policies, or schemas under an existing release identity.

## Cells and topology

Every plan uses `topology.mode: "cellular"`.

| class | minimum topology |
|---|---|
| `single-cell` | one cell |
| `multi-cell` | two cells in two failure domains |
| `planetary` | three cells, two regions, three failure domains |

A planetary deployment must be able to stop routing to one cell without stopping healthy cells.

## Waves

Traffic is counted in integer basis points.

- Start with `shadow` at zero user traffic.
- Increase strictly; never remove an exposed cell.
- End with `global` at 10,000 basis points across every cell.
- Planetary plans add `canary` (at most 100) and `regional` (at most 5,000).

Each wave sets a minimum observation time and a minimum number of healthy windows per cell.

## The health contract

The plan lists integer objectives, each with unit, comparison, and threshold. The minimum set covers:

- availability, error rate, p95 latency;
- quality score, safety violations, tool success;
- resource saturation, knowledge age, cost per request.

The core also requires exact artifact identity, exact Grail identity, state integrity, model identity, behavioral-baseline compatibility, and tool-contract compatibility.

The verdict is derived. An observation cannot label itself healthy when a budget failed.
A model provider, tool, or knowledge source can change without a commit, so health evidence expires after `max_evidence_age_seconds`.

## State, data, and resilience

- State uses `none`, `expand-contract`, or `dual-read-write`, and must stay backward compatible during rollout.
- Any migration needs a content-addressed rollback snapshot.
- Acknowledged user work must not be lost by rollback. If that cannot be proven, rollout is refused.
- Tenant isolation is mandatory. Raw prompts, memories, credentials, and regulated data are not deployment evidence.
- Every deployment needs circuit breakers, rate limits, load shedding, an independent kill switch, automatic pause, and automatic rollback.
- Provider failure is `fail-closed` or `degrade-explicitly`. A silent, success-shaped fallback is forbidden.

## Decisions

A decision is `advance`, `complete`, `hold`, `rollback`, or `quarantine`.
Decisions form their own hash chain; health windows form a per-cell chain that cannot overlap or restart.
A decision that cites any unhealthy or stale observation can never authorize `advance` or `complete`.

## Health after launch

Production is a continuously renewed health claim. Implementations must keep emitting health windows, requalify when evidence expires, rehearse rollback, restore, failover, and capacity, enforce error budgets, and retire releases only through explicit migration.

## Conformance

`validate_plan_payload`, `validate_health`, and `validate_decision` prove content relationships.
`authorize_plan_frame` and `authorize_decision_frame` add signatures and signer authority.
Conformance includes passing `python3 operations_conformance.py`.
Claim `planetary` only when every planetary requirement is proven by current evidence.

## Related

- [[RAPP CICD]]
- [[RAPP Work]]
- [[Step 13 Production Deployment]]
- [[Step 14 Post-Deployment Review]]
- [[Security Considerations]]
- [[Sources and Provenance]]

========================================================================
FILE: Operations/RAPP Work.md
========================================================================

---
title: RAPP Work
section: Operations
status: published
hook: How does rapp/1 bind a work organization to its catalog, releases, migrations, and rollback targets without granting hidden authority?
source: "protocols/rapp-work/1/SPEC.md §1-§10"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# RAPP Work

**RAPP Work** (`rapp-work/1`) is the rule set for running a work organization on rapp/1.
It records what the organization advertises, which releases it trusts, how workspaces move, and what it rolls back to.
It is purely additive: it changes no rapp/1 byte, hash, signature, egg, or endpoint.

## The answer in brief

- A **catalog** says what exists. It never grants permission to run it.
- A **migration** always creates a new target. It never upgrades in place.
- A **rollback target** is an exact, already authorized release.
- Every authoritative record is **signed**, even where base rapp/1 would allow an unsigned frame.
- Observations are **bounded** to 128 and never silently deleted.

## Foundation and registration

Every authoritative RAPP Work payload is canonical I-JSON, identified by `H("rapp/1:particle", payload)`, carried in the eleven-key frame (see [[The Frame]]), signed, and appended to the organization's body stream.

An adopting estate appends one `protocol` entry pinning this specification, plus seven `kind` entries in [[The Registry]]:

| Kind | Only permitted payload schema |
| --- | --- |
| `work.organization` | `rapp-work/1-organization` |
| `work.catalog` | `rapp-work/1-catalog` |
| `work.vector` | `rapp-work/1-vector` |
| `work.migration` | `rapp-work/1-migration` |
| `work.receipt` | `rapp-work/1-receipt` |
| `work.observation` | `rapp-work/1-observation` |
| `work.rollback` | `rapp-work/1-rollback` |

The set is closed. The registry also pins `rapp-hive/1`, [[RAPP CICD|rapp-cicd/1]], and [[RAPP Deploy|rapp-deploy/1]].

## The organization

`rapp-work/1-organization` is the first record of a work body stream. It binds `organization_rappid`, `owner_rappid`, one `world_id`, one `hive_rappid`, the `release_scope`, an exact `policy_sha256`, and `created_utc`.

A name, repository, URL, or local path cannot derive or replace these identities (see [[Identity and the Rappid]]).

## Catalogs are discovery, not authority

A catalog is an append-only list of up to 256 items. Each item has a `kind` (`plugin`, `skill`, `static-api`, or `portable-neuron`), a typed rapp/1 address, a locator, and `authority:"discovery-only"`.

Signing a catalog proves what was advertised. It does not grant execution, installation, tool, network, or publication rights.
Portable Neurons are accepted only as inert data, never as instructions.

## The Hive vector

`rapp-work/1-vector` records which authenticated Hive state the organization accepted:

```json
{
  "registry_seq": 8,
  "registry_hash": "<64 lowercase hex>",
  "hive_rappid": "<RAPPID>",
  "mother_head_frame_hash": "<64 lowercase hex>",
  "catalog_hash": "<64 lowercase hex>"
}
```

Consumers keep the accepted vector as a **high-water mark**:

- a lower sequence is rollback;
- different hashes at the same sequence are a fork;
- resetting retained state is not recovery.

Git ancestry, a newer timestamp, or a moving branch cannot substitute for this check.

## Rollback targets

`rapp-work/1-rollback` binds one authorized [[RAPP CICD]] release by its particle hash, artifact SHA-256, Grail id, state-schema SHA-256, source snapshot, restore evidence, and an immutable Git descriptor.
The hashes are the authority; the Git descriptor is only a locator.
A branch, moving tag, or `main` raw URL is refused as a rollback target.

## Create-only migration

`rapp-work/1-migration` records an immutable intent with `mode:"create-only"`.
It binds the source workspace and snapshot, a fresh target workspace, the target release, the accepted vector, selected catalog items, and the rollback record.

- The migration id is a particle hash of the organization, source, target, and target release.
- Exact replay is idempotent. A second, different payload under the same id is refused.
- Old keys, private history, prompts, and unlisted state are not imported.

## Receipts and recovery

Receipts are `migration-completed`, `catalog-verified`, or `release-verified`, and are always signed.
Before any mutation, recovery checks that the intent is unchanged, the receipt and signer are authorized, all evidence verifies, the source is unchanged, bindings are exact, and the target key is in verified custody.
Nothing may be regenerated to make a check pass.

## Observations

A `rapp-work/1-observation` binds one release, one deploy plan, the accepted vector, evidence, and a verdict.
A `healthy` verdict requires authorized [[RAPP Deploy]] health evidence.
The reference profile keeps at most 128 observations; at the bound a new one is refused, never overwritten.

## Conformance

Conformance covers the seven schemas, signed registry kinds, high-water persistence, create-only migration, custody preflight, inert discovery data, and the observation bound, and includes passing `python3 work_conformance.py`.
JSON Schema, a Git commit, a raw URL, or an unsigned receipt is never authority.

## Related

- [[RAPP CICD]]
- [[RAPP Deploy]]
- [[The Registry]]
- [[Trust and Signatures]]
- [[Security Considerations]]
- [[Sources and Provenance]]

========================================================================
FILE: Building/Conformance and Drift.md
========================================================================

---
title: Conformance and Drift
section: Building
status: published
hook: How do you prove an implementation conforms to rapp/1, and how do you find and fix drift in real artifacts?
source: "book/10-conformance-and-drift.md §10.1-§10.9; SPEC.md §11; rapp/KERNEL-DRIFT.md; docs/GRAIL-SPECIES.md"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Conformance and Drift

**Conformance** means an implementation passes fixed protocol tests.
**Drift** means real, published artifacts no longer match the current rules.
You need two separate checks: stable controlled vectors, and a fresh audit of what is actually published.

## The answer in brief

- **Controlled vectors** hold the implementation still. They never depend on remote state.
- A **real-world harness** reads current artifacts and reports clean, drift, or not inspected.
- A red report describes work to do. Fix the artifacts, never teach the checker to accept old forms.
- Fail closed: "could not look" is never "no drift".

## Controlled vectors

The upstream reference suite runs with:

```bash
python3 conformance.py
```

At the pinned commit it reports 23 controlled checks. (The book's figure of 22 predates V11.) They map to earlier rules:

- V1/V1b — [[Canonicalization]];
- V2 — domain separation in [[Content Addressing]];
- V3 — mint-once [[Identity and the Rappid|identity]];
- V4–V9 — building and verifying [[The Frame|frames]];
- V10 — the sealed-artifact profile;
- V11 — rev-17 regression suites (errata E-1..E-23).

Green here is not a generic clean build. It is a set of protocol claims exercised against fixed inputs.
A controlled suite must not start failing just because someone migrated a public repository.

## The real-world harness

A separate harness refreshes the live repositories and walks every frame and identity record. For each frame chain it asks:

1. Does the reference canonicalizer reproduce the stored address?
2. Does each `prev` link equal the previous payload address?
3. Does the full envelope pass `verify_frame` against its real head and stream?

Refreshing is part of the test. A report from a stale cache is a snapshot pretending to be live.

## A worked case: from eight drifts to zero

The first audit found 32 historical frames whose canonical bytes the reference reproduced exactly, but whose envelopes failed at step 1.

| Historical field | Current field |
|---|---|
| `twin_id` | `stream_id` |
| `ts` | `utc` |
| `sha256` | `payload_hash` |
| `parent_sha` | `prev` |
| absent | `frame_hash` |
| absent | `prev_wave` |

It also found short provisional identity tails and old schema labels: eight drifts in total.
After owner-authorized re-anchoring and migration, the audit reported 46 of 46 current envelopes accepted and zero drift.
It went green because the artifacts changed, not because the verifier learned to read the old form.

## Reading a red report

| Failure | Correct response |
|---|---|
| canonical bytes differ | replace the canonicalizer; regenerate unpublished output |
| same bytes, wrong domain-tagged hash | migrate through the current producer; do not alias hashes |
| rappid grammar or tail fails | owner-authorized re-anchor |
| frame step 1/1a fails | reject; re-genesis if committed history is immutable |
| frame step 2/3 fails | reject as corruption or tampering |
| frame step 4/5 fails | surface fork or drift; never reparent automatically |
| frame step 6 fails | refresh registry, then reject if still invalid |
| egg integrity/viability fails | reject the whole egg |

The rule is **reject first, migrate deliberately**. See [[Failure Atlas]].

## From finding to convergence

1. Capture the failing artifacts and exact checker output.
2. Classify every mismatch by normative section.
3. Identify the current owner and authority record.
4. Generate conformant artifacts without changing published addressed bytes.
5. Re-anchor identity or re-genesis history when authorized.
6. Update the append-only [[The Registry|registry]].
7. Rerun both the controlled suite and the live harness.
8. Retire old live forms, keeping only sealed history where required.

## Drift in this library

The same discipline governs how this library ships the Brainstem kernel.
`tests/test_grail_species.py` is the hard gate: it fails CI if the shipped kernel breaks the pinned Grail shape.
`rapp/KERNEL-DRIFT.md` is the explanation: every file that differs from the pinned commit is listed with a reason and a disposition, and a check fails when one is missing.
In release pipelines, the upstream specification makes `kernel-drift` a release-blocking finding (see [[RAPP CICD]]).

## Related

- [[Implementing the Protocol]]
- [[Conformance Classes]]
- [[Failure Atlas]]
- [[Distros and Pinning]]
- [[Versioning and Evolution]]
- [[Sources and Provenance]]

========================================================================
FILE: Building/Distros and Pinning.md
========================================================================

---
title: Distros and Pinning
section: Building
status: published
hook: How does this library ship the Brainstem kernel pinned by a species contract and drift-ledgered, with every difference recorded in `rapp/KERNEL-DRIFT.md`, and its own catalog around it?
source: "rapp/GRAIL-SPECIES.json; rapp/KERNEL-DRIFT.md; docs/GRAIL-SPECIES.md; docs/RELEASE-PROCESS.md; CLAUDE.md; SPEC.md §11.1"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Distros and Pinning

The AIBAST Agents Library is a **distribution** of the Brainstem.
It ships the Grail kernel **pinned** to one exact source commit, with every difference recorded in a drift ledger, and adds its own agent catalog, pages, and cloud tiers around it.
Kernel updates arrive one way, through reviewed kernel-sync pull requests.

## The answer in brief

- **Pin**: `rapp/GRAIL-SPECIES.json` records the kernel's shape and the exact Grail commit it came from.
- **Contract**: a species test fails CI if the shipped kernel stops matching that shape.
- **Ledger**: `rapp/KERNEL-DRIFT.md` names every shipped file that differs from the pin, and why.
- **Catalog**: the library's own agents, registry, and pages sit outside the kernel.

## The pin

The species contract records where the kernel came from:

```json
"source": {
  "ref": "main",
  "commit": "49db80c8c6b6caa7647369beaf477d374a8f293c",
  "fetched_at": "2026-09-04T12:57:59+00:00",
  "files": 31
}
```

It also records `"kernel_version": "0.6.16"`, every route, the `BasicAgent` methods, the discovery rule, the import shims, the default port, the `/chat` response field, and the install layout.

## The species test

`tests/test_grail_species.py` compares the shipped kernel with the pinned shape. It fails when the kernel drops or changes:

- a Flask route the Grail exposes;
- a `BasicAgent` method or its signature;
- the discovery rule (`*_agent.py`, flat, no subdirectories);
- an import shim;
- the default port (`7071`) or the `/chat` response field (`response`);
- an install-layout constant.

```bash
python -m unittest -v tests/test_grail_species.py
GRAIL_SPECIES_LIVE=1 python -m unittest tests/test_grail_species.py
```

Live mode also compares against the current Grail. Items the Grail has and the library lacks are reported as "pending kernel sync"; only a broken shared item fails.

## The drift ledger

Every shipped file that differs from the pinned Grail commit appears in `rapp/KERNEL-DRIFT.md` with a disposition:

- **permanent** — identity rewrites such as repository and support links, the Microsoft persona in `soul.md`, and the catalog pin in the chat's registry panel;
- **upstream candidate** — fixes that belong to every Brainstem user, such as installer overrides and `GET /health/public`, waiting to return through a kernel sync;
- **distribution content** — files only this library ships, such as its learn-new-agent agent and tests.

`python scripts/grail_species.py drift <grail-dir> --ledger rapp/KERNEL-DRIFT.md` fails when a differing path is missing from the ledger.

## One layout, either installer

A Grail install and a library install share one layout: `~/.brainstem`, its `venv/`, `src/rapp_brainstem/`, and the flat `agents/` directory.
Because the contract keeps those identical, either installer can run over the other and the result is still one working Brainstem with the user's agents intact.

## What the library owns

These surfaces belong to the library and are kept through every kernel sync:

- `agents/@aibast-agents-library/`, `registry.json`, `build_registry.py`;
- `index.html`, `docs/installer.html`, `why.html`, `metrics.html`, and `state/`;
- `rapp_ai/`, the Azure Functions tier;
- `README.md`, `docs/rapp-guide.html`, `.github/`, and `tools/`.

## How a kernel update lands

1. A kernel-sync pull request brings the new Grail into the staging ring.
2. The same change regenerates `rapp/GRAIL-SPECIES.json` and refreshes `rapp/KERNEL-DRIFT.md`.
3. Preflight, the Pages deploy, and the clean-runner one-liner smoke must pass.
4. `tools/promotion_check.sh` must report GREEN.
5. One pull request from staging to `microsoft:main`, opened and merged by a human.

A fix that belongs to every Brainstem user goes to the Grail first and comes back through this path.

## How rapp/1 supports this model

The upstream rapp/1 specification (§11.1) treats the Grail as an immutable kernel identified by `grail_id`:

- new behavior must live outside the kernel;
- different kernel bytes are a different Grail, never a retag of the old one;
- if needed behavior cannot be built outside the pin, the implementation reports an incompatibility rather than editing the kernel.

The library's pin, species test, and ledger put that discipline into daily practice.
For release-level byte pinning, see [[RAPP CICD]].

## Related

- [[The Brainstem Kernel]]
- [[The Agent Contract]]
- [[Conformance and Drift]]
- [[RAPP CICD]]
- [[Versioning and Evolution]]
- [[Sources and Provenance]]

========================================================================
FILE: Building/Implementing the Protocol.md
========================================================================

---
title: Implementing the Protocol
section: Building
status: published
hook: In what order should you build a rapp/1 implementation, and how do you know it is done?
source: "book/11-implementing-rapp.md §11.1-§11.11; SPEC.md §11"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Implementing the Protocol

To build a rapp/1 implementation, **build from the bottom up**.
Start with exact values and bytes, then hashes, identity, frames, eggs, and finally signatures and the registry.
Each layer relies on the one below having exactly one answer.

## The build order

```text
safe I-JSON parser
      ↓
canonical bytes
      ↓
H / Hb and typed addresses
      ↓
rappid mint and load
      ↓
frame build and verification
      ↓
egg pack and verification
      ↓
JWS, registry, succession, and current heads
```

Starting with `/chat`, ZIP, or signatures tends to hide lower-layer ambiguity behind a convenient API.

## 1. State your claim

Pick a [[Conformance Classes|conformance class]]: **producer**, **consumer**, or **router/mirror**.
One program can be more than one, but say so explicitly. A producer that builds valid frames is not automatically a full consumer.

Write the target at the top of the port:

```text
Target: RAPP rev-7 Producer + byte-core Consumer
Implemented: §§4–7, §9 integrity/viability
External adapters required: §10 JWS, §13 registry and freshness
```

## 2. Accept only admissible values

The parser must reject:

- duplicate object member names;
- unpaired UTF-16 surrogates;
- numbers outside the binary64 round-trip domain;
- values deeper than 64 levels;
- canonical output larger than 1 MiB.

A production port imports a tested RFC 8785 (JCS) implementation or proves its own with edge vectors. Compare UTF-8 **bytes**, not pretty-printed strings. See [[Canonicalization]].

## 3. Keep the address space in the type

```python
def H(space, value):
    preimage = space.encode() + b"\x0a" + canonical(value).encode("utf-8")
    return hashlib.sha256(preimage).hexdigest()
```

A bare digest should never travel without its space. Use separate constructors for values (`H`) and raw bytes (`Hb`), and no helper that guesses. See [[Content Addressing]].

## 4. Separate mint from load

Use two visibly different operations: `mint_rappid(...)` creates a new identity; `load_rappid(...)` reuses a stored one.
Never write `get_or_create_rappid`. A failed read would quietly become a new identity. See [[Identity and the Rappid]].

## 5. Make frame building pure

The builder takes explicit inputs. It does not read the clock, load the head, or publish.
Compute in one direction: validate, compute `payload_hash`, assemble, compute the wave, attach `frame_hash`, sign later if required.
Never mutate a built frame. See [[The Frame]].

## 6. Keep verification pure and ordered

```text
verify(candidate, head, stream_of_record, registry_snapshot)
    → accepted
    → refused(step, reason)
```

The verifier never repairs, persists, or reparents. Step order is observable behavior: shape before hashing, particle before wave, chain before trust. Keep a negative suite in every port; see [[Failure Atlas]].

## 7. Treat append as a transaction

Two writers can both read head 7 and build different frame 8s. Write the frame object first, then move the head with a compare-and-swap against the head you read.
If the swap fails, do not silently rebuild on the new head.

## 8. Verify eggs before extracting

Pack, read, verify, then extract. Check every path and the entry set before writing anything. `zip.extractall()` must never be the parser. See [[The Egg]].

## 9. Wrap cryptography narrowly

Do not implement Ed25519, ES256, DER, or JWS yourself. A thin rapp/1 adapter owns the protected header, signing input, allowed algorithms, `kid` parsing, and registry key lookup; a maintained library does the math. See [[Trust and Signatures]].

## 10. Test across languages

Record, for every positive fixture: input value, canonical UTF-8 hex, space tag, preimage hex, expected digest, and expected frame or manifest. For every negative fixture, record the refusal step and reason.
Accepting extra forms is as nonconformant as rejecting valid ones.

## Definition of done

```text
[ ] parser enforces the RAPP I-JSON input domain
[ ] canonical bytes match an independent implementation
[ ] address values always retain their spaces
[ ] mint and load are separate identity operations
[ ] builder emits exactly eleven frame keys
[ ] verifier observes the complete ordered checklist
[ ] append uses an atomic remembered-head comparison
[ ] egg verification precedes extraction
[ ] JWS adapter uses the exact protected header and signing input
[ ] registry sequence, freshness, succession, and tombstones are enforced
[ ] controlled positive and negative vectors pass
[ ] at least one independently produced artifact round-trips
```

The last item is the one most often skipped. Test with an implementation someone else wrote.

## Related

- [[Conformance Classes]]
- [[Conformance and Drift]]
- [[Protocol Layers]]
- [[Failure Atlas]]
- [[The Frame]]
- [[Sources and Provenance]]

========================================================================
FILE: Building/The Agent Contract.md
========================================================================

---
title: The Agent Contract
section: Building
status: published
hook: What exactly must a Brainstem agent file look like, and how does it reach the user through POST /chat?
source: "rapp_brainstem/agents/basic_agent.py; rapp_brainstem/brainstem.py (load_agents, /chat, /health); rapp_brainstem/CLAUDE.md; rapp/GRAIL-SPECIES.json; SPEC.md §8"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# The Agent Contract

An **agent** is one Python file that gives the Brainstem one new skill.
The file follows a small, fixed **contract**: a class built on `BasicAgent`, a description of its inputs, and a `perform` method.
Every new capability is a new agent behind `POST /chat`, never a new web address.

## The answer in brief

- File name ends in `_agent.py` and sits directly in `agents/`.
- The class extends `BasicAgent`.
- `metadata` is an OpenAI function schema: name, description, parameters.
- `perform(**kwargs)` does the work and returns text.
- The model decides when to call it, through `POST /chat`.

## Discovery

The Brainstem finds agents with one rule, recorded in the species contract `rapp/GRAIL-SPECIES.json`:

```json
"discovery": {
  "glob": "*_agent.py",
  "flat": true,
  "subdirectories_excluded": true,
  "listing_globs": [
    "*.py",
    "*_agent.py"
  ]
}
```

- Only the flat `agents/` directory is scanned. `agents/experimental/` is intentionally excluded.
- Agents reload from disk on every request. Edit the file and test again; no restart is needed.
- If two files register the same agent name, the later file is quarantined and reported by `GET /health`.

## The base class

Every agent extends `BasicAgent` from `agents/basic_agent.py`. Its four methods are part of the pinned contract:

| Method | Role |
|---|---|
| `__init__(self, name, metadata)` | sets the agent's name and function schema |
| `perform(self, **kwargs)` | runs the agent; arguments come from the model's tool call |
| `system_context(self)` | optional text added to the system prompt each turn |
| `to_tool(self)` | turns `metadata` into an OpenAI function-calling tool definition |

The default `metadata` shape shows the expected fields:

```python
self.metadata = {
    "name": self.name,
    "description": "Base agent -- override this.",
    "parameters": {"type": "object", "properties": {}, "required": []}
}
```

## How a request flows

For `POST /chat` the Brainstem:

1. loads `soul.md`, the system prompt;
2. discovers agents from `agents/`;
3. builds tool definitions from each agent's `metadata`;
4. calls the model with the conversation and the tools;
5. runs `perform()` for each tool call, looping up to three rounds;
6. returns the final answer and `agent_logs`.

Agents written for the cloud tier can import `utils.azure_file_storage`. The Brainstem maps it to a local JSON store through a `sys.modules` shim, so the same file runs in both places.

## The wire the agent sits behind

The upstream rapp/1 specification fixes the synchronous wire (see [[The Wire]]):

- Request: a JSON object with `user_input` (required), optional `conversation_history`, optional `session_id`. Unknown members are ignored.
- Success: HTTP 200 with at least `response`, `agent_logs`, and `session_id`.
- Malformed request: HTTP 400 with exactly `{"error": string}`.
- `GET /health` is the liveness probe; it carries no RAPP semantics.

A minimal call:

```bash
curl -s localhost:7071/chat -H 'Content-Type: application/json' \
  -d '{"user_input": "What can you do?"}'
```

The answer is in the `response` field. The species contract pins this as `"chat_response_field": "response"`.

## Why the contract stays small

The rapp/1 specification says new capability is a new agent behind `/chat`, never a sibling REST route.
That keeps one stable surface for every host: the local Brainstem, the Azure tier, and Copilot Studio.
It is also why this library's catalog ships agents and stacks, not server changes (see [[Distros and Pinning]]).

## Related

- [[The Brainstem Kernel]]
- [[The Wire]]
- [[Distros and Pinning]]
- [[Step 05 Generate Agent Code]]
- [[Step 06 Code Quality Review]]
- [[Sources and Provenance]]

========================================================================
FILE: Building/The Brainstem Kernel.md
========================================================================

---
title: The Brainstem Kernel
section: Building
status: published
hook: What is the Brainstem kernel this library ships, and what does it guarantee to every agent and host?
source: "rapp_brainstem/CLAUDE.md; rapp_brainstem/brainstem.py; rapp/GRAIL-SPECIES.json; docs/GRAIL-SPECIES.md; CLAUDE.md; SPEC.md §8, §11.1"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# The Brainstem Kernel

The **Brainstem** is the local AI server at the center of this library.
It is a single-file Flask app that talks to the GitHub Copilot API and runs your agents as tools.
The AIBAST Agents Library ships the **Grail** Brainstem kernel pinned by its species contract. Every difference from the pin is recorded in `rapp/KERNEL-DRIFT.md`, and the catalog is built around it.

## The answer in brief

- One file, `rapp_brainstem/brainstem.py`, holds auth, routing, streaming, diagnostics, model calls, and agent orchestration.
- It runs on port `7071` and needs only a GitHub account with Copilot access. No API keys.
- Its public shape — routes, `BasicAgent`, discovery, shims, port, `/chat` response field, install layout — is pinned in `rapp/GRAIL-SPECIES.json`.
- The pin records kernel version `0.6.16`, generated from Grail commit `49db80c8`.

## What it does

Each `POST /chat` request:

1. loads `soul.md` as the system prompt;
2. discovers agents from `agents/*_agent.py`;
3. calls the Copilot API with the agents as tools;
4. runs tool calls through each agent's `perform()`, up to three rounds;
5. returns JSON, or server-sent events on `POST /chat/stream`.

Authentication tries, in order: `GITHUB_TOKEN`, the `.copilot_token` file, `gh auth token`, then device-code sign-in via `/login`.
Copilot API tokens are short-lived and refresh automatically.

## The pinned surface

The species contract lists every route the Grail exposes. A sample:

```json
"POST /chat",
"POST /chat/stream",
"GET /health",
"GET /agents",
"POST /agents/import",
"GET /version"
```

It also pins:

- `"default_port": 7071`
- `"chat_response_field": "response"`
- the `BasicAgent` methods `__init__`, `perform`, `system_context`, `to_tool` (see [[The Agent Contract]])
- import shims such as `agents.basic_agent` and `utils.azure_file_storage`
- the install layout under `$HOME/.brainstem`: `venv`, `src/rapp_brainstem`, and its flat `agents` directory

## Health

`GET /health` reports `status`, `version`, `model`, the loaded `agents`, any quarantined agent files, and Copilot sign-in state.
It never exchanges tokens; that happens lazily on the first `/chat`.

```bash
curl -s localhost:7071/health | python3 -m json.tool
```

The library adds one small route, `GET /health/public`, returning only `status` and `version`. Its CORS is limited to the library's two Pages origins, so the static catalog can show whether a local Brainstem is ready. It is recorded in the drift ledger as an upstream candidate.

## Configuration

Settings come from `.env` in `rapp_brainstem/`: `GITHUB_TOKEN`, `GITHUB_MODEL` (default `auto`), `SOUL_PATH`, `AGENTS_PATH`, `PORT`, `BRAINSTEM_LAN_MODE`, `BRAINSTEM_ALLOWED_HOSTS`, and `VOICE_ZIP_PASSWORD`.
The target is Python 3.11 with a virtual environment at `~/.brainstem/venv`.

## How rapp/1 frames the kernel

The upstream rapp/1 specification names the Grail as the reference for the synchronous wire: an endpoint conforms when it answers the Grail conformance scenarios the way the pinned Grail does (see [[The Wire]]).
§11.1 then treats the Grail kernel as an immutable anchor identified by `grail_id`:

- different kernel bytes are a different Grail;
- new behavior lives outside the kernel;
- a changed or unmeasured kernel byte is `kernel-drift` and fails closed.

This library follows that model. Its catalog, pages, and Azure and Power Platform tiers live outside the kernel (see [[Distros and Pinning]]). The vendored `brainstem.py` does carry a few **ledgered edits**: one upstream-candidate route (`GET /health/public`) plus permanent identity and catalog-pin rewrites (the support link and `RAR_REVISION`), all listed in `rapp/KERNEL-DRIFT.md`.

## Running it

```bash
cd rapp_brainstem && ./start.sh
cd rapp_brainstem && python -m pytest tests -v
```

## Related

- [[The Agent Contract]]
- [[Distros and Pinning]]
- [[The Wire]]
- [[Conformance and Drift]]
- [[Step 07 Deploy Prototype]]
- [[Sources and Provenance]]

========================================================================
FILE: ms-rapp-1/Microsoft Foundry.md
========================================================================

---
title: Microsoft Foundry
section: ms-rapp-1
status: published
hook: How is ms-rapp/1 used in Microsoft Foundry, and what does a Foundry agent see?
source: "docs/ms-rapp1/openapi.json; tools/build_ms_rapp1.py; Microsoft Learn: Foundry Agent Service tool catalog, function calling, and agent tracing (checked 2026-11-01)"
---

# Microsoft Foundry

ms-rapp/1 meets Microsoft Foundry at one point: the **Step Catalog becomes an OpenAPI tool**.
A Foundry agent then calls Steps the same way a Brainstem calls agents, with no custom code.

## The answer in brief

- `tools/build_ms_rapp1.py --write` renders `docs/ms-rapp1/openapi.json`: one operation per Step.
- Add that file to a Foundry agent as an **OpenAPI tool**, pointed at your RAPP Runtime host.
- Put it in a **toolbox** to share the same Steps across many agents.
- Read each run in Foundry **tracing**, which records every tool call.

This page describes a pattern. It is separate from the library's solution templates, which use Copilot Studio, Microsoft 365 and Power Platform.

## Mapping

| ms-rapp/1 | Microsoft Foundry | Note |
|---|---|---|
| Step | an operation in an OpenAPI tool | the operation's request body is the Step's `metadata.parameters` |
| Step Catalog | one OpenAPI tool, optionally in a toolbox | OpenAPI tools can be shared through toolboxes |
| Step (in-process) | a function tool | the Step's `metadata` is already a function schema; your app runs `perform` |
| Step API host | the server URL in the OpenAPI file | your RAPP Runtime deployment |
| Run Receipt | agent tracing | built on OpenTelemetry and Application Insights; content recording is off by default |
| Step Policy | agent instructions and content filters | the Step's own checks still run in RAPP Runtime |
| Change Control | a new OpenAPI file version | rebuild the file when the catalog changes; `--check` fails if it is stale |

## Two ways to connect

**OpenAPI tool (recommended).** The Step runs in RAPP Runtime. Foundry calls the Step API over HTTPS. One file describes the whole catalog, and toolboxes can share it.

**Function tool.** Your application registers the Step's `metadata` as a function and runs `perform` itself when the model calls it. Use this when the Step must run inside your own process. Function tools run on the client side, so they cannot go in a toolbox.

## What stays the same

The Step file does not change between hosts. The same `action_items_agent.py` loads in a Brainstem, runs in RAPP Runtime, and is described to Foundry by the generated OpenAPI file.

## Not yet verified

The generated file has not been loaded into a live Foundry project. Foundry features named here were read from Microsoft Learn on 2026-11-01; some, such as toolboxes, may be in preview. Check the current documentation before relying on them.

See also [[ms-rapp-1 Overview]], [[Steps]] and [[RAPP Runtime]].

========================================================================
FILE: ms-rapp-1/ms-rapp-1 Overview.md
========================================================================

---
title: ms-rapp-1 Overview
section: ms-rapp-1
status: published
hook: What is ms-rapp/1, and how does it stay backward compatible with rapp/1 and the Brainstem?
source: "This vault's rapp/1 notes at the pinned commit; docs/ms-rapp1/; tools/build_ms_rapp1.py; tests/test_ms_rapp1.py"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# ms-rapp-1 Overview

**ms-rapp/1** is the enterprise profile of rapp/1.
It keeps every rapp/1 rule unchanged and adds one extension, **RAPP Runtime**, for running AI steps inside an enterprise review boundary.
If you know the Brainstem, you already know the pattern: one fixed engine, one endpoint, a folder of single-file capabilities.

## The answer in brief

- **rapp/1 is the base, unchanged.** This vault's Protocol and Building notes, pinned to one upstream commit, are the rules ms-rapp/1 inherits.
- **Anything that runs on the Brainstem runs here.** A Step is a rapp/1 agent: same base class, same metadata, same `perform`.
- **The extension is additive.** Steps carry two extra fields that a rapp/1 host ignores.
- **Compatibility is tested, not promised.** `tests/test_ms_rapp1.py` loads each example Step as a plain agent and fails if the profile drifts.

## Three levels

| Level | What conforms | What it adds |
|---|---|---|
| 1. rapp/1 | Any agent that follows [[The Agent Contract]] | Nothing. This is the Brainstem's own contract. |
| 2. RAPP Runtime | A Step: a rapp/1 agent with `ROUTE` and `RESULT_SCHEMA` | The Step API, the Step Catalog, Run Receipts. See [[RAPP Runtime]] and [[Steps]]. |
| 3. Microsoft Foundry | A Step Catalog published as an OpenAPI tool | Foundry agents call Steps with no custom code. See [[Microsoft Foundry]]. |

Each level includes the one before it. A file that conforms at level 3 still loads in a Brainstem at level 1.

## Rules that never change

1. **Never break the agent contract.** `BasicAgent`, `metadata`, `perform(**kwargs)` and the `*_agent.py` file name stay exactly as rapp/1 defines them.
2. **Never break the wire.** A host that offers `/chat` keeps the request and response described in [[The Wire]].
3. **Additions are named, never silent.** Everything ms-rapp/1 adds is listed in these notes and marked as an extension.
4. **Rename with an alias.** When an enterprise name differs from a rapp/1 name, both work. See [[RAPP Runtime]] for the name map.

## How it was built

ms-rapp/1 follows the distribution pattern in [[Distros and Pinning]]: the upstream rules come in at a pinned commit, and enterprise additions are layered on top and labeled.
Drift is caught the same way as in [[Conformance and Drift]]: a build check and a test, run on every change.

========================================================================
FILE: ms-rapp-1/One Concept Across the Stack.md
========================================================================

---
title: One Concept Across the Stack
section: ms-rapp-1
status: published
hook: How does one Step file show up in Copilot Studio, Microsoft 365 Copilot, Foundry, the Agent Framework and the Agents SDK?
source: "docs/ms-rapp1/; tools/build_ms_rapp1.py; Microsoft Learn: Copilot Studio REST API tools and MCP, Microsoft 365 Copilot API and MCP plugins, Foundry tool catalog, Agent Framework tools (checked 2026-11-01)"
---

# One Concept Across the Stack

The Microsoft agent stack has many surfaces, and each has its own word for "a thing the model can call": action, tool, plugin, connector, function, skill.
ms-rapp/1 reduces them to one concept: **a Step is a function with a schema**. Every surface below already accepts that shape, so one Step file reaches all of them.

## The answer in brief

- A Step's `metadata` is a function schema: a name, a description, a parameters object.
- That one schema can be written out three ways: a **function tool**, an **OpenAPI operation**, or an **MCP tool**.
- Every Microsoft agent surface accepts at least one of the three. None needs the Step to change.

## The three projections

| Projection | Made from | Who accepts it |
|---|---|---|
| Function tool | `metadata` as is (`BasicAgent.to_tool()`) | Brainstem, Foundry function calling, Agent Framework function tools, Agents SDK code |
| OpenAPI operation | `docs/ms-rapp1/openapi.json`, one operation per Step | Copilot Studio REST API tools, Power Platform custom connectors, Foundry OpenAPI tools, Microsoft 365 Copilot API plugins |
| MCP tool | `name`, `description`, and `parameters` as the input schema | Copilot Studio MCP, Microsoft 365 Copilot MCP plugins, Foundry MCP, Agent Framework MCP |

The function tool and the OpenAPI file are built and tested in this repository. The MCP projection is the same three fields under MCP's names; it is described here and not yet built.

## Surface by surface

| Surface | Its word | How a Step arrives |
|---|---|---|
| Brainstem | agent | the file itself, in `agents/` |
| RAPP Runtime | Step | the file itself, in the Step Catalog |
| Copilot Studio | tool (REST API or MCP) | the OpenAPI file; Copilot Studio converts version 3 files to version 2 |
| Power Platform | custom connector | the OpenAPI file |
| Microsoft 365 Copilot | plugin (API or MCP) | the OpenAPI file, or MCP |
| Microsoft Foundry | tool (OpenAPI, function, MCP) | see [[Microsoft Foundry]] |
| Microsoft Agent Framework | function tool, MCP tool | `metadata` as a function, or MCP |
| Microsoft 365 Agents SDK | your agent's code | the agent calls the Step API, or runs `perform` in process |

## Why one concept is enough

Each surface adds hosting, channels, sign-in and governance around the same core: the model reads a schema and calls a function.
Keep the function in one file with one schema and the surfaces become delivery choices, not rewrites.
Change the Step once and every projection is rebuilt from it; `tools/build_ms_rapp1.py --check` fails if the OpenAPI file falls behind.

## Not yet verified

These mappings follow the published shape of each surface, read from Microsoft Learn on 2026-11-01. The generated OpenAPI file has not yet been imported into Copilot Studio, Power Platform, Microsoft 365 Copilot or Foundry, and the MCP projection is not built. Several of these features are in preview.

See also [[Steps]], [[RAPP Runtime]] and [[ms-rapp-1 Overview]].

========================================================================
FILE: ms-rapp-1/RAPP Runtime.md
========================================================================

---
title: RAPP Runtime
section: ms-rapp-1
status: published
hook: What is RAPP Runtime, and how does each of its pieces map to the Brainstem?
source: "docs/ms-rapp1/; the Brainstem kernel in rapp_brainstem/; tools/build_ms_rapp1.py"
---

# RAPP Runtime

**RAPP Runtime** is the ms-rapp/1 engine that runs AI steps.
It has the Brainstem's shape, named in terms enterprise engineers and reviewers already use.

## The answer in brief

- One fixed engine runs every Step. It does not change per use case.
- One signed-in endpoint, the **Step API**, serves every Step. A new capability never adds an endpoint.
- The **Step Catalog** is a folder of reviewed Step files, loaded when they are called.
- Every run leaves a **Run Receipt** for audit.

## Name map

| RAPP Runtime | Brainstem | What it is |
|---|---|---|
| RAPP Runtime | Brainstem kernel | The fixed engine. See [[The Brainstem Kernel]]. |
| Step API | `POST /chat` | `POST /api/lens/<route>`: one endpoint for every Step. |
| Step | `agent.py` | One file, one business task, one checked result. See [[Steps]]. |
| Step Catalog | `agents/` | The approved set of Steps: only reviewed, deployed files. |
| Live catalog | agents reload every request | A merged and deployed Step is used on the next call. |
| Step Policy | `soul.md` | Fixed instructions. The model passes values; the Step checks them. |
| Result | `response` | The checked output, returned as `frame`. |
| Run Receipt | agent logs | Which Step, which model, how many attempts, what usage. |
| Change Control | a pull request into `agents/` | A Step arrives only by reviewed pull request and deploy, never from a browser. |

The code names (`lens`, `/api/lens/<route>`) stay as they are. The enterprise names are documentation names, so no published caller breaks.

## Where the shape differs, on purpose

| | Brainstem `/chat` | Step API |
|---|---|---|
| Input | `{user_input, conversation_history, session_id}` | the Step's own `metadata.parameters` |
| Output | `{response, session_id, ...}` | `{frame}`, matching the Step's `RESULT_SCHEMA` |
| Who picks the agent | the model | the caller, by route |

A Step is a fixed task with structured input. That keeps each Step reviewable on its own, which is what an enterprise release review assesses.
A free-text `/chat` on RAPP Runtime is allowed by the profile, but it accepts open text, so it should go through its own review before release.

See also [[ms-rapp-1 Overview]] and [[Run Receipts and Change Control]].

========================================================================
FILE: ms-rapp-1/Run Receipts and Change Control.md
========================================================================

---
title: Run Receipts and Change Control
section: ms-rapp-1
status: published
hook: How does ms-rapp/1 keep an AI step auditable, and how does a new Step get into production?
source: "docs/ms-rapp1/; this vault's Security Considerations and Conformance and Drift notes"
---

# Run Receipts and Change Control

Two rules make RAPP Runtime fit an enterprise review: every run leaves a record, and the set of Steps changes only through review.

## The answer in brief

- A **Run Receipt** records each run: the Step, the model, the number of attempts and the usage.
- The **Step Catalog** holds only files that were reviewed and deployed. The runtime never writes or downloads a Step.
- A new Step is a pull request, not a new endpoint and not a new release of the engine.

## Run Receipts

A receipt answers the questions an auditor asks about one AI step:

| Question | Receipt field |
|---|---|
| Which capability ran? | the Step's route and the hash of its file |
| Which model answered? | the model name |
| Did the model's answer pass the Step's checks? | the number of attempts, and the last refusal if any |
| What did it cost? | the token usage |

Receipts record what ran, not the customer's content. Keep payloads out of logs unless the review approves them.

## Change Control

1. A Step is written as a file and opened as a pull request.
2. Review reads one file: its parameters, its result schema, its checks.
3. Merge and deploy put it in the Step Catalog. The next call uses it.

The engine never loads code from a browser, an upload or a model response. This is the same rule app stores apply to apps after review: new behavior arrives as reviewed code.

## When a Step goes back to review

A Step stays inside an existing review when it uses only what the service already uses: the same sign-in, the same model, no new outside system.
A Step that sends email, writes to a new data store or calls a new service is a new data flow and needs its own review.

See also [[RAPP Runtime]], [[Security Considerations]] and [[Conformance and Drift]].

========================================================================
FILE: ms-rapp-1/Steps.md
========================================================================

---
title: Steps
section: ms-rapp-1
status: published
hook: What does a Step file look like, and why does it load unchanged in a Brainstem?
source: "docs/ms-rapp1/steps/action_items_agent.py; tools/build_ms_rapp1.py; rapp_brainstem/agents/basic_agent.py"
---

# Steps

A **Step** is a rapp/1 agent with two extra fields.
Drop it into a Brainstem's `agents/` folder and it loads like any other agent. RAPP Runtime serves the same file through the Step API.

## The answer in brief

- A Step extends `BasicAgent`, sets `name` and `metadata`, and implements `perform(**kwargs)`, exactly as in [[The Agent Contract]].
- It adds `ROUTE` (its Step API path) and `RESULT_SCHEMA` (the shape of its result).
- A rapp/1 host ignores the two extra fields. That is the whole compatibility story.

## The contract

| Field | rapp/1 | ms-rapp/1 adds | Rule |
|---|---|---|---|
| file name | `*_agent.py` | | so a Brainstem discovers it |
| class | one `BasicAgent` subclass | | |
| `metadata` | name, description, parameters | | `parameters` is an object schema; it is the Step API request body |
| `perform(**kwargs)` | returns a string | | for a Step, a JSON string matching `RESULT_SCHEMA` |
| `ROUTE` | | yes | 1 to 40 lowercase letters, digits or hyphens |
| `RESULT_SCHEMA` | | yes | a JSON schema object |

`tools/build_ms_rapp1.py --check` enforces these rules on every Step in `docs/ms-rapp1/steps/`.

## The example

`docs/ms-rapp1/steps/action_items_agent.py` lists the action items in meeting notes. It is deterministic, so the tests run it without a model.

```python
ROUTE = "action-items"
RESULT_SCHEMA = {"type": "object", "properties": {"items": {...}}, "required": ["items"]}

class ActionItemsAgent(BasicAgent):
    def __init__(self):
        self.name = "ActionItems"
        self.metadata = {"name": self.name, "description": "...",
                         "parameters": {"type": "object", "properties": {"notes": {"type": "string"}},
                                        "required": ["notes"]}}
        super().__init__(name=self.name, metadata=self.metadata)

    def perform(self, **kwargs):
        ...
        return json.dumps({"items": items})
```

Given the notes `Action: Dana: send the pricing sheet` and `TODO: book the follow-up`, it returns one item owned by Dana and one marked Unassigned.

## Writing a good Step

- **One fixed task.** A Step that does two things is two Steps.
- **Structured in, structured out.** The parameters and the result schema are the review surface.
- **No new systems.** A Step that reaches a new outside service or data store is a new data flow and goes back to review. See [[Run Receipts and Change Control]].

See also [[RAPP Runtime]] and [[Microsoft Foundry]].

========================================================================
FILE: Reference/Failure Atlas.md
========================================================================

---
title: Failure Atlas
section: Reference
status: published
hook: When a frame is refused, which check failed and what usually caused it?
source: "book/B-glossary-and-failure-atlas.md §B.2, §B.3"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Failure Atlas

A consumer checks every incoming frame in a fixed order.
The **Failure Atlas** maps each check to the failure it usually catches.
Use it to find *where* a frame was refused, then fix the producer.

## The one rule to remember

**The step is a refusal location, not a repair instruction.**

- Correct the producer, or perform an authorized migration.
- Do not change the received frame until it passes.
- When evidence is missing or unverifiable, the consumer **fails closed**. It never turns "could not check" into a pass.

## Frame verification steps

| Step | Consumer checks | Typical failure |
|---|---|---|
| `1` | exact keys, types, grammar, registry values, fixed UTC | dialect, missing/null confusion, malformed field |
| `1a` | `stream_id` equals the stream of record | cross-stream replay |
| `2` | recomputed particle equals `payload_hash` | payload changed |
| `3` | recomputed wave equals `frame_hash` | envelope changed |
| `4` | genesis or contiguous particle chain and nondecreasing UTC | gap, fork, wrong parent, time reversal |
| `5` | swarm `prev_wave` rule; null elsewhere | wrong wire discipline |
| `6` | required/present signature, key binding, tenure, tombstone | missing authorship or unauthorized signer |

## Reading each step in plain words

- **Step 1 — shape.** The frame must have exactly the right fields, types and formats. Extra fields, a different encoding, or a null where a value belongs all fail here. See [[The Frame]] and [[Canonicalization]].
- **Step 1a — right stream.** A valid frame copied into a different stream is refused.
- **Step 2 — payload.** The consumer re-hashes the payload. A mismatch with `payload_hash` means the payload changed. See [[Content Addressing]].
- **Step 3 — envelope.** The consumer re-hashes the unsigned envelope. A mismatch with `frame_hash` means something in the envelope changed. See [[The Wire]].
- **Step 4 — chain.** The frame must be a genesis, or link to the previous frame's particle, with time that does not go backward. Gaps, forks and wrong parents fail here.
- **Step 5 — wire discipline.** Swarm (`net:*`) streams must link `prev_wave`. Other streams must leave it null.
- **Step 6 — signature and authority.** A required signature must be present, bound to a registered key, within its tenure, and not revoked by a tombstone. See [[Trust and Signatures]] and [[The Registry]].

## A common failure outside the frame: the wrong space

Every rapp/1 hash belongs to a named **address space**.
A bare 64-hex digest has no meaning on its own.
Hashing the right bytes in the wrong space gives a different, non-matching address.

| Space | Function |
|---|---|
| `rapp/1:particle` | frame payload address |
| `rapp/1:wave` | unsigned frame-envelope address |
| `rapp/1:rappid` | identity tail |
| `rapp/1:egg` | packed file address inside an egg |
| `rapp/1:egg-manifest` | whole egg identity |
| `rapp/1:seal` | retired-head seal |

When a digest does not match, first ask: **in which space?**

## Related

- [[The Frame]]
- [[Conformance Classes]]
- [[Conformance and Drift]]
- [[Security Considerations]]
- [[Glossary]]

========================================================================
FILE: Reference/Glossary.md
========================================================================

---
title: Glossary
section: Reference
status: published
hook: What does each rapp/1 term mean, in plain words?
source: "book/B-glossary-and-failure-atlas.md §B.1, §B.2, §B.4; SPEC.md §3 Terminology"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Glossary

This is the **vocabulary of rapp/1** in one place.
Each term gets a short, plain definition.
The specification text stays authoritative; see [[Sources and Provenance]].

## Identity terms

- **rappid** — the permanent name of a running brainstem, object or door. Format: `rappid:@<owner>/<slug>:<64-lowercase-hex>`. The tail is minted once from UUIDv4 octets or a public key (SPKI DER), never from the owner/slug name. See [[Identity and the Rappid]].
- **identity** — continuity across changing content. In rapp/1, identity is the minted tail of a rappid, not the readable owner/slug.
- **provisional identity** — an older rappid whose tail is not 64 lowercase hex characters. It can be read but must not be emitted. Upgrading it requires owner-authorized re-anchoring.
- **re-anchor** — an owner-authorized identity change for exactly one allowed case: provisional upgrade, key rotation, key compromise, or pre-standard key-tag migration.
- **tombstone** — an owner-signed registry record that revokes a keyed rappid from `revoked_utc` forward.

## Data and hashing terms

- **canonical form** — the one RFC 8785 JCS byte representation of an admissible I-JSON value. See [[Canonicalization]].
- **I-JSON** — the interoperable JSON profile from RFC 7493 that canonicalization is built on.
- **JCS** — JSON Canonicalization Scheme, RFC 8785. It fixes member order, escaping, number form and whitespace.
- **legacy form** — any historical encoding that is not the current canonical form. Live legacy is drift and must be migrated. Sealed re-genesis history is kept as evidence, not as a second dialect.
- **content address** — a SHA-256 digest computed in a named rapp/1 domain. It changes if the content changes. See [[Content Addressing]].
- **domain separation** — prefixing hash input with an exact space tag and a newline, so the same bytes in different roles get different addresses.
- **address space** — a named domain in which a hash has meaning. rapp/1 stores and looks up by `(space, hash)`, never by a bare 64-hex string.

## Event terms

- **frame** — the closed eleven-field event envelope. It carries a payload particle, a whole-frame wave, chain links and an optional signature. See [[The Frame]].
- **particle** — `H("rapp/1:particle", payload)`, stored as `payload_hash`. It addresses what happened.
- **wave** — `H("rapp/1:wave", frame - {frame_hash, sig})`, stored as `frame_hash`. It addresses the exact unsigned envelope. See [[The Wire]].
- **stream** — an append-only sequence of frames sharing one `stream_id`.
- **biography stream** — a stream identified directly by a rappid. It chains particles through `prev`; `prev_wave` is null.
- **swarm stream** — a shared `net:*` stream. It chains particles through `prev` and waves through `prev_wave`, and every frame must be signed.
- **worldline** — the particle-linked history of a brainstem or stream.
- **genesis** — the sequence-zero frame the live chain descends from.
- **head** — the highest verified frame descending from the registered genesis. Consumers keep heads to detect rollback.
- **re-genesis** — the owner-authorized operation that seals an old chain, publishes a new sequence-zero frame, updates the registry and retires the old bytes under `legacy/`.
- **kind** — a registered `noun.verb` event name.

## Packaging and trust terms

- **egg** — a `rapp/1-egg` manifest plus, for tree variants, deterministic stored-ZIP contents. It packages a brainstem, rapplication, session, invite, neighborhood, estate, or sealed ciphertext artifact. See [[The Egg]].
- **registry** — the signed, append-only estate root of trust for keys, kinds, genesis records, re-anchors, tombstones, owner succession and canonical-source pointers. See [[The Registry]].
- **estate** — a governed collection of brainstems and neighborhoods sharing one registry and owner succession.
- **authorship** — the claim that a key signed an artifact. It needs a valid signature, and does not by itself prove the key was authorized. See [[Trust and Signatures]].
- **authority** — the right of a signer to decide at a given time. It comes from the registry and its owner-succession records.
- **integrity** — evidence that bytes or chain links have not changed. Integrity does not imply authorship.
- **freshness** — confidence that signed mutable state is recent enough. A valid registry signature proves authenticity, not freshness.
- **fail closed** — refuse, or report unknown, when evidence is missing, malformed, stale or unverifiable. Never turn "could not check" into a pass.

## Roles

- **producer** — emits only current canonical values, addresses, identities, frames and egg variants.
- **consumer** — validates frames, eggs, signatures, registry state and all refusal conditions before accepting input.
- **router/mirror** — transports or serves artifacts without inventing endpoints or rewriting addressed bytes.

See [[Conformance Classes]] for how these roles are tested.

## Runtime and release terms

- **Grail kernel** — an estate-declared, byte-pinned runtime. Its `grail_id` is `"grail:" || Hb("rapp/1:grail", kernel_bytes)`. Once activated, those bytes are permanent; capabilities grow outside them. See [[The Brainstem Kernel]].
- **release capsule** — the canonical `rapp-cicd/1-release` payload naming one immutable candidate. See [[RAPP CICD]].
- **serving lineage** — the sequence of release identities that have received user traffic.
- **deployment cell** — an independently observable and isolatable runtime failure domain, governed by `rapp-deploy/1`. See [[RAPP Deploy]].

## Address spaces

| Space | Function | Input |
|---|---|---|
| `rapp/1:particle` | frame payload address | canonical value via `H` |
| `rapp/1:wave` | unsigned frame-envelope address | canonical value via `H` |
| `rapp/1:rappid` | identity tail | UUID or SPKI octets via `Hb` |
| `rapp/1:egg` | packed file address inside an egg | raw octets via `Hb` |
| `rapp/1:egg-manifest` | whole egg identity | manifest without `sig` via `H` |
| `rapp/1:seal` | retired-head seal | exact retained head octets via `Hb` |

A bare digest should always prompt one question: **in which space?**

## Notation

| Notation | Meaning |
|---|---|
| `canonical(v)` | UTF-8 JCS serialization of admissible value `v` |
| `H(space, v)` | SHA-256 of `utf8(space) + 0x0A + canonical(v)` |
| `Hb(space, b)` | SHA-256 of `utf8(space) + 0x0A + raw octets b` |
| `x - {a,b}` | object `x` with exactly members `a` and `b` removed |
| `64hex` | exactly 64 lowercase hexadecimal characters |
| `uint53` | integer from 0 through 2^53−1 |
| SPKI DER | canonical DER encoding of a SubjectPublicKeyInfo public key |

## Related

- [[Failure Atlas]]
- [[Protocol at a Glance]]
- [[Content Addressing]]
- [[The Frame]]
- [[Identity and the Rappid]]
- [[Sources and Provenance]]

========================================================================
FILE: Reference/Sources and Provenance.md
========================================================================

---
title: Sources and Provenance
section: Reference
status: published
hook: Where does this vault's protocol content come from, and which text is authoritative?
source: "SPEC.md (whole document); book/ (whole book); NOTICE.md"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
---

# Sources and Provenance

The protocol notes in this vault are an **authored, plain-language expansion** of the upstream RAPP/1 specification.
They explain the specification. They do not replace it.
When a note and the specification differ, **the specification wins**.

## What the vault draws on

- **Protocol, Operations and Building notes** — expand the upstream RAPP/1 specification and its companion book.
- **Production Guide step notes** — expand the RAPP production guide in this repository, [the production guide](../rapp-guide.html).

Notes drawn only from the production guide carry no upstream pin.

## The pin

Every specification-derived note is pinned to one upstream commit:

`0b24e7d60786d39d97265338add9ca784bf5a7ab`

- The pin means the note was written against that exact version of the specification.
- Newer upstream versions do not change these notes until someone re-reviews them and moves the pin.

## How each note records its source

Every note starts with YAML frontmatter. Two fields carry provenance:

- `source` — the upstream file and section the note expands, for example `SPEC.md §7; book/05-the-frame.md`.
- `upstream_commit` — the pinned commit, for notes drawn from the specification.

Example:

```yaml
source: "SPEC.md §7; book/05-the-frame.md"
upstream_commit: 0b24e7d60786d39d97265338add9ca784bf5a7ab
```

## The build check

A build check reads every note's frontmatter.
**It fails if a specification-derived note loses its pin.**
This keeps every protocol claim traceable to a fixed source.

## The specification text is authoritative

- The vault paraphrases. It may simplify wording for readability.
- Normative rules (MUST, MUST NOT, exact formats) live in the specification.
- Exact identifiers — field names, wire tags such as `rapp/1`, hash space names, file names — are copied verbatim.

If you are implementing, read the specification section named in each note's `source` field.
Start with [[Implementing the Protocol]].

## License

The upstream RAPP/1 specification is MIT licensed.
Copyright (c) 2025-2026 Kody Wildfeuer.

The full upstream license notice is in [NOTICE](NOTICE.md).

## Related

- [[How to Use This Vault]]
- [[Protocol at a Glance]]
- [[Versioning and Evolution]]
- [[Conformance and Drift]]
- [[Glossary]]

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.