/reborn-extension-surfaces
Use when adding or changing a Reborn integration — a new extension, a channel surface, model-callable tools, or a shared auth provider — or when deciding whether something is "a channel", "an extension", or "a tool". Maps the unified extension model (NEA-25) to the exact
$ npx -y skills add nearai/ironclaw --skill reborn-extension-surfaces --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/reborn-extension-surfaces
Context preview
The summary Claude sees to decide when to auto-load this skill.
Use when adding or changing a Reborn integration — a new extension, a channel surface, model-callable tools, or a shared auth provider — or when deciding whether something is "a channel", "an extension", or "a tool". Maps the unified extension model (NEA-25) to the exact
SKILL.md
reborn-extension-surfaces.SKILL.mdname: reborn-extension-surfaces
description: Use when adding or changing a Reborn integration — a new extension, a channel surface, model-callable tools, or a shared auth provider — or when deciding whether something is "a channel", "an extension", or "a tool". Maps the unified extension model (NEA-25) to the exact manifest sections, crates, seams, and tests.
Reborn Extension Surfaces
The top-level product object is always an **extension**. A channel is not a sibling product type: it is one **capability surface** an extension's manifest declares, exactly like tools and auth. Runtime (`wasm` / `mcp` / `first_party`) is implementation only and never taxonomy. The retired vocabulary (connectable channels, `slack_bot`, `slack_personal`, extension `kind` strings) is pinned at zero by `crates/app/ironclaw_architecture_tests/tests/reborn_retired_taxonomy.rs` — if your change trips that gate, you are re-introducing a deleted model.
**Schema is `reborn.extension_manifest.v3`** — v2 plus explicit `[channel]` and `[auth.*]` sections. The design is law: `docs/internal/reborn/extension-runtime/` (`overview.md` §3 the manifest, §4 the adapters, §5 the flows, §6 lifecycle). The worked example for *every* section below is the live Slack manifest — read it first: `crates/extensions/packages/slack/manifest.toml`.
The model in one diagram
extension (one manifest.toml, one installed identity, e.g. `slack`)
[[tools]] → tool surfaces (model-callable), each with [[tools.credentials]]
[channel] → channel surface (AT MOST ONE per extension; inbound/outbound)
[auth.<vendor>] → auth surface: one recipe per vendor (oauth2_code | api_key)
[mcp] → hosted-MCP extension: discovered tools INSTEAD of [runtime]+[[tools]]
[runtime] first_party|wasm|mcp → how the adapter LOADS (implementation only, never taxonomy)
- `ExtensionId` (`slack`, `github`, `gmail`) — product/installed identity.
- `VendorId` (`slack`, `github`, `google`) — credential authority; several
extensions may share one (gmail + google-drive + calendar + … share `google`). The manifest field is `vendor = "..."`. It is **not** the extension id. (Renamed from `ProviderId`/`RuntimeCredentialAccountProviderId` in this train — overview §2; stored id strings are unchanged.)
- `CapabilitySurfaceKind` (`crates/contracts/ironclaw_extension_contracts/src/surface.rs`) — `tool`,
`channel`, `auth` (+ reserved `trigger`, `file`).
- Surfaces are **derived** from the resolved manifest — never store a parallel
taxonomy. The manifest compiles **once** per install into a typed `ResolvedExtensionManifest` (+ `manifest_digest`); all production projection reads the resolved record, never re-parsed TOML (overview §3.3).
Adapters implement **behavior only** (overview §4): they never report ids, schemas, effects, scopes, routes, or credentials — the resolved manifest is the sole authority. Trait homes: `ToolAdapter` — `crates/contracts/ironclaw_extension_contracts/src/tool_adapter.rs`; `ChannelIngress`/`ChannelDelivery` — `crates/contracts/ironclaw_extension_contracts/src/channel_adapter.rs`; `ReplySink` — `crates/contracts/ironclaw_extension_contracts/src/reply.rs`; `ExtensionEntrypoint`/`ExtensionBindings` — `crates/extensions/ironclaw_extension_host/src/entrypoint.rs`. Auth has **no** adapter trait — it is one host engine driving manifest recipes (overview §4.3).
Where a bundled package lives
Every first-party integration is a self-contained package: `crates/extensions/packages/<id>/` (manifest + schemas + prompts + any WASM) beside one module `crates/extensions/ironclaw_extension_support/src/packages/<id>.rs` (embeds via `include_str!`/`include_bytes!`, onboarding copy, trust effects). A collector concatenates them; add a line to `PACKAGES` in `.../src/packages/mod.rs`. Composition and the CLI consume these as **opaque bundles** and never name a package (overview §3). Do NOT register assets in composition — the old `available_extensions.rs::*_assets()` home (now `crates/extensions/ironclaw_extension_host/src/available_extensions.rs`) is being dissolved. Re-verify the module list: `grep -n 'ID,' crates/extensions/ironclaw_extension_support/src/packages/mod.rs`.
Adding a tool surface
1. Declare each capability as a `[[tools]]` entry (id, description, effects, default_permission, visibility, `input_schema_ref`, optional `prompt_doc_ref`) with a `[[tools.credentials]]` block naming its `vendor`, `audience`, and `injection`. Copy the plain schema-declaring shape from `crates/extensions/packages/github/manifest.toml`; for `standard_op`-bound messaging tools the exemplar is `crates/extensions/packages/slack/manifest.toml`, whose tools are all standard-op-bound (count entries with `grep -c '^\[\[tools\]\]' <manifest>` rather than trusting a written number). 2. Schemas and prompt docs are **package assets** (`schemas/…`, `prompts/…`) embedded by the package module — not composition. 3. Model-visible tool wording is product surface: if a tool acts *as the user* (delegated authority), its description and prompt doc must say so — and must say the tool is for side effects inside a job, never for delivering the final answer (the host delivers final replies on the outbound channel surface — overview §5.4). Exemplar: `crates/extensions/packages/slack/prompts/slack/send_message.md`. 4. A **messaging-shaped** tool (send/read/react over a conversation) binds `standard_op = "<op_name>"` instead of declaring its own schemas — a closed, host-owned vocabulary with host-canonical input/output schemas. See `docs/internal/reborn/extension-runtime/standard-operations.md` for the full vocabulary and binding rules.
Adding a channel surface
1. Add a `[channel]` section (**at most one per extension**) with `id`, `display_name`, `inbound`/`outbound` bools, and **required** `conversation_model` (`continuous` | `isolated`, overview §3)
Read more
name: reborn-extension-surfaces description: Use when adding or changing a Reborn integration — a new extension, a channel surface, model-callable tools, or a shared auth provider — or when deciding whether something is "a channel", "an extension", or "a tool". Maps the unified extension model (NEA-25) to the exact manifest sections, crates, seams, and tests.
Reborn Extension Surfaces
The top-level product object is always an **extension**. A channel is not a sibling product type: it is one **capability surface** an extension's manifest declares, exactly like tools and auth. Runtime (`wasm` / `mcp` / `first_party`) is implementation only and never taxonomy. The retired vocabulary (connectable channels, `slack_bot`, `slack_personal`, extension `kind` strings) is pinned at zero by `crates/app/ironclaw_architecture_tests/tests/reborn_retired_taxonomy.rs` — if your change trips that gate, you are re-introducing a deleted model.
**Schema is `reborn.extension_manifest.v3`** — v2 plus explicit `[channel]` and `[auth.*]` sections. The design is law: `docs/internal/reborn/extension-runtime/` (`overview.md` §3 the manifest, §4 the adapters, §5 the flows, §6 lifecycle). The worked example for *every* section below is the live Slack manifest — read it first: `crates/extensions/packages/slack/manifest.toml`.
The model in one diagram
extension (one manifest.toml, one installed identity, e.g. `slack`) [[tools]] → tool surfaces (model-callable), each with [[tools.credentials]] [channel] → channel surface (AT MOST ONE per extension; inbound/outbound) [auth.<vendor>] → auth surface: one recipe per vendor (oauth2_code | api_key) [mcp] → hosted-MCP extension: discovered tools INSTEAD of [runtime]+[[tools]] [runtime] first_party|wasm|mcp → how the adapter LOADS (implementation only, never taxonomy)
- `ExtensionId` (`slack`, `github`, `gmail`) — product/installed identity.
- `VendorId` (`slack`, `github`, `google`) — credential authority; several
extensions may share one (gmail + google-drive + calendar + … share `google`). The manifest field is `vendor = "..."`. It is **not** the extension id. (Renamed from `ProviderId`/`RuntimeCredentialAccountProviderId` in this train — overview §2; stored id strings are unchanged.)
- `CapabilitySurfaceKind` (`crates/contracts/ironclaw_extension_contracts/src/surface.rs`) — `tool`,
`channel`, `auth` (+ reserved `trigger`, `file`).
- Surfaces are **derived** from the resolved manifest — never store a parallel
taxonomy. The manifest compiles **once** per install into a typed `ResolvedExtensionManifest` (+ `manifest_digest`); all production projection reads the resolved record, never re-parsed TOML (overview §3.3).
Adapters implement **behavior only** (overview §4): they never report ids, schemas, effects, scopes, routes, or credentials — the resolved manifest is the sole authority. Trait homes: `ToolAdapter` — `crates/contracts/ironclaw_extension_contracts/src/tool_adapter.rs`; `ChannelIngress`/`ChannelDelivery` — `crates/contracts/ironclaw_extension_contracts/src/channel_adapter.rs`; `ReplySink` — `crates/contracts/ironclaw_extension_contracts/src/reply.rs`; `ExtensionEntrypoint`/`ExtensionBindings` — `crates/extensions/ironclaw_extension_host/src/entrypoint.rs`. Auth has **no** adapter trait — it is one host engine driving manifest recipes (overview §4.3).
Where a bundled package lives
Every first-party integration is a self-contained package: `crates/extensions/packages/<id>/` (manifest + schemas + prompts + any WASM) beside one module `crates/extensions/ironclaw_extension_support/src/packages/<id>.rs` (embeds via `include_str!`/`include_bytes!`, onboarding copy, trust effects). A collector concatenates them; add a line to `PACKAGES` in `.../src/packages/mod.rs`. Composition and the CLI consume these as **opaque bundles** and never name a package (overview §3). Do NOT register assets in composition — the old `available_extensions.rs::*_assets()` home (now `crates/extensions/ironclaw_extension_host/src/available_extensions.rs`) is being dissolved. Re-verify the module list: `grep -n 'ID,' crates/extensions/ironclaw_extension_support/src/packages/mod.rs`.
Adding a tool surface
1. Declare each capability as a `[[tools]]` entry (id, description, effects, default_permission, visibility, `input_schema_ref`, optional `prompt_doc_ref`) with a `[[tools.credentials]]` block naming its `vendor`, `audience`, and `injection`. Copy the plain schema-declaring shape from `crates/extensions/packages/github/manifest.toml`; for `standard_op`-bound messaging tools the exemplar is `crates/extensions/packages/slack/manifest.toml`, whose tools are all standard-op-bound (count entries with `grep -c '^\[\[tools\]\]' <manifest>` rather than trusting a written number). 2. Schemas and prompt docs are **package assets** (`schemas/…`, `prompts/…`) embedded by the package module — not composition. 3. Model-visible tool wording is product surface: if a tool acts *as the user* (delegated authority), its description and prompt doc must say so — and must say the tool is for side effects inside a job, never for delivering the final answer (the host delivers final replies on the outbound channel surface — overview §5.4). Exemplar: `crates/extensions/packages/slack/prompts/slack/send_message.md`. 4. A **messaging-shaped** tool (send/read/react over a conversation) binds `standard_op = "<op_name>"` instead of declaring its own schemas — a closed, host-owned vocabulary with host-canonical input/output schemas. See `docs/internal/reborn/extension-runtime/standard-operations.md` for the full vocabulary and binding rules.
Adding a channel surface
1. Add a `[channel]` section (**at most one per extension**) with `id`, `display_name`, `inbound`/`outbound` bools, and **required** `conversation_model` (`continuous` | `isolated`, overview §3)
IronClaw is an Agent OS focused on privacy, security and extensibility

