@sema-agent/agent-types
v0.3.0
Published
Zero-dependency pure-type mirror of the full Claude Code agent SDK public type surface (options, settings, hooks, session message stream, permissions, MCP, control plane, sessions). No runtime code.
Maintainers
Readme
@sema-agent/agent-types
Zero-dependency, pure-type mirror of the Claude Code agent SDK public type surface. No runtime
code — every file is a hand-maintained .d.ts.
Coverage constitution: mirror the whole surface
Mirror everything upstream exports. Curation is not a policy any more.
Through 0.1.x this package deliberately mirrored only the slice its consumers had already needed. That policy has a standing cost, and it was paid repeatedly: a consumer reaches for a name that is not here, its
switchnarrows toneverin the wrong place, and a localascast or a local widened union goes in to bridge the gap — a workaround that then has to be found and removed later. 0.1.4 spent a whole batch removing exactly that class of workaround after completingSDKMessage(12 arms → 39); 0.2.0 removed six more after completingHookEvent(25 → 31).From 0.2.0 the rule is: every name the upstream
sdk.d.tsexports has a mirror here. A name is only allowed to be absent if a pure.d.tspackage provably cannot carry it, and then it must be recorded — see "Value exports" below.Differences from upstream are allowed in exactly one direction: a sema superset (a value or field the sema shell has positively attested and upstream has not adopted yet). Every such difference carries an
@remarksgiving the evidence coordinate and what would retire it. There is no "we didn't need it yet" exemption.
The rule is enforced, not just written down: scripts/run-agent-types-mirror-test.mjs (in the sema
shell repo) pins the upstream export roster name-by-name, pins the sema-superset names against a
whitelist so the surface cannot silently grow either, and — when pointed at an upstream sdk.d.ts
via SEMA_UPSTREAM_SDK_DTS — checks bidirectional assignability for every shared name against
a recorded expected-direction table.
Value exports
26 of the upstream exports are runtime values (17 functions, 2 classes, 7 constants) — a count the
0.3.232 baseline leaves unchanged, since 0.3.221…0.3.232 added no value export. This package
ships zero runtime bytes, and its exports map declares only a types condition, so re-declaring
those names would type-check and then fail at import — a footgun, not a mirror. Instead each one
gets a type-space companion in runtime.d.ts: query → QueryFn, HOOK_EVENTS →
HookEventsTuple, InMemorySessionStore → InMemorySessionStoreLike, and so on. The companions
are pinned against typeof <upstream value> by the same fence. Import the values themselves from
@anthropic-ai/claude-agent-sdk, which is where they live.
What this package is (and is not)
This package describes the in-process interface shapes of a CC-style agent runtime: the query options and settings surface, the control plane a caller steers a live session through, the hook control-flow contracts, the session message stream vocabulary, the MCP surface, and the permission/decision shapes.
It is deliberately separate from @sema-agent/sdk, and the boundary is constitutional:
@sema-agent/sdktypes describe the@sema-agent/serverwire contract — read-only observation events (AgentEvent): consumers watch, they cannot intercept. The types in this package describe bidirectional control flow — hooks can deny, rewrite inputs/outputs, and inject context, with return-value semantics. These are two different protocol models, not two namings of one thing. Wire types must never be added here; control-flow/rendering-vocabulary types must never be added to@sema-agent/sdk.
Under the tri-client architecture ruling ("B form"), the
messages module additionally serves as the cross-client rendering vocabulary: UI layers that
render CC-model session transcripts (CLI shell, desktop, web, app) share these message shapes,
while their host shells adapt wire frames into them.
Baseline mapping
| package version | mirrors | product baseline | coverage |
| --------------- | ------- | ---------------- | -------- |
| 0.1.0 – 0.1.3 | @anthropic-ai/[email protected] (sdk.d.ts) | Claude Code 2.1.219 | curated subset |
| 0.1.4 | @anthropic-ai/[email protected] (sdk.d.ts) + CC 2.1.220 binary | Claude Code 2.1.220 | SDKMessage complete (39 arms); rest curated |
| 0.2.0 | @anthropic-ai/[email protected] (sdk.d.ts) + CC 2.1.220 binary | Claude Code 2.1.220 | full surface — all 238 upstream exports (212 mirrored 1:1, 26 value-space companions) |
| 0.3.0 | @anthropic-ai/[email protected] (sdk.d.ts) | Claude Code 2.1.232 | full surface — all 240 upstream exports (214 mirrored 1:1, 26 value-space companions) |
Every declaration carries a @since CC 2.1.218 JSDoc tag (or a later version when first
introduced). When the CC baseline moves, new/changed declarations get new tags and this table gets
a new row — consumers can always tell which baseline they are aligned to.
How the 0.3.0
@sincetags were derived. The two baselines are twelve CC releases apart, so tagging everything new as2.1.232would have been wrong for most of the additions — they are spread across eight different releases (2.1.221,.222,.223,.224,.225,.227,.229,.232). Each release in the range that exists on the registry (0.3.221…0.3.229,0.3.231; there is no0.3.230) was fetched and itssdk.d.tsprobed for each new declaration, taking the first version that contains it. Every probe came back contiguous — once present, present in all later versions — so no tag rests on an interpolation. Each version's ownpackage.jsondeclares the matchingclaudeCodeVersion(0.3.N⇒2.1.Nthroughout the range), which is what the tags name.
What moved in 0.3.0
The upstream delta is entirely additive: 2 new exports, 8 changed declarations, 0 removals.
SDKMessage still has exactly 39 arms and HOOK_EVENTS exactly 31 events, so neither exhaustive
switch gained a case.
| where | what | @since |
| ----- | ---- | -------- |
| messages | SDKContextUsage, SDKContextUsageCategory — new exports; the structured twin of the /context report, reached via SDKAssistantMessage.context_usage | CC 2.1.232 |
| messages | SDKSystemMessage.terminal_slash_commands — the terminal-bound subset of slash_commands, for remote UIs to hide | CC 2.1.229 |
| messages | SDKModelRefusalFallbackMessage.scope — distinguishes a session-wide model swap from a subagent-local one | CC 2.1.222 |
| messages | SDKMessageOrigin: new 'unclassified' arm (2.1.223) and 'peer-send-message' subkind (2.1.224) | CC 2.1.223 / 2.1.224 |
| options | Options.resumeDropsTurn — opt-in fork-point validation for truncating resumes; print/headless lane only | CC 2.1.223 |
| options / mcp | OnUserDialog and OnElicitation gained options.requestId and a \| null return (answer the control request out of band). OnUserDialog's no-callback default also changed: an unhandled dialog is now left unanswered rather than auto-cancelled | CC 2.1.225 |
| settings | dialogExpiry, crossSessionInbound | CC 2.1.224 |
| settings | forceLoginGatewayUrl | CC 2.1.227 |
| settings | disableCommandPluginSources; attribution became an open sub-object; new command plugin source | CC 2.1.229 |
| settings | additionalMarketplaces / allowedMarketplaces — aliases of extraKnownMarketplaces / strictKnownMarketplaces | CC 2.1.232 |
| settings | new archive plugin source and unsupported.error | CC 2.1.224 |
| settings | SandboxCredentialsConfig grew the credential-masking surface: files[].mode: 'mask' with extract / onExtractNoMatch / maskDuplicates / injectHosts (2.1.221), then decode / maskClaims on both files and envVars, envVars[].extract / onExtractNoMatch, and the awsPairs + sigv4 SigV4 re-signing policy (2.1.224) | CC 2.1.221 / 2.1.224 |
control, sessions, permissions, misc, dialogs, foreign, runtime and hooks are
unchanged at this baseline. Two upstream edits deliberately produce no mirror change, recorded
so a later re-baseline does not re-litigate them: the zod import became a namespace import
(import { z } → import * as z), and bwrapPath/socatPath widened their zod transform input
from string to string | undefined while the inferred output stays string. The five
constant tuples (EXIT_REASONS, HOOK_EVENTS, ORG_POLICY_LIMIT_PREFIXES, USAGE_*) only
changed quote style upstream, not membership.
settings.d.ts additionally factors the marketplace-source union — which upstream repeats verbatim
at five Settings keys — into three module-local (non-exported) helpers. Upstream does not export
it either, and the module's export {} marker keeps them off the public surface, so the export
roster is unaffected.
Baseline-row correction (0.1.4). Rows through 0.1.3 read "Claude Code 2.1.218" for mirror source 0.3.219. That was wrong:
@anthropic-ai/[email protected]declaresclaudeCodeVersion: "2.1.219"in its ownpackage.json. The mis-mapping produced exactly one wrong tag —FastModeDisabledReasonand the threefast_mode_disabled_reasonfields carrying it are absent from0.3.218and first appear in0.3.219, so they are@since CC 2.1.219, not2.1.218. Every other declaration is present in0.3.218as well, so its@since CC 2.1.218tag stands.0.3.219and0.3.220ship a byte-identicalsdk.d.ts.
Not every declaration's evidence comes from sdk.d.ts. Where the published type surface is
deliberately opaque — a Record<string, unknown> payload whose real shape is defined per-kind
inside the CLI — the mirrored shape is lifted from the CC binary's own runtime validation schema,
and the declaration carries an @remarks recording that evidence coordinate and how far back the
shape holds. dialogs.d.ts is presently the only such module.
Module layout (extension axis)
New CC type domains get new modules; existing module surfaces only grow additively. This keeps future domain additions from ever forcing a breaking split of a single mega-index.
options.d.ts— query construction:Optionsand everything it composes (AgentDefinition,CanUseTool,ThinkingConfig,EffortLevel,OutputFormat,ModelInfo,SpawnedProcess…).settings.d.ts— thesettings.jsonsurface:Settings, the source-precedence vocabulary,ResolvedSettings, and theSandbox*sub-tree.control.d.ts— the control plane:Query,WarmQuery,Transport, and theSDKControlRequest/SDKControlResponse/SDKControl*Responseenvelopes.sessions.d.ts— session persistence:SessionStoreand its key/entry/summary shapes, plus the session CRUD option bags.mcp.d.ts— MCP:McpServerConfig,McpServerStatus,SdkMcpToolDefinition, the elicitation round-trip.hooks.d.ts— bidirectional hook control flow:HookEvent,HookInputunion + per-event inputs,HookJSONOutputfamily. Complete as of 0.2.0 — all 31 upstream events.messages.d.ts— session message stream: theSDKMessagefamily (assistant/user/result/ system/status/progress/compact-boundary…). Complete as of 0.1.4 — all 39 upstream arms.dialogs.d.ts— host-rendered blocking dialogs (request_user_dialog): the opaqueUserDialogRequest/UserDialogResultenvelope plus the per-dialogKindpayload/result shapes this package has positively attested.permissions.d.ts—PermissionMode,PermissionUpdate,PermissionResult,SDKPermissionDenial.misc.d.ts—ModelUsage,ApiKeySource,ExitReason,RewindFilesResult,McpServerConfigForProcessTransport, …runtime.d.ts— type-space companions for the upstream value exports (see above).foreign.d.ts— structural stand-ins for types the upstream surface imports from@anthropic-ai/sdk,@modelcontextprotocol/sdk,zodand Node's builtins. Where the real type is reproducible it is reproduced field-for-field (ForeignToolAnnotations,ForeignCallToolResult,ForeignElicitResult,ForeignJsonRpcMessage,ForeignNodeSignal); where it is a branded runtime class a.d.tsprovably cannot reproduce, the stand-in is deliberately wider and says so. Envelopes are generic over the foreign payload with the stand-in as default — a consumer that has the real@anthropic-ai/sdkcan inject exact types (SDKAssistantMessage<BetaMessage>), everyone else gets a truthful structural default with zero added dependencies.
Fidelity discipline
Shapes are mirrored field-for-field from the upstream reference; renames/omissions are forbidden. Where the sema shell adapts wire frames into these messages, the adapter must keep a field-level round-trip guard (every semantic wire field either maps into the CC message or carries an explicit drop annotation).
Two recorded divergences exist, both one-directional and both carrying their own @remarks. Both
were re-checked against 0.3.232 for the 0.3.0 baseline and both still stand — neither has been
adopted upstream, and neither collides with anything the 0.3.221…0.3.232 range added:
| name | direction | why | 0.3.232 re-check |
| ---- | --------- | --- | ---------------- |
| NonNullableUsage (→ SDKResultSuccess/SDKResultError/SDKResultMessage) | mirror ⊂ upstream | upstream maps over the real BetaUsage; this package maps over the ApiUsage stand-in | unchanged — upstream still maps over BetaUsage |
| SDKRateLimitInfo.overageDisabledReason (→ SDKRateLimitEvent) | mirror ⊃ upstream | carries the sema-attested value org_service_zero_credit_limit, which upstream has not adopted | still absent at [email protected] @4517, whose 13-value list is byte-identical to 0.3.220's — so no new upstream value collides with it |
No divergence was retired at this baseline, and none was added: every one of the 240 upstream exports is mirrored, and the 46 extra names in this package remain exactly the recorded stand-in / value-companion / superset set.
