FabricFabricHarness
Reference

Filesystem sources

Mount read-only content (knowledge bases, docs, fixtures) into a sandbox so the agent can grep / glob / read it like ordinary files.

withFilesystemSources pre-populates a sandbox with read-only content from one or more sources. The agent's built-in grep, glob, and read tools see it as ordinary files — no vector store, no embeddings, no retrieval pipeline.

This is the right primitive for support agents, runbook lookup, FAQ assistants, internal-docs Q&A, or any workflow where the corpus is small enough to mount as files (low MB).

Quickstart

import { defineAgent, localDirectorySource, withFilesystemSources } from '@fabric-harness/sdk/lite';

const sandbox = withFilesystemSources('empty', [{
  mountAt: '/workspace/kb',
  source: localDirectorySource('./knowledge-base', { include: (p) => p.endsWith('.md') }),
}]);

export default defineAgent(async ({ init, payload }) => {
  const agent = await init({ sandbox, runtime: 'stateless' });
  const session = await agent.session();
  const message = String((payload as any)?.message ?? '');
  return { reply: await session.prompt<string>(
    `Search /workspace/kb (markdown) and answer concisely.\n\nCustomer: ${message}`,
  )};
});

The agent sees /workspace/kb/*.md and uses its built-in tools to search.

Sources

localDirectorySource(hostPath, options?)

Reads a host directory recursively. Each file becomes an entry; the relative path inside hostPath is preserved.

localDirectorySource('./docs', {
  name: 'product-docs',
  include: (relativePath) => relativePath.endsWith('.md') && !relativePath.startsWith('drafts/'),
});
  • include — predicate to skip files. Defaults to "include everything."
  • name — label used in telemetry.

inMemorySource(files, options?)

Bundle content directly into the agent module. Useful for fixtures, tests, or small static corpora that ship with the agent.

inMemorySource({
  'faq.md': '# FAQ\n\nQ: Reset password? A: Visit /forgot-password.',
  'guides/billing.md': '# Billing\n\nCharges happen on the 1st of each month.',
});

Cloudflare R2 sources

@fabric-harness/cloudflare includes an R2 source helper for support knowledge bases and other object-backed file sets:

import { r2FilesystemSource } from '@fabric-harness/cloudflare';
import { withFilesystemSources } from '@fabric-harness/sdk/lite';

const sandbox = withFilesystemSources('empty', [{
  mountAt: '/workspace/knowledge-base',
  source: r2FilesystemSource(env.SUPPORT_KB, { prefix: 'knowledge-base/' }),
}]);

Objects such as knowledge-base/reset-password.md are mounted as /workspace/knowledge-base/reset-password.md and become available to the built-in read, grep, and glob tools. See examples/support-agent-cloudflare-r2.

S3 and Azure Blob structural sources

@fabric-harness/connectors includes dependency-free structural helpers for S3-compatible and Azure Blob-compatible clients. They do not import cloud SDKs; adapt your cloud SDK calls to the small client shape.

import { s3FilesystemSource, azureBlobFilesystemSource } from '@fabric-harness/connectors';

const s3Source = s3FilesystemSource(s3ClientAdapter, { prefix: 'knowledge-base/' });
const azureSource = azureBlobFilesystemSource(blobClientAdapter, { prefix: 'knowledge-base/' });

Use these with withFilesystemSources() the same way as local, in-memory, or R2 sources.

Custom sources

A source is just an object with an entries() method that yields { path, content } pairs. Implement one for S3, R2, GCS, an MCP filesystem server, or any other backend:

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

function s3Source(bucket: string, prefix: string): FilesystemSource {
  return {
    name: `s3://${bucket}/${prefix}`,
    async *entries() {
      // ...list & fetch from S3
      yield { path: 'doc-1.md', content: '...' };
    },
  };
}

Composition

withFilesystemSources(base, sources) accepts any sandbox base — a backend name, a SandboxFactory, or an existing SandboxEnv. It returns a SandboxFactory you pass to init({ sandbox }).

Mount multiple sources at different paths:

withFilesystemSources('empty', [
  { mountAt: '/workspace/kb',       source: localDirectorySource('./kb') },
  { mountAt: '/workspace/runbooks', source: localDirectorySource('./runbooks') },
  { mountAt: '/workspace/legal',    source: localDirectorySource('./legal-templates') },
]);

Wrap a non-empty backend so mounts coexist with the workspace:

withFilesystemSources('local', [{
  mountAt: '/workspace/reference',
  source: localDirectorySource('./reference'),
}]);

Conventions and limits

  • Read-only by convention. The SDK doesn't block writes to mounted paths — it relies on the agent's role/skill prompts to enforce that. If you need hard read-only enforcement, use a sandbox backend that supports it (Docker --read-only mounts via metadata.mountReadOnly, for example).
  • Eager population. withFilesystemSources walks the source(s) and writes every file into the sandbox at creation time. This is the right model for small corpora; for very large knowledge bases use a retrieval-augmented approach instead.
  • One source per path. Mounting two sources at the same path is allowed but the second overwrites the first. Mount at distinct paths.

See also