FabricFabricHarness
Getting Started

Your First Agent

Build, describe, and run an agent end-to-end — bare and /strict imports.

This walkthrough builds an ask agent two ways: the default import for headless defaults, and the /strict import when you want every option declared in source (Temporal, compliance/audit, replay-deterministic workloads). Both run through the same CLI and share the same session primitives.

The runtime (stateless, inline, temporal) is configured at init() and is independent of which entrypoint you import from.

Fastest path: fh init

npx @fabric-harness/cli init my-first-agent
cd my-first-agent
npm install
fh dev

fh init scaffolds a runnable agent, role, skill, and config. Skip ahead to step 4 below to test it.

Templates: default (hello), data-analyst (CSV queries), support-agent (knowledge-base), cloudflare (Workers AI binding).

1. Create the workspace (manual)

A Fabric Harness workspace is any directory with a .fabricharness/ folder.

mkdir my-first-agent
cd my-first-agent
mkdir -p .fabricharness/agents
npm init -y
npm install @fabric-harness/sdk @fabric-harness/cli

2. Write the agent

Create .fabricharness/agents/ask.ts:

import { agent } from '@fabric-harness/sdk';

export default agent<{ question: string }>({
  name: 'ask',
  triggers: { webhook: true },
  run: async ({ init, input }) => {
    const session = await (await init()).session();
    return { answer: await session.prompt<string>(input.question) };
  },
});

agent({...}) from the bare @fabric-harness/sdk injects headless defaults (runtime: 'stateless', sandbox: 'virtual' powered by just-bash, the pi-agent-core loop, auto-compaction). Same call shape as @fabric-harness/sdk/strict — switch to strict for Temporal or compliance workloads without changing the body.

import { agent, schema } from '@fabric-harness/sdk/strict';

export default agent({
  name: 'ask',
  description: 'Answers a question using the configured model.',
  input: schema.object({
    question: schema.string().describe('Question to answer'),
  }),
  output: schema.string(),
  model: process.env.FABRIC_MODEL ?? 'openai/gpt-5.5',
  triggers: { webhook: true },
  run: async ({ init, input }) => {
    const fabricAgent = await init({
      runtime: 'inline',
      sandbox: 'local',
      compaction: { enabled: false },
    });
    const session = await fabricAgent.session();
    return await session.prompt(input.question);
  },
});

From /strict every option is declared in source — nothing implicit. Required for Temporal-backed durability and recommended for compliance workloads.

Both forms register a metadata agent (fh describe ask works on either). Either import supports schemas, policy, artifacts, and skills — strict just refuses to inject defaults. triggers.webhook: true exposes the agent at POST /agents/:agent/:id on the Node and Cloudflare server targets.

3. List and describe

From the workspace root:

fh agents
fh describe ask

describe prints the input/output schema, declared model, default target, and any examples. Use --json if you need machine-readable output.

4. Run it

fh run ask --question "What is Temporal?"

Behind the scenes the CLI:

  1. Discovers .fabricharness/agents/ask.ts.
  2. Loads workspace config (.fabricharness/config.ts, optional).
  3. Picks a model — CLI flag → FABRIC_MODEL env → config → agent default.
  4. Validates the input against the declared Fabric schema.
  5. Calls run({ init, input, payload }).
  6. Validates the output against the declared Fabric schema.
  7. Persists the session under .fabricharness/sessions/.

Other ways to pass payload:

fh run ask --payload '{"question":"What is Temporal?"}'
fh run ask question="What is Temporal?"
fh run ask --payload-file input.json
echo '{"question":"hi"}' | fh run ask --stdin

5. Use a real model

Put provider keys once in the repo-level .env.local; Fabric Harness auto-loads repo/workspace .env and .env.local files, and shell env still wins.

cp .env.example .env.local
# edit .env.local and set OPENAI_API_KEY=...
fh run ask --model openai/gpt-5.5 --question "What is Temporal?"

For repeated use, put the model in .fabricharness/config.ts so you do not need --model either.

Never paste API keys into source files or session artifacts. Use .env.local, a secret store, or shell environment variables.

6. Inspect what happened

fh sessions
fh inspect <session-id>
fh logs <session-id>
fh metrics <session-id>

Next steps