FabricFabricHarness
Building Agents

Sessions and Prompts

agent.session(), session.prompt(), and the harness loop.

A session is a persisted message/context thread. Inside a session, you can run prompts, skills, tasks, and shell commands.

Create a session

const fabricAgent = await init();
const session = await fabricAgent.session();           // new id
const resumed  = await fabricAgent.session('s-001');   // resume by id
const scoped   = await fabricAgent.session('s-002', {
  role: 'engineer',
  model: 'openai/gpt-5.5',
  cwd: 'project',
});

session.prompt(text, options?)

Run one harness loop turn — a single user prompt that may produce assistant messages, tool calls, and shell commands until the model returns a final answer.

const answer = await session.prompt('What is Temporal?');

Typed results

Use result to validate and type the return value. The framework asks the model for a typed object and validates it against the schema.

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

const triage = await session.prompt('Triage this issue', {
  result: schema.object({
    severity: schema.enum(['low', 'medium', 'high', 'critical']),
    summary: schema.string(),
    recommendedLabels: schema.array(schema.string()),
  }),
});

Streaming

for await (const event of session.stream('Tell me about Temporal')) {
  if (event.type === 'text_delta') process.stdout.write(event.text);
}

Working directories

Set cwd at agent, session, prompt/skill/task, or shell scope. Relative cwd values are resolved inside the sandbox and cannot escape the sandbox workspace.

const fabricAgent = await init({ cwd: 'project' });
const session = await fabricAgent.session();

await session.shell('npm install');          // runs in /workspace/project
await session.shell('npm test', { cwd: 'ui' }); // runs in /workspace/project/ui

await session.prompt('Inspect the UI package', { cwd: 'ui' });
await session.skill('review', { cwd: 'api', args: { focus: 'routes' } });
await session.task('Refactor tests', { cwd: 'packages/core' });

File tools (read, write, grep, glob) use the same scoped cwd during prompts/skills/tasks, so coding agents can work in a repository subdirectory without repeating absolute paths.

Tools and commands

import { defineCommand } from '@fabric-harness/node';

const npm = defineCommand('npm');
const git = defineCommand('git');

await session.prompt('Run the failing tests and propose a fix', {
  commands: [npm, git],
  // tools: optional override of built-in tools
});

See Tools and Commands.

session.skill(name, options?)

Invoke a Markdown skill from .fabricharness/skills/<name>/SKILL.md. Args interpolate into the skill body, and result validates the typed return value.

const triage = await session.skill('triage-issue', {
  args: { issueNumber: 42, repository: 'octocat/repo' },
  commands: [gh],
  result: schema.object({
    severity: schema.enum(['low', 'medium', 'high', 'critical']),
  }),
});

session.task(text, options?)

Spawn a child task. Tasks are durable when the session runs on the Temporal worker target.

const result = await session.task('Refactor the authentication middleware', {
  id: 'refactor-auth',
  result: schema.object({ filesChanged: schema.array(schema.string()) }),
});

session.shell(command, options?)

Execute a shell command in the session's sandbox.

const out = await session.shell('npm test', { cwd: '/workspace' });

Session history

const history = await session.history();
// { id, createdAt, updatedAt, entries, events }

The CLI's fh inspect, fh logs, and fh metrics are wrappers around this same data.