TechFabricTechFabricHarness
Getting Started

Configuration

How config.ts and environment variables combine, and which one wins when the same setting is declared in both places.

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'
    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',         // 'empty' | 'virtual' | 'local' | 'docker' | 'cloudflare' |
                              // 'e2b' | 'daytona' | 'modal' | 'kubernetes' | 'firecracker' |
                              // 'azure-container-apps' | 'azure-container-instances' | 'aks' | 'databricks'
    metadata: {
      inheritSafeEnv: true,
      envAllowlist: ['GH_TOKEN', 'DATABASE_URL'],
      defaultTimeoutMs: 30_000,
      outputLimitBytes: 256_000,
    },
  },
  store: {
    backend: 'file',          // 'file' | 'sqlite' | 'postgres'
  },
  metadata: {
    // Default Cloudflare Worker name (overridable per environment); bindings and
    // routes are edited in the wrangler configuration the cloudflare build emits.
    name: 'my-agent',
  },
};

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

TechFabric 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 defineAgent({
  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.