Skip to content

Adapter guide

Spacecraft is designed so the runtime components you swap most often — inference backend, memory strategy, inbound channel, vector store, tool dispatcher — are pluggable adapters, registered by ID and resolved at launch. This page is the authoritative reference; the canonical source is packages/spacecraft/cli/ADAPTERS.md.

The stable SDK entry point is celestial-cli/sdk. It exports the registration helpers plus matching list* / get* helpers for inference, memory, tool, gateway, and vector-DB adapters:

import {
registerInferenceAdapter,
registerMemoryAdapter,
registerToolHandler,
registerGatewayAdapter,
registerVectorDbProvider,
} from 'celestial-cli/sdk'

Starter template: packages/spacecraft/cli/examples/custom-adapter-plugin.ts.

Unified capability catalog (sc capabilities)

Section titled “Unified capability catalog (sc capabilities)”

Per ADR-030, sc capabilities lists everything pluggable in one view: inference adapters, memory adapters, harness tool types (bash, http, js), gateway adapters (telegram, http), vector-DB providers (chroma today), depot models, registered spacecraft packages, and skills.

Terminal window
sc capabilities # human-readable
sc capabilities --json # machine-readable, catalogVersion: "capabilities/v0"

sc adapters is the narrower legacy view — inference + memory only.

Remote catalog overlays (Supabase, ADR-031)

Section titled “Remote catalog overlays (Supabase, ADR-031)”

When Supabase URL + key env vars are set, sc capabilities merges remote rows from spacecraft_catalog_capabilities (migration packages/supabase/migrations/003_spacecraft_catalog_capabilities.sql) into the local catalog.

VariableRole
CELESTIAL_CATALOG_SUPABASE_URLSupabase URL (falls back to SUPABASE_URL).
CELESTIAL_CATALOG_SUPABASE_SERVICE_ROLE_KEY / _ANON_KEYAPI key (falls back to the matching SUPABASE_* env vars). Anon works with the migration’s SELECT RLS policy.
CELESTIAL_CATALOG_MERGE_MODEoff — no network. enrich — overlay display_name, drop ids with enabled = false. restrict — per kind, if any row exists, only listed enabled ids remain (intersected with local). Default enrich when URL+key exist.

Upsert overlays with sc catalog sync:

Terminal window
sc catalog sync ./catalog-overlays.yaml --dry-run
sc catalog sync ./catalog-overlays.yaml

Starter file: packages/spacecraft/cli/examples/catalog-overlays.yaml.

Accepted shapes: top-level array of rows, or { rows: [...] }. Row schema:

  • kind: inference | memory | tool | gateway | vectordb
  • capability_id: string (required)
  • display_name: string | null
  • enabled: boolean (default true)
  • metadata: object

Overlays affect discovery (what sc capabilities and wizards see). They do not change ToolExecutor wiring — executables are still resolved from in-process registries.

Resolved by ID through src/orchestrator/adapters/factory.ts.

Built-in IDs: vercel-ai, default (alias of vercel-ai).

Selection order at runtime:

  1. CLI: sc launch --adapter <id>
  2. Agent-level config: inference_adapter
  3. Blueprint-level config: inference.adapter
  4. Default: vercel-ai
import { registerInferenceAdapter } from './src/orchestrator/adapters/factory'
registerInferenceAdapter('my-adapter', ({ defaultBaseUrl }) => ({
async generate(agent, messages) {
// your provider call
return { reply: 'ok' }
},
getCapabilities() {
return {
supportsTools: false,
supportsStructuredOutput: true,
supportsTierRouting: false,
}
},
}))

Inbound mission traffic (Telegram today, HTTP webhook stub, future channels) is selected from blueprint comm_array[0].adapter and constructed via src/gateway/create-gateway-port.ts. Additional adapters register with registerGatewayAdapter(id, factory).

  • telegram — wraps TelegramCommAdapter (CommAdapterGateway).
  • httpHttpWebhookGateway: POST JSON { "text": "..." } to options.path (default /ingress); optional options.port / SPACECRAFT_HTTP_GATEWAY_PORT; optional options.replyWebhookUrl for outbound replies.

Blueprint shape (only comm_array is read — there is no mouth key):

comm_array:
- adapter: telegram
options:
token_env: TELEGRAM_BOT_TOKEN
chat_id_env: TELEGRAM_CHAT_ID
mode: single-chat

You may also set comm_array to a single object; the loader normalizes it to the array shape.

Set tools_use_sandbox: true on the blueprint (or pass sc launch --tool-sandbox) to dispatch tool calls through SandboxRuntimePort (ADR-027). See src/orchestrator/tool-sandbox.ts.

Harness YAML tools[].type is dispatched through src/orchestrator/tool-registry.ts. Built-ins (bash, http, js) register when ToolExecutor loads. Extensions:

registerToolHandler('my-type', async (tool, args) => {
// ...
})

RAG vector stores are created via src/orchestrator/vectordb/factory.ts, backed by src/orchestrator/vectordb/vector-db-registry.ts. Register new backends with registerVectorDbProvider('id', config => adapter) and extend RagConfig.provider in src/orchestrator/types.ts.

Resolved by ID through src/orchestrator/memory-factory.ts.

Built-in IDs:

  • default
  • standard (alias of default)
  • rag
  • scribe, scribe+standard, scribe+rag — tee turns to .scribe/session.jsonl. Optional scribe_metadata on blueprint memory is merged into every JSONL line’s metadata (use for workspace_id, agent_id, episode_id across multi-agent hosts).

Selection order at runtime:

  1. CLI: sc launch --memory-adapter <id>
  2. Blueprint-level config: memory.adapter
  3. Auto-default: rag when memory.strategy === 'rag'; otherwise default.
import { registerMemoryAdapter } from './src/orchestrator/memory-factory'
registerMemoryAdapter('my-memory', ({ memory }) => ({
async compress(messages, lastUserMessage) {
// your memory policy
return messages
},
}))
  • Keep adapters stateless when possible.
  • Expose capabilities (getCapabilities) for feature gating.
  • Return explicit, typed errors for unsupported features.
  • Avoid side effects in constructors; initialize lazily in generate / compress.