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
});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.