RAPP agent.py to Agent Skill — and back. The same pair works unchanged in
Copilot Studio, Cowork, Scout, and other SKILL.md-reading harnesses, giving
each of them RAPP agent.py compatibility. The Rapid Agent
Prototype Pattern: a capability is one Python file — one class, one typed
metadata contract, one perform() method — and every other shape is a
projection of it. This skill converts between the two shapes with zero
fidelity loss:
- agent — a RAPP single-file agent cartridge (
*_agent.py). The canonical form. - skill — an Agent Skill projection shipped as a pair: a
SKILL.mdwith the full Python embedded (plus anrci-capsule:v1:comment vaulting the byte-exact original, sha256-verified) and a linked python file beside it that literally is the agent.py. A host with sandbox execution — Copilot Studio becomes a first-party user of agent.py this way — runs the linked file directly; the SKILL.md alone remains self-sufficient if the linked file is missing. Converting back is a checksum-verified restore, never a re-render.
Everything routes through one deterministic engine. Do not improvise conversions, do not hand-edit formats, and do not paraphrase code — model-driven transformation is exactly the drift this skill exists to prevent.
Commands
Run from this skill's directory. Stdlib-only Python 3.9+, fully offline — no pip install, no network, no credentials.
python3 scripts/toast.py convert <path> --to skill -o out/SKILL.md # agent.py -> SKILL.md + linked agent
python3 scripts/toast.py convert <path> --to agent # SKILL.md -> agent.py
python3 scripts/toast.py roundtrip <path> # prove fidelity, exit 1 on drift
python3 scripts/toast.py inspect <path> # capsule status, identity, provenance
python3 scripts/toast.py selftest # prove every verdict can fire
Always pass -o with a path that is not an existing file you care about; the
tool refuses to overwrite its own source file or an existing target with
different bytes without --force. A byte-identical existing target is an
idempotent success. Never target this skill's own SKILL.md. Without -o,
output lands next to the source file (the tool prints the absolute path).
Exit codes: 0 = verified, 1 = drift or refusal (message says which), 2 =
RAW BREAD — a capsule-less SKILL.md has no byte-exact return trip yet;
convert it to an agent first, or pass --allow-raw to measure
capability-level fidelity only. Treat only exit 1 as drift.
The full lifecycle: the FIRST conversion of a hand-written SKILL.md creates a
runnable launchpad agent without inventing behavior. Instructions travel
verbatim; an explicit ## Parameters JSON-Schema fence supplies the typed
contract; a Python fence whose info string is
python # rapp:deterministic supplies implementation when present. Ordinary
example fences remain documentation. A prose-only skill remains prose-only in
the launchpad. Converting
that agent back embeds it literally inside a new SKILL.md — single-file
shareable — with the agent.py linked beside it, and it still maps back to the
identical agent.py. Both platforms are served by the same pair, and the Python
is preserved byte-exact at every hop.
Converting agent.py → Agent Skill
- Run
convert <file> --to skill -o <dir>/SKILL.md. Two things are emitted: the SKILL.md (frontmatter from the agent's own metadata, its docstring as instructions, a generated## ParametersJSON-Schema fence, a generated## Run this — do not improvisesection with the entire agent.py embedded verbatim, and the capsule comment) plus the linked agent file next to it — a byte-exact copy of the source. Ship both in the skill's bundle. - Immediately run
roundtrip <file>on the source agent. Report success only onIDENTICAL. OnDRIFT, report the two sha256 prefixes it prints and stop — never hand-patch the output to make it match. - The output says
SYNTHESISED(fresh projection) orRESTORED (byte-exact)(a vaulted original existed). Relay that word to the user — the two must never be confused.
Converting SKILL.md → agent.py
- Run
convert <file> --to agent.- If the SKILL.md carries a capsule, the agent is restored byte-exact (sha256-verified; a checksum mismatch aborts — never bypass it).
- If it is a plain hand-written SKILL.md (no capsule), a launchpad agent is
synthesised: instructions travel verbatim in
INSTRUCTIONS, typed parameters come from a## Parametersfence when present, and a fence whose info string ispython # rapp:deterministicis preserved as implementation when present. Ordinary Python examples are never executable. Otherwiseperform()returns the original instructions plus the supplied inputs; it does not infer commands from prose. Say so explicitly — a synthesis is a capability projection, not a restoration. A prose-only skill (no Parameters fence) synthesises an agent with an EMPTY parameter schema — the contract is untyped and nothing is validatable as required; tell the user so, and offer to add a## ParametersJSON-Schema fence to the source skill first if they want a typed contract.
- The emitted filename ends
_agent.py(snake_case) so RAPP Brainstem auto-discovery loads it unchanged. Contract details: references/rapp-agent-contract.md.
Verifying (mandatory before claiming success)
roundtripon an agent proves: agent → skill → agent returns the exact original bytes, and the projection is a fixed point over repeated cycles.roundtripon a converted SKILL.md proves: the vaulted agent restores checksum-verified, and the inline Python fence still matches it — editing inside the generated markers is detected as INLINE DRIFT, exit 1.- Behavioural fidelity is graded, never assumed: EXEC (host executed the
file — only claim after
python3 <file> --toolactually exits 0), CODE (the code travels in the fence), SPEC (typed contract only). Never report EXEC without having executed. - Try it end to end on the bundled sample:
python3 scripts/toast.py roundtrip assets/hello_rapp_agent.py
Host tiers for the emitted Agent Skill
- Copilot Studio / Cowork (sandbox execution): run the linked agent file
directly —
--toolfor the contract, one JSON object for arguments; if the linked file is missing, materialize it verbatim from the fence first. Treat stdout as a tool result: collect missing inputs, execute returnedstepsin order, follow returnedinstructions, or otherwise use the result verbatim. This earns the EXEC tier and makes the host a first-party user of the agent.py itself. - Scout and other instruction-driven hosts (no sanctioned script execution today): the same SKILL.md still works — treat the Parameters schema and the fenced code as the exact specification and never paraphrase a step (CODE tier). When the host later gains a sanctioned execution path, the identical file upgrades to EXEC. The file does not change — that is the promotion, not a port.
Talking to a live RAPP entity
When a running RAPP brainstem is available, everything rides one wire: POST /chat. Follow references/rapp1-protocol.md
exactly — the response field is response (never assistant_response), keep
the returned session_id for continuity, and never invent sibling REST
routes. Dropping a converted *_agent.py into the brainstem's agents/
directory hot-loads it with no restart.
Guardrails
- Never edit content between
<!-- toaster:generated:begin -->and<!-- toaster:generated:end -->, and never strip or truncate anrci-capsule:v1:comment — that is the byte-exact original. - Never import or execute an agent file in order to read it; the converter
parses with
astonly. Executing the agent is a separate, user-visible step. - Report unconvertible files with the reason; never silently skip or "fix" them.
- Sandbox files do not persist across conversations: return or save the converted artifacts in the same turn you produce them.
- The converter carries identity through; it never mints identity from content.
Run this — do not improvise
This capability's deterministic implementation is a RAPP single-file agent, linked beside this file as rapp_agent_converter_agent.py and embedded as the fenced Python below (sha256 3b70de75d3c7d502…; a byte-exact copy is also vaulted in the capsule comment at the end of this file). On a host with sandbox execution, run the linked file directly — if it is missing, write the fence contents verbatim to rapp_agent_converter_agent.py first:
python3 rapp_agent_converter_agent.py '{"key": "value"}' # arguments as one JSON object
echo '{"key": "value"}' | python3 rapp_agent_converter_agent.py # or on stdin
python3 rapp_agent_converter_agent.py --tool # emit the JSON tool contract
Treat stdout as a tool result. If it reports missing or unresolved inputs, stop and collect them. If it returns steps, execute those steps in order exactly as returned; if it returns instructions, follow them with the supplied inputs. Otherwise use the result verbatim. Do not invent behavior beyond that output. On a host without code execution, treat the Parameters schema and the code below as the exact specification and never paraphrase a step. Never edit inside the generated markers; a converter-equipped host can instead restore the original file checksum-verified with the installed rapp-agent-converter/scripts/toast.py convert SKILL.md --to agent.
"""RappAgentConverter -- Use this skill whenever the user works with RAPP single-file agents (the Rapid Agent Prototype Pattern): converting an agent.py cartridge into a Copilot Studio / Cowork / Scout Agent Skill, converting a SKILL.md back into a runnable agent.py, bringing a RAPP-built agent into Copilot Studio, verifying such a conversion lost nothing, or talking to a live RAPP brainstem over its /chat endpoint. Always run the bundled deterministic converter instead of transforming the files by hand.
Generated by the rapp skill from rapp-agent-converter. The RCI capsule at the bottom of this file carries the full original; `toast.py convert` restores it byte-exact."""
import json
import re
import sys
try:
from agents.basic_agent import BasicAgent
except ImportError: # running OUTSIDE a brainstem -- stay executable anyway.
class BasicAgent: # noqa: D101 - minimal stand-in, same contract
def __init__(self, name=None, metadata=None):
if name:
self.name = name
if metadata:
self.metadata = metadata
def perform(self, **kwargs):
return "Not implemented."
def system_context(self):
return None
def to_tool(self):
return {"type": "function", "function": {
"name": self.name,
"description": self.metadata.get("description", ""),
"parameters": self.metadata.get("parameters", {})}}
# The procedural layer, verbatim from the source capability.
INSTRUCTIONS = 'RAPP `agent.py` to Agent Skill — and back. The same pair works unchanged in\nCopilot Studio, Cowork, Scout, and other SKILL.md-reading harnesses, giving\neach of them RAPP agent.py compatibility. The Rapid Agent\nPrototype Pattern: a capability is **one Python file** — one class, one typed\n`metadata` contract, one `perform()` method — and every other shape is a\nprojection of it. This skill converts between the two shapes with zero\nfidelity loss:\n\n- **agent** — a RAPP single-file agent cartridge (`*_agent.py`). The canonical\n form.\n- **skill** — an Agent Skill projection shipped as a **pair**: a `SKILL.md`\n with the full Python embedded (plus an `rci-capsule:v1:` comment vaulting the\n byte-exact original, sha256-verified) and a **linked python file beside it\n that literally is the agent.py**. A host with sandbox execution — Copilot\n Studio becomes a first-party user of agent.py this way — runs the linked\n file directly; the SKILL.md alone remains self-sufficient if the linked file\n is missing. Converting back is a checksum-verified restore, never a\n re-render.\n\nEverything routes through one deterministic engine. Do not improvise\nconversions, do not hand-edit formats, and do not paraphrase code — model-driven\ntransformation is exactly the drift this skill exists to prevent.\n\n## Commands\n\nRun from this skill's directory. Stdlib-only Python 3.9+, fully offline — no\npip install, no network, no credentials.\n\n```bash\npython3 scripts/toast.py convert <path> --to skill -o out/SKILL.md # agent.py -> SKILL.md + linked agent\npython3 scripts/toast.py convert <path> --to agent # SKILL.md -> agent.py\npython3 scripts/toast.py roundtrip <path> # prove fidelity, exit 1 on drift\npython3 scripts/toast.py inspect <path> # capsule status, identity, provenance\npython3 scripts/toast.py selftest # prove every verdict can fire\n```\n\nAlways pass `-o` with a path that is not an existing file you care about; the\ntool refuses to overwrite its own source file or an existing target with\ndifferent bytes without `--force`. A byte-identical existing target is an\nidempotent success. Never target this skill's own `SKILL.md`. Without `-o`,\noutput lands next to the source file (the tool prints the absolute path).\n\nExit codes: 0 = verified, 1 = drift or refusal (message says which), 2 =\n`RAW BREAD` — a capsule-less SKILL.md has no byte-exact return trip yet;\nconvert it to an agent first, or pass `--allow-raw` to measure\ncapability-level fidelity only. Treat only exit 1 as drift.\n\nThe full lifecycle: the FIRST conversion of a hand-written SKILL.md creates a\nrunnable launchpad agent without inventing behavior. Instructions travel\nverbatim; an explicit `## Parameters` JSON-Schema fence supplies the typed\ncontract; a Python fence whose info string is\n`python # rapp:deterministic` supplies implementation when present. Ordinary\nexample fences remain documentation. A prose-only skill remains prose-only in\nthe launchpad. Converting\nthat agent back embeds it literally inside a new SKILL.md — single-file\nshareable — with the agent.py linked beside it, and it still maps back to the\nidentical agent.py. Both platforms are served by the same pair, and the Python\nis preserved byte-exact at every hop.\n\n## Converting agent.py → Agent Skill\n\n1. Run `convert <file> --to skill -o <dir>/SKILL.md`. Two things are emitted:\n the SKILL.md (frontmatter from the agent's own metadata, its docstring as\n instructions, a generated `## Parameters` JSON-Schema fence, a generated\n `## Run this — do not improvise` section with the **entire agent.py\n embedded verbatim**, and the capsule comment) plus the **linked agent\n file** next to it — a byte-exact copy of the source. Ship both in the\n skill's bundle.\n2. Immediately run `roundtrip <file>` on the source agent. Report success only\n on `IDENTICAL`. On `DRIFT`, report the two sha256 prefixes it prints and\n stop — never hand-patch the output to make it match.\n3. The output says `SYNTHESISED` (fresh projection) or `RESTORED (byte-exact)`\n (a vaulted original existed). Relay that word to the user — the two must\n never be confused.\n\n## Converting SKILL.md → agent.py\n\n1. Run `convert <file> --to agent`.\n - If the SKILL.md carries a capsule, the agent is **restored byte-exact**\n (sha256-verified; a checksum mismatch aborts — never bypass it).\n - If it is a plain hand-written SKILL.md (no capsule), a launchpad agent is\n **synthesised**: instructions travel verbatim in `INSTRUCTIONS`, typed\n parameters come from a `## Parameters` fence when present, and a fence\n whose info string is `python # rapp:deterministic` is preserved as\n implementation when present. Ordinary Python examples are never\n executable. Otherwise\n `perform()` returns the original instructions plus the supplied inputs;\n it does not infer commands from prose. Say so explicitly — a synthesis is\n a capability projection, not a restoration. A prose-only skill (no\n Parameters fence) synthesises an agent with an EMPTY parameter schema —\n the contract is untyped and nothing is validatable as required; tell the\n user so, and offer to add a `## Parameters` JSON-Schema fence to the source\n skill first if they want a typed contract.\n2. The emitted filename ends `_agent.py` (snake_case) so RAPP Brainstem\n auto-discovery loads it unchanged. Contract details:\n [references/rapp-agent-contract.md](references/rapp-agent-contract.md).\n\n## Verifying (mandatory before claiming success)\n\n- `roundtrip` on an agent proves: agent → skill → agent returns the exact\n original bytes, and the projection is a fixed point over repeated cycles.\n- `roundtrip` on a converted SKILL.md proves: the vaulted agent restores\n checksum-verified, and the inline Python fence still matches it — editing\n inside the generated markers is detected as INLINE DRIFT, exit 1.\n- Behavioural fidelity is graded, never assumed: **EXEC** (host executed the\n file — only claim after `python3 <file> --tool` actually exits 0), **CODE**\n (the code travels in the fence), **SPEC** (typed contract only). Never report\n EXEC without having executed.\n- Try it end to end on the bundled sample:\n `python3 scripts/toast.py roundtrip assets/hello_rapp_agent.py`\n\n## Host tiers for the emitted Agent Skill\n\n- **Copilot Studio / Cowork** (sandbox execution): run the linked agent file\n directly — `--tool` for the contract, one JSON object for arguments; if the\n linked file is missing, materialize it verbatim from the fence first. Treat\n stdout as a tool result: collect missing inputs, execute returned `steps` in\n order, follow returned `instructions`, or otherwise use the result verbatim.\n This earns the EXEC tier and makes the host a first-party user of the\n agent.py itself.\n- **Scout** and other instruction-driven hosts (no sanctioned script execution\n today): the same SKILL.md still works — treat the Parameters schema and the\n fenced code as the exact specification and never paraphrase a step (CODE\n tier). When the host later gains a sanctioned execution path, the identical\n file upgrades to EXEC. The file does not change — that is the promotion, not\n a port.\n\n## Talking to a live RAPP entity\n\nWhen a running RAPP brainstem is available, everything rides one wire: `POST\n/chat`. Follow [references/rapp1-protocol.md](references/rapp1-protocol.md)\nexactly — the response field is `response` (never `assistant_response`), keep\nthe returned `session_id` for continuity, and never invent sibling REST\nroutes. Dropping a converted `*_agent.py` into the brainstem's `agents/`\ndirectory hot-loads it with no restart.\n\n## Guardrails\n\n- Never edit content between `<!-- toaster:generated:begin -->` and\n `<!-- toaster:generated:end -->`, and never strip or truncate an\n `rci-capsule:v1:` comment — that is the byte-exact original.\n- Never import or execute an agent file in order to read it; the converter\n parses with `ast` only. Executing the agent is a separate, user-visible step.\n- Report unconvertible files with the reason; never silently skip or "fix" them.\n- Sandbox files do not persist across conversations: return or save the\n converted artifacts in the same turn you produce them.\n- The converter carries identity through; it never mints identity from content.'
# Ordered commands lifted verbatim from the capability's own documentation.
STEPS = []
class RappAgentConverterAgent(BasicAgent):
def __init__(self):
self.name = 'RappAgentConverter'
self.metadata = {
"name": "RappAgentConverter",
"description": "Use this skill whenever the user works with RAPP single-file agents (the Rapid Agent Prototype Pattern): converting an agent.py cartridge into a Copilot Studio / Cowork / Scout Agent Skill, converting a SKILL.md back into a runnable agent.py, bringing a RAPP-built agent into Copilot Studio, verifying such a conversion lost nothing, or talking to a live RAPP brainstem over its /chat endpoint. Always run the bundled deterministic converter instead of transforming the files by hand.",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
super().__init__(name=self.name, metadata=self.metadata)
def perform(self, **kwargs): # toaster:generated-perform
return json.dumps({"status": "ok", "instructions": INSTRUCTIONS,
"inputs": kwargs,
"note": "Prose-only capability: follow INSTRUCTIONS "
"with the given inputs."}, indent=2)
if __name__ == "__main__":
# echo '{"arg": "value"}' | python3 rapp_agent_converter_agent.py
# python3 rapp_agent_converter_agent.py '{"arg": "value"}'
# python3 rapp_agent_converter_agent.py --tool # emit the JSON tool contract
_a = sys.argv[1:]
if _a and _a[0] == "--tool":
print(json.dumps(RappAgentConverterAgent().to_tool(), indent=2))
else:
_raw = _a[0] if _a else (sys.stdin.read().strip() or "{}")
print(RappAgentConverterAgent().perform(**json.loads(_raw)))
# rci-capsule:v1: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