SharedOS API / @aicoo/sharedos-adapters
@aicoo/sharedos-adapters
Codex, Claude Code, DeepSeek Harness, and Pi as SharedOS runtimes, and a model API in the same seat.
An adapter is translation and nothing else. The turn loop, the permission-filtered tool catalogue, per-call re-authorization, and audit all come from the SharedOS execution envelope, so installing another harness changes no kernel code and adds no second permission path.
import { SharedOSExecutor } from "@aicoo/sharedos-runtime";
import { createCodexRuntime } from "@aicoo/sharedos-adapters";
import { ChildProcessTransport } from "@aicoo/sharedos-adapters/node";
const codex = createCodexRuntime({
transport: new ChildProcessTransport({
command: "codex",
// `-` makes `codex exec` read its prompt from stdin, which is where the
// opening frame goes. Without both, nothing reaches Codex.
args: ["exec", "--json", "--skip-git-repo-check", "-"],
openingFrame: (request) => ({ type: "user_input", text: request.prompt }),
}),
});
const turns = new SharedOSExecutor(kernel, codex);
Use createCodexRuntime rather than wrapping createCodexDriver in
StandardRuntime yourself. The executor stamps the installed plugin's manifest
onto every execution record, and StandardRuntime reports itself as
sharedos.standard, so the driver-only form files a Codex turn's evidence under
the reference loop. Comparing harnesses depends on each column's evidence naming
the harness that produced it.
Four ways to occupy the seat
| Path | What is in the delegate seat | Entry points |
|---|---|---|
| Driven harness | A vendor CLI, run one turn at a time by SharedOS's own loop | createCodexRuntime, createClaudeCodeRuntime, createDeepseekRuntime, createPiRuntime; HarnessRuntime |
| Driven model | A model API, with no vendor between it and the kernel | ModelDriver, ModelRuntime, OpenAiCompatibleModelClient; TranscriptModelClient for a scripted reply sequence |
| Native harness over MCP | A vendor CLI running its own loop, with the catalogue served to it | createMcpHarnessRuntime and the *_MCP_HARNESS specs, from @aicoo/sharedos-adapters/node |
| Transcript | Supplied vendor frames or model replies, for testing the translation without a CLI or a provider | TranscriptTransport, HarnessTranscript, and the *FrameWriters that render a declared attempt in a vendor's shape; TranscriptModelClient, ModelTranscript for the model seat |
The first two run inside StandardRuntime: SharedOS owns the loop, renders the
permission-filtered catalogue into the harness's or the model's own tool shape,
and mediates every call. The third hands the loop to the vendor and serves the
catalogue over the Model Context Protocol instead; it is documented in
docs/mcp-toolshare.md. All of them converge on
RuntimeHost.invokeTool, which is the only place a tool is executed.
The three pieces of a driven harness
An adapter is assembled from parts that are replaceable independently, which is what lets the translation be verified without the vendor's CLI present.
| Piece | Responsibility |
|---|---|
HarnessProtocol | The vendor's wire shapes: tool declarations, tool calls, tool results, completion |
HarnessTransport | How the harness is reached: a subprocess, an HTTP session, a supplied transcript |
HarnessDriver | An AgentTurnDriver that joins the two and hands every tool call to the envelope |
ModelDriver is the same shape with the protocol folded in: the catalogue is
rendered straight into the model's tool-call format, and a ModelClient stands
where the transport does.
What the adapter must not do
Tool calls are passed to the envelope as the harness emitted them, including names that are not in the catalogue.
Filtering them in the adapter would be the adapter quietly enforcing policy, and worse, it would erase the attempt: a guess at an unexposed tool has to reach the envelope to be refused and recorded. An adapter that silently dropped it would make a harness that tried look identical to one that did not.
The one call that does not reach the envelope is the escalation affordance. A
call naming sharedos.escalate on a turn whose catalogue offers it ends the
turn escalated with the reason the harness gave, because asking for a human is
an ending rather than a tool (ADR 0011, 0017). The catalogue gates the name: on
a turn that was never granted the affordance the call is passed through like any
other and refused tool_unavailable.
For the same reason a refusal is reported back to the harness as an ordinary
tool result carrying its reason code, not as a transport error. The harness needs
to know it was refused so it can choose differently. A model whose call
arguments are not a JSON object is answered the same way, invalid_tool_arguments,
and never sent {} in their place.
Tool calls arriving together in one frame are executed one at a time. SharedOS re-authorizes every call separately, so serialising them is the conservative order and the one whose audit trail matches what actually happened.
Who executes the tools
The four harnesses do not agree on this, and the difference decides what a driven column can claim.
| Harness | Catalogue reaches the harness by | Tool executed by |
|---|---|---|
| Codex | function declarations, on the wire | The host |
| Claude Code | input_schema tools, on the wire | The host |
| DeepSeek | Out of band — its dsh-mcp-client plugin, over MCP | The host, via MCP |
| Pi | Out of band — an MCP extension, or defineTool in the SDK | The host, via MCP |
Codex and Claude Code carry a tool catalogue in the protocol itself. DeepSeek
Harness and Pi run their own tools and have no wire frame that means "here is
your catalogue", so their driven adapters stamp catalogueDelivery: "out-of-band"
onto every execution record they produce: a column whose catalogue arrived out
of band is making a narrower claim than one whose catalogue was on the wire, and
that belongs in the evidence rather than in a footnote.
It is also why a native run over a CLI's own stdio — any of the four — leaves
the kernel rows not exercised: the driver can carry the transport, but a CLI
exposes neither its API layer nor a frame for the catalogue (ADR 0014), so the
harness reaches for its own tools. The MCP path is what closes that gap.
createMcpHarnessRuntime serves the permission-filtered catalogue over MCP to a
CLI running natively; scripts/mcp-conformance.mjs runs the case set against
each installed CLI that way, and ADR 0018 records what the escalation-case runs
on all four showed.
Verification status
The translation code is exercised end to end against supplied transcripts, which
run the real protocol modules through a real kernel and a real execution
envelope. Nothing in this package captures a vendor session: a transcript is
whatever its caller hands it, and the conformance suite writes its own.
TranscriptTransport replays vendor frames in batches and releases the next
batch only once a result has been written, which is the shape of every
tool-using harness. TranscriptModelClient is its counterpart for the model
seat: it replays supplied replies through the real ModelDriver, one reply per
model call, and treats a spent transcript as an error rather than a completion,
so a script that ends too early fails the turn instead of reading as a model
choosing to stop.
What a transcript cannot cover is the transport binding — the exact command-line flags each CLI wants, and the outer envelope it wraps its frames in — and what a model actually chooses. Two scripts cover exactly those gaps:
scripts/native-conformance.mjsspawns each installed CLI as a driven harness, and runs the model column when a key is present;scripts/mcp-conformance.mjsruns each installed CLI natively against the catalogue over MCP.
Both report a harness that is absent, unauthenticated, or emitting shapes the
adapter does not parse as not exercised, never as a pass and never as a kernel
failure. The version each run drove is the harness's own to report, so it is
recorded in the artifact the script writes under artifacts/conformance/ —
local to the machine that ran it, not committed — rather than pinned here; ADR
0014 and ADR 0018 pin the versions of the runs they record.
Availability
probeHarness reports whether a harness can run here, and says why not when it
cannot. probeCodex, probeClaudeCode, probeDeepseek, and probePi are the
same call with each adapter's *_REQUIREMENTS supplied:
import { probeClaudeCode } from "@aicoo/sharedos-adapters/node";
const availability = await probeClaudeCode();
// { harness: "claude-code", available: false, reason: "The claude executable is not on PATH." }
// or { harness: "claude-code", available: true, version: "…" }
Every one of these harnesses can authenticate from a stored login as well as from an environment variable, so a probe treats credentials as optional unless the requirements say otherwise, and reports which one it found. Conformance runs use this to mark a column as not exercised rather than as failing: an absent harness is not evidence about SharedOS.
Reason codes
The codes an adapter ends a turn with — harness_*, model_* — and the one it
answers in band on the MCP path, escalation_pending, are listed with the rest
in docs/errors.md.
Host neutrality
The main entry point has no Node dependency. ChildProcessTransport, the
availability probes, and the MCP harness runtime are published from
@aicoo/sharedos-adapters/node, because spawning a CLI, reading PATH, and
opening a loopback server are host concerns rather than protocol ones.
Classes
DriverRuntime
Defined in: packages/adapters/src/runtime.ts:31
A driver installed as a runtime under its own identity.
StandardRuntime is the reference turn loop and reports itself as
sharedos.standard, which is correct for the driver it was built for and
wrong for a vendor harness or a model: the executor stamps the plugin's
manifest onto every execution record, so a Codex turn wrapped in
StandardRuntime alone would file its evidence under the standard runtime.
That matters beyond tidiness. Comparing harnesses depends on each column's evidence naming the harness that produced it; a column that misattributes itself is worse than a column that is absent, because it looks like data.
This keeps the loop and replaces only the identity. StandardRuntime still
owns the steps, still stops at maxSteps, and still re-authorizes every
call -- which is the property that distinguishes a driven column from one
where a vendor CLI owns the loop.
Extended by
Type Parameters
| Type Parameter |
|---|
D extends AgentTurnDriver & object |
Implements
Constructors
Constructor
new DriverRuntime<
D>>(driver,options?):DriverRuntime<D>>
Defined in: packages/adapters/src/runtime.ts:37
Parameters
| Parameter | Type |
|---|---|
driver | D |
options | StandardRuntimeOptions |
Returns
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-manifest"></a> manifest | readonly | object | packages/adapters/src/runtime.ts:34 |
manifest.id | public | string | packages/contracts/dist/runtime.d.ts:9 |
manifest.metadata? | public | JsonObject | packages/contracts/dist/runtime.d.ts:12 |
manifest.protocolVersion | public | "1" | packages/contracts/dist/runtime.d.ts:11 |
manifest.version | public | string | packages/contracts/dist/runtime.d.ts:10 |
Methods
run()
run(
request,host,signal):Promise<{metadata?:JsonObject;output:JsonValue;type:"complete"; } | {error: {code:string;details?:JsonObject;message:string;retryable?:boolean; };metadata?:JsonObject;type:"fail"; } | {metadata?:JsonObject;reason:string;type:"escalate"; }>
Defined in: packages/adapters/src/runtime.ts:42
Parameters
| Parameter | Type |
|---|---|
request | RuntimeTurnRequest |
host | RuntimeHost |
signal | AbortSignal |
Returns
Promise<{ metadata?: JsonObject; output: JsonValue; type: "complete"; } | { error: { code: string; details?: JsonObject; message: string; retryable?: boolean; }; metadata?: JsonObject; type: "fail"; } | { metadata?: JsonObject; reason: string; type: "escalate"; }>
Implementation of
HarnessDriver
Defined in: packages/adapters/src/driver.ts:57
One vendor harness, driven as a SharedOS agent turn.
A driver is only translation. The turn loop, the permission-filtered catalogue, per-call re-authorization, and audit all belong to the SharedOS execution envelope, which is why adding a harness requires no kernel change and no second enforcement path.
Tool calls are passed through exactly as the harness emitted them, including names that are not in the catalogue. Filtering those here would be the adapter quietly enforcing policy, and worse, it would erase the attempt: a guess at an unexposed tool has to reach the envelope to be refused and recorded.
Implements
Constructors
Constructor
new HarnessDriver(
options):HarnessDriver
Defined in: packages/adapters/src/driver.ts:65
Parameters
| Parameter | Type |
|---|---|
options | HarnessDriverOptions |
Returns
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-manifest-1"></a> manifest | readonly | object | packages/adapters/src/driver.ts:58 |
manifest.id | public | string | packages/contracts/dist/runtime.d.ts:9 |
manifest.metadata? | public | JsonObject | packages/contracts/dist/runtime.d.ts:12 |
manifest.protocolVersion | public | "1" | packages/contracts/dist/runtime.d.ts:11 |
manifest.version | public | string | packages/contracts/dist/runtime.d.ts:10 |
Methods
open()
open(
request,signal):Promise<AgentTurnSession>>
Defined in: packages/adapters/src/driver.ts:77
Parameters
| Parameter | Type |
|---|---|
request | RuntimeTurnRequest |
signal | AbortSignal |
Returns
Promise<AgentTurnSession>
Implementation of
HarnessRuntime
Defined in: packages/adapters/src/runtime.ts:52
A harness driver installed as a runtime under its own identity; see DriverRuntime.
Extends
Constructors
Constructor
new HarnessRuntime(
driver,options?):HarnessRuntime
Defined in: packages/adapters/src/runtime.ts:37
Parameters
| Parameter | Type |
|---|---|
driver | HarnessDriver |
options | StandardRuntimeOptions |
Returns
Inherited from
Properties
| Property | Modifier | Type | Inherited from | Defined in |
|---|---|---|---|---|
<a id="property-manifest-2"></a> manifest | readonly | object | DriverRuntime.manifest | packages/adapters/src/runtime.ts:34 |
manifest.id | public | string | - | packages/contracts/dist/runtime.d.ts:9 |
manifest.metadata? | public | JsonObject | - | packages/contracts/dist/runtime.d.ts:12 |
manifest.protocolVersion | public | "1" | - | packages/contracts/dist/runtime.d.ts:11 |
manifest.version | public | string | - | packages/contracts/dist/runtime.d.ts:10 |
Methods
run()
run(
request,host,signal):Promise<{metadata?:JsonObject;output:JsonValue;type:"complete"; } | {error: {code:string;details?:JsonObject;message:string;retryable?:boolean; };metadata?:JsonObject;type:"fail"; } | {metadata?:JsonObject;reason:string;type:"escalate"; }>
Defined in: packages/adapters/src/runtime.ts:42
Parameters
| Parameter | Type |
|---|---|
request | RuntimeTurnRequest |
host | RuntimeHost |
signal | AbortSignal |
Returns
Promise<{ metadata?: JsonObject; output: JsonValue; type: "complete"; } | { error: { code: string; details?: JsonObject; message: string; retryable?: boolean; }; metadata?: JsonObject; type: "fail"; } | { metadata?: JsonObject; reason: string; type: "escalate"; }>
Inherited from
ModelDriver
Defined in: packages/adapters/src/model/driver.ts:141
A model API driven as a SharedOS agent turn.
The same port a vendor harness occupies, with the vendor removed. A harness driver translates frames from a CLI that has already decided what to call; this one puts the model itself in the seat, so the catalogue it sees is the permission-filtered one the kernel built and nothing between the two can add a tool, drop a tool, or answer a call on its own.
What that buys is an axis the other columns cannot separate. A scripted
column leaves out the transport; a live CLI column leaves out the catalogue;
an MCP column keeps both but hands the turn loop to the vendor's scaffolding.
This one keeps the loop inside StandardRuntime and drops the vendor
entirely, which is what makes "the model behaved this way" distinguishable
from "the vendor's scaffolding made the model behave this way".
It is not a replacement for the scripted adversary and cannot be one. A model chooses what to call, so an attempt it declines to issue leaves no operation in the record and is graded as unexercised. That is the honest grading, and the reason the deterministic column stays the reference.
Implements
Constructors
Constructor
new ModelDriver(
options):ModelDriver
Defined in: packages/adapters/src/model/driver.ts:148
Parameters
| Parameter | Type |
|---|---|
options | ModelDriverOptions |
Returns
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-manifest-3"></a> manifest | readonly | object | packages/adapters/src/model/driver.ts:142 |
manifest.id | public | string | packages/contracts/dist/runtime.d.ts:9 |
manifest.metadata? | public | JsonObject | packages/contracts/dist/runtime.d.ts:12 |
manifest.protocolVersion | public | "1" | packages/contracts/dist/runtime.d.ts:11 |
manifest.version | public | string | packages/contracts/dist/runtime.d.ts:10 |
Methods
open()
open(
request,_signal):Promise<AgentTurnSession>>
Defined in: packages/adapters/src/model/driver.ts:159
Parameters
| Parameter | Type |
|---|---|
request | RuntimeTurnRequest |
_signal | AbortSignal |
Returns
Promise<AgentTurnSession>
Implementation of
ModelRequestError
Defined in: packages/adapters/src/model/client.ts:100
A model call that did not produce an answer. Carries no response body.
Extends
Error
Constructors
Constructor
new ModelRequestError(
message,status?):ModelRequestError
Defined in: packages/adapters/src/model/client.ts:103
Parameters
| Parameter | Type |
|---|---|
message | string |
status? | number |
Returns
Overrides
Error.constructor
Properties
| Property | Modifier | Type | Description | Inherited from | Defined in |
|---|---|---|---|---|---|
<a id="property-cause"></a> cause? | public | unknown | - | Error.cause | node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.error.d.ts:26 |
<a id="property-message"></a> message | public | string | - | Error.message | node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts:1077 |
<a id="property-name"></a> name | public | string | - | Error.name | node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts:1076 |
<a id="property-stack"></a> stack? | public | string | - | Error.stack | node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts:1078 |
<a id="property-status"></a> status? | readonly | number | - | - | packages/adapters/src/model/client.ts:101 |
<a id="property-stacktracelimit"></a> stackTraceLimit | static | number | The Error.stackTraceLimit property specifies the number of stack frames collected by a stack trace (whether generated by new Error().stack or Error.captureStackTrace(obj)). The default value is 10 but may be set to any valid JavaScript number. Changes will affect any stack trace captured after the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. | Error.stackTraceLimit | node_modules/.pnpm/@types+node@22.20.1/node_modules/@types/node/globals.d.ts:68 |
Methods
captureStackTrace()
staticcaptureStackTrace(targetObject,constructorOpt?):void
Defined in: node_modules/.pnpm/@types+node@22.20.1/node_modules/@types/node/globals.d.ts:52
Creates a .stack property on targetObject, which when accessed returns
a string representing the location in the code at which
Error.captureStackTrace() was called.
const myObject = {};
Error.captureStackTrace(myObject);
myObject.stack; // Similar to `new Error().stack`
The first line of the trace will be prefixed with
${myObject.name}: ${myObject.message}.
The optional constructorOpt argument accepts a function. If given, all frames
above constructorOpt, including constructorOpt, will be omitted from the
generated stack trace.
The constructorOpt argument is useful for hiding implementation
details of error generation from the user. For instance:
function a() {
b();
}
function b() {
c();
}
function c() {
// Create an error without stack trace to avoid calculating the stack trace twice.
const { stackTraceLimit } = Error;
Error.stackTraceLimit = 0;
const error = new Error();
Error.stackTraceLimit = stackTraceLimit;
// Capture the stack trace above function b
Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
throw error;
}
a();
Parameters
| Parameter | Type |
|---|---|
targetObject | object |
constructorOpt? | Function |
Returns
void
Inherited from
Error.captureStackTrace
prepareStackTrace()
staticprepareStackTrace(err,stackTraces):any
Defined in: node_modules/.pnpm/@types+node@22.20.1/node_modules/@types/node/globals.d.ts:56
Parameters
| Parameter | Type |
|---|---|
err | Error |
stackTraces | CallSite[] |
Returns
any
See
https://v8.dev/docs/stack-trace-api#customizing-stack-traces
Inherited from
Error.prepareStackTrace
ModelRuntime
Defined in: packages/adapters/src/model/runtime.ts:11
A model driver installed as a runtime under its own identity.
The same arrangement HarnessRuntime makes, for the same reason: a column comparing models must be able to say which one produced which record. See DriverRuntime.
Extends
Constructors
Constructor
new ModelRuntime(
driver,options?):ModelRuntime
Defined in: packages/adapters/src/runtime.ts:37
Parameters
| Parameter | Type |
|---|---|
driver | ModelDriver |
options | StandardRuntimeOptions |
Returns
Inherited from
Properties
| Property | Modifier | Type | Inherited from | Defined in |
|---|---|---|---|---|
<a id="property-manifest-4"></a> manifest | readonly | object | DriverRuntime.manifest | packages/adapters/src/runtime.ts:34 |
manifest.id | public | string | - | packages/contracts/dist/runtime.d.ts:9 |
manifest.metadata? | public | JsonObject | - | packages/contracts/dist/runtime.d.ts:12 |
manifest.protocolVersion | public | "1" | - | packages/contracts/dist/runtime.d.ts:11 |
manifest.version | public | string | - | packages/contracts/dist/runtime.d.ts:10 |
Methods
run()
run(
request,host,signal):Promise<{metadata?:JsonObject;output:JsonValue;type:"complete"; } | {error: {code:string;details?:JsonObject;message:string;retryable?:boolean; };metadata?:JsonObject;type:"fail"; } | {metadata?:JsonObject;reason:string;type:"escalate"; }>
Defined in: packages/adapters/src/runtime.ts:42
Parameters
| Parameter | Type |
|---|---|
request | RuntimeTurnRequest |
host | RuntimeHost |
signal | AbortSignal |
Returns
Promise<{ metadata?: JsonObject; output: JsonValue; type: "complete"; } | { error: { code: string; details?: JsonObject; message: string; retryable?: boolean; }; metadata?: JsonObject; type: "fail"; } | { metadata?: JsonObject; reason: string; type: "escalate"; }>
Inherited from
OpenAiCompatibleModelClient
Defined in: packages/adapters/src/model/client.ts:198
A chat-completions client for any provider speaking the OpenAI wire shape.
DeepSeek is the one this was built against, but nothing here is DeepSeek specific: the endpoint, model, and provider label are all supplied, so pointing the column at another compatible provider is configuration rather than a second client.
Implements
Constructors
Constructor
new OpenAiCompatibleModelClient(
options):OpenAiCompatibleModelClient
Defined in: packages/adapters/src/model/client.ts:208
Parameters
| Parameter | Type |
|---|---|
options | OpenAiCompatibleModelClientOptions |
Returns
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-model"></a> model | readonly | string | The model this client was configured to ask for. | packages/adapters/src/model/client.ts:199 |
<a id="property-provider"></a> provider | readonly | string | The provider that serves it, recorded alongside the model on every turn. | packages/adapters/src/model/client.ts:200 |
Methods
complete()
complete(
request,signal):Promise<ModelReply>>
Defined in: packages/adapters/src/model/client.ts:222
Parameters
| Parameter | Type |
|---|---|
request | ModelCompletionRequest |
signal | AbortSignal |
Returns
Promise<ModelReply>
Implementation of
ToolNameCodec
Defined in: packages/adapters/src/model/driver.ts:53
How a SharedOS tool name is spoken to a model, and read back.
Dots become underscores on the way out and the catalogue's own map decides the way back, so a catalogued tool round-trips exactly rather than through a guess. The map is built per turn from the permission-filtered catalogue, which means it contains precisely the tools this actor was allowed to see.
A name the map does not contain is decoded by reversing the substitution and then passed through unchanged. That path is best-effort and it exists for one reason: a model that invents a tool outside its catalogue must still be able to reach the envelope and be refused. Filtering it here, or failing to decode it, would erase the attempt -- and an attempt that never arrives is graded as a tool that was never tried, not as a tool that was refused.
Constructors
Constructor
new ToolNameCodec(
tools):ToolNameCodec
Defined in: packages/adapters/src/model/driver.ts:57
Parameters
| Parameter | Type |
|---|---|
tools | readonly object[] |
Returns
Methods
fromWire()
fromWire(
name):string
Defined in: packages/adapters/src/model/driver.ts:83
Parameters
| Parameter | Type |
|---|---|
name | string |
Returns
string
toWire()
toWire(
name):string
Defined in: packages/adapters/src/model/driver.ts:79
Parameters
| Parameter | Type |
|---|---|
name | string |
Returns
string
TranscriptModelClient
Defined in: packages/adapters/src/model/transcript.ts:38
Replays a supplied conversation through the real model driver.
This is how the native harness is verified without a provider or a
credential present, and it is the exact counterpart of TranscriptTransport
for a vendor harness. The replies are the caller's, written in the model's
own tool-call shape; the name decoding, argument parsing, escalation
recognition, and step accounting are the driver's; and the only thing left
unexercised is the provider that would have produced the replies.
A spent transcript is an error rather than a completion. A live provider
always answers; a recording that has run out has nothing to say, and
answering "done" on its behalf would grade a script that ended too early as
a model choosing to stop. The driver fails the turn model_call_failed,
which is the visible result.
Implements
Constructors
Constructor
new TranscriptModelClient(
transcript,options?):TranscriptModelClient
Defined in: packages/adapters/src/model/transcript.ts:46
Parameters
| Parameter | Type |
|---|---|
transcript | ModelTranscript |
options | TranscriptModelClientOptions |
Returns
Properties
| Property | Modifier | Type | Default value | Description | Defined in |
|---|---|---|---|---|---|
<a id="property-model-1"></a> model | readonly | string | undefined | The model this client was configured to ask for. | packages/adapters/src/model/transcript.ts:39 |
<a id="property-provider-1"></a> provider | readonly | string | undefined | The provider that serves it, recorded alongside the model on every turn. | packages/adapters/src/model/transcript.ts:40 |
<a id="property-seen"></a> seen | readonly | ModelCompletionRequest[] | [] | Every request the driver made, in order, for a test to read back. | packages/adapters/src/model/transcript.ts:42 |
Methods
complete()
complete(
request,signal):Promise<ModelReply>>
Defined in: packages/adapters/src/model/transcript.ts:55
Parameters
| Parameter | Type |
|---|---|
request | ModelCompletionRequest |
signal | AbortSignal |
Returns
Promise<ModelReply>
Implementation of
TranscriptTransport
Defined in: packages/adapters/src/transcript.ts:27
Replays a supplied conversation through the real protocol translation.
This is how an adapter is verified without the vendor's CLI or credentials present. The frames are the vendor's, the parsing is the adapter's, and the only thing left unexercised is the transport that would have carried them.
Implements
Constructors
Constructor
new TranscriptTransport(
transcript):TranscriptTransport
Defined in: packages/adapters/src/transcript.ts:32
Parameters
| Parameter | Type |
|---|---|
transcript | HarnessTranscript |
Returns
Properties
| Property | Modifier | Type | Default value | Defined in |
|---|---|---|---|---|
<a id="property-opened"></a> opened | readonly | HarnessTurnRequest[] | [] | packages/adapters/src/transcript.ts:28 |
<a id="property-written"></a> written | readonly | JsonObject[] | [] | packages/adapters/src/transcript.ts:29 |
Methods
open()
open(
request):Promise<HarnessChannel>>
Defined in: packages/adapters/src/transcript.ts:39
Parameters
| Parameter | Type |
|---|---|
request | HarnessTurnRequest |
Returns
Promise<HarnessChannel>
Implementation of
Interfaces
HarnessAvailability
Defined in: packages/adapters/src/harness.ts:80
Whether a harness can actually be run here, and if not, why not.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-available"></a> available | readonly | boolean | - | packages/adapters/src/harness.ts:82 |
<a id="property-detail"></a> detail? | readonly | JsonObject | Includes versionOutput, the line version was read from, verbatim. | packages/adapters/src/harness.ts:95 |
<a id="property-harness"></a> harness | readonly | string | - | packages/adapters/src/harness.ts:81 |
<a id="property-reason"></a> reason? | readonly | string | - | packages/adapters/src/harness.ts:83 |
<a id="property-version"></a> version? | readonly | string | The build that answered, as the harness itself reports it. A result about a vendor CLI is a result about one version of it, and the version is the harness's to state: nothing in this repository pins the installed binary, and a number carried in a runbook is a claim about what someone typed rather than about what ran. Absent when the executable declined to report one -- see HarnessRequirements.versionArguments. | packages/adapters/src/harness.ts:93 |
HarnessChannel
Defined in: packages/adapters/src/harness.ts:42
One open harness turn. Reads and writes are frames, never SharedOS types.
Methods
close()
close():
Promise<void>>
Defined in: packages/adapters/src/harness.ts:46
Returns
Promise<void>
read()
read(
signal):Promise<JsonObject|undefined>>
Defined in: packages/adapters/src/harness.ts:44
The next frame, or undefined once the harness has finished speaking.
Parameters
| Parameter | Type |
|---|---|
signal | AbortSignal |
Returns
Promise<JsonObject | undefined>
write()
write(
frame,signal):Promise<void>>
Defined in: packages/adapters/src/harness.ts:45
Parameters
| Parameter | Type |
|---|---|
frame | JsonObject |
signal | AbortSignal |
Returns
Promise<void>
HarnessDriverOptions
Defined in: packages/adapters/src/driver.ts:21
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-declarestep"></a> declareStep? | readonly | (index, request) => number | undefined | The step to declare for the nth call this turn releases, if any. undefined -- the default for every call -- leaves the step to the loop. It exists for the one thing a driven harness cannot otherwise express: reaching past its own budget. The loop's index stops at maxSteps, so a call at or past the ceiling can only be made by a driver that names the step itself, which makes the driver the attacker for that call. | packages/adapters/src/driver.ts:38 |
<a id="property-manifest-5"></a> manifest | readonly | object | - | packages/adapters/src/driver.ts:22 |
manifest.id | public | string | - | packages/contracts/dist/runtime.d.ts:9 |
manifest.metadata? | public | JsonObject | - | packages/contracts/dist/runtime.d.ts:12 |
manifest.protocolVersion | public | "1" | - | packages/contracts/dist/runtime.d.ts:11 |
manifest.version | public | string | - | packages/contracts/dist/runtime.d.ts:10 |
<a id="property-maxignoredframes"></a> maxIgnoredFrames? | readonly | number | Guard against a harness that streams unrelated frames without end. | packages/adapters/src/driver.ts:28 |
<a id="property-prompt"></a> prompt? | readonly | (request) => string | Overrides how the turn message becomes the harness prompt. | packages/adapters/src/driver.ts:26 |
<a id="property-protocol"></a> protocol | readonly | HarnessProtocol | - | packages/adapters/src/driver.ts:23 |
<a id="property-transport"></a> transport | readonly | HarnessTransport | - | packages/adapters/src/driver.ts:24 |
HarnessFrameWriter
Defined in: packages/adapters/src/writer.ts:22
The inverse of HarnessProtocol.interpret: frames a harness would send.
A HarnessProtocol only ever reads. That is correct for production, where
the frames come from the vendor, and it leaves no way to build a recorded
conversation for a harness to be replayed against. Writing those frames by
hand per test is how a fixture drifts from the shape the parser expects, so
the two live side by side and are exercised against each other.
A writer is deliberately not part of HarnessProtocol. Requiring every
adapter to implement an encoder that production never calls would put dead
code in the security-relevant path.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-protocolid"></a> protocolId | readonly | string | The protocol these frames belong to; must match the reading protocol's id. | packages/adapters/src/writer.ts:24 |
Methods
complete()
complete(
output?):JsonObject
Defined in: packages/adapters/src/writer.ts:27
Parameters
| Parameter | Type |
|---|---|
output? | JsonValue |
Returns
message()
message(
text):JsonObject
Defined in: packages/adapters/src/writer.ts:26
Parameters
| Parameter | Type |
|---|---|
text | string |
Returns
toolCall()
toolCall(
callId,tool,arguments_):JsonObject
Defined in: packages/adapters/src/writer.ts:25
Parameters
| Parameter | Type |
|---|---|
callId | string |
tool | string |
arguments_ | JsonObject |
Returns
HarnessProtocol
Defined in: packages/adapters/src/harness.ts:66
The translation between SharedOS and one vendor's wire shapes.
This is the whole adapter. Everything else -- the turn loop, per-call re-authorization, the permission-filtered catalogue, audit -- is supplied by the SharedOS execution envelope and is not reimplemented per vendor.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-id"></a> id | readonly | string | packages/adapters/src/harness.ts:67 |
Methods
describeTools()
describeTools(
tools):JsonValue
Defined in: packages/adapters/src/harness.ts:69
Render the permission-filtered catalogue in the harness's own tool shape.
Parameters
| Parameter | Type |
|---|---|
tools | readonly object[] |
Returns
encodeToolResult()
encodeToolResult(
result):JsonObject
Defined in: packages/adapters/src/harness.ts:76
Parameters
| Parameter | Type |
|---|---|
result | { callId: string; completedAt: string; metadata?: JsonObject; output: JsonValue; status: "succeeded"; tool: string; } | { callId: string; completedAt: string; error: { code: string; details?: JsonObject; message: string; retryable?: boolean; }; metadata?: JsonObject; status: "denied"; tool: string; } | { callId: string; completedAt: string; error: { code: string; details?: JsonObject; message: string; retryable?: boolean; }; metadata?: JsonObject; status: "failed"; tool: string; } |
Returns
interpret()
interpret(
frame): readonlyHarnessStep[]
Defined in: packages/adapters/src/harness.ts:75
Everything one frame means, in order. Frames carrying nothing relevant -- progress notices, token counts, thinking blocks -- yield an empty array, and a frame carrying several tool calls yields one step each.
Parameters
| Parameter | Type |
|---|---|
frame | JsonObject |
Returns
readonly HarnessStep[]
HarnessRequirements
Defined in: packages/adapters/src/harness.ts:99
What a harness needs before it can run: an executable, credentials, or both.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-credentialsoptional"></a> credentialsOptional | readonly | boolean | True when the harness can authenticate from a stored session instead. | packages/adapters/src/harness.ts:106 |
<a id="property-credentialvariables"></a> credentialVariables | readonly | readonly string[] | Environment variables, any one of which satisfies the credential need. | packages/adapters/src/harness.ts:104 |
<a id="property-executable"></a> executable | readonly | string | Executable expected on PATH. | packages/adapters/src/harness.ts:102 |
<a id="property-harness-1"></a> harness | readonly | string | - | packages/adapters/src/harness.ts:100 |
<a id="property-versionarguments"></a> versionArguments? | readonly | readonly string[] | How to ask this executable what it is. Defaults to --version, which all four harnesses here answer; declared so one that does not can say so. | packages/adapters/src/harness.ts:111 |
HarnessTranscript
Defined in: packages/adapters/src/transcript.ts:16
A harness conversation, supplied by its caller.
Batches are released one tool result at a time: the first batch is emitted when the turn opens, and each later batch is unlocked by the adapter writing a result back. That is the shape of every tool-using harness, so a transcript exercises the same code path a live session does.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-batches"></a> batches | readonly | readonly readonly JsonObject[][] | packages/adapters/src/transcript.ts:17 |
HarnessTransport
Defined in: packages/adapters/src/harness.ts:55
How a harness is reached: a subprocess, an HTTP session, or a recorded transcript. Keeping this separate from the protocol is what lets one adapter be exercised deterministically and then run live without changing the translation code under test.
Methods
open()
open(
request,signal):Promise<HarnessChannel>>
Defined in: packages/adapters/src/harness.ts:56
Parameters
| Parameter | Type |
|---|---|
request | HarnessTurnRequest |
signal | AbortSignal |
Returns
Promise<HarnessChannel>
HarnessTurnRequest
Defined in: packages/adapters/src/harness.ts:31
Everything a harness needs to start one turn.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-context"></a> context | readonly | RuntimeVisibleContext | The sanitised context. It carries no grants and no issuing authority. | packages/adapters/src/harness.ts:37 |
<a id="property-executionid"></a> executionId | readonly | string | - | packages/adapters/src/harness.ts:32 |
<a id="property-metadata"></a> metadata? | readonly | JsonObject | - | packages/adapters/src/harness.ts:38 |
<a id="property-prompt-1"></a> prompt | readonly | string | - | packages/adapters/src/harness.ts:33 |
<a id="property-tools"></a> tools | readonly | JsonValue | The permission-filtered catalogue, already in the harness's own shape. | packages/adapters/src/harness.ts:35 |
ModelClient
Defined in: packages/adapters/src/model/client.ts:91
A model API in the SharedOS driver seat.
Deliberately narrower than any provider SDK: one call, tools in, tool calls out. Everything that decides whether a call is allowed to happen -- the catalogue, the turn loop, per-call re-authorization, audit -- stays in the execution envelope, so a second provider is a second implementation of this interface and no new enforcement path.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-model-2"></a> model | readonly | string | The model this client was configured to ask for. | packages/adapters/src/model/client.ts:93 |
<a id="property-provider-2"></a> provider | readonly | string | The provider that serves it, recorded alongside the model on every turn. | packages/adapters/src/model/client.ts:95 |
Methods
complete()
complete(
request,signal):Promise<ModelReply>>
Defined in: packages/adapters/src/model/client.ts:96
Parameters
| Parameter | Type |
|---|---|
request | ModelCompletionRequest |
signal | AbortSignal |
Returns
Promise<ModelReply>
ModelCompletionRequest
Defined in: packages/adapters/src/model/client.ts:44
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-messages"></a> messages | readonly | readonly ModelMessage[] | packages/adapters/src/model/client.ts:45 |
<a id="property-tools-1"></a> tools | readonly | readonly ModelTool[] | packages/adapters/src/model/client.ts:46 |
ModelDriverOptions
Defined in: packages/adapters/src/model/driver.ts:88
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-client"></a> client | readonly | ModelClient | - | packages/adapters/src/model/driver.ts:90 |
<a id="property-declarestep-1"></a> declareStep? | readonly | (index, request) => number | undefined | The step to declare for the nth call this turn releases, if any. Returning undefined -- the default for every call -- leaves the step to the loop, which is what a driver asking for one call at a time should do. It exists for the one thing a driver cannot otherwise express: reaching past its own budget. The loop's index stops at maxSteps, so a call at or past the ceiling can only be made by a driver that names the step itself. Supplying this makes the driver the attacker for that call, which is a different claim from the model choosing it, and a column that uses it should say so rather than letting the row read as a model's doing. | packages/adapters/src/model/driver.ts:115 |
<a id="property-manifest-6"></a> manifest | readonly | object | - | packages/adapters/src/model/driver.ts:89 |
manifest.id | public | string | - | packages/contracts/dist/runtime.d.ts:9 |
manifest.metadata? | public | JsonObject | - | packages/contracts/dist/runtime.d.ts:12 |
manifest.protocolVersion | public | "1" | - | packages/contracts/dist/runtime.d.ts:11 |
manifest.version | public | string | - | packages/contracts/dist/runtime.d.ts:10 |
<a id="property-maxmalformedcalls"></a> maxMalformedCalls? | readonly | number | Guard against a model that never forms a readable call. A call whose arguments do not parse is refused by the driver and answered back to the model, which costs the turn no step; a model that kept producing them would otherwise be spoken to until the turn timed out. Past this many in one turn, the turn fails instead. | packages/adapters/src/model/driver.ts:101 |
<a id="property-prompt-2"></a> prompt? | readonly | (request) => string | Overrides how the turn message becomes the model's prompt. | packages/adapters/src/model/driver.ts:92 |
ModelReply
Defined in: packages/adapters/src/model/client.ts:56
What the model answered with.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-finishreason"></a> finishReason? | readonly | string | Why generation stopped, in the provider's own vocabulary. stop and tool_calls are the model ending its reply; length is the provider ending it at the output-token ceiling. Carried because the two are different facts about the same reply: a completion that was cut off mid-way looks, without this, exactly like a completion the model chose to end, and a record whose purpose is honest attribution has to tell them apart. | packages/adapters/src/model/client.ts:68 |
<a id="property-model-3"></a> model? | readonly | string | The model the provider says actually answered. Recorded separately from the one that was asked for because they differ: DeepSeek maps an unrecognised name onto a default rather than rejecting it, so a run configured for one model can be served by another. The record should say what answered, which is the weaker claim and the honest one. | packages/adapters/src/model/client.ts:79 |
<a id="property-text"></a> text | readonly | string | - | packages/adapters/src/model/client.ts:57 |
<a id="property-toolcalls"></a> toolCalls | readonly | readonly ModelToolCall[] | - | packages/adapters/src/model/client.ts:58 |
<a id="property-usage"></a> usage? | readonly | ModelUsage | Absent when the provider reported no usage; never estimated. | packages/adapters/src/model/client.ts:70 |
ModelTool
Defined in: packages/adapters/src/model/client.ts:21
A tool offered to the model, already rendered into the provider's alphabet.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-description"></a> description | readonly | string | packages/adapters/src/model/client.ts:23 |
<a id="property-name-1"></a> name | readonly | string | packages/adapters/src/model/client.ts:22 |
<a id="property-parameters"></a> parameters | readonly | JsonObject | packages/adapters/src/model/client.ts:24 |
ModelToolCall
Defined in: packages/adapters/src/model/client.ts:14
One tool call a model asked for, exactly as it came off the wire.
The name is the provider's alphabet, not SharedOS's, and the arguments are still an unparsed string. Neither is normalised here: a client's job is to carry what the model said, and deciding what an unparseable argument blob or an unrecognised name means is a policy question that belongs to the driver.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-arguments"></a> arguments | readonly | string | packages/adapters/src/model/client.ts:17 |
<a id="property-id-1"></a> id | readonly | string | packages/adapters/src/model/client.ts:15 |
<a id="property-name-2"></a> name | readonly | string | packages/adapters/src/model/client.ts:16 |
ModelTranscript
Defined in: packages/adapters/src/model/transcript.ts:11
A model conversation, supplied by its caller.
One reply per model call. The first reply answers the opening prompt, and each later reply is released only once every tool call in the reply before it has been answered -- which is what the driver already requires of a live provider, so a transcript exercises the same code path a live model does.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-replies"></a> replies | readonly | readonly ModelReply[] | packages/adapters/src/model/transcript.ts:12 |
ModelUsage
Defined in: packages/adapters/src/model/client.ts:50
What a provider billed for one reply, when it said.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
<a id="property-inputtokens"></a> inputTokens? | readonly | number | packages/adapters/src/model/client.ts:51 |
<a id="property-outputtokens"></a> outputTokens? | readonly | number | packages/adapters/src/model/client.ts:52 |
OpenAiCompatibleModelClientOptions
Defined in: packages/adapters/src/model/client.ts:150
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-apikey"></a> apiKey | readonly | string | - | packages/adapters/src/model/client.ts:151 |
<a id="property-baseurl"></a> baseUrl | readonly | string | The chat-completions root, without a trailing slash. | packages/adapters/src/model/client.ts:156 |
<a id="property-fetch"></a> fetch? | readonly | {(input, init?): Promise<Response>; (input, init?): Promise<Response>; } | Injected for tests, which must never reach a network. | packages/adapters/src/model/client.ts:168 |
<a id="property-maxoutputtokens"></a> maxOutputTokens? | readonly | number | - | packages/adapters/src/model/client.ts:157 |
<a id="property-model-4"></a> model | readonly | string | - | packages/adapters/src/model/client.ts:152 |
<a id="property-provider-3"></a> provider | readonly | string | Names the provider on every record this client's turns produce. | packages/adapters/src/model/client.ts:154 |
<a id="property-requesttimeoutms"></a> requestTimeoutMs? | readonly | number | How long one model call may take, independently of the turn's own budget. | packages/adapters/src/model/client.ts:166 |
<a id="property-temperature"></a> temperature? | readonly | number | Left at zero by default, which reduces variation between runs but does not remove it. This column is not deterministic and must not be described as if it were: a temperature of zero is not a seed, and the same prompt can still produce a different call sequence on a different day. | packages/adapters/src/model/client.ts:164 |
TranscriptModelClientOptions
Defined in: packages/adapters/src/model/transcript.ts:15
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
<a id="property-model-5"></a> model? | readonly | string | What the record names as the model; defaults to transcript. | packages/adapters/src/model/transcript.ts:17 |
<a id="property-provider-4"></a> provider? | readonly | string | What the record names as the provider; defaults to transcript. | packages/adapters/src/model/transcript.ts:19 |
Type Aliases
ClaudeCodeDriverOptions
ClaudeCodeDriverOptions =
Omit<HarnessDriverOptions,"manifest"|"protocol"> > &object
Defined in: packages/adapters/src/claude-code/index.ts:38
Type Declaration
manifest?
readonlyoptionalmanifest?:RuntimeManifest
transport
readonlytransport:HarnessTransport
CodexDriverOptions
CodexDriverOptions =
Omit<HarnessDriverOptions,"manifest"|"protocol"> > &object
Defined in: packages/adapters/src/codex/index.ts:38
Type Declaration
manifest?
readonlyoptionalmanifest?:RuntimeManifest
transport
readonlytransport:HarnessTransport
DeepseekDriverOptions
DeepseekDriverOptions =
Omit<HarnessDriverOptions,"manifest"|"protocol"> > &object
Defined in: packages/adapters/src/deepseek/index.ts:45
Type Declaration
manifest?
readonlyoptionalmanifest?:RuntimeManifest
transport
readonlytransport:HarnessTransport
HarnessFrame
HarnessFrame =
JsonObject
Defined in: packages/adapters/src/harness.ts:11
One raw protocol frame, in whatever shape the harness speaks.
HarnessStep
HarnessStep = {
arguments:JsonObject;callId:string;tool:string;type:"tool_call"; } | {text:string;type:"message"; } | {metadata?:JsonObject;output?:JsonValue;type:"complete"; } | {error:ProtocolError;type:"failed"; }
Defined in: packages/adapters/src/harness.ts:19
What one frame means once the vendor protocol has interpreted it.
message is assistant prose. It is kept rather than discarded so a harness
whose terminal frame carries no text still produces a turn output.
ModelMessage
ModelMessage = {
content:string;role:"system"|"user"; } | {content:string;role:"assistant";toolCalls: readonlyModelToolCall[]; } | {content:string;role:"tool";toolCallId:string; }
Defined in: packages/adapters/src/model/client.ts:35
One turn of conversation.
assistant carries the tool calls the model asked for and tool carries one
result back, because a chat-completions provider requires the pair to appear
in that order and requires every call in an assistant message to be answered
before the next one is sent.
PiDriverOptions
PiDriverOptions =
Omit<HarnessDriverOptions,"manifest"|"protocol"> > &object
Defined in: packages/adapters/src/pi/index.ts:49
Type Declaration
manifest?
readonlyoptionalmanifest?:RuntimeManifest
transport
readonlytransport:HarnessTransport
Variables
CLAUDE_CODE_ADAPTER_VERSION
constCLAUDE_CODE_ADAPTER_VERSION:"0.1.0-alpha.3"="0.1.0-alpha.3"
Defined in: packages/adapters/src/claude-code/index.ts:15
CLAUDE_CODE_HARNESS_ID
constCLAUDE_CODE_HARNESS_ID:"claude-code"
Defined in: packages/adapters/src/claude-code/index.ts:13
The id this harness goes by everywhere: manifests, requirements, MCP specs, scripts.
CLAUDE_CODE_PROTOCOL_ID
constCLAUDE_CODE_PROTOCOL_ID:"anthropic.messages.stream-json"="anthropic.messages.stream-json"
Defined in: packages/adapters/src/claude-code/protocol.ts:15
Claude Code speaks Anthropic message content blocks inside a stream-json envelope.
The content blocks -- tool_use, tool_result, text -- are the stable
part and are what this module translates. The {type:"assistant"|"user"| "result"} envelope is the CLI's --output-format stream-json framing.
CLAUDE_CODE_REQUIREMENTS
constCLAUDE_CODE_REQUIREMENTS:HarnessRequirements
Defined in: packages/adapters/src/claude-code/index.ts:30
What a live Claude Code session needs before it can run.
CLAUDE_CODE_RUNTIME_MANIFEST
constCLAUDE_CODE_RUNTIME_MANIFEST:RuntimeManifest
Defined in: packages/adapters/src/claude-code/index.ts:17
claudeCodeFrameWriter
constclaudeCodeFrameWriter:HarnessFrameWriter
Defined in: packages/adapters/src/writer.ts:58
Frames in the Anthropic content-block shape Claude Code speaks.
claudeCodeProtocol
constclaudeCodeProtocol:HarnessProtocol
Defined in: packages/adapters/src/claude-code/protocol.ts:48
CODEX_ADAPTER_VERSION
constCODEX_ADAPTER_VERSION:"0.1.0-alpha.3"="0.1.0-alpha.3"
Defined in: packages/adapters/src/codex/index.ts:15
CODEX_HARNESS_ID
constCODEX_HARNESS_ID:"codex"
Defined in: packages/adapters/src/codex/index.ts:13
The id this harness goes by everywhere: manifests, requirements, MCP specs, scripts.
CODEX_PROTOCOL_ID
constCODEX_PROTOCOL_ID:"openai.responses.function-calling"="openai.responses.function-calling"
Defined in: packages/adapters/src/codex/protocol.ts:18
Codex speaks the OpenAI Responses function-calling shape.
That is the layer this module targets: function tool declarations,
function_call items, and function_call_output results. It is deliberately
not the Codex CLI's own event envelope, which differs between releases. What
carries these frames -- the CLI in JSON mode, the Codex SDK, or a direct
Responses call -- is the transport's problem, not the protocol's.
CODEX_REQUIREMENTS
constCODEX_REQUIREMENTS:HarnessRequirements
Defined in: packages/adapters/src/codex/index.ts:30
What a live Codex session needs before it can run.
CODEX_RUNTIME_MANIFEST
constCODEX_RUNTIME_MANIFEST:RuntimeManifest
Defined in: packages/adapters/src/codex/index.ts:17
codexFrameWriter
constcodexFrameWriter:HarnessFrameWriter
Defined in: packages/adapters/src/writer.ts:31
Frames in the OpenAI Responses function-calling shape Codex speaks.
codexProtocol
constcodexProtocol:HarnessProtocol
Defined in: packages/adapters/src/codex/protocol.ts:66
DEEPSEEK_ADAPTER_VERSION
constDEEPSEEK_ADAPTER_VERSION:"0.1.0-alpha.3"="0.1.0-alpha.3"
Defined in: packages/adapters/src/deepseek/index.ts:15
DEEPSEEK_HARNESS_ID
constDEEPSEEK_HARNESS_ID:"deepseek"
Defined in: packages/adapters/src/deepseek/index.ts:13
The id this harness goes by everywhere: manifests, requirements, MCP specs, scripts.
DEEPSEEK_PROTOCOL_ID
constDEEPSEEK_PROTOCOL_ID:"deepseek.harness.session-events"="deepseek.harness.session-events"
Defined in: packages/adapters/src/deepseek/protocol.ts:27
DeepSeek Harness speaks its own session-log vocabulary over a newline-delimited JSON-RPC 2.0 stdio transport.
That vocabulary is the layer this module targets: tool/call carrying the
model's raw argument string, assistant/message carrying assembled content
blocks, and turn/end carrying a structured reason. It is deliberately not
the dsh CLI's command-line surface, which is a plugin composition that
varies per deployment. What carries these frames -- the SDK runtime server,
the ACP bridge, or a recorded log -- is the transport's problem.
One asymmetry is worth stating plainly, because it is a property of the
harness rather than of this adapter. DeepSeek Harness executes its own tools:
its wire has no frame meaning "here is your catalogue". A host that wants the
catalogue to be the permission-filtered one must deliver it out of band, and
the harness's own path for that is an MCP server (dsh-mcp-client). So
HarnessProtocol.describeTools renders the harness's ToolSchema shape, which is what
that out-of-band channel carries, and no frame is emitted for it.
DEEPSEEK_REQUIREMENTS
constDEEPSEEK_REQUIREMENTS:HarnessRequirements
Defined in: packages/adapters/src/deepseek/index.ts:37
What a live DeepSeek Harness session needs before it can run.
DEEPSEEK_RUNTIME_MANIFEST
constDEEPSEEK_RUNTIME_MANIFEST:RuntimeManifest
Defined in: packages/adapters/src/deepseek/index.ts:17
deepseekFrameWriter
constdeepseekFrameWriter:HarnessFrameWriter
Defined in: packages/adapters/src/writer.ts:92
Frames in the session-log shape DeepSeek Harness streams.
Wrapped in their session.event notification rather than left bare, because
that is the shape a live SDK runtime emits and a fixture that skipped the
envelope would exercise only half of what the parser has to accept.
deepseekProtocol
constdeepseekProtocol:HarnessProtocol
Defined in: packages/adapters/src/deepseek/protocol.ts:107
PI_ADAPTER_VERSION
constPI_ADAPTER_VERSION:"0.1.0-alpha.3"="0.1.0-alpha.3"
Defined in: packages/adapters/src/pi/index.ts:15
PI_HARNESS_ID
constPI_HARNESS_ID:"pi"
Defined in: packages/adapters/src/pi/index.ts:13
The id this harness goes by everywhere: manifests, requirements, MCP specs, scripts.
PI_PROTOCOL_ID
constPI_PROTOCOL_ID:"pi.rpc.jsonl"="pi.rpc.jsonl"
Defined in: packages/adapters/src/pi/protocol.ts:30
Pi speaks newline-delimited JSON events in its RPC mode (pi --mode rpc).
The message vocabulary is the layer this module targets: an AssistantMessage
whose content carries toolCall blocks, a ToolResultMessage carrying the
result back, and the agent_end / response frames that end a turn. It is
deliberately not Pi's streaming delta events, which restate the same content
token by token; Pi's own guidance is to treat the assembled message as
authoritative, and reading both would issue every call twice.
Two asymmetries are worth stating plainly, because both are properties of the harness rather than of this adapter:
- Pi does not declare tools on the RPC wire, and ships no MCP client of its
own. Its path for a host-supplied tool is
defineToolthrough the SDK, or an extension such aspi-mcp-adapter, which is how the MCP column reaches it; HarnessProtocol.describeTools renders thedefineToolshape and no frame is emitted for it. - Pi executes its own tools.
tool_execution_startannounces a call Pi is already running, not a request for the host to run one, so it is not read as a tool call. ThetoolCallcontent block -- the model's actual request -- is.
PI_REQUIREMENTS
constPI_REQUIREMENTS:HarnessRequirements
Defined in: packages/adapters/src/pi/index.ts:37
What a live Pi session needs before it can run.
PI_RUNTIME_MANIFEST
constPI_RUNTIME_MANIFEST:RuntimeManifest
Defined in: packages/adapters/src/pi/index.ts:17
piFrameWriter
constpiFrameWriter:HarnessFrameWriter
Defined in: packages/adapters/src/writer.ts:135
Frames in the RPC message shape Pi speaks.
piProtocol
constpiProtocol:HarnessProtocol
Defined in: packages/adapters/src/pi/protocol.ts:86
Functions
createClaudeCodeDriver()
createClaudeCodeDriver(
options):HarnessDriver
Defined in: packages/adapters/src/claude-code/index.ts:50
Claude Code as a SharedOS agent turn driver.
As with Codex, the adapter translates and nothing else. Enforcement stays in the execution envelope, so installing a second harness changes no kernel code and adds no second permission path.
Parameters
| Parameter | Type |
|---|---|
options | ClaudeCodeDriverOptions |
Returns
createClaudeCodeRuntime()
createClaudeCodeRuntime(
options,runtimeOptions?):HarnessRuntime
Defined in: packages/adapters/src/claude-code/index.ts:65
Claude Code as an installable runtime, reporting its own manifest.
Prefer this over wrapping the driver in StandardRuntime directly: the
executor stamps the plugin's manifest onto every execution record, so only
this form files a turn's evidence under the harness that produced it.
Parameters
| Parameter | Type |
|---|---|
options | ClaudeCodeDriverOptions |
runtimeOptions | StandardRuntimeOptions |
Returns
createCodexDriver()
createCodexDriver(
options):HarnessDriver
Defined in: packages/adapters/src/codex/index.ts:50
Codex as a SharedOS agent turn driver.
The adapter is translation only. Install it with StandardRuntime, and the
turn loop, the permission-filtered catalogue, per-call re-authorization, and
audit all come from the SharedOS execution envelope unchanged.
Parameters
| Parameter | Type |
|---|---|
options | CodexDriverOptions |
Returns
createCodexRuntime()
createCodexRuntime(
options,runtimeOptions?):HarnessRuntime
Defined in: packages/adapters/src/codex/index.ts:65
Codex as an installable runtime, reporting its own manifest.
Prefer this over wrapping the driver in StandardRuntime directly: the
executor stamps the plugin's manifest onto every execution record, so only
this form files a turn's evidence under the harness that produced it.
Parameters
| Parameter | Type |
|---|---|
options | CodexDriverOptions |
runtimeOptions | StandardRuntimeOptions |
Returns
createDeepseekDriver()
createDeepseekDriver(
options):HarnessDriver
Defined in: packages/adapters/src/deepseek/index.ts:57
DeepSeek Harness as a SharedOS agent turn driver.
As with Codex and Claude Code, the adapter translates and nothing else. Enforcement stays in the execution envelope, so installing a third harness changes no kernel code and adds no second permission path.
Parameters
| Parameter | Type |
|---|---|
options | DeepseekDriverOptions |
Returns
createDeepseekRuntime()
createDeepseekRuntime(
options,runtimeOptions?):HarnessRuntime
Defined in: packages/adapters/src/deepseek/index.ts:72
DeepSeek Harness as an installable runtime, reporting its own manifest.
Prefer this over wrapping the driver in StandardRuntime directly: the
executor stamps the plugin's manifest onto every execution record, so only
this form files a turn's evidence under the harness that produced it.
Parameters
| Parameter | Type |
|---|---|
options | DeepseekDriverOptions |
runtimeOptions | StandardRuntimeOptions |
Returns
createPiDriver()
createPiDriver(
options):HarnessDriver
Defined in: packages/adapters/src/pi/index.ts:61
Pi as a SharedOS agent turn driver.
As with every other harness here, the adapter translates and nothing else. Enforcement stays in the execution envelope, so installing a fourth harness changes no kernel code and adds no second permission path.
Parameters
| Parameter | Type |
|---|---|
options | PiDriverOptions |
Returns
createPiRuntime()
createPiRuntime(
options,runtimeOptions?):HarnessRuntime
Defined in: packages/adapters/src/pi/index.ts:76
Pi as an installable runtime, reporting its own manifest.
Prefer this over wrapping the driver in StandardRuntime directly: the
executor stamps the plugin's manifest onto every execution record, so only
this form files a turn's evidence under the harness that produced it.
Parameters
| Parameter | Type |
|---|---|
options | PiDriverOptions |
runtimeOptions | StandardRuntimeOptions |
Returns
parseToolArguments()
parseToolArguments(
raw):JsonObject|undefined
Defined in: packages/adapters/src/internal.ts:45
Argument blobs are model or harness output, so they are parsed rather than
trusted: an empty blob is an empty object, anything that is not a JSON
object is refused as undefined.
Parameters
| Parameter | Type |
|---|---|
raw | string |
Returns
JsonObject | undefined