SDK

Find the public TypeScript entry points for building and hosting Tardigrade actors.

Install

bun add tardie

Choose an entrypoint for the API you need:

text
tardie/core                  atoms, actors, runtime, state initialisation
tardie/agent                 agent authoring
tardie/agent/services        execution and wiring
tardie/libraries             RPC libraries and built-in methods
tardie/model                 model configuration and provider layers
tardie/code                  code execution and sandboxes
tardie/platform/bun          Bun hosting and storage
tardie/platform/cloudflare   Cloudflare hosting and storage
tardie/deprecated            component APIs

Author an actor

Core primitives and runtime APIs share a flat entrypoint. State codecs and initialisation are available from the same module:

ts
import { AtomState, actorMethod, defineActor, durableAtom, event, initialiseState, type InitialState } from "tardie/core"
import { agentMethods, messages, infer } from "tardie/agent"
import { defineLibrary } from "tardie/libraries"

State initialisation shows how to create a thread from an existing actor's state.

Thread methods

Call declared actor methods through thread.methods. Thread controls such as invoke, result, cancel, and getState remain on the thread handle. Actor method names can match thread control names because the callable methods occupy a separate namespace.

ts
const output = yield* thread.methods.message({ text: "Hello" }, { id: "message-1" })
const receipt = yield* thread.invoke("message", { text: "Hello" }, { id: "message-2" })
const state = yield* thread.result("message", receipt.id)

Libraries

A library names a list of Effect RPC methods. Each method declares its payload, success, and error schemas. Attach descriptions, MCP-compatible behaviour hints, and execution mode as RPC annotations:

ts
import { Effect, Schema } from "effect"
import { Rpc } from "effect/unstable/rpc"
import { defineLibrary, MethodDescription, MethodHints } from "tardie/libraries"

const notes = defineLibrary({
  name: "notes",
  description: "Read research notes.",
  methods: [
    Rpc.make("read", {
      payload: Schema.Struct({ key: Schema.String }),
      success: Schema.String,
      error: Schema.String,
    })
      .annotate(MethodDescription, "Read a note by key.")
      .annotate(MethodHints, { readOnlyHint: true, openWorldHint: false }),
  ],
})

const notesLive = notes.implement({
  read: ({ key }) => Effect.succeed(`Note: ${key}`),
})

notes.methods is an ordinary RpcGroup, so it can also supply handlers to an Effect RPC server. Library adapters support unary methods without RPC middleware and schemas that decode payloads and encode results without services. They validate input before calling a handler and encode its output with the declared success schema.

MethodHints supports MCP's readOnlyHint, destructiveHint, idempotentHint, openWorldHint, and optional title. Hints describe behaviour; permission policy controls execution. Treat annotations from remote, untrusted servers as untrusted data.

MethodExecution accepts "foreground" or "background"; DEFAULT_METHOD_EXECUTION is "foreground". Foreground calls wait for a result and may perform asynchronous I/O. Background calls return durable handles. For handlers that submit work to another executor, mark the RPC as background, declare ExecutionHandle as its success schema, and pass { submit: ["methodName"] } to implement. Optional cancellation handlers use the same method names. Code mode accepts foreground methods.

Choose how to expose the configured libraries:

ts
import { arxiv, workspace } from "tardie/libraries"
import { tools, codeMode } from "tardie/agent"

const libraries = [arxiv(), workspace()]
const directTools = tools(libraries)
const researchCode = codeMode(libraries)

Yield the chosen Effect during actor setup. Supply matching implementations in host services with toolActs(libraries) for direct tools or codeModeActs(libraries) for code mode. Both atoms also accept the host's full catalog when no library selection is supplied. Missing or duplicate selected library names fail during setup. Built-ins include arxiv, fetch, workspace, agents, and alarm.

arxiv().search is exposed as arxiv.search inside code mode and arxiv__search as a direct tool. It returns the arXiv Atom XML feed with its source URL and applied pagination. DEFAULT_ARXIV_POLICY supplies pagination defaults; override them when constructing the library or per search call. DEFAULT_ARXIV_ENDPOINT can also be overridden. Applications own request pacing according to the arXiv API guidance.

Host and services

Import hosting separately from actor definitions. Agent implementations live in the services entrypoint:

ts
import { createBunHost } from "tardie/platform/bun"
import { runtimeLayer } from "tardie/agent/services"
import { modelLayer } from "tardie/model"
import { providerLayer } from "tardie/model/providers/openrouter"

For Cloudflare, import createActorWorker from tardie/platform/cloudflare and export its ActorObject and ThreadObject classes as ActorDO and ThreadDO. Each instance directory and each thread own separate SQLite databases. Use createActorObject and createThreadObject separately for custom Worker routing. Provider modules have individual entrypoints so applications can choose their provider dependencies.

Pass a fully provided Effect telemetry layer as telemetry to any host. The layer is inherited by host-managed fibers, actor runtimes, commit logging, and recovery work. Effect 4 exposes OTLP integrations from effect/unstable/observability; provide their HTTP client and serialization dependencies in the application layer before passing it to the host.

ts
import { createActorWorker } from "tardie/platform/cloudflare"
import { telemetryLayer } from "./telemetry"

const worker = createActorWorker({ actor, services, telemetry: telemetryLayer })

HTTP errors

Platform HTTP adapters return failures as { code, message }. The code is stable for programmatic handling and message is safe to show to callers. Internal causes stay in the Effect log and are not included in the response.

json
{
  "code": "actor_commit_failed",
  "message": "Actor state could not be persisted; recreate the actor store before retrying"
}

Applications should branch on code and treat message as descriptive text. Unknown failures use internal_error so implementation details do not cross the HTTP boundary.

Component APIs

Component actors use the compatibility entrypoints:

ts
import { actor } from "tardie/deprecated/core"
import { agentMethods, infer, system, tool } from "tardie/deprecated/agent"
import { createBunHost } from "tardie/deprecated/bun"

The package has no API at bare tardie. Source folders inside core and agent are private; use their flat entrypoints.