provider-adapter-development
Skill0 starsChanged 47 days agoApache-2.0View on GitHub
Implement or change an AgentProvider against the neutral SPI, including capability descriptors, run handles, interaction settlement and the in-process trust boundary.
In this repository11 other files it gives its agents.
- AGENTS.mdAGENTS.md
- changesets-releaseSkill
- local-ci-paritySkill
- npm-releaseSkill
- package-architectureSkill
- package-artifact-validationSkill
- pnpm-supply-chainSkill
- public-api-evolutionSkill
- runtime-contract-evolutionSkill
- runtime-lifecycle-coordinationSkill
- workspace-lifecycleSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 5 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 13
Use this skill when a change touches any of:
- Distinctive: line 22
Do not use this skill when:
- Distinctive: line 71
Declare capabilities as structured descriptors: Do not add a boolean.
- Distinctive: line 84
If a provider cannot express something, say so in the descriptor.
- Very specific: line 95
Settle every interaction exactly once: When the Runtime calls respondToInteraction, the provider must either apply the response or reject …
- Distinctive: line 104
Do not report success while a run is awaiting an interaction.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill 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.
Files
Provider adapter development
Trigger
Use this skill when a change touches any of:
packages/provider/src/— the provider SPI itself- an implementation of
AgentProvider,ProviderSessionorProviderRun - a
ProviderDescriptor/ capability descriptor - how a provider reports interactions, interrupts, usage or termination
Counter-trigger
Do not use this skill when:
- you are changing the shape of an event or interaction DTO — use
runtime-contract-evolution - you are changing how the Runtime composes providers or the registry — use
package-architecture - the work is workspace acquisition or cleanup — use
workspace-lifecycle - you are adding a new production adapter package — that is a scoped,
reviewed milestone; open an issue first.
@relvo-labs/agent-provider-claudeand@relvo-labs/agent-provider-codexare both live and in scope for this skill
Owns
packages/provider/src— the neutral provider SPI and its conformance kitdocs/adr/ADR-0009-provider-trust-boundary.md— the in-process trust statementdocs/adr/ADR-0006-provider-handle-and-recovery-record.md— handle vs. serialisable record
Does not own
packages/protocol/src— owned byruntime-contract-evolutionpackages/runtime/src— owned byruntime-lifecycle-coordinationpackages/workspace/src— owned byworkspace-lifecycle
Relationships
boundary-with→runtime-contract-evolution— that skill defines what a provider may emit; this skill defines how an adapter produces it. A provider may only emit payloads the protocol already defines.boundary-with→package-architecture— this skill owns the SPI contract; that skill owns who is allowed to import it.boundary-with→workspace-lifecycle— an adapter consumes a lease root; it never acquires or releases the lease.boundary-with→runtime-lifecycle-coordination— adapters provide effects and callbacks; runtime coordination owns activation and settlement ordering.escalates-to→public-api-evolution— widening the SPI is a public break for every out-of-tree adapter.
Procedure
- Emit semantic input, not envelopes. A provider produces
ProviderEventInput: a semantic payload only. It must never inventeventId,sequence,occurredAt, or a provider sequence. Runtime snapshots and validates the whole input synchronously during eachemit()call, so object reuse or later mutation cannot rewrite history. Pass ordinary acyclic data, not getters or proxies. Self/mutual cycles become a typed provider-contract diagnostic before staging; repeated references are valid if the graph is acyclic. If you need envelope identity or ordering, you are in the wrong layer. - Keep native identity internal. Provider-native conversation IDs, thread handles,
file descriptors and checkpoints stay behind
ProviderRun/ProviderSession, which are ordinary non-serializable objects. To persist recovery information, implementexportRecoveryRecord()and return{ providerId, wireVersion, opaque }whereopaqueisJsonValue. Consumers must treatopaqueas opaque; never document its internals as public API. Declare capabilities as structured descriptors. Do not add a boolean.
// wrong — the boolean bag grows forever and cannot express degrees { supportsInterrupt: true, supportsResume: false, supportsImages: true } // right — a descriptor can express *how*, and can be extended compatibly { run: { interrupt: { mode: 'cooperative', deliversPartialOutput: true } }, interaction: { approval: { modes: ['once', 'session'] }, question: { choices: true } }, }If a provider cannot express something, say so in the descriptor. Do not invent false symmetry by faking a capability the provider lacks.
- Separate interrupt from dispose.
ProviderRun.interrupt(reason)ends one run. The session survives and must still accept a new run.ProviderSession.dispose()releases provider resources. It must be idempotent, remain safe to retry after rejection, and must not be used to cancel a run. A provider that can only kill the whole session declaresrun.interrupt.mode = 'unsupported'rather than silently disposing.
Settle every interaction exactly once. When the Runtime calls
respondToInteraction, the provider must either apply the response or reject it with a typed error. Re-delivering the sameinteractionIdmust be a no-op, not a second application.Emit a new interaction only while its run is
runningorawaiting_interaction. Once interruption begins, a late request is a provider-contract violation recorded as a diagnostic; it cannot create routing state or resume the run.Do not report success while a run is awaiting an interaction. Runtime validates completion against the pre-settlement run state, records explicit interaction settlements, and only then records the terminal run event.
- Respect the trust boundary. An in-process provider is a trusted plugin. It runs
with full process privileges. Do not write code, docs or permission prompts implying
the Runtime sandboxes it, restricts its filesystem access, or can enforce a policy
against it. Permission descriptors express provider-declared intent for UX, not an
enforced security control. See
docs/adr/ADR-0009-provider-trust-boundary.md. No PTY, and no shell. Control paths are structured. Do not add terminal scraping, ANSI parsing or pseudo-terminal emulation to core or the SPI.
tools/repo/check-static.tsenforces this for live adapter source by matching the module specifier, not the call site, so an alias (import { exec as run } from 'child_process') cannot slip past it.An adapter that legitimately spawns a subprocess — as the Codex adapter does — is held to a stricter form of the same rule rather than exempted from it: an argv vector and never a command string,
shell: falsestated explicitly, noexec/execSync, and spawning confined to one named module so the property can be reviewed by reading a single file. A command string is a parsing surface for prompt text and workspace paths; an argv vector is not.- Correlate before you settle. A long-lived provider connection carries more than the run in front of you: background, scheduled and already-retired turns share the same stream. Bind each terminal frame to the run that caused it using the provider's own correlation fields, and drop what you cannot attribute. Completing a run with another turn's result is indistinguishable from a correct completion in the event log.
- Publish classifications, not upstream prose.
AgentError.message,providerCodeand diagnostic text are durable and consumer-visible. Provider error strings routinely contain credentials, native ids, paths and prompt text, so map them to a closed allowlist instead of copying them — pattern-based redaction only catches the shapes you already thought of. Raw text belongs in the host's own injected seam, not the log. - Depend on a non-permissive SDK as an optional peer. A published package may only
carry permissively licensed runtime dependencies (
tools/repo/check-licenses.ts). Resolve such an SDK at runtime, keep the seam types hand-authored, and fail with a typedprovider_unavailablenaming the package when it is absent.
Verification
pnpm --filter @relvo-labs/agent-provider test
pnpm --filter @relvo-labs/agent-runtime test # SPI conformance runs against the runtime
pnpm dag:check
pnpm gate@relvo-labs/agent-provider/testing exports createScriptedProvider — a deterministic
double used to test the runtime against the SPI. It is not a conformance suite for an
adapter, and there is no exported adapter conformance suite yet: an adapter proves itself
with its own deterministic tests that validate every emitted ProviderEventInput against
the protocol schema and cover the failure, interrupt, disposal and correlation paths, with
no credentials and no network. packages/provider-claude/test and
packages/provider-codex/test are the worked examples; the latter also shows how an
adapter that spawns a subprocess proves its spawning, framing, EOF and signal-escalation
paths against a local stand-in server without a credential or a network.
Extracting the shared parts into a real exported suite is open work; do not cite one that
does not exist.
Runtime cleanup tests inject disposal rejection and require a later identical close attempt
to retry safely. An adapter that treats a rejected dispose() call as permanently consumed
does not satisfy the SPI.
Provenance
- Source: independent — authored for this repository.
- Reviewed-not-copied:
mindfold-ai/Trellis@88f4834449da9b4f607ec05e322408a0aa66f2ce(repository/skill license ambiguity) — reviewed for agent lifecycle vocabulary only; no text or structure incorporated.
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
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.

