Add new skill: RAPP Agent Converter - #279
Conversation
Bring RAPP single-file agents (agent.py, the Rapid Agent Prototype Pattern) into Microsoft Copilot Studio and back with zero fidelity loss. The emitted projection is a pair: a SKILL.md carrying the complete Python inline plus an rci-capsule comment vaulting the byte-exact original (sha256-verified restore, never a re-render), and a linked python file beside it that literally is the agent.py -- so execution hosts run the real implementation first-party. Implements rapp-capability-interchange/1.0 for the agent<->skill pair, interoperable with the reference toaster, with a rapp/1 /chat wire reference for talking to live RAPP entities. Verified: selftest proves every verdict fires (match, checksum refusal, inline-tamper drift, raw-bread refusal, edit-honored); 29 real agents round-trip byte-identical; three existing gallery skills complete the raw SKILL.md -> agent.py -> SKILL.md+linked-agent -> agent.py chain with the Python preserved byte-exact; cross-tool restore against the upstream toaster is byte-identical in both directions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The old name was one-directional and Copilot Studio specific, but the skill is bidirectional and host-agnostic: its own metadata targets Cowork, Copilot Studio and Scout, and the SKILL.md states it works with any host that consumes SKILL.md. "MCS" also appears nowhere else in the gallery, where the convention is copilot-studio-*, and 80 of 82 submissions use lowercase-hyphenated slugs. Keeps "rapp" because that is the activation trigger for the audience that has agent.py cartridges, and matches the existing doc-format-converter naming precedent. Updates the folder, SKILL.md frontmatter name, metadata display name and description, and the README heading and cd line. No payload changes: selftest still passes and the bundled sample still round-trips byte-identical. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new submission skill, RAPP Agent Converter, to the gallery under submissions/rapp-agent-converter/. The skill provides an offline, stdlib-only Python tool and accompanying documentation to convert between RAPP single-file agents (*_agent.py) and gallery Agent Skills (SKILL.md), including capsule-based byte-exact restoration.
Changes:
- Introduces a new skill (
SKILL.md) plus human-facing overview (README.md) and submission metadata (metadata.json). - Adds the deterministic converter implementation (
scripts/toast.py) and reference docs for the RAPP contract/protocol. - Adds a sample RAPP agent cartridge (
assets/hello_rapp_agent.py) for round-trip verification and demos.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| submissions/rapp-agent-converter/SKILL.md | Agent-facing operational instructions for running conversions/verification and interacting with a live RAPP brainstem. |
| submissions/rapp-agent-converter/scripts/toast.py | Stdlib-only converter implementation handling capsule pack/unpack, agent/skill parsing, projection, and selftests. |
| submissions/rapp-agent-converter/references/rapp1-protocol.md | Reference for the /chat wire protocol and interop rules when talking to a live RAPP entity. |
| submissions/rapp-agent-converter/references/rapp-agent-contract.md | Reference contract for RAPP single-file agents (structure, loader gates, portability shim). |
| submissions/rapp-agent-converter/README.md | Human-facing skill overview, rationale, and quick-start instructions for gallery viewers. |
| submissions/rapp-agent-converter/metadata.json | Submission metadata (name/description/platforms/tags/author/version/dates). |
| submissions/rapp-agent-converter/assets/hello_rapp_agent.py | Sample minimal RAPP agent cartridge used for demos and conversion round-trip checks. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| rci["name"] = name if isinstance(name, str) else cls.name | ||
| rci["slug"] = _kebab(manifest.get("display_name") or "") or rci.get("slug") \ | ||
| or _kebab(rci["name"]) |
| perform = (" def perform(self, **kwargs):\n" | ||
| + textwrap.indent(impl["perform_body"], " ")) | ||
| else: | ||
| perform = DEFAULT_PERFORM |
| 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 |
Agents without __manifest__.display_name were projected with the literal slug
"capability" because _kebab("") returns that fallback before the converter
could use the capsule slug or agent name. Only call _kebab when display_name
is present, then fall through to the carried slug and tool name.
Add the no-display-name case to selftest so the gallery submission itself
owns the regression. Also remove the remaining Copilot-Studio-first opening
from the human and agent instructions; the pair targets every Agent Skill
host and Copilot Studio is one execution surface, not the format boundary.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (5)
submissions/rapp-agent-converter/SKILL.md:45
- The skill targets Scout (cross-OS), but the command examples assume a Unix-like environment (
bash) and apython3launcher, which won’t work on many Windows machines. Please either add a Windows launcher note (e.g.,py -3/python) or make the command block OS-agnostic so the documented workflow matches the supported platforms.
```bash
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
submissions/rapp-agent-converter/scripts/toast.py:390
read_skill()decodes markdown witherrors='replace', which can mask invalid UTF‑8 and make capsule detection / content parsing behave unpredictably. Since SKILL.md content must be UTF‑8 in practice, failing fast on decode errors avoids producing “successful” conversions from corrupted input.
def read_skill(raw: bytes, filename: str) -> dict:
text = raw.decode("utf-8", "replace")
got = _capsule_or_reparse(raw, filename, "skill")
cap = got[1] if got and got[0] == "ok" else None
rci = cap if cap else (got[1] if got else blank_rci())
submissions/rapp-agent-converter/scripts/toast.py:505
- The generated “Run this” section hardcodes
python3, but the submission claims Scout support (cross-OS) and Windows often won’t have apython3launcher. Consider making the generated snippet OS-agnostic or adding a short Windows launcher note so the emitted skill text doesn’t instruct users to run a command that may not exist.
"```bash\n"
f"python3 {fn} '{{\"key\": \"value\"}}' # arguments as one JSON object\n"
f"echo '{{\"key\": \"value\"}}' | python3 {fn} # or on stdin\n"
f"python3 {fn} --tool # emit the JSON tool contract\n"
"```\n\n"
submissions/rapp-agent-converter/scripts/toast.py:241
read_agent()decodes source witherrors='replace', which can silently corrupt non‑UTF‑8 Python files (or files using a PEP 263 encoding) and undermine the “byte-identical” guarantees (e.g., a corrupted projection could still round-trip via the capsule while the visible embedded code differs). It’s safer to require UTF‑8 input (fail fast) or implement proper PEP 263 decoding and refuse encodings that cannot be represented losslessly in UTF‑8 markdown.
This issue also appears on line 386 of the same file.
def read_agent(raw: bytes, filename: str) -> dict:
text = raw.decode("utf-8", "replace").lstrip("\ufeff")
got = _capsule_or_reparse(raw, filename, "agent")
cap = got[1] if got and got[0] == "ok" else None
rci = cap if cap else (got[1] if got else blank_rci())
submissions/rapp-agent-converter/README.md:64
- The quickstart example uses
/tmpand assumes apython3launcher. Since this submission claims Scout support (cross-OS), adding a brief Windows launcher note and using a relative output path would prevent the README quickstart from failing on Windows.
cd rapp-agent-converter
python3 scripts/toast.py selftest # every verdict fires
python3 scripts/toast.py convert assets/hello_rapp_agent.py --to skill -o /tmp/SKILL.md
python3 scripts/toast.py roundtrip assets/hello_rapp_agent.py # IDENTICAL, or exit 1
python3 assets/hello_rapp_agent.py '{"person": "Ada"}' # the cartridge itself runs anywhere
Make generated skills fail closed: malformed capsules, missing generated regions, multiple deterministic fences, and inline Python edits now refuse on all reads, including convert and inspect. The inline check is structural and cannot be disabled by rewording prose or confused by an authored example fence. Make the oracle real in every mode. Agent fixed-point cycles now cross both formats instead of restoring the same skill bytes, and --allow-raw performs a skill->agent->skill->agent stability proof before returning success. Restore the vaulted filename by default, accept byte-identical existing targets idempotently, generate valid classes for numeric-leading skill names, preserve standard Agent Skill permission frontmatter, and keep author/version/tags under metadata instead of unsupported top-level fields. Clarify raw-skill synthesis: instructions and explicit contracts travel, but the converter never invents ordered commands from prose. Generated host instructions now treat planner output as a tool result and execute returned steps rather than presenting a plan as completed work. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
submissions/rapp-agent-converter/SKILL.md:46
- The skill targets Scout (cross-OS), but the command examples hardcode
python3, which commonly fails on Windows (python/py -3are typical). This makes the documented execution steps non-portable for one of the declared platforms; adjust the examples to be cross-platform (or explicitly branch by OS).
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
submissions/rapp-agent-converter/scripts/toast.py:110
restore()assumes the capsule’s preserved entry is well-formed; malformed/malicious capsules can currently raiseKeyError/binascii.Error/OSErrorand bubble up as an uncaught exception (traceback) instead of a clean[FAIL] ...message. Treat decode/decompress/key errors as aValueErrorso callers reliably get a controlled failure mode.
def restore(rci: dict, fmt: str):
p = rci.get("preserved", {}).get(fmt)
if not p:
return None
raw = gzip.decompress(base64.b64decode(p["b64"]))
submissions/rapp-agent-converter/README.md:66
- README command examples also hardcode
python3, which is not reliably available on Windows (a supported Scout host). Updating these examples (or branching by OS) will make the quickstart runnable on all declared platforms.
cd rapp-agent-converter
python3 scripts/toast.py selftest # every verdict fires
python3 scripts/toast.py convert assets/hello_rapp_agent.py --to skill -o /tmp/SKILL.md
python3 scripts/toast.py roundtrip assets/hello_rapp_agent.py # IDENTICAL, or exit 1
python3 assets/hello_rapp_agent.py '{"person": "Ada"}' # the cartridge itself runs anywhere
| def linked_agent_name(rci: dict) -> str: | ||
| """The sidecar name the projection links to — the vaulted original's own | ||
| filename when known, so the link and the restore always agree.""" | ||
| return ((rci.get("preserved", {}).get("agent") or {}).get("filename") | ||
| or agent_filename(rci)) |
Fail closed on the complete generated projection, not only the Python fence: read_skill now regenerates and byte-compares commands, parameters, prose, and code against the checksum-verified agent. Capsule comments are parsed only in their defined HTML/Python forms and decoded values must be valid RCI objects. Reject capsule-controlled path traversal, non-UTF-8 source that cannot be embedded byte-exact, ordinary example fences masquerading as implementation, and malformed generated artifacts. Parse and preserve standard block-form YAML metadata and permissions. Preflight both files in the Agent Skill pair before writing, so a conflicting linked agent cannot leave a broken SKILL.md behind. Normalize the gzip OS header and pin a known compressed-byte fixture; projections are now byte-identical on Python 3.11, 3.13, and 3.14. Expand selftest to cover all regressions, including generated command tampering, capsule shape, path traversal, metadata, raw prose examples, numeric slugs, and non-UTF-8 refusal. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (3)
submissions/rapp-agent-converter/SKILL.md:122
- These verification examples also hard-code
python3, which isn’t consistently available on Windows (Scout can run on any OS). Consider usingpythonin the documented invocation (and optionally mentionpython3/py -3depending on OS) so the guidance matches the stated cross-OS target.
file — only claim after `python3 <file> --tool` actually 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`
submissions/rapp-agent-converter/SKILL.md:47
- The command examples assume a Bash-like shell and the
python3launcher. Since this skill targets Scout (cross-OS) too, these commands are not reliably runnable on Windows (wherepython3is often absent and shell quoting differs). Prefer OS-agnostic examples (e.g.,pythonwith a note aboutpy -3on Windows) and avoid implying Bash by using a non-shell-specific fence.
This issue also appears on line 118 of the same file.
```bash
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
submissions/rapp-agent-converter/scripts/toast.py:716
- The generated “Run this” section emits a
bashfence, usespython3, and includes anecho ... | ...pipeline. For Scout’s cross-OS environment you can’t assume Bash,python3, or POSIX quoting/pipes. Consider emitting a non-shell-specific fence (e.g.,text), usingpython, and showing stdin redirection from a file instead of a pipe.
"```bash\n"
f"python3 {fn} '{{\"key\": \"value\"}}' # arguments as one JSON object\n"
f"echo '{{\"key\": \"value\"}}' | python3 {fn} # or on stdin\n"
f"python3 {fn} --tool # emit the JSON tool contract\n"
"```\n\n"
Reject generated regions hidden inside Markdown fences or comments, conflicting or invalid parameter schemas, aliased pair destinations, and malformed RCI field types before rendering. The capsule validator now covers every consumed field and the tool contract must be a JSON-Schema object. Parse nested YAML block scalars as well as maps and lists, while treating only explicit `python # rapp:deterministic` fences as implementation. Capsule syntax is recognized only in defined HTML/Python comment forms, so prose can document it safely. The regression suite now covers hidden generated content, block metadata and scalars, conflicting schemas, invalid RCI shapes, pair path collisions, path traversal, non-UTF-8 source, cross-version gzip bytes, and ordinary Python examples. The real CAT block-scalar fixture and Python 3.11/3.13/3.14 all pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Require platform.metadata and platform.claude to be objects and validate the rendered permission fields before write_skill consumes them. This closes the last type-confusion path in the RCI record and adds it to selftest. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (2)
submissions/rapp-agent-converter/SKILL.md:46
- These command examples assume a POSIX shell and
python3, but the skill targets Scout as well (cross-OS). On Windows/Scout,python3and the surrounding quoting/piping aren’t reliable; prefer apython-based invocation (or provide OS-specific alternatives) so the documented commands work on all advertised platforms.
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
submissions/rapp-agent-converter/scripts/toast.py:825
- The generated “Run this” section hardcodes
python3and uses shell-specific JSON quoting/piping. Since this skill claims Scout support (cross-OS, unknown shell), the generated instructions should avoid assumingpython3or any particular quoting rules; otherwise the emitted SKILL.md guidance will fail on common Windows shells.
try:
code = source.decode("utf-8")
except UnicodeDecodeError as exc:
raise ValueError(
"vaulted agent must be UTF-8 for an Agent Skill projection"
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (2)
submissions/rapp-agent-converter/scripts/toast.py:629
split_frontmatter()only matches YAML frontmatter when it uses LF (\n). A SKILL.md checked out or authored with CRLF line endings will be treated as having no frontmatter, which can change the derived slug/metadata and break round-trips on Windows.
def split_frontmatter(text: str):
m = re.match(r"---\s*\n(.*?)\n---\s*\n?(.*)$", text, re.S)
if not m:
return {}, text
fm, body = {}, m.group(2)
submissions/rapp-agent-converter/scripts/toast.py:64
- Several core regexes assume LF-only newlines (e.g.,
\nliterals and EOL anchors without allowing a preceding\r). On Windows/CRLF files this can prevent capsule detection and generated-block matching, causing false drift/refusals or missed capsules despite byte-identical content.
This issue also appears on line 625 of the same file.
)
GENERATED_BEGIN = "<!-- toaster:generated:begin -->"
GENERATED_END = "<!-- toaster:generated:end -->"
GENERATED_BLOCK_RE = re.compile(
r"^<!-- toaster:generated:begin -->[ \t]*\n"
Recognize generated markers only when they occupy their reserved top-level comment lines. This lets the converter skill document its own marker syntax without being mistaken for a damaged generated projection, while preserving the fail-closed behavior for real marker blocks. Add the self-hosting case to selftest and prove the converter SKILL.md can be synthesized into its own RAPP launchpad agent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Some valid gallery skills end with an unclosed authored code fence. Appending the generated pair contract would hide it inside that fence and correctly fail verification. When authored Markdown leaves a fence or HTML comment open, emit the generated contract before the authored body instead, preserving the source instructions while keeping the linked-agent contract top-level and active. Add an open-fence self-hosting regression to the cross-version selftest. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (4)
submissions/rapp-agent-converter/SKILL.md:39
- The command examples assume the
python3launcher exists, but this skill targets Scout where users may run on Windows (oftenpython/py -3instead). Adding a short Windows note here would prevent the “Commands” section from being misleading on that platform.
Run from this skill's directory. Stdlib-only Python 3.9+, fully offline — no
pip install, no network, no credentials.
submissions/rapp-agent-converter/SKILL.md:58
- The exit-code documentation says code 2 only means
RAW BREAD, buttoast.py roundtripalso returns 2 when a skill has a capsule but no vaulted agent (byte-level roundtrip still unavailable). Please document that exit 2 covers both cases to avoid consumers misclassifying failures.
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.
submissions/rapp-agent-converter/scripts/toast.py:849
- The generated “Run this” snippet is labeled as
bashand relies on POSIX-style quoting/pipes (single quotes,echo |). Since the skill claims to target Scout (cross-OS), it would be safer to emit a shell-neutral snippet and demonstrate stdin redirection (works in more shells) plus a Windowspythonfallback.
)
if params.get("properties") and not authored_params:
generated += [f"\n{GENERATED_BEGIN}\n"
"\n## Parameters\n\nThe typed contract this capability "
"answers to (JSON Schema — the deterministic layer):\n\n"
submissions/rapp-agent-converter/README.md:67
- The “Try it” commands use POSIX single-quote JSON (
'{'...'}'), which won’t work in common Windows shells. Since this submission targets Scout, consider switching the example to stdin redirection (shell-agnostic) and noting the Windowspythonlauncher as needed.
cd rapp-agent-converter
python3 scripts/toast.py selftest # every verdict fires
python3 scripts/toast.py convert assets/hello_rapp_agent.py --to skill -o /tmp/SKILL.md
python3 scripts/toast.py roundtrip assets/hello_rapp_agent.py # IDENTICAL, or exit 1
python3 assets/hello_rapp_agent.py '{"person": "Ada"}' # the cartridge itself runs anywhere
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (5)
submissions/rapp-agent-converter/scripts/toast.py:250
unpack_capsule()gzip-decompresses the capsule JSON with no size limit. Because the capsule may come from user-provided SKILL.md/agent.py files, this allows decompression bombs that can exhaust memory/CPU during inspection, conversion, or roundtrip checks. Add a maximum decompressed size (and ideally a cap on the base64 payload length) before parsing JSON.
if not re.fullmatch(r"[A-Za-z0-9+/=]+", payload):
raise ValueError("malformed rci-capsule:v1 payload")
try:
decoded = json.loads(gzip.decompress(base64.b64decode(payload)))
except Exception as exc:
submissions/rapp-agent-converter/SKILL.md:42
- The command examples assume a POSIX shell (
bash) and apython3launcher. Since this submission targets Scout (cross-OS), these defaults will fail on common Windows setups (nopython3, different shell semantics). Use a shell-agnostic fence and a launcher placeholder (orpython/py -3guidance) so the steps remain runnable across supported platforms.
Run from this skill's directory. Stdlib-only Python 3.9+, fully offline — no
pip install, no network, no credentials.
```bash
python3 scripts/toast.py convert <path> --to skill -o out/SKILL.md # agent.py -> SKILL.md + linked agent
submissions/rapp-agent-converter/scripts/toast.py:125
restore()base64-decodes and gzip-decompresses untrusted capsule content with no size limit. A crafted capsule can cause memory/CPU exhaustion (decompression bomb) when converting or round-tripping, which is a realistic risk in sandboxed hosts. Add a maximum decompressed size and fail fast if exceeded.
This issue also appears on line 246 of the same file.
def restore(rci: dict, fmt: str):
p = rci.get("preserved", {}).get(fmt)
if not p:
return None
raw = gzip.decompress(base64.b64decode(p["b64"]))
if _sha(raw) != p["sha256"]:
raise ValueError(f"preserved {fmt} payload failed its checksum")
return raw
submissions/rapp-agent-converter/scripts/toast.py:880
- The generated "Run this" section bakes in a POSIX shell pipeline (
echo ... |) and apython3launcher. Since the emitted projection is described as working for Scout (cross-OS), the generated instructions should avoid assuming a particular shell/launcher. Using a neutral fence and a<python>placeholder keeps the emitted SKILL.md portable.
"```bash\n"
f"python3 {fn} '{{\"key\": \"value\"}}' # arguments as one JSON object\n"
f"echo '{{\"key\": \"value\"}}' | python3 {fn} # or on stdin\n"
f"python3 {fn} --tool # emit the JSON tool contract\n"
"```\n\n"
submissions/rapp-agent-converter/README.md:68
- The quickstart snippet is POSIX-specific (
cd ...and/tmp/...) and usespython3, which makes it misleading for Windows users even though the submission targets Scout (cross-OS). Consider using a relative output path and a launcher placeholder so the quickstart works across supported platforms.
```bash
cd rapp-agent-converter
python3 scripts/toast.py selftest # every verdict fires
python3 scripts/toast.py convert assets/hello_rapp_agent.py --to skill -o /tmp/SKILL.md
python3 scripts/toast.py roundtrip assets/hello_rapp_agent.py # IDENTICAL, or exit 1
What this adds
submissions/rapp-agent-converter/— a skill that converts RAPP single-fileagents (
agent.py) into Agent Skills and back, with byte-identical roundtrips in both directions.
The emitted projection is a pair: a
SKILL.mdcarrying the complete Pythoninline plus an
rci-capsule:v1:comment vaulting the byte-exact original(sha256-verified restore, never a re-render), and a linked
.pybeside it thatliterally is the
agent.py— so execution hosts run the real implementationfirst-party.
Targets Cowork, Copilot Studio, and Scout. The converter is stdlib-only
Python 3.9+, fully offline: no pip install, no network, no credentials.
Verification
selftestproves every verdict fires: match, checksum refusal, inline-tamperdrift, raw-bread refusal, edit-honored
plus the bundled sample). A base-class file is correctly refused with a
reason rather than silently converted
SKILL.md -> agent.py -> SKILL.md + linked agent -> agent.pychain with thePython preserved byte-exact
--toolexits 0,invocation with one JSON object returns success, and with the linked file
deleted the agent is materialized from the fence byte-identical
(sha256
4a42921a9bffbbe3) and still executesagents/directory loaded with no restart and executed first-partySKILL.mdis byte-identical to the authored one, and still restores the original
agent.pybyte-exactnpm run check:submissionspasses (all submissions),npm testpasses, andnpm run buildcompletes.Notes for reviewers
submissions/rapp-agent-converter/**is touched — no site orinfrastructure changes, and no generated artifacts committed by hand
RAPPtoMCS: the oldname was one-directional and Copilot Studio specific, while the skill is
bidirectional and host-agnostic.
MCSalso appears nowhere else in thegallery, where the convention is
copilot-studio-*