FabricFabricHarness
Getting Started

Configuration

config.ts, environment variables, and precedence.

Most agents work with zero configuration. When you need defaults across agents — a model, a Temporal address, a session-store backend, a capability policy, a sandbox profile — put them in .fabricharness/config.ts.

.fabricharness/config.ts

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

const config: FabricHarnessConfig = {
  agent: {
    model: 'openai/gpt-5.5',
    // Optional capability policy applied to every agent unless overridden by init():
    policy: {
      commandPolicy: {
        allow: ['git status*', 'git log*', 'gh issue view*'],
        requireApproval: ['gh issue comment*', 'psql*'],
        deny: ['git push*', 'rm -rf*'],
      },
      maxCommandTimeoutMs: 30_000,
      approvals: { requiredApprovals: 1, defaultTimeoutMs: 60_000, risk: 'medium' },
    },
  },
  run: {
    target: 'node',          // 'node' | 'temporal-worker' | 'cloudflare'
    model: 'openai/gpt-5.5',
    idPrefix: 'fab',
    cwd: 'project',          // default sandbox/session cwd for fh run
  },
  temporal: {
    address: 'localhost:7233',
    taskQueue: 'fabric-harness',
    namespace: 'default',
    workflowIdPrefix: 'fabric-cli',
    promptWorkflowMode: 'hybrid',
  },
  sandbox: {
    backend: 'local',         // 'virtual' | 'empty' | 'local' | 'docker' | 'cloudflare'
    metadata: {
      inheritSafeEnv: true,
      envAllowlist: ['GH_TOKEN', 'DATABASE_URL'],
      defaultTimeoutMs: 30_000,
      outputLimitBytes: 256_000,
    },
  },
  store: {
    backend: 'file',          // 'file' | 'sqlite' | 'postgres' | 'cloudflare'
  },
  cloudflare: {
    workerName: 'my-agent',
    routes: [{ pattern: 'api.example.com/agents/*', zoneName: 'example.com' }],
    bindings: {
      kv: [{ binding: 'SESSIONS' }],
      r2: [{ binding: 'KB' }],
      d1: [{ binding: 'DB' }],
    },
  },
};

export default config;

The config is loaded dynamically — you can use TypeScript freely (imports, type checks, conditional logic, etc.).

Precedence

For each setting, the highest source wins:

CLI flag  >  environment variable  >  config.ts  >  agent default

Common environment variables:

VariablePurpose
FABRIC_MODELDefault provider/model-id for fh run.
FABRIC_TARGET / FABRIC_HARNESS_TARGETDefault --target for fh run.
FABRIC_TEMPORAL_TASK_QUEUEDefault Temporal task queue.
FABRIC_TEMPORAL_ADDRESSDefault Temporal address.
FABRIC_TEMPORAL_NAMESPACEDefault Temporal namespace.
FABRIC_DOCKER_TESTGates live Docker tests (=1 to enable).
OPENAI_API_KEY, AZURE_OPENAI_*, etc.Provider credentials.

Loading .env files

Fabric Harness auto-loads common env files from the repo root and workspace root:

.env
.env.local
.fabricharness/.env
.fabricharness/.env.local

For local development, put provider keys once in the repo-level .env.local:

cp .env.example .env.local
# edit .env.local and set OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.

Shell environment values always win. Use explicit --env <file> only for overrides; repeatable explicit env files override auto-loaded files but not shell env.

fh run ask --env .env.test --question "hi"
fh dev --env .env.test
fh temporal-worker --env .env.test

--env is supported on run, dev, and temporal-worker.

Agent-level overrides

A metadata agent can declare its own defaults:

export default agent({
  name: 'ask',
  model: 'openai/gpt-5.5',  // wins over config.run.model
  target: 'node',                // wins over config.run.target
  // ...
});

CLI flags still override agent defaults.

Where config files live in the build

fh build reads .fabricharness/config.ts at build time and bakes the relevant subset into the manifest. Runtime-sensitive values (Temporal address, secrets, etc.) stay env-driven so they can change per environment.