FabricFabricHarness

What is Fabric Harness

A TypeScript framework for building durable, deployable autonomous agents.

Fabric Harness is a TypeScript framework for building durable, deployable autonomous agents. You write agents in .fabricharness/agents/, run them locally for development, and deploy the same code to Node, Docker, a Temporal worker, Cloudflare Workers + Sandbox, or Foundry Hosted Agents on Azure.

Why a framework, not just an SDK

Most agent libraries leave you to wire up the runtime, the build, the dev server, the deployment story, and the durability story yourself. Fabric Harness is opinionated about those things so the agent code stays focused on the work:

  • Workspace conventions.fabricharness/agents, roles/, skills/, policies/, sandboxes/, plus a project AGENTS.md.
  • CLI — discover, run, build, deploy, inspect, replay, and verify everything from one binary (fabric-harness or fh).
  • Runtime adapters — local Node, Docker sandbox, Temporal worker, Cloudflare Workers, Foundry-hosted, more on the way.
  • Headless by default — agents complete autonomously. Approvals are an explicit hook, not a default user prompt.
  • Durable by design — long-running sessions can survive crashes, restarts, retries, and human approval delays via Temporal.
  • Capability-scoped security — commands and tools are explicit, secrets stay out of model context.

Standard agent terminology

Fabric Harness keeps the terms that are converging across the agent ecosystem. You will find these everywhere in the docs:

TermMeaning
AgentA configured autonomous runtime.
SessionA persisted message/context thread.
SkillA reusable Markdown- or code-backed procedure.
RoleA scoped instruction/model profile.
SandboxAn isolated execution environment with filesystem/shell/tools.
TaskA child or delegated agent run.
ToolsModel-callable functions.
CommandsShell-level capabilities exposed to the sandbox.
BuildA compiled, deployable workspace artifact.

SDK entrypoints, runtimes, and targets

Fabric Harness fits both quick prototypes and audited production agents. The key is that SDK entrypoint, runtime, and deploy target are separate choices:

  • Lite SDK entrypoint (@fabric-harness/sdk/lite) keeps the import graph small for headless edge/serverless agents.
  • Full SDK entrypoint (@fabric-harness/sdk) includes everything in Lite plus providers, policies, stores, telemetry, result validation, Docker/remote sandbox helpers, and more.
  • Runtime is stateless, inline, or temporal.
  • Target is where it runs: node, temporal-worker, docker, cloudflare, or another build target.
Lite SDK + stateless runtime: 10 lines, headless
import { defineAgent } from '@fabric-harness/sdk/lite';

export default defineAgent(async ({ init, payload }) => {
  const session = await (await init({ runtime: 'stateless' })).session();
  return { reply: await session.prompt<string>(String((payload as any)?.message ?? '')) };
}, { name: 'echo' });
Full SDK: typed I/O, capability policy, artifacts, skills
import { agent, schema } from '@fabric-harness/sdk';

export default agent({
  name: 'triage',
  input: schema.object({ issueNumber: schema.number(), title: schema.string() }),
  output: schema.object({ severity: schema.enum(['low','medium','high']), summary: schema.string() }),
  run: async ({ init, input }) => {
    const session = await (await init({ policy: triagePolicy })).session();
    return await session.prompt('Triage and return the typed result.');
  },
});

Both examples deploy through the same CLI and use the same init() / session.prompt() / session.skill() / session.task() / session.shell() surface. Start with the Lite SDK if you want fewer imports; move to the Full SDK when you need typed metadata, policy, artifacts, providers, stores, or telemetry. See SDK entrypoints, runtimes, and targets for the full distinction.

Public API surface

const fabricAgent = await init(options);
const session = await fabricAgent.session(id?, options?);

await session.prompt(text, options?);
await session.skill(name, options?);
await session.task(text, options?);
await session.shell(command, options?);

Where to go next