# TechFabric Harness complete documentation Canonical index: https://harness.techfabric.com/llms.txt License: Apache-2.0 TechFabric Harness is a TypeScript framework for governed, durable autonomous agents. The complete corpus includes Databricks Responses API and MLflow ResponsesAgent interoperability, Unity AI Gateway, Unity Catalog Agent Services, SQL, AI Search and RAG evaluation, Lakeflow, Lakebase, Apps deployment and certification, plus enterprise identity/RBAC, channels, databases, sandboxes, MCP, operator controls, and every public API reference. --- # What is TechFabric Harness Canonical: https://harness.techfabric.com/docs A TypeScript framework for building durable, deployable autonomous agents. ## The 30 second answer **Databricks (or any host platform) decides who can touch data, models, and compute. TechFabric Harness decides how an autonomous agent runs.** Fabric is a **headless** TypeScript framework for **durable, deployable agents**. Finite jobs live in `.fabricharness/jobs/`; persistent, addressable agents live in `.fabricharness/agents/`. Run them locally and build for Node, Docker, Temporal, Cloudflare, Azure-oriented targets, or Databricks Apps and Model Serving proxy deployments. Its distinctive boundary is **not** the prompt loop, threads, or request-time tool lists. Fabric keeps execution recoverable and governance enforceable when work: - outlives a request or process, - waits minutes or days for an exact-operation approval, - crosses infrastructure (shell, sandboxes, channels, other clouds), - or must leave correlated operator evidence behind. | You need… | Use | | --- | --- | | Interactive Databricks-only agent with request/thread lifecycle | [Databricks AppKit](https://developers.databricks.com/docs/appkit/v0/plugins/agents) or native SDK | | Recoverable runs, durable approvals, portable policy, isolated work, multi-target deploy | **TechFabric Harness** (on Databricks or elsewhere) | | Deterministic short application code (no agent loop) | Native Databricks TypeScript SDK | For the full overlap analysis, see [Why TechFabric Harness on Databricks](/docs/databricks/why-fabric). > **Headless runtime, optional clients.** Agents run through the SDK, HTTP, schedules, channels, or > Temporal without requiring a UI. Use `fh fiber` for terminal interaction or > `@fabric-harness/react` for an application UI; both consume the same authenticated public protocol. New to the framework? Follow [Learn TechFabric Harness](/docs/learning-paths). It gives every shipped feature family a progressive guide, runnable practice workspace, failure/cleanup expectation, and production proof instead of asking you to discover the framework from the API reference. ## Why a framework, not just an SDK Most agent libraries leave you to wire up the runtime, the build, the dev server, the deployment story, and the durability story yourself. TechFabric Harness is opinionated about those things so the agent code stays focused on the work: - **Workspace conventions** — `.fabricharness/jobs`, `agents`, `roles`, `skills`, `policies`, `sandboxes`, plus a project `AGENTS.md`. - **CLI** — discover, run, build, deploy, inspect, replay, and verify everything from one binary (`fabric-harness` or `fh`). - **Runtime adapters** — local Node, Docker sandbox, Temporal worker, Cloudflare Workers, Foundry-hosted, more on the way. - **Headless by default** — agents complete autonomously. Approvals are an explicit hook, not a default user prompt. - **Durable by design** — bounded runs, persistent sessions, submissions, cancellation, checkpoints, retry classification, and optional Temporal workflows survive process and worker failure. - **Capability-scoped security** — definition policy remains a security floor across tools, commands, filesystems, networks, sandboxes, and connectors; secrets stay out of model context. - **Durable governance** — approvals bind the exact operation and principal, survive long waits, and remain correlated with lineage, cost, artifacts, and terminal state. - **Portable contracts** — agent, session, tool, policy, source, sandbox, store, and deployment contracts do not belong to one cloud or data platform. ## What is distinctive Many platforms now provide TypeScript agent definitions, threads, scoped tools, streaming, and request-time approval. Fabric includes those features, but does not present them as unique. Its strongest advantages begin where a request-scoped agent host stops: | Requirement | TechFabric Harness contract | | --- | --- | | Work must survive process or worker failure | Durable submissions, leases, bounded retries, terminal-state classification, checkpoints, and optional deterministic Temporal workflows | | Approval may take minutes or days | Approval records remain bound to the operation and executing identity instead of living only in one HTTP stream | | Policy must follow the workload | Definition policy is a security floor across local, Databricks, cloud, edge, cluster, connector, and sandbox execution | | The agent must perform isolated work | Tasks, shell commands, mounted sources, artifacts, checkpoints, forks, and portable sandbox references share the session contract | | Operators need recovery evidence | Events, traces, replay views, lineage, cost, artifacts, cleanup records, and distinct cancelled, exhausted, retryable, permanent, and terminal outcomes stay correlated | | The deployment platform may change | The same finite or persistent definition builds for Node, Docker, Temporal, Cloudflare, Azure-oriented targets, Databricks Apps, and other supported backends | ## How TechFabric Harness works Definitions declare what an agent can do. The runtime creates an isolated session, assembles roles, skills, tools, policy, and context, then drives the model loop. Every tool or shell action passes through capability policy before a sandbox or provider adapter executes it. Events, approvals, artifacts, cost, and results remain correlated to the session and submission. ```mermaid flowchart LR INPUT[CLI, HTTP, schedule, or channel] --> DEF[Job or persistent agent] DEF --> SESSION[Session runtime] subgraph Context[Context assembly] ROLE[Roles] SKILL[Skills] MEMORY[Memory and mounted sources] end ROLE --> SESSION SKILL --> SESSION MEMORY --> SESSION SESSION --> MODEL[Model provider] MODEL --> ACTION{Next action} ACTION -->|Tool| POLICY[Capability policy] ACTION -->|Shell or file| POLICY ACTION -->|Final result| RESULT[Typed result and events] POLICY -->|Approval needed| APPROVAL[Durable approval] POLICY -->|Allowed| EXEC[Sandbox or connector] APPROVAL --> EXEC EXEC --> SESSION SESSION --> STORE[(Session and submission store)] classDef entry fill:#f4f4f5,stroke:#71717a,color:#18181b classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef control fill:#fef3c7,stroke:#d97706,color:#422006 classDef state fill:#dcfce7,stroke:#16a34a,color:#052e16 class INPUT,DEF entry class SESSION,MODEL,RESULT fabric class ACTION,POLICY,APPROVAL control class EXEC,STORE,ROLE,SKILL,MEMORY state ``` On Databricks, the same runtime can use Model Serving, SQL Warehouses, Unity Catalog, AI Search, Genie, Feature Serving, Lakeflow, Lakebase, MLflow, and Databricks Apps under one propagated identity. It can also author Jobs, pipelines, indexes, endpoints, grants, workspace objects, and secret references through opt-in approval-bound tools. Start with [TechFabric Harness on Databricks](/docs/databricks). ## Build governed agents around Databricks workloads TechFabric Harness is designed for enterprises that already use Databricks as their governed data and AI platform and need an application runtime around it. Data, models, compute, and authorization stay native to Databricks. Fabric adds durable agent sessions, model-safe tools, approval routing, identity propagation, deployment contracts, lineage, and cost correlation. | Workload | Databricks foundation | TechFabric Harness adds | | --- | --- | --- | | Analytics copilot | Genie, SQL Warehouses, Unity Catalog | Safe `SELECT` path, steward approval for broader SQL, OBO identity, durable conversations | | Knowledge assistant | AI Search, AI Gateway, MLflow | Citation-validated RAG, session state, evaluation export, release evidence | | Data operations agent | Jobs, Lakeflow, notebooks | Approval-bound execution, durable receipts, retries, cleanup, status collection | | Stateful Databricks App | Apps, Lakebase, UC Volumes | Persistent sessions and streams, restart recovery, attachments, tenant deletion | | Agent API and discovery | Responses API, MLflow ResponsesAgent, Agent Services | One interoperable endpoint, deployment artifacts, discovery, grants, and policy | Start with the [Databricks workload map](/docs/databricks/workloads), use the [enterprise adoption guide](/docs/databricks/enterprise-adoption) to plan a production rollout, and review [workspace compatibility evidence](/docs/databricks/compatibility) before making a cloud, region, or preview claim. Databricks now also provides a beta TypeScript [AppKit agent host](https://developers.databricks.com/docs/appkit/v0/plugins/agents) with threads, tools, subagents, cancellation, human approval, and Responses-compatible routes. That is real overlap. Use AppKit directly for a Databricks-only interactive agent when its request and thread lifecycle is sufficient. Use Fabric when the workload needs recoverable execution, durable waits, portable policy, isolated shell/filesystem work, cross-system orchestration, or the option to move the same contract beyond Databricks. The approaches also compose: Fabric can use Databricks Apps, Agent Bricks, Unity AI Gateway, Lakebase, Jobs, and Unity Catalog as native services. ## Complete capability map | Area | Included TechFabric Harness features | | --- | --- | | Agent lifecycle | Finite agents, persistent addressable agents, per-interaction initialization, sessions, submissions, tasks, subagents, dispatch, schedules, webhooks, and channels | | Context | Prompts, roles, Markdown-first skills, session memory, mounted filesystem sources, attachments, compaction, typed input, and validated output | | Execution | Typed tools, commands, shell, MCP, connectors, isolated sandboxes, sandbox capability discovery, snapshots, forks, and portable references | | Durability | Bounded retries and loops, leases, cancellation propagation, checkpoints, replay views, idempotent operations, recovery, and deterministic Temporal workflows | | Governance | Capability policy for tools, commands, filesystems, networks, credentials, connectors, exact-operation approvals, identity binding, budgets, redaction, and tenant isolation | | State | File, SQLite, Postgres, Redis, Cloudflare, Lakebase, session streams, submissions, memory, artifacts, attachments, and deletion contracts | | Models and data | OpenAI-compatible providers, Anthropic, Bedrock, Vertex, Azure, Databricks, Workers AI, custom providers, databases, retrieval, and governed data tools | | Delivery | CLI, HTTP, Responses API interoperability, typed client, React hooks, Fiber console, queues, schedules, channels, portable build artifacts, and deployment targets | | Operations | Structured events, OpenTelemetry, MLflow integration, metrics, token and cost attribution, logs, release evidence, certification, and supply-chain attestations | ## Standard agent terminology TechFabric Harness keeps the terms that are converging across the agent ecosystem. You will find these everywhere in the docs: | Term | Meaning | | --- | --- | | **Agent** | A configured autonomous runtime. | | **Session** | A persisted message/context thread. | | **Skill** | A reusable Markdown- or code-backed procedure. | | **Role** | A scoped instruction/model profile. | | **Sandbox** | An isolated execution environment with filesystem/shell/tools. | | **Task** | A child or delegated agent run. | | **Tools** | Model-callable functions. | | **Commands** | Shell-level capabilities exposed to the sandbox. | | **Build** | A compiled, deployable workspace artifact. | ## Agent functions for conversations, finite jobs for results Use a **persistent agent function** when people or systems will message the same address over time. Hooks keep its model, tools, skills, sandbox, and instructions together in one readable definition: ```ts title=".fabricharness/agents/triage.ts" import { createAgent, useModel, useSandbox, useSkill, useTool, } from '@fabric-harness/sdk'; import { reviewChecklist } from '../skills/review'; import { proposeFix, searchIssues } from '../tools/github'; function TriageAgent() { useModel('anthropic/claude-sonnet-4-6'); useSandbox('docker', { cwd: '/workspace' }); useSkill(reviewChecklist); useTool(searchIssues); useTool(proposeFix); return `Triage the reported issue end to end. Reproduce it, identify the root cause, propose a fix, and verify the result before you finish.`; } export default createAgent(TriageAgent, { durability: { maxAttempts: 5, timeoutMs: 2 * 60 * 60_000 }, }); ``` The function renders before each interaction. Its return value is the instruction, while hooks compose capabilities in call order. Static policy, durability, triggers, and initial-data validation belong in `createAgent()`'s second argument so the host can enforce them even when the function cannot render. Use a **finite agent** when one typed invocation should return one bounded result: ```ts title=".fabricharness/jobs/echo.ts" import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'echo', input: schema.object({ message: schema.string() }), output: schema.string(), run: ({ input, prompt }) => prompt(input.message), }); ``` The bare `@fabric-harness/sdk` import gives finite agents headless defaults (`runtime: 'stateless'`, `sandbox: 'virtual'`, the Pi loop runtime, and automatic compaction). Definition-level instructions, tools, policies, cost budgets, and approval timeouts become runtime defaults; invocation policy and budgets cannot weaken the definition's security floor. For **Temporal-backed finite agents** or **compliance/audit workloads** where implicit defaults are undesirable, switch to `@fabric-harness/sdk/strict`. The call shape stays the same, but every runtime option is explicit. Runtime (`stateless` / `inline` / `temporal`) and deployment target remain separate choices. ```ts title="Strict — every option declared, Temporal-safe" import { defineAgent, schema } from '@fabric-harness/sdk/strict'; export default defineAgent({ name: 'triage', model: 'openai/gpt-5.5', input: schema.object({ issueNumber: schema.number(), title: schema.string() }), output: schema.object({ severity: schema.enum(['low','medium','high']), summary: schema.string() }), triggers: { webhook: true, schedule: '*/15 * * * *' }, run: async ({ init, input }) => { const fabric = await init({ runtime: 'temporal', sandbox: 'local', compaction: { enabled: false }, policy: triagePolicy, }); const session = await fabric.session(); return await session.prompt(`Triage issue #${input.issueNumber}: ${input.title}`); }, }); ``` Persistent and finite definitions deploy through the same CLI and share the same session, tool, skill, sandbox, policy, and model contracts. See [Dynamic agents and hooks](/docs/building/dynamic-agents), [Persistent agents](/docs/building/persistent-agents), and [SDK entrypoints, runtimes, and targets](/docs/reference/sdk-entrypoints-runtimes-targets) for the full distinction. ## Public API surface ```ts const fabricAgent = await init(options); const session = await fabricAgent.session(id?, options?); await session.prompt(text, options?); await session.skill(name, options?); await session.task(text, options?); await session.shell(command, options?); ``` ## Where to go next - **Want the 10-line agent?** [Headless agents with the minimal entrypoint](/docs/getting-started/headless-mode). - **Confused by entrypoints, stateless, inline, or Temporal?** [SDK entrypoints, runtimes, and targets](/docs/reference/sdk-entrypoints-runtimes-targets). - **New here?** [Use cases](/docs/use-cases) → [Installation](/docs/getting-started/installation) → [Your first agent](/docs/getting-started/first-agent). - **Want CLI specifics?** [CLI reference](/docs/cli). - **Ready to deploy?** [Deployment](/docs/deployment). - **Building on Databricks?** [Architecture, integrations, quickstart, and validation](/docs/databricks). - **Curious about scope?** See the [capability matrix](/docs/reference/capability-matrix). --- # Learn TechFabric Harness Canonical: https://harness.techfabric.com/docs/learning-paths A progressive route through every TechFabric Harness capability, from the first finite agent to durable production and Databricks certification. TechFabric Harness has a broad surface, but you should not learn it as a list of exports. Start with one agent lifecycle, add only the capabilities the workload needs, and prove each boundary before moving to the next stage. This page is the canonical map for the complete framework. ## Choose the first outcome | You want to build | Start here | You are done when | | --- | --- | --- | | One bounded task with typed input and output | [Your first agent](/docs/getting-started/first-agent) | `fh run` validates the input, returns a typed result, and records a terminal run. | | A durable conversational agent | [Persistent agents](/docs/building/persistent-agents) | Two interactions use the same address without sharing state with another identity. | | An agent that safely takes action | [Enterprise controls](/docs/building/enterprise-controls) | An allowed action succeeds, a denied action fails before execution, and an approval is bound to the exact operation. | | An agent that works in files or a shell | [Sandboxes](/docs/building/sandboxes) | Capability discovery, timeout, cancellation, and cleanup pass for the selected backend. | | A recoverable long-running workflow | [Runtime modes](/docs/reference/runtime-modes) | A restart or worker replacement resumes accepted work without duplicating its external effect. | | A web, chat, voice, or channel application | [HTTP applications](/docs/building/http-applications) | Authenticated ingress reaches the intended agent and preserves actor and tenant identity. | | A Databricks workload | [Databricks quickstart](/docs/databricks/quickstart) | Mock authoring, workspace preflight, identity, deployment, and the target-workspace smoke test pass. | | A production deployment | [Production readiness](/docs/reference/production-readiness) | Build verification, auth, stores, recovery, observability, deletion, and supply-chain gates pass, and [validation status](/docs/reference/validation-status) matches the enabled capability set. | ## The learning sequence ### 1. Learn the two agent lifecycles Read [Agent APIs](/docs/getting-started/api-consistency), then build both forms: - `defineAgent()` is a finite, bounded invocation that returns one result. - `createAgent()` is a persistent, addressable agent initialized for each interaction. Use [Agent anatomy](/docs/building/anatomy) for finite definitions and [Dynamic agents and hooks](/docs/building/dynamic-agents) for persistent composition. Then inspect the definition with `fh agents` and `fh describe` before running it. Practice with `hello-world`, `minimal`, `finite-jobs`, and `dynamic-agent` in the [example catalog](/docs/examples). Do not proceed until you can explain where termination bounds, static policy, interaction state, and initialization belong. ### 2. Build context deliberately Add context one layer at a time: 1. [Sessions and prompts](/docs/building/sessions-prompts) for the conversation boundary. 2. [Roles](/docs/building/roles) for instruction overlays. 3. [Skills](/docs/building/skills) for Markdown-first procedures. 4. [Session memory](/docs/building/session-memory) and [context compaction](/docs/reference/compaction) for bounded continuity. 5. [Filesystem sources](/docs/reference/filesystem-sources) and [artifacts](/docs/building/artifacts) for mounted knowledge and retained output. Practice with `with-skill`, `with-packaged-skills`, `with-s3-source`, `data-analyst`, and `support-agent`. Verify what enters model context, what remains server-side, and what is retained after deletion. ### 3. Give the agent capabilities Use [Tools](/docs/building/tools) for typed model calls, [Commands](/docs/building/commands) for shell capabilities, [Tasks](/docs/building/tasks) and [Subagents](/docs/building/subagents) for delegation, and [MCP](/docs/reference/mcp) for remote tool discovery. Every capability needs: - a schema and effect classification; - a definition-level policy floor; - bounded output, timeout, cancellation, and concurrency; - explicit secret resolution outside model context; and - deterministic failure behavior that callers can distinguish from cancellation or exhaustion. Practice with `with-tools`, `with-finish-tool`, `with-task`, `with-local-shell`, `with-signal-messages`, and `application-routes`. ### 4. Isolate execution Start with the [sandbox guide](/docs/building/sandboxes), choose a backend using the [sandbox matrix](/docs/reference/sandboxes-matrix), and learn the portable [sandbox lifecycle](/docs/reference/sandbox-lifecycle). Use [sandbox connectors](/docs/building/sandbox-connectors) when the environment is provider-managed. The full path covers virtual, local, Docker, Kubernetes, Cloudflare Computer, Cloudflare Sandbox, Databricks SQL, Daytona, E2B, Modal, and Vercel Sandbox. Provider pages under [Ecosystem → Sandboxes](/docs/ecosystem/sandboxes) document authentication and unsupported operations. Practice with the matching `with-*` workspace and verify create, exec, files, timeout, cancellation, and cleanup—not only a successful command. ### 5. Add governance before mutation Read [Policies and approvals](/docs/reference/policies-approvals), then the guided [Approvals](/docs/building/approvals) and [Enterprise controls](/docs/building/enterprise-controls) pages. Continue with: - [Authentication and RBAC](/docs/operating/auth); - [Multi-tenancy](/docs/operating/multi-tenancy); - [Rate limiting](/docs/operating/rate-limiting); - [Private networking](/docs/operating/private-networking); - [Secrets, retention, and residency](/docs/operating/data-governance); and - [Security hardening](/docs/reference/security-hardening). Practice with `with-approval`, `private-networking`, `with-analytics-copilot`, and the Databricks authoring workspaces. Test one allowed action, one policy denial, one expired or rejected approval, and one cross-tenant access attempt. ### 6. Make accepted work durable Read [Runtime modes](/docs/reference/runtime-modes), [Session stores](/docs/reference/session-stores), and [Build and run artifacts](/docs/deployment/build-artifacts). Then add: - checkpoints and replay with `with-checkpoint`; - unified database persistence with `database-persistence`; - durable child work with `with-task` and `finite-jobs`; - Temporal activities and deterministic workflows with [Temporal Worker](/docs/deployment/temporal-worker); and - recovery objectives with [Backup and disaster recovery](/docs/operating/disaster-recovery). The durability proof is a restart, cancellation, retry-classification, and idempotency test. A successful uninterrupted run is not durability evidence. ### 7. Choose models, data, and retrieval Use [Model providers](/docs/building/model-providers) for OpenAI-compatible, Anthropic, Bedrock, Vertex, Azure, Databricks, Workers AI, and custom providers. Use [Databases](/docs/ecosystem/databases) for SQLite, libSQL/Turso, Postgres, Lakebase, MySQL, MongoDB, Redis/Valkey, and Supabase patterns. For knowledge workloads, choose mounted files, a database tool, MCP, or provider-native retrieval based on the data boundary. The [use-case guide](/docs/use-cases) compares those approaches. Databricks AI Search and governed RAG have their own [RAG path](/docs/databricks/rag). ### 8. Deliver through the right interface The same runtime can be reached through: - the [CLI](/docs/cli), `fh fiber`, schedules, and webhooks; - the authenticated [HTTP server](/docs/reference/http-server); - `@fabric-harness/client` and [React hooks](/docs/building/react); - [Channels](/docs/building/channels), including every adapter in [Ecosystem → Channels](/docs/ecosystem/channels); and - [Voice](/docs/building/voice) with a selected [voice provider](/docs/building/voice-providers). Practice with `react-chat`, `scheduled-jobs`, `with-channel-adapters`, `with-slack-channel`, and `voice-data-collector`. Validate signature/authentication failures, duplicate delivery, retries, stream reconnection, and identity propagation. ### 9. Build and deploy portably Learn `fh build`, `fh deploy`, build manifests, package verification, and target-specific preflight from [Deployment overview](/docs/deployment). The maintained paths cover Node, Docker, Temporal, Cloudflare, Azure/ACI/AKS, Foundry Hosted Agents, Databricks Apps and serving proxies, AWS/SST, Fly.io, Railway, Render, GitHub Actions, and GitLab CI. Remote sandbox providers are execution backends and do not replace the deployment runtime. For each target, follow its page through prerequisites, build, validation, expected health result, failure behavior, and cleanup. Use [Portable agent packages](/docs/deployment/portable-packages) when another repository consumes the artifact. ### 10. Operate and improve the system Use [Agent events](/docs/reference/events), [Telemetry](/docs/reference/telemetry), and [Cost attribution](/docs/operating/cost-attribution) before production traffic. Add: - [Evaluations](/docs/building/evals) and the [eval library](/docs/reference/eval-library); - [Operator Console](/docs/operating/operator-console); - [Operational SLOs](/docs/operating/operational-slos); - [Audit export](/docs/operating/audit-export); - [Supply-chain evidence](/docs/operating/supply-chain); and - the [production readiness checklist](/docs/reference/production-readiness) and current [validation status](/docs/reference/validation-status). Practice with `with-observability` and `operational-slos`. Prove redaction, correlation, alerting, retention, deletion, and recovery instead of treating emitted logs as sufficient observability. ### 11. Learn the Databricks path in order Databricks owns data, models, identity, compute, governance, and hosting. Harness owns the portable, durable agent-control boundary around those services. 1. [Choose a workload](/docs/databricks/workloads) and read [why Harness](/docs/databricks/why-fabric). 2. Complete the [quickstart](/docs/databricks/quickstart) and [local naming/authentication](/docs/databricks/local-naming-auth). 3. Choose native services from [Databricks integrations](/docs/databricks/integrations): AI Gateway and Model Serving, SQL, Unity Catalog, AI Search, RAG, Genie, Jobs, Lakeflow, Feature Serving, Lakebase, MLflow, managed MCP, Agent Services, Supervisor Agents, Knowledge Assistants, managed memory, Apps, and ResponsesAgent. 4. Learn approval-bound writes in [resource management](/docs/databricks/authoring), including Jobs, Lakeflow, AI Search, Serving, Unity Catalog, Workspace, secret references, Asset Bundles, and Genie Agents. 5. Use the dedicated [Genie Agent Mode path](/docs/databricks/genie-agent-mode) for the explicit Beta create, permission, streaming, model-tool, failure, and cleanup journey. 6. Deploy through the [Databricks App tutorial](/docs/deployment/databricks-app) and add Lakebase or Temporal durability when the workload requires it. 7. Check [workspace compatibility](/docs/databricks/compatibility) and [live certification](/docs/databricks/live-certification), then compare the exact package and target against [validation status](/docs/reference/validation-status) before making a production claim. Preview availability is workspace-dependent. Contract support, a successful optional live probe, and release-blocking certification are different claims and remain labeled separately. ## Complete feature-family map | Feature family | Primary learning guide | Runnable practice | Production proof | | --- | --- | --- | --- | | Finite agents, schemas, middleware, nested invocation | [Agent anatomy](/docs/building/anatomy) | `minimal`, `finite-jobs` | Bounded terminal result and idempotent child invocation | | Persistent agents, hooks, state, finish guards | [Dynamic agents](/docs/building/dynamic-agents) | `dynamic-agent` | Identity-isolated interactions and restart continuity | | Sessions, prompts, roles, skills, memory, compaction | [Sessions and prompts](/docs/building/sessions-prompts) | `with-skill`, `with-packaged-skills` | Context bounds, redaction, retention, and deletion | | Tools, commands, tasks, subagents, finish tools, signals | [Tools](/docs/building/tools) | `with-tools`, `with-task`, `with-finish-tool`, `with-signal-messages` | Schema denial, effect policy, timeout, cancellation | | Filesystem sources, artifacts, attachments | [Filesystem sources](/docs/reference/filesystem-sources) | `with-s3-source`, `data-analyst` | Mount bounds, artifact integrity, cleanup | | MCP and connector recipes | [MCP](/docs/reference/mcp) | `with-databricks-managed-mcp` | Authenticated discovery, allowlist, effect preservation | | Sandboxes and isolated execution | [Sandbox matrix](/docs/reference/sandboxes-matrix) | Docker, Kubernetes, Cloudflare, Daytona, E2B, Modal, Vercel workspaces | Capability, isolation, timeout, cancellation, reclamation | | Policy, approvals, budgets, secrets | [Enterprise controls](/docs/building/enterprise-controls) | `with-approval`, `with-analytics-copilot` | Allow, deny, approval, expiry, secret-redaction tests | | Stores, checkpoints, replay, Temporal | [Runtime modes](/docs/reference/runtime-modes) | `with-checkpoint`, `database-persistence`, `with-temporal` | Crash recovery and no duplicate external effect | | HTTP, client, React, Fiber, schedules | [HTTP applications](/docs/building/http-applications) | `application-routes`, `react-chat`, `scheduled-jobs` | Auth, reconnect, duplicate delivery, graceful shutdown | | Channels and voice | [Channels](/docs/building/channels) | `with-channel-adapters`, `voice-data-collector` | Signature, identity, retry, deduplication tests | | Models, databases, retrieval | [Model providers](/docs/building/model-providers) | `support-agent`, `data-analyst`, provider examples | Credential, authorization, data-boundary tests | | Evals, telemetry, SLOs, audit, cost | [Evaluations](/docs/building/evals) | `with-observability`, `operational-slos` | Redacted correlated evidence and release thresholds | | Registry, boundary, portable packages | [Agent registry](/docs/building/agent-registry) | `agent-registry` | Immutable definition, grants, provenance, compatibility | | Deployment targets and supply chain | [Deployment overview](/docs/deployment) | Target-specific workspaces | Verified artifact, health, rollback, cleanup | | Databricks data, AI, authoring, Apps, durability | [Databricks](/docs/databricks) | All `with-databricks-*` workspaces | Target-workspace preflight and retained certification | ## Public package map | Package | Learn it here | | --- | --- | | `@fabric-harness/sdk` | [Agent APIs](/docs/getting-started/api-consistency), [building agents](/docs/building/anatomy) | | `@fabric-harness/cli` | [CLI overview](/docs/cli) | | `@fabric-harness/node` | [Node deployment](/docs/deployment/node), [HTTP server](/docs/reference/http-server) | | `@fabric-harness/client` | [HTTP applications](/docs/building/http-applications) | | `@fabric-harness/react` | [React applications](/docs/building/react) | | `@fabric-harness/vite` | [Vite integration](/docs/reference/vite-integration) | | `@fabric-harness/temporal` | [Temporal Worker](/docs/deployment/temporal-worker) | | `@fabric-harness/cloudflare` | [Cloudflare deployment](/docs/deployment/cloudflare) | | `@fabric-harness/azure` | [Azure deployment](/docs/deployment/azure) | | `@fabric-harness/databricks` | [Databricks learning path](/docs/databricks) | | `@fabric-harness/connectors` | [Connector catalog](/docs/building/connector-catalog) | | `@fabric-harness/channels` | [Channels](/docs/building/channels) | | `@fabric-harness/databases` | [Databases](/docs/ecosystem/databases) | | `@fabric-harness/evals` | [Evaluations](/docs/building/evals) | | `@fabric-harness/agent-registry` | [Agent registry and governance](/docs/building/agent-registry) | | `@fabric-harness/agent-boundary` | [Portable packages](/docs/deployment/portable-packages) | ## How to know a feature is learned For every feature you adopt, keep six things together: 1. **Prerequisites:** runtime, package, provider, authentication, permissions, and preview/SKU needs. 2. **Minimal path:** the smallest public-API configuration that demonstrates the capability. 3. **Expected result:** observable output, event, artifact, state transition, or health response. 4. **Failure path:** at least one denial, invalid input, cancellation, timeout, or unavailable-provider test. 5. **Cleanup:** the exact resource, store, session, sandbox, or deployment reclamation action. 6. **Evidence:** a deterministic test locally and a provider-backed smoke or certification record where the feature depends on managed infrastructure. The [example catalog](/docs/examples) is indexed by these expectations. API signatures remain in the [generated reference](/docs/reference/api); the reference is a lookup tool, not the learning order. Use [Runnable examples](/docs/examples/runnable) for synchronized commands, expected evidence, provider limitations, failure behavior, and cleanup across every workspace. --- # Runnable examples Canonical: https://harness.techfabric.com/docs/examples/runnable Runnable commands, expected proof, failure behavior, and cleanup for every maintained TechFabric Harness example. {/* Generated by scripts/generate-example-learning-guide.mjs. Edit the example package, README, track contract, or generator; do not edit this file directly. */} This guide is synchronized with every top-level workspace under `examples/`. Use it after the [complete framework learning path](/docs/learning-paths) to choose a runnable proof for a feature. Commands assume an authorized source checkout from the repository root. For a public project without source access, initialize a workspace with: ```sh npx --yes @fabric-harness/cli@latest init ``` Then copy the public API pattern from the linked feature guide. An example build proves local composition; it does not establish readiness for a managed provider. ## How to run a row Run the first command as the deterministic or build proof. Run the second command, when present, for the workload or development server. `pnpm --dir` executes the script from the example's own workspace, so the commands work when copied from the repository root. ## Framework foundations Learn finite and persistent lifecycles, state, schemas, configuration, tools, approvals, tasks, schedules, application routes, and browser clients before adding a managed runtime. - **Prerequisites and authentication:** Node.js 22 or newer and the repository pnpm version. Use the mock commands where shown; model-backed commands additionally need the credential for the model configured by that workspace. - **Expected evidence:** The selected check exits successfully or the run returns the typed result, durable state transition, event, or browser behavior described in the proof column. - **Failure behavior:** Invalid input, policy denial, approval rejection, exhaustion, cancellation, timeout, and unknown capabilities remain distinct terminal outcomes. A mock path never establishes provider readiness. - **Cleanup:** Stop development servers with Ctrl-C. Retain local run records only when they are needed for logs or replay; remove example-local databases and artifacts when the proof is complete. | Example | Command | What it proves | | --- | --- | --- | | [`agent-registry`](/docs/reference/source-access) | `pnpm --dir examples/agent-registry run check`
`pnpm --dir examples/agent-registry run run` | This credential-free example validates a vertical-neutral agent definition, pins an immutable version and model budget, separates proposal authority from execution authority, and proves that an `approval-required` autonomy ceiling prevents direct execution. | | [`application-routes`](/docs/reference/source-access) | `pnpm --dir examples/application-routes run check`
`pnpm --dir examples/application-routes run dev` | Runs authenticated custom Fetch routes and middleware, including a report route and durable delivery to an addressable customer agent. | | [`with-mounted-agent-router`](/docs/reference/source-access) | `pnpm --dir examples/with-mounted-agent-router run build`
`pnpm --dir examples/with-mounted-agent-router run run` | Mounts the persistent-agent HTTP surface inside an application that already owns its own server, under its own prefix and behind its own middleware. | | [`database-persistence`](/docs/reference/source-access) | `pnpm --dir examples/database-persistence run check`
`pnpm --dir examples/database-persistence run dev` | Uses one persistence contract for sessions, submissions, conversation offsets, attachments, finite runs, budgets, and cascade deletion across local libSQL and optional managed databases. | | [`dynamic-agent`](/docs/reference/source-access) | `pnpm --dir examples/dynamic-agent run build`
`pnpm --dir examples/dynamic-agent run dev` | This example composes a persistent agent with hooks. It stores milestone state durably, unlocks `advanced_analysis` after the first milestone, upgrades its model after the second, streams a named `data-progress` part, attaches response metadata, and uses an agent-finish guard to keep the same response working until `complete_milestone` runs. | | [`finite-jobs`](/docs/reference/source-access) | `pnpm --dir examples/finite-jobs run check`
`pnpm --dir examples/finite-jobs run dev` | Runs a typed parent job, admits an idempotent child run through middleware, and exposes the child receipt and event stream through the public run protocol. | | [`hello-world`](/docs/reference/source-access) | `pnpm --dir examples/hello-world run build` | Defines the functionally named `hello` and `ask` finite agents, then proves config defaults, credential-free mock execution, and optional durable Temporal execution. | | [`minimal`](/docs/reference/source-access) | `pnpm --dir examples/minimal run build` | The smallest possible TechFabric Harness agent. No input schema, no output schema, no capability policy, no session store, no artifacts. Just `defineAgent({...})` + `session.prompt` against a model of your choice. | | [`react-chat`](/docs/reference/source-access) | `pnpm --dir examples/react-chat run check`
`pnpm --dir examples/react-chat run dev` | Connects a React client to the public Harness protocol, streams transient SSE updates, reconciles them with durable messages, and exercises responsive light and dark layouts. | | [`scheduled-jobs`](/docs/reference/source-access) | `pnpm --dir examples/scheduled-jobs run check`
`pnpm --dir examples/scheduled-jobs run dev` | Declares a weekday report schedule and demonstrates local Node execution plus Cloudflare Cron generation, tenant-aware admission, and public run inspection. | | [`with-approval`](/docs/reference/source-access) | `pnpm --dir examples/with-approval run build` | Demonstrates policy-gated tool execution. | | [`with-checkpoint`](/docs/reference/source-access) | `pnpm --dir examples/with-checkpoint run build`
`pnpm --dir examples/with-checkpoint run run` | The `workspace-recovery` finite agent proves that a local sandbox can return to a named checkpoint. It writes one file, takes a checkpoint, writes a second file, restores the checkpoint, and reports the recovered filesystem state. | | [`with-config`](/docs/reference/source-access) | `pnpm --dir examples/with-config run build`
`pnpm --dir examples/with-config run run` | Demonstrates central workspace configuration through `.fabricharness/config.ts`. | | [`with-finish-tool`](/docs/reference/source-access) | `pnpm --dir examples/with-finish-tool run build`
`pnpm --dir examples/with-finish-tool run run` | Demonstrates the `finish` / `give_up` result tool pattern for structured output. | | [`with-imported-skills`](/docs/reference/source-access) | `pnpm --dir examples/with-imported-skills run build`
`pnpm --dir examples/with-imported-skills run run` | Demonstrates **build-time skill imports**: a skill authored as a `SKILL.md` directory anywhere in the project, imported directly by the agent that uses it. | | [`with-packaged-skills`](/docs/reference/source-access) | `pnpm --dir examples/with-packaged-skills run build`
`pnpm --dir examples/with-packaged-skills run run` | Demonstrates packaged skills with lazy resource loading. | | [`with-signal-messages`](/docs/reference/source-access) | `pnpm --dir examples/with-signal-messages run build`
`pnpm --dir examples/with-signal-messages run run` | Demonstrates `session.createSignalEntry()` for injecting typed signal entries into the session history. | | [`with-skill`](/docs/reference/source-access) | `pnpm --dir examples/with-skill run build`
`pnpm --dir examples/with-skill run run` | The `personalized-greeter` finite agent loads a Markdown-first `hello-skill` and the `friendly` role from the embedded `.fabricharness/` workspace, then invokes the skill with typed arguments. | | [`with-task`](/docs/reference/source-access) | `pnpm --dir examples/with-task run build`
`pnpm --dir examples/with-task run run` | Demonstrates parent/child task orchestration with shared durable session storage. | | [`with-tools`](/docs/reference/source-access) | `pnpm --dir examples/with-tools run build`
`pnpm --dir examples/with-tools run run` | Demonstrates built-in sandbox file tools with durable session history. | ## Runtimes, sandboxes, sources, and stores Move the same public lifecycle across local, container, remote-sandbox, durable workflow, object-source, and database boundaries. - **Prerequisites and authentication:** Start with the local or Docker proof. Provider-backed workspaces require the provider credential, target account, supported region or plan, and any runtime-specific CLI named in its guide. - **Expected evidence:** A build proves adapter composition. A live run must additionally prove capability discovery, bounded command or file behavior, cancellation, and resource reclamation on the selected backend. - **Failure behavior:** Missing credentials, unsupported operations, isolation escape attempts, network denial, process failure, timeout, cancellation, and cleanup failure surface explicitly; Harness does not redirect work to the host or another backend. - **Cleanup:** Every live sandbox or deployment must stop its exact remote resource. Source mounts are read-only and detach with the session; durable stores retain only the records selected by the example retention policy. | Example | Command | What it proves | | --- | --- | --- | | [`coding-agent-lite`](/docs/reference/source-access) | `pnpm --dir examples/coding-agent-lite run build` | Clones a repo into a Docker sandbox, installs dependencies, then runs an arbitrary prompt against the cloned source. This demonstrates TechFabric Harness lite mode for coding-agent workflows in about 13 lines. | | [`remote-coding-agent`](/docs/reference/source-access) | `pnpm --dir examples/remote-coding-agent run build` | Provider-neutral remote sandbox example for coding agents. | | [`with-azure`](/docs/reference/source-access) | `pnpm --dir examples/with-azure run build`
`pnpm --dir examples/with-azure run build:foundry` | Minimal TechFabric Harness agent that runs through an Azure OpenAI deployment with Azure Key Vault-resolved secrets. | | [`with-cloudflare-sandbox`](/docs/reference/source-access) | `pnpm --dir examples/with-cloudflare-sandbox run build`
`pnpm --dir examples/with-cloudflare-sandbox run build:cloudflare` | Builds a Cloudflare Worker artifact that uses Cloudflare Sandbox containers for shell and filesystem operations. It includes a finite job and a persistent agent backed by Durable Object admission, FIFO leases, offset streams, attachment storage, abort, reconciliation, and cascade deletion. | | [`with-cloudflare-shell-workspace`](/docs/reference/source-access) | `pnpm --dir examples/with-cloudflare-shell-workspace run build`
`pnpm --dir examples/with-cloudflare-shell-workspace run build:cloudflare` | This example targets Cloudflare Workers with the early-preview `@cloudflare/computer` Workspace backend. | | [`with-cloudflare-workers-ai`](/docs/reference/source-access) | `pnpm --dir examples/with-cloudflare-workers-ai run build`
`pnpm --dir examples/with-cloudflare-workers-ai run dev` | Builds and optionally deploys a Cloudflare Worker that resolves Workers AI through its native binding without an API key in agent state. | | [`with-daytona`](/docs/reference/source-access) | `pnpm --dir examples/with-daytona run build`
`pnpm --dir examples/with-daytona run run` | Runs a bounded shell workload in a Daytona-managed remote development sandbox. | | [`with-docker`](/docs/reference/source-access) | `pnpm --dir examples/with-docker run build` | Runs standard Harness file and shell tools inside a Docker container with a scoped workspace mount. | | [`with-e2b`](/docs/reference/source-access) | `pnpm --dir examples/with-e2b run build`
`pnpm --dir examples/with-e2b run run` | Runs a finite job in E2B, streams bounded command output, and removes the sandbox during session cleanup. | | [`with-kubernetes`](/docs/reference/source-access) | `pnpm --dir examples/with-kubernetes run build`
`pnpm --dir examples/with-kubernetes run run` | The `kubernetes-system-inspector` finite agent attaches a Harness sandbox to a Kubernetes pod via the `kubernetesSandbox()` adapter from `@fabric-harness/connectors/k8s` and runs a bounded diagnostic command in `/workspace`. | | [`with-local-shell`](/docs/reference/source-access) | `pnpm --dir examples/with-local-shell run build`
`pnpm --dir examples/with-local-shell run run` | The `node-version-inspector` finite agent uses the local sandbox and `session.shell()` to report the Node.js version available to a Harness workload. | | [`with-modal`](/docs/reference/source-access) | `pnpm --dir examples/with-modal run build`
`pnpm --dir examples/with-modal run run` | Runs a finite Harness workload in a Modal serverless sandbox through the portable sandbox contract. | | [`with-postgres-store`](/docs/reference/source-access) | `pnpm --dir examples/with-postgres-store run build`
`pnpm --dir examples/with-postgres-store run run` | Demonstrates configuring one Postgres bundle for sessions, submissions, conversation streams, attachments, finite runs, and cost budgets. | | [`with-s3-source`](/docs/reference/source-access) | `pnpm --dir examples/with-s3-source run build`
`pnpm --dir examples/with-s3-source run run` | The `s3-report-browser` finite agent mounts a bounded S3 prefix as a read-only Harness source and lists its files with the built-in `glob` tool. It needs no embeddings, retrieval service, or vector database. | | [`with-temporal`](/docs/reference/source-access) | `pnpm --dir examples/with-temporal run build`
`pnpm --dir examples/with-temporal run run:mock` | Runs the `temporal-agent` through a real Temporal worker with deterministic workflow boundaries, plus a credential-free Node-target mock path for local verification. | | [`with-vercel-sandbox`](/docs/reference/source-access) | `pnpm --dir examples/with-vercel-sandbox run build`
`pnpm --dir examples/with-vercel-sandbox run run` | Runs a finite job through Vercel Sandbox, forwards timeout cancellation, and stops the sandbox during cleanup. | ## Delivery, security, and operations Prove authenticated ingress, channel identity, private networking, redacted telemetry, evaluations, and operational objectives around the agent lifecycle. - **Prerequisites and authentication:** The deterministic checks need only Node.js and pnpm. Live channel and voice paths require their signing secrets, provider credentials, callback URLs, and a store suitable for duplicate-delivery and restart tests. - **Expected evidence:** Evidence includes verified ingress identity, governed replies, redacted correlation fields, evaluated SLO decisions, or an allowed network path paired with a denied bypass. - **Failure behavior:** Bad signatures, stale timestamps, duplicate delivery, tenant mismatch, redaction violations, unavailable exporters, and disallowed network destinations fail closed or enter the documented retry path. - **Cleanup:** Stop local listeners, remove temporary provider callbacks and test subscriptions, revoke short-lived credentials, and retain only redacted operational evidence required by policy. | Example | Command | What it proves | | --- | --- | --- | | [`operational-slos`](/docs/reference/source-access) | `pnpm --dir examples/operational-slos run test` | Exports stable Harness operational metrics, evaluates the reference SLO policy, and validates importable Prometheus and Grafana assets. | | [`private-networking`](/docs/reference/source-access) | `pnpm --dir examples/private-networking run test`
`pnpm --dir examples/private-networking run start` | Proves that an allowed request succeeds through the configured proxy while a direct network bypass fails. | | [`voice-data-collector`](/docs/reference/source-access) | `pnpm --dir examples/voice-data-collector run build` | Uses OpenAI Realtime to collect functionally named fields, submits typed `submit_field` calls, and persists the resulting field map in session memory. | | [`with-channel-adapters`](/docs/reference/source-access) | `pnpm --dir examples/with-channel-adapters run check`
`pnpm --dir examples/with-channel-adapters run dev` | This runnable workspace mounts all 18 first-party channel adapters on one persistent agent. | | [`with-observability`](/docs/reference/source-access) | `pnpm --dir examples/with-observability run test` | This example emits the same redacted Fabric observability record to Braintrust, Jetty, and Sentry adapter callbacks, with stable job, agent, session, submission, and tenant correlation. The `observability.eval.ts` fixture runs through `@fabric-harness/evals` and Vitest. OpenTelemetry's hierarchical span adapter is covered by `packages/sdk/test/otel-observer.test.ts` and accepts the same correlation fields. | | [`with-slack-channel`](/docs/reference/source-access) | `pnpm --dir examples/with-slack-channel run build`
`pnpm --dir examples/with-slack-channel run dev` | An end-to-end **channel** example: a Slack app mention drives a persistent agent, which replies in the same thread. Demonstrates the channels workstream (design) — webhook ingress → dispatch → outbound tool, with exactly-once delivery and per-user identity. | ## End-to-end workload examples Apply the framework to recognizable engineering and support work without treating the workload prompt as a substitute for lifecycle, policy, and cleanup controls. - **Prerequisites and authentication:** Most workloads require the model credential declared by the example. Shell or repository workloads also need their named local tools, fixtures, and read or write permissions. - **Expected evidence:** The result should match the typed workload artifact—review, reproduction, documentation, analysis, migration, support answer, test, or release note—and preserve the run evidence used to reproduce it. - **Failure behavior:** Missing inputs, unavailable models, malformed typed output, denied commands, unsafe mutations, and exhausted limits fail without silently returning an unvalidated artifact. - **Cleanup:** These examples should leave external systems unchanged unless an approval-bound action explicitly says otherwise. Remove temporary clones, generated fixtures, and local run records after reviewing the result. | Example | Command | What it proves | | --- | --- | --- | | [`api-docs-generator`](/docs/reference/source-access) | `pnpm --dir examples/api-docs-generator run build`
`pnpm --dir examples/api-docs-generator run run` | Generate MDX docs pages for HTTP routes. Demonstrates `fumadocsSource` to give the agent your existing docs as a tone/structure reference. | | [`bug-reproducer`](/docs/reference/source-access) | `pnpm --dir examples/bug-reproducer run build`
`pnpm --dir examples/bug-reproducer run run` | Convert a free-form bug report into a minimal failing test. Pure inference — no shell required, runs anywhere. | | [`changelog-writer`](/docs/reference/source-access) | `pnpm --dir examples/changelog-writer run build`
`pnpm --dir examples/changelog-writer run run` | Generate a Keep-a-Changelog markdown section between two git refs. | | [`code-review`](/docs/reference/source-access) | `pnpm --dir examples/code-review run build` | Provides separate read-only `code-review` and `pr-review` agents that return typed findings and a final recommendation for local source or a GitHub pull request. | | [`data-analyst`](/docs/reference/source-access) | `pnpm --dir examples/data-analyst run build` | Analyzes a CSV inside a network-isolated Docker sandbox and stores reproducible `analysis.md` and `summary.json` artifacts in the Harness session store. | | [`dependency-auditor`](/docs/reference/source-access) | `pnpm --dir examples/dependency-auditor run build`
`pnpm --dir examples/dependency-auditor run run` | Run `npm` / `pnpm` audit and ask the model to prioritize the findings. | | [`incident-runbook`](/docs/reference/source-access) | `pnpm --dir examples/incident-runbook run build`
`pnpm --dir examples/incident-runbook run run` | Match an alert to a mounted runbook (Fumadocs/Mintlify MDX) and walk through diagnostic steps. Read-only — never executes. | | [`issue-triage-ci`](/docs/reference/source-access) | `pnpm --dir examples/issue-triage-ci run build` | Runs a cautious CI issue-triage agent that is read-only by default, emits inspectable artifacts, denies publishing operations, and approval-gates issue comments. | | [`release-notes`](/docs/reference/source-access) | `pnpm --dir examples/release-notes run build`
`pnpm --dir examples/release-notes run run` | Customer-facing release notes from merged PRs between two tags. | | [`schema-migration`](/docs/reference/source-access) | `pnpm --dir examples/schema-migration run build`
`pnpm --dir examples/schema-migration run run` | Draft a SQL migration with `up`/`down` statements. Apply commands are gated behind approval in complete entrypoint. | | [`support-agent`](/docs/reference/source-access) | `pnpm --dir examples/support-agent run build` | A customer support agent that answers questions by searching a knowledge base. The knowledge base is just a directory of markdown files mounted into the agent's sandbox — no vector store, no embeddings, no retrieval pipeline. | | [`support-agent-cloudflare-r2`](/docs/reference/source-access) | `pnpm --dir examples/support-agent-cloudflare-r2 run build` | Support-agent example that mounts a Cloudflare R2 bucket prefix into the Fabric sandbox as normal files. | | [`support-agent-foundry`](/docs/reference/source-access) | `pnpm --dir examples/support-agent-foundry run build` | Support-agent example shaped for Microsoft Foundry Hosted Agents. | | [`test-generator`](/docs/reference/source-access) | `pnpm --dir examples/test-generator run build`
`pnpm --dir examples/test-generator run run` | Generate a Vitest spec for a TypeScript source file. Includes a `fixtures/src/util.ts` so `run` works clean. | ## Databricks workloads Progress from credential-free composition to target-workspace identity, governed data and AI access, native resource authoring, App bindings, durability, and protected certification. - **Prerequisites and authentication:** Run the mock or local contract first. Live paths require Databricks OAuth, least-privilege workspace and Unity Catalog permissions, the documented SKU or preview, and the exact resource identifiers named by the workspace. - **Expected evidence:** A local check proves Harness composition only. A live proof must record target-workspace preflight, identity, native service evidence, bounded agent behavior, cleanup, and the certification tier that actually ran. - **Failure behavior:** Authentication, authorization, preview, policy, stale-fingerprint, ambiguous-write, cancellation, timeout, and native terminal failures remain explicit. Non-idempotent or ambiguous writes are not retried automatically. - **Cleanup:** Trash or delete only the exact Harness-owned temporary resource in a finally path, wait for the native terminal state, then remove its ownership record. Never remove a pre-existing customer resource as example cleanup. | Example | Command | What it proves | | --- | --- | --- | | [`with-analytics-copilot`](/docs/reference/source-access) | `pnpm --dir examples/with-analytics-copilot run build`
`pnpm --dir examples/with-analytics-copilot run start` | Separates safe single-statement SQL reads from approval-bound arbitrary SQL and Genie management, with local validation before any Databricks call. | | [`with-databricks`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks run build`
`pnpm --dir examples/with-databricks run run` | Lighthouse use case #1 from the Databricks platform plan: a governed analytics copilot that answers questions over the lakehouse, with **Unity Catalog enforcing access** and Fabric adding approval routing, lineage, and an egress allowlist on top. | | [`with-databricks-agent-service`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-agent-service run test`
`pnpm --dir examples/with-databricks-agent-service run start` | This example registers an externally hosted TechFabric Harness agent in Unity Catalog, verifies discovery and metadata updates, reads its grants, optionally exercises grant/revoke, and deletes the temporary registration. It defaults the external route to the Harness `/responses` endpoint. Agent Services is not yet represented in the modular TypeScript SDK, so Fabric keeps its preview transport private and exposes this lifecycle through the typed `databricks()` bundle. | | [`with-databricks-app-resources`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-app-resources run check`
`pnpm --dir examples/with-databricks-app-resources run build` | Build a TechFabric Harness agent as a Databricks App while keeping Databricks Apps, Declarative Automation Bundles, Unity Catalog, Jobs, Model Serving, SQL Warehouses, and Databricks Secrets authoritative. | | [`with-databricks-appkit-interop`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-appkit-interop run test`
`pnpm --dir examples/with-databricks-appkit-interop run start` | This runnable spike pins `@databricks/appkit` 0.53.0 and proves the safe additive boundary: an AppKit beta agent discovers and invokes a read-only tool exposed by TechFabric Harness over MCP. The Harness server remains authoritative for authenticated identity, tenant context, policy version, canonical argument digest, cancellation signal, and tool-call evidence. | | [`with-databricks-authoring-admin`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-authoring-admin run build`
`pnpm --dir examples/with-databricks-authoring-admin run run` | Combines custom-model serving endpoint management, non-destructive Unity Catalog administration, workspace notebook writes, and secret-reference writes. All surfaces are opt-in and route to the `platform-admin` approval audience. The secret tool receives `{kind:'secret', name}` and resolves `APP_RUNTIME_SECRET` server-side; raw material never enters model tool input or lineage. | | [`with-databricks-bundle-deploy`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-bundle-deploy run build`
`pnpm --dir examples/with-databricks-bundle-deploy run run` | Validates, deploys, and runs a checked-in Databricks Asset Bundle (DAB) through governed model tools. Harness does not generate the bundle YAML — `bundle/databricks.yml` and its notebooks stay checked-in infrastructure-as-code. The agent owns only the lifecycle: `databricks_bundle_validate` is read-only, while `databricks_bundle_deploy`, `databricks_bundle_run`, and `databricks_bundle_destroy` are mutations that require `data-platform` steward approval. Deploy records a sha256 fingerprint of the bundle source tree in a managed-resource store, so drift and foreign deployments are detected instead of stomped. After deploy, the agent can kick off a run of a bundle-defined job or pipeline by its `databricks.yml` resource key with `databricks_bundle_run`; submission is always `--no-wait`, and run status is polled through the bounded jobs/lakeflow status tools rather than waited on inside the tool call. | | [`with-databricks-compute`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-compute run test`
`pnpm --dir examples/with-databricks-compute run start` | Keeps SQL Warehouses, SQL-backed portable sandboxes, asynchronous Jobs, one-off notebook submission, and Databricks App hosting as distinct execution choices. | | [`with-databricks-cost-attribution`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-cost-attribution run build`
`pnpm --dir examples/with-databricks-cost-attribution run start` | Demonstrates `databricksTenantCostLimit` with a mocked generated Statement Execution client, so the example runs **without any environment variables** or a live warehouse. | | [`with-databricks-dataeng`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-dataeng run build`
`pnpm --dir examples/with-databricks-dataeng run run` | Lighthouse use case #3 from the Databricks platform plan: a data-engineering agent that manages **Lakeflow Declarative Pipelines** (DLT) and inspects Delta tables, under Unity Catalog governance, on a **Temporal worker**. Pipeline runs are among the heaviest continuous-compute consumption surfaces. | | [`with-databricks-genie-authoring`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-genie-authoring run test`
`pnpm --dir examples/with-databricks-genie-authoring run run:lifecycle` | Teaches approval-gated Genie authoring, Agent Mode invocation of an existing resource, and a complete two-identity lifecycle with exact-resource cleanup in `finally`. | | [`with-databricks-jobs-authoring`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-jobs-authoring run build`
`pnpm --dir examples/with-databricks-jobs-authoring run run` | Creates, verifies, runs/repairs, explicitly updates, and deletes a multi-task Databricks Job through governed model tools. Every write/execute requires `data-platform` steward approval. Classic compute must use the configured Databricks cluster policy and stays within worker, concurrency, timeout, runtime, node-type, and tag bounds. | | [`with-databricks-managed-mcp`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-managed-mcp run build`
`pnpm --dir examples/with-databricks-managed-mcp run start` | This runnable example connects Harness's Databricks adapter to a local Streamable HTTP MCP server, discovers one explicitly allowed tool, invokes it under a rotating OBO credential, and records a governed lineage event. The local server stands in for Databricks managed Genie MCP, so no workspace or credentials are required. | | [`with-databricks-ontology-export`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-ontology-export run build`
`pnpm --dir examples/with-databricks-ontology-export run start` | Runs the Genie Ontology exporter end to end with **no Databricks credentials**: a recorded lending-shaped module manifest goes through `planModuleOntologyExport` (UC metric-view DDL, glossary terms, domain assignments, policy classifications, derived Genie Agent spec fingerprint, and the operational-truth feed table specs), recorded Platform history (AssetEvent / ActionInvocation / PolicyEvaluation records) goes through `planOntologyFeedHydration` with a demo redaction producer to produce merge-ready feed rows and deterministic `MERGE ... WHEN NOT MATCHED THEN INSERT` statements, and the idempotent re-run is proven against an in-memory stand-in for the Delta merge. | | [`with-databricks-rag`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-rag run build`
`pnpm --dir examples/with-databricks-rag run run` | Lighthouse use case #2 from the Databricks platform plan: a RAG support agent that answers from a Databricks AI Search knowledge base, with a Unity AI Gateway model service reasoning over the retrieved passages under Unity Catalog governance. | | [`with-databricks-rag-admin`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-rag-admin run build`
`pnpm --dir examples/with-databricks-rag-admin run run` | Demonstrates endpoint and delta-sync index lifecycle alongside the existing governed query tool. Set Databricks OAuth credentials plus `DATABRICKS_CATALOG`, `DATABRICKS_EXISTING_INDEX`, and `DATABRICKS_TEXT_COLUMN`; the principal needs Vector Search endpoint/index administration and `SELECT` on the source Delta table. `aiSearchAdmin` is bound to a resource policy, so also set `DATABRICKS_ADMIN_ENDPOINT`, `DATABRICKS_ADMIN_INDEX` (catalog-qualified), and `DATABRICKS_EMBEDDING_ENDPOINT` — those are the only endpoint, index, and embedding model the admin tools accept, pinned into the tool schemas and re-checked at call time. The embedding endpoint is bounded separately because the source column's contents are sent to it. Run `pnpm build && pnpm run`. | | [`with-databricks-revenue-ops`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-revenue-ops run test`
`pnpm --dir examples/with-databricks-revenue-ops run run:mock` | This is the opinionated customer reference for a governed, durable agent on Databricks. Databricks owns data, identity, Genie, the SQL Warehouse, the forecast Job, App hosting, Lakebase, and MLflow. Harness adds a bounded agent lifecycle, exact-operation approval, stable delivery identity, restart-safe submissions, and correlated terminal evidence. | | [`with-databricks-simple`](/docs/reference/source-access) | `pnpm --dir examples/with-databricks-simple run test`
`pnpm --dir examples/with-databricks-simple run run` | Minimal runnable TechFabric Harness example that demonstrates the Databricks happy path with mocked APIs — no real credentials required. | ## Provider evidence and release claims Provider-backed examples have three distinct evidence levels: 1. **Local contract:** types, policy, serialization, and failure behavior pass without provider credentials. 2. **Live smoke:** the named account, workspace, region, identity, and resource pass one bounded run and cleanup. 3. **Protected certification:** retained evidence meets the release gate and scope stated by that provider's certification page. Do not turn a build, mock run, optional probe, preview enrollment, or single-region smoke into a general production claim. Databricks claims must match the current [public certification record](/docs/databricks/live-certification). --- # TechFabric Harness on Databricks Canonical: https://harness.techfabric.com/docs/databricks Build governed TypeScript agents with the Responses API, Unity AI Gateway, Unity Catalog, SQL Warehouses, Lakebase, MLflow and Databricks Apps. ## The 30 second answer **Databricks owns the data, models, identity, and hosting plane. Fabric is an optional durable control layer for agents that use that plane.** | Question | Answer | | --- | --- | | Does Fabric replace Unity Catalog / Jobs / MLflow? | **No.** Those stay native and authoritative. | | Does Fabric overlap AppKit? | **Yes**, at the agent-runtime layer (threads, tools, request-time approval). | | When is Fabric still worth it? | When runs must **survive failure**, wait for **exact-operation approvals**, use **isolated shell/fs work**, keep **portable policy**, or leave **recovery evidence** across targets. | | When should you skip Fabric? | Databricks-only interactive agents where AppKit’s request/thread lifecycle is enough. | Read the full decision guide: [Why Fabric on Databricks](/docs/databricks/why-fabric). --- TechFabric Harness provides a first-party Databricks package, Databricks deployment targets, and Unity Catalog-aware connectors. It is designed for agents that need governed access to enterprise data, durable state, approval controls, lineage, and cost attribution without replacing Databricks authorization. Databricks remains the native data, AI, compute, identity, governance, and hosting platform. Fabric is an optional durable control layer around those services. The current Databricks developer stack also includes a beta [AppKit agent host](https://developers.databricks.com/docs/appkit/v0/plugins/agents) with TypeScript definitions, tools, threads, cancellation, approvals, subagents, and Responses-compatible routes. That is direct overlap, not a gap Fabric should pretend still exists. Fabric differentiates when execution must survive a failed process or long approval wait, policy must follow the workload across infrastructure, an agent needs isolated shell/filesystem work, or operators need portable recovery evidence. ## Why add Fabric to a Databricks workload | Requirement | Fabric advantage | | --- | --- | | Recover after process or worker failure | Stable submissions, leases, bounded retry classification, checkpoints, replay, terminal states, and optional deterministic Temporal workflows | | Wait safely for a person or external system | Exact-operation and principal-bound approvals can persist beyond one request stream and remain correlated with the resumed work | | Govern effects outside a model-tool list | Definition policy constrains tools, commands, filesystems, networks, credentials, connectors, sandboxes, budgets, and timeouts | | Perform isolated work | Sessions can run tasks and shell commands, mount sources, create attachments and artifacts, and checkpoint or fork capable sandboxes | | Cross the workspace boundary | The same finite or persistent agent contract can run on Databricks, Node, Docker, Temporal, Cloudflare, Azure-oriented targets, Kubernetes patterns, and custom backends | | Operate with evidence | Identity, events, lineage, cost, artifacts, cleanup records, certification, and terminal outcomes remain correlated to the submission | The current npm release is `@fabric-harness/databricks@7.1.1`. The exact `7.1.1` package and App artifacts passed all 21 release-blocking Tier R checks in protected Azure `eastus2`, including managed Genie MCP under OBO, governed SQL, live RAG, actual-cost reconciliation, and Lakebase-backed App restart recovery. The certifying run executed in single-user workspace mode, so it makes no claim about cross-user or cross-tenant isolation; seven configured Tier O checks passed and two failed. A byte-identical same-commit Tier A run also passed all ten required governed authoring lifecycles with an empty cleanup ledger. See the [retained compatibility evidence](/docs/databricks/compatibility#current-711-protected-evidence) for the run, commit, digests, and explicit limitations. Stable Databricks services use exact-pinned official modular TypeScript SDKs; preview and workspace-dependent features remain labeled rather than inferred from mock tests. ## Start at your level | Route | Start here | What you keep | | --- | --- | --- | | **Build your first agent** | [Scaffold, mock, connect, and deploy](/docs/databricks/quickstart) | One generated project, deterministic safe-tool test, reviewed environment template, and focused `NEXT_STEPS.md` | | **Choose a workload** | [RAG, analytics, operations, persistent Apps, or native access](/docs/databricks/workloads) | The same agent structure with composable recipes and explicit resource ids | | **Production and advanced controls** | [Identity, policy, durability, certification, and native SDK composition](/docs/databricks/enterprise-adoption) | Required policy-bearing model tools, request-scoped OBO, Lakebase/Temporal options, and certification evidence | The beginner path is ordinary advanced TypeScript—not a separate wizard runtime. Add typed native clients through `bundle.sdk`, custom governed tools, durability, or additional certification without regenerating the project. Advanced control means making identity, resources, effects, and opt-outs more explicit; it does not disable the safe defaults. ```mermaid flowchart LR U[User or system] --> I[HTTP, schedule, channel, or CLI] I --> H[TechFabric Harness agent] subgraph Control[Fabric control plane] H --> P[Policy and approvals] H --> S[Durable session runtime] H --> T[Governed tools] end subgraph Databricks[Databricks data and AI services] T --> M[Unity AI Gateway] T --> Q[SQL Warehouse] T --> V[AI Search] T --> G[Genie Agents] T --> F[Feature Serving] T --> L[Lakeflow Jobs] S --> B[Lakebase] T --> C[Unity Catalog] end C --> D[(Tables and volumes)] H --> O[MLflow and OpenTelemetry] classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef data fill:#dcfce7,stroke:#16a34a,color:#052e16 classDef control fill:#fef3c7,stroke:#d97706,color:#422006 class H fabric class M,Q,V,G,F,L,B,C,D data class P,S,T control ``` ## What is first party | Area | TechFabric Harness surface | Databricks service | | --- | --- | --- | | Model runtime | `databricksFoundationModelProvider()` | Unity AI Gateway model services and custom Model Serving endpoints | | Data access | `databricksSqlReadTool()`, `databricksSqlTool()`, `databricksSqlSandbox()`, `sandbox: 'databricks'` | SELECT-only analytics reads, approval-bound arbitrary SQL, and SQL Warehouses | | Governance | `withGovernance()`, policy and approval helpers | Unity Catalog remains the authorization authority | | Agent interoperability | `responses` endpoint, `databricks-app`, `databricks-serving` | Responses API and MLflow ResponsesAgent | | Agent discovery and grants | `bundle.agentServices` | Unity Catalog Agent Services | | Retrieval | `databricksAiSearch()`, `databricksEmbeddings()` | Databricks AI Search and Model Serving | | Analytics | `databricksGenieTool()`, `DatabricksGenieAgentModeClient`, `databricksAiQueryTool()` | Ordinary Genie conversations, explicit Beta Agent Mode streaming, and AI Functions | | Features | `databricksFeatureLookupTool()` | Feature Serving | | Orchestration | Jobs, notebooks, and `databricksLakeflowTools()` | Jobs and Lakeflow pipelines | | Resource management | Stable opt-in Jobs, Lakeflow, AI Search, custom-model serving, managed UC, workspace, and secret-reference tools; beta Genie Agent lifecycle | Governed create/verify/mutate/delete lifecycles with capability-specific evidence | | Durable state | `lakebaseClient()`, `databricksPersistence()` | Lakebase Autoscaling | | Files | Volume source/writer and `UcVolumesAttachmentStore` | Unity Catalog Volumes and Files API | | Operations | MLflow tracing, usage capture, consumption, actual-cost budgets | MLflow and system tables | | Hosting | `databricks-app`, `databricks-serving` | Databricks Apps and Model Serving proxy | | Native access | `databricksSdk()`, `databricksWorkspaceApi()` | Generated service clients plus credential-safe access to the remaining workspace APIs | ## What Databricks teams can deliver | Starting workload | Recommended Fabric path | First proof to capture | | --- | --- | --- | | Governed analytics copilot | Genie plus `databricksSqlReadTool()` and `analyticsCopilotGovernance()` | OBO identity, allowed `SELECT`, blocked mutation, inspectable SQL, actual-cost attribution | | RAG or knowledge assistant | `databricksAiSearch()` plus `createDatabricksRagChain()` and AI Gateway | Known answer with citations, insufficient-context refusal, MLflow evaluation record | | Durable App | `databricks-app` plus `databricksPersistence()` on Lakebase | Create a session, restart the App, recover conversation offsets and submissions | | Data engineering operator | Jobs/Lakeflow tools with approval policy | Exact-input approval, idempotent run receipt, status/output collection, cleanup | | Interoperable agent service | Responses API plus MLflow ResponsesAgent or Agent Services registration | Authenticated `/api/responses`, trace correlation, discovery and grant evidence | For a multi-team rollout, use the [enterprise adoption guide](/docs/databricks/enterprise-adoption). It maps workloads to platform prerequisites, identity choices, operating ownership, rollout phases, and production exit evidence. ## Choose the right starting point - Read [why Fabric on Databricks](/docs/databricks/why-fabric) to understand what Fabric adds above native SDK clients, which responsibilities remain with Databricks, and when not to add a harness. - Use the [enterprise adoption guide](/docs/databricks/enterprise-adoption) to align application, platform, security, and data-governance teams on a workload and production path. - Read [Databricks development with TechFabric Harness](/docs/databricks/development) to understand the local-to-App workflow, supported workload patterns, AI Gateway integration, and where Fabric adds value. - Use [native access and platform coverage](/docs/databricks/native-access) for the generated clients, unrestricted workspace API escape hatch, coverage dimensions, and known gaps. - Build an interoperable App or serving agent with [Responses API and ResponsesAgent](/docs/databricks/responses-agent). - Register an external agent for discovery and governance with [Unity Catalog Agent Services](/docs/databricks/agent-services). - Use the [Databricks workload map](/docs/databricks/workloads) to choose a typed API, managed recipe, or Databricks-native escape hatch. - Use [Fabric Desktop for Databricks projects](/docs/databricks/fabric-desktop) for a guided recipe, workspace discovery, mock/live run, build, preview, and Databricks App deployment workflow. - Use the [quickstart](/docs/databricks/quickstart) to run a mocked agent and then connect a workspace. - Read [architecture](/docs/databricks/architecture) to understand identity, control, and data flow. - Use [integrations](/docs/databricks/integrations) as the feature and API map. - Use [resource management](/docs/databricks/authoring) for approval-gated creation, protected live lifecycle tests, cleanup, and production-readiness status. - Choose an execution surface with [compute patterns](/docs/databricks/compute). - Read [connectors and sandboxes](/docs/databricks/sandboxes-connectors) before choosing SQL execution, Volumes, or a general-purpose code sandbox. - Apply the [enterprise controls](/docs/databricks/enterprise) for production identity, approvals, audit, durability, and cost limits. - Use the evidence-driven [workspace compatibility matrix](/docs/databricks/compatibility) for cloud, region, auth, API, App, and Lakebase requirements. - Review [authoring certification](/docs/databricks/authoring-certification) for automated test coverage, destructive protected-workspace lifecycles, cleanup behavior, and retained release evidence. ## Workspace validation Before deploying, run the Databricks certification command against the target workspace. It verifies OAuth scopes, Unity Catalog grants, API access, App resources, Unity AI Gateway model services, SQL Warehouses, and Lakebase connectivity while producing secret-redacted evidence for the deployment record. Follow [authoring certification](/docs/databricks/authoring-certification) for the exact configuration, cleanup contract, and retained release evidence. --- # Why TechFabric Harness on Databricks Canonical: https://harness.techfabric.com/docs/databricks/why-fabric What Fabric adds above Databricks native SDKs, governance, data, AI, and compute—and when to use the native platform directly. ## The 30 second answer **Databricks decides who can touch data, models, and compute. Fabric decides how an autonomous agent runs.** | Layer | Owner | Examples | | --- | --- | --- | | Platform of record | **Databricks** | Unity Catalog, AI Gateway, Apps, Genie, Jobs, Lakeflow, Lakebase, MLflow | | Durable agent control | **TechFabric Harness** | Recoverable runs, exact-operation approvals, portable policy, sandboxes, evidence, multi-target deploy | Fabric does **not** replace Databricks. It is optional when AppKit’s request/thread lifecycle is enough, and valuable when work must outlive a request, wait for a steward, run isolated shell or filesystem tasks, or leave portable recovery evidence—on Databricks and beyond. ### Use AppKit (or native) when - the app and users live entirely in Databricks; - the agent is primarily interactive chat, Genie, analytics, files, or Model Serving; - request-scoped approval and thread persistence meet the recovery bar. ### Use Fabric on Databricks when - a run must survive process failure, a multi-day approval, or worker replacement; - policy must cover tools **and** commands, filesystems, networks, connectors, or sandboxes; - the same agent must run locally, on a Databricks App, and optionally on Temporal or another cloud; - operators need retry classification, principal lineage, replay, cost attribution, and cleanup evidence. ### Use both when Fabric owns a broader durable workflow and calls Agent Bricks, Genie, Model Serving, Jobs, or AI Search as governed native capabilities. Application code can use `bundle.sdk`; only selected operations are exposed to the model through `bundle.tools`. --- TechFabric Harness is a **Databricks partner-built application and agent accelerator**. It composes and operationalizes Databricks-native capabilities; it does not replace or replicate them. TechFabric Harness and the current Databricks developer platform are **complementary below the agent runtime and competitive at the agent-runtime boundary**. The [Databricks Developer Hub](https://developers.databricks.com/docs/start-here) brings Apps, Lakebase, Agent Bricks, the Data Lakehouse, AppKit, agent skills, and coding-agent templates into one developer path. Databricks remains the native data, AI, compute, identity, governance, and hosting platform. Fabric uses those capabilities as the native foundation. Databricks now also offers a beta [AppKit agent host](https://developers.databricks.com/docs/appkit/v0/plugins/agents) with TypeScript and Markdown definitions, scoped tools, subagents, threads, cancellation, human approval, and Responses-compatible routes. Those features overlap directly with part of TechFabric Harness. Use AppKit directly when a Databricks-only interactive agent and its request/thread lifecycle meet the requirement. Add Fabric when execution must survive process failure or a long approval wait, policy must travel across infrastructure, work needs an isolated shell or filesystem, or operators need a durable record of recovery and effects. The result remains a Databricks App, Job, Lakeflow pipeline, MLflow experiment, Unity Catalog securable, or other native resource that developers can inspect and operate with Databricks tooling. ## The boundary ```mermaid flowchart LR APP[Your TypeScript agent] subgraph Fabric[TechFabric Harness durable control layer] RUN[Finite runs, persistent agents, recovery] GOV[Portable policy and durable approvals] ISO[Tasks, sources, shell, sandboxes] OBS[Replay, evidence, cost, artifacts] end subgraph Native[Databricks application and agent platform] APPKIT[Apps and AppKit agents] BRICKS[Agent Bricks] SDK[Official modular TypeScript SDKs] IAM[OAuth, App identity, OBO] UC[Unity Catalog and ACLs] DATA[SQL, AI Search, Genie] WORK[Jobs, Lakeflow, Model Serving] STATE[Lakebase, Volumes, MLflow] end APP --> RUN APP --> APPKIT RUN --> GOV RUN --> ISO GOV --> SDK APPKIT --> SDK APPKIT --> BRICKS SDK --> IAM IAM --> UC SDK --> DATA SDK --> WORK RUN --> STATE RUN --> OBS RUN -. governed endpoint .-> BRICKS classDef fabric fill:#f8e8d9,stroke:#b8541f,color:#0e1116 classDef native fill:#f2ede4,stroke:#7a8290,color:#0e1116 class RUN,GOV,ISO,OBS fabric class APPKIT,BRICKS,SDK,IAM,UC,DATA,WORK,STATE native ``` Stable Databricks operations use the official modular TypeScript SDKs. Every generated SDK package is exact-pinned to one reviewed version and exercised through serialization, authentication, and live-workspace tests. A small private protocol adapter is restricted to endpoints the SDK does not yet expose, such as selected Beta protocols; it is not a public general-purpose REST client. Fabric does not replace Unity Catalog or weaken its decisions. Fabric can reject an operation before it reaches Databricks, but Databricks remains the final authorization boundary. Agent Bricks can be a managed agent endpoint that Fabric invokes, while Apps and Lakebase can host and persist the Fabric runtime. ## Where the products overlap | Capability | Databricks AppKit or Agent Bricks | TechFabric Harness | Relationship | | --- | --- | --- | --- | | TypeScript agent authoring | AppKit `createAgent()` and `runAgent()` | `defineAgent()` for finite agents and `createAgent()` for persistent agents | Direct overlap, with different lifecycle semantics | | Threads and streaming | AppKit thread stores, chat streaming, invocation and Responses routes | Sessions, conversation streams, submissions, typed client, React hooks, and Responses interoperability | Direct overlap | | Tool scoping | Plugin toolkits, allowlists, read-only SQL, MCP host policy | Typed tools plus definition policy across tools, commands, filesystems, networks, sandboxes, credentials, and connectors | Overlap; Fabric policy spans more execution surfaces | | Human approval | Request-stream approval for mutating AppKit tools | Exact-operation and principal-bound approvals that can be persisted by the selected runtime/store | Overlap; durable waits are a Fabric advantage | | Identity | App service principals and OBO user execution | Principal propagation through model, tools, approvals, lineage, submissions, and request-scoped bundles | Complementary and overlapping | | Managed agents | Knowledge Assistants, Genie, Supervisor Agents, and custom agents | Invoke managed endpoints as tools or compose custom finite and persistent agents | Complementary or substitutable by workload | | Model and data governance | Unity AI Gateway, Unity Catalog, MLflow, system tables | Defense-in-depth policy, budgets, correlation, redaction, and governed tool contracts | Complementary | | Durable workflow recovery | Request and thread lifecycle; AppKit documents cancellation and pluggable thread storage | Retry classification, leases, submissions, checkpoints, replay, cancellation propagation, recovery, and deterministic Temporal workflows | Fabric advantage | | Isolated agent work | Databricks application and compute services | Portable sandboxes, tasks, shell, mounted sources, artifacts, snapshots, forks, and cross-process sandbox references | Fabric advantage | | Runtime portability | Databricks workspace and App hosting | Node, Docker, Temporal, Cloudflare, Azure-oriented targets, Kubernetes patterns, Databricks, and custom backends | Fabric advantage | ## Advantages to lead with ### Durable execution beyond a request Fabric distinguishes finite, bounded agents from persistent, addressable agents. Submissions carry stable identity and terminal state; retries are bounded and classified; leases prevent competing workers; cancellation propagates; checkpoints and replay make recovery inspectable. The optional Temporal runtime preserves this contract across worker restarts and long waits without making Temporal a requirement for local authoring. ### Governance that remains attached to the effect Definition policy is a security floor: invocation policy may narrow it but cannot silently widen it. Approval grants bind the exact tool or command input and executing principal. Policy covers more than model tools—it can constrain commands, filesystem reads and writes, network destinations, credentials, connectors, sandboxes, budgets, and timeouts. Events, lineage, cost, artifacts, and terminal state remain correlated with the governed operation. ### Portable isolated execution Fabric sessions can mount sources, run tasks and shell commands, create artifacts, checkpoint or fork capable sandboxes, and hand portable sandbox references across processes. Backend capability discovery keeps this contract explicit across local, Docker, Kubernetes, Cloudflare, Daytona, E2B, Modal, Databricks SQL, and other adapters. ### One contract beyond Databricks The same agent, session, tool, policy, source, store, and event contracts can run on Databricks or outside it. This matters when a workflow starts in a Databricks App but also coordinates GitHub, Slack, cloud infrastructure, external databases, an isolated code environment, or a durable worker. ## Full Fabric feature surface on Databricks | Developer need | Databricks provides | Fabric adds above it | | --- | --- | --- | | Model inference | Unity AI Gateway and Model Serving | One model-provider contract, OAuth refresh, bounded retries, request correlation, usage, and redacted failures | | Governed data access | SQL Warehouses and Unity Catalog | Model-safe typed tools, structured resource extraction, catalog allowlists, approval routing, and denial lineage | | RAG | AI Search, embeddings, AI Gateway, MLflow evaluation | A composed retrieve/generate/validate path, typed citations, durable sessions, evaluation export, and release gates | | Genie | Genie conversations, Agents, ACLs, and Agent Mode | Conversation tools, lifecycle management, managed-only deletion, approval binding, durable ownership, and bounded Beta streaming | | Data operations | Jobs, Lakeflow, notebooks, and serving endpoints | Compute-policy validation, idempotency and fingerprints, durable receipts, repair/status collection, approvals, and cleanup | | Resource management | Native create/update/delete APIs | Opt-in model write tools that fail closed, bind approval to exact input and principal, and delete only Harness-managed resources | | Identity | OAuth M2M, Databricks App identity, OBO | One verified principal propagated through model, tools, approvals, lineage, and request-scoped bundles without putting tokens in model context | | Durable state | Lakebase and UC Volumes | Sessions, submissions, conversation offsets, attachments, leases, restart recovery, and cascade deletion | | Operations | MLflow and system tables | Agent/run/tenant correlation, estimated and actual-cost controls, cleanup ledgers, and capability-specific certification evidence | | Delivery | Databricks Apps and Model Serving | Local mock mode, typed agent definitions, reproducible build targets, Responses API interoperability, and the same runtime contract on other clouds | The complete Fabric surface also includes typed inputs and results, roles, Markdown-first skills, session memory, tasks and subagents, attachments, artifacts, filesystem sources, MCP, channels, schedules, webhooks, queues, the Fiber console, React hooks, OpenTelemetry, evaluation helpers, portable builds, certification, and supply-chain evidence. Not every individual feature is unique; the differentiator is the durable, policy-constrained, portable contract that holds them together. ## Typed clients and model tools are deliberately different Fabric exposes two seams: - `bundle.sdk` contains principal-bound native Databricks clients for deterministic application code. Calling one is no more autonomous than calling the Databricks SDK yourself. - `bundle.tools` contains bounded `ToolDef` objects that a model may select. Write and execute tools carry effect metadata, governance descriptors, approval requirements, redaction, and lineage. This separation prevents “the application can create a Job” from silently becoming “the model can create any Job.” Model-facing write surfaces are opt-in and fail initialization when their approval or compute policy is incomplete. ```ts import { databricks } from '@fabric-harness/databricks'; import { init } from '@fabric-harness/sdk'; const dbx = databricks({ host: process.env.DATABRICKS_HOST!, principal: { kind: 'service-principal', host: process.env.DATABRICKS_HOST!, clientId: process.env.DATABRICKS_CLIENT_ID!, clientSecret: process.env.DATABRICKS_CLIENT_SECRET!, }, model: 'system.ai.gpt-oss-20b', warehouseId: process.env.DATABRICKS_WAREHOUSE_ID, aiSearch: { index: 'main.knowledge.docs_index', textColumn: 'chunk', idColumn: 'id', }, governance: { catalogs: ['main'], stewardAudience: 'data-platform', }, }); const fabric = await init({ modelProvider: dbx.modelProvider, tools: dbx.tools, policy: dbx.policy, store: dbx.store, }); ``` This bundle uses one identity for AI Gateway, generated SDK clients, SQL, retrieval, and optional Lakebase credential exchange. Add resource-management flags only when the agent truly needs them. ## Choose the right runtime Use Databricks AppKit directly when: - the application and its users live entirely in Databricks; - the agent is primarily interactive chat, Genie, analytics, files, or Model Serving; - request-scoped approval and thread persistence meet the recovery requirement; and - a Databricks-native application and deployment lifecycle is preferred over runtime portability. Use Fabric on Databricks when one or more of these are requirements: - a run must survive process failure, an approval delay, a worker replacement, or a multi-step workflow; - policy must remain enforceable across Databricks and non-Databricks tools, commands, filesystems, networks, connectors, or sandboxes; - the workload needs tasks, shell execution, mounted sources, checkpoints, forks, attachments, or artifacts around Databricks data and AI; - the same finite or persistent agent needs local tests, a Databricks App, another cloud deployment target, or an optional Temporal worker; - operators need retry and terminal-state classification, tenant/principal lineage, replay, cost attribution, cleanup evidence, and reproducible certification; or - a workflow coordinates Databricks with channels, external systems, or isolated compute. Use both when Fabric owns a broader durable workflow and calls Agent Bricks, Genie, Model Serving, Jobs, Lakeflow, AI Search, or another App as a governed native capability. Application code can use `bundle.sdk`, while only selected operations are exposed to the model through `bundle.tools`. Use the native Databricks SDK without either agent runtime when the flow is short, deterministic application code. ## What Fabric does not claim - It is not a replacement for Databricks SDKs, CLI, Declarative Automation Bundles, Terraform, Apps or AppKit, Agent Bricks, Unity Catalog, MLflow, Jobs, Lakeflow, AI Search, Genie, Lakebase, Model Serving, or AI Gateway. - It does not claim that ordinary TypeScript agent definitions, threads, scoped tools, streaming, or request-time HITL are unique to Fabric. - It does not make a preview API stable; preview capabilities remain labeled and require their own workspace evidence. - It does not infer AWS or GCP compatibility from an Azure certification run. - It does not put workspace tokens, raw secret values, or user-supplied identity labels into model context. - It cannot make an unbounded autonomous agent safe. Production deployments still need least privilege, explicit tools, budgets, approvals, evaluation, and workspace-specific tests. ## Continue - [Build a Databricks agent](/docs/databricks/development) - [Run RAG on Databricks](/docs/databricks/rag) - [Manage Databricks resources safely](/docs/databricks/authoring) - [Understand identity and control flow](/docs/databricks/architecture) - [Review native SDK and workspace compatibility](/docs/databricks/compatibility) - [Inspect live authoring certification evidence](/docs/databricks/authoring-certification) --- # Databricks development with TechFabric Harness Canonical: https://harness.techfabric.com/docs/databricks/development Turn Databricks AI and data services into durable, governed TypeScript applications with a local-first workflow. TechFabric Harness is the application runtime around Databricks AI and data services. It does not replace Unity Catalog, Spark, Lakeflow, MLflow, Jobs, SQL Warehouses, or Model Serving. It gives developers one TypeScript workflow for composing those services into agents that can run locally, deploy to Databricks Apps, preserve identity, enforce policy, persist state, and produce operational evidence. ## Where Fabric fits ```mermaid flowchart LR subgraph Author[Developer workflow] CODE[TypeScript job or agent] MOCK[Local mock and tests] BUILD[Fabric build] end subgraph Runtime[Fabric application runtime] APP[Databricks App] LOOP[Session and model loop] POLICY[Policy and approvals] AUDIT[Lineage, cost, and telemetry] end subgraph Platform[Databricks services] GATEWAY[Unity AI Gateway] DATA[SQL and Unity Catalog] RAG[AI Search and Genie] COMPUTE[Jobs and Lakeflow] STATE[Lakebase and Volumes] MLFLOW[MLflow and system tables] end CODE --> MOCK MOCK --> BUILD BUILD --> APP APP --> LOOP LOOP --> POLICY POLICY --> GATEWAY POLICY --> DATA POLICY --> RAG POLICY --> COMPUTE LOOP --> STATE LOOP --> AUDIT AUDIT --> MLFLOW classDef author fill:#f4f4f5,stroke:#71717a,color:#18181b classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef control fill:#fef3c7,stroke:#d97706,color:#422006 classDef dbx fill:#dcfce7,stroke:#16a34a,color:#052e16 class CODE,MOCK,BUILD author class APP,LOOP,AUDIT fabric class POLICY control class GATEWAY,DATA,RAG,COMPUTE,STATE,MLFLOW dbx ``` Databricks remains authoritative for data permissions, compute, model access, and platform operations. Fabric owns the agent lifecycle around those services: admission, sessions, tools, approvals, durable state, retries, typed results, audit correlation, and deployment artifacts. ## Start locally, connect later Create a Databricks-oriented project without requiring workspace credentials: ```sh npx @fabric-harness/cli init \ --template databricks \ --dir analytics-agent cd analytics-agent npm install ``` The template creates a finite analytics job, role, skill, governed SQL policy, Databricks App configuration, environment sample, and certification manifest. ```sh fh agents fh describe databricks-analyst fh run databricks-analyst \ --question 'Describe main.sales.orders' \ --mock ``` Mock mode exercises discovery, input validation, tool assembly, the model loop, and HTTP routing. It deliberately does not simulate Unity Catalog grants or claim that a workspace API succeeded. When the local behavior is ready, configure a PAT for single-user development or OAuth M2M for a production-like service principal: ```dotenv title=".env.local" DATABRICKS_HOST=https://adb-1234567890123456.7.azuredatabricks.net DATABRICKS_CLIENT_ID=00000000-0000-0000-0000-000000000000 DATABRICKS_CLIENT_SECRET=resolve-from-your-secret-manager DATABRICKS_WAREHOUSE_ID=0123456789abcdef DATABRICKS_MODEL=databricks-gpt-oss-20b DATABRICKS_INFERENCE_MODE=auto ``` Run the same definition without `--mock` to exercise the real workspace. See [Local naming and authentication](/docs/databricks/local-naming-auth) for PAT, OAuth M2M, App identity, OBO, tenant, and deployment-profile behavior. ### Model selection and precedence The scaffolded default, `databricks-gpt-oss-20b`, is a bare foundation-model serving endpoint (pay-per-token) that works on every workspace tier, including free tiers without Unity AI Gateway. A `system.ai.*` model service routes through Unity AI Gateway instead and 404s on workspaces where the gateway is not enabled. When several sources name a model, the first one wins: 1. `fh run --model ` 2. `FABRIC_MODEL` 3. `run.model` in `.fabricharness/config.ts` 4. the job file's `model:` field 5. `agent.model` in `.fabricharness/config.ts` 6. `DATABRICKS_MODEL` — the bundle model provider's default, used only when nothing above names a model `DATABRICKS_MODEL` therefore cannot rescue a bad value set higher in the chain; fix the job file or config instead. A `databricks/`-prefixed reference (for example `databricks/databricks-gpt-oss-20b`) is accepted anywhere a model is named — the Databricks provider strips its routing prefix at the wire boundary, so serving endpoints always receive the bare endpoint name and a prefixed `system.ai.*` reference still routes through AI Gateway. If required environment variables are missing, the first live run fails once with the full list of missing prerequisites (host, warehouse, Genie space, steward audience, cost enforcement) instead of failing fast one variable at a time. ## Use AI Gateway without custom HTTP plumbing Use a discovered `system.ai.*` service as the model: ```ts title=".fabricharness/jobs/databricks-analyst.ts" import { defineDatabricksAgent } from '@fabric-harness/databricks'; import { schema } from '@fabric-harness/sdk'; import policy from '../policies/databricks.js'; export default defineDatabricksAgent({ name: 'databricks-analyst', description: 'Answer governed questions using workspace data.', input: schema.object({ question: schema.string() }), output: schema.string(), model: 'system.ai.gpt-oss-20b', tools: ['sql-read', 'tables', 'table-info'], triggers: { manual: true, webhook: true }, sandbox: 'empty', policy, }); ``` Fabric automatically routes `system.ai.*` through the workspace Unity AI Gateway path. Custom endpoint names route through Model Serving. The Databricks provider adds: - OAuth token acquisition, caching, and early refresh; - request tags for submission, attempt, tenant, and agent identifiers; - retry-safe requests and redacted provider errors; - model usage and cost correlation; - a common provider contract for local tests and deployed runtimes. Discover enabled services in the target workspace instead of assuming a model is available. The [integration map](/docs/databricks/integrations#inference-names-and-urls) documents automatic routing and explicit overrides. ## Compose the governed Databricks stack Use `databricks()` when an application needs several Databricks services under one identity: ```ts import { databricks } from '@fabric-harness/databricks'; import { init } from '@fabric-harness/sdk'; const dbx = databricks({ host: process.env.DATABRICKS_HOST!, principal: { kind: 'service-principal', host: process.env.DATABRICKS_HOST!, clientId: process.env.DATABRICKS_CLIENT_ID!, clientSecret: process.env.DATABRICKS_CLIENT_SECRET!, }, model: 'databricks-gpt-oss-20b', warehouseId: process.env.DATABRICKS_WAREHOUSE_ID, aiSearch: { index: 'main.knowledge.docs_index', textColumn: 'chunk', idColumn: 'id', strategy: 'hybrid', }, genie: { conversations: { agentId: process.env.DATABRICKS_GENIE_SPACE_ID! }, }, lakeflow: true, // list/status only; add { runPolicy } for start/stop consumption: true, governance: { catalogs: ['main'], stewardAudience: 'data-steward', }, }); const runtime = await init({ modelProvider: dbx.modelProvider, tools: dbx.tools, policy: dbx.policy, store: dbx.store, }); ``` One principal is threaded through model calls, generated Databricks SDK clients, SQL, and optional Lakebase credential exchange. Fabric policy can narrow access or require approval, while Unity Catalog and Databricks resource ACLs make the final authorization decision. ## Add only the workloads you need Managed recipes add project-local wiring, compatible dependencies, environment stubs, and verification commands: ```sh fh add databricks core fh add databricks sql fh add databricks ai-search fh add lakebase fh add lakeflow fh add jobs ``` Recipes are dependency-aware and refuse incompatible ranges rather than silently replacing them. Use `fh add --dry-run` to inspect changes and `fh update` to update managed recipe files. ## Workload patterns | Workload | Databricks services | What Fabric adds | | --- | --- | --- | | Governed lakehouse analyst | AI Gateway, SQL Warehouse, Unity Catalog | Typed input/output, SQL policy, approvals, tenant identity, audit lineage | | RAG application | AI Search, AI Gateway, MLflow 3 | Retrieval orchestration, validated citations, evaluation export, release quality gates | | Persistent copilot | Databricks Apps, Lakebase, UC Volumes | Addressable instances, conversation streams, durable submissions, attachments, deletion | | Data operations agent | Jobs, notebooks, Lakeflow | Idempotent admission, status/output collection, approval gates, durable receipts | | BI assistant | Genie, SQL Warehouse, Unity Catalog | Governed tool composition, session context, principal and tenant propagation | | Feature-aware agent | Feature Serving, Model Serving | Low-latency feature lookup as a governed tool with model usage correlation | | Model Serving integration | AI Gateway or custom endpoints | One provider API, OAuth refresh, request tags, retries, usage and cost attribution | | Agent interoperability | Responses API, MLflow ResponsesAgent, Databricks Apps | Durable `/responses` endpoint plus a registered Python proxy in Model Serving | | External agent governance | Unity Catalog Agent Services and HTTP connections | Discoverable agent registration, standard UC grants, lifecycle certification, and cleanup | ## Databricks-native RAG quality Fabric's deterministic RAG chain follows a preprocess, retrieve, augment, generate, and validate flow. AI Search performs retrieval, AI Gateway performs generation, and MLflow 3 performs managed evaluation. ```mermaid flowchart LR QUESTION[Golden-set question] --> RETRIEVE[AI Search retrieval] RETRIEVE --> GENERATE[AI Gateway generation] GENERATE --> TRACE[MLflow trace] TRACE --> JUDGES[Managed judges] JUDGES --> REL[Answer relevance] JUDGES --> RREL[Retrieval relevance] JUDGES --> GROUND[Groundedness] JUDGES --> SUFF[Sufficiency] JUDGES --> CORRECT[Correctness] REL --> GATE{All meet threshold?} RREL --> GATE GROUND --> GATE SUFF --> GATE CORRECT --> GATE GATE -->|Yes| PASS[Release evidence] GATE -->|No| BLOCK[Block release] classDef source fill:#f4f4f5,stroke:#71717a,color:#18181b classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef dbx fill:#dcfce7,stroke:#16a34a,color:#052e16 classDef decision fill:#fef3c7,stroke:#d97706,color:#422006 classDef deny fill:#fee2e2,stroke:#dc2626,color:#450a0a class QUESTION source class RETRIEVE,GENERATE,TRACE,JUDGES dbx class REL,RREL,GROUND,SUFF,CORRECT,PASS fabric class GATE decision class BLOCK deny ``` The certification fixture uses managed relevance, retrieval relevance, groundedness, sufficiency, and correctness judges with a configurable threshold. A project should replace the small certification fixture with its own domain questions, expected facts, retrieval expectations, insufficient-context cases, and adversarial inputs. See [RAG on Databricks](/docs/databricks/rag). ## Durable Apps instead of stateless demos `databricks-app` bundles the Node server and agent definitions for Databricks Apps. Optional Lakebase persistence stores sessions, submissions, and conversation streams. Unity Catalog Volumes store governed attachments. ```sh fh build --target databricks-app fh deploy --preview --target databricks-app --profile analytics-dev fh deploy --target databricks-app --profile analytics-dev ``` The generated artifact contains `app.yaml`, `databricks.yml`, the self-contained server bundle, roles, skills, definitions, and build manifest. Runtime credentials come from App identity and resource bindings, not the developer's deployment profile. For configuration-preserving recovery, redeploy the generated bundle with the same variables. A bare App start can omit values injected during deployment. The [Databricks App tutorial](/docs/deployment/databricks-app) documents the certified deployment and recovery procedure. ## Governance and operations are runtime behavior Fabric controls are evaluated around every agent operation rather than described only in a prompt: - capability and catalog policies constrain available actions; - sensitive SQL, pipeline, and mutation tools can require durable approval; - Fabric principals and tenants propagate into submissions and request tags; - Unity Catalog remains authoritative for tables, schemas, volumes, rows, and columns; - Lakebase telemetry joins actors, submissions, governed objects, outcomes, and estimated cost; - System Tables reconcile delayed actual usage with tenant and agent budgets; - cascade deletion removes sessions, submissions, streams, and attachments; - MLflow and OpenTelemetry expose traces and operational evidence. This is most useful when an agent moves from a notebook experiment to a shared application with multiple users, governed data, long-running work, or production operating requirements. ## When to use TechFabric Harness Use Fabric when the application needs several of these together: - local TypeScript development and Databricks App deployment; - model calls plus SQL, retrieval, Jobs, Lakeflow, Genie, or Feature Serving; - persistent agents or durable workflow state; - user, service-principal, tenant, and OBO identity propagation; - approval, policy, audit, deletion, or cost enforcement; - repeatable workspace certification and deployment evidence. A direct Databricks SDK or notebook is usually simpler for a one-off query, a standalone Spark transformation, or a single model request with no agent lifecycle. Fabric is valuable when those calls need to become a governed application. ## Production validation Fabric ships local contracts and a protected workspace certification runner. Before approving a deployment, validate the actual cloud, region, workspace, identity, resources, data, and workload: 1. Verify OAuth M2M or App identity and every required resource permission. 2. Prove one allowed and one deliberately denied Unity Catalog operation. 3. Exercise AI Gateway, SQL, retrieval, Jobs, Lakeflow, and other enabled services. 4. Deploy the App, persist work, redeploy, and verify recovery and cascade deletion. 5. Run the project's MLflow evaluation dataset and enforce quality thresholds. 6. Verify lineage and System Tables cost reconciliation for real tenant tags. 7. Test concurrency, rate limits, long-running work, and expected failure modes. 8. Exercise OBO login, expiry, refresh, and user-specific grants when OBO is enabled. 9. Retain redacted certification, compatibility, recovery, and conformance evidence. Certification records are environment-specific. Do not infer that a passing Azure workspace also certifies an untested AWS/GCP workspace, region, preview feature, or production corpus. Use the [workspace compatibility matrix](/docs/databricks/compatibility) and [authoring certification guide](/docs/databricks/authoring-certification) for the complete evidence path. ## Next steps - [Create the reference project](/docs/databricks/quickstart) - [Understand local names and identities](/docs/databricks/local-naming-auth) - [Choose Databricks integrations](/docs/databricks/integrations) - [Build and evaluate RAG](/docs/databricks/rag) - [Deploy a Databricks App](/docs/deployment/databricks-app) - [Apply enterprise controls](/docs/databricks/enterprise) --- # Responses API and ResponsesAgent Canonical: https://harness.techfabric.com/docs/databricks/responses-agent Expose a durable TechFabric Harness agent through the OpenAI Responses API and MLflow ResponsesAgent on Databricks Apps and Model Serving. TechFabric Harness exposes persistent agents through `POST /responses`, the interface Databricks uses for new agent Apps. The same contract is packaged as an MLflow `ResponsesAgent` for Model Serving, AI Playground, evaluation, monitoring, and clients that use `DatabricksOpenAI.responses`. ```mermaid flowchart LR CLIENT[DatabricksOpenAI or HTTP client] -->|Direct POST /responses| APP[Databricks App] CLIENT -->|Serving invocation| SERVING[Model Serving and AI Playground] SERVING --> PROXY[MLflow ResponsesAgent proxy] PROXY -->|POST /responses| APP APP --> AUTH[OAuth or App OBO identity] AUTH --> API[Fabric Responses adapter] API --> SUB[Durable submission] SUB --> AGENT[Persistent Fabric agent] AGENT --> DBX[AI Gateway, SQL, AI Search, Genie, MCP] AGENT --> EVENTS[Token and tool events] EVENTS -->|SSE| CLIENT SUB --> STORE[Lakebase session and submission stores] SUB --> TRACE[MLflow trace] ``` ## Build your first Responses agent Create `.fabricharness/agents/analyst.ts`: ```ts import { createAgent } from '@fabric-harness/sdk'; export default createAgent(({ id }) => ({ name: 'analyst', model: 'databricks/system.ai.gpt-oss-20b', sandbox: 'virtual', instructions: `You are a governed data analyst for instance ${id}.`, triggers: { webhook: true }, })); ``` Enable the endpoint in `.fabricharness/config.ts`: ```ts import type { FabricHarnessConfig } from '@fabric-harness/node'; export default { run: { idPrefix: 'analytics-agent' }, responses: { agent: 'analyst', defaultSession: 'default', customOutputKeys: ['client_type'], }, } satisfies FabricHarnessConfig; ``` `custom_inputs` are not added to model context. `customOutputKeys` is an explicit allowlist for non-secret values that may be returned under `custom_outputs`; all other custom fields stay outside the prompt and response. By default, each authenticated principal gets a separate persistent agent instance. When you set `responses.instanceId`, it acts as a namespace prefix and Harness still appends the principal id. This prevents two App users who choose the same conversation id from sharing session history. Start locally: ```bash pnpm add @fabric-harness/sdk @fabric-harness/node @fabric-harness/databricks pnpm exec fh dev ``` Call it without streaming: ```bash curl http://localhost:3000/responses \ -H 'content-type: application/json' \ -H 'idempotency-key: analyst-demo-1' \ -d '{ "input": [{"role":"user","content":"Summarize yesterday orders"}], "context": {"conversation_id":"orders-42"}, "custom_inputs": {"client_type":"local-demo"} }' ``` Set `"stream": true` to receive `response.output_text.delta` events followed by one `response.output_item.done` event. All events for an answer use the same item id. Harness normalizes both ordinary string deltas and the typed reasoning/output blocks returned by Unity AI Gateway. Reasoning blocks remain internal; typed `text` and `output_text` blocks become incremental response deltas and the completed output item. ## Continue a conversation Use either durable conversation mechanism: - Send the same `context.conversation_id` for each turn. The authenticated principal selects the persistent agent instance, so one caller cannot select another caller's instance. - Send the prior response `id` as `previous_response_id`. Fabric resolves the original durable submission and reuses its instance and session after checking tenant and principal ownership. An `Idempotency-Key` is scoped to tenant, principal, agent, and key. Retrying the same request returns the same response id. Reusing the key with a different payload is rejected by the submission store. Treat aggregate and streaming calls as separate invocation modes: retry either mode with its original key, but use a new key when changing `stream` because that changes the admitted request payload. ## Authentication on Databricks Locally, use the server bearer token or your configured OIDC authenticator. In a Databricks App: - App authorization runs as the App service principal. - User authorization validates the forwarded token against the workspace current-user API before accepting it. Validation is cached by token digest and bounded by token expiry. - Each validated App user receives a stable, opaque Fabric tenant by default. Session listing, direct reads, approvals, artifacts, abort, and deletion remain inside that tenant; legacy unscoped sessions are not visible to a tenant-bound user. - App users receive only invoke and own-session permissions. The generated authenticator does not grant `admin:read`, `build:read`, `session:replay`, or wildcard access. - Clients must call Apps with Databricks OAuth. Personal access tokens are not supported for App URLs. The generated Declarative Automation Bundle requests the `sql`, `genie`, and `model-serving` user API scopes. Databricks combines those scopes with each user's existing workspace and Unity Catalog permissions. Users must consent after scopes change; restart an older App before adding scopes if the workspace requires it. The App build automatically exposes the first persistent agent. Set `responses.agent` when the workspace contains multiple persistent agents. ```bash fh build --target databricks-app fh deploy --target databricks-app TOKEN="$(databricks auth token --host "$DATABRICKS_HOST" | jq -r .access_token)" curl "$DATABRICKS_APP_URL/responses" \ -H "Authorization: Bearer $TOKEN" \ -H 'content-type: application/json' \ -H 'x-mlflow-return-trace-id: true' \ -d '{"input":[{"role":"user","content":"What changed in revenue?"}],"stream":true}' ``` When `DATABRICKS_MLFLOW_EXPERIMENT_ID` configures the App's MLflow exporter and `x-mlflow-return-trace-id: true` is present, a non-streaming response includes `metadata.trace_id`; a stream emits a separate trace-id event before `[DONE]`. The identifier matches the deterministic MLflow trace produced for the durable submission. `GET /ready` reports `mlflowTracing: configured` without returning the experiment identifier. The bundle attaches the experiment with `CAN_EDIT`, and the final `app.yaml` resolves that managed resource through `valueFrom`. A Databricks App build is not ready when that value was not injected. ## Model Serving interoperability Build the wrapper after the App is reachable: ```bash pnpm add @fabric-harness/databricks fh build --target databricks-serving cd .fabricharness/build/databricks-serving python serving/contract_test.py python3 -m pip install -r serving/requirements.txt fh deploy --target databricks-serving ``` The CLI loads the native Databricks SDK only for the Serving deployment operation. The integration package is therefore an optional CLI peer and an explicit project dependency; a missing package fails before model registration with an install instruction. Databricks init templates and managed recipes add it automatically. The artifact subclasses `mlflow.pyfunc.ResponsesAgent`, declares the MLflow task `agent/v1/responses`, forwards non-streaming and streaming requests to the App, preserves `custom_inputs`, and authenticates to a Databricks App with short-lived OAuth M2M credentials. Use an App-dedicated service principal with `CAN USE`; do not put a personal access token or long-lived workspace token in Model Serving environment variables. The generated requirements accept MLflow `>=3.10`; the protected Azure release gate currently validates model logging and deployment with MLflow `3.14.0`. Optional request fields are read with attribute-safe fallbacks because MLflow's own model-validation input may omit `databricks_options`. Run `serving/contract_test.py` before logging the model and retain the live model-registration result as the compatibility record for your workspace. After model registration, `fh deploy` uses the typed TypeScript serving-admin client to create or update the endpoint and enable an AI Gateway inference table. Payload logging is written under the configured serving catalog and schema with a table prefix derived from the endpoint name. The CLI serializes these mutations: it waits for endpoint readiness before replacing an existing model, waits again before the AI Gateway update, and waits once more before reporting success. This makes release retries safe when an earlier endpoint or gateway configuration is still converging. Databricks agent endpoints currently support inference tables but not Gateway rate limits; the App's authenticated HTTP limiter remains the enforced request boundary. ## Request reference | Field | Purpose | Harness behavior | | --- | --- | --- | | `input` | String or Responses message items | Converted to one bounded agent turn; required | | `stream` | Enable SSE | Emits text deltas, a final output item, optional trace id, then `[DONE]` | | `context.conversation_id` | Durable conversation key | Selects a named session inside the authenticated instance | | `context.user_id` | Client correlation | Accepted as metadata; never trusted for authorization | | `previous_response_id` | Continue a prior response | Resolves a tenant- and principal-owned durable submission | | `custom_inputs` | Application-specific metadata | Kept out of model context unless application code explicitly uses it | | `metadata` | Client metadata | Validated as JSON and kept outside the default prompt | Production errors do not return upstream bodies or secrets. Aborted responses return `409` in non-streaming mode; streams emit `response.failed` with a bounded Databricks error object. ## Release verification Every change runs the Node request/parser and durable endpoint tests plus the generated Python contract. The protected Databricks workflow deploys the App and MLflow wrapper, then verifies OAuth, non-streaming output, streaming deltas, stable item ids, trace correlation, restart recovery, and secret redaction. The public capability registry links the retained `4.4.1` Azure evidence and marks this surface `protected-live`; its product status remains Beta because the upstream API is Beta and it is still a Tier O, Serving-profile check rather than a core Tier R release requirement. See [compatibility and certification](/docs/databricks/compatibility) for the exact artifact identity. References: [Databricks agent authoring](https://docs.databricks.com/aws/en/agents/agent-framework/author-agent), [query deployed agents](https://docs.databricks.com/aws/en/agents/agent-framework/query-agent), and [MLflow ResponsesAgent](https://mlflow.org/docs/latest/genai/serving/responses-agent/). --- # Unity Catalog Agent Services Canonical: https://harness.techfabric.com/docs/databricks/agent-services Register an external TechFabric Harness agent in Unity Catalog, make it discoverable, manage grants, certify the lifecycle, and clean up safely. Unity Catalog Agent Services gives an externally hosted TechFabric Harness agent a governed identity in Databricks. The registration appears beside tables, models, and functions in Catalog Explorer. Teams can discover it with `READ_METADATA`, and administrators can control access with Unity Catalog grants. Agent Services is a Databricks Beta. During the current Beta it supports registration, discovery, metadata updates, permissions, and deletion. Databricks does not yet route runtime requests through the registered service. Use the Harness `/responses` endpoint to invoke the agent directly; use the Agent Service as its Unity Catalog catalog entry and permission boundary. This page also covers the separate **Supervisor Agents** and **managed memory** Betas. Supervisor Agents are Databricks-owned agent runtimes with queryable serving endpoints; Unity Catalog Agent Services registers an externally hosted agent. Harness composes either surface without presenting the native Databricks loop as a Harness loop. ## Compose a native Supervisor Agent Supervisor Agent discovery and invocation use the official generated Databricks SDK. The lifecycle is deliberately hidden until the caller acknowledges the upstream Beta: ```ts import { databricks, databricksManagedAgentTool, } from '@fabric-harness/databricks'; const workspace = databricks({ host: process.env.DATABRICKS_HOST!, principal: { kind: 'service-principal', host: process.env.DATABRICKS_HOST!, clientId: process.env.DATABRICKS_CLIENT_ID!, clientSecret: process.env.DATABRICKS_CLIENT_SECRET!, }, supervisorAgents: { acknowledgeBeta: true }, }); const agents = await workspace.supervisorAgents!.list({ maxPages: 10 }); const tools = await workspace.supervisorAgents!.listTools(agents[0]!.supervisorAgentId!); const answer = await workspace.supervisorAgents!.invoke(agents[0]!.supervisorAgentId!, { input: 'Summarize the renewal risk.', }); const assistant = databricksManagedAgentTool(workspace.agentEndpoints.client, { endpointName: agents[0]!.endpointName!, kind: 'supervisor-agent', resourceId: agents[0]!.name, maxOutputBytes: 512_000, }); ``` `list()` and `listTools()` bound pagination and reject repeated page tokens. `invoke()` resolves the current endpoint with the official SDK, propagates cancellation, disables ambiguous invocation retries, and caps the native response admitted into Harness model context. Knowledge Assistants use the same fixed-resource tool projection with `kind: 'knowledge-assistant'`. The official Beta SDK is available as `workspace.supervisorAgents.sdk` for explicit create, update, tool, example, and delete operations. Those mutations have contract coverage only; they are not yet protected-live certified. ## Use managed memory explicitly Managed memory remains distinct from Harness session and submission persistence. An application must supply the tenant/user scope at a trusted boundary for every entry operation; the scope is not accepted from the model: ```ts const workspace = databricks({ host, principal, managedMemory: { acknowledgeBeta: true }, }); const memory = workspace.managedMemory!; await memory.createEntry( 'main.agents.revenue_memory', `tenant/${authenticatedTenant}/user/${authenticatedUser}`, { path: '/memories/preferences/reporting', contents: 'Prefer quarter-over-quarter comparisons.', }, ); const matches = await memory.search('main.agents.revenue_memory', { scope: `tenant/${authenticatedTenant}/user/${authenticatedUser}`, query: 'reporting preference', topK: 5, }); ``` Store and entry create/read/update/delete plus bounded search are supported behind explicit Beta acknowledgement. Paths are restricted to `/memories/`, parent traversal is rejected, search limits are bounded, and deletion semantics remain an application-owned retention decision. This adapter uses a reviewed narrow protocol allowlist because Databricks does not currently ship the managed memory API in its generated TypeScript SDK. It has deterministic contract tests, not retained live certification. ```mermaid flowchart LR DEV[Developer or CI] --> SDK[databricks bundle.agentServices] SDK --> UC[Unity Catalog Agent Service] UC --> META[Catalog Explorer discovery] UC --> GRANTS[READ_METADATA and EXECUTE grants] UC --> CONN[Unity Catalog HTTP connection] CONN -. records host and credentials .-> APP[TechFabric Harness App] USER[Application caller] -->|POST /responses| APP APP --> SESSION[Durable Harness session] SESSION --> DBX[Databricks data and AI services] classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef governed fill:#dcfce7,stroke:#16a34a,color:#052e16 classDef identity fill:#fef3c7,stroke:#d97706,color:#422006 class SDK,APP,SESSION fabric class UC,META,GRANTS,DBX governed class CONN identity ``` ## The four objects involved | Object | Purpose | Credential owner | | --- | --- | --- | | Harness App or external server | Runs the agent and exposes `POST /responses` | TechFabric Harness deployment | | Unity Catalog HTTP connection | Stores the agent host and external-service credential | Unity Catalog | | Unity Catalog Agent Service | Makes the agent discoverable and permissioned | Unity Catalog | | Workspace OAuth/PAT identity | Creates and manages the registration | Developer, CI service principal, or App service principal | The workspace credential used by `@fabric-harness/databricks` is not sent to the external agent. The HTTP connection stores the credential used to reach the agent, such as `FABRIC_HARNESS_API_TOKEN`. Keeping these identities separate prevents a workspace administrator token from becoming an agent runtime secret. ## Before you begin 1. Ask an account administrator to enable the **Agent Services** preview for the account. 2. Deploy a persistent Harness agent to a reachable HTTPS endpoint. A Databricks App built with `fh build --target databricks-app` exposes it at `/responses`. 3. Create or choose a Unity Catalog schema for agent registrations. 4. Create a Unity Catalog HTTP connection whose host points at the deployed agent. 5. Give the automation principal the required grants. The registration principal needs: - `USE CATALOG` on the parent catalog; - `USE SCHEMA` and `CREATE SERVICE` on the parent schema; - `USE CONNECTION` on the HTTP connection; - `MANAGE_ACCESS_CONTROL` on the Agent Service before it manages grants. Agent consumers typically receive `READ_METADATA` to discover the service and `EXECUTE` to express permission to use it. `EXECUTE` is a governance grant in this Beta; it does not create an invocation route by itself. ## Install and scaffold Install the Databricks package directly: ```bash pnpm add @fabric-harness/databricks @fabric-harness/sdk ``` Or let the CLI install the package, environment template, implementation, and contract test: ```bash fh add databricks agent-services --dry-run fh add databricks agent-services pnpm exec vitest run test/databricks/agent-services.test.ts ``` The managed recipe writes `.fabricharness/databricks/agent-service.ts`. Existing files are preserved unless `--force` is supplied, and an incompatible installed package range stops the operation before files are written. ## Deploy the Harness agent A persistent agent provides the durable conversation behind `/responses`: ```ts // .fabricharness/agents/support.ts import { createAgent } from '@fabric-harness/sdk'; export default createAgent(({ id }) => ({ name: 'support', description: 'Answer governed support questions.', model: `databricks/${process.env.DATABRICKS_MODEL ?? 'system.ai.gpt-oss-20b'}`, instructions: `You are the support agent for conversation ${id}. Answer using approved support sources only.`, triggers: { webhook: true, manual: true }, })); ``` Build and deploy it as a Databricks App: ```bash fh doctor --target databricks-app fh build --target databricks-app fh deploy --target databricks-app ``` Confirm the runtime boundary before registering it: ```bash curl --fail --request POST "$FABRIC_AGENT_URL/responses" \ --header "Authorization: Bearer $FABRIC_HARNESS_API_TOKEN" \ --header 'Content-Type: application/json' \ --data '{ "model": "support", "input": "Where is my order?", "stream": false }' ``` See [Responses API and ResponsesAgent](/docs/databricks/responses-agent) for streaming, continuation, custom inputs, trace IDs, tenancy, and durable deployment behavior. ## Create the HTTP connection The beginner path is **Catalog Explorer → Add → Create a connection**: 1. Select connection type **HTTP**. 2. Enter the deployed agent HTTPS host. 3. Keep the connection base path at `/`; the Agent Service supplies `/responses`. 4. Select bearer-token authentication and reference a secret containing `FABRIC_HARNESS_API_TOKEN`. 5. Record the connection resource name returned by Databricks. For SQL-driven infrastructure, store the token in Databricks Secrets and reference it instead of placing a credential in source code or command history: ```sql CREATE CONNECTION fabric_support_connection TYPE HTTP OPTIONS ( host 'https://fabric-support-app.example.com', port '443', base_path '/', bearer_token secret ('fabric', 'harness_api_token') ) COMMENT 'Credentialed connection to the Fabric support agent'; ``` Use the resource name returned by the connection API. Current metastores can return a single-part name such as `connections/fabric_support_connection`; the Agent Services API also documents a scoped form such as `connections/main.agents.fabric_support_connection`. The Harness client accepts either shape, with or without the `connections/` prefix. For production private networking, use a Databricks-supported Private Link path where available. If the service uses IP allowlisting, allow the serverless outbound addresses used by Unity Catalog HTTP connections. The connection secures credentials but does not replace network policy. ## Register the agent Use OAuth M2M for release automation and a short-lived user OAuth profile for local administration. PATs work for local testing but should not be embedded in application configuration. ```ts import { databricks, databricksPrincipalFromEnv, } from '@fabric-harness/databricks'; const workspace = databricks({ host: process.env.DATABRICKS_HOST!, principal: databricksPrincipalFromEnv(process.env), // Agent Services is a Databricks Beta; acknowledgement is intentionally explicit. agentServices: { acknowledgeBeta: true }, }); const services = workspace.agentServices!; const registered = await services.create({ catalog: 'main', schema: 'agents', id: 'support_agent', connection: 'fabric_support_connection', basePath: '/responses', comment: 'Governed support agent for the customer operations team', systemPrompt: 'Answer customer support questions using approved sources.', }); console.log(registered.name); ``` `create()` does not silently retry. The preview API does not provide an idempotency token, and a network retry after an ambiguous response could conceal whether a registry entry was created. For reconcilers, call `get()` first, create on a confirmed 404, and update known fields when the entry already exists. ## Discover and update registrations ```ts const service = await services.get('main.agents.support_agent'); const page = await services.list({ catalog: 'main', schema: 'agents', }); await services.update('main.agents.support_agent', { comment: 'Support agent owned by Customer Operations', systemPrompt: 'Answer concisely from approved support sources.', basePath: '/responses', }); ``` Agent Services is a Beta endpoint that is not yet present in the modular Databricks SDK. The explicit preview client is intentionally limited to such gaps; stable services use `databricksSdk()`. Updates use an explicit Databricks `update_mask`; omitted fields remain unchanged. The current API allows updates to `comment`, `config.system_prompt`, and `config.base_path`. The connection is fixed at creation. To move a service to another connection, create a replacement registration and migrate grants before deleting the old one. List the entire metastore only for administrative inventory jobs: ```ts let pageToken: string | undefined; do { const page = await services.list({ ...(pageToken ? { pageToken } : {}) }); for (const service of page.agent_services ?? []) console.log(service.name); pageToken = page.next_page_token; } while (pageToken); ``` Application discovery should remain schema-scoped so it does not depend on broad metastore metadata access. ## Grant and revoke access ```ts await services.grant( 'main.agents.support_agent', 'customer-support', ['EXECUTE', 'READ_METADATA'], ); const grants = await services.permissions('main.agents.support_agent'); console.log(grants.privilege_assignments); await services.revoke( 'main.agents.support_agent', 'customer-support', ['EXECUTE', 'READ_METADATA'], ); ``` Assignable privileges are `EXECUTE`, `READ_METADATA`, `MANAGE`, `MANAGE_ACCESS_CONTROL`, and `ALL_PRIVILEGES`. Prefer group grants, reserve `MANAGE_ACCESS_CONTROL` for the platform automation principal, and avoid `ALL_PRIVILEGES` for application callers. Multiple changes can be applied in one permission request: ```ts await services.updatePermissions('main.agents.support_agent', [ { principal: 'support-users', add: ['EXECUTE', 'READ_METADATA'] }, { principal: 'former-support-users', remove: ['EXECUTE'] }, ]); ``` Harness validates principal names and non-empty changes before issuing a request. Unity Catalog is still the authority that decides whether the acting principal can manage the securable. ## Delete safely Deleting the Agent Service removes only its Unity Catalog registration. It does not delete or stop the external Harness App, erase its Lakebase sessions, or remove its HTTP connection. ```ts await services.delete('main.agents.support_agent'); ``` Use this order when retiring an agent: 1. Remove consumer grants or redirect clients. 2. Preserve required MLflow traces, audit records, and deployment receipts. 3. Delete the Agent Service registration. 4. Delete the HTTP connection only when no other governed object references it. 5. Retire the App and apply the session-retention policy. For ephemeral CI registrations, always delete in `finally`: ```ts let releaseProbeRegistered = false; try { await services.create({ catalog: 'main', schema: 'agents', id: 'fabric_release_probe', connection: 'fabric_support_connection', }); releaseProbeRegistered = true; // discovery, update and permission assertions } finally { if (releaseProbeRegistered) await services.delete('main.agents.fabric_release_probe'); } ``` ## Certify in every release TechFabric Harness includes a protected live check that creates a unique temporary registration, reads it, updates it, discovers it in the schema, reads its permissions, optionally exercises grant/revoke, and deletes it. Configure the `databricks-live` GitHub Environment: | Name | Kind | Purpose | | --- | --- | --- | | `DATABRICKS_HOST` | Secret | Workspace URL | | `DATABRICKS_CLIENT_ID` | Secret | OAuth M2M service principal | | `DATABRICKS_CLIENT_SECRET` | Secret | OAuth M2M secret | | `DATABRICKS_CATALOG` | Variable | Parent catalog | | `DATABRICKS_SCHEMA` | Variable | Parent schema | | `DATABRICKS_AGENT_SERVICES_TEST` | Variable | Set to `1` after enabling the Beta | | `DATABRICKS_AGENT_SERVICE_CONNECTION` | Variable | Existing UC HTTP connection resource | | `DATABRICKS_AGENT_SERVICE_BASE_PATH` | Variable | Optional; defaults to `/responses` | | `DATABRICKS_AGENT_SERVICE_TEST_PRINCIPAL` | Variable | Optional principal for grant/revoke evidence | The certification runner automatically makes `agent-services` required when `DATABRICKS_AGENT_SERVICES_TEST=1`: ```bash pnpm --filter @fabric-harness/databricks build node packages/databricks/dist/certify.js ``` Evidence is written to `artifacts/databricks-certification.json` with credentials redacted. A green unit suite proves request and validation contracts; only the protected workspace run proves that the preview is enabled and the actual principal has the necessary Unity Catalog grants. ## Naming and tenancy Use one schema per ownership or data-governance boundary, then give services stable names: ```text main.customer_operations.support_agent main.data_platform.data_quality_agent main.finance.close_assistant ``` Do not place tenant IDs or secrets in `comment`, `systemPrompt`, service names, or connection names. For a multi-tenant Harness deployment, keep tenant enforcement in the Harness principal/RBAC layer and use Unity Catalog schemas or grants for organizational boundaries. An Agent Service registration does not weaken the agent definition's Harness capability policy. ## Failure guide | Failure | Likely cause | Action | | --- | --- | --- | | `400 AgentServices feature is not available` or `404` | Account preview is disabled or unavailable in the region | Enable Agent Services in account Previews and confirm workspace availability; a successful empty list alone is not proof that create is enabled | | `PERMISSION_DENIED` on create | Missing parent or connection privileges | Grant `USE CATALOG`, `USE SCHEMA`, `CREATE SERVICE`, and `USE CONNECTION` | | `PERMISSION_DENIED` on grants | Missing control privilege | Grant `MANAGE_ACCESS_CONTROL` to the automation principal | | Registration exists but calls fail | Registration is not an invocation proxy | Test the external App `/responses` route and its bearer token directly | | Agent missing from Catalog Explorer | Consumer lacks metadata access | Grant `READ_METADATA` and verify the selected schema | | Connection reaches the wrong path | Base paths are composed incorrectly | Keep the connection base path `/` and the service base path `/responses` | | CI leaves an entry after interruption | Process was terminated before `finally` | Use a scheduled inventory cleanup by a name prefix and maximum age | For the Databricks product contract and current limitations, see the official [Agent Services documentation](https://docs.databricks.com/aws/en/ai-gateway/agent-services) and [Unity Catalog HTTP connections](https://docs.databricks.com/aws/en/query-federation/http). --- # Databricks workload map Canonical: https://harness.techfabric.com/docs/databricks/workloads Choose the TechFabric Harness API, managed recipe, or Databricks-native escape hatch for agent, data, ML, deployment, and governance workloads. TechFabric Harness uses three integration levels. First-party workloads have typed APIs and an explicit certification level in the package capability registry; Beta surfaces can remain contract-tested until their protected live gate passes. Managed recipes orchestrate the official Databricks CLI, Python SDK, SQL, or Jobs for workloads whose authoring experience is Python-native. The escape hatch lets an agent invoke any current Databricks REST, SQL, notebook, Job, or Declarative Automation Bundle resource without waiting for a dedicated TypeScript wrapper. One bundle operation is no longer escape-hatch territory: the validate/deploy/run/destroy lifecycle of a checked-in bundle is a first-party governed surface through the [`assetBundles` option](/docs/databricks/authoring#checked-in-asset-bundles), with steward approval and source-fingerprint drift detection. | Workload | Use now | Integration level | | --- | --- | --- | | Conversational agent App | [`responses` configuration](/docs/databricks/responses-agent) and `databricks-app` | First-party | | Model Serving agent | `databricks-serving` MLflow `ResponsesAgent` artifact | First-party | | Unity AI Gateway models | `databricksFoundationModelProvider()` and model-service discovery | First-party, Databricks Beta | | SQL and Unity Catalog | SQL tools/sandbox plus governance preflight | First-party | | Stateful App | `databricksPersistence()` on Lakebase and UC Volume attachments | First-party | | AI Search RAG | `databricksAiSearch()` query adapter and `createDatabricksRagChain()` | First-party query lifecycle | | MLflow GenAI | trace exporter, evaluation rows, managed evaluation Job | First-party core lifecycle | | Genie, Feature Serving, Jobs and Lakeflow | Package tools and Jobs client | First-party control APIs | | Managed or custom MCP | `databricksWithManagedMcp()` with rotating OBO/M2M auth, allowlists, effects, and governed context | First-party Databricks adapter on shared MCP transport | | Unity Catalog Agent Services | `bundle.agentServices` registration, discovery, grants and cleanup | First-party, Databricks Beta | | Training, registry promotion and batch inference | Official Python SDK/notebook executed as a Harness-managed Job | Managed recipe | | Dashboards, Sharing, Clean Rooms and Marketplace | Declarative Automation Bundle, Job, SQL or REST call | Databricks-native escape hatch | ## Start from the business workload ### Analytics and BI copilots Use ordinary Genie conversations for governed natural-language analytics and `databricksSqlReadTool()` when the model needs inspectable SQL. The `analyticsCopilotGovernance()` pack leaves Genie questions and single-statement `SELECT` reads interactive while routing arbitrary SQL and Genie lifecycle changes to a steward. The runnable [`with-analytics-copilot`](/docs/reference/source-access) example proves the allow, approval, and local-denial behavior without credentials. For an employee-facing Databricks App, build the bundle per request with a verified OBO principal. For a shared automation service, use OAuth M2M and a least-privilege service principal. In both cases, retain the generated SQL, tool decision, acting principal label, Unity Catalog outcome, and cost correlation with the submission. ### Knowledge assistants and RAG Keep indexing, embedding pipelines, and governed source tables native to Databricks. Fabric queries the AI Search index, builds bounded context, invokes AI Gateway or Model Serving, validates citations, and exports evaluation rows to MLflow. This makes the application layer testable without pretending to replace Databricks retrieval or evaluation. ### Data engineering and operations agents Use Jobs and Lakeflow for compute. Fabric should admit the request, bind approval to the exact definition or run input, submit idempotently, persist the receipt, collect terminal status and outputs, and make cleanup visible. Keep pipeline source, cluster policies, service-principal grants, and production promotion in the platform team's existing Databricks delivery process. ### Stateful customer and employee Apps Deploy the Node runtime as a Databricks App, persist sessions/submissions/conversation streams in Lakebase, and store governed attachments in UC Volumes. The release proof is behavioral: create a session, restart or redeploy the App, recover it, continue from the prior offset, and verify tenant deletion. A successful build alone is not durability evidence. ```mermaid flowchart TB NEED[Databricks workload] --> NATIVE{Typed Harness API?} NATIVE -->|Yes| FIRST[First-party package surface] NATIVE -->|No| PYTHON{Python or SQL native?} PYTHON -->|Yes| RECIPE[Managed Job or notebook recipe] PYTHON -->|No| ESCAPE[REST, SQL, Job, or Bundle escape hatch] FIRST --> POLICY[Harness policy, identity, approvals, telemetry] RECIPE --> POLICY ESCAPE --> POLICY POLICY --> EVIDENCE[Receipts, MLflow traces, lineage, cost, cleanup] classDef decision fill:#fef3c7,stroke:#d97706,color:#422006 classDef route fill:#dbeafe,stroke:#2563eb,color:#172554 classDef evidence fill:#dcfce7,stroke:#16a34a,color:#052e16 class NATIVE,PYTHON decision class FIRST,RECIPE,ESCAPE,POLICY route class EVIDENCE evidence ``` ## Agent and governance workloads Use the Responses endpoint as the common boundary for Apps and subagents. Use `databricksWithManagedMcp()` for Databricks managed MCP endpoints, Unity Catalog MCP Services, Genie tools, or another App's MCP endpoint. The adapter rotates OBO/M2M credentials, enforces workspace origin, applies `allowTools`, and requires an explicit effect for surfaces where read versus mutation cannot be inferred. Remote discovery therefore cannot silently widen the local capability policy. [Unity Catalog Agent Services](/docs/databricks/agent-services) is a typed discoverability and permission surface. The package requires explicit Beta acknowledgement, defaults external Harness registrations to `/responses`, and supports create, get, list, update, permission, grant, revoke, and delete operations. Runtime invocation is not available through the Databricks service during the current Beta; call the Harness endpoint directly. For long-lived conversations, use Lakebase-backed Harness sessions today. Databricks managed agent memory can be introduced as another session-memory adapter without changing agent code because Harness sessions already depend on the common store interface. ## Retrieval and data workloads Databricks AI Search is the current product name. Harness uses `databricksAiSearch()` and `aiSearch` for new code while retaining the former names as deprecated source-compatible aliases. The REST API continues to use its existing `vector-search` path. The online RAG path is documented in [Databricks RAG](/docs/databricks/rag). Create and update indexes using a Databricks Job or Bundle, then give the App service principal `SELECT` and endpoint access before invoking the retriever. Lakeflow authoring belongs in declarative SQL or Python source. Keep pipeline definitions in the deployed project, run them through a Job or Bundle, and use Harness Lakeflow tools for start, stop, status and agent approvals. When the bundle itself is checked in, hand its validate/deploy/run/destroy lifecycle to the governed [`assetBundles` surface](/docs/databricks/authoring#checked-in-asset-bundles) instead of an ungated shell call. Treat expectations and event-log quality metrics as release evidence. ## ML and evaluation workloads Use MLflow for trace storage, evaluation datasets, judges, labeling sessions, reusable scorers and production monitoring. Harness supplies execution identity and correlation; MLflow remains the evaluation engine. Use [RAG evaluation](/docs/databricks/rag#managed-mlflow-evaluation) as the working pattern for a generated Python evaluation Job in [evaluation and quality](/docs/databricks/rag#evaluation-and-quality-native-databricks-first). Training and fine-tuning should run on Databricks AI Runtime through a Job or notebook. Register the result in Unity Catalog, promote with model aliases, and deploy with Model Serving traffic controls. Do not build new workflows on the deprecated Foundation Model Training API. ## Adding a new workload Before exposing a new Databricks API, define its auth modes, UC permissions, cloud availability, preview status, cleanup behavior, retry/idempotency rules, mock contract, live gate, runnable example, and documentation route. The package capability registry is the source of truth for these claims: ```ts import { listDatabricksCapabilities } from '@fabric-harness/databricks'; const productionSurfaces = listDatabricksCapabilities({ status: 'stable' }); ``` This keeps experimental Databricks surfaces usable without presenting them as generally available or silently enabling them in production. --- # Databricks recipes (`fh add`) Canonical: https://harness.techfabric.com/docs/databricks/recipes Scaffold Genie analytics copilots, Lakebase, SQL, AI Search, Lakeflow, Jobs, cost controls, and Apps wiring with managed TechFabric Harness recipes. Use managed **Databricks recipes** to wire `@fabric-harness/databricks` into an existing project without copying examples by hand. Recipes write versioned files under `.fabricharness/databricks/` (or a job for the analyst composite), update dependencies, and leave secrets in environment variables. Greenfield projects can still start with: ```sh fh init --template databricks ``` Recipes are for **adding one product surface** (or a small workload composite) afterward. Generated Databricks recipes default to `DATABRICKS_MODEL=databricks-gpt-oss-20b` (a bare foundation-model serving endpoint, available on free-tier workspaces) and `DATABRICKS_INFERENCE_MODE=auto`. Use a discovered `system.ai.*` model service instead when the workspace has Unity AI Gateway enabled. Set `DATABRICKS_HOST` to the workspace origin, for example `https://`; do not include `/ai-gateway/mlflow/v1` in the host value. ## List and install ```sh fh add fh add --json fh add databricks core fh add databricks sql fh add lakebase # alias fh add ai-search fh add lakeflow fh add jobs fh add bundle # checked-in Asset Bundle lifecycle fh add system-tables-cost fh add apps fh add agent-services fh add genie # governed Genie + SELECT-only SQL copilot fh add mcp--databricks # governed managed MCP client fh add data--databricks # compatibility alias for genie fh add kb--databricks # compatibility alias for rag-chain fh add lakehouse # analyst composite (sql + tables) fh add databricks lakebase --dry-run fh update databricks sql ``` ## Catalog | Recipe | Alias examples | Managed files | Dependencies | Maps to | | --- | --- | --- | --- | --- | | `core` | `databricks-core` | `databricks/identity.ts`, `policies/databricks.ts` | `@fabric-harness/databricks` | Workspace identity + UC egress policy | | `sql` | `databricks-sql` | `databricks/sql.ts` | `@fabric-harness/databricks` | SELECT-only SQL Warehouse + table discovery | | `lakebase` | `databricks-lakebase` | `databricks/lakebase.ts` | `@fabric-harness/databricks`, `pg` | Lakebase persistence | | `ai-search` | `databricks-ai-search` | `databricks/ai-search.ts` | `@fabric-harness/databricks` | Agentic `search` tool bundle | | `rag-chain` | `databricks-rag-chain` | `databricks/rag-chain.ts`, `jobs/rag-answer.ts` | `@fabric-harness/databricks` | Cookbook online chain + MLflow 3 eval export ([RAG docs](/docs/databricks/rag)) | | `lakeflow` | `databricks-dataeng` | `databricks/lakeflow.ts` | `@fabric-harness/databricks` | [with-databricks-dataeng](/docs/reference/source-access) | | `jobs` | `databricks-compute` | `databricks/jobs.ts` | `@fabric-harness/databricks` | [with-databricks-compute](/docs/reference/source-access) | | `bundle` | `databricks-bundle`, `databricks-asset-bundle` | `databricks/bundle.ts`, `policies/databricks-bundle.ts` | `@fabric-harness/databricks` | Governed checked-in Asset Bundle lifecycle; deploy/run/destroy added to `requireApproval` ([resource management](/docs/databricks/authoring#checked-in-asset-bundles)) | | `system-tables-cost` | `databricks-cost` | `databricks/cost.ts` | `@fabric-harness/databricks` | [with-databricks-cost-attribution](/docs/reference/source-access) | | `apps` | `databricks-app` | `databricks/apps.ts` | `@fabric-harness/databricks`, `@fabric-harness/node` | Apps runtime preset + deploy targets | | `agent-services` | `databricks-agent-services` | `databricks/agent-service.ts` | `@fabric-harness/databricks` | [Unity Catalog registration and grants](/docs/databricks/agent-services) | | `genie` | `analytics-copilot`, `data--databricks` | `databricks/genie.ts` | `@fabric-harness/databricks` | Genie questions + statement-level SELECT-only SQL + copilot governance | | `managed-mcp` | `mcp--databricks` | `databricks/managed-mcp.ts` | `@fabric-harness/databricks` | Managed MCP / AI Gateway MCP Service discovery with explicit allowlist and effects | | `analyst` | `lakehouse` | `jobs/databricks-analyst.ts` | `@fabric-harness/databricks` | init template / simple analyst job | “Lakehouse” is an **alias for the analyst composite** (governed SQL + UC tools), not a separate Databricks SDK product. `kb--databricks` maps to `rag-chain`. `mcp--databricks` now maps to the tested managed-MCP adapter; the generated factory is asynchronous because remote tool discovery happens at startup. ## Typical flows ### SQL analyst on Apps ```sh fh init --template minimal fh add databricks core fh add databricks sql fh add databricks analyst # set DATABRICKS_* in .env fh run databricks-analyst --question "What tables are in main?" --mock fh build --target databricks-app ``` ### Genie analytics copilot ```sh fh init --template minimal fh add databricks genie # set host, identity, Warehouse, Genie Space, catalog, and steward audience fh test ``` The generated bundle adds `databricks_genie_ask` for governed natural-language questions and a separate `sql_read` tool. `sql_read` rejects mutations and multiple statements before calling Statement Execution. Arbitrary SQL is not generated; add `databricksSqlTool()` only with its required statement policy and separate approval routing. Genie lifecycle tools remain approval-bound. Missing Warehouse, Genie Space, identity, or steward configuration fails during bundle construction. The `DATABRICKS_GENIE_SPACE_ID` environment value is passed to the current conversation contract as `agentId`; generated code does not emit the retired legacy configuration alias. ### RAG support agent ```sh # Deterministic cookbook chain (retrieve → augment → generate): fh add databricks rag-chain fh run rag-answer --question "How do I reset my password?" # Or agentic multi-tool search (SQL + search + …): fh add ai-search # Import createVectorSearchBundle() and pass modelProvider + tools into init() ``` See [RAG on Databricks](/docs/databricks/rag) for citation validation, MLflow 3 export, and the quality workflow. ### Managed MCP or AI Gateway MCP Service ```sh fh add mcp--databricks # set host, identity, a same-workspace MCP URL, and one safe tool name fh test ``` The generated `createDatabricksManagedMcp()` returns a principal-bound bundle. Close `bundle.managedMcp` when the request or worker stops. Its default recipe exposes one named tool as `read`; expand `allowTools` and `effects` deliberately after reviewing the server contract. Missing host, credentials, URL, tool name, remote permission, or effect classification fails before the tool is usable. See the [managed MCP integration guide](/docs/databricks/integrations#managed-mcp-and-mcp-services). ### Lakebase durable state ```sh fh add lakebase # In .fabricharness/config.ts: # import { createLakebasePersistence } from './databricks/lakebase.js'; # persistence: createLakebasePersistence(), ``` ### Data engineering ```sh fh add lakeflow fh add jobs # Use createLakeflowBundle() / createDatabricksJobsTools() in agent init ``` ### Checked-in Asset Bundle lifecycle ```sh fh add databricks bundle # set DATABRICKS_HOST, identity, DATABRICKS_BUNDLE_DIR, DATABRICKS_BUNDLE_TARGET # Use createDatabricksAssetBundleTools() in agent init; deploy/run/destroy require approval ``` The generated `createDatabricksAssetBundleTools()` wires `databricksAssetBundleLifecycle` and its tools for the checked-in bundle in `DATABRICKS_BUNDLE_DIR`; the policy file adds `databricks_bundle_deploy`, `databricks_bundle_run`, and `databricks_bundle_destroy` to `toolPolicy.requireApproval` while validation stays read-only. Run submission is always `--no-wait`; poll status through the bounded jobs/lakeflow tools. The Databricks CLI must be on `PATH`. See [Checked-in Asset Bundles](/docs/databricks/authoring#checked-in-asset-bundles) for the fingerprint and managed-only-destroy semantics. ## Conventions - **Package owns behavior** — recipes only wire `@fabric-harness/databricks` into your workspace. - **Managed markers** — files start with `// fabric-harness-recipe: databricks/@1` for safe `fh update`. - **No secrets in source** — only env names are written to `.env.example`. - **Runnable verification** — generated tests import from `../../.fabricharness/` and are compiled by the recipe contract suite. - **Merge config yourself** — recipes do not silently rewrite `config.ts`; they print paths and env requirements. - **Deploy** — Apps/Serving artifacts still come from `fh build --target databricks-app|databricks-serving`. ## See also - [Databricks quickstart](/docs/databricks/quickstart) - [Integrations map](/docs/databricks/integrations) - [Connector recipes reference](/docs/reference/recipes) - [Examples](/docs/examples) --- # RAG on Databricks Canonical: https://harness.techfabric.com/docs/databricks/rag Use Databricks-native AI Search and Unity AI Gateway for bounded, citation-validated online RAG with MLflow 3 evaluation records. TechFabric Harness wires Databricks-native products for retrieval, generation, tracing, and evaluation. It does **not** reimplement AI Search, Unity AI Gateway, the offline index pipeline, or MLflow judges. Follow the same mental model as the [Databricks AI Cookbook RAG inference chain](https://docs.databricks.com/aws/en/agents/tutorials/ai-cookbook/fundamentals-inference-chain-rag): 1. (Optional) preprocess the user query 2. **Retrieve** with Databricks AI Search 3. **Augment** the prompt with retrieved context 4. **Generate** through Unity AI Gateway or a custom Model Serving endpoint 5. Validate inline citations and apply answer limits Offline chunk → embed → index remains a **Databricks Job / notebook / Lakeflow** concern. Quality measurement uses **[MLflow 3 evaluation](https://docs.databricks.com/aws/en/mlflow3/genai/eval-monitor/)** and managed Databricks judges, not a parallel Fabric-only judge product. ## Quick start (managed recipe) ```sh fh add databricks rag-chain # set DATABRICKS_HOST, OAuth credentials, DATABRICKS_AI_SEARCH_INDEX, DATABRICKS_MODEL fh run rag-answer --question "How do I reset my password?" ``` For a credential-free local run, add `--mock`: ```sh fh run rag-answer --question "How do I reset my password?" --mock ``` The generated recipe then selects its deterministic retriever and model fixture. This exercises discovery, input/output validation, the RAG chain, and citation handling without calling AI Search or Model Serving. Remove `--mock` to use the configured Databricks index and model. Scaffolded files: | Path | Role | | --- | --- | | `.fabricharness/databricks/rag-chain.ts` | `createRagChain()` + `evaluationArtifacts()` | | `.fabricharness/jobs/rag-answer.ts` | Finite job calling the chain | Related recipes: | Recipe | Use when | | --- | --- | | `fh add databricks ai-search` | Bundle-only / agentic `search` tool (multi-tool agents) | | `fh add databricks rag-chain` | Fixed online inference chain (cookbook path) | | `fh add lakeflow` / Jobs | Offline pipeline ops (index refresh), not the chain itself | ## Code API ### Deterministic chain (cookbook online path) ```ts import { databricksRagChain, toMlflow3EvaluationRecord, exportMlflow3EvaluationJsonl } from '@fabric-harness/databricks'; const chain = databricksRagChain({ databricks: { host: process.env.DATABRICKS_HOST!, principal: { kind: 'pat', token: process.env.DATABRICKS_TOKEN! }, model: 'databricks-gpt-oss-20b', aiSearch: { index: 'main.support.kb_index', textColumn: 'chunk', idColumn: 'id', inputMode: 'text', strategy: 'hybrid', }, }, retrieval: { k: 5, scoreThreshold: 0.25 }, postProcess: { requireCitations: true, citationRepairAttempts: 2, }, }); const turn = await chain.invoke({ question: 'How do I reset my password?' }); // turn.answer, turn.sources, turn.citations, turn.retrieval, turn.usage ``` With `requireCitations`, Fabric asks the model to revise an uncited answer or an answer that cites an unknown ID using only the exact source IDs returned by retrieval. Repair is bounded and fails closed if the model still omits a valid marker or retains a fabricated ID; Fabric never adds a citation to the answer on the model's behalf. ### Complete AI Search query controls Text input uses native `HYBRID` retrieval by default. Query representation and retrieval strategy are separate: ```ts const result = await bundle.retriever.query('quarterly retention', { inputMode: 'text', strategy: 'hybrid', // ann | hybrid | full-text k: 20, filter: { language: 'en' }, scoreThreshold: 0.35, queryColumns: ['chunk', 'title'], sortColumns: ['published_at DESC'], facets: ['language', 'product'], reranker: { model: 'databricks_reranker' }, columnsToRerank: ['title', 'chunk'], signal: abortController.signal, }); result.chunks; result.facetResult; result.nextPageToken; result.response; // complete generated-SDK response ``` Use `inputMode: 'vector'` with `strategy: 'ann'` for a self-managed embedding index. Supply an `embeddingEndpoint` when configuring the bundle or provide a precomputed `queryVector` for a specific request. `text-and-vector` sends both inputs for a supported native strategy. The same controls can be defaults on `databricksRagChain({ retrieval: ... })` or per-turn: ```ts const turn = await chain.invoke({ question: 'What changed?', retrieval: { strategy: 'hybrid', k: 12, facets: ['release'], reranker: { model: 'databricks_reranker' }, }, }); ``` Pagination and facet metadata are retained on `RagTurn.retrieval`. For direct search calls, `retriever.nextPage(token, { signal })` retrieves the following page. ### Streaming `chain.stream()` yields incremental `delta` events while the model generates, then one terminal `turn` event carrying the same validated `RagTurn` that `invoke` returns: ```ts for await (const event of chain.stream({ question: 'How do I reset my password?' })) { if (event.type === 'delta') process.stdout.write(event.textDelta); if (event.type === 'turn') persist(event.turn); // validated answer, citations, usage } ``` Deltas are raw first-pass model output for live UI — they are emitted **before** citation validation, bounded repair, truncation, and the sources footer run, so the concatenated deltas can differ from the final answer. The terminal `turn` is authoritative: use it for persistence, evaluation export, and cost telemetry. A failed citation validation raises from the iterator after the deltas were observed. When the model provider does not implement `stream()`, the chain falls back to `generate()` and emits the whole answer as one delta. The protected `rag` certification check uses this streaming path against the configured live AI Search index and Databricks model endpoint. It requires text deltas, a terminal turn, retrieved context, and at least one valid inline citation. Release run `29622641870` certified the exact `2.0.0` package candidate in the protected Azure `eastus2` workspace: the streaming chain emitted 12 text deltas, retrieved three source chunks, returned a valid `fabric-databricks` citation, and produced its authoritative terminal turn. The same run completed Databricks Job `613907318899842` for the managed 50-case RAG evaluation with a `SUCCESS` result. Agent Mode was not configured in that workspace and is not implied by this RAG evidence. That record predates the 3.0 native-SDK transport and is historical for 3.0 promotion. The 3.0 release gate reruns the same retrieval, streaming, citation, and managed-evaluation checks against the exact package artifact. What runs under the hood: | Step | Databricks product | Fabric helper | | --- | --- | --- | | Retrieve | Databricks AI Search | `databricksAiSearch` / UC principal | | Generate | Unity AI Gateway / Model Serving | `databricksFoundationModelProvider` | | Orchestrate | — | `databricksRagChain` (thin glue only) | ### Agentic multi-tool RAG When the agent must also call SQL, Genie, or Jobs, keep tool-calling: ```ts const chain = databricksRagChain({ databricks: { /* + aiSearch */ } }); const { modelProvider, tools, policy } = chain.asAgentTools(); // pass into init({ modelProvider, tools, policy }) ``` Or continue using `databricks({ aiSearch })` + `bundle.tools` as in `examples/with-databricks-rag`. ## Evaluation and quality (native Databricks first) ### Local CI smoke (optional) Lightweight checks on a `RagTurn` validate actual `[source-id]` markers, required facts, and retrieval: ```ts import { scoreRagTurn, toMlflow3EvaluationRecord, exportMlflow3EvaluationJsonl } from '@fabric-harness/databricks'; const scores = scoreRagTurn(turn, { mustContain: ['Settings'], requireCitations: true, mustRetrieveIds: ['doc-1'], }); ``` These are **smoke scorers**, not a substitute for managed evaluation. ### What developers inspect Keep the answer and its source references visible beside quality evidence. The representative state below shows the relationship between retrieved context, citations, managed judges, latency, and cost; replace the fixture corpus and expected facts with the application's governed domain data. ### MLflow 3 managed evaluation Export MLflow 3 rows with structured inputs, outputs, expectations, retrieved context, and trace metadata: ```ts const record = toMlflow3EvaluationRecord(turn, { expectedAnswer: 'Use Settings, then Security.', traceId: 'tr-...', submissionId: 'sub-...', }); const jsonl = exportMlflow3EvaluationJsonl([record]); // Merge the record into an MLflow Evaluation Dataset from a Databricks notebook or job. ``` The release certification fixture runs this loop as a serverless Databricks Job. The notebook at `scripts/databricks/rag_evaluation.py` queries five candidates from the real AI Search index, uses the configured Databricks model to retain only sources that supply relevant or complementary evidence, records the filtered documents in the retriever span, and generates a citation-backed answer. It merges the governed 50-case golden set into a content-hashed Unity Catalog evaluation dataset, so changed fixtures cannot inherit stale rows from an earlier release, and runs the following managed judges: | Case category | Count | Purpose | | --- | ---: | --- | | Factual | 30 | Paraphrased questions over individual governed documents | | Multi-document | 10 | Answers that must combine identity, governance, runtime, deployment, or RAG evidence | | Insufficient context | 5 | Unsupported questions where the correct behavior is to abstain | | Adversarial | 5 | Retrieved prompt-injection text that must be treated as untrusted data | The source documents and cases live together in `scripts/databricks/rag_fixture.json`. The provisioner merges those documents into the Delta source table, triggers the AI Search index, and embeds the same cases into the evaluation notebook. This prevents the index fixture and golden set from drifting apart. | Judge | What it catches | | --- | --- | | Relevance to query | The answer does not address the request | | Retrieval relevance | Retrieved chunks add irrelevant context | | Retrieval groundedness | Retrieved claims are not supported by the source chunks | | Retrieval sufficiency | Retrieval omitted context needed to answer | | Correctness | The answer misses the expected facts | Each aggregate must meet `DATABRICKS_RAG_EVAL_THRESHOLD` (default `0.8`). Evidence includes the MLflow run, versioned dataset and fixture hash, generation and judge models, category counts, selected aggregate metrics, and threshold result. A failed judge fails the Databricks Job and therefore the release certification gate. The protected release workflow for commit `5fcf927bcf0a3a15e3aec86e2629516cbb76ad26` evaluated fixture `18bd4dffc32c` as MLflow run `18131356bcac4460a26de20d40b9573a` in the reference Azure workspace. It covered all 50 cases with `databricks-gpt-oss-120b` for generation and managed judging, and passed the unchanged `0.8` floor: | Metric | Score | | --- | ---: | | Relevance to query | 0.86 | | Retrieval relevance | 0.895 | | Retrieval groundedness | 0.84 | | Retrieval sufficiency | 0.86 | | Correctness | 0.88 | This is retained workspace evidence for the reference fixture, not a claim that every application or dataset will achieve the same scores. Replace the documents, question-level expected facts, and adversarial cases with your domain corpus before treating the gate as production evidence. ```mermaid flowchart LR G[UC golden dataset
content-hashed version] --> J[Serverless evaluation Job] J --> V[AI Search
top five candidates] V --> R[Model-assisted reranker
relevant sources only] R --> T[MLflow retriever span] T --> M[AI Gateway generation
bounded context and citations] T --> E[Five MLflow managed judges] M --> E E -->|all scores at least 0.8| P[Release evidence] E -->|score below threshold| F[Block release] F --> D[Diagnose retrieval, prompt, or index] D --> J classDef source fill:#dcfce7,stroke:#16a34a,color:#052e16 classDef gate fill:#fef3c7,stroke:#d97706,color:#422006 classDef fail fill:#fee2e2,stroke:#dc2626,color:#450a0a class G,V,R,T,M source class J,E,P gate class F,D fail ``` Provision or repair the disposable fixture, then run the same gate used by protected CI: ```sh FABRIC_DATABRICKS_PROVISION=1 pnpm databricks:cert:provision pnpm databricks:certify ``` The provisioner is idempotent: it reuses the UC dataset, Jobs, AI Search index, Feature Serving endpoint, Genie Agent, and Lakeflow pipeline. Improve quality by diagnosing retrieval versus generation, changing `topK`, prompts, chunks, or embeddings, and rerunning the managed judges before redeploying Apps or Model Serving. The default job limits MLflow to one prediction worker and one scorer worker, with prediction and scorer rate limits, so pay-per-token endpoints do not exceed workspace output-token quotas. Raise `MLFLOW_GENAI_EVAL_MAX_WORKERS`, `MLFLOW_GENAI_EVAL_MAX_SCORER_WORKERS`, `MLFLOW_GENAI_EVAL_PREDICT_RATE_LIMIT`, or `MLFLOW_GENAI_EVAL_SCORER_RATE_LIMIT` only when the workspace uses capacity that supports the additional concurrency. Do **not** build a second full judge product in Fabric when MLflow managed evaluation already exists in the workspace. ## Offline index pipeline (not the chain) Building/updating the AI Search index (chunking, embedding, write) stays on Databricks: - Notebooks / Jobs - Lakeflow pipelines (`fh add lakeflow`) - UC Volumes as document sources Fabric agents **consume** the index via AI Search at inference time. ## Guardrails | Concern | Prefer | | --- | --- | | Data access | Unity Catalog grants on the index + service principal | | Tool / SQL risk | `databricks()` governance policy / approvals | | Content policy / gateway | Mosaic AI Gateway / serving policies (configure on the endpoint) | | Audit | MLflow traces (`bundle.mlflowTraceExporter()`) + lineage hooks | The default chain treats retrieved chunks as untrusted data, serializes them as bounded JSONL, limits per-chunk and total context size, and rejects citation markers that do not match a retrieved source. `turn.sources` means "retrieved"; only source IDs referenced by the final answer appear in `turn.citations`. ```ts const chain = databricksRagChain({ databricks: { /* model + aiSearch */ }, topK: 5, maxContextChars: 32_000, maxChunkChars: 8_000, postProcess: { citationPolicy: 'validate', maxAnswerChars: 8_000, }, }); ``` ## See also - [Databricks recipes](/docs/databricks/recipes) - [Integrations map](/docs/databricks/integrations) - [example: with-databricks-rag](/docs/reference/source-access) - [Cookbook: RAG chain for inference](https://docs.databricks.com/aws/en/agents/tutorials/ai-cookbook/fundamentals-inference-chain-rag) --- # Databricks architecture Canonical: https://harness.techfabric.com/docs/databricks/architecture How TechFabric Harness routes identity, policy, model calls, data tools, durable state, telemetry, and deployments through Databricks. TechFabric Harness separates the agent runtime from the services the agent is allowed to call. A single Databricks principal can be threaded through Model Serving, REST tools, SQL, and Lakebase credential exchange. Fabric policy adds approvals, egress restrictions, budgets, and audit correlation; Unity Catalog still makes the final data authorization decision. ## Runtime layers ```mermaid flowchart TB subgraph Entry[Invocation] CLI[fh run] API[Jobs and agents API] EVT[Schedule or channel] end subgraph Runtime[TechFabric Harness runtime] DEF[Job or persistent agent definition] SES[Session and model loop] POL[Capability policy] APR[Human approval] AUD[Audit, lineage, and cost] end subgraph Identity[Databricks identity] APP[App service principal] OBO[On-behalf-of user] M2M[OAuth M2M] end subgraph Services[Databricks services] SERVE[Model Serving] SQL[SQL Warehouse] UC[Unity Catalog] RAG[AI Search] STATE[Lakebase] OPS[MLflow and system tables] end CLI --> DEF API --> DEF EVT --> DEF DEF --> SES SES --> POL POL -->|sensitive action| APR POL -->|allowed action| Services SES --> AUD APP --> SES OBO --> SES M2M --> SES SERVE --> UC SQL --> UC RAG --> UC STATE --> AUD OPS --> AUD classDef entry fill:#f4f4f5,stroke:#71717a,color:#18181b classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef identity fill:#fef3c7,stroke:#d97706,color:#422006 classDef dbx fill:#dcfce7,stroke:#16a34a,color:#052e16 class CLI,API,EVT entry class DEF,SES,POL,APR,AUD fabric class APP,OBO,M2M identity class SERVE,SQL,UC,RAG,STATE,OPS dbx ``` ## One request, one governed identity ```mermaid sequenceDiagram autonumber actor User participant App as Databricks App participant Fabric as TechFabric Harness participant Policy as Policy and approvals participant Model as Model Serving participant Tool as SQL or Databricks API participant UC as Unity Catalog participant State as Lakebase User->>App: Prompt or job input App->>Fabric: Request plus app or user identity Fabric->>State: Load session and submission Fabric->>Model: Prompt with short-lived OAuth token Model-->>Fabric: Tool request Fabric->>Policy: Evaluate capability and approval rules alt approval required Policy-->>User: Approval request User-->>Policy: Approve or deny end Policy->>Tool: Execute as the governed principal Tool->>UC: Enforce catalog, schema, table, row, and column grants UC-->>Tool: Authorized result or denial Tool-->>Fabric: Redacted result plus lineage metadata Fabric->>State: Persist events and final result Fabric-->>User: Typed response or durable receipt ``` ## Finite jobs and persistent agents Finite jobs live in `.fabricharness/jobs/`, return one typed result, and are invoked at `POST /jobs/:name`. Persistent agents live in `.fabricharness/agents/`, retain an addressable conversation, and return a submission receipt from `POST /agents/:name/:id`. Both use the same model, tool, policy, and Databricks integration surfaces. Lakebase can back sessions, submissions, and conversation streams. The runtime exchanges a workspace OAuth token for a short-lived database credential, supplies that credential through the Postgres pool, refreshes early, and deduplicates concurrent refreshes. ## Deployment boundaries `databricks-app` runs the bundled Node server inside Databricks Apps. `databricks-serving` builds an MLflow `ResponsesAgent` proxy that calls an agent hosted elsewhere; it does not execute the TypeScript runtime inside Model Serving. The App exposes the same `/responses` contract directly. The proxy preserves `response.output_text.delta` and `response.output_item.done` events and returns a normal `ResponsesAgentResponse` for non-streaming clients. See [Databricks deployment](/docs/deployment/databricks) for target details. --- # Databricks quickstart Canonical: https://harness.techfabric.com/docs/databricks/quickstart Install, scaffold, mock, connect, test, build, and deploy a governed Databricks agent with TechFabric Harness. This walkthrough starts with no credentials, proves the local agent contract, then connects the same project to Databricks with OAuth. Use the **workspace origin** everywhere, for example `https://adb-1234567890123456.7.azuredatabricks.net`. Do not use an AI Gateway path as the host. For an end-to-end customer architecture—OBO identity, Genie, SELECT-only verification, exact-operation approval for one allowlisted Job, Lakebase recovery, MLflow correlation, and an optional Temporal worker—use the runnable [`with-databricks-revenue-ops`](/docs/reference/source-access) reference after this quickstart. ```mermaid flowchart LR Install[Install project CLI] --> Scaffold[Scaffold Databricks agent] Scaffold --> Mock[Run with deterministic mock] Mock --> Login[Databricks CLI OAuth login] Login --> Live[Live Genie + governed SQL + cost run] Live --> Extend[Add RAG, Lakeflow, or Lakebase recipes] Extend --> Build[Build portable Databricks App] classDef local fill:#e8f1ff,stroke:#4f7fd9,color:#172033 classDef workspace fill:#e5f7ec,stroke:#2f9e62,color:#172033 class Install,Scaffold,Mock local class Login,Live,Extend,Build workspace ``` ## 1. Check the prerequisites The core TechFabric Harness packages support Node.js 20.18 or later, but `@fabric-harness/databricks` requires **Node.js 22 or later**. Use Node 22 LTS for this walkthrough. The Databricks CLI is optional for mock mode and required for the recommended local OAuth and deployment flow. ```sh node --version npm --version databricks version ``` If `databricks` is missing, install the current CLI using the [official Databricks instructions](https://docs.databricks.com/aws/en/dev-tools/cli/install): ```sh curl -fsSL https://raw.githubusercontent.com/databricks/setup-cli/main/install.sh | sh databricks version ``` ## 2. Create the agent project Run the published CLI directly. The generated project pins compatible Harness packages together, so a global CLI is not required. ```sh npx --yes @fabric-harness/cli@latest init \ --template databricks \ --dir analytics-agent cd analytics-agent npm install ``` The template creates: ```txt .fabricharness/ jobs/databricks-analyst.ts policies/databricks.ts roles/data-analyst.md skills/analyze-table/SKILL.md fixtures/analytics.json config.ts databricks-certification.json test/databricks-safe-tools.test.ts NEXT_STEPS.md .env.example ``` Use the project-local executable for every following command: ```sh npx fh --version npx fh doctor --getting-started --tools --model mock/test-model npm test npx fh agents npx fh describe databricks-analyst ``` ## 3. Run without credentials ```sh npx fh run databricks-analyst \ --question "What tables are in main?" \ --mock ``` `--mock` replaces the model with a deterministic in-process provider. It needs no Databricks or AI credentials and verifies that Harness can discover and load the TypeScript definition, local policy, role, skill, schema, model loop, and result contract. `npm test` separately proves that the generated SQL tool admits a SELECT and rejects a mutation before the mock Statement Execution client is called. Neither check requires credentials. The answer is synthetic. Mock mode does **not** list real tables, execute SQL, check Unity Catalog grants, call AI Gateway, or validate OAuth. A response such as `Mock response: What tables are in main?` proves the application path, not the factual quality of a data answer. ## 4. Create another simple agent Generate a finite job in the same project: ```sh npx fh new job hello ``` Replace `.fabricharness/jobs/hello.ts` with: ```ts title=".fabricharness/jobs/hello.ts" import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'hello', description: 'Give a short personalized greeting.', input: schema.object({ name: schema.string() }), output: schema.string(), triggers: { manual: true, webhook: true }, async run({ input, prompt }) { return await prompt(`Greet ${input.name} in one sentence.`); }, }); ``` Discover and run it without provider credentials: ```sh npx fh agents npx fh describe hello npx fh run hello --name Ada --mock ``` To test the deployment protocol locally, start the HTTP server in one terminal: ```sh npx fh dev --mock --port 4000 ``` Invoke the job from another terminal: ```sh curl --fail --request POST http://127.0.0.1:4000/jobs/hello \ --header 'content-type: application/json' \ --data '{"name":"Ada"}' ``` ## 5. Authenticate to Databricks For a developer workstation, use a named Databricks CLI OAuth profile. The browser login stores and refreshes the user OAuth credential through the Databricks CLI; TechFabric Harness asks the CLI for a short-lived access token when it needs one. ```sh export DATABRICKS_HOST=https://adb-1234567890123456.7.azuredatabricks.net databricks auth login \ --host "$DATABRICKS_HOST" \ --profile fabric-harness databricks auth profiles databricks current-user me --profile fabric-harness npx fh doctor --target databricks-app ``` In a headless shell (CI container, SSH without a desktop keyring) the Databricks CLI cannot reach its secure token cache; add `DATABRICKS_AUTH_STORAGE=plaintext` so `databricks auth token` works. Create `.env.local`: ```dotenv title=".env.local" DATABRICKS_HOST=https://adb-1234567890123456.7.azuredatabricks.net DATABRICKS_CONFIG_PROFILE=fabric-harness DATABRICKS_AUTH_MODE=cli DATABRICKS_MODEL=databricks-gpt-oss-20b DATABRICKS_WAREHOUSE_ID=0123456789abcdef DATABRICKS_GENIE_SPACE_ID=0123456789abcdef0123456789abcdef DATABRICKS_CATALOG=main DATABRICKS_ANALYTICS_STEWARD_AUDIENCE=analytics-stewards DATABRICKS_COST_TENANT_ID=acme DATABRICKS_COST_PER_DAY_USD=50 DATABRICKS_INFERENCE_MODE=auto ``` The workspace OAuth credential authenticates both management/data APIs and the selected Databricks model surface. You do not configure a separate OpenAI key. The principal still needs permission to use the model or serving endpoint, `CAN USE`/`CAN QUERY` for the SQL Warehouse as appropriate, and the required Unity Catalog grants. For unattended CI or production-like local tests, replace CLI auth with OAuth M2M: ```dotenv DATABRICKS_HOST=https://adb-1234567890123456.7.azuredatabricks.net DATABRICKS_CLIENT_ID=00000000-0000-0000-0000-000000000000 DATABRICKS_CLIENT_SECRET=resolve-from-a-secret-store DATABRICKS_MODEL=databricks-gpt-oss-20b DATABRICKS_WAREHOUSE_ID=0123456789abcdef DATABRICKS_GENIE_SPACE_ID=0123456789abcdef0123456789abcdef DATABRICKS_CATALOG=main DATABRICKS_ANALYTICS_STEWARD_AUDIENCE=analytics-stewards DATABRICKS_COST_TENANT_ID=acme DATABRICKS_COST_PER_DAY_USD=50 ``` Do not set CLI-profile, PAT, and M2M credentials together when testing authentication behavior. See [Local naming and authentication](/docs/databricks/local-naming-auth) for PAT, M2M, Databricks App service principal, and OBO patterns. ## 6. Run the analyst against the workspace First run the target-aware preflight, then remove `--mock`: ```sh npx fh doctor --target databricks-app npx fh run databricks-analyst \ --question "List the tables in main.default" npx fh run databricks-analyst \ --question "Describe main.default.my_table and suggest three quality checks" ``` The generated analyst is the governed analytics-copilot spine. Ordinary Genie questions and one statement `SELECT` through `sql_read` stay interactive; arbitrary SQL remains available only behind the analytics-steward approval route. Unity Catalog discovery and System Tables consumption are included, and an actual-cost-backed daily tenant limit blocks the next model ask after the configured budget is exhausted. Test an allowed query, inspect the SQL, verify a denied Unity Catalog object, and exercise the approval path. Live startup fails once, before the first model ask, listing every missing prerequisite (workspace host, Warehouse, Genie Agent, steward audience, tenant id, positive daily budget) in a single error instead of failing fast one variable at a time. Mock mode deliberately bypasses those workspace bindings while retaining definition and policy assembly. A run whose model turns end with no content — typically because every tool call was denied by the generated policy — is not reported as success: `fh run` prints a warning and exits nonzero. The session always offers the built-in filesystem tools alongside the declared Databricks tools; with `sandbox: 'empty'` and the generated tool allowlist they are denied, so a model that wanders to `grep`/`read` produces exactly this signal. Narrow the role/instructions or widen the policy deliberately rather than ignoring it. Inspect the resulting session and audit trail: ```sh npx fh sessions npx fh inspect npx fh logs npx fh approvals ``` After deployment, discover and resolve approvals through the App without granting the caller operator-console access: ```sh TOKEN="$(databricks auth token --host "$DATABRICKS_HOST" | jq -r .access_token)" export DATABRICKS_OAUTH_TOKEN="$TOKEN" npx fh approvals \ --url "$DATABRICKS_APP_URL/api" \ --token-env DATABRICKS_OAUTH_TOKEN ``` The remote list is tenant-scoped. Use the returned session and approval ids with `fh approve` or `fh reject` and the same URL and token environment variable. ## 7. Add and test Databricks features Preview recipes before changing the workspace, then install only the surfaces the agent needs: ```sh npx fh add databricks sql --dry-run npx fh add databricks sql npx fh add databricks ai-search npx fh add databricks rag-chain npx fh add databricks lakeflow npx fh add databricks jobs npx fh add databricks lakebase npx fh add databricks system-tables-cost npx fh add databricks apps npx fh add databricks agent-services npm install npm run build ``` | Capability | Credential-free check | Live proof | | --- | --- | --- | | AI Gateway/model | `fh run ... --mock` | A run without `--mock` returns a model response. | | SQL + Unity Catalog | Definition and policy load | Allowed metadata/query succeeds; denied catalog access remains denied. | | AI Search/RAG | Recipe build and deterministic mock tests | Known document is retrieved with citations; insufficient context is declined. | | Lakeflow + Jobs | Recipe build and request-contract tests | Create/read/cancel against a test job or pipeline. | | Lakebase | Persistence bundle build | Session survives App process replacement and credential refresh. | | Cost + lineage | Event schema tests | Tenant/principal tags appear in MLflow/system-table evidence. | | Human approval | Local approval contract | Pause, App redeploy, approve, and resume without losing state. | | OBO | Identity contract tests | Signed-in user permissions differ from the App service principal as expected. | | Agent Services | Lifecycle request contracts | Temporary registration is created, discovered, updated, permissioned, and deleted in Unity Catalog. | Use [Databricks recipes](/docs/databricks/recipes) for required environment variables and [RAG on Databricks](/docs/databricks/rag) for the MLflow evaluation and adversarial/insufficient-context workflow. Mocked unit tests and live certification answer different questions; keep both in release CI. ## 8. Build and deploy a Databricks App Build and inspect the deployment plan first: ```sh npx fh build --target databricks-app npx fh deploy \ --target databricks-app \ --profile fabric-harness \ --preview ``` Then deploy with the same profile: ```sh npx fh deploy \ --target databricks-app \ --profile fabric-harness ``` The build output is under `.fabricharness/build/databricks-app/`. TechFabric Harness produces the App server, manifest, `app.yaml`, and Databricks Declarative Automation Bundle configuration. Databricks App resources and secret references should supply production configuration; do not commit tokens or client secrets. The output is a portable package: workspace-owned contracts are bundled and the directory can be handed to Runway or another deployer without the source repository. See [Portable agent packages](/docs/deployment/portable-packages). ### What developers see in the App The deployed App should make the selected agent, runtime health, acting identity, region, and bound Databricks resources inspectable without rendering secret values. This is a representative, sanitized deployment state; names and resource health come from the active environment. Continue with the [Databricks App tutorial](/docs/deployment/databricks-app) for App resources, Lakebase durability, OBO, approvals, restart/redeploy recovery, and protected live certification. --- # Databricks integrations Canonical: https://harness.techfabric.com/docs/databricks/integrations Complete map of TechFabric Harness integrations for Databricks data, AI, orchestration, state, governance, telemetry, and cost. `@fabric-harness/databricks` exposes composable factories and a `databricks()` bundle. Use the bundle for the common governed stack; use individual exports when you need a narrower integration. Resource lifecycle APIs are covered in [Databricks resource authoring](/docs/databricks/authoring). To scaffold project wiring (managed files, env stubs, dependencies), use **[Databricks recipes](/docs/databricks/recipes)**: ```sh fh add databricks sql fh add lakebase fh add ai-search fh add lakeflow fh add agent-services ``` ## Data and AI | Service | TechFabric Harness API | Agent use | | --- | --- | --- | | Unity AI Gateway | `bundle.aiGateway`, `databricksFoundationModelProvider()` | Discover and invoke `system.ai.*` model services with submission/tenant request tags | | Model Serving | `databricksFoundationModelProvider({ mode: 'serving-endpoints' })` | Custom serving-endpoint inference | | SQL Warehouse | `databricksSqlReadTool()`, `databricksSqlTool()` | SELECT-only analytics reads plus construction-time policy-bound SQL execution | | Unity Catalog | `unityCatalogTablesTool()`, `databricksTableInfoTool()`, `DatabricksUnityCatalogAdmin` | Discover metadata; opt-in grants/catalog/schema/volume lifecycle | | Unity Catalog Agent Services | `bundle.agentServices` | Register external agents, discover them, update metadata, manage grants, and delete registrations | | AI Search | `databricksAiSearch()`, `databricksRagChain()`, `DatabricksAiSearchAdmin` | Retrieval plus opt-in endpoint/index lifecycle | | RAG quality | `scoreRagTurn()`, MLflow 3 export, managed evaluation Job | Local smoke checks plus a UC evaluation dataset and Databricks managed relevance, groundedness, sufficiency, and correctness judges | | Embeddings | `databricksEmbeddings()` | Query embeddings through a serving endpoint | | AI Functions | `databricksAiQueryTool()` | Invoke `ai_query()` through a SQL Warehouse against explicitly allowed endpoints | | Genie Agents (formerly AI/BI Genie spaces) | `DatabricksGenieClient`, `DatabricksGenieAdmin`, `DatabricksGenieAgentModeClient` | Stable governed conversations, beta normalized lifecycle/ACL management with managed-only model deletion, and explicit Beta Agent Mode SSE streaming | | Feature Serving | `databricksFeatureLookupTool()` | Low-latency governed feature lookup | | Workspace files | `bundle.workspaceSource()`, `workspaceWrite` | Read-only context plus opt-in import/mkdir/delete tools | | Asset Bundles | `bundle.assetBundle`, `assetBundles`, `databricksAssetBundleLifecycle()` | Governed checked-in bundle validate/deploy/run/destroy with source-fingerprint drift detection, no-wait run submission by resource key, and managed-only teardown | ## Managed MCP and MCP Services Use `databricksWithManagedMcp()` when a bundle consumes Databricks managed MCP servers or a Unity Catalog MCP Service through Unity AI Gateway. Discovery is asynchronous, so the synchronous `databricks()` factory rejects a configuration containing `mcp` rather than silently omitting its tools. ```ts import { databricksPrincipalFromEnv, databricksWithManagedMcp, } from '@fabric-harness/databricks'; const dbx = await databricksWithManagedMcp({ host: process.env.DATABRICKS_HOST!, principal: databricksPrincipalFromEnv(process.env), governance: { catalogs: ['main'], }, mcp: [ { name: 'support_genie', endpoint: { kind: 'genie', spaceId: process.env.DATABRICKS_GENIE_SPACE_ID! }, }, { name: 'delivery', endpoint: { kind: 'mcp-service', name: 'main.agents.fabric_runway' }, effects: { 'runway_catalog': 'read', 'runway_request_*': 'write', }, }, ], }); // Remote names are stable and collision-safe. console.log(dbx.tools.map((tool) => tool.name)); // mcp__support_genie__ask_genie, mcp__delivery__runway_catalog, ... try { // Use dbx.modelProvider, dbx.tools, and dbx.policy with init(). } finally { await dbx.managedMcp.close(); } ``` The adapter builds the documented workspace URLs for Genie, AI Search, SQL, Unity Catalog functions, and `/ai-gateway/mcp-services/`. It obtains a fresh bearer token from the bundle's PAT, OAuth M2M, CLI-profile, or OBO provider on every transport request and refuses to send that token to another origin. Tokens are absent from tool metadata and redacted from connection and tool errors. Genie and AI Search are classified read-only. SQL, Unity Catalog functions, registered MCP Services, and custom workspace URLs must supply `effects` globs or `defaultEffect`; otherwise discovery fails closed. Write/execute tools receive a static governed MCP resource, lineage, catalog policy, and approval binding through the same `withGovernanceTools()` path as native tools. Request-scoped Apps must call `forPrincipalWithManagedMcp()` and close the returned bundle after the request; the synchronous `forPrincipal()` method rejects principal reuse for remote connections. Authentication requires a workspace bearer credential accepted by the selected managed server. A registered MCP Service also needs `EXECUTE` on the service and `USE CATALOG` / `USE SCHEMA` on its parents. Missing Preview enrollment, OAuth authorization, UC privilege, effect classification, or approval is returned as an error before the underlying mutation can execute. Dynamic agents can mount the same governed connection conditionally. The connector is lazy: token resolution and tool discovery occur only when the current render declares it, and the runtime closes the connection after the interaction. ```ts import { connectDatabricksManagedMcpServer } from '@fabric-harness/databricks'; import { createAgent, defineMcpConnection, useMcpConnection, usePersistentState, } from '@fabric-harness/sdk'; const server = { name: 'catalog', endpoint: { kind: 'functions', catalog: 'main', schema: 'agent_tools' }, defaultEffect: 'execute', } as const; const catalogTools = defineMcpConnection({ name: server.name, connect: () => connectDatabricksManagedMcpServer({ host: process.env.DATABRICKS_HOST!, tokenProvider: async () => process.env.DATABRICKS_TOKEN, server, }), }); export default createAgent(() => { const [approved] = usePersistentState('catalogApproved', false); if (approved) useMcpConnection(catalogTools); return approved ? 'Use the governed catalog functions when needed.' : 'Complete approval before using catalog functions.'; }); ``` For an employee-facing Databricks App, construct the definition with a request-scoped OBO token provider. For shared automation, use a least-privilege OAuth M2M provider. Raw workspace credentials must never enter persistent state or initial data. ## Inference names and URLs Use the workspace **origin** for `DATABRICKS_HOST`, not an API path. Fabric selects the inference base from the model name: | Model value | Mode | OpenAI-compatible base URL | | --- | --- | --- | | `system.ai.gpt-oss-20b` (or another discovered `system.ai.*` service) | Unity AI Gateway | `${DATABRICKS_HOST}/ai-gateway/mlflow/v1` | | A custom endpoint name such as `support-agent-prod` | Custom Model Serving | `${DATABRICKS_HOST}/serving-endpoints` | `DATABRICKS_INFERENCE_MODE=auto` is the default. Set `ai-gateway` or `serving-endpoints` only when overriding automatic routing. Use `DATABRICKS_AI_GATEWAY_BASE_URL` for a proxy or explicitly configured Gateway base. Discover services enabled in the current workspace with `await bundle.aiGateway.listModelServices()` instead of assuming every `system.ai.*` service is available. ## Engineering and operations | Service | TechFabric Harness API | Agent use | | --- | --- | --- | | Jobs | `databricksRunJobTool()`, `DatabricksJobsAuthoring` | Run existing Jobs within a required `runPolicy` allowlist, or opt into policy-bounded Jobs 2.2 lifecycle | | Notebooks | `databricksNotebookTool()` | Submit a one-time notebook run within a required `notebookPolicy` allowlist | | Lakeflow | `databricksLakeflowTools()`, `DatabricksLakeflowAuthoring` | Operate existing pipelines; separately opt into create/update/delete/events | | MLflow runs | metric and parameter tools | Write run metadata | | MLflow tracing | `bundle.mlflowTraceExporter()` | Export settled agent spans to MLflow Tracing | | Serving usage | `servingUsageCapture()` | Associate inference-table usage with submissions | | System tables | `databricksConsumption()` | Aggregate billable usage for tenants and agents | | Actual-cost budgets | `databricksActualCostSource()`, `databricksTenantCostLimit()` | Reconcile policy budgets against usage records | | Lakebase | `lakebaseClient()`, `databricksPersistence()` | Sessions, submissions, conversation streams, and telemetry | | UC Volumes | `UcVolumesAttachmentStore`, Volume source/writer | Governed attachments and non-tabular context | ## Reuse from vertical applications Application repositories must not create their own Databricks client package. Compose a principal with `databricksPrincipalFromEnv()`, use `databricksSdk()` for generated service clients, and use the bundle only for reviewed SDK gaps such as AI Gateway and SQL warehouse discovery. For libraries that require `fetch`, `createDatabricksAuthenticatedFetch()` supplies a rotating workspace credential and bounds authorization retry to one 401/403 response. For SQL, `runStatement()` uses the generated Statement Execution client with named parameters and bounded polling. Provider-service and warehouse listings are available from `bundle.aiGateway` and `bundle.sqlWarehouses`; raw protocol transport remains private to Harness. ## Add a standalone tool ```ts import { databricksSdk, databricksFeatureLookupTool, withGovernance, } from '@fabric-harness/databricks'; const principal = { kind: 'service-principal', host: process.env.DATABRICKS_HOST!, clientId: process.env.DATABRICKS_CLIENT_ID!, clientSecret: process.env.DATABRICKS_CLIENT_SECRET!, } as const; const sdk = databricksSdk({ host: process.env.DATABRICKS_HOST!, principal, }); const customerFeatures = withGovernance( databricksFeatureLookupTool(sdk.modelServingQuery, { endpoint: 'customer-features', name: 'lookup_customer_features', }), { principal: `sp:${process.env.DATABRICKS_CLIENT_ID}`, onLineage: (record) => auditSink.write(record), }, ); ``` ## Integration boundaries - TechFabric Harness does not replace Unity Catalog permissions or Databricks resource ACLs. - Managed MCP and Unity AI Gateway are Databricks Preview/Beta surfaces; run the protected live certification in every target workspace before release. - The SQL tool and SQL sandbox execute statements; they do not provide a Linux shell. - Workspace files and Unity Catalog Volumes are separate APIs and path spaces. - `databricks-serving` is a proxy target, while `databricks-app` hosts the Node runtime. - Availability and API behavior can vary by cloud, region, workspace feature enablement, and preview status. Validate each enabled integration in the target workspace. --- # Databricks resource management Canonical: https://harness.techfabric.com/docs/databricks/authoring Author governed Genie agents, Jobs, Lakeflow pipelines, Model Serving and Unity Catalog resources from an agent, with approvals and managed-only deletion. TechFabric Harness lets an agent (or a user driving one) **manage** the Databricks resources it operates — create a Job, define a pipeline, build an AI Search index, size a serving endpoint, create a Genie Agent, grant access — through the same governed, typed seams the consumption tools already use. Resource management is **opt-in per surface** and **fails closed**: a consumption-only `databricks()` bundle keeps its existing tools, and any model-exposed write surface refuses to initialize unless approval routing is configured. Stable services run through Databricks' official modular TypeScript SDK. Fabric owns the agent layer: approval binding, policy, lineage, durable retries, managed-resource fingerprints, and cleanup. Protocols absent from the SDK stay in a small, explicit raw protocol adapter. This does not replace Databricks Asset Bundles, Terraform, or checked-in pipeline source: Harness never *generates* that IaC. But the lifecycle of a checked-in bundle — validate, deploy, run, destroy — is itself a governed agent surface; see [Checked-in Asset Bundles](#checked-in-asset-bundles). The docs use **resource management** as the developer-facing term. “Authoring” remains in a few flag and certification names where it distinguishes create/update/delete from consumption; it does not mean a second infrastructure-as-code system. ## Quickstart: author your first Job Enable one surface, bound its compute, and route writes to an approval audience: ```ts import { init } from '@fabric-harness/sdk'; import { databricks } from '@fabric-harness/databricks'; const dbx = databricks({ host: process.env.DATABRICKS_HOST!, principal: { kind: 'service-principal', host: process.env.DATABRICKS_HOST!, clientId: process.env.DATABRICKS_CLIENT_ID!, clientSecret: process.env.DATABRICKS_CLIENT_SECRET!, }, jobAuthoring: true, computePolicy: { maxConcurrentRuns: 1, maxRunTimeoutSeconds: 1800, requiredTags: { 'cost-center': 'agents' }, // schedules stay disabled unless you opt in with `schedules: true` }, governance: { stewardAudience: 'data-platform', catalogs: ['main'], onLineage: (record) => audit(record), }, }); const fabric = await init({ modelProvider: dbx.modelProvider, tools: dbx.tools, policy: dbx.policy }); ``` What happens when the model calls `databricks_create_job`: 1. The call routes to the `data-platform` approval audience. Execution does not start without a grant bound to this exact call (see [approvals](#how-approval-and-governance-work)). 2. The job spec is validated against `computePolicy` before any API call — schedules off, timeout and concurrency capped, required tags present. 3. The created job is stamped with the `fabric-harness:managed` tag and a canonical spec fingerprint, so later updates and deletes can prove ownership. 4. The operation is recorded in lineage with the executing principal and every approver. For local development only, `allowUnapprovedAuthoring: true` bypasses the fail-closed approval requirement. It is the single escape hatch and should never be set in a deployed app. Runnable end-to-end versions of this flow live in the [authoring examples](#examples-and-failure-behavior). ## How approval and governance work An approval **grant** binds the logical tool-call id, a canonical digest of the input, the executing principal, the approver identities, and an expiry. A durable retry may replay the same operation, but a grant can never be reused for different input or a different identity. Grant TTL starts when the approval is decided, not when it was requested. The `governance` block controls routing and audit: | Field | Effect | | --- | --- | | `stewardAudience` | Required for any model-exposed authoring surface. Write/execute tools route approval requests to this audience. | | `approvalServices` | Optional narrowing: only write/execute tools whose `metadata.service` appears here require approval. Excluded services remain usable without a grant, which supports separate dev and production tools. Omit it to gate every write/execute tool. | | `approvalTtlSeconds` | Grant time-to-live, measured from the approval decision. | | `catalogs` | Belt-and-suspenders allowlist checked against every catalog-qualified resource in structured tool inputs. Unity Catalog remains the authoritative enforcement boundary. | | `principalLabel` | Label recorded in lineage for the acting principal (never a token). Defaults to a label derived from the configured principal. | | `onLineage` | Sink for audit/lineage records; wire to OTel or your event pipeline. | Read tools remain approval-free when an admin surface is enabled. The typed clients (`DatabricksJobsAuthoring`, `DatabricksGenieAdmin`, …) can always be used without model approval policy — "the SDK may author" is deliberately separate from "a model may autonomously author". Native Databricks/Unity Catalog authorization is authoritative in either path. Narrow by service only when that service boundary is explicit in the tool inventory. For example, use separate `deploy_dev` (`service: "dev"`) and `deploy_prod` (`service: "prod"`) tools, then set `approvalServices: ["prod"]`. The governance wrapper and approval policy use the same selection, so the dev tool runs without a grant while the production tool fails closed until approved. Genie conversations, lifecycle management, and Agent Mode are configured together under `genie`. Supplying `genie.manage` is the explicit write opt-in; no separate authoring boolean is required. ## Request-scoped user identity Use a principal returned by forwarded-token validation/current-user inspection, never a label supplied by the request: ```ts const inspection = await inspectDatabricksAppUserAuthorization({ headers, host }); const user = dbx.forPrincipal({ tokenProvider: forwardedTokenProvider, principal: inspection.principal }); ``` The scoped bundle has isolated generated SDK/model/embedding/credential clients and does not mutate the parent. Persistence wiring and policy/lineage sinks remain app-scoped. Approval records and lineage distinguish the executing principal from all approvers. ## Native SDK boundary `databricks()` exposes the official principal-bound clients at `bundle.sdk`. Application code can also create them directly: ```ts import { databricksSdk, databricksJobs } from '@fabric-harness/databricks'; const sdk = databricksSdk({ host, principal }); const jobs = databricksJobs(sdk.jobs); ``` Generated clients own stable Jobs, Statement Execution, Lakeflow, Vector Search, Model Serving, Files, Secrets, Genie, Access Management, Unity Catalog, MLflow Experiments, and Lakebase request/response models. Fabric's private raw protocol transport has an exhaustive method-and-path allowlist for endpoints that the modular SDK does not yet expose. Anything else is denied before credentials are resolved or network I/O starts. Source-boundary and runtime-denial tests enforce that quarantine. Every generated module is exact-pinned to SDK `0.21.0`, and CI verifies the package pins, runtime constant, compatibility page, README, generated serialization, and packaged import together. Genie Agent permissions use the generated `@databricks/sdk-accessmanagement` client; they are not a raw-protocol exception. The only stable-API fallbacks are the exact Genie query-result and AI Search floating-score decoder mismatches documented on the compatibility page. ## Resource-management surfaces Each surface is an independent opt-in. Enable only what the agent needs: | Flag | Typed client | Model tools and constraints | | --- | --- | --- | | `jobAuthoring` | `DatabricksJobsAuthoring` | CRUD/list/repair; Jobs API 2.2; classic compute requires an allowed cluster-policy id | | `oneOffCompute` | `submitRun()` | **Separate flag** — `jobAuthoring` alone does not expose `databricks_submit_run`; policy-bounded multi-task one-off runs | | `lakeflowAuthoring` | `DatabricksLakeflowAuthoring` | Pipeline create/update/delete; `lakeflow: true` is read-only and `lakeflow.runPolicy` adds bounded start/stop | | `lakeflowEvents` | `pipelineEvents()` | Requires `lakeflowAuthoring` and `warehouseId`; queries `event_log('')` | | `genie.manage` | `DatabricksGenieAdmin` | Normalized version-2 create/get/list/update/export/import plus ACLs; the object itself is the explicit write opt-in | | `genie.manage.delete` | `databricks_delete_genie_agent` | Must be `managed-only`; exact Harness-managed id and expected fingerprint only | | `genie.agentMode` | `DatabricksGenieAgentModeClient` | Explicit Beta SSE stream, deadlines, lineage callbacks, pagination, and optional bounded model tool | | `aiSearchAdmin` | `DatabricksAiSearchAdmin` | Endpoint/index create, describe, sync, wait, and delete; delta-sync and direct-vector unions. Takes a **required policy**, not a boolean: `allowedOperations` decides which tools register, and endpoint/index/embedding/source-table bounds are pinned into the schemas and re-checked at call time. `{ allowAnyAiSearchAdmin: true }` is the explicit unbounded opt-out | | `servingAdmin` | `DatabricksServingAdmin` | Custom/foundation/external/agent endpoint variants, config updates, and separate AI Gateway updates | | `ucAdmin` | `DatabricksUnityCatalogAdmin` | Grants plus catalog/schema/volume creation | | `ucDestructiveAdmin` | `deleteManaged()` tools | Requires `ucAdmin`; exact identifiers only; managed resources only; no force/cascade | | `workspaceWrite` | Governed bundle tools | Notebook import, mkdirs, and exact-path deletion | | `secretsWrite` | `DatabricksSecretsAuthoring` | Requires `secretProvider`; scope lifecycle and `SecretRef` writes; built-in tools never accept raw values | | `assetBundles` | `DatabricksAssetBundleLifecycle` (or one per name) | Checked-in Asset Bundle validate/deploy/run/destroy through the Databricks CLI; source-fingerprint drift detection; managed-only destroy; a name-keyed map adds a required `bundle` selector | A bundle with **every** surface enabled looks like this — treat it as a reference for field names, not a starting point: ```ts const dbx = databricks({ host, principal, jobAuthoring: true, oneOffCompute: true, computePolicy: { allowedPolicyIds: ['policy-id'], allowedExistingClusterIds: ['explicit-shared-cluster-id'], maxWorkers: 2, maxConcurrentRuns: 1, maxRunTimeoutSeconds: 1800, allowedNodeTypes: ['Standard_D4ds_v5'], allowedRuntimeVersions: ['15.4.x-scala2.12'], serverlessPerformance: 'STANDARD', schedules: false, requiredTags: { 'cost-center': 'agents' }, }, lakeflowAuthoring: true, lakeflowEvents: true, assetBundles: { bundleDir: '.', target: 'dev' }, genie: { manage: { resourceStore: managedResourceStore, delete: 'managed-only', }, }, aiSearchAdmin: { allowedOperations: ['createIndex', 'syncIndex', 'describeIndex'], allowedIndexes: ['main.kb.docs_idx'], allowedEndpoints: ['kb-search'], allowedEmbeddingModelEndpoints: ['databricks-bge-large-en'], allowedSourceTables: ['main.kb.docs'], }, servingAdmin: true, ucAdmin: true, ucDestructiveAdmin: true, workspaceWrite: true, secretsWrite: true, secretProvider, warehouseId, governance: { stewardAudience: 'data-platform', approvalTtlSeconds: 900, catalogs: ['main'], onLineage: audit, }, }); ``` ## Compute policy reference `computePolicy` bounds every Jobs-authoring and one-off-run spec **before** any API call: | Field | Enforcement | | --- | --- | | `allowedPolicyIds` | Classic VM compute requires a non-empty list and a matching `policyId` on every new cluster. Serverless jobs take the serverless branch and bypass cluster policy. | | `allowedExistingClusterIds` | Existing all-purpose clusters are denied unless their exact id is listed. | | `maxWorkers` | Caps `numWorkers` on every new cluster. | | `maxConcurrentRuns` | Caps the job's `maxConcurrentRuns` (default 1). | | `maxRunTimeoutSeconds` | Caps `timeoutSeconds`. | | `allowedNodeTypes` | When set, every new cluster's `nodeTypeId` must be listed. | | `allowedRuntimeVersions` | When set, every new cluster's `sparkVersion` must be listed. | | `requiredTags` | Every new cluster must carry exactly these `custom_tags`; empty keys or values are rejected at configuration time. | | `schedules` | Schedules are rejected unless explicitly `true`. | | `serverlessPerformance` | When set (`'STANDARD'` or `'PERFORMANCE_OPTIMIZED'`), a spec that names a different serverless performance target is rejected. | Allowlist fields must be non-empty when configured; numeric caps must be non-negative. Violations fail at bundle initialization or before the write executes — never after. `computePolicy` does **not** bound execution of an *existing* job. `databricksRunJobTool` and `databricksNotebookTool` carry their own required `runPolicy` / `notebookPolicy`, enforced on the run path itself. See [Bound what a model can run](/docs/databricks/compute). ## Managed resources and safe deletion Destructive tools only touch resources TechFabric Harness can **prove** it created. Because Databricks services expose different metadata capabilities, three marker schemes exist: - **Jobs** — created jobs carry the tags `fabric-harness:managed=true` and `fabric-harness:fingerprint=`. `ifExists: 'reuse'` adopts only a single job matching name, managed tag, and fingerprint; anything ambiguous is refused. Updates refuse to remove the ownership tags and re-stamp the fingerprint. - **Unity Catalog** — created catalogs and schemas carry the property `fabric-harness.managed="true"`; volumes (which have no properties) carry a comment prefixed `[fabric-harness:managed]`. `deleteManaged()` reads the object first and refuses to delete anything not carrying its marker. No force or cascade options exist. - **Genie Agents** — the Genie management API supports neither tags nor properties, so ownership lives in a durable `DatabricksManagedResourceStore` manifest recording fingerprint, creator, and tool-call provenance. Deletion requires the exact managed id and expected fingerprint; an already-trashed managed id is treated as an idempotent success. `MemoryDatabricksManagedResourceStore` is only for tests and local development; use `LakebaseDatabricksManagedResourceStore` or another durable implementation in production. - **Asset Bundles** — bundle ownership lives in the same `DatabricksManagedResourceStore` manifest (`resourceType: "databricks-bundle"`), recording a sha256 fingerprint of the sorted bundle source tree (excluding `.databricks/` CLI state, `node_modules/`, and `dist/`). Deploy records the fingerprint after a successful CLI run; destroy requires the record and refuses to tear down a drifted tree unless `force` is set. See [Checked-in Asset Bundles](#checked-in-asset-bundles). A create whose API response is ambiguous is never retried automatically, so a transient failure cannot orphan an unmarked resource. Schedules default off. Serverless jobs take the serverless branch; classic VM job compute requires a non-empty `allowedPolicyIds` and a matching `policyId` on every new cluster. Existing all-purpose clusters are denied unless their exact id appears in `allowedExistingClusterIds`. ## Checked-in Asset Bundles A job/pipeline bundle authored in YAML — by hand, by `databricks bundle init`, or by exporting a Lakeflow Designer canvas as a `.designer.ipynb` referenced from a `notebook_task` — stays checked-in IaC. What Harness governs is its **lifecycle**. The `assetBundles` option points the bundle at a directory containing `databricks.yml` and adds four model tools plus a typed client at `bundle.assetBundle`: ```ts const dbx = databricks({ host, principal, assetBundles: { bundleDir: './bundle', target: 'dev' }, governance: { stewardAudience: 'data-platform' }, }); ``` | Tool | Effect | Behavior | | --- | --- | --- | | `databricks_bundle_validate` | read | Runs `databricks bundle validate` in `bundleDir`; no workspace mutation. | | `databricks_bundle_deploy` | write | Validates, deploys, then records the source fingerprint in the managed-resource store. Optional `expectedFingerprint` input fails with `DatabricksManagedResourceConflictError` when the recorded fingerprint differs — optimistic concurrency so one agent cannot stomp a bundle recorded from another tree. | | `databricks_bundle_run` | execute | Submits a run of a bundle-defined job/pipeline by its `databricks.yml` resource key. Always `--no-wait` — waiting inside a tool call would violate finite-agent boundedness. The result includes `resourceKey` plus a job `runId`, or the Lakeflow `pipelineId`/`updateId`, and `runUrl` when supplied by the CLI, so the bounded jobs/lakeflow status tools compose without parsing text. No managed record is required: bundles deployed outside Harness (e.g. by CI) stay runnable, and the CLI fails cleanly against an undeployed bundle. | | `databricks_bundle_destroy` | write | Requires the managed record (`DatabricksUnmanagedResourceError` otherwise), refuses a drifted tree unless `force: true`, runs `databricks bundle destroy --auto-approve`, and deletes the record. | The fingerprint is a deterministic sha256 over the sorted bundle source tree (relative path plus content), excluding `.databricks/`, `node_modules/`, and `dist/`. The lifecycle shells out to the Databricks CLI (`executable` defaults to `databricks`, so it must be on `PATH`) and authenticates through the CLI's normal environment or `--profile` resolution; `target`, `profile`, and `env` pass through unchanged. CLI failures surface with a bounded stderr tail and are never retried automatically. ### Several bundles in one agent Passing a name-keyed map instead of one entry configures several bundles — a separate lifecycle per name, exposed as `bundle.assetBundles`: ```ts const dbx = databricks({ host, principal, assetBundles: { jobs: { bundleDir: './bundles/jobs', target: 'dev' }, pipelines: { bundleDir: './bundles/pipelines', target: 'dev' }, }, governance: { stewardAudience: 'data-platform' }, }); await dbx.assetBundles?.jobs?.validate(); ``` The tool names stay the same four. Every one of their input schemas gains a required `bundle` selector enumerating the configured names (`jobs`, `pipelines`), so a call must always say which bundle it means — including when only one bundle is configured, which keeps the schema and its approval digests stable if a second bundle is added later. Names must match `^[A-Za-z0-9][A-Za-z0-9_-]*$`, and an empty map is rejected. Governed lineage names only the bundle the call selected, never the whole configured set, because the descriptor is a `/bundle` input path rather than a static value. An approval grant binds the tool-call id, the executing principal, and the canonical tool **input**. `bundle` is part of that input, so a grant approved for `{ bundle: 'jobs' }` cannot be replayed against `{ bundle: 'pipelines' }` — distinct names cannot cross-approve. A name's `target`, however, is configuration rather than input: retargeting `jobs` from `dev` to `prod` does **not** invalidate outstanding grants for `jobs`, so a durable approved call replayed after that change would hit the new target. When dev and prod need separate approvals, model them as separate named entries (`jobs_dev`, `jobs_prod`) instead of editing one name's target. Managed-resource identity is scoped per name and target — `#[#]`, where the `#` suffix is present only when that entry configures a `target` — so several lifecycles can share one durable `DatabricksManagedResourceStore` without overwriting each other's fingerprint records. The single-bundle shape keeps the bare manifest name, so existing records stay addressable. One limitation: approval routing is per **tool name**, so every named bundle routes to the same `governance.stewardAudience`. Per-bundle audiences are not expressible — if `jobs` and `pipelines` need different approvers, build two agents. Like every authoring surface, `assetBundles` fails closed: without `governance.stewardAudience` (or the local-only `allowUnapprovedAuthoring: true`), bundle initialization throws instead of exposing ungated deploy/run/destroy tools. Application code can also drive the same lifecycle directly through `databricksAssetBundleLifecycle()` / `databricksAssetBundleTools()` without a model. See `examples/with-databricks-bundle-deploy` for a runnable steward-gated flow and [`fh add databricks bundle`](/docs/databricks/recipes) for the scaffold. ## Genie Agents Databricks renamed Genie spaces to **Genie Agents**, while the stable management and Conversation API paths retain `/genie/spaces`. Fabric consistently calls the resource identifier `agentId`. The stable consumption path uses the typed `DatabricksGenieClient`. It starts or continues a conversation, requires a terminal `COMPLETED` state, retrieves every query result from its attachment-specific endpoint, and returns typed text, query, result, suggested-question, and visualization metadata. Missing ids, terminal failure, polling exhaustion, cancellation, oversized responses, and malformed attachments fail explicitly. Application code can also list conversation history and message comments or delete an exact conversation id; only ask is model-facing by default. Genie lifecycle management is **stable for the certified create/query/update/trash scope**: ```ts const dbx = databricks({ host, principal, genie: { manage: { resourceStore: new LakebaseDatabricksManagedResourceStore({ client: lakebase }), delete: 'managed-only', }, }, governance: { stewardAudience: 'data-platform', catalogs: ['main'] }, }); const salesAnalyst = await dbx.genieAdmin?.create({ version: 2, title: 'Sales analyst', parentPath: '/Shared/agents', warehouseId: 'warehouse-id', dataSources: [{ table: 'main.sales.orders' }], }); ``` `DatabricksGenieAdmin` provides list/get/create/update/delete, export/import, and permissions APIs. The serializer emits Databricks `serialized_space` version 2, deterministic 32-character ids, and the required sorted collections. Updates compare the caller's expected canonical fingerprint and send the last observed Databricks ETag. The management API has no general field mask: `description` is the only field that supports explicit clearing via `remove`; other fields can only be set to new values. Ambiguous creates, updates, and deletes are not retried. Raw `serialized_space` is accepted only by typed-client import/export; no built-in ToolDef accepts it. Model-facing create, inspect, update, and optional delete tools use a normalized schema containing tables, columns, sample questions, and one text instruction. SQL examples, functions, joins, filters, expressions, measures, and benchmarks become available only when `genie.manage.sqlPolicy` is configured. The policy runs server-side for every SQL fragment, must return the complete parsed `catalog.schema.object` set, and denies any resource outside `dataSources`. An allowlisted prepared statement is also valid; returning an empty or partial parse for dynamic SQL is not. Mutation requires steward approval and a durable ownership record. ```ts const certifiedSql = new Map([ ['SELECT COUNT(*) FROM main.sales.orders', ['main.sales.orders']], ]); const dbx = databricks({ // ...identity, ownership store, governance... genie: { manage: { resourceStore: managedResourceStore, sqlPolicy: ({ sql }) => { const resources = certifiedSql.get(sql); if (!resources) throw new Error('SQL is not in the certified statement set'); return { resources }; }, }, }, }); ``` Fabric's ordinary Genie client uses the Conversation API. The separately configured Agent Mode client supports Databricks' Beta SSE endpoint: ```ts const dbx = databricks({ host, principal, genie: { agentMode: { agentId: '0123456789abcdef0123456789abcdef', acknowledgeBeta: true, timeoutMs: 5 * 60_000, idleTimeoutMs: 2 * 60_000, modelTool: { maxOutputBytes: 512 * 1024 }, onEvent: (event) => auditAgentModeProgress(event), }, }, }); for await (const event of dbx.genieAgentMode!.respond('Summarize revenue by region')) { if (event.type === 'response.completed') console.log(event.response.output); } ``` It validates the preview's 32-hex agent id, never retries the response-creating POST, propagates cancellation, enforces idle and overall deadlines, parses arbitrarily chunked SSE, preserves unknown Beta events, enforces monotonic sequence numbers and event/stream limits, and requires `response.completed` or `response.failed`. `modelTool` adds the governed `databricks_genie_agent_mode` tool; progress goes only to `onEvent`, while the model receives one bounded terminal response. `listConversationItems()` exposes the cursor-based history endpoint. A failed terminal event is yielded and then raises `DatabricksGenieAgentModeResponseError` on the next iterator step. The workspace must be enrolled by the Databricks account team and a workspace admin must enable **Genie Agents Agent Mode API** in Previews. Agent Mode allows one in-flight response per conversation and can keep an SSE connection open for up to 90 minutes. Fabric does not silently substitute it for ordinary Genie conversations. See the [Genie Agents API](https://docs.databricks.com/aws/en/genie-agents/conversation-api) and [Beta Agent Mode API](https://docs.databricks.com/aws/en/genie-agents/api) for the native contracts. ### Bind a Genie Agent to a Databricks App ```ts title=".fabricharness/config.ts" export default { target: 'databricks-app', databricks: { app: { genie: { agentId: '0123456789abcdef0123456789abcdef', // permission defaults to CAN_RUN }, }, }, }; ``` The generated bundle attaches a `genie_space` resource and injects `DATABRICKS_GENIE_AGENT_ID` through `valueFrom`; it does not embed the id in model context. `CAN_EDIT` and `CAN_MANAGE` are rejected unless the deployment block also sets `authoring: true`. ### Genie Ontology export `planModuleOntologyExport` is the first piece of the Genie Ontology exporter: it consumes a governed Fabric module manifest — the JSON-serializable `ModuleManifest` / `ModuleManifestBundle` contract from `@fabricorg/platform/manifest`, consumed type-only — and produces a deterministic, fingerprinted `DatabricksOntologyExportPlan` describing how the module's declared ontology maps onto Unity Catalog Semantics (metric views, glossary terms, domain assignments) and a Genie Agent spec: ```ts import { planModuleOntologyExport } from '@fabric-harness/databricks'; const plan = await planModuleOntologyExport({ manifest, // ModuleManifest or ModuleManifestBundle produced by the vertical's Platform process catalog: 'main', schema: 'lending_semantics', // domain defaults to the manifest namespace; genie/feed options are optional }); ``` The plan step is pure — no network, no clock — so its output is safe to render for review and diffs byte-identically across runs for an unchanged manifest; `plan.fingerprint` changes when the manifest or plan inputs change. The manifest is an export source only: UC Metric Views remain the runtime semantic source of truth, export is one-directional (Platform → UC/Genie), and Genie stays read-only over Fabric-governed domains. `plan.policyClassifications` records the class (`threshold-ratio-metric`, `gate-compliance-rule`, or `code-evaluator`) plus the matched evidence for every manifest policy, and `plan.metricViewDdl` carries one `CREATE OR REPLACE VIEW ... WITH METRICS LANGUAGE YAML` statement per module (`_metrics`), tagged with the `fabric-harness.managed` marker and a manifest-fingerprint comment so drift is detectable by inspection and re-export is byte-identical. Threshold/ratio data policies become metric-view measures; compliance gates (FCRA/TCPA-style) become glossary business rules and never `MEASURE(...)` — a code policy becomes a metric seed only through the explicit `metricSeedPolicyIds` opt-in. Measures from countable action volumes arrive with the operational-truth feed tables in a later release. When the `feed` option is present, `plan.feedTables` carries the operational-truth feed: three Delta/UC tables per module — `._asset_events` (domain events with `schema_version`, tenant, correlation, and causation), `_action_invocations` (action id, version, terminal status, failure classification, duration, and redacted parameters only), and `_policy_evaluations` (decision, reasons, evaluator identity/version, and failure mode). The generated DDL is `CREATE TABLE IF NOT EXISTS ... USING DELTA` with `'delta.appendOnly' = 'true'`, the managed tag, and a feed-fingerprint comment. Each table is replay-safe by construction: the hydration pipeline merges on the Platform id column (`spec.replayKey` — `event_id`, `invocation_id`, `evaluation_id`) with `MERGE ... WHEN NOT MATCHED THEN INSERT`, so re-hydrating recorded history is idempotent. Tenant scoping is a `tenant_id` column enforced by UC grants per consumer, never filtered at export, and the feed reads durable history records only — it is orthogonal to the vertical's host execution runtime. Events land at their declared `schema_version`; Harness performs no upcasting at append time (the conservative resolution of design question Q3 — a vertical that wants a current-shape stream upcasts in its own producer). `applyModuleOntologyExport` executes the feed DDL through the same approval-gated statement seam as the metric views, ahead of them (the metric view sources the asset-events feed), with one provenance record per table. Every feed table spec carries an explicit `publishableFields` allowlist, and row materialization projects each record onto exactly that list before Delta append — anything not allowlisted is dropped, so PII/PHI never reaches Genie's training surface. **Redaction ownership stays with the vertical**: Harness defines no redaction policy of its own. Feed rows are materialized only through the caller's redacted-record producer (the fabric-autorefi `redactActionParameters` pattern); materialization fails closed without it, so raw Platform records can never be appended unredacted. Harness's role is limited to the schema contracts, the publish-time allowlist check, and absence tests proving raw parameters and PII-bearing fields never land. Retention for the append-only feed is defined in `docs/databricks-genie-ontology-feed-retention.md`: a 90-day hot retention window by default (per-table configurable, keyed to each table's recorded domain time), no Harness-side archive by default, and a scheduled expiry job that lands with the first dogfood deployment — re-hydration through `planOntologyFeedHydration` can always restore expired rows from Platform history. `planOntologyFeedHydration` is the replay-safe append pipeline (design §3.7). It takes the plan's feed table specs, recorded Platform history grouped by kind (`assetEvents`, `actionInvocations`, `policyEvaluations`), and the required redacted-record producer, and returns merge-ready rows plus one deterministic `MERGE INTO ... USING (VALUES ...) WHEN NOT MATCHED THEN INSERT` statement per table, keyed by the spec's replay key. Rows are redacted, allowlist-projected, deduplicated on the replay key within the batch (first occurrence wins, drops counted), and sorted by replay key, so identical history yields a byte-identical plan and re-applying a statement inserts no duplicate rows — the idempotent re-run contract. The pipeline is pure (no network, no credentials): the scheduled feed pipeline executes the statements through `runStatement` with a `DatabricksStatementClient` constructed for the per-tenant workspace service principal (§5), while tenant scoping stays a `tenant_id` column enforced by UC grants. For asset events, `assetEventRecordFromEnvelope` maps the shipped `AssetEventEnvelope` shape from `@fabricorg/platform/events` (consumed type-only, exactly like the manifest) onto the feed record fields; Platform ships no durable ActionInvocation/PolicyEvaluation record contract, so the minimal `DatabricksOntologyActionInvocationRecord` / `DatabricksOntologyPolicyEvaluationRecord` types define what the vertical's history reader hands over. The runnable `examples/with-databricks-ontology-export` workspace demonstrates the full story credential-free — plan, hydration with a demo redaction producer, idempotent re-run, and a PII-absence check — with exact expected output in its README. `plan.glossaryTerms` and `plan.domainAssignments` carry the Unity Catalog glossary upsert payloads: one term per object type (`displayName` names the term; `idPrefix` and the module `idPrefixes` registry are preserved as metadata for identifier parsing), subject-vocabulary terms, one term per event type with `schemaVersion` metadata, lifecycle terms for actions with `mutatesDomain: true` (read-side phrasing only), business-rule terms referencing `policyId@policyVersion` for gate/compliance and code policies (a `dataDefinition` summary for data policies; code-evaluator logic is Platform-internal and never exported), and one term per state-machine state label. Every term carries `manifestVersion` metadata. Domain assignments bind one UC domain per module namespace — the `domain` option overrides the default — with the module description as the domain comment. Adapter steps, code-policy bodies, and `requiredRoles` / `requiredPermissions` / `eventPhase` are deliberately excluded. These payloads are plan data until apply; the governed publish path goes through `applyModuleOntologyExport` (see below), and the glossary/domain UC REST surface maturity is still being tracked while Genie Ontology is in public preview — apply accepts an injected `DatabricksOntologyGlossaryPublisher` so the publish client can evolve without changing the plan contract. When the `genie` option is present, `plan.genieSpec` carries a fully derived `DatabricksGenieAgentSpecV2` — the same spec shape the Genie authoring tools accept, normalized and fingerprinted through the identical canonicalization `DatabricksGenieAdmin` applies. Each module in the bundle contributes a `kind: "metric-view"` data source (`.._metrics`), plus its declared feed tables when `feed` options are present; threshold/ratio policies become `sqlSnippets.measures` reusing the exact metric-view measure names and expressions; object-type `displayName`s and state labels land as column synonyms; bundle `dependencies` become joins on the shared `object_type` key (only when both manifests are in the bundle); sample questions come from action and state vocabulary with read-side phrasing only; and the single permitted instruction carries the namespace description, the event lifecycle vocabulary, and the read-only constraint — Genie never mutates Fabric-governed domains. Action parameter names are treated as untrusted text: they appear only as read-side slot hints in sample questions, and only after passing a denylist filter (`password`, `secret`, `token`, `ssn`, …) plus the vertical's own `genie.sensitiveFieldPatterns`. `plan.genieSpecFingerprint` is the canonical spec fingerprint the governed apply path will use as `expectedFingerprint`, so a plan-time diff keys off the same conflict contract as the shipped authoring path: ```ts const plan = await planModuleOntologyExport({ manifest: bundle, // ModuleManifestBundle — joins derive from cross-module dependencies catalog: 'main', schema: 'vertical_semantics', genie: { agentId: existingAgentId, // omit to create; used for the conflict-check fingerprint admin: genieAdmin, // existing fingerprinted authoring client (apply only; wiring, not an input) parentPath: '/Workspace/Genie', warehouseId: 'wh-1', // sensitiveFieldPatterns: ['drivers_license'], // vertical-declared additions to the denylist }, }); // plan.genieSpec — reviewable, deterministic DatabricksGenieAgentSpecV2 // plan.genieSpecFingerprint — desired post-apply fingerprint for no-op/conflict detection ``` `applyModuleOntologyExport` is the governed write side of the plan/apply split. It takes the plan plus already-constructed clients (it never resolves credentials — interactive export should build them with OBO identity so UC enforces the curator's own grants) and applies the artifacts in dependency order: feed tables → metric views → glossary/domains → Genie Agent: ```ts import { applyModuleOntologyExport } from '@fabric-harness/databricks'; const result = await applyModuleOntologyExport(plan, { resourceStore, // shared managed-resource provenance store principal: 'user:curator@example.com', // exporting principal label, never a token toolCallId, // stable correlation id for this apply invocation statements, // statement-execution client (metric-view DDL seam) warehouseId: 'wh-1', approval: async (request) => { // Required. Called once per write, before it happens: feed-table DDL, // metric-view DDL, domain assignment, glossary publish, Genie Agent // create/update — each // with effect: 'write', the governed resource, and the content fingerprint. // Route to the steward approval flow; throw to deny. }, sqlPolicy, // required when the derived spec carries SQL fragments (fail-closed) genie: { admin: genieAdmin, agentId: existingAgentId }, // admin must share resourceStore glossary, // optional DatabricksOntologyGlossaryPublisher }); ``` Every authoring mutation is approval-gated: the `approval` callback fires per write with `effect: "write"` and is the caller's hook into the same steward approval flow that gates the authoring tools — apply never approves itself. Genie spec changes go through `DatabricksGenieAdmin.update` compare-and-swapped against the fingerprint recorded at last apply in the managed-resource store: a live fingerprint that drifted (another author's edit) surfaces the typed `DatabricksManagedResourceConflictError` — no blind overwrite, no silent retry. Updates also require the agent to be recorded as Harness-managed, exactly like the model-facing authoring tool. SQL fragments in the derived spec (measure snippets, join SQL) are admitted only through `sqlPolicy`, and apply throws before any write when the spec carries fragments but no policy was supplied. Exporter-generated metric-view and feed-table DDL is deterministic plan output; it executes through `runStatement` with approval rather than a raw fetch. On success the managed-resource store records provenance for every artifact — one record per metric view (`ontology-metric-view/`), per glossary domain (`ontology-glossary-domain/`), the Genie Agent ownership record written by `DatabricksGenieAdmin` itself, and an append-only export record keyed by the plan fingerprint (`ontology-export/`) — each carrying the exporting principal, `toolCallId`, timestamps, and the `fabric-harness.managed` tag. A changed manifest yields a new plan fingerprint and therefore a new export record; historical records are never rewritten. Re-export against an unchanged manifest produces an empty diff: when every recorded fingerprint matches the plan and the managed Genie Agent still matches live, apply performs no writes and returns `result.noChanges: true` with the per-artifact `applied: false` markers. The result also carries the applied artifacts (view names, agent id, glossary term counts, domain assignments), provenance record ids, and post-apply fingerprints. Apply is not transactional across artifacts — a conflict on a later artifact leaves earlier ones applied and recorded — but every artifact is independently idempotent, so re-running apply converges. #### Drift detection and steward attestation Genie Ontology's knowledge store *infers* expressions, synonyms, concepts, and experts; the manifest *declares* semantics. They will diverge, and the divergence is surfaced as evidence — never applied back. `compareOntologyDrift` is the pure declared-vs-inferred comparison: it takes the export plan's declared side (glossary terms and measure-seed policy classifications) plus the knowledge store's inferred concepts as plain data, and classifies every finding: | Finding kind | Severity | Meaning | | --- | --- | --- | | `inferred-synonym-vs-declared-term` | `analytics-only` (or `conflict`) | A learned synonym mapped onto a declared glossary term. | | `inferred-expression-vs-declared-measure` | `analytics-only` (or `conflict`) | A learned expression mapped onto a declared measure. | | `inferred-concept-without-declared-counterpart` | `informational` | An inference (including every learned expert) with no declared counterpart. | | `declared-definition-without-inferred-counterpart` | `informational` | A declared term or measure no inference has observed. | Severity encodes the conflict policy: the manifest is authoritative for mutation semantics, so an inference whose label collides with a *different* declared definition than its target is a `conflict` routed to steward review; a tolerated inference mapped onto its declared target is `analytics-only`; an exact restatement of the declared name is agreement and produces no finding. The comparison is deterministic — no network, no clock — and runs credential-free against plain fixtures. The knowledge-store read goes through the injected `DatabricksGenieKnowledgeStoreReader` interface (one read method returning plain data), so the preview/unsettled knowledge-store APIs (design question Q1) stay behind the caller's adapter and a preview-API change never reshapes the module. `attestOntologyDrift` wraps the comparison into the steward-surfacing path: it reads inferred concepts through the injected reader, compares, and appends exactly one attestation record per run to the caller-supplied `DatabricksOntologyDriftEvidenceSink`: ```ts import { attestOntologyDrift } from '@fabric-harness/databricks'; const record = await attestOntologyDrift(plan, { stewardAudience: 'lending-stewards', // required — routes the record to steward review knowledgeStore, // injected read-only client (design Q1 preview caveat) evidence, // append-only audit sink agentId: existingAgentId, // optional Genie Agent scope for the read }); // record.attestation — ExecutionAttestation via databricksExecutionAttestation // record.comparison — the classified findings ``` The record's attestation is built through the same `databricksExecutionAttestation` helper the Platform bridge uses, with `runId` (a content fingerprint of plan + findings + audience) as the external operation id and the steward audience in its metadata. Records are append-only audit evidence: each run appends, historical records are never rewritten. **Nothing auto-applies back** — the drift module exposes no apply path, the knowledge-store interface is read-only by construction, and the only side effect is the single evidence append. A fingerprint mismatch on the Genie side still blocks silent re-export through the existing `DatabricksManagedResourceConflictError` contract on the next `applyModuleOntologyExport`; nothing flows back into the module without a human changing governed code. Current status: the `genie-ontology-export` capability is registered at **beta** in the capability registry while Genie Ontology is in public preview. Plan, apply, and drift carry credential-free contract coverage; retained protected-workspace apply evidence is still pending and is the remaining P0 exit item. Promotion to stable follows the same rule as `genie-authoring`: retained protected-workspace evidence on non-preview APIs. ## Serving and AI Search constraints `aiSearchAdmin` takes a resource policy, not a boolean. `allowedOperations` decides which of the six tools are registered at all — an agent that only needs to sync an index never sees `databricks_delete_search_endpoint`: | Policy field | Enforcement | | --- | --- | | `allowedOperations` | Non-empty list of `createEndpoint`, `deleteEndpoint`, `createIndex`, `deleteIndex`, `syncIndex`, `describeIndex`. Only the listed tools are constructed. | | `allowedIndexes` | Exact index-name membership. Required when any registered operation names an index. | | `allowedEndpoints` | Exact endpoint-name membership. Required when any registered operation names an endpoint — `createIndex` names both dimensions. | | `allowedEmbeddingModelEndpoints` | Exact serving-endpoint membership for `embedding.modelEndpoint` on delta-sync index creation. The source column's contents are sent to this endpoint, so it is a separate dimension from the Vector Search endpoint and the two never substitute for each other. **Omitting both this and `allowAnyEmbeddingModelEndpoint` removes delta-sync creation entirely** — the branch is dropped from the tool schema and a delta-sync spec is rejected at runtime. A direct-vector-only agent therefore needs no opt-out arm; reaching for `allowAnyEmbeddingModelEndpoint` to satisfy the type would instead grant delta-sync against any embedding endpoint. | | `allowedSourceTables` | Optional exact `sourceTable` membership for delta-sync index creation. When present, names are pinned and re-checked like the other resources. When omitted, the governance catalog allowlist and the executing principal's Unity Catalog grants remain the bound. It is invalid when the embedding arm is omitted because that policy withholds the delta-sync branch entirely. | | `allowAnyIndex` / `allowAnyEndpoint` / `allowAnyEmbeddingModelEndpoint` | Per-dimension explicit opt-outs. Mutually exclusive with the matching allowlist. | | `allowAnyAiSearchAdmin` | Whole-surface explicit opt-out: all six tools, unpinned. | Names are pinned into the tool `inputSchema` (`const` for one, `enum` for several) and re-checked at call time; an out-of-policy name throws `DatabricksResourceNotAllowedError` before the Vector Search API is reached. AI Search direct-access creation requires a full schema and vector column dimension. The model-facing serving tools reject `environmentVars`; applications that deliberately need raw values must use the typed client so those values never enter model context. See the native [Serving Endpoints API](https://docs.databricks.com/api/workspace/servingendpoints), [AI Search Indexes API](https://docs.databricks.com/api/workspace/vectorsearchindexes/createindex), and [Unity Catalog Grants API](https://docs.databricks.com/api/workspace/grants/update). ## Secrets and lineage The `databricks_put_secret` input is `{ scope, key, secretRef: { kind: 'secret', name } }`. The configured `SecretProvider` resolves material during server-side execution and passes it directly to Databricks. The value never appears in model context, tool input, or lineage. The raw-value method exists only on the typed client and is an application-level trust decision. Structured governance metadata uses extended JSON Pointer paths, including `*` for arrays. Bundle initialization validates every authoring descriptor against its input schema. At execution, a required zero-match fails closed, every catalog-qualified resource is allowlist-checked, and every resource is recorded in lineage. ## Examples and failure behavior - `examples/with-databricks-jobs-authoring`: policy-bound multi-task Job lifecycle. - `examples/with-databricks-bundle-deploy`: governed checked-in Asset Bundle validate/deploy/run/destroy with fingerprint drift detection. - `examples/with-databricks-dataeng`: Lakeflow operation, authoring, and event expectations. - `examples/with-databricks-rag-admin`: AI Search endpoint/index lifecycle and query verification. - `examples/with-databricks-authoring-admin`: serving, non-destructive UC, workspace, and secret-reference writes. - `examples/with-databricks-genie-authoring`: normalized Genie Agent lifecycle with a durable Lakebase ownership manifest. - `examples/with-databricks-ontology-export`: credential-free Genie Ontology export plan, feed hydration, idempotent re-run, and PII-absence check. All examples document exact credentials and expected output in their README. Missing approval routing fails at bundle initialization. Missing warehouse/secret provider dependencies, governance descriptor errors, grant/principal mismatches, catalog denial, native Databricks authorization, timeouts, ambiguous creates, and cleanup leaks fail explicitly. ## Stability Jobs, Lakeflow, AI Search administration, non-preview custom-model serving, managed-only UC administration, workspace writes, secret-reference writes, and Genie Agent management (for its create/query/update/trash scope) are **stable** for their documented scope, backed by retained protected-workspace lifecycle evidence. Jobs evidence covers serverless STANDARD and policy-bound classic definitions; AI Search evidence covers direct-vector and Delta Sync lifecycles. Provisioned Throughput, AI Gateway administration, Agent Mode streaming, and Databricks App OBO authentication retain their separate Databricks preview constraints. The full release gate, destructive certification lifecycle, and retained evidence are documented in [Authoring certification and release evidence](/docs/databricks/authoring-certification). ## Upgrade note Approvals persisted before grant provenance existed cannot authorize a post-upgrade tool call. An idempotent session detects the missing grant and requests approval again under a new provenance id. This is intentionally fail-closed; operators may see one new approval after upgrading a durable session. Pair compute limits with `databricksTenantCostLimit()` and System Tables reconciliation when authoring Jobs or serving resources. Compute lifecycle outside governed Jobs remains deferred until budget guardrails can be enforced server-side. --- # Databricks compute patterns Canonical: https://harness.techfabric.com/docs/databricks/compute Choose SQL Warehouses, Lakeflow Jobs and notebooks, Databricks Apps, or an isolated sandbox without conflating their execution models. Databricks offers several execution surfaces. TechFabric Harness keeps them explicit so policy, identity, idempotency, and output handling match the workload. ```mermaid flowchart TD Q{What must execute?} Q -->|Governed SQL| SQL[SQL Warehouse] Q -->|Existing workflow| JOB[Lakeflow Job] Q -->|One-off notebook| NB[Notebook task] Q -->|Fabric HTTP runtime| APP[Databricks App] Q -->|General shell or untrusted code| SB[External isolated sandbox] SQL --> UC[Unity Catalog permissions and lineage] JOB --> VOL[Logs and output envelope in UC Volumes] NB --> VOL APP --> LB[Lakebase durable state] SB --> NET[Container, cluster, or provider egress boundary] classDef decision fill:#fff4d6,stroke:#d97706,color:#451a03 classDef compute fill:#e8f0fe,stroke:#2563eb,color:#172554 classDef governed fill:#dcfce7,stroke:#16a34a,color:#052e16 class Q decision class SQL,JOB,NB,APP,SB compute class UC,VOL,LB,NET governed ``` | Workload | Fabric API | Durable result | Policy effect | | --- | --- | --- | --- | | SQL statement | `databricksSqlReadTool()`, policy-bound `databricksSqlTool()`, or `databricksSqlSandbox()` | Statement id/result | Read-only by default; bind and gate broader execution | | Existing Job | `databricksJobs().runJob()` | Typed run receipt and state | `execute`; bounded by `runPolicy.allowedJobIds`; use delivery id as idempotency token | | Notebook | `databricksJobs().submitNotebook()` | Typed run receipt and task output | `execute`; bounded by `notebookPolicy`; gate data mutations | | Agent hosting | `fh build --target databricks-app` | Lakebase session/submission stream | HTTP runtime, not a shell | | General code | Docker, Kubernetes, E2B, Daytona, Modal, or another sandbox | Provider-specific snapshot/ref | Enforce filesystem, process, and network boundaries | ## Run and monitor a Job ```ts import { databricksJobs, databricksSdk } from '@fabric-harness/databricks'; const sdk = databricksSdk({ host: process.env.DATABRICKS_HOST!, principal: { kind: 'pat', token: process.env.DATABRICKS_TOKEN! }, }); const jobId = Number(process.env.DATABRICKS_JOB_ID); const jobs = databricksJobs(sdk.jobs, { runPolicy: { allowedJobIds: [jobId] }, notebookPolicy: { allowedNotebookPathPrefixes: ['/Workspace/Shared/fabric'] }, }); const receipt = await jobs.runJob({ jobId, idempotencyToken: submission.id, notebookParams: { customer: tenant.id }, }); const state = await jobs.wait(receipt.runId, { timeoutMs: 15 * 60_000, signal: abortController.signal, }); if (state.resultState !== 'SUCCESS') { throw new Error(`Job ${receipt.runId} ended in ${state.resultState}`); } ``` The caller-supplied idempotency token survives HTTP retries and upstream message redelivery. Calling `cancel(runId)` is safe to retry. `wait()` returns typed lifecycle/result state and throws `DatabricksRunTimeoutError` rather than returning an ambiguous running result after its deadline. ## Bound what a model can run Every model-callable execute/write factory takes a **required** resource policy. There is no unbounded default: omitting it is a compile error, runtime checks run before the Databricks API, and opting out uses a deliberate, greppable `allowAny...: true` arm. ```ts import { databricksNotebookTool, databricksRunJobTool } from '@fabric-harness/databricks'; const tools = [ databricksRunJobTool(sdk.jobs, { allowedJobIds: [Number(process.env.DATABRICKS_JOB_ID)] }), databricksNotebookTool(sdk.jobs, { allowedNotebookPathPrefixes: ['/Workspace/Shared/fabric'], }), ]; ``` ```ts const sql = databricksSqlTool( sdk.statements, { allowedStatements: ['CALL main.ops.refresh_daily()'] }, { warehouseId }, ); const ai = databricksAiQueryTool( sdk.statements, { allowedEndpoints: ['support-classifier'] }, { warehouseId }, ); const pipeline = databricksPipelineStartTool(sdk.pipelines, { allowedPipelineIds: [pipelineId], }); const metric = databricksMlflowLogMetricTool(sdk.experiments, { allowedRunIds: [runId], }); ``` Pinned input schemas guide the model, but runtime enforcement is the security boundary. An out-of-policy SQL statement, endpoint, pipeline id, or MLflow run id never reaches the generated client. The Jobs and notebook model tools use the Harness tool-call id as their default Databricks idempotency token. Harness guarantees that id is unique per logical call even when a model provider omits an id, while preserving it across the call's approval, lineage, execution, and result records. Typed `databricksJobs()` callers should continue to supply a stable delivery or submission id when they need retry coalescing across process boundaries. | Policy field | Enforcement | | --- | --- | | `runPolicy.allowedJobIds` | Exact numeric membership. A non-empty array of non-negative integers, checked at construction. | | `runPolicy.allowAnyJobId` | Explicit opt-out. Mutually exclusive with `allowedJobIds`. | | `notebookPolicy.allowedNotebookPaths` | Exact workspace path membership. | | `notebookPolicy.allowedNotebookPathPrefixes` | Subtree match on segment boundaries only, so `/Workspace/prod` admits `/Workspace/prod/ingest` and rejects `/Workspace/production-evil`. | | `notebookPolicy.allowAnyNotebookPath` | Explicit opt-out. Mutually exclusive with both allowlists. | Enforcement lives in `databricksJobs()`, **before** `run-now` or `runs/submit` is called: an out-of-policy target throws `DatabricksRunNotAllowedError` and never reaches the workspace. Any `notebookPath` containing a `..` segment is rejected while a policy is configured. The tool's `inputSchema` is also pinned (`const` for one id, `enum` for several) — that is a model-facing hint, not the boundary; the runtime check is. The boundary is **job ids, not job names**. The run client is deliberately narrow (`runNow`, `submitRun`, `getRun`, `cancelRun`, `getRunOutput`) and cannot resolve names, and resolving a name at call time would be a time-of-check/time-of-use hole. Resolve names to ids yourself at configuration time; a helper built on the authoring client may return `number[]` in a future release. Note that `computePolicy` does **not** bound this path. It applies to Jobs authoring and one-off compute specs, not to triggering an existing job. ## Submit a notebook ```ts const receipt = await jobs.submitNotebook({ notebookPath: '/Workspace/Shared/fabric/daily-report', existingClusterId: process.env.DATABRICKS_CLUSTER_ID!, idempotencyToken: submission.id, baseParameters: { report_date: '2026-07-09' }, }); ``` Submission is bounded the same way as `runJob`: the `jobs` client above already carries a `notebookPolicy`, so an out-of-policy `notebookPath` throws `DatabricksRunNotAllowedError` before `runs/submit` is called. Notebook submission is asynchronous Jobs compute. It does not turn the SQL sandbox into a shell and does not execute TypeScript inside Model Serving. ## Persist logs and outputs in a UC Volume ```ts import { UcVolumesAttachmentStore } from '@fabric-harness/databricks'; const store = new UcVolumesAttachmentStore({ client: sdk.files, catalog: 'main', schema: 'agents', volume: 'fabric_attachments', rootPrefix: 'job-output', }); const ref = await jobs.exportOutput(receipt.runId, store, `submission:${submission.id}`); ``` For multi-task Jobs, `getOutputs()` retrieves each task run output. `exportOutput()` stores one content-addressed JSON envelope with notebook result, driver logs, truncation state, errors, and raw metadata. Unity Catalog controls access to the Volume. The [runnable compute example](/docs/reference/source-access) uses a deterministic mock by default and switches to a real workspace when credentials are present. --- # Databricks connectors and sandboxes Canonical: https://harness.techfabric.com/docs/databricks/sandboxes-connectors Choose between the Databricks SQL sandbox, Unity Catalog Volume connectors, workspace sources, attachment storage, and general-purpose compute sandboxes. Databricks appears in both the sandbox and connector layers, but those layers solve different problems. Select them by capability rather than by provider name. ```mermaid flowchart TD NEED{What must the agent do?} NEED -->|Run governed SQL| SQL[Databricks SQL sandbox or SQL tool] NEED -->|Read or write governed files| VOL[Unity Catalog Volume connector] NEED -->|Read workspace source files| WS[Workspace Files source] NEED -->|Persist user attachments| ATT[UC Volumes attachment store] NEED -->|Run bash, packages, or arbitrary code| GEN[Docker or remote code sandbox] SQL --> WH[SQL Warehouse] VOL --> FILES[Files API] WS --> WAPI[Workspace API] ATT --> FILES GEN --> DATA[Call Databricks tools over governed APIs] classDef question fill:#fef3c7,stroke:#d97706,color:#422006 classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef dbx fill:#dcfce7,stroke:#16a34a,color:#052e16 class NEED question class SQL,VOL,WS,ATT,GEN fabric class WH,FILES,WAPI,DATA dbx ``` ## SQL sandbox `databricksSqlSandbox()` adapts `session.shell(sql)` to SQL Statement Execution on a SQL Warehouse. It returns JSONL or CSV in `stdout`. Its small filesystem is in-memory session storage; it is not DBFS, a Volume, a cluster driver, or an operating-system shell. ```ts import { databricksSqlSandbox } from '@fabric-harness/databricks/sql-sandbox'; import { init } from '@fabric-harness/sdk'; const runtime = await init({ sandbox: databricksSqlSandbox({ host: process.env.DATABRICKS_HOST!, principal: { kind: 'on-behalf-of', userToken: () => workspaceIdentity() }, warehouseId: process.env.DATABRICKS_WAREHOUSE_ID!, catalog: 'main', schema: 'analytics', resultFormat: 'jsonl', }), }); const session = await runtime.session(); const result = await session.shell(` SELECT region, sum(net_revenue) AS revenue FROM orders GROUP BY region ORDER BY revenue DESC `); ``` The SDK backend name is also usable after registering the Databricks provider adapter: ```ts import { registerDatabricksSqlSandboxBackend } from '@fabric-harness/databricks'; import { init } from '@fabric-harness/sdk'; registerDatabricksSqlSandboxBackend(); const runtime = await init({ sandbox: 'databricks' }); ``` The factory reads host, Warehouse, and identity from the sandbox creation environment. A portable `databricks-sql` ref stores only host, Warehouse, catalog, schema, result format, and timeout; PAT, OAuth secret, OBO token, generated SDK client, and token provider are deliberately excluded. Attach resolves credentials again in the receiving process, so a rotated credential can be used without rewriting the ref. Missing host, Warehouse, or attach-time identity fails closed. Use `databricksSqlReadTool()` for model-facing analytics reads. It advertises a `read` effect and fails locally unless input is one `SELECT` (a SELECT-ending CTE is accepted); mutations, administration keywords, malformed SQL, and multiple statements never reach Statement Execution. ```ts import { analyticsCopilotGovernance, databricksSdk, databricksSqlReadTool, } from '@fabric-harness/databricks'; const sdk = databricksSdk({ host, principal }); const sqlRead = databricksSqlReadTool(sdk.statements, { warehouseId: process.env.DATABRICKS_WAREHOUSE_ID!, }); const governance = analyticsCopilotGovernance({ stewardAudience: 'analytics-stewards', catalogs: ['main'], }); ``` The analytics-copilot pack scopes approval routing to the SQL and Genie services. `sql_read` and ordinary `databricks_genie_ask` calls are reads and stay interactive; policy-bound `databricksSqlTool()` execution and Genie lifecycle writes still route to the steward audience. Enabling a different authoring service fails bundle initialization until approval routing covers it. This Harness check is defense in depth: Unity Catalog privileges under the acting service principal or OBO user remain authoritative. Use `databricksSqlTool(client, executionPolicy, options)` only when the model deliberately needs more than SELECT-only access. Bind exact statements or supply a server-side validator; the `allowAnyStatement: true` arm is an explicit advanced opt-out. Approval routing remains a separate defense-in-depth layer. The sandbox is useful when the session's shell abstraction should itself mean SQL. See the runnable [`with-analytics-copilot`](/docs/reference/source-access) example for service-principal and OBO authentication, expected output, and failure behavior. ## Unity Catalog Volume connector The connector uses the Databricks Files API and keeps all paths under a configured `/Volumes///` root. ```ts import { databricksVolumeSource } from '@fabric-harness/connectors/databricks-volume'; const source = databricksVolumeSource({ host: process.env.DATABRICKS_HOST!, token: async () => workspaceIdentity(), volumePath: '/Volumes/main/support/knowledge', include: (path) => path.endsWith('.md') || path.endsWith('.pdf'), }); await session.mount('/knowledge', source); ``` `databricksVolumeWriter()` provides scoped `put()` and `delete()` operations. Use `UcVolumesAttachmentStore` when attachments must participate in Fabric's attachment lifecycle. The acting principal still needs the relevant `USE CATALOG`, `USE SCHEMA`, and Volume privileges. ## General-purpose code execution For Python, package installation, bash, repository mutation, or untrusted code, use a code sandbox such as Docker, Kubernetes, E2B, Daytona, Modal, or another remote backend. Give that sandbox Databricks tools or scoped OAuth access as needed. This preserves the common sandbox interface without pretending a SQL Warehouse is a machine shell. See the focused [Databricks SQL sandbox reference](/docs/ecosystem/sandboxes/databricks-sql) and the [sandbox matrix](/docs/reference/sandboxes-matrix). --- # Enterprise Databricks controls Canonical: https://harness.techfabric.com/docs/databricks/enterprise Identity propagation, Unity Catalog enforcement, approvals, audit lineage, durable state, cost controls, secret handling, and deployment hardening. TechFabric Harness adds runtime controls around Databricks calls. Those controls are defense in depth: Unity Catalog and Databricks resource permissions remain authoritative. ## Identity modes | Mode | Use | Fabric API | | --- | --- | --- | | App service principal | Databricks Apps and unattended production workloads | `appServicePrincipalFromEnv()` | | OAuth M2M | External services acting as one application | `databricksIdentity({ kind: 'service-principal' })` | | On-behalf-of user | Preserve the signed-in user's grants | `onBehalfOfFromHeaders()` | | Personal access token | Local development or controlled single-user testing | `kind: 'pat'` | Token providers are resolved at call time and refresh before expiry. Identity labels, not tokens, are placed in actors, submissions, lineage, and cost records. For Databricks Apps ingress, use `databricksAppsOidcAuthenticator()` as the Node server `authenticate` hook. It validates workspace JWT signatures, issuer, audience, expiry, and signing-key rotation before mapping the forwarded user email to both the Fabric actor and Unity Catalog principal. See [Authentication and RBAC](/docs/operating/auth#databricks-apps). When Databricks Apps forwards an OBO access token instead of an OIDC identity token, use the narrow Apps authorization entrypoint. It validates the token against the workspace current-user API, returns only safe identity and lifetime metadata, assigns an opaque tenant per user, and caches by a token digest bounded by token expiry: ```ts import { createDatabricksAppUserAuthenticator } from '@fabric-harness/databricks/app-user-authorization'; import { startDevServer } from '@fabric-harness/node'; const authenticate = createDatabricksAppUserAuthenticator({ host: process.env.DATABRICKS_HOST!, }); await startDevServer({ authenticate }); ``` Missing forwarded authorization falls through so another configured authenticator may run. Invalid or unauthorized forwarded tokens fail closed. The raw token is never returned, logged, or used as a cache key. Applications that need authenticated user identity but do not pass an OBO token to downstream Databricks APIs can opt into `trustForwardedUserIdentity`. It maps the integrity-protected `x-forwarded-user`, `x-forwarded-email`, and `x-forwarded-preferred-username` ingress headers to a natural-person principal. Generated Databricks App bundles enable this trust mode because they are reachable only through Apps ingress; a forwarded email or preferred username is required so an M2M caller with only `x-forwarded-user` is not reclassified as a person. `trustForwardedUserIdentity`, `trustForwardedServicePrincipal`, `appPrincipalId`, and `appAuthorizedCallerIds` are explicit ingress-trust controls; enable them only when the server is exclusively reachable through Databricks Apps. See the runnable `examples/with-databricks-simple/app-auth.ts` path for deterministic output and failure behavior. ## Enforcement flow ```mermaid flowchart LR R[Tool request] --> A[Definition and invocation policy] A --> E{Allowed?} E -->|No| DENY[Reject and audit] E -->|Yes| H{Approval required?} H -->|Yes| WAIT[Durable approval wait] WAIT --> DEC{Decision} DEC -->|Deny or expire| DENY DEC -->|Approve| CALL[Call Databricks] H -->|No| CALL CALL --> UC[Unity Catalog and resource ACLs] UC -->|Denied| DENY UC -->|Allowed| RESULT[Redacted result] RESULT --> LINEAGE[Lineage, telemetry, and cost] classDef decision fill:#fef3c7,stroke:#d97706,color:#422006 classDef allow fill:#dcfce7,stroke:#16a34a,color:#052e16 classDef deny fill:#fee2e2,stroke:#dc2626,color:#450a0a class E,H,DEC decision class CALL,UC,RESULT,LINEAGE allow class DENY deny ``` ## Controls to configure 1. Use a least-privilege service principal or a user OBO token for each request. 2. Restrict outbound network policy to the workspace host and any explicitly required services. 3. Add catalog allowlists as defense in depth; do not treat them as a substitute for UC grants. 4. Route write and execute tools to a data-steward approval audience. 5. Persist sessions, submissions, and streams in Lakebase for restart recovery. 6. Send governed tool lineage to an audit sink, MLflow, OpenTelemetry, or Lakebase telemetry tables. 7. Apply estimated and actual-cost tenant budgets, then reconcile against system-table usage. 8. Keep secrets in Databricks App resources, environment-backed secret references, or an external secret manager. Never put credentials in prompts, tool inputs, or lineage labels. 9. Build with provenance and SBOM output, inspect the v2 manifest, and require an API token on production artifact routes. ## Lakebase credential exchange `lakebaseClient()` does not use a workspace OAuth token as the Postgres password. It exchanges the workspace token for a database credential using the endpoint resource name, refreshes that credential early with jitter, single-flights concurrent refreshes, and supplies it to the connection pool. ```ts const app = databricksApp(); const server = await startDevServer({ host: '0.0.0.0', port: Number(process.env.DATABRICKS_APP_PORT ?? 8080), ...(await app.serverOptions()), }); ``` `serverOptions()` injects the Lakebase session, submission, and conversation-stream stores into the shared Node server. See [Lakebase](/docs/ecosystem/databases/lakebase) for configuration. ### Schema ownership in automated deployments A production deployment usually has two database principals: - the **release principal** used by CI to deploy resources and apply schema changes; - the **App principal** used by the running Databricks App to read and write durable state. Keep one release principal as the stable owner of the Harness tables. Apply new migrations with that principal before rolling out an App version, then grant the App principal only the DML and sequence permissions it needs. Do not transfer table ownership to every new deployment identity. ```sql -- Run as the stable schema owner. Quote UUID-shaped service-principal names. GRANT USAGE ON SCHEMA public TO ""; GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE fh_submission_telemetry, fh_lineage TO ""; GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO ""; ``` At startup, Fabric resolves existing telemetry tables through PostgreSQL's relation catalog. This is important because the App principal's first `search_path` schema can differ from the schema that owns the shared tables. Fabric skips owner-only `ALTER TABLE` and `CREATE INDEX` statements when the resolved objects already exist. If a required object is genuinely absent, migration still fails rather than pretending the schema is current. Submission telemetry sinks are failure-isolated: an MLflow or Lakebase observer error is logged but cannot terminate the App process or change an agent result. Treat missing telemetry as an operations failure anyway. The protected certification gate must prove that lifecycle events and lineage rows were actually written before promoting the release. --- # Workspace compatibility Canonical: https://harness.techfabric.com/docs/databricks/compatibility Evidence-based Databricks cloud, region, authentication, API, App, Lakebase, and runtime compatibility. TechFabric Harness targets Databricks workspaces on AWS, Azure, and Google Cloud through the official modular TypeScript SDK for stable services. Availability of Apps, Lakebase, serverless Model Serving, private connectivity, and individual AI services varies by workspace, region, and account configuration. A successful check in one workspace is recorded only for that cloud and region. ## Runtime and API contract Every generated client is exact-pinned to the same reviewed [Databricks modular JavaScript SDK](https://docs.databricks.com/aws/en/dev-tools/sdk-javascript) release. Fabric does not mix modular SDK versions. | Surface | Transport owner | Databricks API contract | | --- | --- | --- | | Jobs | `@databricks/sdk-jobs` `0.21.0` | Jobs 2.2 | | Lakeflow Declarative Pipelines | `@databricks/sdk-pipelines` `0.21.0` | Pipelines 2.0 | | SQL Statement Execution | `@databricks/sdk-statementexecution` `0.21.0` | Statement Execution 2.0 | | AI Search | `@databricks/sdk-vectorsearch` `0.21.0` | Vector Search 2.0 | | Model Serving and query | `@databricks/sdk-modelserving` and `@databricks/sdk-modelservingquery` `0.21.0` | Serving 2.0 | | Genie stable lifecycle and conversations | `@databricks/sdk-genie` `0.21.0` | Genie 2.0 | | Workspace object permissions, including Genie ACLs | `@databricks/sdk-accessmanagement` `0.21.0` | Permissions 2.0 | | Unity Catalog catalogs, schemas, tables, volumes, and grants | `@databricks/sdk-uc-*` `0.21.0` | Unity Catalog 2.1 | | Workspace files and volumes | `@databricks/sdk-files` and `@databricks/sdk-uc-volumes` `0.21.0` | Files 2.0 / Unity Catalog 2.1 | | Workspace secrets | `@databricks/sdk-secrets` `0.21.0` | Secrets 2.0 | | Workspace identity | `@databricks/sdk-scim` `0.21.0` | SCIM 2.0 preview path | | MLflow experiments | `@databricks/sdk-experiments` `0.21.0` | MLflow 2.0 | | Lakebase | `@databricks/sdk-postgres` `0.21.0` | Postgres/Lakebase generated contract plus credential exchange 2.0 | | Databricks Apps | Databricks CLI project deployment and Apps runtime contract | Apps 2.0 | | Internal SDK-gap protocols | Private deny-by-default Fabric adapter | Agent Services 2.1 Beta, Genie Agent Mode Beta, Workspace object import/export 2.0, MLflow Traces 3.0, AI Gateway v2, ResponsesAgent custom schema, and exact Genie/AI Search decoder fallbacks | | Application native escape hatch | `databricksWorkspaceApi()` | Any workspace-relative `/api/*` or `/serving-endpoints/*` API under the configured identity | | Runtime | Supported version | | --- | --- | | MLflow ResponsesAgent | `>=3.10`; protected Azure gate currently exercises `3.14.0` | | Node.js | `>=22.0.0` | | `@fabric-harness/databricks` | `>=7.0.0 <8` | | `pg` for Lakebase | `^8.11.0` | `DATABRICKS_SDK_VERSION` is read from the installed official SDK. `DATABRICKS_API_VERSIONS` uses that same value in certification evidence, and a release test requires every `@databricks/sdk-*` dependency, this page, and the package README to agree. `DATABRICKS_AUTH_MODES` and `DATABRICKS_PACKAGE_COMPATIBILITY` keep authentication and runtime checks on the same contract. ## Authentication modes | Mode | Use | | --- | --- | | OAuth M2M | External services and protected CI service principals | | App service principal | Runtime identity injected into a Databricks App | | On-behalf-of | Per-user Unity Catalog grant enforcement from an App request | | PAT | Developer smoke tests and transitional automation | Production deployments should use OAuth or App identity. The official SDK credential chain resolves CLI profiles and OAuth M2M credentials. Tokens remain in credential providers and request headers; they are not written to prompts, lineage, compatibility records, or certification errors. ## Native SDK boundary Generated clients own stable request/response serialization for Jobs, Statement Execution, Lakeflow, Vector Search, Model Serving, Files, Secrets, Genie, Access Management, Unity Catalog, MLflow Experiments, and Lakebase. TechFabric Harness adds agent-specific approval binding, structured resource policy, lineage, managed-resource ownership, bounded retries, and durable cleanup. Fabric's raw protocol transport is private to protocols not represented by the modular SDK: Agent Services, Genie Agent Mode streaming, Workspace object import/export, MLflow 3 traces, AI Gateway/model-service discovery, and the ResponsesAgent custom request schema. It has an exhaustive method-and-path allowlist; an unlisted route is rejected before credentials are resolved or network I/O begins. Callers receive typed capabilities through the Databricks bundle and never construct the raw transport. SCIM identity, authoring certification verification, and all other stable services use generated clients. Source-boundary and runtime-denial tests prevent stable modules from silently adding raw API paths. The exact SDK pin, generated serialization tests, packaged-runtime import test, and protected workspace lifecycle checks all gate a release. Generated types reduce wire drift; they do not replace live behavioral certification. Application code is not limited to the services with a generated client or a Harness adapter. `databricksWorkspaceApi()` is the public, credential-safe native REST escape hatch. It preserves arbitrary JSON or raw request bodies, raw responses, cancellation, rotating identity, credential redaction, and safe retry defaults. It is not automatically model-callable and does not weaken the private allowlist used by Harness's own SDK-compatibility protocols. See [native access and platform coverage](/docs/databricks/native-access). ## Multidimensional coverage The package capability registry separates: - Databricks upstream maturity; - native API fidelity; - lifecycle operations; - runtime certification; - identity modes; - contract clouds versus clouds with retained live evidence; and - known gaps. `DATABRICKS_PLATFORM_DOMAINS` includes unsupported product families as well as implemented ones. An absent first-party adapter therefore cannot be mistaken for an absent Databricks capability. Use the generated SDK or `databricksWorkspaceApi()` while a higher-level governed adapter is missing. There are two narrowly tested SDK 0.21 compatibility exceptions. Its generated Genie query-result decoder expects object rows while the live API returns array rows. Its shared JSON decoder also tries to convert a valid floating-point AI Search score to `BigInt`. Fabric retries only those two read-only responses through the quarantined raw protocol transport when each exact decoder failure is detected; other errors fail closed. Remove each fallback as soon as the pinned SDK accepts the live payload. ## Certification records The protected live workflow emits schema-versioned, redacted evidence containing: - cloud, region, workspace id/host, auth mode, and principal kind; - Node and package versions plus every REST API family used; - required and optional check identifiers with duration and result; - source commit plus SHA-256 digests of the exact npm candidate and App artifact; - App restart/cascade-deletion evidence and deployment conformance; - a stable evidence id suitable for partner review. Tier R release checks cannot become `not-configured`: that result makes certification fail. A Tier O failure remains visible in the evidence but does not block a Tier R release. An environment-specific required-check list can add checks but cannot remove Tier R. Tier A covers the protected Jobs/Lakeflow/AI Search/serving/UC/workspace/secrets/Genie authoring lifecycles; Tier O covers previews and SKU-specific paths unless a workflow explicitly promotes one. Authoring certification uses a reverse-order cleanup ledger and fails when any created resource leaks. See the [Databricks certification page](/docs/databricks/live-certification) for the current public status, scope, limitations, and machine-readable record. The runner executes required checks before configured optional checks while preserving declaration order in the emitted evidence. This keeps short-lived OBO credentials and on-demand App health from expiring while a long MLflow evaluation or other Tier O probe runs; optional checks still execute and remain visible in the same record. ```bash node packages/databricks/dist/certify.js node scripts/build-databricks-compatibility-matrix.mjs \ artifacts/databricks-certification.json ``` `databricksCompatibilityRecord()` accepts only passing evidence with cloud, region, auth, runtime, package, and artifact identity. The matrix labels a cloud/region `live-certified` only when such a record is retained; otherwise it remains a contract target requiring workspace certification. ### Current `7.1.1` protected evidence Package `7.1.1` is published on npm and passed its exact-version protected gate in [GitHub Actions run 33909857317](/docs/reference/source-access) from commit `bc56fa834a26e882953e4824796bd780a5b4efdb`. Evidence `dbx-cert-ca5de23e2502326192565582e6844c5ee423d0bcaf9d3ada19c96a608ae9743b` records all 21 Tier R checks as passed in Azure `eastus2` under OAuth M2M. Seven configured Tier O checks passed; two Tier O probes failed and are recorded below without blocking the release tier. Tier R covered identity, AI Gateway, Model Serving, SQL, Unity Catalog allow/deny, catalog preflight denial, governed mutation approval, RAG, Genie, managed MCP under OBO, Volumes, Lakebase, lineage, System Tables, actual-cost reconciliation, App health, and Lakebase-backed restart recovery with cascade deletion. The required hook-authored dynamic-agent check also preserved its persistent state across that restart. The generated App passed a 25-request burst test with no failures or duplicate run IDs and enforced its rate limit. This run executed in single-user workspace mode: the two-user isolation checks were skipped rather than passed, so the record makes no claim about cross-user or cross-tenant protection and carries no user-isolation evidence digest. Multi-user production deployments should treat that isolation as uncovered until a two-identity run retains passing evidence. Configured Tier O probes passed for ResponsesAgent, managed RAG evaluation, AI Search, Genie Agent Mode, Jobs, Lakeflow, and a classic notebook. Unity Catalog Agent Services registration was rejected by the workspace API, and Feature Serving did not resolve its configured records; this record establishes nothing for those two surfaces. The exact packed candidate digest is `e6ed0ce22a6d8805e935a78e2310cba3bd7f82a357bc25fa679685ed7331b70e`. The certified App directory digest is `0ec00f14ab57f1c9e73e633824d25a3beaac8f54f8a06f6db2fddca86024ea38`. The bound restart-evidence digest is `d67f9ab298c671df879815a19a6d8d9fd0c259112d7490c8b865dbafbd09d69b`. The retained `7.1.1` compatibility matrix labels Azure `live-certified` and AWS/GCP `requires-workspace-certification`. The exact tarball also passed the focused same-commit Tier A gate in [run 33915517941](/docs/reference/source-access). Evidence `dbx-cert-abd5c9a21d0fe784a8ca44572a0d4955ee18494ce677d90fe9af1fe849abb722` records all ten required authoring checks as passed. Every destructive lifecycle ended with `cleanupRequired: false`, both sweepers found no retained resources, and the cross-tier manifest matched package version, commit, and tarball digest byte-for-byte. The Tier A record does not establish classic compute, Delta Sync, provisioned throughput, or Genie Agent Mode authoring. With no passing two-user probe in the current run, the separate 14-day rolling isolation claim also remains unestablished. This Azure `eastus2` record does not imply AWS, GCP, or another Azure region. ### Prior `7.0.2` protected evidence Package `7.0.2` passed its exact-version protected gate in [run 31053240003](/docs/reference/source-access) from commit `544cd478d29b26ed7090499c682af0922f4533d1`. Evidence `dbx-cert-40f9f87ecd2044f529d37e4dcbc260e55707cda9df5c987790078f35df29850a` records all 21 Tier R checks and nine configured Tier O checks as passed in Azure `eastus2`, including current-run two-user isolation. Its package digest is `edf67563b0bf0daa211ada78c5a3996063a39befa464fa2df27ba04e102cb59c`, its App directory digest is `04f852085e16f6b1a5d04b81e6c7160970282bf03091c7cf249410e56a364e74`, and its same-package Tier A evidence is retained by [run 31056050505](/docs/reference/source-access) as `dbx-cert-37f20b775f8f1e676f6b7d36bb17bb61f1ae9c593e560e028d1872764d70693d`. ### Prior `5.0.1` protected evidence Package `5.0.1` passed its exact-version protected gate in [run 30501444655](/docs/reference/source-access) from commit `067694748e1326b3ef039f19c91486ded15b6f70`. Evidence `dbx-cert-6826f4cc09501d1c112281248c0307589d922ae0fa21adc1c894c929bbf75613` records the same 20 required Tier R checks and nine configured Tier O checks as passed in Azure `eastus2`, including current-run two-user isolation. Its package digest is `ee1eaac3c3e11ff6eaf1918023946d95381facab6107e6b81f7115a3a6660fd8`, its App directory digest is `2110a13af799b63c5f9047f1959254802419c82143a9eaec7f49c83b794bf808`, and it did not carry same-package Tier A evidence. ### Prior `4.9.2` protected evidence Package `4.9.2` is published on npm and passed its exact-version protected gate in [GitHub Actions run 29812986146](/docs/reference/source-access) from commit `50996433b34cdedb6d2732949dedfe6a918cdd48`. Evidence `dbx-cert-89ee6c419eda616be6cbffbcd42b842ed5a0f37d85683510c49c801f7911555b` records all 20 Tier R checks as passed in Azure `eastus2` under OAuth M2M, including: - identity, Unity AI Gateway, Model Serving, live RAG, and governed mutation approval; - SQL plus Unity Catalog allow/deny and catalog preflight denial; - ordinary Genie consumption, managed Genie MCP under OBO, and an OBO grant differential; - Volumes, Lakebase, lineage, System Tables, and actual-cost reconciliation; and - Databricks App health plus Lakebase-backed stop/start recovery and cascade deletion. The exact packed candidate digest is `91fb6cd09f2d631b47b6827b4eda535b7c405562fa9f5ed659c66a1c0f5f7258`. The certified App directory digest is `828d6ba0309b72430a6e2c024086815c28a762fd8b2adec1ba43100e7bb1c247`, and the bound restart-evidence digest is `d5ace515506f18043c48039716cd8c8c5f4d98dd0b11437bebe6f5d49aa49d1a`. The workflow retained the post-certification App archive, package candidate, recovery record, compatibility matrix, and passing Databricks App black-box conformance report together. ResponsesAgent, managed RAG evaluation, AI Search, Feature Serving, Jobs, Lakeflow, and a classic notebook also passed as visible Tier O checks. Agent Services returned "feature is not available" and Genie Agent Mode returned `FEATURE_DISABLED`; both remain optional previews and are not implied by the release claim. This record is retained as historical `4.9.2` evidence. The capability registry embedded in the published package remains pinned to the `4.9.1` evidence available when that artifact was built; Jobs 2.2 consumption is stable, while ResponsesAgent stays Beta because the upstream surface is Beta. This record proves one OBO user-versus-App grant differential, not two-user App isolation: `DATABRICKS_OBO_TOKEN_B` was not configured for this dispatch. It also does not imply AWS, GCP or another Azure region. Current-package Tier A evidence is recorded separately below because its short-lived U2M/OBO identity runs in the dedicated authoring workflow. ### Prior `4.3.x` status Packages through `4.3.2` are published, but no passing exact-package Tier R record for that line is retained in this repository. Do not describe the 4.3.x line as live-certified. ### Prior `4.2.0` recertification status Package `4.2.0` adds deterministic artifact digesting, programmatic Bundle validation and App deployment, and a narrow Databricks Apps user-authorization entrypoint. Its build, package, documentation, SDK-boundary, and local contract gates pass, but it does not yet have a passing exact-package protected workspace record. Do not describe `4.2.0` as live-certified until the Tier R consumption workflow is rerun with valid OBO and Feature Serving fixtures. ### Prior `4.1.1` recertification record Package `4.1.1` is published and its build, package, documentation, SDK-boundary, and local contract gates passed. The exact-package Azure `eastus2` consumption run [`29689767139`](/docs/reference/source-access) recorded 23 passing checks, including the Databricks App, Lakebase restart path, AI Search/RAG, Genie, SQL and UC, Volumes, lineage, system tables, and cost reconciliation. It is **not** a passing release certification record: the short-lived OBO fixture token was rejected as invalid, and the workflow's explicitly promoted Feature Serving fixture returned `404`. Agent Mode also reported the workspace preview as disabled, but remained non-blocking Tier O evidence. Do not substitute that partial run for a passing `4.1.1` record. Rotate the OBO fixture, repair or remove the promoted Feature Serving fixture, rerun Tier R, and link the resulting evidence before describing `4.1.1` as live-certified. The older records below remain valid only for their exact package, artifact, cloud, region, and capability set. The current retained consumption record is the `7.1.1` Tier R evidence in [run 33909857317](/docs/reference/source-access): all 21 required checks passed against the exact published tarball and commit `bc56fa834a26e882953e4824796bd780a5b4efdb`. The same package's management evidence is retained by [run 33915517941](/docs/reference/source-access) as `dbx-cert-abd5c9a21d0fe784a8ca44572a0d4955ee18494ce677d90fe9af1fe849abb722`: all ten required identity, approval, serverless Jobs, Lakeflow, direct-vector AI Search, custom-model Serving, UC OBO, Workspace, secret-reference, and Genie authoring checks passed. Every destructive lifecycle ended with `cleanupRequired: false`, both resource sweeps were empty, and the retained tarball digest `e6ed0ce22a6d8805e935a78e2310cba3bd7f82a357bc25fa679685ed7331b70e` matched independently across the Tier R and Tier A records. The `4.0.2` records remain useful historical and second-region authoring evidence: - `dbx-cert-b2c709717ef3a452234a5b2944311a576dafda03a9eea8246747ab3fa430b183` from [run 29660486290](/docs/reference/source-access) covers OBO execution in `eastus2`, serverless Jobs, Lakeflow, direct-vector and Delta Sync AI Search, custom-model serving, managed-only UC schema/grants, Workspace objects, secret references, and Genie Agent create/query/update/ACL-read/trash. - `dbx-cert-d5bdbd276533a8634910e223898337314446561be2a444030fc2d11baa237bec` from [run 29660486237](/docs/reference/source-access) covers a policy-bound classic `new_cluster` Jobs definition lifecycle in Azure `westus3`. Both records use artifact digest `72f602626b9d79a808f6dd9e30f6ba703061bda19bae2aef983e7e92d7c61a45`; every required check passed, all destructive lifecycles completed their six phases, and the pre/post sweeps found no retained resources. Neither record implies AWS, GCP, provisioned throughput, Agent Mode Beta, or another region passed the same live gate. The earlier `4.0.1` records remain historical evidence and do not substitute for this exact native-SDK release evidence. When the Agent Services Beta is enabled, set `DATABRICKS_AGENT_SERVICES_TEST=1` and `DATABRICKS_AGENT_SERVICE_CONNECTION`. The runner then makes the create/discover/update/grant-read/ delete lifecycle a required workspace check. Add `DATABRICKS_AGENT_SERVICE_TEST_PRINCIPAL` to include an `EXECUTE` and `READ_METADATA` grant/revoke differential. See [Unity Catalog Agent Services](/docs/databricks/agent-services). ## App and Lakebase prerequisites For the reference App, enable Databricks Apps, grant its service principal the selected SQL Warehouse/serving/UC resources, provision the scoped runtime-token secret, and configure a UC Volume for attachments. Restart recovery additionally requires a Lakebase Autoscaling endpoint and database credential-exchange permission. Apply [private networking](/docs/operating/private-networking) when the workspace uses private connectivity or an enterprise CA. When CI and the App use different Lakebase principals, keep a stable release principal as table owner, run schema migrations before App rollout, and grant the App principal DML plus sequence usage. Fabric resolves shared telemetry relations independently of the App principal's first `search_path` schema, so an already-migrated deployment does not require table ownership merely to restart. See [Enterprise Databricks controls](/docs/databricks/enterprise#schema-ownership-in-automated-deployments). --- # Databricks certification Canonical: https://harness.techfabric.com/docs/databricks/live-certification Public certification status, tested capabilities, evidence scope, and limitations for TechFabric Harness on Databricks. TechFabric Harness tests its Databricks integration in protected workspaces before making live-support claims. Certification binds the tested package, source commit, generated Databricks App, workspace profile, and redacted evidence into one retained record. A passing record applies only to that exact scope; it is not a blanket claim for every cloud, region, preview, or workspace configuration. ## Certification record - **Current npm package:** `@fabric-harness/databricks@7.1.1` - **Exact live-certified package:** `@fabric-harness/databricks@7.1.1` - **Certification date:** September 4, 2026 - **Workspace profile:** Azure Databricks, `eastus2`, OAuth machine-to-machine - **Consumption checks:** 21 of 21 required Tier R checks passed - **Additional checks:** 7 configured Tier O checks passed; 2 Tier O checks failed - **Authoring checks:** 10 of 10 required Tier A checks passed with an empty cleanup ledger - **Source commit:** `bc56fa834a26e882953e4824796bd780a5b4efdb` ### What the public record shows Exact-package results and limitations belong in the same view. The image below is a sanitized rendering of the machine-readable public record; the JSON evidence and protected run remain authoritative. Version `7.1.1` is the byte-identical npm package certified by the Tier R record. The protected publisher independently matched its tarball and generated App digests to the retained evidence before publishing. The focused Tier A workflow then downloaded that exact retained tarball and proved the governed authoring lifecycles against the same source commit and package digest. The public record promotes `7.1.1` only after exact-commit Tier R, same-package Tier A, guarded publication, public package consumption, and tag verification all passed. ### The repository version is the certified version The version in this repository's `packages/databricks` manifest is `7.1.1` — the same version the machine-readable record certifies. There is no outstanding source candidate: the published version, the certified version, and the repository version are one package, and every live-support claim on this page belongs to that exact build and source commit. A future candidate appears in the record only as an explicitly uncertified entry until the complete protected evidence chain below promotes it — no part of that chain is assumed from a version bump. Development builds may be published under the npm `dev` dist-tag for single-user evaluation. A development-tagged package is explicitly uncertified, does not move `latest`, does not advance this record, and must not be used to claim shared-user isolation or production readiness. Promoting that exact version to `latest` still requires the complete protected evidence above. Tier R runs its 25-request concurrency burst in a fresh 60-second production rate-limit window. This keeps earlier correctness probes from consuming burst capacity while preserving the real 30-request prompt ceiling. Any failed burst request still fails certification, and retained load evidence aggregates non-secret failure categories such as `admission_http_429` for diagnosis. ## What the protected record proves The current Tier R record passed: - workspace identity and OAuth machine-to-machine authentication; - Unity AI Gateway, Model Serving, SQL, and Unity Catalog allow-and-deny controls; - governed mutation approval, lineage, Volumes, Lakebase, and System Tables cost reconciliation; - RAG, Genie, and managed MCP invocation under on-behalf-of identity; - Databricks App health, Lakebase-backed stop/start recovery, hook-authored dynamic-agent continuity, cascade deletion, and burst-load bounds. The certifying run executed in single-user workspace mode, so the two-user isolation probe was skipped rather than passed; see the capability status below for exactly what that does not cover. The same `7.1.1` record also passed configured Tier O probes for MLflow ResponsesAgent, managed RAG evaluation, AI Search, Genie Agent Mode, Jobs, Lakeflow, and a classic notebook. Two Tier O probes failed in this run: Unity Catalog Agent Services registration was rejected by the workspace API, and Feature Serving did not resolve its configured records. Tier O failures are recorded visibly and do not block certification, but this record establishes nothing for those two surfaces. The same-package Tier A record passed approval provenance plus create, verify, mutate, delete, and verify-delete lifecycles for serverless Jobs, Lakeflow, direct-vector AI Search, custom-model Serving, Unity Catalog administration under OBO, Workspace objects, secret references, and Genie Agents. Every lifecycle ended with `cleanupRequired: false`; the pre-run and post-run sweepers found no retained certification resources. ## Capability status ### Live-certified - **Core consumption path:** Required Tier R checks passed in the recorded Azure workspace. - **Databricks App restart recovery:** Durable state, stream offsets, approvals, and deletion behavior passed stop/start probes. ### Beta and workspace-dependent - **MLflow ResponsesAgent — passed Tier O:** The Responses schema, stable streamed output item, inference tables, and secure App proxy path passed in the current run. - **Genie Agent Mode — passed Tier O:** Ordered output and a terminal SSE event passed in the current run. - **Managed RAG evaluation — passed Tier O:** The configured MLflow 3 evaluation job completed successfully against the governed golden set. ### Not established by this record - **Two-user App isolation, current run:** The certifying run executed in single-user workspace mode, so the user-isolation checks were skipped rather than passed. This record says nothing about cross-user or cross-tenant protection; multi-user production deployments must treat that isolation as uncovered until a two-identity run retains passing evidence. - **Two-user App isolation rolling claim:** With no passing two-user probe in the current run, the separate 14-day rolling claim remains unestablished. - **Unity Catalog Agent Services:** The Tier O registration lifecycle probe failed in the current run, so this record establishes neither registration nor runtime invocation. - **Feature Serving:** The Tier O primary-key resolution probe failed in the current run. - **Optional authoring variants:** The current Tier A record does not establish classic-compute Jobs, Delta Sync indexes, provisioned-throughput Serving, or Genie Agent Mode authoring. - **AWS and Google Cloud workspaces:** This Azure record does not establish live behavior in another cloud or region. `Beta` and `workspace-dependent` are textual status labels, not color-only indicators. Preview availability can differ by account, region, entitlement, and Databricks rollout. A controlled single-user development or private evaluation can leave `require_user_isolation` disabled; that is the workflow default and does not require inventing a second user. A single-user certification can publish a changed Databricks package — the current `7.1.1` record is exactly that case — but it carries an explicit limitation: the certification makes no claim about cross-user or cross-tenant isolation, and multi-user production deployments should treat that isolation as uncovered. In the evidence record this appears as the user-isolation checks being skipped rather than passed, so the run makes no claim about cross-tenant protection. Certifying a shared or user-facing App's isolation behavior, and advancing the public two-user rolling claim, continue to require two distinct identities and retained isolation evidence. ## How certification is evaluated The reference Databricks App is an on-demand certification target. The protected live workflow deploys and starts it for the bounded certification window, uploads the redacted evidence, and stops its compute in an unconditional cleanup step. A cleanup failure fails the workflow rather than leaving the App silently active. Operators should not keep the reference App running between certifications. Fabric uses three evidence tiers: - **Tier R — production consumption and runtime behavior:** Every required check must pass before publishing a changed Databricks package. - **Tier A — protected resource-authoring lifecycles:** Required for management claims; cleanup must complete without leaked resources. - **Tier O — preview, SKU-specific, or optional integrations:** Recorded visibly but non-blocking unless explicitly promoted for that run. The release workflow validates the protected run, commit, package digest, generated App digest, restart evidence, required results, and evidence age before publishing. Direct local publication of the Databricks package fails closed. An independently versioned, non-Databricks release scope may publish only its explicit package allowlist without a Databricks run; it cannot include, tag, or publish the Databricks candidate. This prevents pending Databricks source from blocking an unrelated connector release without weakening the Databricks gate. ## What customers should verify Before production rollout, run the documented preflight and smoke tests in the target workspace. Confirm: - the intended cloud and region expose Databricks Apps, Lakebase, Model Serving, and required AI services; - the application and user principals have only the necessary workspace and Unity Catalog grants; - on-behalf-of scopes are consented and resolve the expected user; - private networking, egress, and SQL policies match the deployment; - restart recovery and tenant isolation pass using representative identities; - Beta capabilities are enabled for the target workspace before relying on them. Use [workspace compatibility](/docs/databricks/compatibility) for API and runtime requirements, [authoring certification](/docs/databricks/authoring-certification) for resource-management coverage, and [ResponsesAgent](/docs/databricks/responses-agent) for that Beta surface's specific contract and evidence. ## Evidence references - Tier R consumption run: `33909857317` - Tier A authoring run: `33915517941` - [Machine-readable public status](/evidence/databricks/current.json) - [Source and protected-run access](/docs/reference/source-access) - Certified package: `@fabric-harness/databricks@7.1.1` - Tier R evidence: `dbx-cert-ca5de23e2502326192565582e6844c5ee423d0bcaf9d3ada19c96a608ae9743b` - Tier A evidence: `dbx-cert-abd5c9a21d0fe784a8ca44572a0d4955ee18494ce677d90fe9af1fe849abb722` - Required results: 21 of 21 Tier R checks passed - Authoring results: 10 of 10 Tier A checks passed for the same package artifact --- # Databricks App Tutorial Canonical: https://harness.techfabric.com/docs/deployment/databricks-app Scaffold, test, build, deploy, and persist a TechFabric Harness agent on Databricks Apps. This tutorial deploys a finite analytics job into Databricks Apps. The App service principal calls Model Serving and Unity Catalog APIs, while optional Lakebase stores sessions, durable submissions, and conversation streams. Read the [Databricks architecture](/docs/databricks/architecture) first when evaluating identity, governance, or service boundaries. Use this page for the scaffold-to-deployment procedure. ## Prerequisites - Node.js 22+ and pnpm or npm. - A Databricks workspace with Apps enabled. - A Model Serving endpoint. - A SQL warehouse for the generated analytics tools. - Optional: a Lakebase Autoscaling endpoint and OAuth Postgres role. ## 1. Scaffold the project ```sh npx @fabric-harness/cli init --template databricks --dir analytics-agent cd analytics-agent npm install ``` The template creates: ```text .fabricharness/ jobs/databricks-analyst.ts roles/data-analyst.md skills/analyze-table/SKILL.md config.ts .env.example AGENTS.md package.json ``` The generated job uses `defineDatabricksAgent()`: ```ts title=".fabricharness/jobs/databricks-analyst.ts" import { defineDatabricksAgent } from '@fabric-harness/databricks'; import { schema } from '@fabric-harness/sdk'; import policy from '../policies/databricks.js'; export default defineDatabricksAgent({ name: 'databricks-analyst', description: 'Answer governed analytics questions with Genie, inspectable SQL, Unity Catalog, and cost context.', input: schema.object({ question: schema.string() }), output: schema.string(), triggers: { webhook: true, manual: true }, model: 'system.ai.gpt-oss-20b', analyticsCopilot: true, tools: ['sql-read', 'genie', 'consumption', 'tables', 'table-info'], sandbox: 'empty', policy, }); ``` ## 2. Run without credentials The mock path validates discovery, schemas, tool assembly, and the model loop without contacting a workspace: ```sh fh agents fh describe databricks-analyst fh run databricks-analyst \ --question "What tables are available in main?" \ --mock ``` Mock mode does not validate OAuth scopes, Unity Catalog grants, SQL execution, or deployment. ## 3. Configure a live workspace Copy the template and fill the required values: ```sh cp .env.example .env.local ``` ```dotenv title=".env.local" DATABRICKS_HOST=https:// DATABRICKS_CLIENT_ID=00000000-0000-0000-0000-000000000000 DATABRICKS_CLIENT_SECRET=replace-with-secret-reference DATABRICKS_WAREHOUSE_ID=0123456789abcdef DATABRICKS_MODEL=system.ai.gpt-oss-20b DATABRICKS_GENIE_SPACE_ID=0123456789abcdef0123456789abcdef DATABRICKS_CATALOG=main DATABRICKS_ANALYTICS_STEWARD_AUDIENCE=analytics-stewards DATABRICKS_COST_TENANT_ID=acme DATABRICKS_COST_PER_DAY_USD=50 DATABRICKS_APP_OBO_REQUIRED=1 FABRIC_DATABRICKS_APP_CAPABILITIES=genie,obo,system-tables-cost ``` Run a live source invocation: ```sh fh run databricks-analyst --question "Describe main.sales.orders" ``` The service principal must have workspace access, permission to invoke the serving endpoint, warehouse usage, `CAN RUN` on the Genie Agent, System Tables access, and the required Unity Catalog grants. Missing App capability bindings fail `fh doctor --target databricks-app`; missing runtime Warehouse, Genie, steward, tenant, or cost settings fail before the first model ask. ## 4. Build the App ```sh fh build --target databricks-app ``` Expected summary: ```text Build complete Output .fabricharness/build/databricks-app Manifest .fabricharness/build/databricks-app/manifest.json Jobs databricks-analyst Agents none ``` Inspect the v2 manifest before deployment: ```sh jq '{schemaVersion, jobs, agents, entrypoint}' \ .fabricharness/build/databricks-app/manifest.json ``` ```json { "schemaVersion": 2, "jobs": [{ "name": "databricks-analyst", "kind": "job" }], "agents": [], "entrypoint": "dist/server.mjs" } ``` The artifact includes `app.yaml`, `databricks.yml`, the shared v2 Node server, and bundled `.mjs` definitions. It does not regenerate a separate legacy HTTP runtime. For a monorepo application, run the build from the package that owns `.fabricharness/`. Imports from workspace-owned agent contracts are bundled into each generated definition, and source-only pnpm protocols are removed from the runtime `package.json`. Treat the whole output directory as the deployment unit: ```sh test -z "$(grep -R -E '\"(workspace|catalog):' .fabricharness/build/databricks-app/package.json || true)" cp -R .fabricharness/build/databricks-app /tmp/detached-agent-app ``` The detached directory is the handoff boundary for Runway or another deployment system. It does not need the source repository, its shared-contract package, or TechFabric Harness packages at runtime. See [Portable agent packages](/docs/deployment/portable-packages) for the full artifact contract, digest-based handoff, isolation test, and deployment-time binding requirements. ### What developers see in the App After deployment, inspect the agent identity, readiness, runtime, workspace region, and each bound resource. The representative state below is sanitized and contains no client workspace identifier, principal identifier, token, or secret value. ## 5. Deploy with a Declarative Automation Bundle ```sh cd .fabricharness/build/databricks-app databricks auth login --host "$DATABRICKS_HOST" databricks bundle validate databricks bundle deploy databricks bundle run ``` Set provider and resource configuration through Databricks App environment/resources rather than committing secrets. Apps supplies `DATABRICKS_APP_PORT`; the generated `app.yaml` starts `dist/server.mjs` on that port. The generated bundle also creates an MLflow experiment, attaches it to the App with `CAN_EDIT`, and injects its ID as `DATABRICKS_MLFLOW_EXPERIMENT_ID`. This activates submission-correlated MLflow traces without granting the App access to unrelated experiments. For a direct `databricks apps deploy` outside the bundle, attach an experiment resource named `fabric-mlflow-experiment` or set an experiment ID and grant the App service principal `CAN_EDIT` yourself. Bind an existing Genie Agent as a least-privilege App resource in `.fabricharness/config.ts`: ```ts export default { target: 'databricks-app', databricks: { app: { genie: { agentId: '0123456789abcdef0123456789abcdef' }, }, }, }; ``` The generated `genie_space` resource defaults to `CAN_RUN` and is injected as `DATABRICKS_GENIE_AGENT_ID` through `valueFrom`. `CAN_EDIT` or `CAN_MANAGE` requires an explicit `authoring: true` on that resource declaration. The App service principal still needs access to the Agent's warehouse and Unity Catalog data. ### Bind any native Databricks App resource Use `databricks.app.resources` when the App needs native resources beyond the Genie and AI Search shortcuts. Harness keeps the Databricks Bundle resource shape intact and adds only: - `name`, the 1-30 character lowercase App resource key used by `valueFrom`; - `env`, the environment variable exposed to the App; and - `authoring: true`, an explicit acknowledgement required for write, manage, or owner permissions. ```ts title=".fabricharness/config.ts" import type { FabricHarnessConfig } from '@fabric-harness/node'; export default { databricks: { app: { resources: [ { name: 'analytics-warehouse', env: 'DATABRICKS_WAREHOUSE_ID', sql_warehouse: { id: '0123456789abcdef', permission: 'CAN_USE', }, }, { name: 'refresh-job', env: 'REFRESH_JOB_ID', job: { id: '12345', permission: 'CAN_MANAGE_RUN' }, }, { name: 'documents-index', env: 'DOCUMENTS_INDEX', uc_securable: { securable_type: 'TABLE', securable_full_name: 'main.rag.documents_index', permission: 'SELECT', }, }, { name: 'vendor-token', env: 'VENDOR_API_TOKEN', secret: { scope: 'analytics-agent', key: 'vendor_api_token', permission: 'READ', }, }, ], }, }, } satisfies FabricHarnessConfig; ``` The supported blocks and normal runtime permissions are: | Native block | Databricks resource | Normal runtime permissions | | --- | --- | --- | | `app` | Another Databricks App | `CAN_USE` | | `database` | Lakebase provisioned database | `CAN_CONNECT_AND_CREATE` | | `postgres` | Lakebase Autoscaling branch/database | `CAN_CONNECT_AND_CREATE` | | `experiment` | MLflow experiment | `CAN_READ` | | `genie_space` | Genie space or Agent | `CAN_VIEW`, `CAN_RUN` | | `job` | Databricks Job | `CAN_VIEW`, `CAN_MANAGE_RUN` | | `serving_endpoint` | Model Serving endpoint | `CAN_VIEW`, `CAN_QUERY` | | `secret` | Databricks secret | `READ` | | `sql_warehouse` | SQL Warehouse | `CAN_USE` | | `uc_securable` | UC connection, function, table/AI Search index, or volume | `USE_CONNECTION`, `EXECUTE`, `SELECT`, `READ_VOLUME` | Management, ownership, secret write, table modification, and volume write permissions fail the build unless the declaration includes `authoring: true`. This prevents an accidental configuration change from turning a runtime App into a resource administrator. Databricks remains the final authorization boundary and can still reject any grant the deployer is not permitted to assign. Each locator becomes a native Bundle variable such as `app_resource_analytics_warehouse_id`. Override it with a Bundle target or `--var` to promote the same artifact without rebuilding: ```sh cd .fabricharness/build/databricks-app databricks bundle validate \ --var app_resource_analytics_warehouse_id= ``` The generated `app.yaml` uses `valueFrom`; `databricks.yml` owns the native resource attachment; and `databricks-app-resources.json` records a non-secret manifest for deployment evidence. A secret binding stores only its scope and key—never the secret value. Run preflight after building: ```sh fh doctor --target databricks-app ``` When a generated artifact is present, doctor invokes the native `databricks bundle validate --strict --output json` command from that artifact. Without a build, it reports the build command without failing setup. Build-time validation remains network-free and rejects duplicate keys, duplicate environment names, reserved Harness bindings, malformed identifiers, invalid native permission pairs, and unacknowledged elevated access before writing an artifact. The restricted [`with-databricks-app-resources` source example](/docs/reference/source-access) contains build, environment override, failure, deployment, and cleanup instructions. A completed deploy means Databricks accepted the new App revision; the public App URL can briefly return `502`, `503`, or `504` while routing changes over. Release automation should poll `/api/ready` and retry only safe `GET` probes during that transition. Do not retry a mutating `POST` unless it carries the Harness idempotency key expected by that route. The protected recovery workflow applies this rule for up to ten minutes before it starts state and approval assertions. For a configuration-preserving production restart, pass the App name explicitly so the Databricks CLI uses the Apps API and restarts the existing active deployment: ```sh databricks apps stop "$DATABRICKS_APP_NAME" databricks apps start "$DATABRICKS_APP_NAME" ``` Running `databricks apps start` without a name inside the generated bundle directory enters project mode and resolves bundle variables again. Use the explicit-name form for a restart, or rerun `fh deploy --target databricks-app` when applying new source or configuration. The protected live workflow verifies the actual platform behavior: a bare stop/start creates a new deployment snapshot from the same configured source path. It then proves that the managed App resources, pending human approval, Lakebase sessions, submissions, conversation offsets, and UC Volume attachments remain usable after the restart. Static, non-secret workspace settings are emitted into `app.yaml`, so the new snapshot retains its catalog, schema, volume, model endpoint, and SQL warehouse configuration. Once the App is running, invoke the finite job through its App URL: ```sh TOKEN="$(databricks auth token --host "$DATABRICKS_HOST" | jq -r .access_token)" curl -sS "$DATABRICKS_APP_URL/api/jobs/databricks-analyst" \ -H "authorization: Bearer $TOKEN" \ -H 'content-type: application/json' \ -d '{"question":"What were yesterday’s top products?"}' ``` Generated Databricks Apps mount the complete Harness HTTP surface beneath `/api`, which is the path Databricks supports for OAuth Bearer-token API access. Root routes remain available for platform health checks and local compatibility, but external clients must use `/api/jobs`, `/api/agents`, `/api/responses`, and the corresponding `/api` inspection routes. Databricks validates the OAuth token at the App ingress. M2M requests use App authorization: the ingress admits the external `/api` request without forwarding the caller token or preserving that prefix for the App process. The generated `app.yaml` and bundle inject the non-secret `DATABRICKS_APP_NAME`, which Fabric uses as the App-principal identity when Databricks does not expose `DATABRICKS_CLIENT_ID` to the process. Interactive OBO requests still bind to the forwarded user and an isolated user tenant. Generated App servers trust Databricks Apps' integrity-protected `x-forwarded-user`, `x-forwarded-email`, and `x-forwarded-preferred-username` headers for browser admission, while the forwarded access token remains available only to downstream OBO clients. A natural-person email or preferred username is required before Fabric takes this path, so an M2M caller that supplies only `x-forwarded-user` remains a service principal. This avoids requiring a SCIM scope merely to admit a user who already granted the App its declared SQL, Genie, and Model Serving scopes. If Apps omits `x-forwarded-user` for browser traffic, Fabric uses the verified email or preferred username as the stable identity instead of admitting an undefined principal. When an external M2M token is forwarded through the same OBO header, Fabric selects App authorization only if its proxy identity or signed token identity matches `FABRIC_HARNESS_DATABRICKS_APP_CALLER_IDS`. Generated artifacts initialize that non-secret allowlist from the deployment service principal's `DATABRICKS_CLIENT_ID`; set `BUNDLE_VAR_databricks_app_caller_ids` to a comma-separated list when multiple automation callers need App authorization. Non-allowlisted forwarded tokens fail closed on OBO validation. This fallback is enabled only in generated Databricks Apps; generic Node servers remain fail-closed. After granting user authorization, verify the browser path through `/api`, not the root route: ```js const identity = await fetch('/api/certification/obo').then((response) => response.json()); const sessions = await fetch('/api/sessions').then((response) => response.json()); ``` Both calls use the signed-in App user's isolated tenant. A `401` here means the generated App is not receiving trusted Databricks Apps identity headers; it is not evidence that SQL or Genie consent was denied. The reference certification route uses token-backed workspace inspection when the token permits it; otherwise it reports the user principal already authenticated from Apps ingress and omits token-lifetime fields. It never reflects the forwarded token. ## 6. Add Lakebase durability Stateless Apps do not need `pg`. The generated server passes `lakebase: false` and omits PostgreSQL imports unless `.fabricharness/config.ts` sets `databricks.app.lakebase: true` or the build resolves a managed Lakebase App resource. Fabric needs both Postgres connection information and the full Lakebase endpoint resource name: ```dotenv DATABRICKS_LAKEBASE_HOST=ep-id.database.us-west-2.cloud.databricks.com DATABRICKS_LAKEBASE_DATABASE=databricks_postgres DATABRICKS_LAKEBASE_USER=00000000-0000-0000-0000-000000000000 DATABRICKS_LAKEBASE_ENDPOINT=projects/project-id/branches/branch-id/endpoints/endpoint-id PGPORT=5432 ``` When Lakebase is enabled, install `pg`. At runtime Fabric: 1. Gets a workspace OAuth token from the App service principal. 2. Exchanges it at `POST /api/2.0/postgres/credentials` using the endpoint resource name. 3. Supplies the database credential through the pool password callback. 4. Refreshes before expiry and single-flights concurrent refreshes. 5. Injects Lakebase session, submission, and conversation-stream stores into the shared server. 6. Binds scheduled runs to the App principal's isolated tenant and coordinates replicas through a Postgres scheduler lease. 7. Persists the last scheduled occurrence and runs the most recent missed occurrence once after an App restart. Stateless Apps use a process-local lease, skip missed ticks, and still bind work to the App principal. Never place the workspace OAuth token directly in `PGPASSWORD`. Scheduled background work is intentionally owned by the App principal, not by whichever user first opens a persistent session. App users retain their own OBO tenants; service-owned schedules and user-owned conversations cannot silently append to one another. ### Resolve approvals from a deployed App Databricks App users have tenant-scoped approval permissions without broad `admin:read`. Discover pending work through the App's `/api` surface: ```sh TOKEN="$(databricks auth token --host "$DATABRICKS_HOST" | jq -r .access_token)" export DATABRICKS_OAUTH_TOKEN="$TOKEN" fh approvals --url "$DATABRICKS_APP_URL/api" --token-env DATABRICKS_OAUTH_TOKEN fh approve \ --url "$DATABRICKS_APP_URL/api" \ --token-env DATABRICKS_OAUTH_TOKEN ``` Discovery returns only sessions visible to the authenticated Databricks user. The `audience` attached to an approval remains a host routing label: restrict `approval:write` to the intended Databricks group or application role. That user-scoped route cannot discover approval requests raised by App-principal scheduled work; the tenant separation above is intentional. A schedule that needs a human decision must either persist a proposal and let a later user-owned session perform the gated action, or publish a deterministic decision card through a trusted external bridge such as [Buzz](/docs/ecosystem/channels/buzz). The application's governed approval record associated with the card receipt must retain the scheduler session and approval ids, map an authenticated response back to that exact request, and resolve through the normal stored approval/CAS boundary. Do not grant a user the App tenant or parse free-form chat as approval. ### Bind an AI Search index Declare the existing index in `.fabricharness/config.ts`: ```ts export default { databricks: { app: { aiSearch: { index: 'main.support.kb_index', }, }, }, }; ``` The App build emits a managed `uc_securable` table resource with `SELECT`, references it through `valueFrom`, and injects the full index name as `DATABRICKS_AI_SEARCH_INDEX`. Databricks grants the App service principal the required parent `USE CATALOG` and `USE SCHEMA` privileges when the deployer is authorized to grant them. The generated bundle uses `var.databricks_ai_search_index`, so targets can bind different indexes without rebuilding the application code. ### Add non-secret App environment configuration Declare application configuration that is safe to embed in the build artifact: ```ts export default { databricks: { app: { env: { FEATURE_MODE: 'rag', SUPPORT_QUEUE: 'priority', }, }, }, }; ``` Fabric emits the entries deterministically into both `app.yaml` and the generated bundle. Keys must be uppercase environment-variable names. Harness-managed names cannot be overridden, and credential-shaped names such as `*_TOKEN`, `API_KEY`, `PASSWORD`, or `SECRET` are rejected. Bind credentials through Databricks App resources and `valueFrom`; do not bake them into generated artifacts. ### Build-time bundle variables `fh build` and `fh deploy` read the following Databricks bundle inputs while generating the App artifact: | Variable | Generated setting | Default | | --- | --- | --- | | `BUNDLE_VAR_databricks_catalog` | `DATABRICKS_CATALOG` | `main` | | `BUNDLE_VAR_databricks_schema` | `DATABRICKS_SCHEMA` | `agents` | | `BUNDLE_VAR_databricks_volume` | `DATABRICKS_VOLUME` | `fabric_attachments` | | `BUNDLE_VAR_databricks_serving_endpoint` | `DATABRICKS_MODEL` | `system.ai.gpt-oss-20b` | | `BUNDLE_VAR_databricks_warehouse_id` | `DATABRICKS_WAREHOUSE_ID` | empty | | `BUNDLE_VAR_databricks_app_caller_ids` | allowed automation caller IDs | `DATABRICKS_CLIENT_ID`, then empty | | `BUNDLE_VAR_lakebase_endpoint` | managed Lakebase endpoint resource | unset | | `BUNDLE_VAR_lakebase_database_resource` | managed Lakebase database resource | unset | These are build inputs, not a secret store. Rebuild after changing them. The generated `databricks.yml` also exposes corresponding deployment variables so bundle targets can override environment-specific catalog, schema, volume, model, warehouse, caller, AI Search, and Lakebase resource values. For `fh deploy`, provide the Lakebase **resource names** to the bundle separately from the direct PostgreSQL connection values shown above: ```sh export BUNDLE_VAR_lakebase_endpoint='projects/project-id/branches/production/endpoints/primary' export BUNDLE_VAR_lakebase_database_resource='projects/project-id/branches/production/databases/app-db' fh deploy --target databricks-app ``` `app-db` is the Lakebase database resource ID. It can differ from the PostgreSQL database name such as `databricks_postgres`. Use the `name` field returned by `databricks postgres list-databases projects/project-id/branches/production`. For a custom server entrypoint, the equivalent wiring is: ```ts import { databricksApp } from '@fabric-harness/databricks'; import { startDevServer } from '@fabric-harness/node'; const app = databricksApp(); const server = await startDevServer({ port: Number(process.env.DATABRICKS_APP_PORT ?? 8080), host: '0.0.0.0', basePath: '/api', ...(await app.serverOptions()), }); const shutdown = async () => { await server.close(); await app.close(); }; process.once('SIGTERM', () => void shutdown()); process.once('SIGINT', () => void shutdown()); ``` ## 7. Add a persistent agent Create `.fabricharness/agents/copilot.ts`: ```ts import { createAgent } from '@fabric-harness/sdk'; export default createAgent(({ id }) => ({ name: 'copilot', model: 'databricks/system.ai.gpt-oss-20b', instructions: `You are the governed analytics copilot for account ${id}.`, triggers: { webhook: true }, })); ``` Rebuild. The manifest now reports the finite job under `jobs` and `copilot` under `agents`. Persistent input returns a durable receipt: ```sh curl -i "$DATABRICKS_APP_URL/agents/copilot/acct-42" \ -H "authorization: Bearer $DATABRICKS_TOKEN" \ -H 'content-type: application/json' \ -d '{"message":"Summarize this account’s sales."}' ``` Use `@fabric-harness/client` to wait or stream by offset. See [Persistent agents](/docs/building/persistent-agents). ## 8. Validate before production Run the repository live suite with a controlled workspace: ```sh FABRIC_DATABRICKS_TEST=1 \ FABRIC_DATABRICKS_LAKEBASE_TEST=1 \ pnpm --filter @fabric-harness/databricks test ``` The production gate should cover App deployment, service-principal access, user OBO where used, Unity Catalog denials, Model Serving, SQL, and Lakebase restart recovery. Local contract tests do not replace that workspace-specific validation. ## See also - [Databricks integration reference](/docs/deployment/databricks) - [Build and run artifacts](/docs/deployment/build-artifacts) - [Enterprise controls](/docs/building/enterprise-controls) - [Production readiness](/docs/reference/production-readiness) --- # Databricks SQL sandbox Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/databricks-sql Use a Databricks SQL Warehouse as a governed query execution sandbox for TechFabric Harness sessions. **Package:** `@fabric-harness/databricks/sql-sandbox` **Execution:** Databricks SQL Statement Execution API `databricksSqlSandbox()` maps `session.shell(statement)` to a SQL Warehouse. It is designed for data agents whose shell abstraction should mean SQL, while retaining the common TechFabric Harness sandbox interface. ```ts import { databricksSqlSandbox } from '@fabric-harness/databricks/sql-sandbox'; import { init } from '@fabric-harness/sdk'; const runtime = await init({ sandbox: databricksSqlSandbox({ host: process.env.DATABRICKS_HOST!, principal: { kind: 'on-behalf-of', userToken: () => workspaceIdentity() }, warehouseId: process.env.DATABRICKS_WAREHOUSE_ID!, catalog: 'main', schema: 'analytics', resultFormat: 'jsonl', waitTimeoutSeconds: 30, }), }); const session = await runtime.session(); const result = await session.shell('SELECT current_user(), current_catalog()'); ``` ## Capabilities | Capability | Behavior | | --- | --- | | `exec()` | Executes one SQL statement and serializes result rows as JSONL or CSV | | Text and binary files | Small in-memory map scoped to the sandbox instance | | Snapshots and restore | Not supported | | Network | Managed by the provider | | Persistence | Session only for the in-memory file map | | Isolation | Databricks SQL Warehouse plus its configured Unity Catalog access | The file methods do not access DBFS, workspace files, or Unity Catalog Volumes. Mount a `databricksVolumeSource()` for governed non-tabular data. Use Docker or another code sandbox for bash, Python package installation, repository work, or arbitrary code execution. ## Required access The acting principal needs workspace access, permission to use the SQL Warehouse, and the required Unity Catalog grants. Prefer a rotating OAuth token provider rather than a long-lived token. See [Databricks connectors and sandboxes](/docs/databricks/sandboxes-connectors) for the selection guide and full examples. --- # Databricks Lakebase Canonical: https://harness.techfabric.com/docs/ecosystem/databases/lakebase Durable state for Databricks Apps using exchanged database credentials. Lakebase is Fabric's preferred durable Postgres path inside Databricks Apps. Configure the database connection fields and the full endpoint resource name: ```sh DATABRICKS_LAKEBASE_HOST=ep-id.database.us-west-2.cloud.databricks.com DATABRICKS_LAKEBASE_DATABASE=databricks_postgres DATABRICKS_LAKEBASE_USER=00000000-0000-0000-0000-000000000000 DATABRICKS_LAKEBASE_ENDPOINT=projects//branches//endpoints/ PGPORT=5432 ``` `databricksApp()` also accepts `PGHOST`, `PGDATABASE`, `PGUSER`, `PGPORT`, and `ENDPOINT_NAME`, which align with App database resource configuration. The Databricks bundle exchanges the app's workspace OAuth identity for a short-lived database credential, refreshes it with single-flight protection, and injects Lakebase-backed session, submission, and conversation-stream stores into the shared server. A raw workspace token is rejected as a database password. Use `lakebaseClient()` when assembling a custom bundle. For the standard path, follow [Databricks App deployment](/docs/deployment/databricks-app#6-add-lakebase-durability), including the live restart and credential-exchange smoke. Local contract tests cannot validate workspace permissions or the hosted credential response shape. --- # Authentication and RBAC Canonical: https://harness.techfabric.com/docs/operating/auth Bind authenticated principals, tenants, permissions, and SSO identities to every server operation. `fh dev` and generated Node builds ship a simple Bearer-token auth surface for solo deployments. Enterprise hosts use `authenticate` to return a principal with tenant and permission scopes. The server derives the execution actor from that principal, so clients cannot spoof audit identity in request bodies. Local/dev mode remains open when no auth is configured. Production mode fails closed: only `/health` and `/ready` are anonymous, and every other HTTP or WebSocket route returns `401` unless the bearer token or custom resolver authorizes it. ## Default: Bearer token ```sh FABRIC_HARNESS_API_TOKEN=changeme fh dev --port 9111 ``` ```sh curl -H 'Authorization: Bearer changeme' http://localhost:9111/sessions ``` WebSocket upgrades use the same token via `?token=` query param (browsers can't set headers on `WebSocket` constructor): ```ts new WebSocket('wss://app.example.com/sessions/abc/ws?token=changeme'); ``` ## Custom resolver: `extractAuthToken` When you have an existing identity layer (cookies, JWT, SSO terminator), pass a custom resolver: ```ts import { startDevServer, parseCookie } from '@fabric-harness/node'; await startDevServer({ extractAuthToken: (req) => { const cookie = parseCookie(req, 'session'); if (!cookie) return undefined; // fall through to bearer check return verifySessionCookie(cookie); // your validator returns true/false }, }); ``` The resolver returns: - `true` — authorize the request - `false` — reject with 401 - `undefined` — fall through to the built-in bearer-token check Same hook works for HTTP requests AND WebSocket upgrades. ## Enterprise principals and permissions Use `authenticate` when the server must enforce tenant isolation and route-level RBAC: ```ts import { startDevServer } from '@fabric-harness/node'; await startDevServer({ authenticate: async (req) => { const claims = await verifyCompanyJwt(req.headers.authorization); if (!claims) return false; return { id: claims.sub, kind: claims.type === 'user' ? 'user' : 'service-principal', provider: 'company-oidc', tenantId: claims.organizationId, displayName: claims.name, ucPrincipal: claims.databricksPrincipal, permissions: claims.permissions, }; }, }); ``` The built-in permission scopes are: | Permission | Operations | | --- | --- | | `agent:invoke` | Jobs, persistent prompts, dispatch, and channel ingress | | `session:read` | Session, run, timeline, metrics, and conversation reads | | `session:abort` | Abort an active persistent submission | | `session:delete` | Cascade-delete a settled persistent instance | | `approval:read`, `approval:write` | Inspect and vote on approvals | | `artifact:read` | Read artifacts and attachments | | `build:read` | Read build manifests | | `mcp:invoke` | Call the server's `/mcp` endpoint | | `session:replay` | Fork a session from a durable entry | | `admin:read` | Admin and OpenAPI routes | `*` grants every permission and `session:*` grants all permissions for one resource. Omitting `permissions` keeps compatibility with existing custom authenticators and grants unrestricted access; enterprise authenticators should always return an explicit array. `tenantId` binds the principal to one tenant. A request for a different `X-Fabric-Tenant` or `?tenant=` receives `403`. Use `tenantIds` instead when an operator may explicitly select from a known set. A single-value `tenantIds` allowlist binds implicitly when the request omits a tenant; an allowlist containing multiple tenants requires an explicit permitted tenant selection and otherwise returns `403`. Omitting the selection never widens access to every tenant. The resulting principal and tenant propagate through submissions, entries, approvals, tool attribution, and telemetry. Add application-specific checks after the built-in scopes with `authorize`: ```ts await startDevServer({ authenticate: companyAuthenticator, authorize: ({ principal, permission, tenantId }) => permission !== 'session:delete' || (principal.roles?.includes('tenant-admin') === true && tenantId !== undefined), }); ``` HTTP and WebSocket upgrades use the same authentication, tenant, and authorization pipeline. ## OIDC and JWKS validation Install `jose`, then use the built-in validator for any OpenID Connect provider. It verifies the signature against a local or remote JWKS, issuer, audience, required claims, algorithms, expiry, and clock tolerance. Remote JWKS keys are cached and refreshed when providers rotate signing keys. ```sh pnpm add jose ``` ```ts import { oidcJwtAuthenticator, startDevServer } from '@fabric-harness/node'; await startDevServer({ authenticate: oidcJwtAuthenticator({ issuer: 'https://identity.example.com', audience: 'fabric-api', jwksUri: 'https://identity.example.com/.well-known/jwks.json', provider: 'company-oidc', claims: { tenantId: 'organization_id', roles: 'roles', groups: 'groups', permissions: 'permissions', }, groupRoles: { 'platform-operators': ['operator'], }, rolePermissions: { operator: ['session:*', 'approval:*', 'artifact:read'], }, }), }); ``` The validator returns `undefined` when no supported token is present, so a configured legacy API token can remain as fallback. An invalid or expired JWT returns `false` and the server responds with `401`. Use `mapPrincipal` when provider claims need logic beyond declarative claim mapping. ### Microsoft Entra ID `entraIdAuthenticator()` configures the tenant-specific v2 issuer and rotating JWKS. It maps `oid`, `tid`, `name`, `roles`, and `groups`, and treats `idtyp: app` as a service principal. ```ts authenticate: entraIdAuthenticator({ tenantId: process.env.ENTRA_TENANT_ID!, clientId: process.env.ENTRA_CLIENT_ID!, groupRoles: { [process.env.ENTRA_OPERATOR_GROUP!]: ['operator'] }, rolePermissions: { operator: ['session:*', 'approval:*', 'admin:read'] }, }) ``` ### Databricks Apps `databricksAppsOidcAuthenticator()` validates workspace-issued JWTs and accepts either an `Authorization: Bearer` token or the Databricks Apps `x-forwarded-access-token` header. It maps the workspace, email/Unity Catalog principal, roles, and groups into the same server identity. ```ts authenticate: databricksAppsOidcAuthenticator({ workspaceHost: process.env.DATABRICKS_HOST!, audience: process.env.DATABRICKS_APP_CLIENT_ID!, rolePermissions: { 'data-steward': ['session:read', 'approval:*'] }, }) ``` If the workspace uses a custom issuer, account-level identity federation, or a proxy JWKS, set `issuer` and `jwksUri` explicitly. Keep the service-principal path for unattended traffic and use the forwarded user token only when operations should inherit that user's Databricks grants. ## Delete a persistent instance Deletion is deliberately restricted to settled work: ```sh curl -X DELETE \ -H "Authorization: Bearer $TOKEN" \ https://agents.example.com/agents/support/customer-42 ``` The operation removes every named session for that agent instance, its settled submissions, conversation streams, session artifacts, and content-addressed attachments. If work is still active, the server requests an abort and returns `409`; retry after settlement. Durable custom stores must implement `SessionStore.delete` and `deleteSessionSubmissions`. ## Recipe: SSO terminator (Cloudflare Access, IAP, Cognito) When fabric-harness runs behind an SSO terminator, the terminator validates the user and forwards a verified header. Trust the header inside the resolver: ```ts await startDevServer({ extractAuthToken: (req) => { const userHeader = req.headers['cf-access-authenticated-user-email']; if (typeof userHeader === 'string' && userHeader.length > 0) return true; return undefined; }, }); ``` Make sure the terminator strips the header from inbound requests that didn't pass through it — otherwise clients can spoof. ## Recipe: per-tenant cookies Combine with `X-Fabric-Tenant` header to scope cookie validation per tenant: ```ts extractAuthToken: (req) => { const tenant = req.headers['x-fabric-tenant']; const cookie = parseCookie(req, `session_${tenant}`); return cookie ? verifyForTenant(cookie, tenant) : undefined; }, ``` ## WebSocket cookies (browsers) Same-origin WebSocket upgrades carry browser cookies automatically — `extractAuthToken` reads them just like HTTP. Cross-origin? `Sec-WebSocket-Protocol` workarounds exist but are clunky; recommend bearer-via-query-param (`?token=...`) for cross-origin WS. ## See also - [HTTP server reference](/docs/reference/http-server) - [Multi-tenancy](/docs/operating/multi-tenancy) --- # Operator Console Canonical: https://harness.techfabric.com/docs/operating/operator-console Inspect sessions, approvals, tenants, and persistent instances from the authenticated Node server. The Node server includes a compact operator console at `/admin`. It uses the same authentication, tenant binding, and `admin:read` permission checks as the admin APIs. Its warm-paper surfaces, burnt-sienna emphasis, compact controls, and light/dark palette follow the same Fabric family contract as `@fabricorg/ui`. The console remains self-contained so loading `@fabric-harness/node` never introduces a React or browser-asset dependency. ```sh FABRIC_HARNESS_API_TOKEN="$API_TOKEN" fh dev --port 4317 ``` Open `http://localhost:4317/admin`, enter the API token, and connect. The token is kept in browser `sessionStorage` and sent as a bearer header; it is not written to the server-rendered page. ## What operators see The console combines tenant-scoped sessions, durable queue state, persistence health, and only the actions allowed for the authenticated principal. These screenshots are deterministic, sanitized UI states; no client data, workspace token, or environment identifier is embedded in the documentation. The console provides paginated, searchable views for: - finite jobs and persistent agents; - sessions, runs, and active durable submissions; - built-in tools and pending or completed approvals; - persistence, queue, and worker health; - session cost metrics, policy decisions, and the audit trail. Operators with `approval:write` can approve or reject a pending request. Operators with `session:replay` can fork a session from any durable entry, while `session:abort` and `session:delete` control abort and cascade deletion. Buttons are hidden when the authenticated principal lacks the corresponding permission; the server independently authorizes every action. An application user does not need `admin:read` merely to handle approvals. Use the tenant-scoped `GET /approvals` endpoint or `fh approvals --url ` to discover visible requests, then `fh approve` or `fh reject` against the same remote URL. The `/admin` console remains reserved for operators who need broader run, health, audit, and replay access. All collection endpoints use the same pagination shape: ```json { "items": [], "total": 0, "offset": 0, "limit": 50, "nextOffset": null } ``` Use `?offset=0&limit=50&q=running`. A tenant-bound principal only receives its own tenant. A principal allowed to operate several tenants can add `?tenant=acme`; the server validates that selection against the principal before reading data. Custom SSO deployments should use cookie authentication in `authenticate`, so the console can load without a separate bearer token. Assign operators `admin:read`, plus the action permissions they need. The APIs remain the source of truth; the console does not bypass RBAC or tenant isolation. --- # Private networking and egress Canonical: https://harness.techfabric.com/docs/operating/private-networking Enforce outbound policy at container, cluster, and cloud-provider boundaries, with proxy, DNS, custom CA, and mTLS support. Fabric applies URL, DNS-answer, and redirect policy before supported HTTP calls. Production deployments also need a boundary outside the agent process. That second layer prevents a custom tool, dependency, or direct socket from bypassing the application policy. ```mermaid flowchart LR A[Agent process] -->|policy-checked request| P[Internal egress proxy] A -. direct socket denied .-> X[Public or private service] P -->|domain and port allowlist| D[Databricks workspace APIs] P -->|private DNS| E[Private endpoints] subgraph Boundary[Container, cluster, or provider boundary] A P end classDef runtime fill:#e8f0fe,stroke:#2563eb,color:#172554 classDef control fill:#fff4d6,stroke:#d97706,color:#451a03 classDef service fill:#dcfce7,stroke:#16a34a,color:#052e16 classDef denied fill:#fee2e2,stroke:#dc2626,color:#450a0a class A runtime class P control class D,E service class X denied ``` ## Require an enforceable boundary `assertEnforceableNetworkPolicy()` rejects a network policy backed only by process-level checks. Call it during production startup after creating the sandbox: ```ts import { DockerSandboxEnv, assertEnforceableNetworkPolicy, type CapabilityPolicy, } from '@fabric-harness/sdk'; const policy: CapabilityPolicy = { network: { mode: 'allowlist', protocols: ['https:'], hosts: ['*.azuredatabricks.net', '*.databricks.com'], resolveDns: true, }, }; const sandbox = new DockerSandboxEnv({ workspacePath: process.cwd(), network: 'fabric-agent-internal', networkBoundary: { enforcement: 'container', reference: 'docker-network:fabric-agent-internal+egress-proxy', }, }); assertEnforceableNetworkPolicy(policy, sandbox, { deployment: 'production', }); ``` The `networkBoundary` value is an operator assertion, not a network provisioner. Create the Docker network with `internal: true`, connect the agent only to that network, and connect an independently configured proxy to both the internal and destination networks. The [`private-networking` example](/docs/reference/source-access) contains a runnable Compose topology that proves a proxied request succeeds while a direct request fails. ## Proxy, custom CA, and mTLS Use one transport factory for connectors that require enterprise TLS settings: ```ts import { readFile } from 'node:fs/promises'; import { createPrivateNetworkFetch } from '@fabric-harness/node'; const client = createPrivateNetworkFetch({ proxy: { url: process.env.HTTPS_PROXY!, authorization: `Bearer ${process.env.EGRESS_PROXY_TOKEN!}`, }, tls: { ca: await readFile('/var/run/fabric-secrets/private-ca.pem'), cert: await readFile('/var/run/fabric-secrets/client.crt'), key: await readFile('/var/run/fabric-secrets/client.key'), }, policy, }); try { const response = await client.fetch(`${process.env.DATABRICKS_HOST}/api/2.0/clusters/list`); if (!response.ok) throw new Error(`Workspace request failed: ${response.status}`); } finally { await client.close(); } ``` Keep proxy authorization and PEM material in a secret provider or mounted secret volume. Proxy URLs with embedded credentials are rejected so credentials cannot appear in URL logs. `rejectUnauthorized` defaults to `true`; do not disable certificate verification in production. ## Kubernetes and AKS `createKubernetesEgressNetworkPolicy()` emits deny-by-default egress with only three permitted paths: 1. selected cluster DNS pods on TCP/UDP 53; 2. a selected egress proxy on one TCP port; 3. explicitly listed private CIDRs and ports. ```ts import { createKubernetesEgressNetworkPolicy, kubernetesSandbox, } from '@fabric-harness/connectors/k8s'; const manifest = createKubernetesEgressNetworkPolicy({ namespace: 'fabric-agents', podSelector: { 'app.kubernetes.io/name': 'fabric-agent' }, egressProxy: { namespaceSelector: { 'kubernetes.io/metadata.name': 'networking' }, podSelector: { 'app.kubernetes.io/name': 'fabric-egress-proxy' }, port: 3128, }, privateCidrs: [{ cidr: '10.40.0.0/24', ports: [443] }], }); // Apply `manifest` with the cluster API before attaching the pod. const sandbox = kubernetesSandbox(pod, { networkPolicy: { namespace: manifest.metadata.namespace, name: manifest.metadata.name, }, }); ``` The generator rejects public CIDRs. Route public destinations through the proxy, where FQDN and certificate policy can be enforced. On AKS, combine this policy with Azure CNI, private clusters, Private Link, private DNS zones, workload identity, and an Azure Firewall or proxy route. Mount custom trust bundles and client certificates through the Secrets Store CSI Driver. ## Databricks private connectivity For Databricks Apps, keep the workspace identity supplied by the platform and configure connectivity at the workspace/account layer: - use workspace private connectivity for front-end and back-end API paths; - route SQL Warehouse, Model Serving, AI Search, Lakebase, and Unity Catalog traffic through approved private endpoints where the workspace feature supports them; - use workspace DNS names in the Fabric allowlist and resolve them through the private DNS path; - exchange the App identity for short-lived Lakebase credentials instead of storing a database password; - store attachments in Unity Catalog Volumes and use service-principal or on-behalf-of identity, never embedded cloud storage keys. See [Databricks architecture](/docs/databricks/architecture), [enterprise Databricks controls](/docs/databricks/enterprise), and [Databricks Apps deployment](/docs/deployment/databricks-app) for the complete identity and data flow. ## Verification checklist - A direct request with proxy settings disabled cannot reach its destination. - An allowed proxied request succeeds; a non-allowlisted hostname is denied by the proxy. - Private DNS resolves only to the expected private ranges. - An untrusted server certificate fails, while the configured private CA succeeds. - The server requires and validates the expected client certificate. - `assertEnforceableNetworkPolicy()` passes with a named container, cluster, or provider boundary. - Logs, traces, errors, and build artifacts contain no proxy credentials, client keys, or workspace tokens. --- # MCP Canonical: https://harness.techfabric.com/docs/reference/mcp How Model Context Protocol servers plug into TechFabric Harness, so an agent can use a tool you did not have to wrap yourself. TechFabric Harness connects Model Context Protocol (MCP) servers to a session as normal Fabric tools. Remote Streamable HTTP, legacy SSE, and local stdio transports are supported. It can also expose Harness jobs, persistent agents, and governed tools as an authenticated MCP Streamable HTTP server. ## Expose Fabric through MCP ```ts import { startDevServer } from '@fabric-harness/node'; await startDevServer({ authenticate: companyAuthenticator, mcp: { enabled: true, exposeJobs: true, exposeAgents: true, tools: [lookupAccount], }, }); ``` Connect an MCP client to `https://agents.example.com/mcp`. Finite jobs appear as `job_` tools using their declared input schema. Persistent agents appear as `agent_` tools accepting `instanceId`, `message`, and optional `session`. Set `FABRIC_HARNESS_MCP_ENABLED=1` to enable the same surface in generated Node artifacts. The `/mcp` route requires `mcp:invoke`. The authenticated principal and tenant propagate into job runs and persistent submissions, including tool attribution and audit entries. Direct tool calls receive the actor, tenant, MCP request id, canonical input digest, cancellation signal, and an empty default sandbox through `ToolContext`. MCP annotations are derived from Fabric tool effects, and tool errors are redacted before returning to the client. Custom tools must declare `metadata.effect`. Read-only and no-effect tools can be exposed directly. `write` and `execute` tools must first be wrapped by server-side governance and declare `metadata.governed: true`; an unknown effect or ungoverned mutation fails server startup. Resolve approval grants and policy versions through the trusted `mcp.resolveToolContext` hook or another server-side store. Never accept an approval grant from model-supplied tool arguments. ```ts await startDevServer({ authenticate: companyAuthenticator, mcp: { enabled: true, tools: [governedWriteTool], resolveToolContext: async ({ toolCallId, input, actor, tenantId }) => ({ policyVersion: await policyStore.currentVersion(tenantId), approval: await approvalStore.findGrant({ toolCallId, input, actor, tenantId }), }), }, }); ``` If the effect is missing, the mutation has not been governance-wrapped, or the configured resolver cannot produce the approval expected by the tool's policy, the operation fails closed before provider execution. ## Remote MCP server Mount an MCP server's tools as session tools: ```ts import { connectMcpServer } from '@fabric-harness/sdk'; const github = await connectMcpServer('github', { url: process.env.GITHUB_MCP_URL!, headers: { authorization: `Bearer ${process.env.GITHUB_TOKEN}`, }, allowTools: ['get_*', 'list_*', 'search_*'], denyTools: ['*delete*'], }); await session.prompt('Look up project FAB-123', { tools: github.tools, }); await github.close(); ``` `connectMcpServer()` uses Streamable HTTP by default. Pass `transport: 'sse'` for a server that still exposes the legacy SSE transport. `allowTools` and `denyTools` accept exact names or `*` globs and filter the server catalog before any tool reaches the model. Provider credentials remain in transport or OAuth state and are not added to tool metadata or model context. The returned connection has `reconnect()` and `close()` lifecycle methods. Prompt and task abort signals propagate to active MCP calls, including the protocol cancellation notification. ## OAuth client credentials Use the machine-to-machine helper when the MCP authorization server supports the `client_credentials` grant. The MCP SDK discovers authorization metadata, obtains a token, and refreshes it when required. ```ts import { connectMcpServer, createMcpClientCredentialsAuth } from '@fabric-harness/sdk'; const authProvider = createMcpClientCredentialsAuth({ clientId: process.env.MCP_CLIENT_ID!, clientSecret: process.env.MCP_CLIENT_SECRET!, scope: 'tools.read', }); const connection = await connectMcpServer('enterprise-tools', { url: process.env.MCP_SERVER_URL!, authProvider, allowTools: ['catalog_*'], }); ``` ## OAuth authorization code Authorization code uses PKCE and application-owned state storage. In production, implement `loadState` and `saveState` with an encrypted server-side session or secret store. Never serialize this state into a prompt, agent memory, job payload, or client-side transcript. ```ts import { connectMcpServer, createMcpAuthorizationCodeAuth } from '@fabric-harness/sdk'; const authProvider = createMcpAuthorizationCodeAuth({ redirectUrl: 'https://agents.example.com/oauth/mcp/callback', clientName: 'TechFabric Harness', clientId: process.env.MCP_CLIENT_ID!, clientSecret: process.env.MCP_CLIENT_SECRET, scopes: ['tools.read'], onAuthorizationUrl: (url) => redirectUser(url), loadState: () => encryptedSession.get('mcp-oauth'), saveState: (state) => encryptedSession.set('mcp-oauth', state), }); // On the callback request, pass the returned code once. Stored refresh tokens // are reused by subsequent connections through the same provider state. const connection = await connectMcpServer('user-tools', { url: process.env.MCP_SERVER_URL!, authProvider, authorizationCode: callbackUrl.searchParams.get('code') ?? undefined, }); ``` ## Local stdio server Use `createStdioMcpClient()` with `createMcpTools()` for a local MCP process: ```ts import { createMcpTools, createStdioMcpClient } from '@fabric-harness/sdk'; const client = createStdioMcpClient({ command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '/workspace'], }); const tools = await createMcpTools(client, { prefix: 'workspace', effect: 'read', source: 'filesystem', }); await session.prompt('Summarize the workspace', { tools }); await client.close(); ``` Tool names are prefixed and normalized before they enter the model toolset. Apply `toolPolicy` rules to the generated names when an MCP server exposes write or execute effects. ## Why MCP MCP is becoming a converging standard for tool/resource exchange across agent ecosystems. Wiring Fabric agents and MCP servers together means you can: - give Fabric agents access to a growing catalog of MCP-served tools, - use the same Fabric policy and approval controls for local and remote MCP tools, - switch between remote and stdio transports without changing the session prompt loop, - expose the same governed job and agent operations to IDEs, automation clients, and agent peers. --- # Channel integrations Canonical: https://harness.techfabric.com/docs/ecosystem/channels Signed event ingress and outbound tools for persistent agents, which is how a webhook becomes a conversation with memory. Channels verify provider webhooks, normalize an event, derive a stable conversation key, and dispatch it to a persistent Fabric agent. Provider event IDs become dispatch IDs for deduplication, while tenant and actor identity flow into the audit trail. ```sh pnpm add @fabric-harness/channels @fabric-harness/sdk ``` | Channel | Stable instance key | Support | | --- | --- | --- | | [Buzz](/docs/ecosystem/channels/buzz) | Community/channel/thread | First-party preview adapter | | [Discord](/docs/ecosystem/channels/discord) | Guild/channel/thread | First-party adapter | | [Facebook Messenger](/docs/ecosystem/channels/messenger) | Page/sender | First-party adapter | | [GitHub](/docs/ecosystem/channels/github) | Repository/issue or PR | First-party adapter | | [Google Chat](/docs/ecosystem/channels/google-chat) | Space/thread | First-party adapter | | [Intercom](/docs/ecosystem/channels/intercom) | Workspace/conversation | First-party adapter | | [Linear](/docs/ecosystem/channels/linear) | Organization/issue | First-party adapter | | [Microsoft Teams](/docs/ecosystem/channels/teams) | Tenant/conversation/thread | First-party adapter | | [Notion](/docs/ecosystem/channels/notion) | Workspace/page or database | First-party adapter | | [Resend](/docs/ecosystem/channels/resend) | Tenant/email | First-party adapter | | [Salesforce Marketing Cloud](/docs/ecosystem/channels/salesforce-marketing-cloud) | Business unit/contact or send | First-party adapter | | [Shopify](/docs/ecosystem/channels/shopify) | Shop/resource | First-party adapter | | [Slack](/docs/ecosystem/channels/slack) | Team/channel/thread | First-party adapter and example | | [Stripe](/docs/ecosystem/channels/stripe) | Connected account/customer or payment resource | First-party adapter | | [Telegram](/docs/ecosystem/channels/telegram) | Bot/chat/topic | First-party adapter | | [Twilio](/docs/ecosystem/channels/twilio) | Account/sender/recipient | First-party SMS and WhatsApp adapter | | [WhatsApp](/docs/ecosystem/channels/whatsapp) | Business account/phone/sender | First-party Meta Cloud API adapter | | [Zendesk](/docs/ecosystem/channels/zendesk) | Account/ticket | First-party adapter | | Generic webhook | Caller-provided conversation ID | Direct `fh add channel webhook` scaffold | First-party means Fabric owns the provider adapter, runs it through the shared Node and edge-safe channel contract, and publishes a dependency-aware `fh add channel ` recipe. Buzz is marked preview because its transport depends on the evolving relay protocol; its authentication, replay, identity, and recipe contracts are maintained. ## Package and version policy Adapters are dependency-free `@fabric-harness/channels/` subpaths implemented with Fetch and Web Crypto. An adapter becomes a separate package only when a required provider SDK, runtime incompatibility, or independent release cadence makes that necessary. Import `channelCompatibility` from `@fabric-harness/channels/compatibility` for the machine-readable API matrix. Deprecated adapters receive at least 180 days of notice and are removed only in a major release. Channels dispatch to `.fabricharness/agents/`, not finite jobs. See [Persistent agents](/docs/building/persistent-agents) for the durable submission model. --- # Databases Canonical: https://harness.techfabric.com/docs/ecosystem/databases Durable session stores and governed database connectivity, covering where an agent's state lives and what it may query. Fabric uses databases for durable runtime state and exposes separate, policy-gated tools for agent data access. Do not give the model raw database credentials. | Database | Runtime use | Agent data access | | --- | --- | --- | | [libSQL](/docs/ecosystem/databases/libsql) | Unified local or remote bundle through `libsqlPersistence()`. | Scoped tool guide. | | [MongoDB](/docs/ecosystem/databases/mongodb) | Unified bundle through `mongodbPersistence()`. | First-party collection-bound find tools. | | [MySQL](/docs/ecosystem/databases/mysql) | Unified bundle through `mysqlPersistence()`. | First-party fixed-statement tools. | | [Postgres](/docs/ecosystem/databases/postgres) | Unified session, submission, stream, attachment, run/event, and cost persistence through `postgresPersistence()`. | First-party fixed-statement tools. | | [Redis](/docs/ecosystem/databases/redis) | Project-owned coordination/store implementation. | First-party namespaced get/set tools. | | [Supabase](/docs/ecosystem/databases/supabase) | Reuse `postgresPersistence()` with the direct Postgres connection. | RLS-aware table/RPC tool guide. | | [Turso](/docs/ecosystem/databases/turso) | Reuse `libsqlPersistence()` with a remote URL/token. | Parameterized libSQL tool guide. | | [Valkey](/docs/ecosystem/databases/valkey) | Reuse `redisPersistence()` with a Redis-protocol client. | Namespaced command tool guide. | | [Databricks Lakebase](/docs/ecosystem/databases/lakebase) | Sessions, submissions, conversation streams, and attachments for Databricks Apps. | Use governed Databricks SQL and Unity Catalog tools separately. | | [SQLite](/docs/ecosystem/databases/sqlite) | Local durable sessions through Node configuration. | First-party fixed-statement tools. | See [Session stores](/docs/reference/session-stores) for the complete persistence contract. Install governed data tools with `pnpm add @fabric-harness/databases` or scaffold a complete provider module with `fh add database postgres`, `mysql`, `mongodb`, `redis`, or `sqlite`. Postgres and Lakebase, MySQL, MongoDB, libSQL/Turso, Redis/Valkey, SQLite, and Supabase/Postgres provide durable Fabric stores. Data tools and session persistence remain separate so model-facing access never receives runtime-store credentials implicitly. --- # Agent registry and governance Canonical: https://harness.techfabric.com/docs/building/agent-registry Register immutable agent versions, bound authority, budgets, and external identities. `@fabric-harness/agent-registry` provides runtime-neutral governance contracts for agent catalogs. It does not execute agents or replace Platform actions. It validates definitions, immutable versions, tenant registrations, capability grants, autonomy ceilings, enrollment, external identities, and privacy-safe evidence while keeping vertical-specific scope in the owning application. ```sh pnpm add @fabric-harness/agent-registry zod ``` ```ts import { agentCapabilityGrantBaseSchema, agentDefinitionSchema, clampRoute, } from '@fabric-harness/agent-registry'; const definition = agentDefinitionSchema.parse({ agentDefinitionId: 'reviewer', name: 'reviewer', displayName: 'Governed reviewer', description: 'Reviews a bounded subject and proposes governed actions.', inputKinds: ['review.request'], outputKinds: ['review.result'], createdAt: new Date().toISOString(), }); const grant = agentCapabilityGrantBaseSchema.parse({ grantId: 'reviewer-grant', readTools: ['read-subject'], proposalActions: ['propose-review'], executionActions: [], }); const route = clampRoute('approval-required', { status: 'auto-executed', actionInvocationId: 'candidate-invocation', }); ``` The registry deliberately separates read, propose, and execute authority. A registration's autonomy is a ceiling: policy may narrow it but cannot widen it. Persist only validated, hash-pinned versions; mint short-lived execution principals per run; and route mutations through governed TechFabric Platform actions. External channel identities remain untrusted candidates until an application resolves an active binding and validates the applicable grant. Use zod `.extend()` in an application package to attach tenant or subject scope. Do not add vertical domain fields to the shared registry. The runnable credential-free fixture is `examples/agent-registry` in the restricted source repository. --- # Mounting agents in your own server Canonical: https://harness.techfabric.com/docs/building/agent-router Serve the persistent-agent HTTP surface from an application that already owns its routes, using createFabricAgentRouter. Harness serves agents from its own runtimes — `fh dev`, the Node build artifact, the Cloudflare worker. `createFabricAgentRouter()` covers the other direction: an application that already owns an HTTP surface, and wants Harness agents on it, under its own paths and behind its own middleware. ```ts import { createFabricAgentRouter } from '@fabric-harness/sdk'; const router = createFabricAgentRouter(backend, { basePath: '/api' }); const handled = await router.handle(request); if (handled) return handled; // …your application keeps everything else. ``` The router is runtime-neutral — `Request`, `Response`, `URL`, and plain objects — so it runs on Node, Cloudflare, Deno, Bun, or any fetch-capable host, and mounts in any framework that can hand it a `Request`. ## Two entry points | Method | Unmatched path | Use when | | --- | --- | --- | | `handle(request)` | resolves `undefined` | You compose routes and want to fall through. | | `fetch(request)` | resolves `404` | Your framework expects a total handler. | ## What the router owns Everything a client observes: route parsing, method dispatch, request validation, response shape, status codes, and the `202` admission receipt. The [streaming protocol](/docs/reference/streaming-protocol) reference documents that wire contract, and the router is the same implementation the built-in runtimes follow — mounting agents yourself does not put you on a different protocol. ## What the backend owns A `FabricAgentRouterBackend` supplies durable submission, conversation reads, and lifecycle: ```ts import type { FabricAgentRouterBackend } from '@fabric-harness/sdk'; const backend: FabricAgentRouterBackend = { async resolveAgent(name) { return { found: registry.has(name), exposed: true }; }, async admit(input) { // Capture the stream position BEFORE admitting. const offset = await streams.nextOffset(input); const submissionId = await runner.admit(input); return { submissionId, offset }; }, async readConversation(address) { /* … */ }, async getSubmission(address) { /* … */ }, async abort(address) { /* … */ }, }; ``` `loadInstance`, `deleteInstance`, `streamUpdates`, and `handleSchedules` are optional. A route whose backend method is absent returns `404` rather than a misleading `405`, and `updatesUrl` appears in the receipt only when `streamUpdates` exists — the router never points a client at a route the host does not serve. ## Two invariants worth stating **Capture the offset before admitting.** The receipt's `offset` is the position a client resumes from; reading it must return this delivery and the reply. Returning `"0"` instead makes every client re-read the whole conversation on every send. **An unexposed agent must answer like a missing one.** `resolveAgent` returning `{ found: true, exposed: false }` produces exactly the `404` that `{ found: false }` does, so probing cannot enumerate private agents. ## Errors A backend method that throws becomes `500` with a generic body. Storage and execution details — connection strings, stack traces, internal identifiers — never reach the caller. Map your own domain failures to responses inside the backend if you need callers to distinguish them. ## Mount paths `basePath` is stripped before matching, so the backend never learns where the router lives. URLs in the receipt are relative to the router, which means the host composes its own prefix rather than the router guessing at it. ## When not to use this If you are deploying with `fh build`, you already have this surface — the Node and Cloudflare targets serve it. Reach for the router when Harness is a component inside a larger service you own, not when it is the service. ## See also - [`examples/with-mounted-agent-router`](/docs/reference/source-access) — a runnable version with an in-memory backend. - [Streaming protocol](/docs/reference/streaming-protocol) — the wire contract this router implements. - [HTTP applications](/docs/building/http-applications) — adding your own routes to a Harness-owned server instead. --- # Agent Anatomy Canonical: https://harness.techfabric.com/docs/building/anatomy The metadata-first shape of a TechFabric Harness agent — default and strict variants of the same call. import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; TechFabric Harness finite agents are metadata-first. The canonical default export is `defineAgent({...})`, which provides lazy `prompt`, `skill`, `task`, `shell`, and `session` helpers. The runtime admits these finite definitions as jobs/runs, so they live under `.fabricharness/jobs/` and use `/jobs` routes. Persistent, addressable agents use `createAgent()` under `.fabricharness/agents/`. - **Default** — `import { defineAgent } from '@fabric-harness/sdk'`. Injects headless defaults (`runtime: 'stateless'`, `sandbox: 'virtual'`, `loopRuntime: pi-agent-core`, `compaction: { enabled: true }`) on every `init()` call. The fast path for prototypes, webhooks, edge agents. - **Strict** — `import { defineAgent } from '@fabric-harness/sdk/strict'`. Same call shape, **no defaults injected**. Required for Temporal-backed durability (replay determinism) and recommended for compliance/audit workloads. Both produce the same `AgentDefinition` and run identically through `fh run`, `fh build`, `fh describe`, and any deploy target. ## Recommended finite-agent definition ```ts import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'ask', input: schema.object({ question: schema.string() }), output: schema.string(), async run({ input, prompt }) { return prompt(input.question); }, }); ``` ## Invoke another finite job Use the job context's `invoke()` for child work. The configured runtime admits a new run without an HTTP round trip and propagates the parent run, tenant, and actor. Cycles and nesting beyond 16 jobs are rejected before admission. ```ts title=".fabricharness/jobs/account-review.ts" import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ input: schema.object({ accountId: schema.string() }), run: async ({ input, invoke }) => { const receipt = await invoke({ job: 'collect-account-evidence', input: { accountId: input.accountId }, idempotencyKey: `evidence:${input.accountId}`, }); return { evidenceRunId: receipt.runId }; }, }); ``` When a definition has a declared or loader-registered name, `invoke(definition, { input })` is also available. The top-level `invoke()` export remains available in application routes, channels, and schedules. Use the named form across module boundaries to avoid importing executable job modules. ## Middleware and run identity Job middleware wraps `run` in declaration order. It receives the same typed context and is suitable for tracing, shared authorization, metrics, and transaction boundaries. `context.run` contains the stable run ID, job name, parent chain, tenant, and actor when the job was admitted through a server; it is absent for a direct handler call in a unit test. ```ts import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'account-review', input: schema.object({ accountId: schema.string() }), middleware: [ async ({ run }, next) => { console.log({ event: 'started', runId: run?.runId }); const output = await next(); console.log({ event: 'completed', runId: run?.runId }); return output; }, ], async run({ input, prompt }) { return prompt(`Review account ${input.accountId}`); }, }); ``` Each middleware may call `next()` once. It may also short-circuit by returning a typed output. The runtime and default session are initialized on the first helper call. Add `init: { sandbox: 'local' }` to set initialization options, or call `session('review')` when you need a named session. ## Lower-level job definition ```ts import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'ask', input: schema.object({ question: schema.string() }), output: schema.string(), triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init()).session(); return session.prompt(input.question); }, }); ``` `init()` defaults are injected automatically. Override any of them by passing a value: `init({ runtime: 'inline', sandbox: 'docker' })`. ```ts import { defineAgent, schema } from '@fabric-harness/sdk/strict'; export default defineAgent({ name: 'ask', input: schema.object({ question: schema.string() }), output: schema.string(), triggers: { webhook: true }, run: async ({ init, input }) => { const fabric = await init({ runtime: 'temporal', sandbox: 'local', compaction: { enabled: false }, }); const session = await fabric.session(); return session.prompt(input.question); }, }); ``` Every option is declared in source. Nothing implicit. Required for Temporal — auto-compaction would break replay determinism. The `defineAgent` call shape is identical across both imports. Plain default-exported functions are intentionally rejected because a definition builder keeps jobs discoverable and gives the CLI typed metadata. Top-level finite-definition `instructions`, `tools`, `policy`, `costBudget`, and approval timeout are applied to `init()`. A call-provided role overrides definition instructions; definition policies and budgets remain security floors, while call policy can add denials and approval requirements. ## The `FabricContext` When the CLI invokes an agent it provides: ```ts interface AgentRunContext { payload: TInput; input: TInput; init(options?: AgentInit): Promise; run?: JobInvocationContext; session(id?: string): Promise; prompt(text: string): Promise; skill(name: string): Promise; task(text: string): Promise; shell(command: string): Promise; invoke(request: NamedJobInvocation): Promise; } ``` Use `input` for typed, schema-validated values inside `run`: ```ts run: async ({ init, input }) => { const fabric = await init(); const session = await fabric.session(); return session.prompt(input.question); } ``` ## `init()` options Agents from either entrypoint call the same `init()` to construct the runtime: ```ts const fabricAgent = await init({ id: 'agent-1', model: 'openai/gpt-5.5', role: 'engineer', // Markdown role file under .fabricharness/roles/ sandbox: 'local', // 'virtual' | 'empty' | 'local' | 'docker' | 'cloudflare' | factory autonomy: { mode: 'background', onMissingInput: 'assume', onApprovalUnavailable: 'fail', onCredentialMissing: 'fail', }, }); ``` When using the bare `@fabric-harness/sdk` import you typically omit `runtime`, `sandbox`, and `loopRuntime` — those defaults are injected. Override anything you like; defaults fill the gaps you don't set. > ⚠️ **Temporal users:** if you set `runtime: 'temporal'` from the bare import, the SDK emits a one-time `console.warn`. Auto-compaction is non-deterministic across Temporal replay. Either switch to `@fabric-harness/sdk/strict` or pass `compaction: { enabled: false }` explicitly. ## Triggers Declare triggers inside `defineAgent({...})`. The Node and Cloudflare server targets respect: ```ts export default defineAgent({ name: 'triage', triggers: { webhook: true, // POST /jobs/triage schedule: '*/15 * * * *', // Node scheduler or Cloudflare Cron Trigger // cli: true, // CLI-only, default true }, async run(ctx) { return ctx.input; }, }); ``` ## Where to go next - [SDK entrypoints, runtimes, and targets](/docs/reference/sdk-entrypoints-runtimes-targets) — when to swap to `/strict`. - [Enterprise controls](/docs/building/enterprise-controls) — definition-level policy, tools, budgets, and approvals. - [Sessions and prompts](/docs/building/sessions-prompts) — the core call surface. - [Skills](/docs/building/skills) and [Roles](/docs/building/roles). - [Tools](/docs/building/tools) and [Commands](/docs/building/commands). - [Sandboxes](/docs/building/sandboxes). --- # Approvals Canonical: https://harness.techfabric.com/docs/building/approvals Pause an agent mid-run until a person approves a risky action, and resume from the same session state once they do. Approvals turn an autonomous agent into one that asks for confirmation at risky moments. The framework persists the request, suspends the relevant code path, and resumes when a human (or another system) resolves it. ## Declarative routing — `approvalRules` Most users want approvals tied to *specific tools*, not scattered through agent code. Declare the rules once in policy and the loop pauses for approval before dispatch: ```ts const fabric = await init({ policy: { toolPolicy: { approvalRules: [ { pattern: 'submit_*', audience: 'reviewer', reason: 'Review before submission of ${name}' }, { pattern: 'delete_*', audience: 'project-admin', ttlSeconds: 3600 }, { pattern: 'finalize_*', audience: 'compliance-team' }, ], }, }, }); ``` `audience` is an opaque string id. fabric-harness never decides who an audience maps to — your host application's identity layer (UI, SSO, RBAC) does that mapping. Rules also work on `commandPolicy.approvalRules` for `bash` invocations. When the agent calls a matching tool, fabric-harness emits `approval_requested` with the audience id, the templated reason, and the TTL. The host UI renders the request to the right humans; on `approval_granted` the loop continues; on denial or TTL it throws. This is sugar over the imperative `session.approval.request()` API — which stays available as the escape hatch for ad-hoc cases. Approved durable responses expose `ApprovalResponse.grant`. The grant binds the approval id, logical tool-call id, canonical input digest, executing principal, approvers, decision time, and optional expiry. Memory, file, SQLite, Postgres, Cloudflare Durable Object, and Temporal paths preserve the same shape. Denied responses never carry a grant. A crash retry may replay the same bound operation; different input, call id, or principal fails closed. ## Webhook subscriptions Agents that should wake on inbound events (event bus, queue, external SaaS webhook) use `defineWebhookSubscription`: ```ts import { defineAgent, defineWebhookSubscription } from '@fabric-harness/sdk'; export default defineAgent({ name: 'data-validator', triggers: { webhook: true }, subscriptions: [ defineWebhookSubscription<{ recordId: string }>({ id: 'on-record-created', events: ['record.created'], handler: async ({ payload, idempotencyKey, headers }) => { // ...invoke whatever your host application exposes. }, }), ], async run() { /* ... */ }, }); ``` `fh dev` and generated Node builds expose each subscription at `POST /agents//subscriptions/`. Set `FABRIC_HARNESS_WEBHOOK_SECRET` to require an `X-Fabric-Signature: sha256=` header on every delivery. The server dedupes by `Idempotency-Key` for at-least-once event buses and emits a `webhook_received` event into the session log for audit. `fh subscriptions [agent]` lists registered subscriptions across the workspace. ## Request an approval `session.approval.request()` returns `true` when the approver allows the action. It throws a `FabricError` (`APPROVAL_DENIED` or `APPROVAL_REQUIRED`) on denial or timeout — wrap in try/catch when you want to handle rejection gracefully. ```ts import { FabricError } from '@fabric-harness/sdk'; try { await session.approval.request({ reason: 'About to push changes to GitHub', subject: 'git push origin main', risk: 'high', timeoutMs: 24 * 60 * 60 * 1000, // 24h }); await session.shell('git push origin main'); } catch (error) { if (error instanceof FabricError && error.code === 'APPROVAL_DENIED') { throw new Error(`Push blocked: ${error.message}`); } throw error; } ``` The available fields are: | Field | Type | Description | |---|---|---| | `reason` | `string` | Human-readable reason shown to the approver. | | `subject` | `string?` | Short subject line for UIs. Defaults to `'custom'`. | | `risk` | `'low' \| 'medium' \| 'high'?` | Drives escalation policy. | | `timeoutMs` | `number?` | Override the session's default approval timeout. | | `onApproval` | `ApprovalCallback?` | Per-call approval handler. Falls back to session/agent `onApproval`. | ## Resolve from the CLI ```sh fh approvals --pending fh approve --actor preetham # or fh reject --actor preetham --reason "Wrong branch" ``` For a deployed Node or Databricks App, use the tenant-scoped remote surface. Omitting the session id discovers approvals across only the sessions visible to the authenticated tenant: ```sh fh approvals \ --url "$FABRIC_HARNESS_APP_URL/api" \ --token-env DATABRICKS_OAUTH_TOKEN \ --tenant acme fh approve \ --url "$FABRIC_HARNESS_APP_URL/api" \ --token-env DATABRICKS_OAUTH_TOKEN \ --tenant acme ``` The `audience` value is a routing label, not an authorization grant. The host must map that label to an authenticated group or role and grant `approval:write` only to eligible approvers. The server always enforces tenant isolation and records the authenticated voting principal. ## Notify approvers Attach `approvalNotificationHandler()` to the agent's `onEvent` callback. It receives requested, escalated, and resolved events, retries transient failures, deduplicates deliveries, and records delivery outcomes through the audit hook. Notification failures never resolve the approval. ```ts import { approvalNotificationHandler, defineAgent, slackApprovalNotifier, } from '@fabric-harness/sdk'; import { redisApprovalNotificationStore } from '@fabric-harness/node'; const notifyApproval = approvalNotificationHandler({ notifier: slackApprovalNotifier({ webhookUrl: process.env.SLACK_APPROVAL_WEBHOOK_URL!, }), baseUrl: 'https://agents.example.com', store: redisApprovalNotificationStore({ client: redis, namespace: 'production', }), retries: 4, deadLetter: async (record) => { await approvalDeadLetters.insert(record); }, audit: async (record) => { await auditLog.append('approval_notification', record); }, onError: (error, notification) => { logger.error({ error, notificationId: notification.id }); }, }); export default defineAgent({ name: 'release-agent', onEvent: notifyApproval, async run({ prompt }) { return prompt('Prepare the approved release.'); }, }); ``` Use `webhookApprovalNotifier()` for an internal workflow service, PagerDuty bridge, or custom notification worker. Slack and generic webhook destinations receive a bounded public payload: raw tool input, environment values, actor credentials, and destination secrets are excluded. Deep links contain only the session, approval, and tenant identifiers; `/admin` still enforces authentication, tenant isolation, and approval permissions when opened. `inMemoryApprovalNotificationStore()` is suitable for local development. Use `redisApprovalNotificationStore()` across replicas or implement `ApprovalNotificationDeliveryStore` with an atomic claim in the system that owns your notification outbox. A dead-letter callback is strongly recommended in production. ## Durable waits On the Temporal worker target, the approval wait runs as a dedicated workflow and can wait without holding a process. The workflow records its ID on the approval request so `fh approve` and `fh reject` signal the owning workflow. The first denial wins; approvals are deduplicated by actor and resume only after `policy.approvals.requiredApprovals` is reached. An escalation deadline emits `approval_escalated` with the configured notify audience and risk, while the overall timeout remains authoritative. Worker restarts do not lose the timer, votes, or pending request. On the inline runtime, the wait uses the configured session store or callback. To make agents safe on either runtime, declare autonomy fallbacks: ```ts await init({ autonomy: { onApprovalUnavailable: 'fail', // or 'assume-rejected' | 'assume-approved' }, }); ``` ## Logged identities Approvals record both the agent identity and the human actor. Combined with the two-identity actor schema (Entra Agent ID + on-behalf-of user), the audit trail answers "which agent acted, on whose behalf, who approved?" ## See also - [Policies and approvals](/docs/reference/policies-approvals) - [`fh approvals`](/docs/cli/approvals) --- # Artifacts Canonical: https://harness.techfabric.com/docs/building/artifacts Publish files that belong to a session so a later step, another agent or a human reviewer can pick them up by reference. An **artifact** is a session-bound file. Agents publish artifacts as the durable, reviewable output of their work — Markdown reports, JSON results, CSVs, images. ## Publish an artifact ```ts await session.artifact('report.md', markdown, { contentType: 'text/markdown' }); ``` The content can be a string or an in-memory buffer: ```ts await session.artifact('summary.json', JSON.stringify({ ok: true }), { contentType: 'application/json', }); ``` Agents that generate a file in the sandbox first can read it back and publish the bytes: ```ts const bytes = await session.fs.readBytes('/workspace/report.md'); await session.artifact('report.md', bytes, { contentType: 'text/markdown' }); ``` ## Read from the CLI ```sh fh artifacts fh artifact get report.md --out ./reports/report.md ``` ## What gets persisted The session store records artifact metadata (id, name, content type, byte size, created time) alongside the session entry that produced it. The bytes are stored separately: - **File store** (default): files under `.fabricharness/sessions//artifacts/`. - **SQLite store**: BLOB column. - **Postgres store**: BYTEA column or external blob URL. - **Cloud stores** (designed): Azure Blob / ADLS, S3, R2. ## Patterns - **Reports.** A triage agent publishes `triage-report.md` for reviewers. - **Generated code.** A migration agent publishes the proposed diff as an artifact and asks for approval before applying it. - **Datasets.** A data agent publishes profiled CSVs alongside the prompt that produced them. See also: [`fh artifacts`](/docs/cli/artifacts), [`fh artifact get`](/docs/cli/artifacts). --- # Channels Canonical: https://harness.techfabric.com/docs/building/channels Turn a signed platform webhook from Slack, GitHub or Stripe into an agent dispatch, without writing an ingress service yourself. Channels are how agents get **triggered** by the outside world. A webhook hits `/channels/:name/*`, the handler verifies the signature, normalizes the platform event, and **dispatches** to a persistent agent keyed by a stable conversation id. Outbound actions are tools bound at agent init. The core seam lives in `@fabric-harness/sdk`; 17 vendor adapters live in `@fabric-harness/channels` behind subpath exports, so platform SDK code stays out of core. Handlers are written against the Web `Request`/`Response` API and `crypto.subtle`, so the same channel runs on Node and Cloudflare. ## Why channels - **Stateless.** A channel is a route container plus a conversation-id (de)serializer. Session continuity falls out of the key — the same Slack thread → same key → same session. - **Exactly-once.** The platform event id (Slack `event_id`, GitHub `X-GitHub-Delivery`) becomes the `dispatchId`, so a webhook redelivery collapses to a single agent turn via the persistent-run idempotency marker. - **Identity propagation.** The platform user becomes the dispatch `actor` and the team/org becomes the `tenantId` — flowing into the audit trail and into on-behalf-of governance (e.g. Databricks UC). - **Policy-gated outbound.** Outbound actions are `defineTool` tools (`effect: 'write'`), so the agent's `CapabilityPolicy` can gate "can this agent post to Slack". ## Slack A channel lives in `.fabricharness/channels/.ts` and exports a `channel`: ```ts title=".fabricharness/channels/slack.ts" import { createSlackChannel } from '@fabric-harness/channels/slack'; export const channel = createSlackChannel({ signingSecret: process.env.SLACK_SIGNING_SECRET!, agent: 'assistant', // dispatch app mentions / threaded messages here }); ``` The dev server mounts it at `POST /channels/slack/events`. Point your Slack app's **Event Subscriptions → Request URL** there and subscribe to `app_mention`. The handler verifies the `v0` HMAC signature, answers the URL-verification challenge, and dispatches the event keyed by the thread. Bind the reply tool to the thread at agent init — the instance id *is* the thread key: ```ts title=".fabricharness/agents/assistant.ts" import { createAgent } from '@fabric-harness/sdk'; import { parseSlackConversationKey, replyInSlackThread } from '@fabric-harness/channels/slack'; export default createAgent(({ id }) => { const thread = parseSlackConversationKey(id); return { model: 'anthropic/claude-haiku-4-5', tools: [replyInSlackThread(thread, { botToken: process.env.SLACK_BOT_TOKEN! })], }; }); ``` ## GitHub Same shape, different signature scheme (`X-Hub-Signature-256`) and key (`owner/repo//`): ```ts title=".fabricharness/channels/github.ts" import { createGitHubChannel } from '@fabric-harness/channels/github'; export const channel = createGitHubChannel({ secret: process.env.GITHUB_WEBHOOK_SECRET!, agent: 'triage', }); ``` Mounted at `POST /channels/github/webhook`. It acknowledges `ping`, dispatches issue / PR / comment events (with `X-GitHub-Delivery` as the dedupe key, the owner as tenant, the sender as actor), and ignores bot senders to avoid loops. Outbound: `commentOnGitHubIssue(ref, { token })`. ## Other first-party channels Scaffold the provider module, environment template, dependency set, and starter test: ```sh fh add channel discord fh add channel teams fh add channel telegram fh add channel twilio fh add channel whatsapp fh add channel google-chat fh add channel linear fh add channel stripe fh add channel zendesk ``` Each first-party adapter verifies the provider's native request authentication, assigns the provider event ID as `dedupeKey`, derives a stable conversation key, and propagates tenant/actor identity. Provider setup and outbound tool examples are in the [channel catalog](/docs/ecosystem/channels). Microsoft Teams includes Bot Connector key discovery and validates issuer, App ID audience, token lifetime, service URL, and channel endorsement without requiring an application JWT library. The subpath exports include typed webhook payloads and conversation refs for custom routing. The built-in normalization covers the event families an agent commonly needs: | Provider | Normalized events | | --- | --- | | Slack | mentions, messages, edited messages | | GitHub | opened, edited, reopened, synchronized, and issue/PR comments | | Discord | commands and component callbacks | | Teams | messages, message updates, and deletes | | Telegram | messages, edited messages, channel posts, and callback queries | | Twilio | SMS/WhatsApp messages and delivery statuses | | WhatsApp | text messages and delivery/read statuses | | Google Chat | messages and interactions | | Linear | issue and project resource changes | | Notion | workspace entity changes | | Stripe | account and financial resource events | | Zendesk | ticket events | | Intercom | conversation and ticket notifications | | Shopify | versioned commerce webhooks | | Messenger | messages and postbacks | | Resend | inbound and delivery email events | | Salesforce Marketing Cloud | signed ENS event batches | Delivery-status dedupe keys include both message ID and status, so a `sent` event cannot suppress a later `delivered` or `read` event. ## Authoring your own channel A channel is `defineChannel({ routes, conversationKey, parseConversationKey })`. The SDK provides the building blocks: `verifyHmacSha256` (constant-time), `hexToBytes`, `conversationKey` / `parseConversationKey` (url-safe), and `readJsonBody` (raw bytes for HMAC **and** parsed JSON from a single read). Inside a route handler, call `ctx.dispatch(agent, { instanceId, input, dedupeKey, tenantId, actor })`. ## See also - Example: [`examples/with-slack-channel`](/docs/reference/source-access) — Slack mention → agent → in-thread reply, end to end. - Example: [`examples/with-channel-adapters`](/docs/reference/source-access) — all 18 verified ingress adapters and their governed outbound tools in one runnable workspace. - [Persistent agents](/docs/building/persistent-agents) — channels dispatch to `createAgent(...)` instances. - [Triggers](/docs/reference/triggers) — gating which agents accept inbound events. --- # Commands and Capabilities Canonical: https://harness.techfabric.com/docs/building/commands Scope which shell commands an agent may run and which secrets it can see, per session rather than per deployment. A **command** in TechFabric Harness is a shell-level capability you explicitly grant to a session — not a generic "run anything" door. Use `defineCommand` from `@fabric-harness/sdk` to declare one. ## Declaring commands ```ts import { defineCommand } from '@fabric-harness/sdk'; const npm = defineCommand('npm'); const git = defineCommand('git'); const gh = defineCommand('gh', { env: { GH_TOKEN: process.env.GH_TOKEN, }, }); ``` A `defineCommand` declaration captures: - the binary name, - environment variables to inject, - working directory defaults, - timeouts and stdin handling. ## Granting commands per call ```ts await session.prompt('Fix the failing tests', { commands: [npm, git, gh], }); ``` The model can only run shell commands whose binary matches one of the declared commands. Anything else fails with a capability error. ## Secrets Use `secret()` to mark a value as a credential reference. The runtime resolves it at exec time and never echoes it into model context. Exported from `@fabric-harness/sdk`. ```ts import { defineCommand, secret } from '@fabric-harness/sdk'; const gh = defineCommand('gh', { env: { GH_TOKEN: secret('GH_TOKEN') }, }); ``` `secret()` is intentionally a token, not the value: it can be passed around without leaking its content into logs, traces, or the LLM context. ## Capability policy Use `policy` to enforce filesystem, command, tool, network, timeout, and approval rules. Policies can be set on `init()`, a session, or an individual prompt; narrower call-level policy is combined with definition-level controls. ```ts await session.prompt('Fix the tests', { policy: { filesystem: { read: ['/workspace/**'], write: ['/workspace/src/**', '/workspace/tests/**'], }, commandPolicy: { allow: ['npm test', 'git diff', 'git status'], requireApproval: ['git push', 'npm publish', 'terraform apply'], }, network: { mode: 'allowlist', hosts: ['api.github.com'], }, maxCommandTimeoutMs: 120_000, }, }); ``` The runtime applies policy at both the tool layer and the sandbox boundary. See [Policies and approvals](/docs/reference/policies-approvals) for deny rules, approval routing, and composition behavior. --- # Connector catalog Canonical: https://harness.techfabric.com/docs/building/connector-catalog Sandbox, MCP, knowledge-base, data, Azure, and Databricks connector options. TechFabric Harness connectors are intentionally modular. The core SDK owns the stable agent/session/tool/sandbox contracts; provider packages and project-local adapters own provider SDKs, credentials, lifecycle, and live compatibility. There are three connector forms: | Form | Use when | Example | |---|---|---| | Package helper | Fabric already ships a dependency-free helper or REST client. | `daytonaSandbox`, `databricksSqlTool`, `foundryAgentTool` | | Recipe via `fh add` | Provider SDK shape or project conventions need local code. | `fh add daytona --print` | | Direct SDK primitive | No connector file is needed. | `fumadocsSource`, `connectMcpServer` | Discover scaffold and guide recipes from one catalog: ```sh fh add fh add --json ``` The JSON form returns stable IDs such as `scaffold:channel:slack` and `guide:mcp:github-mcp`, plus the exact command for each entry. Catalog entries also include declared dependencies. Direct scaffolds install missing dependencies with the detected package manager; use `--no-install` for manifest-only changes. Guide recipes remain side-effect free unless `--install-deps` is supplied. ## What `fh add` installs Named recipes either add a maintained package adapter or generate a project-local connector that uses the provider SDK directly. The command preview lists every dependency and file before installation: ```sh fh add slack --print fh add notion-channel --print fh add --json ``` Use the [ecosystem catalog](/docs/ecosystem) to open the provider-specific setup, identity mapping, webhook verification, policy, and validation instructions. ## Quickstart for any provider If no pre-built adapter exists, use `fh add --category ` and pipe to your coding agent: ```sh fh add https://e2b.dev --category sandbox | claude fh add https://api.notion.com --category data | cursor-agent fh add https://docs.linear.app --category mcp | codex ``` The CLI emits the canonical category spec (`sandbox.md`, `mcp.md`, or `data.md` shipped with `@fabric-harness/sdk`) along with a "build me a connector for this URL" header. The agent reads the provider's docs, follows the spec literally, and writes a single TypeScript file at `./connectors/.ts`. No PR to fabric-harness needed — the file lives in your project. When fabric-harness ships a first-party recipe for the provider, prefer the named slug: ```sh fh add daytona | claude fh add linear-mcp | claude ``` ### Auto-PR mode `fh add daytona --pr` opens a draft GitHub PR with a stub connector file (committed to a `connector/` branch) and the canonical spec embedded in the PR body. You (or your coding agent) push commits that flesh out the stub. Requires the `gh` CLI and a configured remote. ```sh fh add daytona --pr fh add https://your-provider.example.com --category sandbox --pr --pr-branch=connector/your-provider ``` ### Validating connectors `fh doctor --connectors` walks `connectors/` and `.fabricharness/connectors/` and flags files that are missing exports, lack the `@fabric-harness/*` import, or are otherwise malformed: ```sh fh doctor --connectors # ✓ connector:daytona.ts: ./connectors/daytona.ts # ✗ connector:broken.ts: missing @fabric-harness/* import # ✓ connectors: 1/2 healthy ``` ## Install packages Core connector helpers: ```sh npm install @fabric-harness/sdk @fabric-harness/connectors ``` Cloud-specific packages: ```sh npm install @fabric-harness/azure npm install @fabric-harness/databricks ``` Provider SDKs stay in your app, not in `@fabric-harness/sdk`: ```sh npm install @daytona/sdk npm install @e2b/code-interpreter ``` ## Sandbox connectors Sandbox connectors adapt remote execution providers to Fabric's `SandboxEnv` contract: file operations, shell execution, cwd scoping, cleanup, and optional snapshots. | Connector | Package helper | Recipe | Validation | Notes | |---|---|---|---|---| | Daytona | `daytonaSandbox()` / `daytonaSandboxFactory()` from `@fabric-harness/connectors` | `fh add daytona` | `FABRIC_DAYTONA_TEST=1` | Wraps an initialized Daytona sandbox. | | E2B | `e2bSandbox()` | `fh add e2b` | `FABRIC_E2B_TEST=1` | Maps E2B command and file APIs. | | Modal | `modalSdkSandbox()` | `fh add modal` | `FABRIC_MODAL_TEST=1` | Native Modal TypeScript SDK process/filesystem adapter. | | Vercel Sandbox | `vercelSandbox()` | `fh add vercel` | `FABRIC_VERCEL_TEST=1` | Native SDK command/filesystem adapter with reconnect and streamed output. | | Custom provider | `remoteSandbox()` / `remoteSandboxEnv()` | `fh add --category sandbox --print` | `validateSandboxAdapter(env)` | Keep provider SDK and credentials in project code. | ### Daytona example ```ts import { Daytona } from '@daytona/sdk'; import { daytonaSandbox } from '@fabric-harness/connectors'; const client = new Daytona({ apiKey: process.env.DAYTONA_API_KEY }); const remote = await client.create(); const fabric = await init({ sandbox: daytonaSandbox(remote, { cleanup: true }), }); ``` ### Validate any sandbox adapter ```ts import { validateSandboxAdapter } from '@fabric-harness/connectors'; await validateSandboxAdapter(env); ``` The validator runs a smoke contract: `mkdir`, `writeFile`, `readFile`, `exec`, and `rm`. See [Sandbox connectors](/docs/building/sandbox-connectors) for the full adapter guide. ## MCP connectors MCP connectors expose remote tools to agents. Use `connectMcpServer(name, options)` from `@fabric-harness/sdk` (or `/strict` if you prefer). | Connector | Recipe | Pattern | |---|---|---| | GitHub MCP | `fh add github-mcp --print` | Hosted MCP with bearer token. | | Mintlify MCP | `fh add mintlify-mcp --print` | Streamable HTTP MCP endpoint for a docs site when available. | | Linear MCP | `fh add linear-mcp --print` | Hosted MCP with API token. | | Slack MCP | `fh add slack-mcp --print` | Hosted or self-hosted bridge. | | Custom MCP | `fh add --category mcp --print` | Reads provider docs and generates a connector. | Example: ```ts import { connectMcpServer } from '@fabric-harness/sdk'; const github = await connectMcpServer('github', { url: 'https://mcp.github.com/mcp', transport: 'streamable-http', headers: { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` }, }); try { const session = await (await init({ tools: github.tools })).session(); await session.prompt('Find open issues tagged bug.'); } finally { await github.close(); } ``` ## Knowledge-base connectors Knowledge-base connectors mount docs/content into a sandbox as files. Agents then use `read`, `grep`, and `glob` instead of a retrieval pipeline. | Source | Helper | Recipe | Notes | |---|---|---|---| | Local Markdown/MDX | `localDirectorySource()` | none | General local docs. | | Fumadocs | `fumadocsSource()` | `fh add fumadocs --print` | Strips frontmatter by default. | | Mintlify local checkout | `mintlifySource()` | none | Includes `docs.json` nav. | | HTTP docs | `httpFilesystemSource()` | none | Fetch URLs into files. | | Cloudflare R2 | `r2FilesystemSource()` from `@fabric-harness/sdk/cloudflare` | docs example | Worker/R2 deployments. | | S3-compatible | `s3FilesystemSource()` from `@fabric-harness/connectors` | none | Structural object-store client. | | Azure Blob | `azureBlobFilesystemSource()` from `@fabric-harness/connectors` | none | Structural blob client. | Example: ```ts import { defineAgent, fumadocsSource, withFilesystemSources } from '@fabric-harness/sdk'; export default defineAgent<{ question: string }>({ run: async ({ init, input }) => { const sandbox = withFilesystemSources('virtual', [{ mountAt: '/workspace/docs', source: fumadocsSource('./apps/docs/content/docs'), }]); const session = await (await init({ sandbox })).session(); return await session.prompt(`Answer using /workspace/docs: ${input.question}`); }, }); ``` ## Data connectors Data connectors should expose narrow tools, not raw credentials or arbitrary network access. | Connector | Package/helper | Recipe | Notes | |---|---|---|---| | Postgres | project-local `ToolDef`/command | `fh add postgres --print` | Prefer read-only credentials and row/time limits. | | Notion | hosted MCP or REST command | `fh add notion --print` | Hosted MCP when available; REST adapter otherwise. | | Databricks SQL | `databricksSqlReadTool()` / `databricksSqlTool()` | see [Databricks](/docs/deployment/databricks) | SELECT-only reads by default; broader statements require an exact allowlist or server-side validator. | | Databricks Jobs | `databricksRunJobTool()` | see [Databricks](/docs/deployment/databricks) | Trigger existing jobs; requires a `runPolicy` allowlist. | | Databricks Lakeflow | `databricksLakeflowTools()` | see [Databricks](/docs/deployment/databricks) | List/status by default; start/stop require a pipeline allowlist. | | Databricks AI Functions | `databricksAiQueryTool()` | see [Databricks](/docs/deployment/databricks) | In-warehouse inference against explicitly allowed serving endpoints. | | Unity Catalog | `unityCatalogTablesTool()` | see [Databricks](/docs/deployment/databricks) | Read catalog/table metadata. | | MLflow | `databricksMlflowLogMetricTool()` / `databricksMlflowLogParamTool()` | see [Databricks](/docs/deployment/databricks) | Write telemetry only to construction-time allowed run IDs. | ## Azure and Foundry connectors Azure helpers live in `@fabric-harness/azure`: | Helper | Purpose | |---|---| | `AzureOpenAIModelProvider` | Azure OpenAI model calls. | | `createAzureBlobArtifactStore()` | Blob-backed artifacts. | | `createAzureKeyVaultSecretResolver()` | Runtime secret resolution. | | `FoundryAgentServiceClient` | Foundry Agent Service REST client. | | `foundryAgentTool()` | Invoke a Foundry agent from a Fabric agent. | | `foundryAgentLifecycleTools()` | Create/update/delete Foundry agents as gated tools. | | `azureContainerAppsJobTool()` | Start existing Container Apps Jobs. | | `azureAksRunCommandTool()` | AKS Run Command. | | `azureContainerInstanceExecTool()` | ACI exec-session creation. | See [Azure](/docs/deployment/azure) and [Foundry Hosted Agents](/docs/deployment/foundry-hosted-agent). ## `fh add` List recipes: ```sh fh add ``` Print one: ```sh fh add daytona --print fh add github-mcp --print fh add postgres --print ``` Generate from provider docs: ```sh fh add https://example.com/provider/docs --category sandbox --print ``` Categories: | Category | Output shape | |---|---| | `sandbox` | `SandboxEnv` / `SandboxFactory` | | `mcp` | `connectMcpServer()` wrapper | | `kb` | `FilesystemSource` | | `data` | `ToolDef`, `Command`, or MCP wrapper | ## Live tests Connector live tests are opt-in. See [Live tests](/docs/reference/live-tests) for the full matrix. ```sh FABRIC_DAYTONA_TEST=1 DAYTONA_API_KEY=... pnpm --filter @fabric-harness/connectors test FABRIC_AZURE_FOUNDRY_TEST=1 AZURE_FOUNDRY_PROJECT_ENDPOINT=... AZURE_TOKEN=... pnpm --filter @fabric-harness/azure test FABRIC_DATABRICKS_TEST=1 DATABRICKS_HOST=... DATABRICKS_TOKEN=... pnpm --filter @fabric-harness/databricks test ``` ## Security checklist - Keep provider credentials in env, managed identity, Key Vault, or secret manager. - Never put tokens in prompts, payloads, session history, artifacts, or build manifests. - Prefer read-only credentials for data tools. - Treat sandbox execution, cloud control-plane actions, and data writes as `execute`/`write` effects. - Gate destructive actions with Fabric policy approvals. - Add unit tests with fake provider objects and live tests behind env gates. --- # Dynamic Agents and Hooks Canonical: https://harness.techfabric.com/docs/building/dynamic-agents Build persistent agents whose instructions, tools, model, integrations, and environment evolve from durable state. Dynamic agents use the existing `createAgent()` persistent-agent builder. Hooks compose capabilities inside its synchronous render function; no additional builder or runtime mode is required. The host renders the function before every delivered interaction using the instance's durable state snapshot. ```ts title=".fabricharness/agents/assistant.ts" import { createAgent, schema, useModel, usePersistentState, useSandbox, useSkill, useTool, } from '@fabric-harness/sdk'; import { reviewChecklist } from '../skills/review'; import { advancedAnalysis, searchIssues } from '../tools/github'; function TriageAgent() { const [phase] = usePersistentState('phase', 'triage', { schema: schema.enum(['triage', 'implementation']), }); useModel(phase === 'triage' ? 'anthropic/claude-haiku-4-5' : 'anthropic/claude-sonnet-4-6'); useSandbox(phase === 'triage' ? 'virtual' : 'docker', { cwd: '/workspace' }); useSkill(reviewChecklist); useTool(searchIssues); if (phase === 'implementation') useTool(advancedAnalysis); return `Complete the ${phase} phase, use the mounted evidence, and do not skip verification.`; } export default createAgent(TriageAgent, { durability: { maxAttempts: 5, timeoutMs: 2 * 60 * 60_000 }, }); ``` The named function is the agent's capability render and its return value is the current instruction. State changes become visible on the next render, so the model, sandbox, and conditional tool switch at an interaction boundary. Resource additions, removals, and definition changes are recorded and narrated to the model. Native-loop hosts resolve the provider that owns the newly selected model; a custom host can supply `modelProviderResolver` when routing cannot be derived from the standard provider registry. Declare retry and wall-clock durability outside the render so admission and recovery can enforce it even when the agent cannot render: ```ts export default createAgent(renderAssistant, { durability: { maxAttempts: 5, timeoutMs: 2 * 60 * 60_000 }, }); ``` Static definition fields—including `policy`, durability, triggers, and initial-data validation—remain in force across every dynamic re-render. Hook output may change per turn, but a refresh cannot silently remove the agent's static authorization boundary. ## The render model Think of the `createAgent()` function as a pure capability render: 1. Fabric loads the addressed instance and its durable state. 2. The function declares the model, instructions, resources, and lifecycle callbacks for this turn. 3. Fabric runs the model and tools under the normal policy, identity, budget, and cancellation limits. 4. Successful state writes are persisted and affect the next render. Hooks must be called synchronously and in composition order. Network calls and other asynchronous work belong in tools, lifecycle callbacks, or lazy MCP connectors. State cannot be written during render. Custom hooks are ordinary functions, so related capabilities can live together: ```ts function useResearchMode(enabled: boolean) { if (!enabled) return; useInstruction('Investigate competing explanations before deciding.'); useTool(searchSources); useSkill(researchSkill); } export default createAgent(() => { const [researchEnabled] = usePersistentState('researchEnabled', false); useResearchMode(researchEnabled); return 'Resolve the request and explain the evidence.'; }); ``` ## Complete hook surface | Hook | Purpose | | --- | --- | | `useInstruction()` | Compose instruction fragments in call order. | | `useModel()` | Select the model, thinking level, and compaction policy for this render. | | `useSandbox()` | Select a portable sandbox and working directory. | | `useTool()` | Mount a typed tool, including conditional and durable tools. | | `useSkill()` | Mount Markdown-first expertise without granting authority. | | `useSubagent()` | Add a named specialist for delegated session tasks. | | `useMcpConnection()` | Lazily connect an MCP tool source for this interaction. | | `usePersistentState()` | Read a durable snapshot and write from tools or lifecycle callbacks. | | `useDelivery()` | Read the normalized user or signal delivery that caused this render. | | `useInitialData()` | Read immutable JSON data captured on first contact. | | `useDispatchMessage()` | Enqueue another real delivery for the same addressed instance. | | `useDataWriter()` | Write a named, model-invisible client data part. | | `useResponseStart()` | Attach synchronous metadata before model work begins. | | `useAgentStart()` | Run awaited intake work after input is durable. | | `useAgentFinish()` | Inspect the result and optionally continue the same response. | | `useResponseFinish()` | Attach final synchronous response metadata. | `defineMcpConnection()` and `defineSubagent()` create reusable declarations. `GeneralSubagent` supplies a general-purpose delegate when a custom specialist is unnecessary. ## Models, instructions, skills, and sandboxes Every render can select a different model or environment. A persistent state transition is a useful way to trade up only when a task earns the additional cost or isolation: ```ts export default createAgent(() => { const [phase] = usePersistentState('phase', 'triage', { schema: schema.enum(['triage', 'implementation']), }); useModel( phase === 'triage' ? 'anthropic/claude-haiku-4-5' : 'anthropic/claude-sonnet-4-6', { thinkingLevel: phase === 'triage' ? 'low' : 'high' }, ); useSandbox(phase === 'triage' ? 'virtual' : 'local', { cwd: '/workspace' }); useInstruction(`Current workflow phase: ${phase}.`); useSkill({ name: 'release', content: releaseInstructions }); return 'Complete the current phase without skipping its verification gate.'; }); ``` Capability policy still applies after composition. A skill adds context; it does not widen filesystem, shell, network, credential, connector, or tool permissions. `useModel()` also takes the per-render compaction policy. The default `@fabric-harness/sdk` import enables auto-compaction; disable it or tune the thresholds when a phase needs verbatim history: ```ts useModel('anthropic/claude-sonnet-4-6', { compaction: { enabled: true, keepRecentEntries: 40 }, }); // or: compaction: false ``` See [Compaction](/docs/reference/compaction) for the full `CompactionSettings` contract and the `/strict` default. ## Durable state and tools State setters work inside tracked tools and lifecycle callbacks. A successful tool commits its state writes with the tool result. Failed tools do not publish a partial state transition. Mark a tool `durable: true` to receive a named step journal: ```ts const [phase, setPhase] = usePersistentState('phase', 'draft', { schema: schema.enum(['draft', 'published']), }); useTool({ name: 'publish_report', input: schema.object({ reportId: schema.string() }), durable: true, async run({ data, step, log }) { const receipt = await step.do(`publish:${data.reportId}`, () => publisher.publish(data.reportId, { idempotencyKey: data.reportId }), ); log.info('Report published', { reportId: data.reportId }); setPhase('published'); return { output: receipt }; }, }); ``` If a worker stops after one step, recovery re-enters the logical tool call, replays completed steps, and executes unfinished ones. External operations still need a stable idempotency key because a process can stop after the external effect but before its checkpoint lands. On restart, resource-change narration may be recorded before recovery finishes. Harness keeps that narration out of the provider transcript until the recovered tool result is paired with its original tool call. If reauthorization or execution fails, the correlated failure is projected as the required tool result, so Anthropic-compatible and other strict providers never receive an orphaned tool use. The recovered call/result pair belongs to the resumed response and is visible to `useAgentFinish()`, preventing required-tool guards from scheduling the same external operation again. Lifecycle metadata, message data, and lifecycle markers retain their submission and attempt identity even when the generated host bundles an agent definition separately from the submission runner. Set `harness: true` on a hook-authored tool only when it needs the runtime-scoped sandbox: ```ts useTool({ name: 'inspect_workspace', harness: true, async run({ harness }) { return { output: await harness.sandbox.readdir('.') }; }, }); ``` ## Delivery, initial data, and dispatch `useDelivery()` exposes the normalized event that triggered the render. `useInitialData()` exposes the first JSON seed admitted for the instance and never replaces it with later values. ```ts interface AccountSeed { accountId: string; plan: 'standard' | 'enterprise'; } export default createAgent(() => { const delivery = useDelivery(); const account = useInitialData(); const dispatch = useDispatchMessage(); useAgentStart(async () => { if (delivery.kind === 'user' && account.plan === 'enterprise') { await dispatch({ kind: 'signal', type: 'account.priority', body: `Prioritize account ${account.accountId}.`, }); } }); return `Handle this ${delivery.kind} delivery for ${account.accountId}.`; }, { initialData: schema.object({ accountId: schema.string(), plan: schema.enum(['standard', 'enterprise']), }), }); ``` Signal deliveries remain typed canonical conversation records with their submission, tenant, and actor correlation intact. They render into model context once using their signal tag, but do not become visible user prompts; the conversation projection classifies them as diagnostic dispatch messages. Durable replay recognizes the correlated signal by submission ID and never applies it a second time. The runtime rejects any contradictory typed delivery and rendered prompt before either is persisted. User deliveries continue to persist as visible user prompts. Self-dispatch is bound to the host's durable submission queue for each render. This scoped binding survives packaged agents that bundle their own SDK copy and process restarts; Node, Databricks Apps, and Cloudflare Durable Objects inject it automatically, while Temporal activities accept the durable queue explicitly. None depend on process-global queue state inside the agent module. Seed the first interaction over HTTP: ```sh curl -X POST 'http://localhost:4317/agents/assistant/account-7?wait=true' \ -H 'content-type: application/json' \ -d '{"message":"Begin","initialData":{"accountId":"account-7","plan":"enterprise"}}' ``` Or pass the same option through `@fabric-harness/client` or `@fabric-harness/react`: ```ts await client.agent({ agent: 'assistant', id: 'account-7' }).send('Begin', { initialData: { accountId: 'account-7', plan: 'enterprise' }, }); ``` Do not put credentials in initial data, persistent state, tool results, metadata, or data parts. These surfaces are serializable and may be retained, projected to clients, or replayed. ## Response metadata, client data, and lifecycle The response lifecycle runs in this order: ```text useResponseStart → useAgentStart → model and tools → useAgentFinish → useResponseFinish ``` All `useAgentStart()` declarations run concurrently. Each receives the interaction `signal`, a scoped `harness`, a redacted progress `log`, and `append()`. Fabric commits their state writes and signal appends together after every callback settles, flattening appends in declaration order. Put dependent work in one callback rather than depending on callback scheduling. `useAgentFinish()` declarations run sequentially at the would-stop boundary. `useDataWriter()` produces typed client-facing data without adding it to model context. Its names are part of the message shape and must be declared unconditionally on every render. ```ts const writeProgress = useDataWriter('progress', { schema: schema.object({ completed: schema.number(), total: schema.number() }), }); useResponseStart(() => ({ startedAt: Date.now() })); useTool({ name: 'complete_item', run: () => { writeProgress({ completed: 3, total: 8 }); return 'recorded'; }, }); useResponseFinish(({ metadata, response }) => ({ startedAt: metadata.startedAt, toolCalls: response.toolCalls.length, finishedAt: Date.now(), })); ``` Use `useAgentFinish()` for an invariant that must hold before a response settles: ```ts useAgentFinish(({ response, append }) => { const verified = response.toolCalls.some( (call) => call.tool === 'verify_release' && !call.error, ); if (!verified) { append({ kind: 'signal', type: 'release.verification-required', body: 'Run verify_release before finishing.', }); } }); ``` The signal continues the same response rather than creating a new user delivery. Finish continuations are capped at eight cycles and remain subject to model-turn, tool-call, token, cost, cancellation, and wall-clock limits. ## MCP connections and Databricks MCP declarations are lazy. Fabric connects only when the current render mounts the declaration, applies the optional remote-tool allowlist, and closes the connection after the interaction. ```ts const documentation = defineMcpConnection({ name: 'documentation', url: 'https://docs.example.com/mcp', auth: () => process.env.DOCS_MCP_TOKEN, tools: ['search', 'read'], }); export default createAgent(() => { const [researchEnabled] = usePersistentState('researchEnabled', false); if (researchEnabled) useMcpConnection(documentation); return 'Use approved documentation sources when research mode is active.'; }); ``` Databricks managed MCP uses the same hook through the existing governed connector: ```ts import { connectDatabricksManagedMcpServer } from '@fabric-harness/databricks'; import { createAgent, defineMcpConnection, useMcpConnection } from '@fabric-harness/sdk'; const catalog = defineMcpConnection({ name: 'catalog', connect: () => connectDatabricksManagedMcpServer({ host: process.env.DATABRICKS_HOST!, tokenProvider: async () => process.env.DATABRICKS_TOKEN, server: { name: 'catalog', endpoint: { kind: 'functions', catalog: 'main', schema: 'agent_tools' }, defaultEffect: 'execute', }, }), }); export default createAgent(() => { useMcpConnection(catalog); return 'Use governed Unity Catalog functions when required.'; }); ``` For Databricks Apps, prefer an OBO or least-privilege M2M token provider resolved at request time. Never persist the workspace credential. See [Databricks integrations](/docs/databricks/integrations) for effect classification, grants, and connection cleanup. ## Subagents Declare specialists once and mount them conditionally: ```ts const reviewer = defineSubagent({ name: 'reviewer', description: 'Reviews release evidence before publication.', model: 'anthropic/claude-sonnet-4-6', thinkingLevel: 'high', agent: () => { useInstruction('Reject unsupported claims and list missing evidence.'); useSkill(reviewChecklist); return 'Review the proposed release independently.'; }, }); export default createAgent(() => { const [readyForReview] = usePersistentState('readyForReview', false); if (readyForReview) useSubagent(reviewer); return 'Prepare a release and delegate review when the evidence is ready.'; }); ``` Subagents share the parent environment and cannot own persistent state, sandbox selection, public response metadata, or root lifecycle hooks. Use [session tasks](/docs/building/subagents) to invoke a named specialist under the normal task-depth, cancellation, checkpoint, and policy limits. Addressable Node and Databricks App runtimes expose the same path without inventing a model-callable delegation tool: ```sh curl -X POST 'http://localhost:4317/agents/assistant/demo/tasks' \ -H 'content-type: application/json' \ -d '{"task":"Review the release evidence","agent":"reviewer","session":"release","timeoutMs":120000,"maxIterations":4}' ``` The endpoint invokes `session.task()` against the freshly rendered hook configuration. It is tenant-checked, checkpoints before and after work, caps timeouts at five minutes and iterations at 16, propagates disconnect cancellation, and rejects unknown subagent names. ## Integrations Dynamic composition works with the existing Fabric ecosystem rather than creating hook-specific adapters: | Integration | Dynamic-agent pattern | Guide | | --- | --- | --- | | Slack, Teams, GitHub, Discord, and 13 more channels | Read normalized channel input with `useDelivery()`; mount governed outbound tools with `useTool()`. | [Channels](/docs/ecosystem/channels) | | Postgres, MySQL, MongoDB, Redis, SQLite, libSQL, Turso, Supabase, Valkey, and Lakebase | Construct the adapter outside render, then mount its tools conditionally. | [Databases](/docs/ecosystem/databases) | | E2B, Daytona, Modal, Vercel, Cloudflare, Databricks SQL, and other sandboxes | Select a backend with `useSandbox()` while retaining capability discovery and policy. | [Sandboxes](/docs/ecosystem/sandboxes) | | OpenTelemetry, Braintrust, Sentry, Jetty, and evaluations | Keep telemetry configured at the runtime boundary; lifecycle metadata and data parts enrich the trace. | [Tooling](/docs/ecosystem/tooling) | | Remote MCP servers | Mount lazy, authenticated, allowlisted connections with `useMcpConnection()`. | [MCP](/docs/reference/mcp) | | Databricks data, AI, Jobs, Genie, AI Search, Unity Catalog, Lakebase, and MLflow | Compose existing governed tools and managed MCP while preserving OBO or M2M identity. | [Databricks](/docs/databricks) | Use `fh add ` to install managed integration wiring. Recipes remain ordinary public Fabric tools, channels, stores, and sandboxes, so the same integration can be used by finite `defineAgent()` jobs and dynamic `createAgent()` instances. ## Run locally Create the agent file under `.fabricharness/agents/`, then start the development server: ```sh pnpm add @fabric-harness/sdk @fabric-harness/node @fabric-harness/cli pnpm exec fh dev ``` Send an interaction to the file name and a stable instance ID: ```sh curl -X POST 'http://localhost:3000/agents/assistant/demo?wait=true' \ -H 'content-type: application/json' \ -d '{"message":"Start the work"}' ``` The complete source example is in `examples/dynamic-agent` in the source distribution. ## Build and publish an agent Put public trigger metadata in the optional static `createAgent()` argument. Hosts inspect this metadata without rendering interaction-dependent hooks: ```ts export default createAgent(Assistant, { description: 'Handles durable support work.', triggers: { webhook: true }, }); ``` Choose a deployment target without changing the agent definition. `triggers.schedule` is intentionally `never` on `createAgent()`: a cron expression cannot identify the instance, session, or message to deliver. Put the schedule on a finite dispatcher job (see [Schedule triggers](/docs/reference/triggers#schedule-triggers)), or, on Cloudflare, use the per-instance schedules API backed by Durable Object alarms (see [Per-instance schedules](/docs/deployment/cloudflare#per-instance-schedules-durable-object-alarms)). ### Node or Docker ```sh pnpm exec fh build --target node NODE_ENV=production \ FABRIC_HARNESS_API_TOKEN="$FABRIC_HARNESS_API_TOKEN" \ node .fabricharness/build/node/dist/server.mjs ``` Ship the complete `.fabricharness/build/node` directory. See [Node deployment](/docs/deployment/node) or build an OCI image with the [Docker target](/docs/deployment/docker). ### Cloudflare ```sh pnpm exec fh build --target cloudflare cd .fabricharness/build/cloudflare pnpm install pnpm exec wrangler deploy ``` Persistent instances are serialized and stored in Durable Objects. Configure production bindings and run the credentialed smoke described in [Cloudflare deployment](/docs/deployment/cloudflare). ### Databricks Apps ```sh pnpm exec fh build --target databricks-app cd .fabricharness/build/databricks-app databricks bundle validate databricks bundle deploy databricks bundle run ``` The generated App uses the shared Node server, Databricks App identity, and the same dynamic render contract. Bind model endpoints, warehouses, Lakebase, MCP Services, and Unity Catalog resources through App resources or bundle variables—not committed identifiers or tokens. Follow the complete [Databricks App tutorial](/docs/deployment/databricks-app), including `fh doctor`, OBO/M2M selection, restart testing, and cleanup. ### Temporal ```sh pnpm exec fh build --target temporal-worker node .fabricharness/build/temporal-worker/dist/worker.mjs ``` The generated worker bundles the workspace's persistent-agent definitions. A dynamic prompt carries only a JSON-safe descriptor (agent name, instance, delivery, actor/tenant correlation, and resource fingerprint) through workflow history. The activity resolves that bundled definition, verifies it matches the addressed persistent session, and re-renders hooks at the trusted worker boundary. It also recomputes the model/tool/MCP resource fingerprint and rejects any mismatch before initializing the agent, so a different worker deployment cannot silently execute a changed resource set. Completed activity results are durably memoized so an activity retry does not repeat a completed model response. For a hand-composed worker, provide `resolveDynamicAgent` to `createLocalTemporalActivities()` and set `dynamicAgents: true` on `temporalSessionRuntime()` only after the matching task queue is deployed. Without both sides, Harness fails closed. Hook functions, resolved MCP credentials, tool implementations, and secret values must never enter workflow input. For a production target, use a durable store, enable authentication and tenant isolation, verify the target's capability matrix, exercise cancellation and restart recovery, and retain the generated manifest as release evidence. ## Limits and compatibility - Dynamic hooks are supported by persistent `createAgent()` definitions. Finite `defineAgent()` jobs keep their explicit bounded run lifecycle. - Named state is durable and may be declared conditionally. Named `useDataWriter()` identities must be declared on every render. - Root lifecycle, dispatch, persistent state, sandbox, MCP, and response-output hooks are unavailable inside a subagent render. - An async legacy initializer is accepted, but hooks after its first `await` fail because render has ended. Keep hooks synchronous. - Dynamic agents inherit the same policy, secret handling, identity isolation, retry, timeout, cancellation, store, and deployment contracts as other persistent agents. - Dynamic Temporal execution uses the coarse prompt activity so re-rendering and all nondeterministic I/O stay outside workflow code. A worker that does not advertise and implement the dynamic-agent resolver is rejected before delegation. See the [runnable dynamic-agent example](/docs/reference/source-access), [persistent-agent lifecycle](/docs/building/persistent-agents), and generated [API reference](/docs/reference/api) for the complete types. --- # Enterprise Controls Canonical: https://harness.techfabric.com/docs/building/enterprise-controls Apply tools, policy, approvals, budgets, and instructions at the job definition boundary. Finite jobs can declare their runtime controls once at the definition boundary. The wrapper applies them whenever `run()` calls `init()`, including through CLI, development server, and built artifacts. ## Complete governed job Create `.fabricharness/jobs/governed-report.ts`: ```ts import { defineTool, defineAgent, schema } from '@fabric-harness/sdk'; const lookupAccount = defineTool({ name: 'lookup_account', description: 'Read an account summary.', inputSchema: { type: 'object', additionalProperties: false, properties: { accountId: { type: 'string' } }, required: ['accountId'], }, execute: async ({ accountId }: { accountId: string }) => ({ accountId, status: 'active', }), }); export default defineAgent({ name: 'governed-report', description: 'Create a read-only account report.', instructions: 'Use only approved account data. Never infer missing values.', input: schema.object({ accountId: schema.string() }), output: schema.string(), triggers: { webhook: true, manual: true }, tools: [lookupAccount], policy: { toolPolicy: { allow: ['lookup_account'], deny: ['write', 'edit', 'bash'], requireApproval: ['export_*'], }, network: { mode: 'none' }, approvals: { requiredApprovals: 2, risk: 'high', defaultTimeoutMs: 5 * 60_000, }, }, costBudget: { perCall: 0.05, perSession: 0.50, onExceed: 'throw', }, approvals: { timeoutMs: 5 * 60_000 }, async run({ init, input }) { const agent = await init(); const session = await agent.session(); return session.prompt(`Create the report for ${input.accountId}.`); }, }); ``` Run and inspect it: ```sh fh describe governed-report fh run governed-report --account-id acct-42 ``` ### What operators see When an effect requires approval, Harness retains the exact request, session, vote count, decision, and authorized controls. The console does not grant permission: the server independently enforces the principal, tenant, policy, expiry, and exact-input approval scope. ## Precedence rules Definition controls are defaults with security-aware composition: | Control | Behavior when `init({...})` also supplies a value | | --- | --- | | `instructions` | A call-provided `role` wins. Otherwise instructions become the agent role. | | `tools` and `skills` | Definition and call values are combined. | | `policy` | Definition policy is a security floor. Calls may add denials and approvals, but cannot replace definition allowlists. | | `costBudget` | The lower per-call and per-session limits win. A call cannot raise the definition budget. | | `approvals.timeoutMs` | The shorter definition/call timeout wins. | For example, this call can narrow the job but cannot enable network or raise its budget: ```ts const agent = await init({ policy: { toolPolicy: { deny: ['lookup_account'] }, }, costLimit: { perSession: 0.25 }, }); ``` ## Adversarial controls For outbound HTTP, enable DNS answer verification in Node deployments so an allowed hostname cannot resolve to loopback, link-local, metadata, or RFC1918 space: ```ts const policy = { network: { mode: 'allowlist', hosts: ['api.example.com'], protocols: ['https:'], resolveDns: true, }, }; ``` `policiedFetch()` checks the original URL, each redirect, IP literals, and DNS answers. Production containers should also enforce egress at the network layer because process-level policy cannot prevent code that deliberately bypasses the configured fetch implementation. Tool aliases declare `policyAlias` so policy evaluates their canonical capability. For example, a `save_file` tool with `policyAlias: 'write'` remains subject to every `write` deny and approval rule. Raw access through `session.sandbox` cannot bypass `requireApproval`; only the exact operation inside the resolved approval scope receives a temporary grant. Durable attachment materialization defaults to 20 attachments, 10 MiB per decoded attachment, and 25 MiB total. `createSubmissionRunner({ attachments: { ... } })` can set lower `maxCount`, `maxAttachmentBytes`, and `maxTotalBytes` values for a route or tenant. ## Approval handlers The definition declares when approval is required and how long it may wait. The host supplies the operator integration: ```ts const agent = await init({ onApproval: async (request) => { const decision = await approvalService.waitForDecision(request); return decision; // approved or denied }, }); ``` Temporal-backed sessions persist approval waits. Inline sessions require the process to remain available. See [Approvals](/docs/building/approvals) for CLI and API resolution. ## Tenant-wide budgets Use a shared budget store when limits must survive restarts or span replicas: ```ts import { tenantCostLimit } from '@fabric-harness/sdk'; import { postgresCostBudgetStore } from '@fabric-harness/node'; const costLimit = tenantCostLimit('acme', { perDayUsd: 50, store: postgresCostBudgetStore({ client: pool }), }); const agent = await init({ tenantId: 'acme', costLimit }); ``` Definition budgets protect one job/session. Shared budget stores enforce organization or tenant ceilings across processes. Postgres and SQLite use atomic reservations: concurrent calls that would cross the ceiling are rejected without committing an over-budget total. Bind scheduled background jobs to a service principal instead of running them without identity: ```ts await startDevServer({ scheduler: { identity: async (jobName) => ({ tenantId: 'acme', actor: { principal: { id: `scheduler:${jobName}`, type: 'service' } }, }), }, }); ``` Channel adapters derive tenant and actor from the verified provider payload. HTTP principals cannot list, read, abort, delete, or vote on resources owned by another tenant. ## See also - [Policies and approvals](/docs/reference/policies-approvals) - [Cost attribution](/docs/operating/cost-attribution) - [Agent anatomy](/docs/building/anatomy) - [Security hardening](/docs/reference/security-hardening) --- # Evaluations Canonical: https://harness.techfabric.com/docs/building/evals Test a job against deterministic scorers and model-based judges, so a prompt change shows up as a number before it ships. Fabric eval suites are TypeScript modules named `*.eval.ts`. Each suite supplies cases, a runner, one or more scorers, and an optional pass threshold. `fh test` discovers and runs them locally or in CI. ## Install ```sh pnpm add -D @fabric-harness/evals @fabric-harness/node ``` ## Evaluate a job ```ts title="evals/hello.eval.ts" import { containsTextScorer, defineEvalSuite } from '@fabric-harness/evals'; import { runAgent } from '@fabric-harness/node'; export default defineEvalSuite({ name: 'hello-quality', cases: [ { id: 'named-user', input: { name: 'Ada' }, expected: 'Ada' }, { id: 'default-user', input: { name: 'World' }, expected: 'World' }, ], runner: async ({ case: evalCase }) => { const run = await runAgent({ agent: 'hello', payload: evalCase.input, mock: true, }); return run.result; }, scorers: [containsTextScorer()], passThreshold: 1, }); ``` Run every suite: ```sh fh test ``` Run a subset or produce machine-readable output: ```sh fh test evals --suite hello-quality fh test --threshold 0.9 --json ``` The command exits nonzero when any suite fails, so it can be used directly as a CI quality gate. ## Choose scorers | Scorer | Use it for | | --- | --- | | `exactMatchScorer()` | Deterministic structured or scalar output. | | `containsTextScorer()` | Required text in an answer. | | `regexMatchScorer()` | IDs, formats, and constrained strings. | | `jsonShapeMatchScorer()` | Required JSON fields and primitive types. | | `llmAsJudgeScorer()` | Semantic criteria that deterministic assertions cannot express. | Prefer deterministic scorers first. For an LLM judge, use a separate provider/model, write a narrow rubric, and set `passThreshold` explicitly. Never pass provider secrets through eval case input. For long-lived comparisons and stored grading trajectories, see [Jetty](/docs/ecosystem/tooling/jetty). For every exported type and scorer, see the [eval library reference](/docs/reference/eval-library). --- # HTTP applications Canonical: https://harness.techfabric.com/docs/building/http-applications Mount authenticated Fetch routes and middleware around Fabric jobs, agents, channels, health, and identity. Use the application surface when one deployed service needs Fabric routes plus product-specific HTTP endpoints. Routes and middleware live in `.fabricharness/config.ts`, so `fh dev` and Node-derived build artifacts run the same application. ```mermaid flowchart LR REQ[HTTP request] --> PUB[Public middleware] PUB --> SYS[Health, rate limit, and authentication] SYS --> RBAC[Principal, tenant, and permission] RBAC --> APP[Authenticated middleware] APP --> CHOICE{Route owner} CHOICE -->|Application| CUSTOM[Fetch route handler] CHOICE -->|Fabric| CORE[Job, agent, channel, MCP, or admin] CUSTOM --> RES[HTTP response] CORE --> RES RES --> APP APP --> PUB classDef public fill:#f3f4f6,stroke:#6b7280,color:#111827 classDef identity fill:#fef3c7,stroke:#d97706,color:#422006 classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef custom fill:#dcfce7,stroke:#16a34a,color:#052e16 class PUB public class SYS,RBAC identity class CORE fabric class CUSTOM custom ``` ## Define routes ```ts title=".fabricharness/config.ts" import { defineApplication, type FabricHarnessConfig } from '@fabric-harness/node'; const application = defineApplication({ routes: [ { method: 'POST', path: '/api/customers/:customerId/message', permission: 'agent:invoke', async handler(request, context) { const body = await request.json() as { message: string; deliveryId?: string; }; const receipt = await context.dispatch( { agent: 'support', id: context.params.customerId!, message: { kind: 'user', body: body.message }, }, body.deliveryId ? { idempotencyKey: body.deliveryId } : undefined, ); return Response.json(receipt, { status: 202 }); }, }, { method: 'POST', path: '/api/reports', permission: 'agent:invoke', async handler(request, context) { const input = await request.json(); return Response.json( await context.invoke({ job: 'report', input }), { status: 202 }, ); }, }, ], }); export default { application, } satisfies FabricHarnessConfig; ``` Route paths support named `:parameters` and a trailing `*` wildcard. The handler uses the standard Web `Request` and returns a Web `Response`. Its context contains: | Field | Purpose | | --- | --- | | `principal`, `actor`, `tenantId` | Server-validated identity and tenant; request bodies cannot replace them. | | `params` | Decoded named path parameters. | | `dispatch()` | Durable admission to a persistent agent with optional idempotency key. | | `invoke()` | Ambient finite-job admission with tenant, actor, and parent correlation. | | `stores` | The configured session, submission, conversation, and attachment stores. | | `signal` | Aborts when the client aborts the request. | | `requestId` | Correlation id for application logs and response headers. | Custom routes inherit the normal authentication, tenant binding, rate limit, and authorization pipeline. Set `permission` to the closest built-in permission. It defaults to `session:read` for `GET` and other non-Fabric paths. Application hooks do not accept identity from payload fields. ## Add middleware Authenticated middleware receives the complete request context and wraps both custom and built-in routes. Calling `next()` once continues the chain. For a custom route, `next()` returns its `Response`, so middleware can add headers or replace it. For a streaming or built-in Node route, `next()` completes when the response finishes. ```ts middleware: [async (request, context, next) => { const started = performance.now(); const response = await next(); await audit.record({ requestId: context.requestId, principalId: context.principal.id, tenantId: context.tenantId, method: request.method, path: new URL(request.url).pathname, durationMs: performance.now() - started, }); if (!response) return; const headers = new Headers(response.headers); headers.set('x-fabric-request-id', context.requestId); return new Response(response.body, { status: response.status, headers }); }], ``` `publicMiddleware` wraps health, rate limiting, and authentication. It intentionally receives no principal or stores. Use it for request timing, trusted ingress normalization, and global response headers, not authorization decisions. ```ts publicMiddleware: [async (request, context, next) => { const response = await next(); console.log(context.requestId, request.method, new URL(request.url).pathname); return response; }], ``` Middleware and handlers share one cached request body. Reading `request.clone().json()` in middleware does not consume the bytes later used by job, channel, webhook-signature, or custom route handling. The configured `maxBodyBytes` limit still applies. ## Route ownership Fabric reserves `/health`, `/ready`, `/jobs`, `/agents`, `/channels`, `/sessions`, `/runs`, `/mcp`, `/admin`, `/builds`, `/dispatch`, and `/openapi.json`. A custom route beneath a reserved root or a duplicate method/path fails before the server listens. This prevents an application update from silently replacing approval, health, or agent behavior. The complete runnable workspace is in [`examples/application-routes`](/docs/reference/source-access). --- # Model Providers Canonical: https://harness.techfabric.com/docs/building/model-providers Configure which LLM providers are available and pick one per agent, per session or per individual call at runtime. TechFabric Harness uses an explicit `provider/model-id` reference everywhere a model is selected. There is no implicit "default OpenAI" — you opt into a provider by configuring credentials and naming the model. ## Reference format ``` provider/model-id ``` Examples: ``` openai/gpt-5.5 anthropic/claude-sonnet-4-6 gemini/gemini-2.5-pro bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0 ``` ## Setting credentials Put provider keys once in a repo/workspace `.env.local`; TechFabric Harness auto-loads `.env` and `.env.local` files, while shell env still wins: ```sh cp .env.example .env.local # OPENAI_API_KEY=... # ANTHROPIC_API_KEY=... # AZURE_OPENAI_ENDPOINT=https://....openai.azure.com # AZURE_OPENAI_API_KEY=... ``` Use explicit `--env ` only for overrides. Never paste API keys into source files or session artifacts. ## Selecting the model The first non-empty wins, in this order: 1. CLI flag: `fh run ask --model openai/gpt-5.5` 2. Environment: `FABRIC_MODEL=openai/gpt-5.5` 3. `.fabricharness/config.ts` → `run.model` or `agent.model` 4. Agent-declared default: `defineAgent({ model: 'openai/gpt-5.5' })` Per-call override: ```ts await session.prompt('Summarize', { model: 'openai/gpt-5.5' }); ``` ## Mock provider For local development and tests, pass `--mock` to `fh run` or `fh dev`. The flag substitutes the deterministic mock provider regardless of the declared model reference and honors typed-result schemas where possible. Without `--mock`, `openai/gpt-5.5` makes a real provider call and requires `OPENAI_API_KEY`. ```ts export default defineAgent({ // ... model: process.env.FABRIC_MODEL ?? 'openai/gpt-5.5', }); ``` ## Provider env names TechFabric Harness knows the standard env names for common providers: - `OPENAI_API_KEY` - `ANTHROPIC_API_KEY` - `OPENROUTER_API_KEY` - `DEEPSEEK_API_KEY` - `MOONSHOT_API_KEY` - `XAI_API_KEY` - `GEMINI_API_KEY` - `GOOGLE_API_KEY` - `AZURE_OPENAI_API_KEY` + `AZURE_OPENAI_ENDPOINT` - `GROQ_API_KEY` - `MISTRAL_API_KEY` - `COHERE_API_KEY` ## Direct OpenAI-compatible presets [DeepSeek](https://api-docs.deepseek.com/), [Moonshot/Kimi](https://platform.kimi.ai/docs/api/overview), and [xAI](https://docs.x.ai/developers/quickstart) expose OpenAI-compatible Chat Completions APIs. Fabric provides named presets so direct-key users do not need to repeat the provider base URL: ```sh FABRIC_MODEL=deepseek/deepseek-v4-flash # DEEPSEEK_API_KEY FABRIC_MODEL=moonshot/kimi-k2.6 # MOONSHOT_API_KEY FABRIC_MODEL=xai/grok-4.5 # XAI_API_KEY ``` `kimi/...` is accepted as an alias for `moonshot/...`. Override endpoints with `DEEPSEEK_BASE_URL`, `MOONSHOT_BASE_URL`, or `XAI_BASE_URL`, or configure `providers.deepseek`, `providers.moonshot`, and `providers.xai` explicitly. These are transport presets, not provider-specific SDK implementations. They retain the typed Fabric model contract, tool calls, streaming, redacted HTTP failures, and cost-budget behavior. Missing keys fail before a network request and name the required variable. Fabric never falls back to OpenRouter or mock inference when a direct preset fails. Built-in prices are effective-dated and intentionally incomplete. DeepSeek V4 and the xAI Grok 4.5 short-context tier have verified rows; Moonshot and unlisted models leave `usage.costUsd` undefined. Register deployment-specific or contract pricing with `registerModelPrices()` rather than treating an unknown price as zero. ## Cloudflare Workers AI binding When deploying to Cloudflare Workers with `fh build --target cloudflare`, you can route inference through the platform binding (`env.AI.run()`) instead of HTTP — no API tokens, no egress, runs at the edge. ```ts import { CloudflareWorkersAIModelProvider } from '@fabric-harness/cloudflare/workers-ai'; export default { async fetch(request: Request, env: Env) { const fabric = await init({ modelProvider: new CloudflareWorkersAIModelProvider({ binding: env.AI, defaultModel: '@cf/meta/llama-3.1-8b-instruct', }), }); // ... }, }; ``` `wrangler.toml`/`jsonc`: ```toml [ai] binding = "AI" ``` Handles modern `{ choices: [...] }` and legacy `{ response: '...' }` Workers AI shapes. Optional Cloudflare AI Gateway routing supports enterprise logging/routing knobs: ```ts new CloudflareWorkersAIModelProvider({ binding: env.AI, defaultModel: '@cf/meta/llama-3.1-8b-instruct', gateway: { id: 'prod-gateway', skipCache: false, cacheTtl: 3600, collectLog: true, eventId: request.headers.get('x-request-id') ?? undefined, metadata: { tenant: 'acme', environment: 'prod' }, }, models: { '@cf/meta/llama-3.1-8b-instruct': { contextWindowTokens: 8192, maxOutputTokens: 2048, supportsTools: true, }, }, }); ``` Model metadata feeds context-budgeting/auto-compaction and admin UIs. The provider includes built-in metadata for common Workers AI chat models and accepts `models` / `defaultModelInfo` overrides for private or newly released models. ## OpenAI-compatible gateways Many AI gateway products speak the OpenAI Chat Completions request/response shape: Vercel AI Gateway, Helicone, Portkey, LiteLLM (self-hosted), internal corp proxies. Wire any of them with the generic `aiGateway()` helper: ```ts import { aiGateway, init } from '@fabric-harness/sdk'; // Helicone const fabric = await init({ modelProvider: aiGateway({ baseUrl: 'https://oai.helicone.ai/v1', apiKey: process.env.OPENAI_API_KEY!, headers: { 'Helicone-Auth': `Bearer ${process.env.HELICONE_API_KEY}` }, defaultModel: 'gpt-4o', name: 'helicone', }), }); // Self-hosted LiteLLM const fabric = await init({ modelProvider: aiGateway({ baseUrl: 'http://litellm.internal:4000/v1', apiKey: process.env.LITELLM_KEY!, defaultModel: 'azure/gpt-5.5', }), }); ``` ### Vercel AI Gateway preset [Vercel AI Gateway](https://vercel.com/docs/ai-gateway/sdks-and-apis/openai-compat) gets a thin preset with the gateway URL pre-baked: ```ts import { vercelAIGateway, init } from '@fabric-harness/sdk'; const fabric = await init({ modelProvider: vercelAIGateway({ apiKey: process.env.AI_GATEWAY_API_KEY!, defaultModel: 'anthropic/claude-sonnet-4-6', }), }); ``` `baseUrl` defaults to `https://ai-gateway.vercel.sh/v1`; override for staging or self-hosted. ## Foundry runtime (Azure) On Azure compute such as an ACA Job, AKS pod, or VM with managed identity, `FoundryRuntimeModelProvider` calls the Foundry-managed Azure OpenAI surface using a Bearer token instead of an API key: ```ts import { FoundryRuntimeModelProvider } from '@fabric-harness/azure/foundry-runtime'; import { init } from '@fabric-harness/sdk'; const fabric = await init({ modelProvider: new FoundryRuntimeModelProvider({ defaultModel: 'gpt-4o', }), }); ``` Set `AZURE_OPENAI_ENDPOINT` and `AZURE_OPENAI_DEPLOYMENT`. Supply `FOUNDRY_AGENT_TOKEN` when your host injects one, or install the optional `@azure/identity` peer dependency to use `DefaultAzureCredential` with the workload's managed identity. ## Spend caps Per-call and per-session USD ceilings prevent runaway spend. Wired through `init({ costLimit })`: ```ts const fabric = await init({ costLimit: { perCall: 0.10, // throw if a single model call exceeds $0.10 perSession: 1.00, // throw if cumulative session spend exceeds $1.00 onExceed: 'throw', // 'throw' (default) | 'approve' }, }); ``` When `onExceed: 'approve'` the loop pauses on a violation and emits `approval_requested` with `kind: 'cost-limit'`. Approve via your existing approval UI (or `fh approve `) to release the loop; deny to throw `CostLimitExceededError`. Limits evaluate after each call's cost lands on `usage.costUsd`. Forks and replays start with a fresh budget — replay is a debug action, not production work. ### Cross-process aggregation For "tenant X spends ≤ $50/day" or "company-wide ≤ $100/hour" caps, pair `perScope + scopeKey + store` with a cross-process `CostBudgetStore`: ```ts import { init, inMemoryCostBudgetStore } from '@fabric-harness/sdk'; import { postgresCostBudgetStore } from '@fabric-harness/node'; const fabric = await init({ costLimit: { perScope: 50.00, scopeKey: `tenant:${tenantId}:day:${todayIso}`, store: postgresCostBudgetStore({ client: pgClient }), // or inMemoryCostBudgetStore() for single-process onExceed: 'throw', }, }); ``` The store is the source of truth — multiple agents / multiple processes share the running total. fabric-harness never interprets `scopeKey`; you pick the convention (per-tenant, per-day, per-org). Reset semantics (daily rollover, billing period close) are also yours — call `store.reset(scopeKey)` from a scheduled task. ## Anthropic prompt caching When an Anthropic response includes `cache_read_input_tokens` / `cache_creation_input_tokens`, fabric-harness records them on `usage.cachedInputTokens` and `usage.cacheWriteTokens`, and the cost calculator discounts billed input tokens by the cached read amount (and adds the cache-write surcharge when present). `fh metrics` shows a new `Cache: read=N write=N` line so you can see how much you're saving. ```text $ fh metrics ask-1f4f... Tokens: input=120000 output=2400 total=122400 Cache: read=96000 write=0 Cost: $0.046800 ``` Cache-read tokens are billed at ~10% of the standard input rate on Claude models. Long, stable system prompts → big savings. ## Per-call cost telemetry Every model call is enriched with a USD estimate from a static price table (mainline OpenAI, Anthropic, Gemini, Bedrock, Cohere). Cost shows up in `fh metrics` and on OpenTelemetry spans as `gen_ai.usage.cost_usd` — see [CLI → metrics](/docs/cli/sessions#fh-metrics). Override or extend the catalog at runtime when you have custom-rate contracts: ```ts import { registerModelPrices } from '@fabric-harness/sdk'; registerModelPrices([ { provider: 'openai', model: 'gpt-4o', inputPerMTok: 1.5, outputPerMTok: 6, effectiveAt: '2026-05-08', notes: 'Enterprise contract' }, ]); ``` ## Reasoning effort Reasoning-capable models accept a `thinkingLevel` controlling how much the model thinks before answering: ```ts type ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'; ``` It is configurable at three scopes, most-specific wins: ```ts const agent = await init({ model: 'cloudflare/@cf/openai/gpt-oss-120b', thinkingLevel: 'medium' }); const session = await agent.session('s1', { thinkingLevel: 'high' }); // per-session override await session.prompt('think hard about this', { thinkingLevel: 'xhigh' }); // per-call override ``` The level is **capability-gated**: reasoning-capable providers map it to their native control, others ignore it (no error). `'off'` (or unset) requests no reasoning. - **Default loop (pi-agent-core):** works for every provider; pi-ai handles capability detection + per-provider mapping and clamps the level to what each model supports. - **Native Fabric providers:** Cloudflare Workers AI binding & OpenAI-compatible map to `reasoning_effort`; Anthropic to `thinking.budget_tokens` (with `max_tokens` raised above the budget); Gemini/Vertex to `thinkingConfig.thinkingBudget`. Gated to known reasoning families (o-series / gpt-5 / gpt-oss, Claude 3.7/4.x, Gemini 2.5). --- # Persistent Agents & Dispatch Canonical: https://harness.techfabric.com/docs/building/persistent-agents Long-lived, addressable agent instances with cross-call sessions, async dispatch, and a streaming WebSocket conversation. TechFabric Harness has two authoring surfaces. A **job** is a finite, run-once execution; a **persistent agent** is a long-lived, URL-addressable instance whose sessions continue across calls. (Fabric names the finite surface *job* because *workflow* is reserved for Temporal durable execution.) | | Finite **job** | Persistent **agent** | | --- | --- | --- | | Author with | `defineAgent({ run })` | `createAgent(AgentFunction, staticConfig?)` | | Directory | `.fabricharness/jobs/` | `.fabricharness/agents/` | | Invoke | `POST /jobs/:name` → `{ result, runId }` | `POST /agents/:name/:id` with `{ message, session? }` | | Lifetime | one run, returns a result | long-lived instance; sessions persist across calls | | Async / streaming | tracked under `/runs` | `dispatch()` + `GET /agents/:name/:id` WebSocket | The directory and route split is enforced. Finite definitions live in `.fabricharness/jobs/` and use `POST /jobs/:name`; persistent definitions live in `.fabricharness/agents/` and use `POST /agents/:name/:id`. ## Defining a persistent agent A persistent agent module default-exports `createAgent(...)`. Prefer a named synchronous agent function: hooks compose its current capabilities and its return value becomes the instruction. ```ts title=".fabricharness/agents/support.ts" import { createAgent, useModel, useSandbox } from '@fabric-harness/sdk'; function SupportAgent({ id }: { id: string }) { useModel('anthropic/claude-sonnet-4-6'); useSandbox('virtual'); return `Resolve the support request for conversation ${id}. Use the conversation history and state what the user should do next.`; } export default createAgent(SupportAgent, { durability: { maxAttempts: 5, timeoutMs: 2 * 60 * 60_000 }, triggers: { webhook: true }, }); ``` The function receives the addressed instance `id` and platform `env`, then renders again for each interaction. `useModel()`, `useSandbox()`, `useTool()`, `useSkill()`, `useSubagent()`, MCP, lifecycle, and persistent-state hooks compose the live harness. Declare policy, durability, triggers, and initial-data validation in the second, host-readable argument. Those fields are validated at registration and remain enforceable even when rendering crashes. The lower-level initializer form that returns a `PersistentAgentConfig` remains supported for programmatic adapters, but hook-composed functions are the recommended authoring surface. See [Dynamic Agents and Hooks](/docs/building/dynamic-agents) for state-driven capability changes. Persistent agents may declare `triggers.webhook` or `triggers.manual`. They do not accept `triggers.schedule`, because a cron expression does not specify which instance, session, and message should be invoked. Use a scheduled finite job that calls `dispatch()` with those values; see [Triggers and Public Route Gating](/docs/reference/triggers#schedule-triggers). ## Direct prompts `POST /agents/:name/:id` durably admits a message for the instance's named session and returns `202 { submissionId, streamUrl, offset }`. Processing is FIFO per session and continues off the request. Add `?wait=true` only when a synchronous compatibility response is required: ```sh # Same instance "u1" → one continuing conversation curl -XPOST localhost:4317/agents/assistant/u1 -d '{"message":"remember my name is Ada"}' curl -XPOST localhost:4317/agents/assistant/u1 -d '{"message":"what is my name?"}' ``` Read settlement at `/agents/:name/:id/submissions/:submissionId`, catch up through `/conversation?offset=`, or tail `/stream?offset=`. Stream checkpoints carry an incarnation; a changed incarnation resets stale offsets after deletion/recreation. Concurrent messages to one instance session queue FIFO instead of returning `409`. ### What operators see The session address, tenant, entry count, queue state, and permitted recovery actions remain visible together. The screenshot uses deterministic, sanitized fixture data; a real console derives every row from the authenticated principal's scope. For conditional admission, `uid: null` means create only, a string means continue exactly that incarnation, and omission is unconditional. A string `uid` cannot carry `initialData` because an existing-incarnation condition forbids creation. ## Async dispatch `dispatch()` hands an input to an instance for asynchronous processing, returning a receipt immediately: ```ts import { dispatch } from '@fabric-harness/sdk'; const receipt = await dispatch({ agent: 'assistant', id: 'u1', input: 'summarize today' }); // { dispatchId, acceptedAt } ``` Over HTTP, `POST /agents/:name/:id/dispatch` returns `202` + the receipt: ```sh curl -XPOST localhost:4317/agents/assistant/u1/dispatch -d '{"input":"summarize today"}' ``` Dispatch processing is **idempotent by `dispatchId`** (a re-delivered dispatch is applied at most once). The `fh dev` server uses an in-process queue; with `runtime: 'temporal'`, durable delivery uses `temporalDispatchQueue` — dispatches survive worker/process restarts. ## Streaming conversation (WebSocket) `GET /agents/:name/:id` upgrades to a conversational WebSocket: ```ts const ws = new WebSocket('ws://localhost:4317/agents/assistant/u1'); // server → { type: 'ready', target: 'agent', name, instanceId } ws.send(JSON.stringify({ type: 'prompt', requestId: 'r1', message: 'hello' })); // server → { type: 'started', requestId } // → { type: 'event', requestId, event } (streamed, repeated) // → { type: 'result', requestId, result, session } ``` Send `{ type: 'ping' }` for a `pong` heartbeat. Prompts on one connection are serialized. ## Jobs and persistent agents Use a finite job for one typed invocation and a persistent agent for an addressable conversation. Both share the same session, tool, policy, sandbox, and deployment surfaces. --- # React applications Canonical: https://harness.techfabric.com/docs/building/react Build agent conversations and finite-run interfaces with the public Fabric client protocol. `@fabric-harness/react` provides `FabricProvider`, `useFabricClient`, `useFabricAgent`, and `useFabricJob`. The package talks only to the public authenticated HTTP protocol, so the same UI can target local development, a Node artifact, Databricks Apps, or another compatible deployment. ```sh pnpm add @fabric-harness/react @fabric-harness/client react ``` ## Configure the provider Create one client for the application. Authentication headers stay in the application transport and are not placed in agent messages or model context. ```tsx title="src/main.tsx" import { FabricProvider } from '@fabric-harness/react'; export function Root({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` For server-rendered frameworks, pass a request-scoped client through `client`. Hooks use stable external-store server snapshots and start network observation only after the component mounts. ## Agent conversations `useFabricAgent` catches up from offset zero, streams text, reasoning, and tool-argument deltas over SSE, replaces transient parts with the canonical durable assistant message, deduplicates reconnect replay, resets stale projections when the stream incarnation changes, and applies truncation records. Render the stable `messages` projection; `transcript` remains available for diagnostics and compatibility. Optimistic messages remain separate in `pending` until their submission-correlated input is observed. ```tsx import { useFabricAgent } from '@fabric-harness/react'; function SupportChat({ customerId }: { customerId: string }) { const chat = useFabricAgent({ agent: 'support', id: customerId, session: 'default' }); async function send(text: string) { const submissionId = await chat.send(text); const settled = await chat.wait(submissionId, { timeoutMs: 30_000 }); console.log(settled.outcome); } return ( <> {chat.messages .filter((message) => message.display === 'visible') .map((message) => (

{message.parts .filter((part) => part.type === 'text') .map((part) => part.text) .join('')}

))} {chat.pending.map((message) => ( ))} ); } ``` While a tool call is still streaming, its message part has `{ type: 'dynamic-tool', state: 'input-streaming', inputText }`. Treat `inputText` as untrusted, partial JSON; only `input-available` contains the provider's completed parsed input. Send image attachments with the normal delivered-message shape: ```ts await chat.send({ kind: 'user', body: 'Inspect this screenshot', attachments: [{ type: 'image', mimeType: 'image/png', data: base64 }], }); ``` ## Finite runs `useFabricJob` admits an asynchronous run, follows its offset events, publishes the terminal run envelope, and exposes retry and abort. Starting a newer invocation supersedes the previous observation, so a late terminal response from the old run cannot replace the new run's state. Use `invokeSync` only for short request/response work. ```tsx const report = useFabricJob<{ accountId: string }, { url: string }>('account-report'); await report.invoke( { accountId: 'account-42' }, { idempotencyKey: 'account-report:account-42' }, ); console.log(report.status, report.run?.output?.url); await report.abort(); ``` Agent observation reconnects from the latest durable offset with bounded exponential backoff and resets the delay after receiving an update. Set `live: 'poll'` in `createFabricAgentStore` when SSE is intentionally unavailable; the default is automatic SSE with polling fallback. Stores with no subscribers or in-flight work are evicted, which keeps long-lived applications with dynamic agent and job addresses bounded. ## Runnable application [`examples/react-chat`](/docs/reference/source-access) starts `fh dev --mock` and Vite with one `pnpm dev` command. It includes multiple persistent agent instances, image attachments, optimistic retry, abort, canonical transcript streaming, and a finite job panel. Its UI renders the public conversation-message projection, including streaming text and tool states. The example consumes `@fabricorg/ui` for shared Fabric semantic tokens and operator controls; this UI package remains an application dependency and is not required by the Harness SDK or runtime. Its automated browser check captures desktop/mobile light and dark layouts and fails on browser errors or mobile horizontal overflow. --- # Roles Canonical: https://harness.techfabric.com/docs/building/roles System-prompt overlays you can apply per agent, session or call, so one agent definition serves several jobs. Roles live under `.fabricharness/roles/.md`. They are **system-prompt overlays**, not persisted user messages. ## Format ```md --- description: Senior backend engineer focused on safe, minimal changes. model: openai/gpt-5.5 --- You are a senior backend engineer. Prefer small, well-tested changes. Do not make broad refactors unless required. ``` ## Precedence ``` call role > session role > agent role ``` ```ts // Agent default const fabricAgent = await init({ role: 'engineer' }); // Session-scoped override (first arg is the session id; pass undefined to auto-generate) const session = await fabricAgent.session(undefined, { role: 'reviewer' }); // Call-scoped override await session.prompt('Review this PR', { role: 'reviewer' }); ``` ## Why a role and not just a prompt A role is reusable, scoped, and never appears in the user-message history that the model sees. That keeps the conversation clean and prevents role text from being summarized away during compaction. --- # Sandbox connectors Canonical: https://harness.techfabric.com/docs/building/sandbox-connectors Modular remote sandbox adapters for Daytona, E2B, Modal, and custom providers. TechFabric Harness treats every execution backend as a `SandboxEnv`: a small interface for shell execution, file IO, path scoping, cleanup, and optional snapshots. Agent/session/runtime code does not need to know whether work is running in the virtual sandbox, local process, Docker, Daytona, E2B, Modal, Cloudflare, Foundry, Kubernetes, or another provider. ## Contract A remote provider adapter implements `RemoteSandboxApi` and wraps it with `createRemoteSandboxEnv`: ```ts import { createRemoteSandboxEnv } from '@fabric-harness/sdk'; import type { RemoteSandboxApi } from '@fabric-harness/sdk'; const api: RemoteSandboxApi = { async exec(command, options) { /* provider shell call */ }, async readFile(path) { /* UTF-8 file read */ }, async readFileBuffer(path) { /* binary file read */ }, async writeFile(path, content) { /* file write */ }, async stat(path) { /* file stat */ }, async readdir(path) { /* list names */ }, async exists(path) { /* existence check */ }, async mkdir(path, options) { /* mkdir */ }, async rm(path, options) { /* remove */ }, }; export const sandbox = createRemoteSandboxEnv(api, { cwd: '/workspace' }); ``` Provider SDK objects and credentials stay in your app code. Fabric only receives file paths, bytes, commands, cwd, env, and timeout values. ## Package adapters `@fabric-harness/connectors` ships dependency-free, structural adapters. Your app owns the provider SDK dependency and passes an initialized sandbox object into Fabric. ```sh npm install @fabric-harness/connectors ``` The connector package declares provider SDKs as optional peers, so applications install only the provider they use. ### Why maintained adapters instead of copied templates A project-installed template is a useful starting point, but the generated adapter becomes application code as soon as it is copied. Fabric keeps the common provider mapping in a versioned package while still letting the application own sandbox creation, credentials, resource limits, and lifecycle. | Concern | Maintained Fabric adapter | Copied project template | |---|---|---| | Provider SDK changes | Bounded peer ranges and one shared compatibility table | Each application must detect and port SDK changes | | Runtime behavior | One `SandboxEnv` contract across Node, Temporal, Cloudflare, and Databricks | Behavior can drift between generated copies | | Recovery | Portable references and decoder registration support cross-process reattachment | Reattachment must be designed per project | | Cancellation | Shared timeout, abort, orphan-settlement, and cleanup semantics | Every copied adapter must preserve the runtime rules itself | | Security | Credentials stay in the provider client; capabilities and tenant ownership remain enforceable by the runtime | Security depends on each generated copy remaining current | | Verification | The same conformance runner checks binary files, cwd/env, streaming, timeout, abort, reconnect, and cleanup | Tests and retained evidence are application-owned | | Customization | Structural interfaces accept provider objects without importing their SDK into Harness core | Direct editing is flexible but creates a permanent fork | This does not make provider infrastructure implicit. The application still provisions the sandbox and chooses whether Fabric owns cleanup. Use a project-local `remoteSandbox()` adapter when an organization needs a provider SDK version or lifecycle policy outside the maintained compatibility range. | Provider | Compatible SDK range | Contract-tested version | |---|---|---| | Daytona | `@daytona/sdk >=0.195.0 <1` | `0.195.0` | | E2B | `@e2b/code-interpreter >=2.6.1 <3` | `2.6.1` | | Modal | `modal >=0.9.0 <1` | `0.9.0` | | Vercel | `@vercel/sandbox >=1.10.1 <2` | `1.10.1` | | Kubernetes | `@kubernetes/client-node >=0.21.0 <0.22` | `0.21.0` | | Cloudflare Sandbox | `@cloudflare/sandbox >=0.9.2 <1` | `0.9.2` | | Cloudflare Shell | `@cloudflare/shell >=0.3.7 <0.4` | `0.3.7` | ### Daytona ```ts import { Daytona } from '@daytona/sdk'; import { daytonaSandbox } from '@fabric-harness/connectors'; const client = new Daytona({ apiKey: process.env.DAYTONA_API_KEY }); const remote = await client.create({ image: 'ubuntu:latest' }); const fabric = await init({ sandbox: daytonaSandbox(remote, { cleanup: true }), }); ``` The adapter maps Daytona filesystem/process calls to Fabric's `SandboxEnv` and uses Daytona's workdir when available through `daytonaSandboxFactory()`. ### E2B ```ts import { Sandbox } from '@e2b/code-interpreter'; import { e2bSandbox } from '@fabric-harness/connectors'; const remote = await Sandbox.create(); const fabric = await init({ sandbox: e2bSandbox(remote, { cleanup: true }), }); ``` If your E2B package exposes a different class, adapt it to the structural `E2BSandboxLike` shape or wrap it in `remoteSandboxEnv()`. ### Modal Fabric maps the native Modal TypeScript SDK sandbox directly. The structural `modalSandbox()` helper remains available for custom provider handles. ```ts import { ModalClient } from 'modal'; import { modalSdkSandbox } from '@fabric-harness/connectors/modal'; const client = new ModalClient(); const app = await client.apps.fromName('fabric-harness', { createIfMissing: true }); const image = client.images.fromRegistry('node:22-alpine'); const remote = await client.sandboxes.create(app, image, { workdir: '/workspace' }); const fabric = await init({ sandbox: modalSdkSandbox(remote, { cleanup: true }) }); ``` ## Generic adapter Use `remoteSandbox()` to produce a reusable `SandboxFactory`: ```ts import { remoteSandbox } from '@fabric-harness/connectors'; export function providerSandbox(client): SandboxFactory { return remoteSandbox({ exec: (command, options) => client.exec(command, options), readFile: (path) => client.readFile(path), readFileBuffer: (path) => client.readFileBuffer(path), writeFile: (path, content) => client.writeFile(path, content), stat: (path) => client.stat(path), readdir: (path) => client.readdir(path), exists: (path) => client.exists(path), mkdir: (path, options) => client.mkdir(path, options), rm: (path, options) => client.rm(path, options), }, { workspacePath: '/workspace' }); } ``` ## Stream command output `SandboxExecOptions` exposes the same output callbacks for local, Docker, and remote sandboxes: ```ts const result = await env.exec('npm test', { timeout: 120_000, onStdout: (chunk) => process.stdout.write(chunk), onStderr: (chunk) => process.stderr.write(chunk), }); ``` E2B, Vercel, and Kubernetes forward provider output as it arrives. Daytona's compatible command API returns collected output, so the adapter invokes the callbacks immediately before the command promise settles. Custom and Modal adapters emit incremental chunks through the same options. Resource and egress enforcement belongs in the provider's sandbox creation call. Configure CPU, memory, image, network blocking, and domain allowlists before passing the provider object to Fabric; use Fabric `policy` for tool, command, filesystem, and application-level network decisions inside the session. ## Certification helper Use the full contract runner before deploying a provider adapter: ```ts import { assertSandboxCertification } from '@fabric-harness/connectors'; const env = daytonaSandbox(remote, { cleanup: true }); const report = await assertSandboxCertification(env, { provider: 'daytona', sdkPackage: '@daytona/sdk', sdkVersion: '0.195.0', credentialed: true, reconnect: async (ref) => daytonaSandbox( await client.get((ref.providerData as { workspaceId: string }).workspaceId), ), verifyCleanup: async () => { /* assert the workspace was deleted */ }, }); ``` The runner verifies: 1. POSIX shell execution and output 2. exact binary file round trips 3. working directory and environment forwarding 4. timeout exit `124` and abort exit `130` 5. stdout/stderr callbacks 6. JSON-safe portable references and cross-client reconnect 7. provider cleanup verification The returned `SandboxCertificationReport` is safe to retain as CI evidence: it records provider, SDK version, timings, and check outcomes without credentials or workspace content. ## Verify a provider connection Live tests are skipped unless enabled: ```sh FABRIC_DAYTONA_TEST=1 DAYTONA_API_KEY=... pnpm --filter @fabric-harness/connectors test FABRIC_E2B_TEST=1 E2B_API_KEY=... pnpm --filter @fabric-harness/connectors test FABRIC_MODAL_TEST=1 MODAL_TOKEN_ID=... MODAL_TOKEN_SECRET=... pnpm --filter @fabric-harness/connectors test ``` ## Connector recipes `fh add` still prints markdown recipes for project-local adapters: ```sh fh add fh add daytona | claude fh add https://e2b.dev --category sandbox | claude ``` Recipes are useful when the provider SDK version or organization conventions require custom code. Package adapters are better when your provider object matches the structural interfaces. ## Provider adapter checklist - Scope every path to the provider workspace root. - Honor `cwd`, `env`, and `timeout` on `exec`. - Convert text and binary content correctly. - Keep API keys and provider SDK objects outside model context/history. - Enforce provider-specific network/resource limits before launching work. - Implement `cleanup` for temporary sandboxes. - Implement `snapshot`/`restore` only when the provider supports it truthfully. - Add a unit test with a fake provider object. - Add a live test behind an env gate. --- # Sandboxes Canonical: https://harness.techfabric.com/docs/building/sandboxes Where shell commands and tool calls actually run — virtual, local, docker, cloudflare, daytona, modal, foundry-hosted, and remote SDK-backed targets. import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; Every session has a sandbox — an isolated environment exposing filesystem, shell, and metadata APIs. TechFabric Harness defines a backend-agnostic `SandboxEnv` interface and ships several implementations. ## The interface ```ts export interface SandboxEnv { exec(command: string, options?: { cwd?: string; env?: Record; timeout?: number; }): Promise; readFile(path: string): Promise; readFileBuffer(path: string): Promise; writeFile(path: string, content: string | Uint8Array): Promise; stat(path: string): Promise; readdir(path: string): Promise; exists(path: string): Promise; mkdir(path: string, options?: { recursive?: boolean }): Promise; rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise; cwd: string; resolvePath(path: string): string; snapshot?(): Promise; restore?(snapshot: SandboxSnapshot): Promise; cleanup(): Promise; } ``` ## Built-in sandboxes Start simple: the bare `@fabric-harness/sdk` `defineAgent` wrapper defaults to `sandbox: 'virtual'`, so a first agent does not need Docker, Cloudflare, or a remote sandbox provider. | Backend | Use first when | Capability notes | | --- | --- | --- | | `virtual` (default for bare import) | You want the fastest no-container path for support bots, routing, tests, and lightweight filesystem/search work. | In-memory filesystem + bash-like shell via `just-bash`; no network; process-level isolation; no snapshot/restore. | | `local` | CI/repo automation intentionally needs host tools like `git`, `gh`, `npm`, or `python`. | Host process execution confined to the workspace root (see below). Scope commands and secrets carefully. | | `docker` | The agent runs untrusted shell, data analysis, package installs, or generated code. | Container isolation; preferred production pilot sandbox for risky shell workloads. | | `cloudflare` | You deploy to Workers and need Cloudflare Sandbox containers per session. | Provider-managed container isolation with Durable Object session storage. | | `empty` | You only need model calls and custom tools; no filesystem or shell. | No shell/filesystem effects. | ## Local sandbox confinement The `local` backend is scoped to the workspace root. Filesystem operations (`readFile`/`writeFile`/`mkdir`/`rm`/…) resolve paths against the workspace, follow symlinks, and reject anything outside it. `session.shell()` commands are scanned before they run: absolute paths, `~` expansion, `..` traversals, and redirection targets (`>`, `>>`, `<`) that resolve outside the workspace root are denied with a `SANDBOX_ESCAPE_BLOCKED` `FabricError` — the same observable policy-denial path as other policy violations, never a silent skip or a crash. In-workspace symlinks that point outside the workspace are denied too. Workloads that legitimately need other directories (for example `/tmp` scratch space) opt them in explicitly with the `allowedPaths` escape hatch: ```ts import { LocalSandboxEnv } from '@fabric-harness/sdk'; const sandbox = new LocalSandboxEnv({ workspacePath: process.cwd(), allowedPaths: ['/tmp/fabric-scratch'], // additional allowed roots }); await init({ sandbox }); ``` `allowedPaths` is also available as `metadata.allowedPaths` on `createSandboxEnv({ backend: 'local', … })`, and forked sandboxes inherit it. Confinement is a static guardrail, not a hard security boundary. Paths constructed dynamically at runtime (shell variables, encoded payloads, substitution tricks that hide the path characters) cannot be statically analyzed, and the check runs before exec, so a symlink swapped in afterwards (a TOCTOU race) is not caught. Quoted string arguments that merely *begin* with an outside absolute path can be over-denied; add the root to `allowedPaths` or rephrase. For untrusted workloads, use `docker` or a provider container/microVM, which enforce a real isolation boundary. ## Decision matrix | Workload | Recommended sandbox | | --- | --- | | Hello world, support FAQ, routing, typed extraction | `virtual` | | GitHub issue triage in CI | `local` + scoped `defineCommand()` commands | | Data analysis over uploaded files | `docker` | | Full coding agent with Linux tools | Docker, Daytona, E2B, Modal, Kubernetes, or Cloudflare Sandbox | | Edge/serverless support agent | Cloudflare target + virtual/filesystem source, or Cloudflare Sandbox when real shell/container support is required | Treat `virtual` as a DX/performance feature, not a hard security boundary. Use Docker or a provider container/microVM for untrusted code. ### What developers verify A successful command is only one part of sandbox evidence. Inspect declared capabilities first, then prove binary files, working directory and environment, streaming, timeout, abort, portable references where supported, reconnect, and cleanup. ## Selecting a sandbox The default import injects `sandbox: 'virtual'` automatically. Pick another by passing a value: ```ts import { defineAgent } from '@fabric-harness/sdk'; import { getSandbox } from '@cloudflare/sandbox'; import { createCloudflareSandboxEnv } from '@fabric-harness/cloudflare'; export default defineAgent({ run: async ({ init, env }) => { const sandbox = createCloudflareSandboxEnv(getSandbox(env.Sandbox, 'session-1')); const session = await (await init({ sandbox })).session(); return await session.prompt('hello edge'); }, }); ``` **Example:** `examples/with-cloudflare-sandbox/`. Edge-deployed via `fabric-harness build --target cloudflare`. ```ts import { defineAgent, schema } from '@fabric-harness/sdk/strict'; export default defineAgent({ name: 'long-running', input: schema.object({ jobId: schema.string() }), run: async ({ init, input }) => { const fabric = await init({ runtime: 'temporal', sandbox: 'local', compaction: { enabled: false }, }); return await (await fabric.session()).prompt(`Process job ${input.jobId}`); }, }); ``` **Example:** `examples/with-temporal/`. Uses `/strict` because auto-compaction is non-deterministic across replays. ```ts import { defineAgent } from '@fabric-harness/sdk'; import { AzureOpenAIModelProvider, createAzureKeyVaultSecretResolver } from '@fabric-harness/azure'; const provider = new AzureOpenAIModelProvider({ endpoint: process.env.AZURE_OPENAI_ENDPOINT!, apiKey: process.env.AZURE_OPENAI_API_KEY!, deployment: 'gpt-5.5', }); export default defineAgent({ run: async ({ init, input }) => { const fabric = await init({ modelProvider: provider }); return await (await fabric.session()).prompt(input.prompt); }, }); ``` **Example:** `examples/with-azure/`. Build with `fabric-harness build --target foundry-hosted-agent`. ```ts import { defineAgent } from '@fabric-harness/sdk'; import { daytonaSandbox } from '@fabric-harness/connectors'; import { Daytona } from '@daytona/sdk'; const client = new Daytona({ apiKey: process.env.DAYTONA_API_KEY }); export default defineAgent({ run: async ({ init, input }) => { const remote = await client.create({ image: 'node:22' }); const fabric = await init({ sandbox: daytonaSandbox(remote, { cleanup: true }) }); return await (await fabric.session()).prompt(input.prompt); }, }); ``` **Example:** `examples/with-daytona/`. Daytona credentials stay in the Daytona client. ```ts import { defineAgent } from '@fabric-harness/sdk'; import { ModalClient } from 'modal'; import { modalSdkSandbox } from '@fabric-harness/connectors/modal'; export default defineAgent({ run: async ({ init, input }) => { const client = new ModalClient(); const app = await client.apps.fromName('fabric-harness', { createIfMissing: true }); const remote = await client.sandboxes.create(app, client.images.fromRegistry('node:22-alpine')); const sandbox = modalSdkSandbox(remote, { cleanup: true }); try { const fabric = await init({ sandbox }); return await (await fabric.session()).prompt(input.prompt); } finally { await sandbox.cleanup(); client.close(); } }, }); ``` **Example:** `examples/with-modal/`. Modal credentials remain in `ModalClient`. ```ts import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent({ run: async ({ init, input }) => { const fabric = await init({ sandbox: { backend: 'docker', image: 'node:22', cleanup: true }, }); return await (await fabric.session()).prompt(input.prompt); }, }); ``` **Example:** `examples/with-docker/`. Per-session container isolation; good fit for coding agents. ## Sandbox vs runtime vs target These are three orthogonal axes: | Axis | Controls | Where it's set | |---|---|---| | **Sandbox** | Where shell commands and tool calls run. | `init({ sandbox })`. | | **Runtime** | How sessions persist. `stateless` / `inline` / `temporal`. | `init({ runtime })`. | | **Target** | The build artifact: Node process, Cloudflare Worker, Temporal worker, Foundry hosted agent. | `fabric-harness build --target `. | A Cloudflare Worker target most naturally pairs with the Cloudflare sandbox. A Temporal target most naturally pairs with `runtime: 'temporal'` and the `/strict` import. But the axes don't lock — you can deploy a Node target with a Daytona sandbox if you want. ## Remote and platform sandboxes `RemoteSandboxApi` keeps provider SDK types out of `@fabric-harness/sdk`, so application code can select a backend without changing the agent/session contract. | Integration path | Use it for | |---|---| | [`@fabric-harness/connectors`](/docs/building/sandbox-connectors) | Daytona, E2B, Modal, and provider-owned remote sandbox objects. | | [`@fabric-harness/azure/aks-sandbox`](/docs/deployment/azure#aks-sandbox-sandboxenv) | Pod-backed execution on AKS. | | [Databricks SQL sandbox](/docs/ecosystem/sandboxes/databricks-sql) | Governed SQL Warehouse execution; `session.shell()` executes SQL rather than bash. | | `remoteSandboxEnv()` | Kubernetes, microVM, or proprietary execution services that implement the common remote contract. | Use `fh add` when a provider needs project-specific lifecycle or SDK mapping. The [sandbox capability matrix](/docs/reference/sandboxes-matrix) shows how to inspect capabilities at runtime. --- # Session memory Canonical: https://harness.techfabric.com/docs/building/session-memory Persistent key/value recall across sessions, scoped by tenant. Distinct from session entries (audit log). `session.memory` lets agents remember facts across sessions — borrower preferences, prior outcomes, learned task history. It's a typed key/value store backed by `SessionMemory`, scoped automatically by the session's `tenantId`. ## Memory vs. entries | | `session.memory` | session entries (`fh export-audit`) | |---|---|---| | Purpose | Recall — facts the agent should remember | Audit — what the agent did | | Persistence | User-controlled key/value | Append-only log | | Visibility to model | Only when the agent reads + injects | Through compaction / replay | | Size | Bounded per key | Grows with each action | | Typical reads | Targeted: `memory.get('borrower:preferences')` | Full session view: `fh inspect`, `fh logs` | Memory writes do NOT land in the session log. Audit is unaffected. ## API ```ts const fabric = await init({ tenantId: 'tenant-acme', memory: postgresSessionMemory({ client: pgClient }), // or inMemorySessionMemory() }); const session = await fabric.session(); // Get / set typed values await session.memory.set({ key: 'borrower:42:preferences', value: { contactChannel: 'sms', timezone: 'America/Phoenix' }, ttlSeconds: 60 * 60 * 24 * 30, // optional 30-day TTL }); const entry = await session.memory.get<{ contactChannel: string }>('borrower:42:preferences'); // { key, value, tenantId, updatedAt, expiresAt?, metadata? } // List with prefix + recency filters const recent = await session.memory.list({ keyPrefix: 'borrower:42:*', limit: 10 }); await session.memory.delete('borrower:42:preferences'); ``` `session.memory` auto-scopes every operation to the session's `tenantId`. Two tenants writing to the same key get isolated values. ## Backends | Backend | Where | Use when | |---|---|---| | `inMemorySessionMemory()` | `@fabric-harness/sdk` | Tests, single-process pilots, ephemeral agents. | | `postgresSessionMemory({ client })` | `@fabric-harness/node` | Production. Survives restarts, shares across a fleet. | Postgres schema: ```sql CREATE TABLE fabric_harness_session_memory ( tenant_id TEXT NOT NULL DEFAULT '', key TEXT NOT NULL, value JSONB NOT NULL, metadata JSONB, expires_at TIMESTAMPTZ, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (tenant_id, key) ); ``` Created automatically on construction. Pass `initialize: false` if you manage migrations separately. ## Patterns **Borrower preferences (long-term).** Set on first contact; read on subsequent sessions to skip re-asking. ```ts const prefs = await session.memory.get<{ channel: 'sms' | 'email' }>('borrower:42:contact'); if (!prefs) { await session.prompt('Ask the borrower how they prefer to be contacted.'); await session.memory.set({ key: 'borrower:42:contact', value: { channel: 'sms' } }); } ``` **Task history (medium-term).** Use TTL so old context doesn't accumulate. ```ts await session.memory.set({ key: `task:${taskId}:summary`, value: { result, durationMs }, ttlSeconds: 60 * 60 * 24 * 7, // 7 days }); ``` **Cross-tenant guards.** Memory operations scope by `tenantId` automatically. The SDK never mixes tenants — `set({ key: 'k' })` from `tenant-a` and `tenant-b` produce isolated rows. ## Reset / cleanup Memory has no built-in expiry sweeper — TTL'd rows are filtered out on read. For high-volume deployments, run a periodic `DELETE FROM fabric_harness_session_memory WHERE expires_at < NOW()` from your scheduler. The `expires_at` column is indexed for that purpose. ## See also - [Multi-tenancy](/docs/operating/multi-tenancy) - [Audit export](/docs/operating/audit-export) --- # Sessions and Prompts Canonical: https://harness.techfabric.com/docs/building/sessions-prompts How agent.session() and session.prompt() work, and what the harness loop does between the model and your tools. A session is a persisted message/context thread. Inside a session, you can run prompts, skills, tasks, and shell commands. ## Create a session ```ts 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. ```ts 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. > `schema` is also exported from `@fabric-harness/sdk` — same API in both. ```ts 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 ```ts 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. ```ts 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 ```ts import { defineCommand } from '@fabric-harness/sdk'; 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](/docs/building/tools) and [Commands](/docs/building/commands). ## Reasoning streams Reasoning-capable models (Anthropic Claude with extended thinking, OpenAI o-series, Gemini 2.5 with thought summaries) emit a separate "thinking" content channel. TechFabric Harness surfaces it on `ModelResponse.thinking` and emits a `text_delta` event with `kind: 'thinking'` so streaming consumers can render it apart from the final answer. ```ts const stream = session.stream('Plan the migration in detail.'); for await (const event of stream) { if (event.type === 'text_delta' && event.data?.kind === 'thinking') { renderThinking(event.data.delta); // grey/italic in your UI } else if (event.type === 'text_delta') { renderOutput(event.data?.delta); // normal model output } } ``` Provider notes: - **Anthropic**: thinking is emitted when the request includes `extended_thinking: true` (set via `headers` on `AnthropicModelProvider`). - **OpenAI o-series**: emitted automatically as `reasoning_content` on the chat completion message. - **Gemini 2.5**: emitted when `thinking_config` is set on the request; consumed via the same `thinking` field. Other providers leave `ModelResponse.thinking` undefined; consumers should fall back to `text_delta` without the `thinking` kind. ### Token-level streaming `OpenAICompatibleModelProvider` and `AnthropicModelProvider` both expose a `stream()` method that returns an `AsyncIterable`. The loop uses it automatically when present, emitting `text_delta` events as tokens arrive (instead of buffering until the response completes). UIs see word-by-word output; per-call cost telemetry still lands on the final aggregated chunk. Consumers don't need code changes — `session.stream()` already understands `text_delta`: ```ts for await (const event of session.stream(prompt)) { if (event.type === 'text_delta') process.stdout.write(event.data?.delta ?? ''); } ``` Mid-stream failures fall through to the loop's normal error path. Retries are NOT automatic for streamed calls — partial state can't be safely re-applied. ## `session.skill(name, options?)` Invoke a Markdown skill from `.fabricharness/skills//SKILL.md`. Args interpolate into the skill body, and `result` validates the typed return value. ```ts 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. ```ts 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. ```ts const out = await session.shell('npm test', { cwd: '/workspace' }); ``` ## `session.fs` and `agent.fs` Use `session.fs` for host-side filesystem plumbing that should not appear in model history: staging input files, collecting scratch output, or checking whether generated artifacts exist. It uses the same sandbox backend and cwd as the session. ```ts const fabric = await init({ sandbox: 'virtual' }); const session = await fabric.session('build-123'); await session.fs.writeText('input/ticket.md', ticketBody); const exists = await session.fs.exists('input/ticket.md'); const files = await session.fs.list('input'); const text = await session.fs.readText('input/ticket.md'); ``` `agent.fs` is also available for quick setup scripts. It is backed by a lazily-created default session; prefer `session.fs` when you need explicit session identity, audit correlation, or lifecycle control. Filesystem aliases follow familiar sandbox conventions: `readFile`, `readFileBuffer`, `writeFile`, `readdir`, and `rm`. ## Session history ```ts 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. --- # Skills Canonical: https://harness.techfabric.com/docs/building/skills Reusable Markdown procedures an agent loads on demand, so a long instruction lives in one file rather than in every prompt. Skills live under `.fabricharness/skills//SKILL.md`. They are Markdown-first: the body is the instructional prompt, the frontmatter declares metadata. ## Format ```md --- name: triage-issue description: Triage a GitHub issue and recommend severity, labels, and next action. model: openai/gpt-5.5 --- You are triaging a GitHub issue. Steps: 1. Read the issue using the `gh` command. 2. Inspect relevant files if available. 3. Determine severity. 4. Recommend labels. 5. Decide whether a fix can be proposed. ``` ## Invocation ```ts const result = await session.skill('triage-issue', { args: { issueNumber: 42, repository: 'octocat/repo' }, commands: [gh], result: schema.object({ severity: schema.enum(['low', 'medium', 'high', 'critical']), summary: schema.string(), recommendedLabels: schema.array(schema.string()), fixSuggested: schema.boolean(), }), }); ``` The framework: 1. Loads the skill by name. 2. Interpolates `args` into the prompt (template variables in the body, plus a structured arguments preamble). 3. Runs the harness loop with the chosen tools/commands. 4. Validates the typed result. ## Import a skill directly A skill does not have to live under `.fabricharness/skills/`. Import its `SKILL.md` and the whole directory compiles at build time: ```ts import severityTriage from "../../skills/severity-triage/SKILL.md"; import { defineAgent } from "@fabric-harness/sdk"; export default defineAgent({ name: "incident-triage", async run({ init }) { const fabric = await init({ model: "openai/gpt-5.5", skills: [severityTriage] }); const session = await fabric.session(); return await session.skill("severity-triage", { args: { report } }); }, }); ``` The Markdown body becomes the prompt, the frontmatter becomes `name`, `description`, `model`, and metadata, and every sibling file becomes a packaged resource the model reads on demand — the same shape directory loading produces, so an imported skill and a workspace skill are indistinguishable at runtime. Importing buys two things over loading by name: - **Portability.** The skill sits next to the code that uses it, so it can ship from a shared package instead of a per-project directory. - **Build-time failure.** A wrong path fails the build; a wrong name in `session.skill('...')` fails at model time, after the run has started. Both forms are supported, and `.fabricharness/skills/` is unchanged. ### Markdown text imports Any other `.md` import compiles to a string. Compose it with `defineSkill()` when the file is not a `SKILL.md`: ```ts import rubric from "../../skills/severity-triage/rubric.md"; import { defineSkill } from "@fabric-harness/sdk"; const closure = defineSkill({ name: "closure-summary", description: "Summarize how an incident was closed out.", instructions: `Summarize the closure in three bullets.\n\n${rubric}`, }); ``` `defineSkill()` also accepts `model`, `metadata`, and `packaged`. A skill carrying `packaged` registers that directory with the `read` tool, so every resource it advertises is readable. ### Type declarations `.md` imports are typed by an opt-in ambient declaration, referenced once per project: ```ts title=".fabricharness/fabric-env.d.ts" /// ``` `fh init` writes this file. It is opt-in rather than automatic because `*.md` is a global wildcard that would otherwise collide with projects that already type Markdown through Vite, MDX, or their own loader. See [`examples/with-imported-skills`](/docs/reference/source-access) for a runnable version. ## Why skills, not just prompts - **Reuse.** Multiple agents can call the same skill. - **Versioning.** Skills are tracked in source control and can be distributed as packaged skill directories. - **Auditability.** Skill instructions are visible and reviewable, separate from agent code. - **Model overrides.** A skill can declare its own model (for cheap classifiers, big-context reviewers, etc.). --- # Subagents Canonical: https://harness.techfabric.com/docs/building/subagents Give persistent agents named specialist roles and delegate finite work through tasks or invoke. TechFabric Harness uses two explicit delegation primitives instead of introducing a second agent runtime: - Persistent agents declare `subagents`, which become named role overlays available to their sessions. - Finite agents delegate work with `task()` or invoke another registered finite agent with `invoke()`. ## Persistent specialist roles ```ts title=".fabricharness/agents/research.ts" import { createAgent } from '@fabric-harness/sdk'; export default createAgent(({ id }) => ({ name: `research-${id}`, instructions: 'Coordinate research and return sourced conclusions.', subagents: [ { name: 'analyst', content: 'Inspect data and quantify findings.' }, { name: 'reviewer', content: 'Challenge assumptions and identify missing evidence.' }, ], })); ``` `subagents` use the same role representation and precedence rules as normal roles. They are system prompt overlays, not persisted user messages, and they do not create another process or hidden workflow runtime. ## Delegate finite work ```ts title=".fabricharness/jobs/research.ts" import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ topic: string }>({ name: 'research', run: async ({ input, task, invoke }) => { const evidence = await task(`Collect evidence about ${input.topic}`, { id: 'collect-evidence', }); const review = await invoke({ job: 'review-evidence', input: { topic: input.topic, evidence }, }); return { evidence, reviewRunId: review.runId }; }, }); ``` Use `task()` when the child work belongs to the current session. Use `invoke()` when the delegated work has its own registered definition, run identity, and admission policy. Temporal turns tasks into child workflows; local and Node runtimes preserve the same public contract. Failures are explicit: unknown invoked agents, task-depth overflow, policy denial, cancellation, and child-run failure reject the parent call. See [Tasks](/docs/building/tasks) and [Persistent agents](/docs/building/persistent-agents) for durability and inspection behavior. --- # Tasks Canonical: https://harness.techfabric.com/docs/building/tasks Durable child runs and delegated agents, which survive a restart and report back to the session that started them. A **task** is a child or delegated agent run. Tasks let an agent split work into named, durable sub-runs that can be inspected, cancelled, and (on the Temporal target) replayed independently. ## Spawn a task ```ts const result = await session.task('Refactor the authentication middleware', { id: 'refactor-auth', result: schema.object({ filesChanged: schema.array(schema.string()), summary: schema.string(), }), }); ``` Options: | Option | Purpose | | --- | --- | | `id` | Stable id (good for resuming, dedup, and CLI inspection). | | `result` | Schema for typed output validation. | | `model` | Override the model for this task. | | `commands` | Scope shell commands available inside the task. | | `cwd` | Working directory for the child session's shell/file tools. | | `checkpoint` | Persist a checkpoint before and after the task (boolean or label). | ## Nesting limit (`MAX_TASK_DEPTH = 4`) A task can spawn its own task, which can spawn its own — up to **four levels deep**. The fifth nested call throws: ```ts // session.task → child.task → grandchild.task → great-grandchild.task ✓ // great-great-grandchild.task → throws "Task nesting exceeds MAX_TASK_DEPTH (4)" ``` The cap prevents runaway recursion. Each [`task_start` / `task_end`](/docs/reference/events) event carries a `depth: number` and a `parentSessionId`, so subscribers can render a tree: ```ts onEvent: (event) => { if (isEvent(event, 'task_start')) { console.log(`${' '.repeat(event.data.depth)}↳ ${event.data.taskId}`); } } ``` ## Inspect or cancel from the CLI ```sh fh tasks fh task refactor-auth fh cancel-task refactor-auth --actor preetham --reason "Replaced by manual fix" ``` ## Durable tasks on the Temporal target When the session runs on the Temporal worker target, each task becomes a child workflow. That gives you: - crash-safe execution, - retries for model and tool calls, - replayable history, - durable cancellation signals. ## Checkpoints inside a task Tasks can mark their own progress with checkpoints: ```ts await session.checkpoint.create({ label: 'before-fix' }); // ... risky work ... await session.checkpoint.create({ label: 'after-fix' }); ``` If the sandbox supports snapshots, the checkpoint records a snapshot ref so you can restore filesystem state along with the conversation state. --- # Test Without Credentials Canonical: https://harness.techfabric.com/docs/building/test-without-credentials The complete no-credential story — mock model, single-file runs, stub sessions, mock sandboxes, and evals. Everything on this page runs offline with zero API keys. Reach for a real model only when the behavior under test depends on the model itself. ## Mock model from the CLI `--mock` injects the deterministic mock provider into `fh run` and `fh dev`. Discovery, input/output schema validation, the model loop, and HTTP routing all still execute: ```sh fh run hello --name Preetham --mock # Mock response: Say hello to Preetham. fh dev --mock --port 3000 curl http://localhost:3000/jobs/hello \ -H 'content-type: application/json' \ -d '{"name":"Preetham"}' # {"result":"Mock response: Say hello to Preetham.","runId":"…"} ``` A `mock/`-prefixed configured model resolves the same way without any flag — `fh init --model mock/test-model` writes `model: "mock/test-model"` into `.fabricharness/config.ts`, and plain `fh run hello` (or the generated project's `npm run run`) executes against the mock. The production guard still applies: mock models throw when `FABRIC_ENV`/`NODE_ENV` is `production` unless `FABRIC_ALLOW_MOCK_MODEL=1` is set. ## Scripted mock responses For deterministic multi-turn scripts — including tool loops — pass an aimock-style fixture file to `fh run --mock-script ` (implies `--mock`, no credentials, wins over every other model selection): ```json title="fixtures/ask.json" { "fixtures": [ { "match": { "userMessage": "order", "hasToolResult": false }, "response": { "toolCalls": [{ "name": "lookup_order", "arguments": { "id": "A-1" }, "id": "call-1" }] } }, { "match": { "toolCallId": "call-1" }, "response": { "content": "Order A-1 ships tomorrow." } } ] } ``` ```sh fh run support --mock-script ./fixtures/ask.json --question "where is my order?" ``` Each entry is `{ match, response }`. The first entry whose `match` is satisfied wins; requests that match nothing fall back to the echo behavior. Match fields (all specified fields must match): | Field | Matches when | | --- | --- | | `userMessage` | Substring of the latest user message. | | `toolCallId` | A tool result with this call id is in the request history. | | `toolName` | A tool result from this tool is in the request history. | | `toolResultContains` | Substring of any tool result content. | | `hasToolResult` | The request already contains tool results (`true`/`false`). | | `sequenceIndex` | Zero-based model-turn index (0 on the first call, 1 after a tool-call round trip). | Responses are `{ "content": "..." }` and/or `{ "toolCalls": [{ "name", "arguments", "id?" }] }`. Scripted tool calls execute for real — the mock emits the call, the loop runs your tool, and a later entry (matched on `toolCallId`, `toolName`, or `sequenceIndex`) answers from the result. Tool call ids default to `mock-tool-`; set `id` explicitly to match a later `toolCallId` entry. The fixture file is either a bare array of entries or the `{ "fixtures": [...] }` wrapper shown above. The same script works in code via `@fabric-harness/sdk/testing`: ```ts import { MockModelProvider, parseMockScript } from '@fabric-harness/sdk/testing'; const script = parseMockScript(fixtureJson); // validates, throws with the entry index const provider = new MockModelProvider({ script }); ``` ## Single-file runs auto-mock `fh run` executes any standalone `.ts`/`.js` file that exports `defineAgent()` — no `.fabricharness/` workspace, no `config.ts`, no install step beyond a resolvable `@fabric-harness/sdk`: ```ts title="agent.ts" import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'hello', input: schema.object({ message: schema.string() }), output: schema.string(), run: async ({ init, input }) => { const fabric = await init(); const session = await fabric.session(); return session.prompt(input.message); }, }); ``` ```sh fh run ./agent.ts --message "hi" # [fabric-harness] no model credentials resolved; using the mock model (set FABRIC_MODEL or pass --model for a real provider). # [fabric-harness] session hello-4edbadf5-… completed (memory store — not persisted). # Mock response: hi ``` When no model credentials resolve (`--model`, `FABRIC_MODEL`, or provider keys), the run falls back to the mock model and says so on stderr, so the command round-trips offline. Pass `--model` (or set `FABRIC_MODEL`) with a configured provider to run the same file against a real model. See [`fh run`](/docs/cli/run) for multi-export files, payload flags, and error behavior. ## MockModelProvider in code `@fabric-harness/sdk/testing` exports the same provider the CLI uses: ```ts import { MockModelProvider } from '@fabric-harness/sdk/testing'; const provider = new MockModelProvider(); const response = await provider.generate({ messages: [{ role: 'user', content: 'ping' }], }); // response.message.content === 'Mock response: ping' ``` The mock is deterministic: it echoes the latest user message as `Mock response: ` and summarizes tool results after tool turns. To exercise a tool loop, script tool calls in the prompt with a `fabric-tool-calls` fenced block: ````ts const response = await provider.generate({ messages: [{ role: 'user', content: 'run the tool\n```fabric-tool-calls\n[{"tool":"lookup_order","input":{"id":"A-1"}}]\n```', }], }); // response.toolCalls === [{ id: 'mock-tool-1', name: 'lookup_order', input: { id: 'A-1' } }] ```` > The `/testing` entry point is shaped for test ergonomics and is not covered by the runtime SemVer commitment. Production code should not import from it. ## Stub sessions for unit tests `StubFabricAgent` and `StubFabricSession` are the in-process implementations behind `init()`. Construct them directly with the mock model to unit-test agent logic without a workspace, server, or credentials: ```ts import { describe, expect, it } from 'vitest'; import { StubFabricAgent } from '@fabric-harness/sdk/testing'; describe('support agent', () => { it('answers through the session contract', async () => { const agent = new StubFabricAgent({ model: 'mock/test-model' }); const session = await agent.session('demo'); const reply = await session.prompt('hello from the test'); expect(reply).toBe('Mock response: hello from the test'); }); }); ``` For workspace-level runs, `runAgent({ agent, payload, mock: true })` from `@fabric-harness/node` covers the same ground through the full CLI pipeline — see [Testing locally](/docs/building/testing). ## Mock sandbox handles Remote sandbox adapters in `@fabric-harness/connectors` are structural: they adapt a provider SDK handle to the Fabric `SandboxEnv` contract. That makes the provider handle mockable — back it with the SDK's in-memory `EmptySandboxEnv` and the real adapter runs end-to-end offline: ```ts import { EmptySandboxEnv } from '@fabric-harness/sdk'; const inner = new EmptySandboxEnv('/home/daytona'); await inner.writeFile('/home/daytona/welcome.txt', 'hello from the mock daytona sandbox\n'); // expose inner's readFile/writeFile/exec/… through the provider's handle shape ``` The canonical pattern lives in [`examples/remote-coding-agent`](/docs/reference/source-access) (`connectors/mock-remote.ts` adapts `EmptySandboxEnv` to the `RemoteSandboxApi` contract), and each provider example ships its own structural mock with the live path gated behind an opt-in flag: | Example | Mock handle | Live opt-in | | --- | --- | --- | | [`with-daytona`](/docs/reference/source-access) | `connectors/mock-daytona.ts` | `FABRIC_DAYTONA_LIVE=1` + `DAYTONA_API_KEY` | | [`with-e2b`](/docs/reference/source-access) | `connectors/mock-e2b.ts` | `FABRIC_E2B_LIVE=1` + `E2B_API_KEY` | | [`with-modal`](/docs/reference/source-access) | `connectors/mock-modal.ts` | `FABRIC_MODAL_LIVE=1` + Modal credentials | | [`with-kubernetes`](/docs/reference/source-access) | `connectors/mock-kubernetes.ts` | `FABRIC_K8S_LIVE=1` + kubeconfig | | [`with-vercel-sandbox`](/docs/reference/source-access) | `connectors/mock-vercel.ts` | `FABRIC_VERCEL_LIVE=1` + `VERCEL_TOKEN` | | [`with-local-shell`](/docs/reference/source-access) | local sandbox directly | not needed — runs on the host | Each example's default `pnpm run run` executes against the mock with no credentials; the live path fails fast with a clear error when the flag is set without its credentials. See [Sandbox connectors](/docs/building/sandbox-connectors) for the adapter contracts. ## Evals with `fh test` Eval suites are TypeScript modules named `**/*.eval.ts`. Run the agent with `mock: true` inside the suite runner and the whole suite is deterministic and offline: ```ts title="evals/hello.eval.ts" import { containsTextScorer, defineEvalSuite } from '@fabric-harness/evals'; import { runAgent } from '@fabric-harness/node'; export default defineEvalSuite({ name: 'hello-quality', cases: [ { id: 'named-user', input: { name: 'Ada' }, expected: 'Ada' }, ], runner: async ({ case: evalCase }) => { const run = await runAgent({ agent: 'hello', payload: evalCase.input, mock: true }); return run.result; }, scorers: [containsTextScorer()], passThreshold: 1, }); ``` ```sh fh test # Eval Results # # hello-quality PASS 100% 39ms # PASS named-user contains_text=1.00 # # Overall: PASS ``` `@fabric-harness/evals` ships deterministic scorers — `exactMatchScorer`, `containsTextScorer`, `regexMatchScorer`, `jsonShapeMatchScorer` — plus `llmAsJudgeScorer` for model-graded checks (the one scorer that needs a real provider). `fh test` exits non-zero when any suite fails, so the same command gates CI. See [Evaluations](/docs/building/evals) and [`fh test`](/docs/cli/test). ## When to add credentials Everything above stays green with no keys. Add a provider key in `.env.local` when you are validating real model behavior, then drop `--mock`: ```sh echo 'OPENAI_API_KEY=sk-...' > .env.local fh doctor --live --model openai/gpt-5.5 fh run hello --name Preetham ``` See [Model providers](/docs/building/model-providers) for supported providers and credential resolution, and [Live tests](/docs/reference/live-tests) for the opt-in environment variable matrix used by the repo's own live suites. --- # Testing Locally Canonical: https://harness.techfabric.com/docs/building/testing The mock model, the doctor, the dev server and the assertion helpers you use to test an agent without spending a token. The framework is designed so that "test the agent" doesn't mean "spin up a full LLM." Use the mock provider for fast, deterministic checks and reach for live models only when behavior depends on the model. For the complete no-credential story — single-file runs, stub sessions, mock sandboxes, and evals — see [Test without credentials](/docs/building/test-without-credentials). ## Mock model ```sh fh run ask --question "hi" --mock ``` `--mock` injects the deterministic mock provider and still exercises input/output validation. Combine it with snapshot testing or schema-only assertions in your test suite. ## Vitest example ```ts import { describe, expect, it } from 'vitest'; import { runAgent } from '@fabric-harness/node'; describe('ask agent', () => { it('returns a string', async () => { const { result } = await runAgent({ agent: 'ask', payload: { question: 'hello' }, mock: true, }); expect(typeof result).toBe('string'); }); }); ``` ## Doctor ```sh fh doctor --tools # binary checks fh doctor --live --model openai/gpt-5.5 # one real provider round-trip ``` ## Dev server `fh dev --mock` starts the same routes the deployed Node target uses without provider credentials. Invoke a finite job at `/jobs/:name`: ```sh fh dev --mock --port 4000 curl -X POST -H 'Content-Type: application/json' \ -d '{"question":"What is Temporal?"}' \ http://localhost:4000/jobs/ask ``` ## Live integration tests Live tests are opt-in and skipped by default. Use them when validating real provider credentials and hosted resources: ```sh pnpm --filter @fabric-harness/connectors test # Daytona / E2B / Modal live suites skip unless enabled pnpm --filter @fabric-harness/azure test # Azure OpenAI / Foundry / ARM live suites skip unless enabled pnpm --filter @fabric-harness/databricks test # Databricks live suites skip unless enabled ``` See [Live tests](/docs/reference/live-tests) for the full environment variable matrix. Harness child-process tests start from a sanitized environment. Provider keys, cloud credentials, database URLs, and agent markers are removed unless a test explicitly supplies an override. This keeps offline suites repeatable on developer machines that happen to be logged into cloud services. HTTP integration tests bind port `0` and use the operating system's assigned port, avoiding parallel-suite collisions. Maintainers should also run `pnpm check:unused`. The Knip configuration treats package entry points as public API, checks internal exports and dependency declarations, excludes generated `.fabricharness/build` output, and is included in `pnpm lint`. ### Maintainer workspace concurrency The root `pnpm test` intentionally runs package suites with `--workspace-concurrency=1`. A measured concurrency-2 run on 2026-07-30 caused the Node persistent-prompt admission test and the Databricks capability-registry import test to exceed their bounded timeouts under shared CPU pressure. Keep the workspace layer serial until those integration suites have isolated worker/resource budgets; Vitest still parallelizes safely within each package. CI avoids the larger duplicate cost by running typecheck, documentation, example, parity, release, coverage, and lint gates only in the Node 22 matrix lane. ## Recipes from `examples/` The repo's `examples/` directory is the canonical reference for how to test each capability: - [`examples/hello-world`](/docs/reference/source-access) — basic metadata agents and real model invocation. - [`examples/with-tools`](/docs/reference/source-access) — built-in tools. - [`examples/with-skill`](/docs/reference/source-access) — skill loading and typed results. - [`examples/with-task`](/docs/reference/source-access) — durable task lifecycle and artifacts. - [`examples/with-approval`](/docs/reference/source-access) — approval-gated commands. - [`examples/with-docker`](/docs/reference/source-access) — Docker sandbox basics. - [`examples/with-temporal`](/docs/reference/source-access) — Temporal worker integration. - [`examples/with-config`](/docs/reference/source-access) — central config including SQLite session storage. - [`examples/with-postgres-store`](/docs/reference/source-access) — Postgres session/artifact storage. - [`examples/data-analyst`](/docs/reference/source-access) — Docker-backed CSV analysis with artifacts. - [`examples/issue-triage-ci`](/docs/reference/source-access) — controlled CI pilot for read-only GitHub issue triage. ## What to assert in tests For metadata agents, the most useful assertions are: 1. **Schema shape.** Output validates against the declared output schema. 2. **Tool/command scope.** No unexpected commands ran. 3. **Artifacts.** Expected artifacts were published with the right content type. 4. **Metrics.** Token / call counts stay within bounds for a given task. 5. **Idempotence.** Re-running the same prompt produces compatible output (when using the mock model or fixed seed). --- # Tools Canonical: https://harness.techfabric.com/docs/building/tools The model-callable functions that ship with TechFabric Harness, and how a tool call is bounded before it reaches your system. Tools are functions the model can call during a session. TechFabric Harness ships a built-in toolbelt that mirrors the proven coding-agent pattern. ## Built-in tools | Tool | Purpose | | --- | --- | | `read` | Read a file from the sandbox. | | `write` | Write a file to the sandbox. | | `edit` | Apply a localized edit (find/replace) to a file. | | `bash` | Execute a shell command in the sandbox. | | `grep` | Search file contents. | | `glob` | Match files by pattern. | | `task` | Spawn a child task. | All built-ins are **capability-aware**: `write` and `edit` honor any filesystem write scope declared on the session, `bash` honors the configured `commands` allowlist. The model-facing tools have stable output and concurrency limits. See [Agent behavior](/docs/reference/agent-behavior#built-in-tools) for paging, truncation, timeout, exact-edit, and same-file serialization semantics. ## Constructing the toolset ```ts import { createBuiltinTools } from '@fabric-harness/sdk'; const sandbox = await session.sandbox; const tools = createBuiltinTools(sandbox); await session.prompt('Find and fix the failing test', { tools }); ``` By default, `session.prompt()` uses the built-in tools. You typically only override this when you want to *limit* which tools are available or *augment* with custom ones. ## Custom tools > Both `defineTool` and `createBuiltinTools` are also exported from `@fabric-harness/sdk` — swap the import path when you want the minimal entrypoint. ```ts import { defineTool, schema } from '@fabric-harness/sdk'; const fetchIssue = defineTool({ name: 'fetch_issue', description: 'Fetch a GitHub issue by number.', input: schema.object({ number: schema.number() }), output: schema.object({ title: schema.string(), body: schema.string() }), run: async ({ data }) => { // data.number is validated against the input schema return { title, body }; }, }); await session.prompt('Triage issue #42', { tools: [...tools, fetchIssue] }); ``` --- # Voice Canonical: https://harness.techfabric.com/docs/building/voice Bidirectional audio for phone calls, browser and kiosk. Realtime mode and pipeline mode behind one VoiceSession contract. `VoiceSession` is fabric-harness's surface for voice-capable LLMs. It streams audio bytes in both directions, surfaces text transcripts, and round-trips tool calls — same governance posture as text agents (cost telemetry, audit, approvals all apply). fabric-harness ships **two voice modes** behind the same `VoiceSession` contract: - **Realtime mode** — one model owns audio in + out + tools. OpenAI Realtime today; Anthropic / Gemini Live when GA. - **Pipeline mode** — `STT → LLM → TTS`. Compose Deepgram / Cartesia STT with any LLM and ElevenLabs / Cartesia TTS. Swap providers without changing the caller code. See [Voice Providers](/docs/building/voice-providers) for the provider matrix, pricing, and the picking heuristic. Telephony bridges (Twilio Media Streams, Vonage, Plivo) live in user-space; scaffold one with `fh add`. ## The contract ```ts interface VoiceSession { sendAudio(frame: Uint8Array): Promise; sendText(text: string): Promise; submitToolResult(input: { id: string; output: unknown }): Promise; cancelResponse(): Promise; events(): AsyncIterable; close(): Promise; } type VoiceEvent = | { type: 'session_open' } | { type: 'audio_delta'; audio: Uint8Array } | { type: 'text_delta'; delta: string; role: 'assistant' | 'user' } | { type: 'transcript'; text: string; role: 'assistant' | 'user' } | { type: 'tool_call'; id: string; name: string; input: unknown } | { type: 'response_done'; usage?: ModelUsage } | { type: 'error'; message: string }; ``` `audio_delta` carries raw PCM 16-bit (or `g711_ulaw` for telephony). `tool_call` flags an LLM tool invocation — your code runs the tool and calls `submitToolResult({ id, output })` to feed the result back. ## OpenAI Realtime ```ts import { OpenAIRealtimeVoiceProvider } from '@fabric-harness/sdk'; const provider = new OpenAIRealtimeVoiceProvider({ apiKey: process.env.OPENAI_API_KEY!, model: 'gpt-realtime', }); const voice = await provider.connect({ instructions: 'You are a friendly intake agent. One question at a time.', voice: 'alloy', audioFormat: 'pcm16', // or 'g711_ulaw' for Twilio tools: [submitFieldTool], turnDetection: 'server_vad', // OpenAI handles barge-in detection }); // Pump audio in (mic / phone) mic.on('data', (frame) => voice.sendAudio(frame)); // Pump audio out (speaker / phone) for await (const event of voice.events()) { if (event.type === 'audio_delta') speaker.write(event.audio); if (event.type === 'tool_call') { const output = await runTool(event.name, event.input); await voice.submitToolResult({ id: event.id, output }); } if (event.type === 'response_done') break; } ``` The provider uses the platform `WebSocket` (Node 22+ + browsers) — no `ws` dependency on the consumer side. ## Pipeline mode (ElevenLabs / Cartesia / Deepgram) When you want a non-OpenAI vendor combo — voice cloning, multilingual TTS, on-prem STT, or just lower per-minute cost — use `PipelineVoiceProvider`. It composes a `SttProvider`, a text `ModelProvider`, and a `TtsProvider` into the same `VoiceSession` contract. Swap any of the three without touching caller code. ```ts import { PipelineVoiceProvider, DeepgramSttProvider, ElevenLabsTtsProvider, AnthropicModelProvider, } from '@fabric-harness/sdk'; const provider = new PipelineVoiceProvider({ stt: new DeepgramSttProvider({ apiKey: process.env.DEEPGRAM_API_KEY!, model: 'nova-3' }), tts: new ElevenLabsTtsProvider({ apiKey: process.env.ELEVENLABS_API_KEY!, model: 'eleven_turbo_v2_5', defaultVoice: '21m00Tcm4TlvDq8ikWAM', // 'Rachel' }), llm: new AnthropicModelProvider({ apiKey: process.env.ANTHROPIC_API_KEY! }), model: 'claude-haiku-4-5-20251001', }); const voice = await provider.connect({ instructions: 'Friendly intake agent. One question at a time.', tools: [submitFieldTool], }); // Same loop as realtime mode — events(), sendAudio(), submitToolResult(). ``` Conversation flow: 1. Caller pumps audio into `voice.sendAudio()`. 2. Deepgram emits final transcripts → pipeline forwards as the next user turn. 3. LLM generates the assistant reply (with tool calls if relevant). 4. Assistant text streams to ElevenLabs → audio bytes arrive as `audio_delta` events. 5. `response_done` fires with rolled-up usage (`inputTokens`, `outputTokens`, `sttSeconds`, `ttsCharacters`, `costUsd`). **Barge-in:** the STT VAD emits `speech_started` when the user interrupts; the pipeline aborts the in-flight LLM + TTS streams and returns to listening. Your UI should drain its audio buffer when `audio_delta` events stop arriving. **Single-vendor variant** (no ElevenLabs key needed): ```ts import { CartesiaSttProvider, CartesiaTtsProvider } from '@fabric-harness/sdk'; new PipelineVoiceProvider({ stt: new CartesiaSttProvider({ apiKey: process.env.CARTESIA_API_KEY! }), tts: new CartesiaTtsProvider({ apiKey: process.env.CARTESIA_API_KEY! }), llm: someLlmProvider, model: 'gpt-4.1-mini', }); ``` For the full matrix (when to pick which mode, latency benchmarks, cost comparisons), see [Voice Providers](/docs/building/voice-providers). ## Tool calls Tool execution is the *caller's* responsibility, not the voice session's. When `tool_call` lands: 1. Look up the tool by `name` in your registry. 2. Run it through whatever governance gates apply — approval policies, cost caps, rate limits — using the v1-era primitives unchanged. 3. Call `voice.submitToolResult({ id, output })`. This keeps the audio path lean and avoids reimplementing the loop machinery on the voice side. ## Cost Realtime audio is billed per audio token at materially higher rates than text. fabric-harness records `audioInputTokens` / `audioOutputTokens` on `usage` and rolls them into `costUsd` via the static price table: ``` $ fh metrics call-3a8b... Tokens: input=1200 output=400 total=1600 Audio: input=12345 output=6789 Cost: $0.234567 ``` Override the rates with `registerModelPrices` for negotiated contracts: ```ts import { registerModelPrices } from '@fabric-harness/sdk'; registerModelPrices([{ provider: 'openai', model: 'gpt-realtime', inputPerMTok: 4, outputPerMTok: 16, audioInputPerMTok: 80, audioOutputPerMTok: 160, effectiveAt: '2026-05-08', notes: 'Enterprise contract', }]); ``` ## Telephony bridges Phone calls? Don't add a Twilio dep to fabric-harness. Use `fh add` to scaffold a project-local bridge: ```sh fh add https://www.twilio.com/docs/voice/twiml/stream --category voice-telephony | claude fh add https://developer.vonage.com/voice/voice-api/code-snippets --category voice-telephony | cursor-agent ``` This emits the canonical telephony spec (`packages/sdk/connector-spec/voice-telephony.md`) with a header pointing at the provider's docs. The coding agent reads the docs, follows the spec, and produces a single file at `./connectors/-bridge.ts`. Twilio uses μ-law 8kHz natively — set `audioFormat: 'g711_ulaw'` and skip the resample for the lowest-latency path. ## Browser-direct voice via the Node server `fh dev` and generated Node builds expose a `WS /sessions/:id/voice` upgrade handler. The server creates the OpenAI Realtime connection on behalf of the browser, so provider API keys stay server-side. Tool calls relay through the agent's existing tool registry, so approval policies, cost caps, and rate limiters apply to voice tools just like text tools. ```ts import { connectFabricVoice } from '@fabric-harness/sdk'; const handle = connectFabricVoice({ url: `wss://app.example.com/sessions/${sessionId}/voice`, authToken, tenantId: 'acme', voice: 'alloy', instructions: 'Friendly intake agent. One question at a time.', onEvent: (event) => { if (event.type === 'audio') speaker.write(event.audio); if (event.type === 'tool_call') { // Optional: handle tool calls client-side. Default is server-side relay. } if (event.type === 'cost_limit') { console.warn('Hit cost ceiling', event); handle.close(); } }, onError: console.error, }); mic.on('frame', (pcm16) => handle.sendAudio(pcm16)); ``` Server requirements: - `OPENAI_API_KEY` env var (the bridge fails 1011 / `error` if missing). - `ws` peer dep installed (`pnpm add ws`). - Optional: `FABRIC_HARNESS_API_TOKEN`, `extractAuthToken`, `X-Fabric-Tenant` — same pipeline as the chat WS. Query params customize each connection: `?model=gpt-realtime&voice=alloy&audioFormat=g711_ulaw&instructions=...`. ### Capture pipeline 1. `navigator.mediaDevices.getUserMedia({ audio: true })`. 2. Pipe through an `AudioWorklet` that resamples to PCM 16-bit 24kHz mono (or μ-law 8kHz for `audioFormat: 'g711_ulaw'`). 3. Forward each frame via `handle.sendAudio(buffer)`. ### Cost governance `VoiceConnectOptions.costBudget` (and the WS bridge's `costLimit` option) wires voice into the v1.4 cost-budget machinery. On every `response.done`, the tracker observes the call cost and emits a `cost_limit` event when a ceiling is crossed. With `onExceed: 'approve'`, your `requestCostLimitApproval` is called before the session continues. Pair with `tenantCostLimit()` for per-tenant per-period ceilings. ## See also - [Cost telemetry](/docs/building/model-providers#per-call-cost-telemetry) - [Connector catalog](/docs/building/connector-catalog) - [Session memory](/docs/building/session-memory) — useful for storing collected fields across calls --- # Voice Providers Canonical: https://harness.techfabric.com/docs/building/voice-providers Choose and compose realtime or pipeline voice providers with OpenAI, ElevenLabs, Cartesia, and Deepgram. TechFabric Harness supports two voice modes: **realtime**, where one model owns audio input, audio output, and tools; and **pipeline**, where you choose separate STT, LLM, and TTS providers. ## Choose a voice architecture - Choose **OpenAI Realtime** when you want a single WebSocket connection with model-managed turn detection and tool calling. - Choose a **Deepgram + ElevenLabs pipeline** when independent STT, LLM, and TTS selection matters. - Choose a **Cartesia pipeline** when you want STT and TTS from one pipeline provider while retaining your preferred LLM. - Serve either mode through `WS /sessions/:id/voice` to keep provider credentials on the server. ## Mode comparison | Aspect | Realtime mode | Pipeline mode | |---|---|---| | Architecture | One WS, model handles audio in + out + tools | Three streams: STT → LLM → TTS | | Voice flexibility | Provider's voices only | Any TTS vendor — voice clones, emotion, accents | | Language support | Provider-bound | Determined by the selected STT and TTS providers | | Tool calling | Native to the model | Through the underlying LLM (Anthropic/OpenAI/Gemini) | | Barge-in | Server VAD | STT VAD + caller cancels TTS | | Useful for | Phone agents, intake bots, simpler audio orchestration | Multilingual, branded voice, vendor flexibility, provider-specific governance | ## Provider matrix | Provider | Role | Fabric integration | Consider when | |---|---|---|---| | OpenAI Realtime | Realtime end-to-end | `OpenAIRealtimeVoiceProvider` | You want one connection for audio, turn detection, responses, and tools. | | ElevenLabs | TTS | `ElevenLabsTtsProvider` | Voice selection and TTS controls are central requirements. | | Cartesia | TTS + STT | `CartesiaTtsProvider`, `CartesiaSttProvider` | You want one pipeline vendor for both speech directions. | | Deepgram | STT | `DeepgramSttProvider` | You need a dedicated streaming transcription provider with endpointing controls. | Provider models, languages, and prices change independently of TechFabric Harness. Confirm the current provider offering, then use `registerModelPrices` to apply your public or negotiated rate card to cost telemetry. ## Realtime mode (OpenAI) ```ts import { OpenAIRealtimeVoiceProvider } from '@fabric-harness/sdk'; const provider = new OpenAIRealtimeVoiceProvider({ apiKey: process.env.OPENAI_API_KEY!, model: 'gpt-realtime', }); const voice = await provider.connect({ instructions: 'You are a friendly intake agent.', voice: 'alloy', audioFormat: 'pcm16', // or 'g711_ulaw' for Twilio. tools: [submitFieldTool], turnDetection: 'server_vad', }); ``` The model owns the audio loop end-to-end. Tool calls relay through the existing `tool_call` / `submitToolResult` contract — same as pipeline mode. ## Pipeline mode (BYO STT + LLM + TTS) ```ts import { PipelineVoiceProvider, DeepgramSttProvider, ElevenLabsTtsProvider, AnthropicModelProvider, } from '@fabric-harness/sdk'; const provider = new PipelineVoiceProvider({ stt: new DeepgramSttProvider({ apiKey: process.env.DEEPGRAM_API_KEY!, model: 'nova-3', }), tts: new ElevenLabsTtsProvider({ apiKey: process.env.ELEVENLABS_API_KEY!, defaultVoice: '21m00Tcm4TlvDq8ikWAM', // 'Rachel' model: 'eleven_turbo_v2_5', }), llm: new AnthropicModelProvider({ apiKey: process.env.ANTHROPIC_API_KEY! }), model: 'claude-haiku-4-5-20251001', }); const voice = await provider.connect({ instructions: 'You are a friendly intake agent. One question at a time.', audioFormat: 'pcm16', tools: [submitFieldTool], }); mic.on('frame', (pcm) => voice.sendAudio(pcm)); for await (const event of voice.events()) { if (event.type === 'audio_delta') speaker.write(event.audio); if (event.type === 'tool_call') { const output = await runTool(event.name, event.input); await voice.submitToolResult({ id: event.id, output }); } if (event.type === 'response_done') { // event.usage contains rolled-up tokens, sttSeconds, ttsCharacters, costUsd. } } ``` The contract is **identical** to realtime mode — `VoiceSession` events, tool calls, cost telemetry, `costBudget`, `cost_limit` events. Swap providers without rewriting your loop. ### Single-vendor variant (Cartesia) ```ts import { PipelineVoiceProvider, CartesiaSttProvider, CartesiaTtsProvider, } from '@fabric-harness/sdk'; const provider = new PipelineVoiceProvider({ stt: new CartesiaSttProvider({ apiKey: process.env.CARTESIA_API_KEY! }), tts: new CartesiaTtsProvider({ apiKey: process.env.CARTESIA_API_KEY! }), llm: someLlmProvider, model: 'claude-haiku-4-5-20251001', }); ``` ## Barge-in Pipeline mode wires barge-in through the STT VAD. When the user starts speaking while the agent is mid-utterance, the STT emits `speech_started`; the pipeline aborts the in-flight LLM call, cancels the TTS stream, and returns to listening. Your UI is responsible for stopping playback when `audio_delta` events stop arriving. Realtime mode handles this server-side via `turnDetection: 'server_vad'`. ## Cost telemetry Both modes feed the same telemetry surface. `response_done.usage` includes: ```ts { inputTokens: number; // LLM input outputTokens: number; // LLM output audioInputTokens?: number; // realtime mode only audioOutputTokens?: number;// realtime mode only sttSeconds?: number; // pipeline mode (Deepgram/Cartesia) ttsCharacters?: number; // pipeline mode (ElevenLabs/Cartesia) costUsd?: number; // rolled up via static price table } ``` Wire `costBudget` to enforce per-call / per-session / per-tenant ceilings — voice participates in the same v1.4 cost-budget machinery as text agents. ```ts import { CostBudgetTracker } from '@fabric-harness/sdk'; const budget = new CostBudgetTracker({ perCallUsd: 0.50, perSessionUsd: 5 }); await provider.connect({ costBudget: budget }); ``` ## Evaluate a voice stack Test candidate providers with representative audio before choosing a production stack. Measure: - time to first transcript and first synthesized audio; - transcription quality for your languages, accents, vocabulary, and audio channel; - interruption behavior under real network conditions; - voice consistency and pronunciation for your domain; - provider region, retention, residency, and audit controls; - end-to-end cost using your own traffic distribution and rate card. Because realtime and pipeline mode share the `VoiceSession` contract, you can run the same application loop against each candidate and compare session events and usage telemetry. ## When to bring your own provider Implement `TtsProvider`, `SttProvider`, or `VoiceProvider` directly and pass it into `PipelineVoiceProvider`. Reasons to build your own: - On-prem TTS (Riva, Coqui) for compliance. - Whisper-via-vLLM for cheap multilingual STT. - Translate-on-the-wire layers (e.g. STT in Spanish → MT → English LLM → TTS in Spanish). The interfaces (`TtsProvider`, `SttProvider`) are intentionally narrow — `synthesize(text) → AsyncIterable` and `open() → SttSession` are the only required methods. ## See also - [Voice](/docs/building/voice) — the `VoiceSession` contract and OpenAI Realtime usage. - [Cost telemetry](/docs/building/model-providers#per-call-cost-telemetry) — pricing and rate-card overrides. - [Connector catalog](/docs/building/connector-catalog) — telephony bridges (Twilio, Vonage) for phone audio. --- # CLI Overview Canonical: https://harness.techfabric.com/docs/cli One binary that runs, builds, deploys, inspects and replays a workspace, so an agent has the same shape everywhere. The TechFabric Harness CLI is a single binary that drives the entire framework: discovering agents, running them locally, building deployment artifacts, starting the dev server, inspecting persisted sessions, and managing approvals, tasks, artifacts, and builds. ## Invocation The CLI is published as `fabric-harness` with `fh` as an exact alias: ```sh fabric-harness --help fh --help ``` For local framework development, run the built monorepo CLI directly: ```sh node packages/cli/dist/bin/fabric-harness.js --help pnpm fh --help ``` ## Synopsis ``` fabric-harness --help fabric-harness capabilities --json fabric-harness run [options] fabric-harness agents [--json] fabric-harness describe [--json] fabric-harness build [--target node|temporal-worker|docker|foundry-hosted-agent|cloudflare] [options] fabric-harness dev [--target node|cloudflare|temporal-worker] [--mock] [--console] [options] fabric-harness fiber [--url ] [--plain] fabric-harness fiber [--url ] [--plain] [--job --input | --agent --id --message ] fabric-harness docs fabric-harness doctor [--target node|temporal-worker|databricks-app|databricks-serving|buzz] [--model provider/model] [--getting-started] [--tools] [--live] [--json] fabric-harness init [directory] [--dir ] [--model provider/model] [--template ] [--store memory|file|sqlite|postgres|redis] fabric-harness new [--force] fabric-harness sessions fabric-harness builds fabric-harness inspect fabric-harness logs [--events] fabric-harness checkpoints fabric-harness artifacts [--json] fabric-harness artifact get [--out ] fabric-harness metrics [--json] fabric-harness tasks [--json] fabric-harness task [--json] fabric-harness cancel-task [--actor ] [--reason ] fabric-harness compact [--keep ] [--summary ] fabric-harness replay fabric-harness approvals [--pending] [--state] fabric-harness approve [--actor ] [--reason ] fabric-harness reject [--actor ] [--reason ] fabric-harness verify-attestation fabric-harness verify-provenance fabric-harness test [path] [options] fabric-harness temporal-worker [--task-queue ] [--address ] [--env ] fabric-harness add [connector] [--print] ``` ## Command groups | Group | Commands | Page | | --- | --- | --- | | Run agents | `run` | [run](/docs/cli/run) | | Discover | `agents`, `describe` | [agents](/docs/cli/agents) | | Build | `build`, `builds`, `verify-attestation`, `verify-provenance` | [build](/docs/cli/build), [builds](/docs/cli/builds) | | Dev server | `dev` | [dev](/docs/cli/dev) | | Testing | `test` | [test](/docs/cli/test) | | Diagnostics | `doctor` | [doctor](/docs/cli/doctor) | | Integration compatibility | `capabilities --json` | [compatibility contract](/docs/cli/compatibility) | | Scaffolding | `init`, `new job`, `new agent` | [TechFabric Harness in 5 minutes](/docs/getting-started/five-minutes) | | Interactive use | Fiber (`fiber`, `console`) | [Fiber terminal console](/docs/cli/console) | | Documentation | `docs list`, `docs read`, `docs search` | [docs](/docs/cli/docs) | | Sessions | `sessions`, `inspect`, `logs`, `replay`, `metrics`, `compact` | [sessions](/docs/cli/sessions) | | Tasks | `tasks`, `task`, `cancel-task` | [tasks](/docs/cli/tasks) | | Approvals | `approvals`, `approve`, `reject` | [approvals](/docs/cli/approvals) | | Artifacts & checkpoints | `artifacts`, `artifact get`, `checkpoints` | [artifacts](/docs/cli/artifacts) | | Temporal | `temporal-worker` | [temporal-worker](/docs/cli/temporal-worker) | | Recipes | `add` | [add](/docs/cli/add) | `fh init` keeps generated core dependencies on the release line shipped with the CLI. The current CLI writes `^6.2.0` ranges for `@fabric-harness/sdk` and, when the selected template needs the Node runtime, `@fabric-harness/node`. Managed `fh add` recipes use the same core dependency floors and reject incompatible installed ranges before writing files. ## Global options | Flag | Purpose | | --- | --- | | `-h`, `--help` | Print help text. | | `--env ` | Load `.env`-style variables before `run`/`dev`/`temporal-worker`. Repeatable; shell env wins. | ## Configuration defaults `.fabricharness/config.ts` may set: - `run.target`, `run.model`, `run.idPrefix`, - `temporal.address`, `temporal.taskQueue`, - `agent.model`. CLI flags always win over config. See [Configuration](/docs/getting-started/configuration). --- # fh add Canonical: https://harness.techfabric.com/docs/cli/add Browse the ecosystem recipes, scaffold one into your workspace, or print it first to see what it will write. ``` fabric-harness add [kind] [name] [options] ``` `fh add` has two recipe modes: | Mode | Command shape | Result | | --- | --- | --- | | Managed recipe | `fh add ` or `fh add ` | Resolves dependencies, writes implementation/environment/test files, and prints a verification command. | | Connector guide | `fh add --print` | Prints Markdown for project-specific provider wiring. | Managed recipes install first-party packages from the release line current when this CLI was published. The recipe registry and generated project templates are checked together in CI; for example, the current CLI emits SDK/Node `^6.2.0` ranges and Databricks `^7.1.1` ranges, while connectors, evals, Temporal, and Cloudflare remain on their independently versioned lines. An existing incompatible first-party major fails before files are written. The catalog labels every entry with its mode. Some connectors also have package helpers in `@fabric-harness/connectors`, `@fabric-harness/channels`, `@fabric-harness/azure`, or `@fabric-harness/databricks`. ## Examples ### List available recipes ```sh fh add fh add --json ``` ### Scaffold directly ```sh fh add channel slack fh add slack fh add channel teams fh add database postgres fh add sandbox e2b --dir ./agent-service fh add modal fh add policy safe-defaults ``` Scaffold kinds are `channel`, `database`, `databricks`, `sandbox`, `tooling`, `model-provider`, `skill`, and `policy`. Existing files are preserved unless `--force` is supplied. When `package.json` exists, Fabric detects pnpm, npm, Yarn, or Bun and installs missing declared dependencies using recipe-owned compatible version ranges. An incompatible existing range stops before files are written. Pass `--no-install` to update the manifest without running the package manager. Every recipe has a unique one-word alias. The explicit kind/name form remains useful in automation and makes ownership clear. Successful installation prints the package-manager-specific Vitest command for the generated contract test. Every generated TypeScript or Markdown file has a marker such as: ```ts // fabric-harness-recipe: channel/slack@1 ``` The marker lets [`fh update`](/docs/cli/update) distinguish an unchanged generated file from user customizations. Use `--dry-run` before applying a recipe in an existing project. ```sh fh add channel slack --dry-run fh add channel slack --dry-run --json ``` ### Print a connector recipe ```sh fh add daytona --print fh add e2b --print fh add github-mcp | codex fh add discord --install-deps --print ``` For sandbox connectors, the output demonstrates the `RemoteSandboxApi` / `SandboxEnv` adapter pattern. For MCP, KB, and data connectors, it demonstrates the appropriate public primitive: `connectMcpServer`, `FilesystemSource`, scoped `Command`, or `ToolDef`. ## Categories ```sh fh add https://provider.example/docs --category sandbox --print fh add https://provider.example/docs --category channel --print fh add https://provider.example/docs --category mcp --print fh add https://provider.example/docs --category kb --print fh add https://provider.example/docs --category data --print ``` | Category | Output shape | |---|---| | `channel` | Verified `Channel`, stable conversation key, durable dispatch, governed outbound tools | | `sandbox` | `SandboxEnv` / `SandboxFactory` | | `mcp` | `connectMcpServer()` wrapper | | `kb` | `FilesystemSource` | | `data` | `ToolDef`, `Command`, or MCP wrapper | | `database` | Bounded data tools; unified persistence bundles are documented for every maintained backend | | `tooling` | Telemetry, evaluation, or grading integration | ## Options | Flag | Description | | --- | --- | | `--json` | Print the catalog, or the direct-recipe change plan when kind/name are supplied. | | `--dir ` | Target directory for direct scaffold recipes. | | `--force` | Replace existing scaffold files. | | `--dry-run` | Print files, dependency resolutions, skips, and conflicts without writing. | | `--no-install` | Update dependency sections without running the detected package manager. | | `--install-deps` | Install dependencies declared by a connector guide. | | `--print` | Print a connector guide even when stdout is a terminal. | | `--category ` | Category for a provider documentation URL. | | `--pr` | Open a draft connector PR for the guide workflow. | ## Package helpers Prefer package helpers when available: - `@fabric-harness/connectors`: Daytona, E2B, Modal, Vercel, Kubernetes, generic remote sandbox, S3, Azure Blob. - `@fabric-harness/channels`: 18 maintained adapters spanning chat, developer tools, support, commerce, billing, knowledge, and email. - `@fabric-harness/databases`: Postgres, MySQL, MongoDB, Redis, and SQLite governed data tools. - `@fabric-harness/azure`: Azure OpenAI, Key Vault, Blob artifacts, Foundry Agent Service, Azure ARM tools. - `@fabric-harness/databricks`: SQL, Jobs, notebooks, Unity Catalog, Agent Services, MLflow, workspace source. ## See also - [Connector catalog](/docs/building/connector-catalog) - [fh update](/docs/cli/update) - [Ecosystem catalog](/docs/ecosystem) - [Sandbox connectors](/docs/building/sandbox-connectors) - [Capability matrix](/docs/reference/capability-matrix) — which connectors are first-class today. --- # fh agents and fh describe Canonical: https://harness.techfabric.com/docs/cli/agents List the finite jobs and persistent agents in a workspace, and inspect any one of them without opening its source. ## `fh agents` ``` fabric-harness agents [--json] ``` List every finite job under `.fabricharness/jobs/` and persistent agent under `.fabricharness/agents/`. The default output is human-readable; `--json` includes each definition's `kind` (`job` or `agent`), source path, model, target, description, and triggers. ```sh fh agents fh agents --json ``` ## `fh describe` ``` fabric-harness describe AGENT_NAME [--json] ``` Show metadata for a single definition. Finite jobs expose their declared model, target default, triggers, examples, and input/output schemas. Persistent agents expose their route name and `kind: "agent"` without running the per-instance initializer. ```sh fh describe ask fh describe ask --json ``` For finite agents declared with `defineAgent({...})`, `describe` shows: - name and description, - input schema, rendered as JSON Schema, - output schema, - declared model, - triggers (`webhook`, etc.), - run target default, - examples (if `examples: [...]` was provided). Plain default-exported functions are rejected. Finite definitions use `defineAgent({...})`; persistent definitions use `createAgent(...)`. ## Why this exists `describe` is the contract for tooling. CI, dev servers, deploy pipelines, and operator tools can use `--json` to discover a definition without parsing TypeScript. --- # fh approvals and fh approve Canonical: https://harness.techfabric.com/docs/cli/approvals Resolve a pending human approval from the terminal, so a paused agent can carry on without anyone opening a console. Agents that gate destructive actions can call `session.approval.request({ reason, risk, timeoutMs })` to pause until a human responds. The CLI is the simplest way to resolve those requests during development and CI. ## `fh approvals` ``` fabric-harness approvals [session-id] [--pending] [--state] [--url ] [--token-env ] [--tenant ] ``` List approval requests for a session. `--pending` filters to unresolved requests; `--state` includes the request's current state machine (timeouts, history of actions). Against a deployed App, omit the session id to discover approvals across every session visible to the authenticated tenant: ```sh fh approvals \ --url https://your-app.databricksapps.com/api \ --token-env DATABRICKS_APP_TOKEN ``` The remote path uses `GET /approvals`, which requires `approval:read` and is tenant-filtered. It does not require `admin:read`. ## `fh approve` ``` fabric-harness approve [--actor ] [--reason ] [--url ] [--token-env ] [--tenant ] ``` Mark an approval as approved. The associated session resumes as soon as the running agent (or worker) observes the resolution. ```sh fh approve ask-1f4f... appr-7 --actor preetham --reason "Cleared by SRE" # Deployed App: the authenticated principal becomes the recorded voter. fh approve ask-1f4f... appr-7 \ --url https://your-app.databricksapps.com/api \ --token-env DATABRICKS_APP_TOKEN \ --reason "Cleared by SRE" ``` ## `fh reject` ``` fabric-harness reject [--actor ] [--reason ] [--url ] [--token-env ] [--tenant ] ``` Mark an approval as denied. The agent typically aborts the gated action and returns an actionable failure. ## See also - [Building agents → Approvals](/docs/building/approvals) - [Policies and approvals](/docs/reference/policies-approvals) --- # Artifacts and Checkpoints Canonical: https://harness.techfabric.com/docs/cli/artifacts List, fetch and inspect the artifacts and checkpoints a session produced, long after the run itself has finished. **Artifacts** are files (Markdown, JSON, CSV, images, ...) that an agent publishes during a session via `session.artifact(name, content, options?)`. **Checkpoints** are explicit named save points. ## `fh artifacts` ``` fabric-harness artifacts [--json] ``` List artifacts for a session. The default output shows id, name, content type, byte size, and creation time. ## `fh artifact get` ``` fabric-harness artifact get [--out ] ``` Fetch a single artifact. If `--out` is omitted, the artifact prints to stdout (use redirection for binary content). If both an id and a name match, the id wins. ```sh fh artifact get ask-1f4f... report.md --out ./reports/report.md ``` ## `fh checkpoints` ``` fabric-harness checkpoints ``` List checkpoints for a session. Each entry includes label, created time, and (when available) a sandbox snapshot reference. ## See also - [Building agents → Artifacts](/docs/building/artifacts) - [Artifacts and observability](/docs/reference/build-manifest) --- # fh build Canonical: https://harness.techfabric.com/docs/cli/build Compile a workspace and emit a deployment manifest, which is the artifact every deploy target consumes. ``` fabric-harness build [--target ] [options] ``` Compiles `.fabricharness/jobs/` and `.fabricharness/agents/`, then emits a deployment artifact under `.fabricharness/build//` with a schema-v2 `manifest.json`. Build manifests use the current time during normal local development. Set the standard `SOURCE_DATE_EPOCH` variable to whole Unix seconds for reproducible artifacts. In GitHub Actions, TechFabric Harness automatically uses the `GITHUB_SHA` commit timestamp when that commit is available, so rebuilding the same source commit produces the same manifest and directory digest. ## Targets | Target | Output | | --- | --- | | `node` (default) | Shared v2 Node HTTP server with finite `/jobs/:name` and persistent `/agents/:name/:id` routes. | | `temporal-worker` | A worker entrypoint that registers Fabric workflows + activities against a Temporal task queue. | | `docker` | `Dockerfile` + Node bundle ready for `docker build`. | | `cloudflare` | Worker entrypoint, Durable Object session store, Sandbox container binding, `wrangler.jsonc`. | | `foundry-hosted-agent` | `Dockerfile`, `azure.yaml`, `infra/main.bicep`, `foundry-agent.yaml`, server bundle. | | `databricks-app` | Databricks App bundle, `app.yaml`, Lakebase-aware server, and Declarative Automation Bundle config. | | `databricks-serving` | MLflow pyfunc proxy and Model Serving deployment assets. | The remaining targets (`aks`, `aca`, `render`) are listed with their capability status in [Deploy targets](/docs/ecosystem/targets). ## Validation Every build statically validates the workspace before emitting anything: skill and role references, imports the chosen target's runtime cannot provide, and files in agent directories that export no definition. See [`fh doctor --workspace`](/docs/cli/doctor#workspace-validation) for the full check list. An error-severity finding fails the build: ```txt Workspace validation failed for target cloudflare: error .fabricharness/jobs/report.ts:1 [target-incompatible-import] "node:fs/promises" is not available on the cloudflare target. Move this work behind a tool that runs in the sandbox, or build for a target whose runtime provides it. ``` That artifact would previously have built cleanly and failed at runtime, after a deploy. Validation runs before any output is written, so a rejected build leaves no half-built artifact for a deploy step to pick up. The same workspace still builds for a target whose runtime provides the import — findings are target-specific, not global. Use `--validate warn` to record findings as build warnings instead, or `--validate off` to skip the check. ## Options | Flag | Description | | --- | --- | | `--out ` | Override the output directory (default `.fabricharness/build/`). | | `--env ` | Load `.env`-style variables before building (e.g. `--env .env.production`). Auto-loads `.env`/`.env.local`; shell env wins. | | `--no-clean` | Skip cleaning the output directory before emit. | | `--validate ` | Static workspace validation before emit. Defaults to `error`. | | `--sbom` | Emit a CycloneDX SBOM via Syft when available. | | `--sbom-required` | Fail if Syft is missing. | | `--provenance` | Emit `provenance.json` for the build artifact. | | `--attestation` | Emit `attestation.intoto.jsonl` with a manifest digest subject. | | `--sign-provenance` | Sign `provenance.json` via `cosign sign-blob`. Implies `--provenance`. | | `--signing-key ` | cosign key path or env reference (default `env://COSIGN_PRIVATE_KEY`). | | `--docker-build` | Run `docker build` after emitting `--target docker`. | | `--docker-push` | Run `docker push` after `--docker-build`. | | `--docker-tag ` | Tag for the built/pushed image. | | `--image-sbom` | Emit an image SBOM via Syft. | | `--image-sbom-required` | Fail if image SBOM cannot be produced. | ## Examples ### Node server artifact ```sh fh build --target node node .fabricharness/build/node/dist/server.mjs ``` ### Docker image with SBOM ```sh fh build --target docker --docker-build --docker-tag myorg/agents:latest --sbom --image-sbom ``` ### Cloudflare scaffold ```sh fh build --target cloudflare cd .fabricharness/build/cloudflare npm install @cloudflare/sandbox @fabric-harness/cloudflare @fabric-harness/sdk npx wrangler dev ``` ### Foundry Hosted Agent scaffold ```sh fh build --target foundry-hosted-agent cd .fabricharness/build/foundry-hosted-agent azd up ``` ### Signed provenance + attestation ```sh export COSIGN_PRIVATE_KEY=$(cat cosign.key) fh build --target node --provenance --sign-provenance --attestation ``` ## What's in `manifest.json` - The TechFabric Harness version and target, - separate `jobs` and persistent `agents` collections with schemas, models, and triggers, - declared sandbox backend(s), - session-store backend, if configured, - digest of the artifact, - optional provenance/attestation metadata. `createdAt` is the wall-clock build time by default, the `SOURCE_DATE_EPOCH` time when explicitly configured, or the source commit time in GitHub Actions. It is therefore stable for protected exact-commit release rebuilds without hiding differences in any artifact file. The CLI exposes manifests through `fh builds`. A Node server can read workspace-local artifacts at `GET /builds/:target/manifest`; Cloudflare exposes its embedded manifest at `GET /manifest`. See also: [Build and run artifacts](/docs/deployment/build-artifacts), [Build manifest](/docs/reference/build-manifest), [`fh builds`](/docs/cli/builds), [`fh verify-attestation`](/docs/cli/builds#verify). --- # Builds and Verification Canonical: https://harness.techfabric.com/docs/cli/builds List the build manifests you have emitted and verify the provenance and attestations attached to each one. ## `fh builds` ``` fabric-harness builds ``` List every build manifest emitted under `.fabricharness/build/`. Output includes target, output dir, agent count, manifest digest, and timestamps. ## `fh verify-attestation` ``` fabric-harness verify-attestation ``` Verify the in-toto attestation produced by `fh build --attestation`. The argument can be a build directory (the CLI finds `attestation.intoto.jsonl`) or a direct path to the attestation file. ```sh fh verify-attestation .fabricharness/build/node fh verify-attestation .fabricharness/build/node/attestation.intoto.jsonl ``` ## `fh verify-provenance` ``` fabric-harness verify-provenance ``` Verify the SLSA-style provenance produced by `fh build --provenance`. Optionally signed with cosign via `--sign-provenance`. ```sh fh verify-provenance .fabricharness/build/node ``` If a `provenance.sig` is present, the CLI invokes `cosign verify-blob` with the configured public key. Otherwise it validates structure and digests only. ## See also - [`fh build`](/docs/cli/build) — emit artifacts and provenance. - [Build manifest](/docs/reference/build-manifest) — manifest schema. - [Security hardening](/docs/reference/security-hardening) — when to require provenance. --- # Compatibility Contract Canonical: https://harness.techfabric.com/docs/cli/compatibility Negotiate TechFabric Harness CLI features safely from Desktop, CI, and other automation. TechFabric Harness exposes a machine-readable contract so an integrating application can verify behavior before it runs a command. Use capability negotiation together with a supported version range. A version check alone cannot prove that a build includes the commands, targets, and protocol versions your application needs. ```bash fh capabilities --json ``` The command writes JSON to stdout and does not inspect a workspace or read credentials. Abridged output (the installed version and arrays vary by release): ```json { "schemaVersion": 1, "product": "fabric-harness", "cliVersion": "", "protocolVersion": 1, "buildManifestVersion": 2, "commands": ["init", "run", "build", "deploy", "doctor", "capabilities"], "buildTargets": ["node", "temporal-worker", "docker", "cloudflare", "databricks-app", "databricks-serving"], "runtimes": ["inline", "temporal"], "features": ["cli.preview-deploy", "buzz.doctor", "databricks.app-build", "databricks.app-deploy", "databricks.ai-gateway"] } ``` The arrays can gain values in a compatible release. Consumers should require the values they use and ignore values they do not recognize. A changed `schemaVersion`, `protocolVersion`, or `buildManifestVersion` requires an explicit compatibility decision. ```mermaid flowchart LR A[Desktop or automation] --> B[Resolve fh executable] B --> C[Check supported semver range] C --> D[Run fh capabilities --json] D --> E{Required protocol and features present?} E -->|Yes| F[Run init, build, deploy, or run] E -->|No| G[Stop with an upgrade or compatibility error] ``` ## Consumer example ```ts import { execFileSync } from 'node:child_process'; const capabilities = JSON.parse( execFileSync('fh', ['capabilities', '--json'], { encoding: 'utf8' }), ); const required = [ 'cli.preview-deploy', 'buzz.doctor', 'databricks.app-build', 'databricks.app-deploy', 'databricks.ai-gateway', ]; if (capabilities.protocolVersion !== 1) { throw new Error(`Unsupported Harness protocol ${capabilities.protocolVersion}`); } const missing = required.filter((feature) => !capabilities.features.includes(feature)); if (missing.length > 0) { throw new Error(`Harness is missing: ${missing.join(', ')}`); } ``` ## Release testing Fabric Desktop tests both its minimum certified Harness release and the current npm `latest`. Harness contributors can test an unpublished CLI against the adjacent Desktop checkout: ```bash pnpm test:desktop-compat ``` The command builds and packs `@fabric-harness/cli`, installs that tarball in isolation, then drives Desktop's real Databricks bridge through scaffold, mock run, build validation, and deploy preview for every bundled template. It also verifies the capability contract and scans generated files for leaked credentials. Keep application templates on the compatible ranges emitted by the installed CLI. Fabric packages are independently versioned, so matching majors are not a compatibility signal. CI builds the executable CLI, scaffolds every platform template, and compares each generated range with the corresponding workspace package so a release cannot leave a fresh project on a stale or invented version. See [release and documentation status](/docs/reference/release-status) for the current published versions and runtime requirements. --- # Fiber terminal console Canonical: https://harness.techfabric.com/docs/cli/console Operate jobs, persistent agents, streams, tool calls, and approvals from a keyboard-first terminal UI. **Fiber** is TechFabric Harness's optional terminal UI. Open it with `fh fiber`. Fiber is a client of the public Fabric HTTP protocol: it does not start a second runtime or bypass server policy. Authentication, tenant isolation, durable admission, offsets, tool events, and approval resolution behave the same as other clients. For the shortest local loop, start the Node dev server and Fiber together: ```sh FABRIC_HARNESS_API_TOKEN=local-token fh dev --mock --console ``` `--console` is intentionally limited to `fh dev --target node`. Cloudflare and Temporal development processes keep their existing external lifecycle and can be observed by running `fh fiber --url ...` separately. Start the server in one terminal: ```sh FABRIC_HARNESS_API_TOKEN=local-token fh dev --mock ``` Then open the interactive console: ```sh FABRIC_HARNESS_API_TOKEN=local-token fh fiber ``` Fiber reads `/admin/agents` and presents an explicit selected row, connection state, activity pane, and input line. Use the arrow keys and Enter to choose a finite job or persistent agent. Persistent agents use `--id ` when supplied and `default` otherwise. Messages are admitted asynchronously. You can keep typing while a turn is active: Fiber shows pending prompts and admits them in order through the server's durable FIFO path. It follows each returned offset and renders assistant messages, tool calls, tool results, approval events, errors, and terminal settlement. Model and tool output is stripped of terminal control sequences before it is rendered. Color is supplemental—selection and run state are also labeled in text. Use Escape to return to target selection when the queue is idle. Ctrl-C aborts the active client request, clears prompts that have not been admitted, and exits. Fiber never prints bearer tokens. ## One-shot jobs ```sh fh fiber --job report --input '{"topic":"weekly usage"}' ``` Input must be JSON. The job uses the authenticated `/jobs/:name` route and prints the complete result envelope. ## One-shot persistent messages ```sh fh fiber \ --agent support \ --id customer-42 \ --session billing \ --message "Where is invoice 1007?" ``` Use `--url` for a deployed server, `--tenant` for explicit operator tenant selection, and `--token-env` when the bearer token is stored under a different environment variable: ```sh PROD_AGENT_TOKEN=... fh fiber \ --url https://agents.example.com \ --token-env PROD_AGENT_TOKEN \ --tenant acme \ --agent support --id customer-42 --message "Retry the export" ``` Tokens are read from the environment rather than command arguments, so they do not appear in shell history or process listings. ## Plain and non-interactive terminals Use `fh fiber --plain` for the line-oriented prompt. CI and redirected stdin are not TTYs, so Fiber fails with actionable guidance in those environments. One-shot `--job` and `--agent --message` commands remain non-interactive and do not load Fiber. ## Interactive commands | Command | Effect | | --- | --- | | `:approvals ` | List approval requests for a session. | | `:approve [reason]` | Approve through the server's RBAC route. | | `:reject [reason]` | Reject through the same route. | | `:quit` | Close the terminal client. | The identity used to resolve an approval comes from the authenticated server principal. Text typed after the approval id is a reason, not an actor override. ## Failure behavior - Connection and HTTP failures remain visible in the status and activity panes; they never become successful output. - Additional prompts remain visible in Fiber's queue and are admitted in order; a failed prompt does not prevent the next queued prompt from running. - Closing Fiber aborts active polling and discards prompts that were not yet admitted. Work already durably admitted remains governed by the server and can be inspected by run/submission id. - ANSI, OSC, and control bytes in model/tool output are removed before terminal rendering. - Missing or invalid authentication is reported by the server and Fiber preserves the server's public, redacted error message. - Exiting Fiber launched by `fh dev --console` closes the watcher and dev server cleanly. --- # fh deploy Canonical: https://harness.techfabric.com/docs/cli/deploy Build and deploy a TechFabric Harness workspace to Databricks, Node, containers, Kubernetes, Cloudflare, Foundry, Temporal, or Render. ```sh fh deploy --target [--preview] [--profile ] [--env ] [--env-name ] [--with-app] ``` `fh deploy` selects a target driver, builds the workspace for that target, runs its prerequisite checks, and invokes the platform deployment command. Use `--preview` first in automation or a new account; it prints the driver actions without changing the target platform. ## Targets | Target | Deployment path | | --- | --- | | `databricks-app` | Build and deploy a Databricks App through its Declarative Automation Bundle | | `databricks-serving` | Build the MLflow proxy and deploy a Databricks Model Serving endpoint | | `node` | Run the built Node server locally | | `docker` | Build and run the generated container | | `cloudflare` | Deploy the generated Worker | | `aks`, `aca`, `aci` | Deploy to Azure Kubernetes Service, Container Apps, or Container Instances | | `foundry-hosted-agent` | Deploy the generated Microsoft Foundry Hosted Agent assets | | `k8s` | Apply the generic Kubernetes artifact | | `temporal-worker` | Deploy the generated Temporal worker | | `render` | Deploy the generated Render service | ## Options | Flag | Behavior | | --- | --- | | `--target ` | Required deployment target | | `--preview` | Print intended commands without executing them | | `--profile ` | Databricks CLI profile used by App/Serving deployment | | `--env ` | Load an explicit `.env`-style file before config and preflight | | `--env-name ` | Load `.env.` and matching workspace environment overrides | | `--with-app` | After `databricks-serving` succeeds, also build and deploy `databricks-app` | Shell variables win over env-file values. Secrets are passed to provider commands through the environment; they are not written to build manifests. ## Databricks Apps ```sh fh doctor --target databricks-app fh deploy --target databricks-app --preview --profile production fh deploy --target databricks-app --profile production --env .env.production ``` The App driver expects the Databricks CLI, authentication, and a workspace bundle generated by the `databricks-app` build. When the App declares capabilities in `FABRIC_DATABRICKS_APP_CAPABILITIES`, doctor fails closed if required Lakebase, Genie, OBO, or cost bindings are absent. ## Databricks Serving, optionally paired with an App ```sh fh doctor --target databricks-serving fh deploy --target databricks-serving --preview fh deploy --target databricks-serving --with-app ``` Serving deployment runs a network-free doctor preflight before any provider mutation. Missing Python/MLflow, Databricks authentication, or package output stops the command with an actionable error. `--with-app` is accepted only with `databricks-serving`; the App deployment starts only after Serving succeeds. Existing endpoint deployments are safe to retry while Databricks is converging an earlier change. The driver waits for endpoint readiness before replacing the served model, waits again before updating AI Gateway inference-table configuration, and waits for that gateway update to settle before reporting success. New endpoints follow the same readiness boundary between creation and the gateway update. A readiness or update failure stops the deploy and does not start `--with-app`. ## Failure behavior - A missing or unknown target fails before a driver runs and prints close target suggestions. - An invalid flag or using `--with-app` on another target fails without deploying. - Databricks preflight failures stop before build/deploy provider calls. - A target command failure is returned as a failed deploy; the CLI does not claim rollback of resources already accepted by the provider. See [Databricks deployment](/docs/deployment/databricks), [`fh build`](/docs/cli/build), and [`fh doctor`](/docs/cli/doctor). --- # fh dev Canonical: https://harness.techfabric.com/docs/cli/dev Start a local HTTP and SSE server for a workspace, so you can drive an agent from a browser or curl while you build it. ``` fabric-harness dev [--target node|cloudflare|temporal-worker] [options] ``` `fh dev` boots the selected target's development server and watches both `.fabricharness/jobs/` and `.fabricharness/agents/`. The Node target uses the same v2 server as Node-derived builds. Cloudflare uses Wrangler for finite jobs and Durable Object-backed persistent agents. ## Routes - `GET /health` - `GET /ready` - `POST /jobs/:name` — invoke a finite job with its JSON input. - `POST /agents/:name/:id` — durably admit a persistent message and return `202`. - `GET /agents/:name/:id/stream?offset=...` — tail persistent conversation records. - `GET /builds/:target/manifest` — read a build manifest still under the workspace. Cloudflare also exposes `GET /manifest`; persistent instances use Durable Objects for FIFO submissions, leases, conversation streams, abort, and deletion. ## Options | Flag | Description | | --- | --- | | `--target ` | Default `node`. | | `--env ` | Load `.env`-style variables. Repeatable; shell env wins. | | `--mock` | Use the deterministic mock model provider for every request. | | `--console` | Open the Fiber terminal UI after the Node target starts; unsupported for Cloudflare and Temporal targets. | | `--host ` | Listen address (default `127.0.0.1`). | | `--port ` | Listen port (default `3000`; the CLI selects the next available port when it is busy). | | `--auth-token-env ` | Require `Authorization: Bearer $$VAR` for invocations. | | `--max-body-bytes ` | Reject request bodies larger than `n`. | | `--rate-limit-window-ms ` | Rate-limit window in ms. | | `--rate-limit-max ` | Rate-limit max requests per window. | ## Example ```sh fh dev --mock --port 4000 --auth-token-env FABRIC_DEV_TOKEN ``` Or keep the server and operator view in one process: ```sh FABRIC_DEV_TOKEN=local-token fh dev --mock --console --auth-token-env FABRIC_DEV_TOKEN ``` ```sh curl -X POST \ -H "Authorization: Bearer $FABRIC_DEV_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"question":"What is Temporal?"}' \ http://localhost:4000/jobs/ask ``` ## When to use which - **`fh run`** — one-shot invocations, scripts, CI smoke tests. - **`fh dev`** — local development with hot reload, finite job webhook testing, and durable persistent-agent streams. See [HTTP Server](/docs/reference/http-server) for the complete Node route table. ## Transport-free runs `fh run` loads the selected public definition directly and does not start an HTTP listener. Finite agents continue to accept JSON payloads. Persistent agents accept a message and durable instance identity controls: ```bash fh run support --id customer-42 --new \ --data '{"account":"acme"}' --prompt "Triage this request" # Continue only the incarnation printed by the first command. fh run support --id customer-42 --uid inst_... --prompt "Continue" ``` Initial data is schema-validated before instance identity or conversation records are committed. `--new` fails if the instance already exists, `--uid` fails if the instance is missing or has been replaced, and the command prints the resolved UID to stderr. SIGINT/SIGTERM cancels the active finite or persistent run and interaction-scoped dynamic sandboxes are reclaimed when it settles. Projects that already use Vite 8 can instead add `fabricHarness()` from `@fabric-harness/vite`; see [Vite integration](/docs/reference/vite-integration). This is optional and uses the same discovery/build registry as `fh dev` and `fh build`. --- # docs Canonical: https://harness.techfabric.com/docs/cli/docs List, read, and search TechFabric Harness documentation as Markdown from the CLI. The docs commands consume the published `llms.txt`, `llms-full.txt`, and per-page Markdown routes. They work in a source checkout or any project with the CLI installed. ## List routes ```sh fh docs list fh docs list --query databricks fh docs list --json ``` Each entry includes its stable slug, title, and description. Duplicate priority/index entries are removed. ## Read a page ```sh fh docs read databricks/quickstart fh docs read /docs/operating/auth fh docs read https://harness.techfabric.com/docs/building/http-applications ``` Output is the page's Markdown source, suitable for a terminal pager or an LLM context file: ```sh fh docs read databricks/integrations | less fh docs read reference/api > /tmp/fabric-api.md ``` ## Search the corpus ```sh fh docs search unity catalog lineage fh docs search durable approval --limit 5 fh docs search lakebase credential --json ``` Search ranks title and description matches before full-corpus occurrences and prints a nearby text snippet. Use `--base-url` to test a preview or self-hosted documentation worker with the same routes. --- # fh doctor Canonical: https://harness.techfabric.com/docs/cli/doctor Diagnose a workspace before you blame the agent, covering tool wiring, configuration and live model connectivity. ``` fabric-harness doctor [--target node|temporal-worker|databricks-app|databricks-serving|buzz] [--model provider/model] [--getting-started] [--tools] [--workspace] [--live] [--json] ``` `fh doctor` validates that your workspace is set up correctly and (optionally) that a real model can be invoked. ## Options | Flag | Description | | --- | --- | | `--target ` | Validate the chosen run, deployment, or first-party integration target. | | `--model ` | Probe a specific model (combine with `--live`). | | `--getting-started` | Check Node version, ESM package setup, Fabric dependencies, npm scripts, and `.fabricharness/agents` discovery. | | `--tools` | Enumerate built-in tools and required binaries (`docker`, `gh`, etc.). | | `--workspace` | Statically validate the workspace: skill and role references, target-incompatible imports, and files in agent directories that export no definition. | | `--live` | Make a bounded live model request, or run read-only relay and durable-state certification for `--target buzz`. | | `--json` | Emit a machine-readable report. | ## Examples ### Local readiness ```sh fh doctor --getting-started --tools ``` ### Live model check ```sh cp .env.example .env.local # edit .env.local and set OPENAI_API_KEY=... fh doctor --live --model openai/gpt-5.5 ``` ### Workspace validation ```sh fh doctor --workspace fh doctor --workspace --target cloudflare ``` Reads source without executing it, so it needs no credentials, no network, and does not import your agent modules. It reports: | Code | Severity | Meaning | | --- | --- | --- | | `skill-not-found` | error | A `session.skill('name')` call whose name no skill defines — neither a `.fabricharness/skills/` directory, a build-time `SKILL.md` import, nor a `defineSkill()` in the same file. | | `role-not-found` | error | An `init({ role })` naming a role no file defines. | | `target-incompatible-import` | error | A Node built-in the chosen target's runtime does not provide. Only reported when `--target` names such a runtime. | | `no-default-export` | warning | A file in an agent directory exporting no default definition. | Errors exit non-zero, so this composes into CI. Warnings do not. Without `--target`, target-specific checks are skipped — a workspace that only ever runs on Node should not be warned about its `node:fs` import. Two checks are deliberately conservative, because a false positive on correct code is worse than a missed finding: a skill imported from a package cannot be resolved from source, so the skill check is suppressed for that file; and the role check is scoped to `init({ ... })` options, since `role:` is also the LLM message discriminator. ### Temporal target ```sh fh doctor --target temporal-worker ``` The doctor checks Temporal connectivity using config/env defaults — make sure `FABRIC_TEMPORAL_ADDRESS` and your task queue are correct. ### Databricks App bindings ```sh fh doctor --target databricks-app --json fh doctor --target databricks-app --live --json ``` Every Databricks report includes a workspace-readiness section. It uses four intentionally narrow classifications: | Classification | Meaning | | --- | --- | | `contract-supported` | The installed Harness code has an offline-tested adapter. It says nothing about this workspace's grants or enrollment. | | `live-certified-here` | The installed package, declared cloud, and region exactly match retained public certification evidence. | | `preview-enabled` | A bounded read-only live probe reached that preview API in this workspace. | | `not-established` | The command cannot prove the claim. Treat it as unknown, not as disabled. | Offline mode reports the configured host, inferred cloud/region, installed package version, exact public certification relationship, and contract support for Apps, Unity Catalog/OBO, SQL, Genie, Model Serving, AI Gateway, Lakebase, managed MCP, Supervisor Agents, and managed memory. `--live` adds bounded read-only identity and service discovery probes. A successful service probe proves reachability under the probing principal; it does not prove every end user's Unity Catalog grant. The command never prints tokens or connection strings. Set `FABRIC_DATABRICKS_APP_CAPABILITIES` to the comma-separated capabilities the App claims: `lakebase`, `genie`, `obo`, and/or `system-tables-cost`. Doctor fails closed when a claim lacks its required endpoint, database, Genie space, OBO opt-in, warehouse, or cost-scope binding. It never prints credential values. The report also includes a redacted effective inventory: - identity kind and credential source; - enabled model-callable tools with effects and service names; - static or input-bound governed resources; - approval coverage; - persistence, scheduler identity, lease, and catch-up modes; and - unsupported or dynamically resolved capabilities. Persistent-agent initializers are interaction-scoped, so doctor reports their tool inventory as dynamic instead of executing an initializer with a fabricated identity. ### Buzz bridge ```sh fh doctor --target buzz --json fh doctor --target buzz --live ``` The offline preflight validates Node 22/native WebSocket support, the relay and forwarding URLs, redacted Nostr-key and HMAC-secret shape, the server-owned community/channel allowlist, durable PostgreSQL or Lakebase configuration, and the current v2 generated recipe. It specifically rejects the old process-memory tail and recipes that omit decision-receipt or dead-letter wiring. `--live` is a read-only certification profile. It performs a bounded NIP-11 probe, requires NIP-01 and NIP-42, signs NIP-98 queries with the configured adapter identity, verifies the returned NIP-01 event integrity, and requires that identity in both the authoritative relay roster and every configured channel member list. It then connects to PostgreSQL or Databricks Lakebase with a single-connection pool and reads only content-free operational evidence: relay cursor lag, cursor-update age, unresolved dead-letter depth, and prepared/published decision-card counts. The default limits are 300 seconds of relay lag, 300 seconds since the cursor update, and zero unresolved dead letters. Set `BUZZ_MAX_RELAY_LAG_SECONDS`, `BUZZ_MAX_CURSOR_AGE_SECONDS`, and `BUZZ_MAX_DEAD_LETTERS` to explicit non-negative integers when the deployment SLO differs. The JSON report is safe for CI evidence: it never includes event content, private keys, forwarding secrets, database URLs, or database passwords. Relay and channel membership prove transport admission only; they do not grant Fabric action authority. ## What it checks - Workspace root resolution. - Agents discovered. - Node/package/ESM/dependency setup (when `--getting-started`). - Built-in tool schemas and binaries on PATH (when `--tools`). - Model provider configuration. - Optional live model round-trip when `--live`. - Optional Temporal connectivity for `--target temporal-worker`. - Databricks CLI, authentication, and claimed App bindings for Databricks deployment targets. - Buzz bridge configuration, v2 durability wiring, and optional read-only relay/Lakebase certification. --- # fh run Canonical: https://harness.techfabric.com/docs/cli/run Execute a workspace agent, or any standalone agent file, against a local Node runtime or a Temporal worker. ``` fabric-harness run [options] ``` Runs the named agent. The CLI loads the agent module, validates the input payload, calls `run({ init, input, payload })`, and validates the output. `` is either a workspace agent name (resolved from `.fabricharness/jobs/`) or a path to an agent file (see [Single-file mode](#single-file-mode)). ## Single-file mode When `` resolves to an existing `.ts`, `.mts`, `.js`, or `.mjs` file, `fh run` executes that file directly — no `.fabricharness/` workspace, no `config.ts`, no credentials required: ```sh fh run ./agent.ts --message "hello" ``` - The file is transpiled on the fly. Package imports (including `@fabric-harness/sdk`) resolve from the nearest `node_modules` to the file, falling back to the CLI's own install. - Every exported `defineAgent()`/`createAgent()` value is discovered. With exactly one export it runs directly; with several, pass `--agent ` to select one (the error lists the exported names). Persistent `createAgent()` agents still require a workspace. - When no model credentials resolve (`--model`, `FABRIC_MODEL`, or provider keys), the run falls back to the mock model and says so on stderr, so the command round-trips offline. `--mock` keeps its explicit meaning. - The reply (and any structured output) prints on stdout; the session id prints on stderr as `[fabric-harness] session completed (memory store — not persisted).` — single-file runs use an in-memory store, so there is nothing to resume. - An explicit path that does not exist (`./missing.ts`) is a hard error; a bare name still falls back to workspace agent resolution. ## Options | Flag | Description | | --- | --- | | `--agent ` | Single-file mode: select one export when the file exports several agents. | | `--id ` | Session identifier. **Reusing an existing id resumes that persisted session** — new turns append to its history. If omitted, a session id is generated using `${idPrefix}-${uuid}`. | | `--resume ` | Explicit alias for `--id `: continue the persisted session ``. | | `--fork ` | Fork persisted session `` into a new session: copies its history into a fresh id (pass `--id` to name the fork), then continues the copy. Requires a persisted store. | | `--target ` | Where the agent runs. Defaults to `node`. `temporal-worker` switches `--runtime` to `temporal`. | | `--runtime ` | Equivalent lower-level flag. Usually set via `--target`. | | `--model ` | Override the agent's default model, e.g. `openai/gpt-5.5`. | | `--mock` | Use the deterministic mock model provider — no credentials needed. | | `--mock-script ` | Scripted mock responses from a JSON fixture file (aimock-style `{ match, response }` entries). Implies `--mock`; see [Test Without Credentials](/docs/building/test-without-credentials#scripted-mock-responses). | | `--cwd ` | Default sandbox/session working directory for this run. Relative paths stay scoped inside the sandbox workspace. | | `--uid ` | Persistent agents: require an existing incarnation with this id. | | `--new` | Persistent agents: require creation of a new instance. | | `--data ` | Persistent agents: immutable initial data for a new instance. | | `--tenant ` | Tenant identifier for this run. | | `--prompt ` | Message text for persistent agents; also the prompt for `--runtime temporal` mode. | | `--payload ''` | Pass an inline JSON payload. | | `--payload-file ` | Read JSON payload from a file. | | `--stdin` | Read JSON payload from stdin. | | `--set key=value` | Set a payload field. May be repeated. | | `-- ` | Shortcut for setting a payload field, e.g. `--question "..."`. | | `=` | Positional shortcut for setting a payload field, e.g. `question="..."`. | | `--env ` | Load `.env`-style variables. Repeatable; shell env wins. | ## Resuming and forking sessions Every successful workspace run prints its session id on stderr with a resume hint: ```text [fabric-harness] session sess-1 completed. Resume: fh run hello --resume sess-1 ``` With a durable store (`store: { backend: 'file' }`, the default), passing the same id again — via `--id` or the explicit `--resume` alias — continues the session: the model sees the prior history and new entries append to it. `--fork ` instead copies a persisted session into a new id and continues the copy, leaving the original untouched: ```sh fh run hello --id sess-1 --message "first" fh run hello --resume sess-1 --message "second" # continues sess-1 fh run hello --fork sess-1 --id sess-1-copy --message "third" # branches a copy ``` With `store: { backend: 'memory' }` nothing is persisted, and the run says so explicitly (`session completed (memory store — not persisted).`) — `fh sessions` staying empty after a memory-store run is expected, not data loss. Resume and fork require a persisted store. ## Payload precedence When more than one source is given, fields merge in this order (later wins): ``` --payload → --payload-file → --stdin → --set / -- / key=value ``` ## Examples ### Single file, no workspace ```sh fh run ./agent.ts --message "hello" fh run ./multi.ts --agent beta --message "hello" ``` ### Inline JSON ```sh fh run ask --payload '{"question":"What is Temporal?"}' ``` ### Field shortcut ```sh fh run ask --question "What is Temporal?" fh run ask question="What is Temporal?" fh run ask --set question="What is Temporal?" ``` ### Working directory ```sh fh run code --cwd /workspace/project --prompt "Run tests and summarize failures" fh run code --cwd packages/core --payload '{"prompt":"Inspect this package"}' ``` `--cwd` is a sandbox cwd, not a host directory switch. Use it to make file/shell tools default to a repository subdirectory. ### From a file or stdin ```sh fh run ask --payload-file input.json echo '{"question":"hi"}' | fh run ask --stdin ``` ### Real model Put provider keys once in a repo/workspace `.env.local`; TechFabric Harness auto-loads it and shell env still wins. ```sh cp .env.example .env.local # edit .env.local and set OPENAI_API_KEY=... fh run ask --model openai/gpt-5.5 --question "What is Temporal?" ``` Use explicit `--env ` only for test/CI overrides. ### Temporal worker target ```sh # In a separate terminal: fh temporal-worker # Then: fh run ask --target temporal-worker --id ask-001 --prompt "What is Temporal?" ``` ## What happens during `run` 1. Resolve workspace root by walking up to find `.fabricharness/`. (Single-file mode skips this and the next step — the file is loaded directly with SDK defaults.) 2. Load `.fabricharness/config.ts` and merge with env and CLI flags. 3. Resolve agent path, target, runtime, model, id, and sandbox cwd. 4. Apply env model provider (e.g. set provider credentials). 5. Validate input payload against the agent's input schema (metadata agents only). 6. Call the agent's `run({ init, input, payload })`. 7. Validate output against the output schema (metadata agents only). 8. Persist session and print the session id on stderr (with a resume hint, or a `not persisted` notice on the memory store). ## See also - [`fh agents` / `fh describe`](/docs/cli/agents) — discover what's runnable. - [Sessions](/docs/cli/sessions) — inspect what just happened. - [Configuration](/docs/getting-started/configuration) — defaults and precedence. --- # Sessions, Inspect, Logs, Replay, Metrics, Compact Canonical: https://harness.techfabric.com/docs/cli/sessions Inspect what actually happened during a run, with logs, replay, metrics and compaction over a session already finished. Every `fh run` and every dev-server invocation persists a session under `.fabricharness/sessions/` (or your configured store). The CLI ships several commands for reading those sessions. With `store: { backend: 'memory' }` nothing is persisted — the run says so on stderr and `fh sessions` stays empty; that is expected, not data loss. To continue a persisted session, re-run with the same `--id` (or `--resume `); see [`fh run`](/docs/cli/run#resuming-and-forking-sessions). ## `fh sessions` ``` fabric-harness sessions ``` Lists persisted sessions. Output includes session id, agent name, last update time, and entry counts. ## `fh inspect` ``` fabric-harness inspect ``` Shows the full structured session: prompts, assistant messages, tool calls, tool results, shell commands, task starts/ends, approvals, compactions, checkpoints, and artifacts. ## `fh logs` ``` fabric-harness logs [--events] ``` Prints a readable timeline. Use `--events` to include the lower-level event stream (`text_delta`, `tool_start`, `tool_end`, etc.). ## `fh metrics` ``` fabric-harness metrics [--json] [--breakdown] ``` Aggregate token, tool, shell, and artifact metrics for the session. Anthropic prompt-cache tokens (`Cache: read=N write=N`) are surfaced when present. When the SDK was able to estimate USD cost from the static price table (or the provider supplied it directly), a `Cost: $0.XXXX` line is printed. Pass `--breakdown` to print per-`provider/model` cost line items: ```text Cost: $0.012450 openai/gpt-4o: $0.011200 anthropic/claude-haiku-4-5-20251001: $0.001250 ``` The cost catalog is a static table shipped in the SDK — override or extend it with `registerModelPrices()` when you have custom-rate contracts. Real-time billing reconciliation is out of scope; use vendor invoices for billing. ## `fh export-audit` ``` fabric-harness export-audit [--format jsonl|csv] [--output |-] ``` Streams every entry in the session log out as one row per line — JSONL by default, CSV via `--format csv`. Each row carries normalized columns: timestamp, type, entryId, parentId, tool, command, model, provider, durationMs, inputTokens, outputTokens, cachedInputTokens, cacheWriteTokens, costUsd, approvalId, audience, eventType, idempotencyKey, errorMessage. Pipe straight into your SIEM / data warehouse: ```sh fh export-audit ask-1f4f... --format jsonl | jq -c 'select(.type == "model_attempt")' fh export-audit ask-1f4f... --format csv --output audit.csv ``` `--output -` writes to stdout (default when `--output` is omitted). Big sessions stream line-by-line — no full-session buffering. ## `fh replay` ``` fabric-harness replay ``` Read-only view of the session's *active path* (post-compaction) and the model context that would be sent on the next turn. Useful for debugging compactions and prompt drift. ## `fh checkpoints` ``` fabric-harness checkpoints ``` Lists checkpoints in a persisted session. Checkpoints are not created automatically — create them from agent code with `session.checkpoint.create(...)`, or per task with `session.task(text, { checkpoint: true })`. When a session has none, the command says so and prints this hint. ## `fh compact` ``` fabric-harness compact [--keep ] [--summary ] ``` Append a compaction entry to a persisted session. `--keep ` keeps the last *n* entries verbatim, `--summary ` provides an explicit summary instead of running the model. ## Example session lifecycle ```sh fh run ask --question "What is Temporal?" # Session id: ask-1f4f... fh inspect ask-1f4f... fh logs ask-1f4f... fh metrics ask-1f4f... fh replay ask-1f4f... fh compact ask-1f4f... --keep 2 --summary "User asked about Temporal." ``` --- # fh tasks and fh cancel-task Canonical: https://harness.techfabric.com/docs/cli/tasks Inspect, cancel and manage the durable child tasks a session started, including ones still running after it exited. A **task** in TechFabric Harness is a child or delegated agent run, typically started via `session.task()` from agent code. Task state is persisted alongside the parent session and exposed via the CLI. ## `fh tasks` ``` fabric-harness tasks [--json] ``` List durable tasks for a session: id, status, start/end time, parent prompt, and result (if completed). ## `fh task` ``` fabric-harness task [--json] ``` Show the status, checkpoints, and metadata of a single task. ## `fh cancel-task` ``` fabric-harness cancel-task [--actor ] [--reason ] ``` Append a cancellation marker so the running task observes the cancel and exits at its next checkpoint. ```sh fh cancel-task ask-1f4f... task-2 --actor preetham --reason "Replaced by manual fix" ``` ## `fh checkpoints` ``` fabric-harness checkpoints ``` List checkpoints inside a session. Checkpoints are explicit save points created via `session.checkpoint.create({ label })`. When the sandbox supports snapshots, a checkpoint may include a sandbox snapshot reference. ## See also - [Building agents → Tasks](/docs/building/tasks) - [Building agents → Approvals](/docs/building/approvals) --- # fh temporal-worker Canonical: https://harness.techfabric.com/docs/cli/temporal-worker Run a Temporal worker locally that executes TechFabric Harness activities, so you can test the durable path before deploying it. ``` fabric-harness temporal-worker [--task-queue ] [--address ] [--env ] ``` Starts a long-running Temporal worker that registers TechFabric Harness workflows and activities (model calls, tool execution, sandbox commands, result validation, compaction, child tasks). Pair this with `fh run --target temporal-worker` to drive durable agent sessions. ## Options | Flag | Description | | --- | --- | | `--task-queue ` | Defaults to `FABRIC_TEMPORAL_TASK_QUEUE`, then `config.temporal.taskQueue`, then `fabric-harness`. | | `--address ` | Defaults to `FABRIC_TEMPORAL_ADDRESS`, then `config.temporal.address`, then `localhost:7233`. | | `--env ` | Explicit env-file override. Repo/workspace `.env` and `.env.local` are auto-loaded; shell env wins. | Additional behavior comes from `.fabricharness/config.ts` and env: - `FABRIC_TEMPORAL_NAMESPACE` / `config.temporal.namespace` - `config.temporal.apiKey` / `config.temporal.apiKeyEnv` - `config.temporal.tls` ## Example ```sh # Terminal 1: a local Temporal dev server (e.g. via `temporal server start-dev`) temporal server start-dev # Terminal 2: Fabric worker; provider keys can live in repo-level .env.local fh temporal-worker --task-queue fabric-harness # Terminal 3: drive an agent fh run ask --target temporal-worker --id ask-001 --prompt "What is Temporal?" ``` ## What it does on startup 1. Resolves workspace root and config. 2. Creates a `FileSessionStore` rooted at the workspace. 3. Creates an empty sandbox plus the built-in tool set. 4. Resolves the model + provider from env/config (`applyEnvModelProvider`). 5. Registers Fabric activities (`createLocalTemporalActivities`). 6. Starts the Temporal worker on the resolved address + task queue. 7. Listens for `SIGINT`/`SIGTERM` and shuts the worker down cleanly. ## See also - [Deployment → Temporal worker](/docs/deployment/temporal-worker) - [Configuration](/docs/getting-started/configuration) --- # fh test Canonical: https://harness.techfabric.com/docs/cli/test Discover the eval suites in a workspace and run them, which is how a prompt change gets a number attached before review. ``` fabric-harness test [path] [options] ``` `fh test` discovers `*.eval.ts` files, imports them as eval suites, runs each case through the suite's runner, scores the outputs, and prints a summary. It exits `0` when every suite passes and `1` when any suite fails. ## Options | Flag | Description | | --- | --- | | `--pattern ` | Glob pattern for eval files (default `**/*.eval.ts`). | | `--suite ` | Run only a specific suite by name. | | `--scorer ` | Filter reporting to a specific scorer. | | `--json` | Output results as JSON. | | `--threshold ` | Override the pass threshold for all suites. | ## Example eval file ```ts import { defineEvalSuite, exactMatchScorer } from '@fabric-harness/evals'; export default defineEvalSuite({ name: 'hello-world', cases: [ { id: 'greeting', input: 'hello', expected: 'HELLO' }, ], runner: ({ case: evalCase }) => String(evalCase.input).toUpperCase(), scorers: [exactMatchScorer()], }); ``` ## Examples Run all eval suites in the current directory: ```sh fh test ``` Run eval suites in a specific directory: ```sh fh test examples/hello-world ``` Run only a specific suite: ```sh fh test --suite hello-world ``` Output results as JSON: ```sh fh test --json ``` Override the pass threshold: ```sh fh test --threshold 0.9 ``` ## Exit codes | Code | Meaning | | --- | --- | | `0` | All suites passed. | | `1` | One or more suites failed, or an error occurred. | ## See also - [Eval library reference](/docs/reference/eval-library) - [CLI overview](/docs/cli) --- # fh update Canonical: https://harness.techfabric.com/docs/cli/update Safely update versioned managed recipes while preserving project changes. ```sh fh update [options] fh update [options] ``` `fh update` plans every managed-file and dependency change before it writes. Recipe markers identify the installed version. Compatible project dependency ranges remain unchanged; incompatible ranges and modified managed files are reported as conflicts. ## Review an update ```sh fh update channel slack --dry-run fh update slack --dry-run fh update channel slack --json ``` Human output is intended for terminal review. JSON output contains the recipe version, package manager, file actions, dependency actions, upgrade notes, and conflicts without embedding generated file contents. Both outputs include the package-manager-specific verification command. ## Apply an update ```sh fh update channel slack fh update database postgres --no-install ``` Fabric checks the entire plan first. It then installs missing compatible dependencies and applies managed file/environment changes as one file transaction. If a file write fails, previously written files are restored. An unmarked file can be adopted automatically only when it exactly matches the previous generated content. A marked file with user changes is never replaced automatically: ```txt Recipe channel:slack has conflicts: - .fabricharness/channels/slack.ts: user-modified managed file at version 1 ``` Review and merge the new recipe manually, or use `--force` when replacement is intentional. ## Options | Flag | Description | | --- | --- | | `--dir ` | Project containing the managed recipe. | | `--dry-run` | Print the complete plan without writing or installing. | | `--json` | Emit a machine-readable plan. | | `--no-install` | Update `package.json` without running the package manager. | | `--force` | Replace conflicting managed files after review. | ## Guarantees - Unknown or incompatible dependency ranges fail before recipe files change. - A recipe never silently downgrades a newer managed version. - Existing user files without a matching recipe marker are preserved. - Missing files from an installed recipe can be recreated. - Running an update twice is idempotent. See [Connector recipes](/docs/reference/recipes) for recipe ownership and authoring conventions. --- # Databricks AppKit interop Canonical: https://harness.techfabric.com/docs/databricks/appkit-interop Use AppKit as a complementary Databricks-native host while Fabric retains governed delivery, durable state, and evidence. Databricks AppKit and TechFabric Harness overlap at the agent-runtime layer. AppKit's beta Agents plugin provides TypeScript agents, threads, streaming, tool budgets, human approval, sub-agents, and hosted MCP. Fabric's value is not replacing those features. It is preserving the durable organizational contract around them: separation of duties, policy and artifact binding, promotion, recovery, cross-system lineage, certification, and retained evidence. The currently proven integration is additive: ```text AppKit beta agent -> MCP -> authenticated TechFabric Harness server -> governed tool ``` Use this shape when a Databricks-native AppKit experience should read from or request work through a Fabric-governed boundary. The existing self-contained Fabric `databricks-app` artifact remains the default when the application needs Fabric sessions, submissions, durable approvals, restart recovery, or a single certified runtime. ## Runnable proof The `examples/with-databricks-appkit-interop` example pins AppKit `0.53.0`. It starts a local Harness MCP server, creates an AppKit beta agent with that server as a hosted tool, invokes `/responses`, and checks the Fabric-side evidence. ```bash pnpm --filter @fabric-harness/example-with-databricks-appkit-interop test pnpm --filter @fabric-harness/example-with-databricks-appkit-interop build pnpm --filter @fabric-harness/example-with-databricks-appkit-interop start ``` Expected output includes: ```json { "responseStatus": "completed", "boundary": "AppKit agent -> MCP -> governed Harness tool", "fabricEvidence": { "actorId": "fabric-interop-user", "tenantId": "fabric-interop-tenant", "policyVersion": "fabric-policy-v1", "cancellable": true } } ``` The proof is local contract evidence. It is not a live workspace or release certification. ## Authentication and OBO The Fabric `/mcp` endpoint must authenticate every request and resolve the actor and tenant before tool dispatch. AppKit's MCP host policy only forwards workspace credentials to endpoints it classifies as same-workspace. Do not pass an OBO token to an arbitrary external MCP URL, and do not derive identity from model-controlled tool arguments. For a production same-workspace deployment: 1. register only the Fabric App MCP URL intended for the environment; 2. validate the bearer token at Fabric ingress; 3. bind the verified principal and tenant to `ToolContext`; 4. resolve approval and policy context server-side; and 5. retain both AppKit/Gateway and Fabric correlation evidence. ## Current safety boundary Keep the AppKit bridge read-only unless the remote mutation is independently approved and enforced by Fabric. In the pinned AppKit version, MCP discovery does not preserve remote effect annotations in the agent tool index, so AppKit's local approval gate cannot distinguish a read from a remote mutation. End-to-end MCP cancellation is also not yet certified. AppKit supplies an abort signal to the agent adapter and its lower-level MCP client accepts one, but the beta Agents dispatch path in `0.53.0` does not forward that signal into the MCP call. These are version-specific limitations. Fabric rechecks them before changing the tested pin. ## What remains authoritative | Concern | Authority | |---|---| | Workspace data and model permissions | Databricks identity, Unity Catalog, and AI Gateway | | AppKit thread and request behavior | The pinned AppKit beta host | | Tool admission, actor/tenant binding, policy, and durable mutation approval | TechFabric Harness MCP server | | Promotion, environment gates, artifact digest, and release evidence | TechFabric Runway and Fabric certification | | Durable Fabric session/restart contract | Existing self-contained `databricks-app` runtime and selected persistent store | ## Failure behavior - Harness rejects an MCP tool whose effect is missing. Write and execute tools also require an explicit governed marker after server-side wrapping. - AppKit host-policy or MCP discovery failures leave the tool unavailable; the example fails if discovery does not expose the expected tool. - Invalid Fabric authentication fails before tool dispatch. - Missing durable storage means AppKit's default in-memory threads are lost on restart. Configure and certify a persistent thread store before relying on App restart continuity. - A remote mutation through this beta bridge is unsupported until effect, approval, cancellation, and live evidence gates close. ## Packaging decision No AppKit-specific Fabric build target is published today. The spike did not change the default target and did not remove the self-contained Node server from Fabric artifacts. AppKit interop therefore adds a Databricks-native front end to Fabric governance; it does not yet reduce the number of runtimes operators must own. See [Databricks integrations](/docs/databricks/integrations), [self-contained application development](/docs/databricks/development), and [protected live certification](/docs/databricks/live-certification). --- # Authoring certification and release evidence Canonical: https://harness.techfabric.com/docs/databricks/authoring-certification The release gate, protected-workspace lifecycle checks, sweeper and retained evidence behind the Databricks stability claims. This page documents how Databricks [resource management](/docs/databricks/authoring) capabilities are tested, certified against a real workspace, and promoted to stable. It is aimed at release engineers and operators evaluating the stability claims; day-to-day authoring users do not need it. ## Test coverage gate The release gate runs `pnpm test:coverage:authoring`. It covers approval binding and replay, principal/input/call mismatches, grant expiry and persistence parsing, governance extraction and denial lineage, Jobs policy/wire contracts, Cloudflare and Temporal grant propagation, and the certification lifecycle runner. Genie contract tests additionally cover deterministic version-2 serialization, validation, every management/ACL wire path, ETag/fingerprint conflicts, durable ownership, managed-only deletion, conversation terminal failures, response bounds, cancellation, history, comments, and attachment-specific results. The current focused gate requires at least 85% lines/functions/statements and 80% branches; the implementation currently exceeds those thresholds. Package suites add every authoring client variant, bundle fail-closed checks, durable stores, CLI build/deploy, and documentation examples. The Databricks package additionally runs a native-SDK boundary suite. It executes generated clients over an instrumented HTTP transport to assert official request paths, JSON field serialization, credential headers, OBO headers, oneof handling, `bigint` identifiers, and SDK error mapping. A source allowlist quarantines preview-only endpoints, every `@databricks/sdk-*` dependency must share one exact reviewed version, and `test:sdk-runtime` imports the production bundle under Node 22. These contract checks run without workspace credentials; the lifecycle gate below proves actual service behavior. ## Protected workspace lifecycles Yes, protected CI can create real workspace resources and remove them. Enable the destructive gate only in an isolated certification workspace: ```bash export FABRIC_DATABRICKS_AUTHORING_TEST=1 export DATABRICKS_OBO_TOKEN=... export DATABRICKS_AUTHORING_AUTH_MODE=on-behalf-of export DATABRICKS_AUTHORING_EXECUTING_PRINCIPAL_KIND=user export DATABRICKS_AUTHORING_EXECUTING_PRINCIPAL_ID=... export DATABRICKS_AUTHORING_EXECUTING_UC_PRINCIPAL=user@example.com export DATABRICKS_AUTHORING_STEWARD_ID=data-platform-certifier export DATABRICKS_AUTHORING_JOB_SPEC='{"name":"jobs","tasks":[{"taskKey":"probe","notebook":{"notebookPath":"/Shared/probe"}}]}' export DATABRICKS_AUTHORING_COMPUTE_POLICY='{}' export DATABRICKS_AUTHORING_GENIE_SPEC='{"version":2,"title":"genie","parentPath":"/Shared","warehouseId":"warehouse-id","dataSources":[{"table":"main.cert.fixture"}]}' export DATABRICKS_AUTHORING_GENIE_QUESTION='How many rows are available?' export FABRIC_DATABRICKS_REQUIRED_CHECKS='identity,approval-provenance,jobs-authoring,lakeflow-authoring,ai-search-admin,serving-admin,uc-admin-obo-execution,workspace-write,secrets-write,genie-authoring' # Also configure the Lakeflow, AI Search, serving, UC, workspace, and secret fixtures below. node packages/databricks/dist/certify.js ``` The remaining fixture variables are `DATABRICKS_AUTHORING_LAKEFLOW_SPEC`, `DATABRICKS_AUTHORING_AI_SEARCH_SPEC`, `DATABRICKS_AUTHORING_SERVING_SPEC`, `DATABRICKS_AUTHORING_GENIE_SPEC`, `DATABRICKS_AUTHORING_UC_CATALOG`, `DATABRICKS_AUTHORING_UC_SCHEMA_PREFIX`, `DATABRICKS_AUTHORING_WORKSPACE_ROOT`, `DATABRICKS_AUTHORING_SECRET_SCOPE_PREFIX`, and the protected secret `DATABRICKS_AUTHORING_SECRET_VALUE`. Every generated name carries the reserved `fabric-harness-authoring-cert-` prefix (or its Unity Catalog-safe underscore form). The separate namespace prevents the authoring sweeper from touching long-lived baseline certification fixtures. Each check executes create, verify, mutate, verify, delete, and verify-delete through approval-bound governed tools. Failures trigger reverse-order cleanup; a scheduled sweeper removes crash leftovers and fails if deletion leaks. The Genie lifecycle uses the same approval-bound ToolDefs as production, asks a real Conversation API question, verifies that the created Agent's ACL is readable through the exact-pinned official Access Management SDK, accepts Databricks' successful soft-delete (`has been trashed`) as deletion evidence, clears durable Harness ownership when a retry finds that the managed Agent was already trashed, and fails if the Agent remains in the active inventory. Agent Mode uses the separate optional `DATABRICKS_GENIE_AGENT_MODE_ID` check and is not implied by management certification. To promote Agent Mode itself, also configure `DATABRICKS_GENIE_AGENT_MODE_QUESTION` and optionally `DATABRICKS_GENIE_AGENT_MODE_TIMEOUT_MS`, then dispatch with `require_agent_mode: true`. The workflow adds `genie-agent-mode` to the required checks and fails on missing configuration, malformed or unordered SSE, missing output, a missing terminal event, or a provider-side Beta denial. Classic compute has an independent promotion gate as well. Configure `DATABRICKS_AUTHORING_CLASSIC_JOB_SPEC` with a `newCluster` task bound to an allowed `policyId`, then dispatch with `certification_scope: classic-compute` in a protected classic-workspace environment. Certification requires only identity, approval provenance, the classic Job fixture, and its compute policy in that scope; it creates, reads, mutates, and deletes the Job definition through the governed tool path and does not start the cluster. The same `DATABRICKS_AUTHORING_COMPUTE_POLICY` allowlists its policy, runtime, node type, workers, and tags. Serverless workspaces cannot supply this evidence because all workloads there use serverless compute; retain the classic report separately with its own workspace, cloud, region, package digest, and cleanup ledger. `require_classic_compute: true` remains available for a full run in a classic workspace that also carries every other authoring fixture. Delta Sync and provisioned throughput also have independent, destructive gates. Configure `DATABRICKS_AUTHORING_DELTA_SYNC_SPEC` and dispatch with `require_delta_sync: true`, or configure `DATABRICKS_AUTHORING_PROVISIONED_THROUGHPUT_SPEC` and dispatch with `require_provisioned_throughput: true`. Each required check creates a uniquely named endpoint, verifies it, creates or updates the governed resource, deletes it, verifies deletion, and runs the post-certification sweeper. Provisioned throughput can incur material cost and must not be enabled without an approved workspace fixture and budget. Workflow inputs select execution as well as promotion. The protected job exposes Agent Mode, classic-compute, Delta Sync, and provisioned-throughput fixtures to the certification process only when their corresponding input is enabled. A stale environment variable therefore cannot silently run an incompatible or cost-bearing optional lifecycle. The `classic-compute` scope similarly masks all full-suite resource fixtures and sweep roots. `DATABRICKS_AUTHORING_AUTH_MODE` is deliberately separate from the base certification identity's `DATABRICKS_AUTH_MODE`: protected CI can keep its app-scoped OAuth M2M identity for deployment and crash cleanup while the authoring lifecycle proves execution with the short-lived OBO user token. When `run_authoring` is selected, the workflow appends all eight authoring checks to the required evidence set; a configured-but-optional lifecycle is not sufficient for capability promotion. ## Release evidence workflow For release evidence, dispatch **Databricks authoring certification** against the protected `databricks-live` GitHub Environment. This focused workflow requires the OBO identity and every fixture. Pass a successful same-commit **Live integration tests** run id, or let the scheduled workflow resolve it. Tier A downloads that run's exact package candidate instead of repacking, runs the candidate tarball's own compiled certifier through every destructive lifecycle, asserts that every required result passed with an empty cleanup ledger, sweeps before and after the run, and retains the Tier R evidence, Tier A evidence, shared tarball, and cross-tier manifest for 90 days. Its concurrency group does not cancel an in-flight run, so a newer dispatch cannot interrupt cleanup. Refresh the short-lived `DATABRICKS_OBO_TOKEN` immediately before dispatching it. Host/token identity validation runs before install or build; a failure at that preflight cannot create resources and therefore skips the post-run sweeper and artifact upload instead of emitting secondary missing-build failures. For a native-SDK major, old evidence is intentionally insufficient. The retained evidence must name the exact package candidate and artifact digest, include `sdkJs` in its API-version map, and be captured after the generated-client migration. Do not promote or publish the candidate from unit tests alone. Run the sweeper in dry-run mode first: ```bash node scripts/sweep-databricks-authoring-certification.mjs FABRIC_DATABRICKS_SWEEP_DELETE=1 \ node scripts/sweep-databricks-authoring-certification.mjs ``` Workspace-object cleanup fails before discovery when the explicit raw protocol client is unavailable; after validation, the same captured client is used for every listed deletion. Missing resources remain safe no-ops, while any real deletion failure leaves the gate red with the leaked resource ID. For a packed package, `packageArtifactSha256` is the standard SHA-256 digest of the `.tgz` bytes and must match `sha256sum` on the retained package. A directory target uses a deterministic tagged tree digest that binds each relative path and file length. Directory hashing rejects symbolic links and other non-file entries, preventing a certification target from escaping its tree or introducing a cycle. The workflow retains the package and report together so this relationship is machine-verifiable after download. `validate-databricks-cross-tier-evidence.mjs` fails when Tier R and Tier A differ by package version, source commit, tarball digest, required-check result, or freshness. This means a weekly authoring success cannot be combined with a separately packed consumption candidate to support a first-class claim. ## Latest authoring evidence boundary The current npm package is `7.1.1`, and it has byte-identical same-package Tier R and Tier A evidence from commit `bc56fa834a26e882953e4824796bd780a5b4efdb`. The focused authoring [run 33915517941](/docs/reference/source-access) downloaded the exact tarball retained by Tier R [run 33909857317](/docs/reference/source-access). Evidence `dbx-cert-abd5c9a21d0fe784a8ca44572a0d4955ee18494ce677d90fe9af1fe849abb722` records all ten required checks as passed in Azure `eastus2` under Databricks U2M/OBO: - approval provenance; - serverless Jobs, Lakeflow, direct-vector AI Search, and custom-model Serving lifecycles; - managed-only Unity Catalog administration with OBO execution; - Workspace object and secret-reference lifecycles; and - Genie Agent create, query, update, ACL-read, and trash. The retained package digest is `e6ed0ce22a6d8805e935a78e2310cba3bd7f82a357bc25fa679685ed7331b70e`. The workflow independently matched it to the packed tarball, verified every required result, required `cleanupRequired: false` after each destructive lifecycle, and completed empty pre/post sweeps. Cross-tier manifest `databricks-cross-tier-certification.json` binds it byte-for-byte to Tier R run `33909857317` and the same commit. This closes the same-candidate authoring proof for `7.1.1`. It does not claim classic compute in `westus3`, Delta Sync, provisioned throughput, or Genie Agent Mode authoring. ### Prior 4.10.0 authoring evidence Published package `4.10.0` retains an earlier complete same-package authoring record from [run 30058616867](/docs/reference/source-access). Evidence `dbx-cert-0574345bfe1bb7fe7b5cf59d862fcabd0c74ea290fde86e95ac453ac7251b79b` passed the same ten required checks with package digest `a688c1bd52ccbd7aad923d8c4212c6b305b080663877be289d5e51838d6a20cf` and an empty cleanup ledger. It remains historical evidence for that exact package. ## Prior 4.0.2 authoring evidence The exact `@fabric-harness/databricks@4.0.2` package passed two protected Azure gates from commit `0961a17b1349213c4c0193ef446639955d624de5`: - [GitHub Actions run 29660486290](/docs/reference/source-access) retained evidence `dbx-cert-b2c709717ef3a452234a5b2944311a576dafda03a9eea8246747ab3fa430b183`. All 11 required identity, approval, serverless Jobs, Lakeflow, direct-vector AI Search, Delta Sync, custom-model Serving, UC OBO, Workspace, secrets, and Genie checks passed in Azure `eastus2`. Genie verification included a governed query and ACL decoding through the official Access Management SDK. - [GitHub Actions run 29660486237](/docs/reference/source-access) retained evidence `dbx-cert-d5bdbd276533a8634910e223898337314446561be2a444030fc2d11baa237bec`. Identity, approval provenance, and the policy-bound classic `new_cluster` Jobs definition lifecycle passed in Azure `westus3` without starting the cluster. Both reports record SDK JS `0.21.0` and package digest `72f602626b9d79a808f6dd9e30f6ba703061bda19bae2aef983e7e92d7c61a45`, independently matched to `sha256sum` on the retained tarball. Every destructive lifecycle completed all six phases with `cleanupRequired: false`, and every pre/post sweep was empty. This evidence does not promote Provisioned Throughput or Agent Mode Beta: the former has no configured fixture, and the protected workspace still returns `FEATURE_DISABLED` for the latter. ## Prior 4.0.1 promotion evidence The exact `@fabric-harness/databricks@4.0.1` package passed two protected Azure gates from commit `dce71eaeac1edba47b4122cd5d81ccf0a1110f64`: - [GitHub Actions run 29657106492](/docs/reference/source-access) retained evidence `dbx-cert-7b2a371109ee02a47b4a5cf9403eb6aafbf2420ea6d3194de574cfc6a941a7f7`. All 11 required identity, approval, serverless Jobs, Lakeflow, direct-vector AI Search, Delta Sync, custom-model Serving, UC OBO, Workspace, secrets, and Genie checks passed in Azure `eastus2`. - [GitHub Actions run 29657107378](/docs/reference/source-access) retained evidence `dbx-cert-69817b237074b4fad5e86ee2aec7733899b0d08e525744ca0bf5cad173421017`. Identity, approval provenance, and the policy-bound classic `new_cluster` Jobs definition lifecycle passed in Azure `westus3` without starting the cluster. Both reports record SDK JS `0.21.0` and package digest `e805d79ae2b5f50e918eacb7eac2c7ca16b24da98e9a8d9d69e0653c43abd2a0`, independently matched to `sha256sum` on the retained tarball. Every destructive lifecycle completed all six phases with `cleanupRequired: false`; Genie executed a governed query; and every pre/post sweep was empty. ## Prior 4.0.0 promotion evidence The exact `@fabric-harness/databricks@4.0.0` package passed two protected Azure gates from commit `7614a3d81a69cacaf84b13c716457b5655d67abd`: - [GitHub Actions run 29640438183](/docs/reference/source-access) retained evidence `dbx-cert-d4d3095389c096994a89d56560b62af1b5e396c7831599ea1fd67d1ad1644f79`. All 11 required identity, approval, serverless Jobs, Lakeflow, direct-vector AI Search, Delta Sync, custom-model Serving, UC OBO, Workspace, secrets, and Genie checks passed in Azure `eastus2`. - [GitHub Actions run 29640438874](/docs/reference/source-access) retained evidence `dbx-cert-a85de02baf1b50717dbb070356006c2185a3bd7353b91eccda089a89a5984a82`. Identity, approval provenance, and the policy-bound classic `new_cluster` Jobs definition lifecycle passed in Azure `westus3` without starting the cluster. Both reports record SDK JS `0.21.0` and package digest `531f86f4c8d1cecf3df9f9d7544a6341a9379562abe9e135c742ee6f51fa969b`, independently matched to `sha256sum` on the retained tarball. Every destructive lifecycle completed all six phases with `cleanupRequired: false`; Genie executed a governed query; and every pre/post sweep was empty. ## Prior 3.0.3 promotion evidence The exact `@fabric-harness/databricks@3.0.3` package passed the protected Azure `eastus2` gate in [GitHub Actions run 29633534464](/docs/reference/source-access). Evidence `dbx-cert-793b88b91f44e5deb0eeff2e2ba168666bb2d03fd2883da256f25c269d3cb73c` records SDK JS `0.21.0` and package digest `9b87c9447d865b84a55a77232ed61eeb8d7f175155ab4db11fc874c59c287b84`. ## Prior 3.0.2 promotion evidence The exact `@fabric-harness/databricks@3.0.2` package passed the protected Azure `eastus2` gate in [GitHub Actions run 29632616112](/docs/reference/source-access). Evidence `dbx-cert-a7c0f49484d6f3d2409be4f6a6b196fc4a1ae83cdcf00ce89de0c8cf4fcab19c` records SDK JS `0.21.0` and package digest `f0330b2ef874995d60b1107b0dc7d02a0dbca24326d5ed867e357289b4e8b910`; the workflow independently matched it to `sha256sum` on the retained tarball. All 10 required checks passed. Every destructive lifecycle completed all six phases with `cleanupRequired: false`, Genie executed a governed query, and the post-run sweep found no retained resources. The pre-run sweep also proved crash recovery: it discovered and deleted the serving endpoint left when the preceding run's short-lived OBO token expired. The failed run therefore did not require manual workspace cleanup. ## Prior 3.0.1 promotion evidence The exact `@fabric-harness/databricks@3.0.1` package passed the protected Azure `eastus2` gate in [GitHub Actions run 29631548469](/docs/reference/source-access). Evidence `dbx-cert-8342f00839b3ed0bbe7ef93483207d0a5e4ea36c5a80d6c9854c1681bccfb930` records SDK JS `0.21.0` and package digest `e16c6524586742f985a840f5e5a10b82f0ac6125e8f61a75e212d22eace47260`. The workflow independently matched that value to `sha256sum` on the retained `.tgz`. All 10 required identity, approval, and lifecycle checks passed. Jobs, Lakeflow, AI Search, custom-model Serving, managed Unity Catalog schema/grants with OBO execution, Workspace objects, secret references, and Genie completed create, verify, mutate, verify-mutation, delete, and verify-delete. Genie also executed a governed query. Every lifecycle cleanup ledger was empty, and both independent sweeps discovered zero retained resources. The evidence promotes only the recorded Azure region and tested variants. It does not promote classic compute, delta-sync, provisioned throughput, Agent Mode streaming, or another cloud/region. ## Historical promotion evidence The records below certify earlier implementations. They remain useful behavioral evidence, but the current native-SDK promotion claim comes only from the exact 4.4.1 package evidence above. The eight protected management capability families are stable for their documented scope after the exact `2.0.0` package candidate from commit `c3d0c9091db39cca6bee5736922d70891aefcfdc` passed all ten required checks with no cleanup leaks in GitHub Actions run `29622641051`. Evidence `dbx-cert-db47ec980bd8e7bdd9687896c68530d121f5dcac0421cf7c1f85d07a49ff52ef` records the package artifact digest `35f492e0ff28cee9a4eee9e719a2d90fe9bd312209e7cd2d128f046dfbe8e087`; both the pre-run and post-run destructive sweeps found no retained certification resources. The retained workflow artifact expires after 90 days. The broader protected release run `29622641870` then passed all 33 required checks from the same commit and package version. Its retained evidence `dbx-cert-0f987b096a5015fb17387564c10ffe1b4356e3256610e17350af57d4593ec1ed` records those 33 required passes plus the separately configured optional OBO check (34 total), zero failures, and successful cleanup for every destructive lifecycle. The two unconfigured optional checks were Agent Services and Genie Agent Mode; neither is included in this production claim. The run also passed Databricks App recovery, load, and black-box lifecycle conformance. The temporary release-branch allowance was removed from the protected environment after evidence upload. That evidence used serverless Jobs, a direct-vector index, and custom-model serving on the protected Azure `eastus2` workspace with OBO execution; it does not imply classic compute, delta-sync, provisioned throughput, Agent Mode, or another cloud/region passed the same live gate. Provisioned Throughput, AI Gateway administration, Agent Mode streaming, and Databricks App OBO authentication retain their separate Databricks preview constraints. Contract tests alone never promote a capability or claim another cloud/region. Capability metadata separates `contractClouds` (typed API targets) from `clouds` (clouds represented by linked retained live evidence). Do not use contract portability as proof that an unlisted cloud/region passed certification. --- # Enterprise Databricks adoption guide Canonical: https://harness.techfabric.com/docs/databricks/enterprise-adoption Choose a Databricks agent workload, align platform and security ownership, prove it in a workspace, and move from pilot to a governed production service. TechFabric Harness helps a Databricks customer turn governed data and AI services into durable agent applications. It is most useful when an application spans several Databricks services, a model may choose actions, identity must follow the user or service, or operations need approval and audit evidence. Databricks remains the system of authority for workspace identity, Unity Catalog permissions, compute, data, model endpoints, retrieval, orchestration, and storage. Fabric owns the application control loop around those services: sessions, tools, policy, approvals, recovery, interoperability, deployment artifacts, lineage, and cost correlation. ## Choose one lighthouse workload Start with one workload whose value and risk can both be measured. Avoid beginning with a generic assistant that can call every workspace capability. | Workload | Good first scope | Databricks services | Fabric control points | Exit evidence | | --- | --- | --- | --- | --- | | Analytics copilot | One governed domain and a curated question set | Genie, SQL Warehouse, Unity Catalog | OBO or M2M identity, `sql_read`, steward approval, durable thread | Answer quality, generated SQL, allowed/denied grants, per-question cost | | Knowledge assistant | One indexed corpus with named owners | AI Search, AI Gateway, MLflow | Bounded context, citations, refusal, session state, evaluation export | Retrieval relevance, groundedness, citation validity, restart recovery | | Data operations agent | One Job or Lakeflow pipeline and one approval audience | Jobs, Lakeflow, notebooks | Exact-input approval, idempotency, durable receipt, terminal status | Approved input, run id, output, retry behavior, cleanup record | | Employee Databricks App | One authenticated user population | Apps, Lakebase, UC Volumes | OBO isolation, durable sessions, attachments, deletion | Two-user isolation, App restart, offset recovery, cascade deletion | | Agent API | One existing application or channel client | Apps or external runtime, ResponsesAgent, Agent Services | Authenticated Responses API, tenant policy, trace correlation | Contract conformance, caller identity, MLflow trace, discovery/grants | The [workload map](/docs/databricks/workloads) lists the supported API, managed-recipe, and native escape-hatch paths. The [why Fabric page](/docs/databricks/why-fabric) explains when the official Databricks SDK alone is the better choice. ## Reference architecture ```mermaid flowchart LR USER[Employee, application, or event] --> EDGE[Databricks App or authenticated API] EDGE --> ID[App principal, OAuth M2M, or OBO user] ID --> RUNTIME[Fabric agent runtime] subgraph Controls[Fabric application controls] RUNTIME --> POLICY[Tools, policy, approvals] RUNTIME --> STATE[Durable session and submission state] RUNTIME --> OBS[Lineage, traces, cost correlation] end POLICY --> GATEWAY[Unity AI Gateway] POLICY --> SQL[SQL Warehouse and Unity Catalog] POLICY --> SEARCH[AI Search and Genie] POLICY --> WORK[Jobs and Lakeflow] STATE --> LAKEBASE[Lakebase] STATE --> VOLUMES[UC Volumes] OBS --> MLFLOW[MLflow and system tables] classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef control fill:#fef3c7,stroke:#d97706,color:#422006 classDef dbx fill:#dcfce7,stroke:#16a34a,color:#052e16 class RUNTIME fabric class POLICY,STATE,OBS control class GATEWAY,SQL,SEARCH,WORK,LAKEBASE,VOLUMES,MLFLOW dbx ``` This architecture does not require exposing a generic REST client to the model. Stable platform operations use exact-pinned official Databricks SDK clients. Model-facing tools are a smaller, policy-visible surface with read, write, execute, or external effects. ## Select the acting identity Identity is an architecture decision, not a deployment detail. | Identity | Choose it when | Main consequence | | --- | --- | --- | | Databricks App principal | The App acts as one service | Every user receives the App's Databricks grants; apply tenant controls in Fabric | | OAuth M2M service principal | CI, backend service, or external runtime acts as one application | Use a dedicated principal per environment and least-privilege workspace/resource grants | | On-behalf-of user | Each signed-in user's UC grants must be authoritative | Build a request-scoped bundle; verify forwarded identity and keep sessions tenant-isolated | | PAT | Local development or a controlled smoke test | Do not use as the default production identity | Do not accept a user id from a request body and call it OBO. The runtime must derive the principal from Databricks-authenticated ingress or a verified token. Tokens remain in credential providers and request headers; prompts, tool arguments, lineage, and cost labels contain non-secret identity labels only. See [local naming and authentication](/docs/databricks/local-naming-auth) and [enterprise controls](/docs/databricks/enterprise). ## Establish the workspace landing zone Before application development, the platform team should provide: 1. A development workspace and disposable certification namespace. 2. A dedicated OAuth service principal, App principal, or OBO test users for each selected mode. 3. A SQL Warehouse and explicit UC catalog, schema, table, volume, and function grants. 4. An enabled `system.ai.*` AI Gateway service or approved custom Model Serving endpoint. 5. AI Search, Genie, Feature Serving, Jobs, or Lakeflow fixtures only for workloads that use them. 6. A Lakebase endpoint, database role, schema owner, migrations, and App DML grants when state must survive restart. 7. UC Volumes for governed attachments when the application accepts files. 8. System-table access and a cost attribution key when actual-cost reconciliation is required. 9. Private connectivity, DNS, CA, and outbound policy appropriate to the workspace network design. 10. Separate steward audiences for approvals and operators for deployment/runtime administration. Feature availability varies by cloud, region, account, and workspace enablement. Read the [compatibility matrix](/docs/databricks/compatibility) before treating an API contract as live evidence for a specific customer environment. ## Roll out in evidence-producing phases ### Phase 0 — contract and threat model - Name the business owner, data owner, platform owner, approval audience, and incident owner. - List the exact tools the model can select and classify every effect. - Define data boundaries, retention, deletion, RTO/RPO, cost limits, and required evaluation scores. - Decide what remains deterministic application code through `bundle.sdk` and what becomes a model tool through `bundle.tools`. Exit when architecture and security reviewers can identify the acting principal, every reachable Databricks resource, every mutation, and the recovery path. ### Phase 1 — local and contract proof - Start with `fh init --template databricks` or add the narrow managed recipes. - Run deterministic mocks for tool assembly, policy, input/output validation, and HTTP routes. - Prove unsafe SQL, unapproved writes, missing credentials, and unsupported configuration fail before a platform mutation. - Package the exact candidate versions and inspect the build manifest and SBOM. Local tests prove application behavior. They do not prove workspace permissions, preview availability, network reachability, or restart durability. ### Phase 2 — protected workspace proof - Run the Tier R consumption certifier with the same package version intended for deployment. - Exercise allowed and denied UC paths, AI Gateway, the selected data/AI services, volumes, Lakebase, lineage, system tables, actual-cost reconciliation, and the App. - Run Tier A separately in a disposable namespace when agents can author resources. - Retain secret-redacted evidence, exact package version, commit, artifact digest, cloud, region, auth mode, and cleanup results. Required checks must pass. A skipped Tier R capability is a failed release proof, not a green run. Tier O previews may remain unconfigured or fail without blocking Tier R unless the deployment explicitly promotes them. ### Phase 3 — pilot - Limit users, catalogs, tools, concurrency, and daily spend. - Compare answers and actions with a golden set and human review. - Measure latency, completion, refusal, approval, retry, and cost behavior. - Restart and redeploy the App; verify session, submission, stream, and attachment recovery. - Test tenant deletion, token expiry, endpoint unavailability, UC denial, and delayed system-table accounting. Before admitting a user to a shared App, combine the retained target-workspace artifacts into one fail-closed pilot report. This gate requires the exact package and App bytes, all Tier R checks, restart recovery, hook-authored dynamic-agent recovery, two distinct user identities, and one complete OBO expiry/refresh lifecycle: ```sh pnpm databricks:pilot:verify -- \ --evidence artifacts/databricks-certification.json \ --package artifacts/release-packages/fabric-harness-databricks.tgz \ --app artifacts/certified-databricks-app/databricks-app \ --recovery artifacts/databricks-app-recovery.json \ --dynamic artifacts/databricks-dynamic-agent.json \ --isolation artifacts/databricks-app-user-isolation.json \ --obo-lifecycle artifacts/databricks-obo-lifecycle.json \ --pilot-id finance-support-pilot \ --enabled-checks databricks-app,dynamic-agent,sql,genie \ --expected-version "$DATABRICKS_PACKAGE_VERSION" \ --expected-commit "$DATABRICKS_CERTIFIED_COMMIT" \ --expected-workspace-id "$DATABRICKS_WORKSPACE_ID" \ --expected-cloud azure \ --expected-region eastus2 \ --output artifacts/databricks-controlled-pilot.json ``` Name the pilot for its function, list only the Tier R checks it will enable, and replace the workspace, cloud, and region values with the target workspace values. A preview or optional check cannot enter this report merely because it exists; it needs its own retained evidence. A passing command prints `Databricks controlled-pilot evidence passed` and writes a secret-free report with status `controlled-pilot-ready`. It deliberately sets `productionCertified: false`: the report authorizes only the named pilot and does not establish the separate 14-day claim. Missing, stale, digest-mismatched, cross-region, single-user, or incomplete OBO-refresh evidence fails without writing a readiness report. Generate `databricks-obo-lifecycle.json` with the prepare/verify sequence in [Local naming and authentication](/docs/databricks/local-naming-auth). Download the other artifacts from the protected target-workspace certification run. The verifier reads them locally and performs no cloud mutations. After the pilot proof, remove the downloaded bearer-free artifacts according to the customer's evidence-retention policy; resource cleanup remains the responsibility of the certification and deployment runbooks. ### Phase 4 — production - Promote an immutable artifact already linked to passing environment evidence. - Apply Lakebase migrations with a stable schema owner before App rollout. - Monitor App health, model/SQL usage, approval queues, failed observers, and cost drift. - Re-certify on package, SDK, cloud/region, auth, App resource, or material workspace-policy changes. - Keep preview capabilities separately labeled and independently promotable. ## Operating ownership | Team | Owns | | --- | --- | | Application team | Agent definition, tools, prompts, typed results, evaluations, user experience | | Databricks platform team | Workspace features, Apps, endpoints, Warehouses, Lakebase, networking, deployment identity | | Data governance | Unity Catalog grants, catalog boundaries, data owners, steward approvals, retention | | Security/IAM | OAuth/OBO design, token verification, secret handling, egress, incident access | | SRE/operations | SLOs, deployment, backup/recovery, monitoring, capacity, runbooks | | FinOps | Budgets, attribution keys, system-table access, drift thresholds, chargeback/showback | Fabric supplies correlated evidence, but it does not transfer ownership away from these teams. ## Production decision checklist - [ ] The workload uses a documented first-party path or an explicitly owned native escape hatch. - [ ] The acting principal and tenant derive from verified authentication. - [ ] UC and resource grants are least privilege and include a tested denial case. - [ ] The model receives only bounded tools; deterministic admin code stays out of the tool set. - [ ] Every write/execute path has explicit policy and, where required, exact-input approval. - [ ] Secrets never enter prompts, tool inputs, logs, evidence, or persisted user messages. - [ ] Lakebase migrations, App grants, backup, restore, restart, and deletion are proven. - [ ] AI Search/Genie answers, SQL, citations, and MLflow evaluation outputs are inspectable. - [ ] Estimated budgets act immediately and actual costs reconcile from system tables. - [ ] Package, commit, artifact digest, cloud, region, auth mode, and evidence all match. - [ ] Preview and workspace-dependent capabilities are labeled and have an owner. - [ ] Failure, rollback, and incident runbooks have been exercised. ## Build the first proof For an analytics copilot, begin with the credential-free [`with-analytics-copilot`](/docs/reference/source-access) example, then connect one Warehouse and one Genie Agent. For a stateful application, start with the [Databricks quickstart](/docs/databricks/quickstart), add Lakebase, and follow the [Databricks App deployment guide](/docs/deployment/databricks-app). For RAG, use the [Databricks RAG guide](/docs/databricks/rag) and treat MLflow evaluation plus restart recovery as part of the release proof. Continue with [development](/docs/databricks/development), [enterprise controls](/docs/databricks/enterprise), and [live certification](/docs/databricks/live-certification). --- # Fabric Desktop for Databricks projects Canonical: https://harness.techfabric.com/docs/databricks/fabric-desktop Create, run, inspect, and deploy TechFabric Harness Databricks projects from Fabric Desktop, CLI, or server mode. Fabric Desktop provides a guided interface over the same TechFabric Harness project files and `fh` CLI used by terminal and CI workflows. A project binding stores non-secret workspace defaults, while credentials remain in Desktop's source credential manager and Databricks authorization remains the authority for every workspace operation. ```mermaid flowchart LR RECIPE[Choose a recipe] --> AUTH[Select an OAuth source] AUTH --> DISCOVER[Discover required resources] DISCOVER --> PROJECT[Create a bound project] PROJECT --> RUN[Mock or confirmed live run] PROJECT --> BROWSE[Browse workspace resources] PROJECT --> BUILD[Build and preview] BUILD --> CONFIRM{Confirm host and target} CONFIRM --> DEPLOY[Deploy Databricks App] DEPLOY --> OPEN[Open App URL] classDef local fill:#f4f4f5,stroke:#71717a,color:#18181b classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef dbx fill:#dcfce7,stroke:#16a34a,color:#052e16 class RECIPE,AUTH,DISCOVER local class PROJECT,RUN,BUILD,CONFIRM fabric class BROWSE,DEPLOY,OPEN dbx ``` ## Enable the project workflow During release certification, start Desktop with the project workflow enabled: ```sh FABRIC_FEATURE_DATABRICKS_PROJECTS=1 bun run electron:dev ``` The feature flag is a Desktop release control. It does not change Harness CLI behavior or weaken the authentication requirements of a generated App. ## Create a bound project 1. Create a project and choose a Databricks recipe. 2. Select one workspace identity. For local development, choose `databricks-oauth` and **Databricks CLI OAuth**. Desktop reads profiles with `databricks auth profiles --output json`, derives the workspace URL from the selected profile, and refreshes tokens every 30 minutes. 3. Use the inline **Configure** control when the identity is not yet verified. Desktop calls the workspace identity API before displaying **Verified**. OAuth-app U2M, service-principal M2M, and an explicit PAT source remain available for environments that require them. 4. Choose **Discover workspace resources** and select the resources requested by the recipe. 5. Create the project. Desktop scaffolds the recipe and writes the selected non-secret identifiers into `.env.example` and the project binding. | Recipe | Resources selected during setup | | --- | --- | | Governed Analytics Copilot | SQL Warehouse, catalog, schema, optional Genie Agent | | Lakebase Stateful RAG Agent | catalog, schema, Model Serving endpoint, AI Search index | | Data Engineering Agent | SQL Warehouse, catalog, schema, Lakeflow pipeline, Databricks Job | Optional APIs are discovered independently. For example, missing permission to list Apps does not prevent a SQL-only project from selecting its Warehouse. When a required API cannot be listed, the wizard accepts the stable resource identifier directly. SQL Warehouse, Unity Catalog, and AI Search tools reuse this verified workspace identity. They do not ask for or store duplicate tokens. Changing the identity updates the linked capability sources to the same normalized workspace origin. The project binding resembles the following. It contains no access token, client secret, or App API token: ```json { "host": "https://adb-1234567890123456.7.azuredatabricks.net", "authSourceId": "databricks-oauth", "catalog": "main", "schema": "analytics", "warehouseId": "0123456789abcdef", "profile": "DEFAULT", "resources": { "servingEndpoint": "databricks-gpt-oss-120b", "vectorIndex": "main.analytics.product_docs" } } ``` Every project session receives this binding as structured context. Installed Databricks skills are attached according to the binding: SQL and Unity Catalog, Genie, AI Search RAG, Lakeflow, Declarative Automation Bundle authoring, and cost optimization. A required source is enabled only when that source exists, is authenticated, and is usable. ## Browse the workspace Open the project's **Workspace** view to inspect: - Unity Catalog catalogs, schemas, and tables; - SQL Warehouses and Model Serving endpoints; - Databricks Apps and Jobs; - Genie Agents and AI Search indexes; - Lakeflow pipelines. Catalog nodes load schemas and tables lazily. Selecting a table inserts its fully qualified `catalog.schema.table` name into the latest session for that project. Other resources insert their stable name or identifier. Resource groups load independently so a permission failure is isolated to the affected group. ## Run, build, and deploy Open **Deploy** on the project: 1. **Mock run** exercises the selected job without workspace side effects. 2. **Live run** shows a confirmation containing the workspace host and bundle target. The approval authorizes that operation only. 3. **Build** creates the Harness deployment artifact. 4. **Preview** validates the deployment plan without deploying the App. 5. **Deploy** requires target-and-host confirmation and streams redacted output. 6. **Cancel** terminates the active Harness subprocess. 7. **Open app** uses the URL captured in deployment history. Desktop serializes operations per project, parses `databricks.yml` structurally, temporarily selects the requested Declarative Automation Bundle target, and restores the source file even when the command fails or is cancelled. Deployment history is stored with the project. The bridge validates the installed `fh` version and capability contract before invoking it. The terminal remains intentionally fail-closed. A non-interactive live run still requires the CI or operator to set the live gate explicitly: ```sh export FABRIC_DATABRICKS_TEST=1 fh run analyst --payload '{"question":"Summarize main.analytics.orders"}' ``` An interactive Desktop confirmation does not set this global environment variable and does not change subsequent terminal commands. ## AI Gateway attribution and guardrails Project settings accept cost attribution tags: ```text team=analytics, cost_center=finance, environment=prod ``` They also accept an AI Gateway guardrail JSON object: ```json { "input": { "pii": true, "safety": true }, "output": { "safety": true, "toxicity": true } } ``` For a Databricks Mosaic AI session, Desktop passes these values only to that project's isolated model subprocess. The provider adds `X-Cost-Attribution-Tags` and `X-Guardrail-Config` to AI Gateway requests. The project context indicator shows when attribution and guardrails are active. ## Desktop, CLI, and server mode ```mermaid flowchart TB UI[Fabric Desktop UI] --> RPC[Typed project RPC] WEB[Desktop server mode] --> RPC RPC --> BRIDGE[Databricks bridge] CLI[Terminal or CI] --> FH[fh CLI] BRIDGE --> FH FH --> FILES[Same project and databricks.yml] FH --> DBX[Databricks APIs and Apps] classDef client fill:#f4f4f5,stroke:#71717a,color:#18181b classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef dbx fill:#dcfce7,stroke:#16a34a,color:#052e16 class UI,WEB,CLI client class RPC,BRIDGE,FH,FILES fabric class DBX dbx ``` Recipe lookup uses the shared bundled-assets resolver, so the same gallery and scaffolding work in the Electron application and headless Desktop server. The generated Databricks developer resource bundle contains the versioned skill pack and can be imported into another Desktop workspace without copying credentials. For the authentication boundaries and naming rules, continue with [Local naming and authentication](/docs/databricks/local-naming-auth). For the release protocol, see the [CLI compatibility contract](/docs/cli/compatibility). --- # Genie Agent Mode learning path Canonical: https://harness.techfabric.com/docs/databricks/genie-agent-mode Create, grant, invoke, govern, test, and clean up a Databricks Genie Agent used through the Beta Agent Mode API. Harness supports the complete application-side journey around Genie Agent Mode, but two native Databricks concepts must stay distinct: - A **Genie Agent** is the Databricks resource. Harness can create, inspect, query, update, permission, export/import, and trash that resource through `DatabricksGenieAdmin`. - **Agent Mode** is a Beta response-streaming API for an existing Genie Agent. Harness does not create a second “Agent Mode agent” resource. The ordinary Genie Conversation API and the Agent Mode SSE API are separate clients. Harness never silently substitutes one for the other. ## Choose the path | Situation | Use | | --- | --- | | A Genie Agent already exists | Configure `genie.agentMode.agentId`, acknowledge Beta, and invoke it. | | Harness should manage the resource | Configure `genie.manage`, create through `genieAdmin`, grant the runtime principal, then bind the returned `agentId` to Agent Mode. | | A Harness model should delegate analytics to Genie | Set `modelTool`, register `dbx.tools`, and retain normal Harness policy and budgets around the call. | | The workload runs as a Databricks App | Declare `databricks.app.genie`; the build emits a native `genie_space` resource and injects the ID through `valueFrom`. | ## Prerequisites You need: - `@fabric-harness/databricks@^7.0.2`, `@fabric-harness/sdk@^6.2.0`, and Node.js 22 or newer; - a Databricks workspace enrolled by the account team for the Agent Mode preview; - **Genie Agents Agent Mode API** enabled under workspace Previews; - a pro or serverless SQL Warehouse; - `SELECT` on every Unity Catalog table used by the Genie Agent; - an authoring principal with workspace-folder and Genie management permission when Harness manages the resource; and - a runtime principal with `CAN_RUN` on the Genie Agent plus access to its warehouse and data. Use separate authoring and runtime principals in production. The same service principal is acceptable only for a controlled development proof where that broader authority is intentional. ## Path 1: invoke an existing Genie Agent ```ts title=".fabricharness/jobs/revenue-review.ts" import { type DatabricksGenieAgentModeResponse, databricks, } from '@fabric-harness/databricks'; import { defineAgent, schema } from '@fabric-harness/sdk'; const host = process.env.DATABRICKS_HOST!; const revenueIntelligence = databricks({ host, principal: { kind: 'service-principal', host, clientId: process.env.DATABRICKS_RUNNER_CLIENT_ID!, clientSecret: process.env.DATABRICKS_RUNNER_CLIENT_SECRET!, }, genie: { agentMode: { agentId: process.env.DATABRICKS_REVENUE_GENIE_AGENT_ID!, acknowledgeBeta: true, timeoutMs: 5 * 60_000, idleTimeoutMs: 2 * 60_000, onEvent: (event) => console.log(event.sequenceNumber, event.type), }, }, }); export default defineAgent({ name: 'revenue-review', input: schema.object({ question: schema.string(), conversationId: schema.string().optional(), }), output: schema.string(), run: async ({ input }) => { const revenueReview = await revenueIntelligence.genieAgentMode!.complete(input.question, { ...(input.conversationId ? { conversationId: input.conversationId } : {}), }); return JSON.stringify(revenueReview satisfies DatabricksGenieAgentModeResponse); }, }); ``` Run it: ```sh export DATABRICKS_HOST=https:// export DATABRICKS_RUNNER_CLIENT_ID=... export DATABRICKS_RUNNER_CLIENT_SECRET=... export DATABRICKS_REVENUE_GENIE_AGENT_ID=0123456789abcdef0123456789abcdef fh run revenue-review \ --payload '{"question":"Summarize revenue by region."}' ``` Expected output includes increasing SSE sequence numbers, a `response.completed` event, and one bounded terminal response containing a `conversationId`. Pass that ID on the next invocation to continue the same native conversation. Agent Mode allows one in-flight response per conversation. ### What developers see The application can present the native conversation while preserving the verified caller, ordered SSE sequence, generated SQL step, result evidence, terminal event, and bounded timeout. This representative view is sanitized and does not embed a workspace or user identifier. ## Path 2: manage, grant, invoke, and clean up The runnable `with-databricks-genie-authoring` workspace contains this lifecycle. The important handoff is `salesAnalyst.agentId`: the exact resource returned by management is the resource Agent Mode invokes. ```ts import { LakebaseDatabricksManagedResourceStore, databricks, databricksSdk, lakebaseClient, } from '@fabric-harness/databricks'; const host = process.env.DATABRICKS_HOST!; const authorClientId = process.env.DATABRICKS_AUTHOR_CLIENT_ID!; const genieAuthoringPrincipal = { kind: 'service-principal' as const, host, clientId: authorClientId, clientSecret: process.env.DATABRICKS_AUTHOR_CLIENT_SECRET!, }; const genieRunnerPrincipal = { kind: 'service-principal' as const, host, clientId: process.env.DATABRICKS_RUNNER_CLIENT_ID!, clientSecret: process.env.DATABRICKS_RUNNER_CLIENT_SECRET!, }; const genieAuthoringSdk = databricksSdk({ host, principal: genieAuthoringPrincipal }); const genieOwnershipStore = new LakebaseDatabricksManagedResourceStore({ client: lakebaseClient({ host: process.env.DATABRICKS_LAKEBASE_HOST!, database: process.env.DATABRICKS_LAKEBASE_DATABASE!, user: process.env.DATABRICKS_LAKEBASE_USER!, endpoint: process.env.DATABRICKS_LAKEBASE_ENDPOINT!, credentialClient: genieAuthoringSdk.postgres, }), }); const genieManagement = databricks({ host, principal: genieAuthoringPrincipal, genie: { manage: { resourceStore: genieOwnershipStore, delete: 'managed-only', }, }, }); const salesAnalyst = await genieManagement.genieAdmin!.create( { version: 2, title: 'Revenue intelligence analyst', parentPath: '/Shared/agents', warehouseId: process.env.DATABRICKS_WAREHOUSE_ID!, dataSources: [{ table: 'main.sales.orders' }], instructions: ['Answer revenue questions using governed data sources.'], }, { ownership: { principal: process.env.DATABRICKS_AUTHOR_CLIENT_ID!, toolCallId: 'revenue-intelligence-bootstrap', }, }, ); try { await genieManagement.genieAdmin!.updatePermissions(salesAnalyst.agentId, [ { servicePrincipalName: process.env.DATABRICKS_RUNNER_CLIENT_ID!, permissionLevel: 'CAN_RUN', }, ]); const revenueIntelligence = databricks({ host, principal: genieRunnerPrincipal, genie: { agentMode: { agentId: salesAnalyst.agentId, acknowledgeBeta: true, timeoutMs: 5 * 60_000, idleTimeoutMs: 2 * 60_000, }, }, }); const revenueReview = await revenueIntelligence.genieAgentMode!.complete( 'Summarize revenue by region.', ); console.log(revenueReview.output); } finally { await genieManagement.genieAdmin!.delete(salesAnalyst.agentId); } ``` Production resource management should use a durable `DatabricksManagedResourceStore`; the provided Lakebase implementation survives process replacement. Model-facing management additionally requires a steward audience, catalog allowlist, exact-operation approval, and a server-side `sqlPolicy` before SQL-bearing configuration becomes available. ## Path 3: expose Agent Mode as a governed model tool `modelTool` constructs `databricks_genie_agent_mode`, but the Harness definition must register `revenueIntelligence.tools`: ```ts title=".fabricharness/jobs/revenue-briefing.ts" import { databricks } from '@fabric-harness/databricks'; import { defineAgent, schema } from '@fabric-harness/sdk'; const host = process.env.DATABRICKS_HOST!; const genieRunnerPrincipal = { kind: 'service-principal' as const, host, clientId: process.env.DATABRICKS_RUNNER_CLIENT_ID!, clientSecret: process.env.DATABRICKS_RUNNER_CLIENT_SECRET!, }; const revenueIntelligence = databricks({ host, principal: genieRunnerPrincipal, model: 'system.ai.gpt-oss-20b', genie: { agentMode: { agentId: process.env.DATABRICKS_REVENUE_GENIE_AGENT_ID!, acknowledgeBeta: true, modelTool: { maxOutputBytes: 512 * 1024 }, }, }, }); export default defineAgent({ name: 'revenue-briefing', input: schema.object({ question: schema.string() }), output: schema.string(), init: { modelProvider: revenueIntelligence.modelProvider, tools: revenueIntelligence.tools, policy: revenueIntelligence.policy, }, run: ({ input, prompt }) => prompt(`Use the governed Genie tool to answer this revenue question: ${input.question}`), }); ``` Progress events go only to the server-side `onEvent` callback. The model receives one bounded terminal response, not the entire SSE stream. ## Bind the resource to a Databricks App ```ts title=".fabricharness/config.ts" export default { target: 'databricks-app', databricks: { app: { genie: { agentId: process.env.DATABRICKS_REVENUE_GENIE_AGENT_ID, permission: 'CAN_RUN', }, }, }, }; ``` The build writes a native `genie_space` resource and injects `DATABRICKS_GENIE_AGENT_ID` through `valueFrom`; the ID is not embedded in the model prompt. `CAN_EDIT` and `CAN_MANAGE` require the App binding to opt into authoring. ## Failure behavior | Failure | Harness behavior | Next action | | --- | --- | --- | | `404 FEATURE_DISABLED` | Fails explicitly; ordinary Genie is not substituted. | Ask the account team to enroll the workspace and enable the preview. | | `403` | Surfaces native permission denial without exposing credentials. | Grant the runtime principal and verify warehouse/data access. | | `409` | Reports the one-in-flight-response conflict. | Wait for or cancel the active response; do not retry concurrently. | | Idle or overall deadline | Aborts the request and raises `DatabricksGenieAgentModeTimeoutError`. | Inspect progress evidence and choose a bounded workload-specific deadline. | | Caller cancellation | Propagates the abort signal to the response stream. | Record the cancelled terminal state; do not convert it to a retry. | | Malformed or out-of-order SSE | Raises `DatabricksGenieAgentModeProtocolError`. | Retain redacted evidence and check the Beta API rollout/version. | | `response.failed` | Yields the terminal event, then raises `DatabricksGenieAgentModeResponseError`. | Inspect the bounded native error and correct the question, data, or agent configuration. | | Stream ends without a terminal event | Fails the protocol contract. | Treat the outcome as unknown; do not claim completion. | Response-creating POSTs are never automatically retried because an ambiguous response could duplicate work. Event size, event count, model-tool output, idle time, and total time are bounded. ## Cleanup - A managed test lifecycle must trash the exact Genie Agent in a `finally` block. - Harness waits until exact-ID reads show the resource is no longer active before removing its durable ownership record. - Repeating deletion after the resource moved to trash is an idempotent no-op. - Do not delete a pre-existing production Genie Agent merely because one Agent Mode conversation finished; retain or delete it according to its owner and lifecycle policy. ## Test and certification boundary Run the local protocol and composition tests without workspace credentials: ```sh pnpm --filter @fabric-harness/databricks test -- genie-agent-mode pnpm --filter @fabric-harness/example-with-databricks-genie-authoring test pnpm --filter @fabric-harness/example-with-databricks-genie-authoring build ``` The current `7.1.1` protected record establishes stable Genie Agent create/query/update/trash authoring and separately records a passing optional Tier O Agent Mode streaming probe in Azure `eastus2`. It does not promote the Beta API to stable, establish Agent Mode authoring as a separate resource lifecycle, prove the 14-day rolling claim, or certify AWS/GCP workspaces. Read the exact [certification record](/docs/databricks/live-certification) before making a customer claim. --- # Local naming and authentication Canonical: https://harness.techfabric.com/docs/databricks/local-naming-auth Understand Fabric job, agent, App, tenant, and Databricks principal names while developing locally. Local development involves two independent authentication boundaries and several intentionally separate names. Keeping them separate prevents a local API token from being mistaken for a Databricks credential, or a model endpoint name from becoming an agent route. ## The complete local request ```mermaid flowchart LR subgraph Caller[Local caller] CLI[fh run] HTTP[HTTP client] end subgraph Fabric[Local Fabric runtime] INGRESS[Fabric ingress authentication] PRINCIPAL[Fabric principal and tenant] ROUTE[Job or agent route] SESSION[Session and policy] end subgraph DatabricksAuth[Databricks authentication] PAT[Developer PAT] M2M[OAuth M2M service principal] OBO[On-behalf-of user] end subgraph Databricks[Databricks workspace] MODEL[AI Gateway or Model Serving] DATA[SQL, Unity Catalog, AI Search] STATE[Lakebase and Volumes] end CLI -->|trusted local process| ROUTE HTTP -->|Bearer token or local default| INGRESS INGRESS --> PRINCIPAL PRINCIPAL --> ROUTE ROUTE --> SESSION SESSION --> PAT SESSION --> M2M SESSION --> OBO PAT --> MODEL PAT --> DATA M2M --> MODEL M2M --> DATA M2M --> STATE OBO --> DATA classDef local fill:#f4f4f5,stroke:#71717a,color:#18181b classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef identity fill:#fef3c7,stroke:#d97706,color:#422006 classDef dbx fill:#dcfce7,stroke:#16a34a,color:#052e16 class CLI,HTTP local class INGRESS,PRINCIPAL,ROUTE,SESSION fabric class PAT,M2M,OBO identity class MODEL,DATA,STATE dbx ``` The Fabric principal answers **who may invoke this local runtime and tenant**. The Databricks principal answers **who performs the model, data, and state operation in the workspace**. They can be the same organizational identity, but they use different credentials and are configured independently. ## Naming model ```mermaid flowchart TB PROJECT[Project metadata.name] --> BUNDLE[Declarative Automation Bundle name] PREFIX[run.idPrefix] --> APP[Databricks App resource name] JOBFILE[.fabricharness/jobs/report.ts] --> JOBNAME[Declared job name or report] AGENTFILE[.fabricharness/agents/support.ts] --> AGENTNAME[Persistent route support] AGENTNAME --> INSTANCE[Caller instance customer-42] INSTANCE --> NAMEDSESSION[Named session default] MODELENV[DATABRICKS_MODEL] --> MODELSERVICE[AI Gateway model service] classDef source fill:#f4f4f5,stroke:#71717a,color:#18181b classDef fabric fill:#dbeafe,stroke:#2563eb,color:#172554 classDef dbx fill:#dcfce7,stroke:#16a34a,color:#052e16 class PROJECT,PREFIX,JOBFILE,AGENTFILE,MODELENV source class BUNDLE,APP,JOBNAME,AGENTNAME,INSTANCE,NAMEDSESSION fabric class MODELSERVICE dbx ``` | Name | Source | Example | Used for | | --- | --- | --- | --- | | Bundle name | `metadata.name` | `analytics-agents` | Databricks Declarative Automation Bundle identity | | App name | `run.idPrefix` | `analytics-app` | Databricks App resource | | Job name | Definition `name`, then relative file path | `daily-report` | CLI and `/jobs/:name` | | Persistent agent name | Relative path under `agents/` | `support` | `/agents/:name/:instanceId` | | Instance ID | Supplied by the caller | `customer-42` | Addressable persistent agent instance | | Session name | Supplied by the caller; default `default` | `incident-104` | Conversation within an instance | | Databricks model | `DATABRICKS_MODEL` or definition model | `databricks-gpt-oss-20b` | AI Gateway or serving endpoint selection | Configure the project and App names in `.fabricharness/config.ts`: ```ts title=".fabricharness/config.ts" export default { metadata: { name: 'analytics-agents' }, run: { idPrefix: 'analytics-app', target: 'node', }, }; ``` `metadata.name` and `run.idPrefix` are sanitized for Databricks resource naming. They do not rename jobs, persistent agents, Unity Catalog objects, or model endpoints. ### Finite job names For finite jobs, a declared name is authoritative: ```ts title=".fabricharness/jobs/report.ts" import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'daily-report', input: schema.object({ accountId: schema.string() }), output: schema.string(), model: 'databricks/system.ai.gpt-oss-20b', triggers: { manual: true, webhook: true }, run: async ({ init, input }) => { const session = await (await init()).session(); return session.prompt(`Summarize account ${input.accountId}.`); }, }); ``` ```sh fh run daily-report --account-id account-42 ``` ```http POST /jobs/daily-report ``` If `name` is omitted, `jobs/report.ts` becomes `report`. Nested paths remain namespaced: `jobs/operations/daily.ts` becomes `operations/daily`. ### Persistent agent names Persistent routes derive from the relative path under `.fabricharness/agents/`: ```ts title=".fabricharness/agents/support.ts" import { createAgent } from '@fabric-harness/sdk'; export default createAgent(({ id }) => ({ model: 'databricks/system.ai.gpt-oss-20b', instructions: `Support account ${id} using governed workspace data.`, triggers: { webhook: true }, })); ``` The route below addresses agent `support`, instance `customer-42`, session `incident-104`: ```sh curl -X POST \ 'http://localhost:3000/agents/support/customer-42?wait=false' \ -H 'content-type: application/json' \ -d '{"message":"Investigate the failed pipeline.","session":"incident-104"}' ``` Fabric persists that identity as the tuple `(support, customer-42, incident-104)`. The instance and session names are application identifiers, not Databricks users or Unity Catalog principals. ## Fabric authentication while local Direct CLI execution does not cross an HTTP authentication boundary: ```sh fh run daily-report --account-id account-42 --mock ``` `fh dev` permits requests without a token in local mode and records them as the synthetic `local-development` service principal. This is intended only for loopback development. To exercise the authenticated HTTP path locally, set an API token before starting the server: ```sh export FABRIC_HARNESS_API_TOKEN="$(openssl rand -hex 32)" fh dev ``` ```sh curl -X POST http://localhost:3000/jobs/daily-report \ -H "authorization: Bearer $FABRIC_HARNESS_API_TOKEN" \ -H 'content-type: application/json' \ -d '{"accountId":"account-42"}' ``` When `FABRIC_ENV=production` or `NODE_ENV=production`, the server fails closed. With no API token or custom `authenticate` hook, protected requests receive `401`. Query-string tokens exist for limited transport compatibility; use the `Authorization` header for normal clients so tokens do not enter URLs or access logs. For OIDC, role, permission, and tenant-aware ingress, use a structured server authenticator. See [Authentication and RBAC](/docs/operating/auth) for JWT validation and Databricks Apps presets. ### Tenant selection A structured Fabric principal can be bound to one tenant or an allowlist: ```ts { id: 'analyst-123', kind: 'user', tenantIds: ['customer-42', 'customer-84'], permissions: ['agent:invoke', 'session:read'], roles: ['analyst'], } ``` The caller selects an allowed tenant with `X-Fabric-Tenant`: ```sh curl -X POST http://localhost:3000/jobs/daily-report \ -H "authorization: Bearer $FABRIC_HARNESS_API_TOKEN" \ -H 'x-fabric-tenant: customer-42' \ -H 'content-type: application/json' \ -d '{"accountId":"account-42"}' ``` A single-tenant principal binds implicitly. A multi-tenant allowlist requires an explicit selection, and selecting a tenant outside the allowlist returns `403`. ## Databricks authentication while local Fabric runtime credentials come from environment variables or an explicit `DatabricksPrincipal`. For local development, the recommended path uses the same Databricks CLI OAuth profile for runtime tokens and deployment. Production Databricks Apps continue to use their app service principal and optional on-behalf-of user token. ### Databricks CLI OAuth for local development Authenticate once with the Databricks CLI: ```sh databricks auth login \ --host https://adb-1234567890123456.7.azuredatabricks.net \ --profile fabric-harness ``` Then select that profile for Harness runtime token resolution: ```dotenv title=".env.local" DATABRICKS_HOST=https://adb-1234567890123456.7.azuredatabricks.net DATABRICKS_CONFIG_PROFILE=fabric-harness DATABRICKS_AUTH_MODE=cli DATABRICKS_MODEL=databricks-gpt-oss-20b ``` For identity/token resolution (`databricksIdentity`, `databricksPrincipalFromEnv`), `DATABRICKS_CONFIG_PROFILE` alone is sufficient — the workspace host is resolved from the named profile in `~/.databrickscfg`. The full recipe runtime and bundle config shown above still take an explicit workspace host (`DATABRICKS_HOST` / `host`), which application code can obtain from the profile via `await databricksHostFromCliProfile(profile)`. Profile-only `fh deploy --target databricks-serving` requires an installed `@fabric-harness/databricks` version that exports `databricksHostFromCliProfile`. Older installations remain supported when `DATABRICKS_HOST` is set explicitly; the CLI fails before building or registering a model when the helper is unavailable. Token acquisition goes through the official Databricks SDK credential chain: it resolves the named profile, and PAT profiles use the stored token directly. OAuth (CLI) profiles shell out to the Go Databricks CLI (>= 0.100.0) via `databricks auth token --profile ` on every request — no `--host` argument, so the CLI's own OAuth cache and refresh apply, not Harness's. Harness attempts no fallback login; run `databricks auth login` first if the CLI reports the profile isn't authenticated. A pasted AI Gateway URL is normalized to the workspace origin before management or authentication URLs are constructed. In headless environments (CI containers, SSH sessions without a desktop keyring) the Databricks CLI cannot reach its secure token cache and token minting fails. Point the CLI at its plaintext cache instead: ```dotenv DATABRICKS_AUTH_STORAGE=plaintext ``` Explicit wiring is also available: ```ts import { databricksIdentity } from '@fabric-harness/databricks'; const token = databricksIdentity({ kind: 'cli-profile', profile: 'fabric-harness', }); ``` `host` is optional; when set, it takes precedence as the workspace origin for API calls, but CLI token acquisition always follows the named profile — `host` and the profile must point at the same workspace. ### PAT for one developer Use a personal access token for a controlled, single-user development session: ```dotenv title=".env.local" DATABRICKS_HOST=https://adb-1234567890123456.7.azuredatabricks.net DATABRICKS_TOKEN=dapi... DATABRICKS_WAREHOUSE_ID=0123456789abcdef DATABRICKS_MODEL=databricks-gpt-oss-20b DATABRICKS_INFERENCE_MODE=auto ``` The process acts with the PAT owner's Databricks permissions. Do not use a developer PAT as an App or shared production identity. PAT lookup is explicit; `DATABRICKS_BEARER` is also accepted for headless compatibility with pre-fetched Databricks tokens. ### OAuth M2M for production-like development Use a service principal to reproduce CI and App-style authorization locally: ```dotenv title=".env.local" DATABRICKS_HOST=https://adb-1234567890123456.7.azuredatabricks.net DATABRICKS_CLIENT_ID=00000000-0000-0000-0000-000000000000 DATABRICKS_CLIENT_SECRET=resolve-from-your-secret-manager DATABRICKS_WAREHOUSE_ID=0123456789abcdef DATABRICKS_MODEL=databricks-gpt-oss-20b DATABRICKS_INFERENCE_MODE=auto ``` Fabric exchanges the client credentials at the workspace OIDC endpoint, caches the access token, refreshes before expiry, and deduplicates concurrent refreshes. If `DATABRICKS_TOKEN` and OAuth credentials are both present, the PAT wins; unset `DATABRICKS_TOKEN` when validating M2M behavior. Run a live request after loading the environment: ```sh fh run databricks-analyst \ --question 'Describe main.sales.orders' ``` ### Explicit principal wiring Use an explicit principal when one process needs more than one Databricks identity: ```ts import { databricks } from '@fabric-harness/databricks'; const dbx = databricks({ host: process.env.DATABRICKS_HOST!, principal: { kind: 'service-principal', host: process.env.DATABRICKS_HOST!, clientId: process.env.DATABRICKS_CLIENT_ID!, clientSecret: process.env.DATABRICKS_CLIENT_SECRET!, }, model: 'databricks-gpt-oss-20b', warehouseId: process.env.DATABRICKS_WAREHOUSE_ID, governance: { catalogs: ['main'] }, }); ``` The token resolver is awaited for each Databricks operation. Raw credentials are not added to model messages, tool inputs, lineage labels, or logs. ### OBO for a signed-in user On-behalf-of authentication preserves a user's Unity Catalog grants: ```ts const principal = { kind: 'on-behalf-of' as const, userToken: async () => currentUserAccessToken(), label: 'signed-in-analyst', }; ``` Fabric does not manufacture or persist an OBO token. Databricks Apps performs user consent and token refresh, then forwards the current user access token on each request. Generated App artifacts validate it against the workspace current-user API, cache validation only by token digest, and map the verified user to a stable, opaque Fabric tenant with least-privilege permissions. For a protected diagnostic route, `inspectDatabricksAppUserAuthorization()` validates the forwarded token against the workspace current-user API and returns only identity plus issued/expiry metadata. It never returns the token or copies workspace error bodies. The reference App exposes this at `GET /certification/obo` for lifecycle certification. ```mermaid sequenceDiagram autonumber actor Analyst participant Ingress as Fabric ingress participant Runtime as Fabric runtime participant Provider as Databricks token provider participant UC as Unity Catalog Analyst->>Ingress: Request with signed user identity Ingress->>Ingress: Validate issuer, audience, expiry, signature Ingress->>Runtime: Fabric user principal and tenant Runtime->>Provider: Resolve short-lived user token Provider-->>Runtime: OBO access token Runtime->>UC: Query as signed-in analyst UC-->>Runtime: User-specific result or denial Runtime-->>Analyst: Audited response ``` One interactive CLI authorization can certify both initial login and refresh. The prepare phase uses the selected U2M profile and stores only non-secret lifetime metadata. After the first one-hour token expires, verify asks the CLI for a refreshed token, calls the App again, and requires the same user, a newer issue time, and a later expiry: ```sh databricks auth login --host "$DATABRICKS_HOST" --profile fabric-harness DATABRICKS_APP_URL="$DATABRICKS_APP_URL" \ DATABRICKS_PROFILE=fabric-harness \ node scripts/certify-databricks-obo-lifecycle.mjs prepare # Run after the expiry printed by prepare. DATABRICKS_APP_URL="$DATABRICKS_APP_URL" \ DATABRICKS_PROFILE=fabric-harness \ node scripts/certify-databricks-obo-lifecycle.mjs verify ``` Use `certify` instead of the two phases when one process can remain active across the token-expiry window. Before sharing the App, run `scripts/certify-databricks-app-user-isolation.mjs` with two distinct U2M profiles as described in [authoring certification](/docs/databricks/authoring-certification). ## Runtime credentials versus deployment profiles `DATABRICKS_TOKEN` or the OAuth environment variables authenticate calls made by the running agent. A Databricks CLI profile authenticates build deployment commands: ```sh databricks auth login --host "$DATABRICKS_HOST" --profile analytics-dev fh build --target databricks-app fh deploy --target databricks-app --profile analytics-dev ``` Passing `--profile` does not change the identity used later by the deployed App. Databricks Apps supplies its service-principal identity at runtime; configure App resource permissions and secret references separately. ## Local verification checklist 1. Run `fh agents` and confirm the job and persistent-agent route names. 2. Run with `--mock` before adding workspace credentials. 3. Set only one Databricks credential mode at a time. 4. Use OAuth M2M to reproduce unattended CI permissions. 5. Set `FABRIC_HARNESS_API_TOKEN` to test authenticated local HTTP calls. 6. Test one allowed and one denied Unity Catalog object. 7. Verify the selected Fabric tenant appears in audit, lineage, and cost attribution. 8. Use `fh deploy --preview --target databricks-app --profile analytics-dev` before deploying. Continue with the [Databricks quickstart](/docs/databricks/quickstart) to scaffold an App or [Enterprise Databricks controls](/docs/databricks/enterprise) to configure OIDC, policy, durability, lineage, and cost enforcement. --- # Native access and platform coverage Canonical: https://harness.techfabric.com/docs/databricks/native-access Use generated Databricks clients, native-complete adapters, or the credential-safe workspace API without losing Harness governance. TechFabric Harness is a native-superset integration. Developers do not need to wait for a Harness-specific wrapper before using a Databricks feature. ## Three API levels | Level | Use it for | Surface | | --- | --- | --- | | Native generated clients | Full request and response types for supported modular SDK services | `databricksSdk()` or `databricks(...).sdk` | | Native-complete Fabric adapters | Databricks behavior plus cancellation, identity, policy, lineage, citations, or durable runtime integration | `databricksAiSearch()`, `databricksRagChain()`, governed tools | | Workspace REST escape hatch | A new or uncommon Databricks API not yet present in the generated TypeScript SDK | `databricksWorkspaceApi()` | The third level is application-facing but is never projected into model context automatically. A mutating endpoint becomes a model tool only after the application adds input validation, capability policy, approval behavior, and ownership semantics. ## Generated SDK clients ```ts import { databricksSdk, databricksPrincipalFromEnv } from '@fabric-harness/databricks'; const sdk = databricksSdk({ host: process.env.DATABRICKS_HOST!, principal: databricksPrincipalFromEnv(process.env), }); const jobs = await sdk.jobs.list({}); const indexes = await sdk.vectorSearch.listVectorIndexes({ endpointName: 'one-env-shared-endpoint-0', }); ``` These are the official modular `@databricks/sdk-*` clients. Fabric supplies one rotating identity and does not narrow their native method or result types. ## Workspace API escape hatch ```ts import { databricksPrincipalFromEnv, databricksWorkspaceApi, } from '@fabric-harness/databricks'; const workspace = databricksWorkspaceApi({ host: process.env.DATABRICKS_HOST!, principal: databricksPrincipalFromEnv(process.env), }); const dashboards = await workspace.request<{ dashboards?: Array<{ dashboard_id?: string; display_name?: string }>; }>('GET', '/api/2.0/lakeview/dashboards', { query: { page_size: 25 }, }); ``` The client: - accepts workspace-relative `/api/*` and `/serving-endpoints/*` paths only; - rejects origin escapes, normalized relative segments, and encoded path separators; - resolves the configured PAT, OAuth M2M, CLI, App, or OBO identity per attempt; - keeps authorization headers out of the public object and prevents callers from replacing them; - propagates cancellation and redacts credentials from errors; - retries transient reads, but never retries a mutation unless it is explicitly classified as idempotent and carries a stable idempotency key. ```ts await workspace.request('POST', '/api/2.1/jobs/run-now', { body: { job_id: 123 }, retry: 'idempotent', idempotencyKey: `submission:${submissionId}:job:123`, }); ``` Prefer a generated client when one exists. The escape hatch preserves native HTTP fidelity, but it does not supply domain schemas, cleanup ownership, policy, or a governed `ToolDef`. Use `requestRaw()` plus `bodyEncoding: 'raw'` for binary upload/download APIs. ## Inspect coverage without guessing `DATABRICKS_CAPABILITIES` reports independent dimensions rather than treating “supported” as one boolean: ```ts import { DATABRICKS_PLATFORM_DOMAINS, getDatabricksCapability, listDatabricksCapabilities, } from '@fabric-harness/databricks'; const search = getDatabricksCapability('ai-search'); console.log(search?.coverage); // upstreamMaturity, apiFidelity, lifecycle, runtimeCertification, // identities, contractClouds, certifiedClouds, knownGaps const nativeComplete = listDatabricksCapabilities({ apiFidelity: 'native-complete', }); ``` `DATABRICKS_PLATFORM_DOMAINS` deliberately includes product families with no current first-party surface. Delta Sharing, Clean Rooms, Marketplace, dashboard authoring, training, and other gaps therefore remain visible instead of disappearing from the compatibility story. Use `databricksWorkspaceApi()` for an unwrapped native API while a first-party adapter is being added. ## Migration from the earlier AI Search API The old `queryType: 'text' | 'vector'` option mixed two independent concepts. Use `inputMode` for the query representation and `strategy` for the Databricks retrieval algorithm: ```ts // Earlier aiSearch: { queryType: 'vector', embeddingEndpoint: 'bge-large-en' } // Current aiSearch: { inputMode: 'vector', strategy: 'ann', embeddingEndpoint: 'bge-large-en', } ``` Text input defaults to `strategy: 'hybrid'`. Set `ann`, `hybrid`, or `full-text` explicitly when the retrieval contract is part of an evaluation or release gate. --- # TechFabric Platform governance Canonical: https://harness.techfabric.com/docs/databricks/platform-governance Compose canonical Databricks execution with TechFabric Platform's durable mutation ledger. `@fabric-harness/databricks` is the Fabric family's production Databricks integration. Vertical applications import it; they do not implement workspace authentication, generic service clients, Lakebase credential exchange, or retry and polling behavior locally. TechFabric Platform owns the business mutation, policy decision, HITL approval, and durable audit ledger. Harness owns Databricks execution and returns technical evidence to the Platform invocation. ```ts import { createDatabricksMutationGovernanceResolver } from "@fabric-harness/databricks/platform"; const resolveMutationGovernance = createDatabricksMutationGovernanceResolver({ workspaceHost: process.env.DATABRICKS_HOST!, principal, resolveResources: ({ parameters }) => [{ resourceType: "unity-catalog-table", resourceId: String((parameters as { table: string }).table), operation: "update", dataClassifications: ["customer-data"], }], }); ``` The resolver produces a provider-neutral `MutationFootprint` and an `ExecutionPrincipal` containing the Databricks identity and its initiating actor. Tokens and client secrets are never represented. Use `databricksExecutionAttestation()` after SQL, Jobs, Lakeflow, Serving, MLflow, deployment, or other external work. Its statement ID, run ID, request ID, trace ID, deployment ID, or digest becomes an external evidence reference and can satisfy a named Platform policy obligation. There is only one business approval queue. Harness capability enforcement is defense in depth and must not create an unrelated approval record for a Platform mutation. ## Governance descriptors on `config.tools` `databricks({ tools: [...] })` accepts your own `ToolDef`s. Any entry whose `metadata.effect` is `'write'` or `'execute'` **must** declare `metadata.governance.resources`, naming the resources the call touches. A tool that omits it fails at bundle construction: ```text databricks governance: authoring tool "databricks_run_job" must declare metadata.governance.resources. ``` This is what lets approval, capability enforcement, and the lineage record identify the target without guessing from the input shape. The run-job tool is the worked example: ```ts metadata: { effect: 'execute', provider: 'databricks', service: 'jobs', governance: { resources: [{ kind: 'job', path: '/jobId' }] }, }, ``` Each descriptor is: | Field | Meaning | | --- | --- | | `kind` | Required non-empty label for the resource class, such as `'job'`, `'notebook'`, `'catalog'`, or `'table'`. | | `path` | JSON Pointer into the tool's schema-declared input, such as `'/jobId'`. Must be absolute; the pointer is walked against `inputSchema` at construction, so a typo fails immediately. Resolves to strings or numbers. | | `value` | A static resource identifier instead of a pointer. Exactly one of `path` or `value` is allowed. | | `catalogQualified` | Marks a dotted value as catalog-qualified so the leading segment is recorded as the catalog. | | `optional` | Allows the pointer to match no value; without it, an unmatched required pointer throws. | A descriptor `path` needs a corresponding `inputSchema` property. Pinning that property with `const` or `enum` — as the bounded run-job tool does — does not affect pointer validation. --- # Deployment Overview Canonical: https://harness.techfabric.com/docs/deployment The build targets TechFabric Harness emits and where each one is meant to run, so you can pick before you write any config. `fh build` produces a deployable artifact for a chosen target. The same agent code runs on every target — only the build output and runtime differ. ## Targets at a glance | Target | What it produces | Deployment requirement | Best for | | --- | --- | --- | --- | | [Node](/docs/deployment/node) | `dist/server.mjs` HTTP server | Configure auth, durable stores, limits, and monitoring. | Local services, internal automation, container wrapping. | | [Docker](/docs/deployment/docker) | `Dockerfile` + Node bundle | Configure registry, secrets, network policy, and persistent stores. | CI smoke tests, ECS / Kubernetes, generic container hosts. | | [AWS](/docs/deployment/aws) | Docker artifact for ECS/App Runner/EKS | Provision the AWS container control plane around the artifact. | AWS container platforms with external durable state. | | [Fly.io](/docs/deployment/fly) | Docker artifact | Configure the application, secrets, port, health checks, and volume/database. | Regional container applications. | | [Railway](/docs/deployment/railway) | Docker artifact | Configure service variables, port, health checks, and durable database. | Managed container deployment. | | [SST](/docs/deployment/sst) | Node/Docker artifact | Provision a long-running AWS container service. | AWS infrastructure defined from TypeScript. | | [Temporal worker](/docs/deployment/temporal-worker) | Worker entrypoint + activities | Provide a Temporal namespace, task queue, identity, and worker operations. | Durable, replayable, approval-gated agent sessions. | | [Cloudflare Workers + Sandbox](/docs/deployment/cloudflare) | Worker + DO + Sandbox container binding | Configure Worker, Durable Object, R2, and optional Sandbox bindings. | Edge-triggered webhooks, per-tenant Durable Object sessions. | | [Foundry Hosted Agents](/docs/deployment/foundry-hosted-agent) | `Dockerfile` + `azure.yaml` + Bicep; Agent Service client/tools | Configure Azure identity, role assignments, project, networking, and region. | Azure-native agents with per-session isolation, Entra Agent ID, OBO auth. | | [Azure Container Apps / ACI / AKS](/docs/deployment/azure) | ARM control-plane tools; Docker deploy path | Configure subscription identity, registry, network, and compute resources. | Azure customers without Foundry availability or with K8s mandates. | | [Databricks](/docs/deployment/databricks) | Databricks App/Serving artifacts, governed tools, OAuth, and Lakebase stores | Configure workspace identity, UC grants, App resources, and certification. | Data, analytics, ML, and governance agents. | | [E2B](/docs/deployment/e2b) | Control-plane helpers for E2B sandbox runtime | Provide provider credentials and validate lifecycle and cleanup. | Ephemeral sandbox execution for untrusted code. | | [Daytona](/docs/deployment/daytona) | Control-plane helpers for Daytona workspace runtime | Provide provider credentials and validate workspace lifecycle. | Reproducible dev environments as agent sandboxes. | | [Modal](/docs/deployment/modal) | Native TypeScript SDK sandbox adapter | Configure Modal credentials, image, resources, network policy, and cleanup. | Serverless GPU/CPU tasks from agent sessions. | | [Azure Container Instances (ACI)](/docs/deployment/aci) | ARM control-plane helpers for ACI | Configure ACR, managed identity, resource group, and networking. | Lightweight container instances for single-shot agents. | ### What remains portable The source definition stays the same while the build manifest records the selected runtime, capabilities, policy, package versions, digest, and provenance for the target-specific artifact. ## How to choose ```mermaid graph TD Start[Where will the agent run?] --> Local{Local / on-prem?} Local -->|Yes| Node Local -->|No| Cloud{Cloud preference?} Cloud -->|Edge / per-tenant| Cloudflare Cloud -->|Azure-native| Azure{Foundry available?} Azure -->|Yes| Foundry[Foundry Hosted Agent] Azure -->|No| ACA[Azure Container Apps] Cloud -->|Data / ML| Databricks[Databricks tools] Cloud -->|Other| Docker[Docker / K8s] Cloud -->|Serverless GPU/CPU| Modal[Modal] Cloud -->|Ephemeral sandbox| E2B[E2B] Cloud -->|Reproducible dev env| Daytona[Daytona] Cloud -->|Lightweight containers| ACI[Azure Container Instances] Node --> Durable{Need durability?} Durable -->|Yes| Temporal[+ Temporal worker] Durable -->|No| NodeOnly[Node server] ``` ## Build invocation ```sh fh build --target node fh build --target docker --docker-build --docker-tag myorg/agents:latest fh build --target temporal-worker fh build --target cloudflare fh build --target foundry-hosted-agent fh build --target databricks-app fh build --target databricks-serving ``` Each target writes to `.fabricharness/build//` and emits a `manifest.json` next to the artifact. See [Build manifest](/docs/reference/build-manifest). For the v2 artifact layout, route examples, and production environment controls, follow [Build and run artifacts](/docs/deployment/build-artifacts). For an end-to-end workspace deployment, use the [Databricks App tutorial](/docs/deployment/databricks-app). ## CI/CD recipes - [GitHub Actions](/docs/deployment/github-actions) — build, sign, deploy on push. - [GitLab CI](/docs/deployment/gitlab-ci) — equivalent pipeline. ## Hardening checklist Before promoting any target to production, walk through [Security hardening](/docs/reference/security-hardening): provenance, attestation, secret handling, network egress, approval gating, and rate limits. --- # Azure Container Instances (ACI) Canonical: https://harness.techfabric.com/docs/deployment/aci Build and deploy TechFabric Harness containers to Azure Container Instances with managed identity. The Azure Container Instances (ACI) target builds the image in Azure Container Registry and creates a public ACI container group using managed identity for image pull. ## Generated artifact - `AciBuildPlugin` integrates ACI with the build pipeline. - `aciReadme()` generates resource and deployment instructions. - `AciDriver` exposes the ACI deploy orchestration contract. ## Build invocation ```sh fh build --target aci ``` This emits `ACI_DEPLOY.md` with the exact image, resource, and deployment steps for the artifact. ## Deploy The ACI target is registered in the build system and deploy registry. Use it like any other target: ```sh export AZURE_ACR_NAME=fabricregistry export AZURE_RESOURCE_GROUP=agents-rg export AZURE_CONTAINER_NAME=support-agent export AZURE_LOCATION=westus3 fh deploy --target aci ``` Optional variables: | Variable | Default | | --- | --- | | `AZURE_ACR_REPOSITORY` | `fabric-harness` | | `AZURE_IMAGE_TAG` | `latest` | | `AZURE_ACI_IDENTITY` | `[system]` | | `AZURE_ACI_CPU` | `1` | | `AZURE_ACI_MEMORY_GB` | `1.5` | | `AZURE_ACI_DNS_NAME_LABEL` | unset | | `PORT` | `3000` | Grant the selected managed identity `AcrPull` on the registry. `fh deploy --preview --target aci` prints the commands without changing Azure resources. Runtime secrets remain external to the build; configure them through your deployment environment or secret delivery path. ## See also - [Deployment overview](/docs/deployment) - [Azure Container Apps / ACI / AKS](/docs/deployment/azure) - [Azure Container Instances documentation](https://learn.microsoft.com/azure/container-instances/) --- # AWS Canonical: https://harness.techfabric.com/docs/deployment/aws Deploy a Fabric Docker artifact to ECS, App Runner or EKS, and what each of the three costs you in operational surface. Build and push the Docker target: ```sh fh build --target docker --docker-build --docker-tag "$ECR_REPOSITORY:$GIT_SHA" ``` Run the image on ECS/Fargate, App Runner, or EKS with port `3000`, `NODE_ENV=production`, a nonempty `FABRIC_HARNESS_API_TOKEN`, model credentials, and an external Postgres session store. Configure health checks at `/health` and readiness at `/ready`. Use task roles/IRSA instead of static AWS credentials, Secrets Manager or Parameter Store for secrets, private networking and egress controls, immutable image digests, least-privilege IAM, centralized logs/traces, and separate task definitions per environment. Verify restart recovery, approval state, rate limits, and artifact access before production. --- # Azure Canonical: https://harness.techfabric.com/docs/deployment/azure Azure OpenAI, Key Vault, Blob artifacts, Container Apps Jobs, ACI, AKS, and Foundry Agent Service helpers. TechFabric Harness keeps Azure-specific integration code in `@fabric-harness/azure` so the core SDK stays provider-neutral. The package includes model, storage, secret, Foundry Agent Service, and Azure ARM control-plane helpers. Use `aksSandbox` for a full pod-backed `SandboxEnv`; use the ACA and ACI helpers for build and control-plane workflows. ## Install ```sh npm install @fabric-harness/azure @fabric-harness/sdk ``` ## Azure OpenAI Use Azure OpenAI as a model provider: ```ts import { AzureOpenAIModelProvider } from '@fabric-harness/azure'; const provider = new AzureOpenAIModelProvider({ endpoint: process.env.AZURE_OPENAI_ENDPOINT!, apiKey: process.env.AZURE_OPENAI_API_KEY!, deployment: process.env.AZURE_OPENAI_DEPLOYMENT!, }); const fabric = await init({ modelProvider: provider }); ``` The provider sends chat-completions requests to: ```txt /openai/deployments/{deployment}/chat/completions ``` ## Blob artifact store ```ts import { createAzureBlobArtifactStore } from '@fabric-harness/azure'; const blobs = createAzureBlobArtifactStore({ accountUrl: 'https://acct.blob.core.windows.net', container: 'fabric-artifacts', token: async () => getAzureAccessToken(), }); await blobs.put('reports/triage.md', markdown, 'text/markdown'); ``` Use this when Fabric session artifacts need to land in Azure Storage. The helper is intentionally narrow; session-store integration and retention policy are controlled by your app. ## Key Vault secret resolver ```ts import { azureKeyVaultSecretProvider } from '@fabric-harness/azure'; import { defineCommand, secret, secretResolver } from '@fabric-harness/sdk'; const keyVault = azureKeyVaultSecretProvider({ vaultUrl: process.env.AZURE_KEY_VAULT_URL!, token: async () => getAzureAccessToken(), }); const gh = defineCommand('gh', { env: { GH_TOKEN: secret('github-token') }, }); const fabric = await init({ resolveSecret: secretResolver(keyVault) }); ``` Secrets stay in Key Vault and are resolved only at command execution time. ## Azure ARM client ```ts import { createAzureArmClient } from '@fabric-harness/azure'; const arm = createAzureArmClient({ subscriptionId: process.env.AZURE_SUBSCRIPTION_ID!, token: async () => getAzureAccessToken(), }); ``` The ARM client is used by the control-plane tools below. ## Container Apps Jobs ```ts import { azureContainerAppsJobTool } from '@fabric-harness/azure'; const tools = [azureContainerAppsJobTool(arm)]; ``` The tool starts an existing Azure Container Apps Job. It is useful when a Fabric agent should trigger a prebuilt containerized workload, for example a data import, validation run, or batch repair. Input shape: ```ts { resourceGroup: string; name: string; environmentVariables?: Record; } ``` ## AKS sandbox (`SandboxEnv`) Run agent code inside an AKS pod via `aksSandbox`. This is the full sandbox interface — `exec`/`readFile`/`writeFile`/`mkdir`/`rm` all work — backed by `@kubernetes/client-node` against credentials pulled from Azure ARM. ```ts import { init } from '@fabric-harness/sdk'; import { createAzureArmClient } from '@fabric-harness/azure'; import { aksSandbox } from '@fabric-harness/azure/aks-sandbox'; const arm = createAzureArmClient({ subscriptionId: process.env.AZURE_SUBSCRIPTION_ID!, token: process.env.AZURE_ACCESS_TOKEN!, }); const sandbox = await aksSandbox({ arm, resourceGroup: 'my-rg', clusterName: 'my-aks', // Either attach to an existing pod: podName: 'agent-pod', // Or create an ephemeral pod from an image (auto-deleted on cleanup): // image: 'alpine:latest', }); const fabric = await init({ sandbox }); ``` Requires `@kubernetes/client-node` as a peer dependency. ## AKS Run Command (control-plane tool) For invoking AKS Run Command from the agent's tool surface (without entering a pod): ```ts import { azureAksRunCommandTool } from '@fabric-harness/azure'; const tools = [azureAksRunCommandTool(arm)]; ``` Treat this as a privileged `execute` effect and guard it with policy: ```ts const policy = { toolPolicy: { requireApproval: ['azure_aks_run_command'], }, }; ``` ## Azure Container Instances exec ```ts import { azureContainerInstanceExecTool } from '@fabric-harness/azure'; const tools = [azureContainerInstanceExecTool(arm)]; ``` The ACI tool creates an exec session for a configured container group/container. It is a control-plane primitive, not a complete remote shell stream. Use it for operator workflows where your app handles the returned exec session details. ## Build targets Two Azure-specific build targets emit deployable artifacts: ### `--target aks` ```sh fh build --target aks ``` Emits Dockerfile, `.dockerignore`, and `k8s/` manifests: - `k8s/deployment.yaml` — Deployment with `/health` and `/ready` probes - `k8s/service.yaml` — ClusterIP Service on port 80 → 3000 - `k8s/README.md` — push-and-apply walkthrough Build the image, push to your ACR, then `kubectl apply -f k8s/`. ### `--target aca` (Azure Container Apps) ```sh fh build --target aca azd up ``` Emits Dockerfile, `azure.yaml` (azd project), and `infra/` Bicep: - `infra/main.bicep` — managed environment + ACR (Basic) + Container App with scale-to-zero - `infra/main.parameters.json` — `azd`-driven parameters - `infra/README.md` — `azd up` walkthrough The Container App ingresses externally on port 3000 with `/health` and `/ready` probes. ## Foundry Agent Service For Foundry Agent Service invocation and lifecycle helpers, see [Foundry Hosted Agents](/docs/deployment/foundry-hosted-agent). ## Live tests Live tests are skipped unless enabled: ```sh FABRIC_AZURE_OPENAI_TEST=1 \ AZURE_OPENAI_ENDPOINT=... \ AZURE_OPENAI_API_KEY=... \ AZURE_OPENAI_DEPLOYMENT=... \ pnpm --filter @fabric-harness/azure test ``` ```sh FABRIC_AZURE_FOUNDRY_TEST=1 \ AZURE_FOUNDRY_PROJECT_ENDPOINT=... \ AZURE_FOUNDRY_AGENT_ID=... \ AZURE_TOKEN=... \ pnpm --filter @fabric-harness/azure test ``` ```sh FABRIC_AZURE_ARM_TEST=1 \ AZURE_SUBSCRIPTION_ID=... \ AZURE_TOKEN=... \ pnpm --filter @fabric-harness/azure test ``` Optional ARM resources: ```sh AZURE_CONTAINER_APPS_JOB_RESOURCE_GROUP=... AZURE_CONTAINER_APPS_JOB_NAME=... AZURE_AKS_RESOURCE_GROUP=... AZURE_AKS_CLUSTER_NAME=... AZURE_ACI_RESOURCE_GROUP=... AZURE_ACI_CONTAINER_GROUP=... AZURE_ACI_CONTAINER_NAME=... ``` --- # Build and Run Artifacts Canonical: https://harness.techfabric.com/docs/deployment/build-artifacts Package v2 jobs and persistent agents into self-contained deployable artifacts. `fh build` compiles the embedded workspace, bundles authored definitions, and emits a target-specific runtime. Node-derived targets use the same v2 HTTP server as `fh dev`, so local and deployed routes have the same semantics. ## What the build binds `fh build` does more than copy source. The generated manifest describes definitions, public routes, policy, required capabilities, runtime versions, package coordinates, artifact digest, and provenance so another system can verify the artifact before it runs. ## Start with both definition types Finite work lives in `.fabricharness/jobs/`: ```ts title=".fabricharness/jobs/summarize.ts" import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'summarize', input: schema.object({ text: schema.string() }), output: schema.string(), triggers: { webhook: true }, async run({ init, input }) { const session = await (await init()).session(); return session.prompt(`Summarize:\n\n${input.text}`); }, }); ``` Long-lived addressable agents live in `.fabricharness/agents/`: ```ts title=".fabricharness/agents/support.ts" import { createAgent } from '@fabric-harness/sdk'; export default createAgent(({ id }) => ({ name: 'support', instructions: `You are the support agent for account ${id}.`, model: 'openai/gpt-5.5', triggers: { webhook: true }, })); ``` ## Build Node ```sh fh build --target node ``` The build summary distinguishes the two surfaces: ```text Build complete Output .fabricharness/build/node Manifest .fabricharness/build/node/manifest.json Jobs summarize Agents support ``` The artifact contains the shared server and self-contained definition modules: ```text .fabricharness/build/node/ .fabricharness/ agents/support.mjs jobs/summarize.mjs roles/ skills/ dist/ agents/support.mjs jobs/summarize.mjs server.mjs manifest.json package.json ``` ### Monorepo contracts stay inside the artifact Definitions can import a shared contracts package owned by the same pnpm workspace: ```json title="agents/package.json" { "dependencies": { "@acme/agent-contracts": "workspace:*", "zod": "catalog:" } } ``` Harness follows and bundles dependencies resolved through `workspace:`, `catalog:`, `file:`, `link:`, `portal:`, and `patch:` protocols. Those source-only specifiers are omitted from the artifact `package.json`. The resulting directory can be copied to a clean machine, staged in a Unity Catalog Volume, or handed to a delivery system such as TechFabric Runway without the original monorepo or a sibling checkout. For the complete producer/consumer contract, detached verification script, runtime-binding boundary, and failure behavior, see [Portable agent packages](/docs/deployment/portable-packages). Registry dependencies intentionally externalized by the server remain in the generated `package.json`; install those in the artifact directory before starting it. A detached artifact must never contain a `workspace:` or `catalog:` dependency. Run it: ```sh PORT=8080 OPENAI_API_KEY="$OPENAI_API_KEY" \ node .fabricharness/build/node/dist/server.mjs ``` ## Invoke the built artifact Finite jobs return their result and a generated run ID: ```sh curl -sS http://localhost:8080/jobs/summarize \ -H 'content-type: application/json' \ -d '{"text":"Fabric builds durable agents."}' ``` ```json { "result": "Fabric is a framework for durable agents.", "runId": "8f2d...", "agentPath": "/app/.fabricharness/jobs/summarize.mjs" } ``` Persistent input is admitted durably and returns `202`: ```sh curl -i http://localhost:8080/agents/support/acct-42 \ -H 'content-type: application/json' \ -d '{"message":"Where is my invoice?"}' ``` ```json { "submissionId": "5ec1...", "streamUrl": "/agents/support/acct-42/conversation?session=default&offset=0", "offset": "0" } ``` Use `@fabric-harness/client` to wait for settlement: ```ts import { createFabricClient } from '@fabric-harness/client'; const client = createFabricClient({ baseUrl: 'http://localhost:8080' }); const admitted = await client.agents.send({ agent: 'support', id: 'acct-42', message: 'Where is my invoice?', }); const settled = await client.agents.wait({ agent: 'support', id: 'acct-42', submissionId: admitted.submissionId, }); ``` ## Manifest schema v2 Every current artifact emits `schemaVersion: 2` with separate collections: ```sh jq '{schemaVersion, jobs, agents}' .fabricharness/build/node/manifest.json ``` Build readers in `@fabric-harness/node` normalize legacy schema-v1 manifests, but external tooling should migrate to `jobs` and `agents`. See [Build manifest](/docs/reference/build-manifest). ## Production exposure In production, a public job or persistent agent must declare `triggers.webhook: true`. Protect the server and scope tenants with environment variables: ```sh NODE_ENV=production \ FABRIC_HARNESS_API_TOKEN="$API_TOKEN" \ FABRIC_HARNESS_TENANT_REQUIRED=1 \ FABRIC_HARNESS_RATE_LIMIT_MAX=100 \ FABRIC_HARNESS_RATE_LIMIT_WINDOW_MS=60000 \ node dist/server.mjs ``` Clients then send both headers: ```sh curl http://localhost:8080/jobs/summarize \ -H "authorization: Bearer $API_TOKEN" \ -H 'x-fabric-tenant: acme' \ -H 'content-type: application/json' \ -d '{"text":"..."}' ``` ## Other targets ```sh fh build --target docker --docker-build --docker-tag acme/support:1.0.0 fh build --target databricks-app fh build --target aks fh build --target aca ``` Node-derived targets inherit the shared v2 server. Cloudflare supports finite jobs and serialized Durable Object-backed persistent sessions. The Cloudflare runtime intentionally omits the Node submission queue, abort, attachment materialization, and offset conversation-stream routes. ## Verify supply-chain metadata ```sh fh build --target docker --provenance --attestation --sbom fh verify-provenance .fabricharness/build/docker fh verify-attestation .fabricharness/build/docker ``` See [Docker](/docs/deployment/docker), [Databricks App](/docs/deployment/databricks-app), and [Security hardening](/docs/reference/security-hardening). --- # Cloudflare Workers + Sandbox Canonical: https://harness.techfabric.com/docs/deployment/cloudflare Deploy to Cloudflare Workers with Durable Object sessions and Cloudflare Sandbox. The Cloudflare target emits an unbundled Worker entrypoint, a Durable Object session store, and a Cloudflare Sandbox container binding for finite jobs and persistent agents. Wrangler owns the Cloudflare bundle; TechFabric Harness emits the entry, bindings, and config. Each persistent agent/instance pair is routed to one Durable Object, which serializes turns and persists named sessions in Durable Object SQLite. Finite runs remain authoritative in one Durable Object per run. A separate, singleton `FabricHarnessRunRegistryObject` stores only tenant-scoped run pointers so `client.runs.list()` can discover runs across those objects. Registry mirror writes are best-effort and never turn a successful run admission or settlement into a failure. A terminal pointer is an upsert, so it heals a start pointer lost during a transient registry fault. Before production, run the live smoke workflow in your Cloudflare account to validate bindings, Durable Object persistence, R2 access, and Sandbox container startup with your account limits. ## Quickstart ```sh npx @fabric-harness/cli init --template cloudflare --dir my-edge-agent cd my-edge-agent npm install npx fabric-harness dev --target cloudflare --port 8787 ``` The template uses the Cloudflare Workers AI binding (`env.AI`) so the Worker can run inference without external model API keys. ## Build ```sh fh build --target cloudflare cd .fabricharness/build/cloudflare npm install ``` Output: ``` .fabricharness/build/cloudflare/ dist/worker.ts wrangler.jsonc Dockerfile # default Cloudflare Sandbox image manifest.json README.cloudflare.md ``` ## Develop locally ```sh fh dev --target cloudflare ``` This wraps `wrangler dev` so the same bundler runs in dev and deploy. Two reload paths run simultaneously: - **Wrangler** watches the bundle's transitive import graph and reloads `workerd` on body edits to your agent files. - **TechFabric Harness's structural watcher** watches `.fabricharness/jobs/` and `.fabricharness/agents/`, then regenerates the entry whenever the definition set changes. Net result: you can edit job bodies, add jobs, or change `triggers: { webhook: true }` without restarting the dev server. Or if you've already built once and just want raw wrangler: ```sh npx wrangler dev ``` ## Deploy ```sh fh build --target cloudflare cd .fabricharness/build/cloudflare npx wrangler deploy ``` ## Routes The Cloudflare Worker exposes both execution models: - `GET /health` · `GET /ready` · `GET /manifest` - `POST /jobs/:name` — invoke a finite job and receive `{ result, runId }` - `POST /jobs/:name?wait=false` — admit an asynchronous run; an `Idempotency-Key` reuses its run - `GET /runs?status=&job=&limit=&cursor=` — list tenant-visible finite runs in reverse chronological order - `GET /runs/:runId` · `GET /runs/:runId/events?offset=0` — inspect finite runs and events - `POST /runs/:runId/abort` — abort an active finite run - `POST /agents/:name/:instanceId?wait=false` with `{ message, session? }` — durably admit a persistent submission - `GET /agents/:name/:instanceId/submissions/:submissionId?session=default` — inspect settlement - `GET /agents/:name/:instanceId/conversation?session=default&offset=0` — read the offset stream - `POST /agents/:name/:instanceId/abort?session=default` — abort queued or active submissions - `GET /agents/:name/:instanceId/schedules` · `POST /agents/:name/:instanceId/schedules` — list or create per-instance wake-up schedules - `DELETE /agents/:name/:instanceId/schedules/:scheduleId` — cancel a schedule - `GET /agents/:name/:instanceId?session=default` — inspect a named persistent session - `DELETE /agents/:name/:instanceId?session=default` — delete that named session - `GET /sessions/:runId` — inspect the stored run - `GET /sessions/:runId/timeline` · `/metrics` · `/tasks` · `/approvals` · `/artifacts` Webhook trigger gating applies on the Worker too: in production mode (`FABRIC_ENV=production`), only definitions with `triggers.webhook === true` are exposed publicly. ## Cron Triggers Declare schedules on finite jobs: ```ts export default defineAgent({ name: 'daily-report', triggers: { schedule: '0 16 * * 1-5' }, // Cloudflare cron is UTC async run({ input }) { return buildReport(input); }, }); ``` The Cloudflare build adds each unique expression to `wrangler.jsonc` and emits `scheduled()`. Scheduled runs use deterministic IDs, persist run state and offset events in a per-run Durable Object, and deduplicate repeated delivery of the same occurrence. HTTP and cron execution share the same job function and `{ runId, acceptedAt, statusUrl, eventsUrl }` receipt contract. Their pointers are indexed in `FABRIC_HARNESS_RUN_REGISTRY`, the same registry used by HTTP runs. ## Per-instance schedules (Durable Object alarms) Cron Triggers address finite jobs. Persistent agents get the complementary primitive: a per-instance wake-up backed by the instance Durable Object's alarm. Schedules are stored as rows in the same Durable Object SQLite database as the instance's sessions and submissions, and the single platform alarm is multiplexed across them — it is always armed for the earliest pending wake-up. ```bash # Wake instance "user-42" of agent "support" every hour with an instruction. curl --fail --request POST http://localhost:8787/agents/support/user-42/schedules \ --header 'content-type: application/json' \ --data '{"everySeconds": 3600, "task": "Check for unresolved threads and follow up."}' # One-shot, with a small structured payload. curl --fail --request POST http://localhost:8787/agents/support/user-42/schedules \ --header 'content-type: application/json' \ --data '{"delaySeconds": 900, "task": "Send the promised recap.", "payload": {"thread": "t-123"}}' ``` `at` (epoch ms, ISO string, or Date), `delaySeconds`, and `everySeconds` control timing; `everySeconds` makes the schedule recurring (first fire uses `at`/`delaySeconds` when given, otherwise one interval from now). `GET` lists pending schedules and `DELETE .../schedules/:scheduleId` cancels one. When the alarm fires, the Durable Object drains due schedules and admits each as a normal durable submission whose delivered message is a signal with `type: "schedule"`: ```ts { kind: 'signal', type: 'schedule', body: 'Check for unresolved threads and follow up.', // the task attributes: { scheduleId, scheduledAt, intervalSeconds, payload }, tagName: 'schedule', } ``` The wake-up therefore flows through the same admission, FIFO, lease, cancellation, and settlement path as any HTTP or dispatch interaction: `POST .../abort` cancels an in-flight scheduled run, the durability policy of the agent applies, and the signal appears in the instance's conversation stream where `useDelivery()` can branch on `type === 'schedule'`. Semantics and caveats: - Cloudflare alarms are **at-least-once** and retried on handler failure; a wake-up can be delivered more than once after a crash. Recurring schedules advance to their next occurrence when drained — before the run starts — so a crashed wake-up never blocks future occurrences, and occurrences missed while the object was down collapse into a single catch-up wake-up instead of rapid-fire replays. - Durable Object eviction is not a failure mode: the platform re-instantiates the object when its alarm fires. Startup also reconciles the alarm against stored schedules, repairing any drift left by a crash between the storage write and `setAlarm`. There is deliberately no watchdog. - Bounds (defaults, configurable on the library coordinator): minimum interval 1 second, payload ≤ 4 KiB, at most 128 schedules per instance. Sub-minute intervals burn Durable Object invocations; prefer Cron Triggers plus a dispatcher job for coarse fleet-wide work. - Deleting the instance (`DELETE /agents/:name/:instanceId`) clears its schedules and unsets the alarm. Schedules live in the instance's Durable Object storage: wiping that storage loses them, and they do not follow the instance if its Durable Object name changes. - This API is Cloudflare-specific by design. It is exposed by `@fabric-harness/cloudflare` (`createCloudflareScheduleCoordinator`, `cloudflareScheduleMessage`) and the generated Worker routes; the portable SDK has no Cloudflare dependency, and `triggers.schedule` on `createAgent()` remains unsupported — declare cron on a finite dispatcher job instead. ## Hand-written Durable Object hosts `fh build --target cloudflare` wires each persistent-agent instance Durable Object out of the same machinery: Durable Object SQLite persistence stores, a session store with the conversation-stream projection, a durable submission runner (per-session FIFO, attempt leases, crash reconciliation, canonical settlement), and the per-instance alarm schedule coordinator. A hand-written Durable Object — one not produced by `fh build` — gets the same behavior by composing `createCloudflareDurableObjectHost` from `@fabric-harness/cloudflare` instead of re-implementing the wiring. Before (hand-rolled; the drain, admission, and cleanup wiring is yours to get right, and declared `durability` bounds are not enforced): ```ts const store = createCloudflareDurableObjectSessionStore(ctx.storage.sql); const schedules = createCloudflareScheduleCoordinator(ctx.storage.sql, ctx.storage); async alarm() { await schedules.reconcile(); const fired = await schedules.drain(); for (const schedule of fired) { // Render the agent, init it over the store, prompt the session… by hand, // with no FIFO, lease, settlement, or maxAttempts/timeoutMs enforcement. await runInteraction(env, store, tenantId(), cloudflareScheduleMessage(schedule)); } } ``` After (the host packages drain → durable submission, the schedule routes, startup reconciliation, admission with enforcement, and instance-delete cleanup): ```ts import { createCloudflareDurableObjectHost, type CloudflareDurableObjectHost, } from '@fabric-harness/cloudflare'; export class TenantOperatorObject { private readonly host: CloudflareDurableObjectHost; constructor(ctx: DurableObjectState, env: Env) { this.host = createCloudflareDurableObjectHost({ sql: ctx.storage.sql, alarm: ctx.storage, objectName: ctx.id.name, // ':' agents: { 'tenant-operator': tenantOperator }, // createAgent() results, by name waitUntil: (promise) => ctx.waitUntil(promise), execute: async (submission, options) => { // Your interaction body: render the persistent agent, init it over // this.host.store, and prompt its session, honoring options.signal, // options.onInputApplied, and options.takeJoinedInputs. return runInteraction(env, this.host.store, submission, options); }, }); ctx.blockConcurrencyWhile(() => this.host.reconcile()); } async fetch(request: Request): Promise { // GET/POST/DELETE /agents/:name/:instanceId/schedules[/:scheduleId]. // Returns undefined for other paths, so custom routes compose freely. return ( (await this.host.handleSchedulesRoute(request)) ?? new Response('not found', { status: 404 }) ); } async alarm(): Promise { // Drains due schedules and admits each as a durable 'schedule'-signal submission. await this.host.alarm(); } // Custom RPC methods are unaffected — the host never intercepts them. async nudge(nudge: TenantOperatorNudge): Promise { const receipt = await this.host.admit({ agent: 'tenant-operator', id: tenantIdFrom(this.host), message: nudgeSignal(nudge), wait: true, }); return receipt.settlement?.result; } } ``` What the host enforces, for alarm-triggered and RPC/HTTP-triggered interactions alike: - Every admission flows through the durable submission runner: per-session FIFO ordering, attempt leases with startup and per-request crash reconciliation, idempotent input application, and canonical settlement records readable through `host.runner` / `host.executor`. - When `agents` is provided, the default admission validator rejects unknown agents, validates initial data and instance-contact preconditions, ensures the instance identity, and stamps the agent's declared `durability: { maxAttempts, timeoutMs }` bounds onto the admission — the same policy the generated Worker applies. Pass `validateInput` to override; the override then owns durability stamping (see `persistentAgentSubmissionDurability` in the SDK). - `host.deleteInstance({ agent, id, session? })` refuses while a submission is unsettled (returning the aborted ids), then clears all schedules and the alarm and deletes the instance's submissions, attachments, conversation stream, and instance identity. What remains the host's composition, exactly as in the generated Worker: the `execute` body (model, sandbox, and tool wiring), every non-schedule HTTP route (submissions, conversation, abort, auth, rate limiting), and any custom RPC surface. ## Choosing a Cloudflare sandbox mode TechFabric Harness supports two Cloudflare sandbox modes. ### Containers / Cloudflare Sandbox Use this mode when your agent needs Linux shell commands, package managers, language toolchains, `bash`, `grep`, `read`, `write`, and `edit` tools. ```ts export default { sandbox: { backend: 'cloudflare', mode: 'sandbox', binding: 'Sandbox', cwd: '/workspace', }, }; ``` ### Computer / `@cloudflare/computer` Use this early-preview mode when you want a lightweight, SQLite-backed durable Workspace and a Worker Loader-backed just-bash runtime. It provides the standard `bash`, `grep`, `glob`, `read`, `write`, and `edit` tools, but it is not a Linux container: native binaries, package managers, and language toolchains still require Cloudflare Sandbox. ```ts export default { sandbox: { backend: 'cloudflare', mode: 'computer', loaderBinding: 'LOADER', cwd: '/workspace', }, }; ``` The generated `wrangler.jsonc` adds: ```jsonc { "compatibility_flags": ["nodejs_compat", "experimental"], "worker_loaders": [{ "binding": "LOADER" }] } ``` Typed Workspace access is exported from `@fabric-harness/cloudflare/computer`. The generated Worker also exports `WorkspaceServiceProxy` and hosts one workspace in each Fabric session Durable Object. Existing `@cloudflare/shell` data is not migrated. The old `shell-workspace` configuration value is a deprecated alias for one release window. If Cloudflare sandboxing isn't configured, the Worker falls back to Fabric's empty sandbox. The build always gives an explicitly configured Cloudflare sandbox precedence over the lightweight `virtual` default added by the default-import `defineAgent()`. This means the same agent source can stay infrastructure-free locally and use the container or Computer workspace selected by the deployment target without changing its prompt and session code. ## Verify the Sandbox contract The runnable `examples/with-cloudflare-sandbox` project includes a `sandbox-certification` job. It exercises the same nine behaviors used by the other maintained remote sandbox adapters: - shell execution and binary file round trips; - working-directory and environment propagation; - stdout/stderr collection; - timeout and abort, including termination of the native Cloudflare process; - portable reference encoding, reconnect, and provider cleanup. Build and run the Worker locally with the actual Cloudflare Sandbox container: ```bash cd examples/with-cloudflare-sandbox pnpm fh build --target cloudflare cd .fabricharness/build/cloudflare pnpm exec wrangler dev --local ``` In another terminal, request the report: ```bash curl --fail --request POST http://localhost:8787/jobs/sandbox-certification \ --header 'content-type: application/json' \ --data '{"input":{"credentialed":false}}' ``` The response contains a schema-v1, secret-free report with one result per check. A passing report has `ok: true`, `provider: "cloudflare-sandbox"`, and nine `status: "passed"` rows. Protected live CI uses `credentialed: true` and retains the same JSON as certification evidence. The generated container image and `@cloudflare/sandbox` dependency are kept on the supported 0.9 line so local and hosted results exercise the same SDK contract. ## How it maps to Fabric primitives | Fabric primitive | Cloudflare equivalent | | --- | --- | | Session store | Durable Object SQLite (one DO per persistent agent instance; finite runs route by run id) | | Run discovery | Tenant-filtered registry DO containing pointers; per-run DOs remain authoritative | | `SandboxEnv` | Cloudflare Sandbox container binding via `@cloudflare/sandbox`, or a durable Computer workspace via `@cloudflare/computer` | | Model provider | `env.AI` Workers AI binding via `CloudflareWorkersAIModelProvider` (optional; HTTP providers also work) | | Webhook trigger | `POST /jobs/:name` | | Schedule trigger | Worker `scheduled()` + `triggers.schedule` | | Per-instance wake-up | Durable Object alarm + SQLite schedule rows (`/agents/:name/:instanceId/schedules`) | | Persistent prompt | `POST /agents/:name/:instanceId` | | Health/manifest | `GET /health`, `GET /manifest` | ## Workers AI binding (no API tokens) `@fabric-harness/cloudflare/workers-ai` ships a `ModelProvider` that routes inference through `env.AI.run()` instead of HTTP. Zero API tokens, zero egress, runs at the edge. Workers AI accepts the OpenAI Chat Completions request body, so the provider serializes through the SDK's standard OpenAI helpers. ```ts import { CloudflareWorkersAIModelProvider } from '@fabric-harness/cloudflare/workers-ai'; export default { async fetch(request: Request, env: Env) { const fabric = await init({ modelProvider: new CloudflareWorkersAIModelProvider({ binding: env.AI, defaultModel: '@cf/meta/llama-3.1-8b-instruct', // Optional: route through Cloudflare AI Gateway // gateway: { id: 'my-gateway', skipCache: false, cacheTtl: 3600 }, }), }); // ... }, }; ``` Add the binding to `wrangler.jsonc`: ```jsonc { "ai": { "binding": "AI" } } ``` You can still use HTTP providers (Anthropic, OpenAI-compatible, Vercel AI Gateway) on the Cloudflare target — store the API key as a [Workers Secret](https://developers.cloudflare.com/workers/configuration/secrets/) and reference it via `env`. ## Account validation Run the Cloudflare smoke in your account before rollout: ```sh FABRIC_CLOUDFLARE_TEST=1 \ FABRIC_CLOUDFLARE_WORKER_URL=https://..workers.dev \ FABRIC_CLOUDFLARE_ARTIFACT_DIR=/path/to/.fabricharness/build/cloudflare \ CLOUDFLARE_ACCOUNT_ID= \ pnpm --filter @fabric-harness/cloudflare test -- live.test.ts ``` The repository test suite also runs local workerd tests without account credentials. It admits concurrent persistent requests, verifies FIFO and attachment materialization, aborts finite and persistent work, deletes a session, kills workerd during a tool call, restarts with the same Durable Object storage, and verifies conservative interrupted-tool settlement. The account smoke adds the provider-specific bindings, Sandbox container, and R2 checks. ## Limits and considerations - Worker request/CPU limits apply; long-running workflows belong on the Temporal worker target. - Persistent turns use a Durable Object submission queue with leases, FIFO execution, restart reconciliation, attachment materialization, abort, deletion, and offset conversation streams. - Per-instance schedules use the instance Durable Object's single alarm with at-least-once delivery; schedule state lives in Durable Object SQLite and is lost if that storage is wiped. - The run registry is a discovery index, not a second source of truth. Monitor mirror errors; terminal writes self-heal missing starts, but an account-level outage can temporarily omit an active pointer while direct run-id inspection continues to work. - Use Temporal when workflows exceed Worker or Durable Object execution/storage limits, require long timers across many external activities, or need Temporal's workflow-history tooling. - Sandbox container start latency depends on the Cloudflare image; warm pools help. - Keep `FABRIC_HARNESS_API_TOKEN`, body limits, rate limits, and `FABRIC_ENV=production` trigger gating enabled for public deployments. - With `FABRIC_ENV=production`, an unset API token fails closed: only `/health` and `/ready` remain reachable without authentication. --- # Databricks Canonical: https://harness.techfabric.com/docs/deployment/databricks First-party Databricks integration — Unity AI Gateway, Unity Catalog governance, RAG, Lakebase, deploy targets, and cost reconciliation. `@fabric-harness/databricks` is a **first-party integration** for building governed agents that consume Databricks services. One `databricks()` call wires Unity AI Gateway, governed SQL, Unity Catalog, AI Functions, Genie, Lakeflow, AI Search, Feature Serving, governance policy, and cost reporting under a single principal. Everything is layered **on top of** Unity Catalog; it never re-implements UC permissions. For the product-level architecture and complete feature map, start with [TechFabric Harness on Databricks](/docs/databricks). This page is the deployment and package reference. For Lakebase, set `DATABRICKS_LAKEBASE_ENDPOINT` (or `ENDPOINT_NAME`) to the full `projects/.../branches/.../endpoints/...` resource name. Run the App, OBO, permission-denial, and Lakebase restart certification suite in the target workspace before rollout. See Databricks' [Node/manual credential flow](https://docs.databricks.com/aws/en/oltp/projects/external-apps-manual-api). For a complete scaffold-to-deploy walkthrough, start with the [Databricks App tutorial](/docs/deployment/databricks-app). ## The bundle ```ts import { databricks } from '@fabric-harness/databricks'; const dbx = databricks({ host: process.env.DATABRICKS_HOST!, // UC enforces this principal's grants on every call. principal: { kind: 'service-principal', host: process.env.DATABRICKS_HOST!, clientId: process.env.DATABRICKS_CLIENT_ID!, clientSecret: process.env.DATABRICKS_CLIENT_SECRET!, }, model: 'system.ai.gpt-oss-20b', warehouseId: process.env.DATABRICKS_WAREHOUSE_ID!, sqlRead: true, // SELECT-only model tool aiSearch: { index: 'main.kb.docs_index', textColumn: 'chunk', idColumn: 'id' }, // RAG aiFunctions: { allowedEndpoints: ['support-classifier'] }, genie: { conversations: { agentId: 'agent-123' } }, // Existing Genie Agent lakeflow: { runPolicy: { allowedPipelineIds: ['pipeline-123'] } }, consumption: true, // System-Tables cost reporting featureServing: { endpoint: 'user-features' }, governance: { stewardAudience: 'data-steward', onLineage: (r) => console.log('[lineage]', r) }, }); // dbx.modelProvider, dbx.tools, dbx.policy, dbx.retriever, dbx.consumption, dbx.store, dbx.identity ``` Provider-qualified model refs also resolve through the generic SDK path. For the default Gateway model, use `FABRIC_MODEL=databricks/system.ai.gpt-oss-20b`. Inside `databricks()` or `defineDatabricksAgent()`, use the native service name `system.ai.gpt-oss-20b`. ## Unity AI Gateway and custom endpoints `databricksFoundationModelProvider({ host, token })` uses Unity AI Gateway for `system.ai.*` model services and retains `/serving-endpoints` for explicitly selected custom endpoints. Both paths are OpenAI-compatible and inherit streaming, tool calls, and reasoning content. The same rotating token threads through every REST and data call. ## Identity & Unity Catalog governance `databricksIdentity()` produces a rotating token from a **PAT**, an **OAuth service principal** (cached + refreshed), or **on-behalf-of** a specific end user. UC enforces that principal's table/row/column grants natively — the agent physically cannot read what it lacks `SELECT` on. On top of UC, Fabric adds: - **Lineage/audit** — `withGovernance()` stamps every tool call (principal, service, catalog/schema) to an `onLineage` sink (secrets redacted). - **Approval routing** — `databricksGovernancePolicy()` routes sensitive (write/execute) tools to a steward audience via `CapabilityPolicy.approvalRules`. - **Egress allowlist** — outbound network pinned to the workspace host. With channel `actor` propagation, an agent can act **on behalf of** the human who triggered it, so UC enforces that user's grants — per-user data boundaries with no per-user policy code. ## Tools | Tool | What | | --- | --- | | `sql_read` | Run one SELECT-only statement on a warehouse. | | `databricks_sql` | Run policy-bound SQL on a warehouse; never added by `warehouseId` alone. | | `databricks_unity_catalog_tables` / `databricks_table_info` | Discover + describe UC tables. | | `search` (AI Search) | RAG retrieval over a Databricks AI Search index. | | `databricks_ai_query` | In-warehouse `ai_query()` model inference (parameterized, injection-safe). | | `databricks_genie_ask` | NL → SQL analytics over an existing Genie Agent. | | `databricks_pipeline_*` | List / status (read) + start / stop (execute) Lakeflow pipelines. | | `databricks_feature_lookup` | Low-latency feature lookup from a Feature Serving endpoint. | | `databricks_consumption` | Real DBUs + list cost from `system.billing` System Tables. | Feature Serving inference uses Databricks' data-plane route `/serving-endpoints/{name}/invocations`. Harness corrects the modular JavaScript SDK 0.21 client's erroneous `/api/serving-endpoints/...` serialization at the shared authenticated transport boundary while retaining the generated request and response codecs. The endpoint principal still requires `CAN_QUERY`. Job, notebook, and MLflow tools (`databricksRunJobTool`, `databricksNotebookTool`, `databricksMlflowLogMetricTool`) and the SQL-warehouse `SandboxEnv` (`databricksSqlSandbox`, `@fabric-harness/databricks/sql-sandbox`) remain available as building blocks. Model-callable job, notebook, SQL, AI Functions, Lakeflow mutation, and MLflow factories require explicit resource policies. Deliberate `allowAny...: true` arms remain available for operator-reviewed advanced code and are intentionally greppable. See [Bound what a model can run](/docs/databricks/compute). ## State — Lakebase Lakebase is Postgres-compatible, and Fabric's Postgres session, submission, and conversation-stream stores are structurally reusable there. `lakebaseClient()` exchanges workspace OAuth for a database credential, caches it until the early-refresh window, and single-flights refreshes. Configure the workspace host and full endpoint resource name; never pass the workspace token as a direct database password. `databricksApp().serverOptions()` supplies all three stores to the shared Node server. ```ts import { databricksPersistence, databricksSdk } from '@fabric-harness/databricks'; import { startDevServer } from '@fabric-harness/node'; const principal = { kind: 'service-principal', host: process.env.DATABRICKS_HOST!, clientId: process.env.DATABRICKS_CLIENT_ID!, clientSecret: process.env.DATABRICKS_CLIENT_SECRET!, } as const; const sdk = databricksSdk({ host: process.env.DATABRICKS_HOST!, principal }); const persistence = databricksPersistence({ lakebase: { endpoint: process.env.DATABRICKS_LAKEBASE_ENDPOINT!, host: process.env.DATABRICKS_LAKEBASE_HOST!, database: process.env.DATABRICKS_LAKEBASE_DATABASE!, user: process.env.DATABRICKS_LAKEBASE_USER!, credentialClient: sdk.postgres, }, }); await persistence.migrate(); const { store, submissionStore, conversationStreamStore } = await persistence.connectAll(); await startDevServer({ sessionStore: store, submissionStore, conversationStreamStore, }); ``` For local Postgres tests, use the explicit `password` option instead of `credentialClient` and `endpoint`. Production Lakebase should always use credential exchange. ## SDK requests and safe retries Stable API requests use the generated Databricks clients. Fabric retries only operations it can classify as idempotent (for example Feature Serving reads and MLflow metric/parameter upserts), while Jobs runs carry a caller-supplied Databricks idempotency token. Ambiguous creates are never retried. ```ts import { databricksJobs, databricksSdk } from '@fabric-harness/databricks'; const sdk = databricksSdk({ host: process.env.DATABRICKS_HOST!, principal, }); const jobs = databricksJobs(sdk.jobs, { runPolicy: { allowedJobIds: [42] } }); await jobs.runJob({ jobId: 42, idempotencyToken: submission.id, }); ``` Fabric's private raw protocol transport is reserved for documented APIs absent from the generated SDK and retains explicit `safe`/`never` retry classification at those narrow call sites. Callers use typed bundle capabilities instead of constructing the transport. Genie ACLs use the official `@databricks/sdk-accessmanagement` client and are not part of this exception. ## Deploy targets Build a deployable artifact with `fabric-harness build --target `: Release orchestrators that already have an immutable `databricks-app` artifact can use the same Harness deployment implementation programmatically. Verify the digest before calling it: ```ts import { deployDatabricksAppArtifact, destroyDatabricksAppArtifact, digestDatabricksArtifact, validateDatabricksAppArtifact, } from '@fabric-harness/databricks'; const digest = await digestDatabricksArtifact(artifactDir); await verifyExpectedReleaseDigest(digest); await validateDatabricksAppArtifact({ artifactDir, target: 'prod', profile: 'production' }); await deployDatabricksAppArtifact({ artifactDir, target: 'prod', profile: 'production', appName: 'analytics-agent', sourceCodePath: '/Workspace/Shared/analytics-agent/app', mode: 'SNAPSHOT', }); // PR-close cleanup uses the same immutable artifact and destroys only its bundle target. await destroyDatabricksAppArtifact({ artifactDir, target: 'preview-42', profile: 'production' }); ``` The function synchronizes the Declarative Automation Bundle, creates the App snapshot, and waits for the Apps CLI operation to succeed. It does not rebuild the directory, which keeps the verified artifact identical to the deployed artifact. Commands use an argument array with shell execution disabled. Successful results report `bundleSynchronized: true`, `appSnapshotActivated: true`, and the final non-empty output line from each operation. `appName`, `sourceCodePath`, and `mode: 'SNAPSHOT'` make activation explicit when an orchestrator already knows the Databricks App resource and the Bundle-synchronized workspace source. Omit them to use Databricks CLI project mode in the artifact directory. The source path must be the workspace location populated by the preceding Bundle deployment, not an unverified local directory. Validation or deployment fails when `databricks.yml` is missing, CLI authentication is unavailable, the Bundle target is invalid, or either CLI command exits non-zero. A Bundle synchronization failure prevents App snapshot activation. The API does not delete a successful deployment automatically; roll back by deploying a previously approved artifact. The runnable `examples/with-databricks-simple/release-artifact.ts` path is digest-only by default and requires an explicit environment opt-in plus an expected digest before it mutates a workspace. - **`databricks-app`** — intended to run the agent in-workspace as a Databricks App (the app's service principal is the acting UC identity). Emits `app.yaml` (bridges `DATABRICKS_APP_PORT`) + deploy docs. `fh deploy` synchronizes the Declarative Automation Bundle, creates a new App snapshot, and waits for the snapshot to reach `SUCCEEDED` before returning. App artifacts omit bundled definition source maps and minify each executable definition because Databricks rejects individual snapshot files larger than 10 MiB. The build checks every generated job, persistent-agent, and server `.mjs` file and fails locally with the definition path, actual size, and limit before a Bundle or App deployment can begin. When `BUNDLE_VAR_lakebase_endpoint` and `BUNDLE_VAR_lakebase_database_resource` are set at build time, the bundle attaches Lakebase Autoscaling as a managed `postgres` App resource. The database variable is the **database resource name**, not the PostgreSQL database name: ```sh export BUNDLE_VAR_lakebase_endpoint='projects/my-project/branches/production/endpoints/primary' export BUNDLE_VAR_lakebase_database_resource='projects/my-project/branches/production/databases/app-db' fh deploy --target databricks-app ``` Find both values with `databricks postgres list-endpoints ` and `databricks postgres list-databases `. The database API response separately reports the PostgreSQL name under `status.postgres_database`; Databricks injects that value as `PGDATABASE`. It also injects the other `PG*` connection variables on every start, while `app.yaml` resolves the endpoint path with `valueFrom`. No database password or workspace token is stored in the artifact. - **`databricks-serving`** — proxy-only: packages an MLflow `ResponsesAgent` proxy to a persistent agent deployed elsewhere, registers it to Unity Catalog, and creates a serving endpoint that **Agent Bricks and the Playground** consume as a model/tool. `predict_stream` preserves Responses text-delta and final output-item events with stable item IDs; `predict` returns a `ResponsesAgentResponse`. It does not execute the TypeScript agent inside Model Serving. Calls from Model Serving to a Databricks App use a least-privilege OAuth M2M service principal; a static Harness bearer token is only appropriate when the upstream is a non-Databricks service that accepts that token. Install `@fabric-harness/databricks` in projects that use `fh deploy --target databricks-serving`. The CLI intentionally lazy-loads this optional integration, keeping ordinary CLI commands free of the native SDK's Node and install-size requirements. Databricks init templates and recipes declare the dependency for you. Generated projects pin CLI, SDK, Node runtime, and Databricks integration ranges independently to versions that exist in the registry; a CLI patch never invents matching patch versions for independently released packages. Executable, interactive, and managed-recipe scaffold tests compare every generated range with the workspace package manifests to guard against release drift. Check [release and documentation status](/docs/reference/release-status) for the current published versions rather than copying a historical template range from a certification record. In a source checkout, the Node build pipeline resolves the Databricks integration directly from its workspace source so clean-clone build tests do not depend on pre-existing `dist` output. Published `@fabric-harness/node` resolves the separately installed `@fabric-harness/databricks` package in the normal way. The release gate tests both paths and rejects a Databricks App server bundle that leaves an unresolved package import. Node-derived targets use the same v2 server as local development, so finite jobs keep `/jobs/:name` and persistent agents keep durable `/agents/:name/:id` admission after deployment. Cloudflare uses its own Durable Object-backed persistent runtime; Node-derived targets use the shared submission server. ## Cost reconciliation `databricksTenantCostLimit()` enforces a `perScope` budget against **real** Databricks spend from System Tables (estimates still guard `perCall`/`perSession`). System Tables are delayed accounting, so this is a reconciliation guard rather than a real-time kill switch. See [Cost attribution](/docs/operating/cost-attribution). ## See also - Examples: `with-databricks` (analytics copilot), `with-databricks-rag` (support agent), `with-databricks-dataeng` (pipelines), `with-databricks-cost-attribution`. - [Model providers](/docs/building/model-providers) · [Channels](/docs/building/channels) · [Cost attribution](/docs/operating/cost-attribution) The public `deployDatabricksAppArtifact()` API also accepts `appName`, `sourceCodePath`, `mode: "SNAPSHOT"`, and `startBeforeDeploy` when a governed release orchestrator must start and activate an explicit App from the immutable source synchronized by its Asset Bundle. Keep this call at the trusted deployment edge; human-facing tools should request a governed Platform action instead of activating production. --- # Daytona Canonical: https://harness.techfabric.com/docs/deployment/daytona Use Daytona's reproducible development environments as agent sandboxes, so a run gets a clean machine every time. Use a [Daytona](https://daytona.io) workspace as a remote `SandboxEnv` while the TechFabric Harness runtime runs in your Node deployment. ## Install ```sh npm install @fabric-harness/connectors @daytona/sdk ``` ## Connect a sandbox ```ts import { Daytona } from '@daytona/sdk'; import { daytonaSandbox } from '@fabric-harness/connectors'; import { init } from '@fabric-harness/sdk'; const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY }); const remote = await daytona.create({ image: 'ubuntu:latest' }); const fabric = await init({ sandbox: daytonaSandbox(remote, { cleanup: true }), }); const session = await fabric.session(); const result = await session.prompt('Inspect the repository and run its test suite.'); ``` Use `daytonaSandboxFactory()` when each session should create and own a separate workspace. The adapter supports `@daytona/sdk >=0.195.0 <1`. It converts Fabric's millisecond timeout to Daytona's seconds-based process timeout and exposes `remote.id` as a portable workspace reference. ```ts registerStandardSandboxRefDecoders({ daytona: { connect: ({ workspaceId }) => daytona.get(workspaceId) }, }); ``` Use [`assertSandboxCertification()`](/docs/building/sandbox-connectors#certification-helper) to verify binary files, cwd/env, output callbacks, timeout, abort, reconnect, and deletion with the target account. ## Environment variables - `DAYTONA_API_KEY` — Daytona API key (read lazily at runtime) ## See also - [Deployment overview](/docs/deployment) - [Sandbox connectors](/docs/building/sandbox-connectors#daytona) - [Daytona documentation](https://daytona.io/docs) --- # Docker Canonical: https://harness.techfabric.com/docs/deployment/docker Emit a Dockerfile from a workspace, and optionally build and push the image, which is the base every container target uses. The Docker target emits a `Dockerfile` plus the Node bundle. With `--docker-build` and `--docker-push`, the CLI invokes Docker for you. ## Build the scaffold ```sh fh build --target docker ``` Output: ``` .fabricharness/build/docker/ .fabricharness/ agents/*.mjs jobs/*.mjs Dockerfile dist/ agents/*.mjs jobs/*.mjs server.mjs manifest.json package.json ``` The definition modules and embedded workspace are runtime inputs. Copy or publish the complete build directory; `dist/server.mjs` alone is not a complete deployment artifact. ## Build the image in one step ```sh fh build --target docker --docker-build --docker-tag myorg/agents:0.1.0 ``` Add `--docker-push` to push immediately: ```sh fh build --target docker --docker-build --docker-push --docker-tag myorg/agents:0.1.0 ``` ## SBOM and provenance The CLI integrates with Syft and cosign: ```sh fh build --target docker \ --docker-build --docker-tag myorg/agents:0.1.0 \ --image-sbom --image-sbom-required \ --provenance --sign-provenance --signing-key env://COSIGN_PRIVATE_KEY ``` Verify later with: ```sh fh verify-attestation .fabricharness/build/docker fh verify-provenance .fabricharness/build/docker ``` ## Running the image ```sh docker run --rm -p 8080:8080 \ -e PORT=8080 \ -e OPENAI_API_KEY=$OPENAI_API_KEY \ myorg/agents:0.1.0 ``` ## Sandbox notes The Docker *target* (the host container) and the Docker *sandbox* (per-session isolation inside that host) are different things: - **Target Docker** = where the Fabric server runs. - **Sandbox Docker** = a separate Docker container started per session for tool execution. Requires Docker socket access from the host. For most production deployments, use a non-Docker sandbox (e.g. Cloudflare Sandbox at the edge, or Foundry Hosted Agents on Azure) and reserve Docker for the host. --- # E2B Canonical: https://harness.techfabric.com/docs/deployment/e2b Run untrusted code in an ephemeral E2B sandbox, so an agent that writes and executes code cannot reach your host. Use [E2B](https://e2b.dev) as an ephemeral `SandboxEnv` for code execution while the TechFabric Harness runtime runs in your Node deployment. ## Install ```sh npm install @fabric-harness/connectors @e2b/code-interpreter ``` ## Connect a sandbox ```ts import { Sandbox } from '@e2b/code-interpreter'; import { e2bSandbox } from '@fabric-harness/connectors'; import { init } from '@fabric-harness/sdk'; const remote = await Sandbox.create(); const fabric = await init({ sandbox: e2bSandbox(remote, { cleanup: true }), }); const session = await fabric.session(); const result = await session.prompt('Run the supplied Python analysis and summarize the output.'); ``` The adapter maps E2B commands and file operations to the common Fabric sandbox interface. Keep `cleanup: true` for per-session environments. The supported range is `@e2b/code-interpreter >=2.6.1 <3`. Native command callbacks, timeout, pause/resume, binary files, and the provider `sandboxId` are mapped to the Fabric contract. ```ts registerStandardSandboxRefDecoders({ e2b: { connect: ({ sandboxId }) => Sandbox.connect(sandboxId) }, }); ``` Use [`assertSandboxCertification()`](/docs/building/sandbox-connectors#certification-helper) to produce the credentialed, secret-free CI evidence file. ## Environment variables - `E2B_API_KEY` — E2B API key (read lazily at runtime) ## See also - [Deployment overview](/docs/deployment) - [Sandbox connectors](/docs/building/sandbox-connectors#e2b) - [E2B documentation](https://e2b.dev/docs) --- # Fly.io Canonical: https://harness.techfabric.com/docs/deployment/fly Deploy the Fabric Docker target to Fly.io, including the configuration a long-running agent needs to stay up. Generate the Docker artifact, initialize a Fly application from that directory, and configure the internal port as `3000`. ```sh fh build --target docker cd .fabricharness/build/docker fly launch --no-deploy fly secrets set FABRIC_HARNESS_API_TOKEN=... FABRIC_MODEL=... fly deploy ``` Use managed or external Postgres for durable state; do not rely on an ephemeral root filesystem. Restrict public routes, configure health/readiness checks, pin regions and machine resources, and test process restart plus rolling deployment behavior. --- # Foundry Hosted Agents (Azure) Canonical: https://harness.techfabric.com/docs/deployment/foundry-hosted-agent Build scaffolds and invoke Azure AI Foundry Agent Service from TechFabric Harness. Foundry Hosted Agents are TechFabric Harness's primary Azure direction. Fabric supports two related paths: 1. **Build scaffold** — `fh build --target foundry-hosted-agent` emits Docker/azd/Bicep/metadata scaffolding. 2. **Agent Service client/tools** — `@fabric-harness/azure` can invoke and manage Azure AI Foundry Agent Service agents from Fabric agents. Use the build scaffold when packaging a Fabric Node or Temporal worker for Azure-managed compute. Use the Agent Service client when an existing Fabric agent needs to invoke or administer an Azure AI Foundry agent. ## Build scaffold ```sh fh build --target foundry-hosted-agent ``` Output: ```txt .fabricharness/build/foundry-hosted-agent/ Dockerfile azure.yaml foundry-agent.yaml infra/main.bicep dist/server.mjs manifest.json ``` Deploy the scaffold with Azure Developer CLI: ```sh cd .fabricharness/build/foundry-hosted-agent azd up ``` ## Foundry Agent Service client ```ts import { createFoundryAgentServiceClient, foundryAgentTool, } from '@fabric-harness/azure'; const foundry = createFoundryAgentServiceClient({ projectEndpoint: process.env.AZURE_FOUNDRY_PROJECT_ENDPOINT!, agentId: process.env.AZURE_FOUNDRY_AGENT_ID!, token: process.env.AZURE_TOKEN!, }); const fabric = await init({ tools: [foundryAgentTool(foundry)], }); ``` This exposes a Fabric tool named `foundry_agent` with input: ```ts { prompt: string; threadId?: string; } ``` The client performs: 1. create or reuse a thread; 2. add a user message; 3. create a run for the configured agent; 4. optionally poll; 5. return thread/run status and messages. ## Lifecycle tools ```ts import { foundryAgentLifecycleTools } from '@fabric-harness/azure'; const tools = [ ...foundryAgentLifecycleTools(foundry), ]; ``` This exposes: - `foundry_create_agent` - `foundry_update_agent` - `foundry_delete_agent` These are privileged write effects. Gate them with approvals: ```ts const policy = { toolPolicy: { requireApproval: [ 'foundry_create_agent', 'foundry_update_agent', 'foundry_delete_agent', ], }, }; ``` ## Identity and audit model Fabric sessions can record actor identity: ```ts await init({ actor: { agentId: process.env.AZURE_ENTRA_AGENT_ID, onBehalfOf: userId, }, }); ``` Approval entries should record: - the Foundry/Entra agent identity; - the on-behalf-of user; - the approver; - the tool or command being authorized. ## Architecture guidance | Pattern | Use when | |---|---| | Fabric Temporal worker outside Foundry | You need durable replay, retries, and long approval waits. | | Fabric agent invoking Foundry Agent Service | You already have Foundry agents and want Fabric governance/tools around them. | ## Model provider On Azure compute with workload identity, route inference through `FoundryRuntimeModelProvider` instead of configuring `AZURE_OPENAI_API_KEY`: ```ts import { FoundryRuntimeModelProvider } from '@fabric-harness/azure/foundry-runtime'; import { init } from '@fabric-harness/sdk'; const fabric = await init({ modelProvider: new FoundryRuntimeModelProvider({ defaultModel: 'gpt-4o', }), }); ``` Set `AZURE_OPENAI_ENDPOINT` and `AZURE_OPENAI_DEPLOYMENT`; supply `FOUNDRY_AGENT_TOKEN` when your host injects a token. On ACA, AKS, or a VM with managed identity, install `@azure/identity` and the provider falls back to `DefaultAzureCredential`. See [model providers → Foundry runtime](/docs/building/model-providers#foundry-runtime-azure). ## Live test ```sh FABRIC_AZURE_FOUNDRY_TEST=1 \ AZURE_FOUNDRY_PROJECT_ENDPOINT=... \ AZURE_FOUNDRY_AGENT_ID=... \ AZURE_TOKEN=... \ pnpm --filter @fabric-harness/azure test ``` The live test retrieves the configured agent and invokes it with a smoke prompt. Set `FABRIC_AZURE_FOUNDRY_POLL=0` to create the run without polling for completion. ## See also - [Azure overview](/docs/deployment/azure) - [Live tests](/docs/reference/live-tests) - [Capability matrix](/docs/reference/capability-matrix) --- # GitHub Actions Canonical: https://harness.techfabric.com/docs/deployment/github-actions Build, sign and deploy a workspace from GitHub Actions, with the provenance attached that fh builds verify later. A reference workflow that builds the workspace, emits a signed Docker image, and pushes to a registry. ```yaml name: build-agents on: push: branches: [main] jobs: build: runs-on: ubuntu-latest permissions: contents: read id-token: write packages: write steps: - uses: actions/checkout@v7 - uses: pnpm/action-setup@v6 with: version: 10.10.0 - uses: actions/setup-node@v7 with: node-version: 22 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm build - name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build, sign, push agents image env: COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }} run: | ./packages/cli/dist/bin/fabric-harness.js build \ --target docker \ --docker-build --docker-push \ --docker-tag ghcr.io/${{ github.repository }}/agents:${{ github.sha }} \ --image-sbom --image-sbom-required \ --provenance --sign-provenance --signing-key env://COSIGN_PRIVATE_KEY \ --attestation - uses: actions/upload-artifact@v7 with: name: build-manifest path: | .fabricharness/build/docker/manifest.json .fabricharness/build/docker/provenance.json .fabricharness/build/docker/attestation.intoto.jsonl ``` ## CI smoke tests Add a job that runs the agent against the mock model in CI: ```yaml smoke: needs: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: pnpm/action-setup@v6 with: version: 10.10.0 - uses: actions/setup-node@v7 with: node-version: 22 cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm build - run: | cd examples/issue-triage-ci ../../packages/cli/dist/bin/fabric-harness.js doctor --tools ../../packages/cli/dist/bin/fabric-harness.js run triage \ --model openai/gpt-5.5 \ --mock \ --payload-file fixtures/issue-opened.json ``` `--mock` is mandatory in this credential-free smoke job. It prevents provider calls, cost, and nondeterministic model output even though the definition contains a real model identifier. See [`examples/issue-triage-ci`](/docs/reference/source-access) for repository access to the complete read-only triage fixture. ## Keep Actions on supported runtimes GitHub-hosted JavaScript actions must use a supported action runtime independently of the Node.js version your job installs. For example, `actions/setup-node` itself runs on Node 24 while it can still install Node 20.19 or Node 22 for compatibility testing. Fabric's reviewed baseline is: | Action | Supported baseline | |---|---| | `actions/checkout` | `v7` | | `actions/setup-node` | `v7` | | `actions/upload-artifact` | `v7` | | `actions/attest` | `v4` | | `pnpm/action-setup` | `v6` | Run `pnpm check:github-actions` before landing workflow or documentation changes. The check rejects older Node-runtime majors, deprecated attestation wrappers, an outdated reviewed Databricks CLI pin, the checksum-pinned Gitleaks CLI release used by the supply-chain workflow, and attempts to restore obsolete runtimes with `ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION`. Fabric runs the open-source Gitleaks `v8.30.1` CLI directly from its checksum-verified release archive. The current `gitleaks/gitleaks-action` requires a commercial license for organization-owned repositories, so it is not used as a portable default. The repository also enables weekly Dependabot checks for the `github-actions` ecosystem. Treat those PRs as runtime and supply-chain updates: read the action's official release notes, update the policy baseline and examples in the same change, run CI, and verify self-hosted runners meet the action's minimum runner version. The current Node 24 actions require runner `2.327.1` or newer. Major tags keep official actions on security and patch updates within the reviewed compatibility line. Pin third-party actions to a full commit SHA in secret-bearing or deployment workflows, and keep the human-readable release tag in the comment beside the pin. Use `${{ github.sha }}` or `${{ github.run_id }}` in artifact names rather than `${{ github.ref_name }}`. Branch ref names can contain `/`, which current `upload-artifact` releases reject in portable artifact names. ## Protected live evidence Keep destructive or credentialed certification in a GitHub Environment with required reviewers and protected deployment branches. Fabric's hosted-sandbox jobs use `sandbox-live`; direct DeepSeek, Moonshot, and xAI smoke tests use `model-providers-live`. A missing secret may skip an optional smoke, but it cannot create retained certification evidence. For hosted sandboxes, run `scripts/validate-sandbox-certification.mjs` before upload. The validator requires credentials, all nine checks, the declared package and SDK target, and the actually installed package version. It emits a digest manifest and immutable Actions run URL. Retain both the report and manifest for review. The ordinary CI workflow also runs `pnpm test:coverage:authoring` and uploads its LCOV/JSON summary. Do not publish Databricks authoring packages if that gate, `docs:impact`, `docs:check`, or `docs:build` fails. --- # GitLab CI Canonical: https://harness.techfabric.com/docs/deployment/gitlab-ci Build, sign and deploy a workspace from GitLab CI, with the provenance attached that fh builds verify later. A reference `.gitlab-ci.yml` that mirrors the GitHub Actions pipeline. ```yaml stages: - install - build - smoke - deploy variables: PNPM_VERSION: "10.10.0" install: stage: install image: node:22 script: - npm install -g pnpm@${PNPM_VERSION} - pnpm install --frozen-lockfile cache: key: files: - pnpm-lock.yaml paths: - node_modules - .pnpm-store build: stage: build image: node:22 needs: [install] script: - npm install -g pnpm@${PNPM_VERSION} - pnpm install --offline - pnpm build - ./packages/cli/dist/bin/fabric-harness.js build --target docker artifacts: paths: - .fabricharness/build/docker/ smoke: stage: smoke image: node:22 needs: [build] script: - npm install -g pnpm@${PNPM_VERSION} - pnpm install --offline - cd examples/issue-triage-ci - ../../packages/cli/dist/bin/fabric-harness.js run triage \ --model openai/gpt-5.5 \ --mock \ --payload-file fixtures/issue-opened.json publish: stage: deploy image: docker:27 services: - docker:27-dind needs: [build] rules: - if: '$CI_COMMIT_BRANCH == "main"' script: - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY" - cd .fabricharness/build/docker - docker build -t "$CI_REGISTRY_IMAGE/agents:$CI_COMMIT_SHA" . - docker push "$CI_REGISTRY_IMAGE/agents:$CI_COMMIT_SHA" ``` The same provenance and attestation flags work — wire `COSIGN_PRIVATE_KEY` into the GitLab masked variables and add the appropriate flags to the `build` stage. --- # Modal Canonical: https://harness.techfabric.com/docs/deployment/modal Run serverless GPU and CPU tasks from Fabric sessions through Modal's native TypeScript SDK. TechFabric Harness runs its Node runtime in your application and sends sandbox work to a native Modal `Sandbox`. The adapter never serializes the Modal client or its credentials into session history. ## Install ```sh pnpm add @fabric-harness/connectors modal ``` ## Connect a sandbox ```ts import { ModalClient } from 'modal'; import { modalSdkSandbox } from '@fabric-harness/connectors/modal'; const client = new ModalClient(); const app = await client.apps.fromName('fabric-harness', { createIfMissing: true }); const image = client.images.fromRegistry('node:22-alpine'); const remote = await client.sandboxes.create(app, image, { timeoutMs: 300_000, workdir: '/workspace', // gpu: 'A10G', // outboundDomainAllowlist: ['api.example.internal'], }); const sandbox = modalSdkSandbox(remote, { cleanup: true }); try { const fabric = await init({ sandbox }); const session = await fabric.session(); await session.prompt('Run the compute task and return the generated artifact.'); } finally { await sandbox.cleanup(); client.close(); } ``` `modalSdkSandbox()` supports streamed stdout/stderr, exact binary files, cwd/env, timeout and abort settlement, portable `sandboxId` references, reconnect, and verified termination. ## Reconnect after worker rotation ```ts registerStandardSandboxRefDecoders({ modal: { connect: ({ sandboxId }) => client.sandboxes.fromId(sandboxId!), }, }); ``` Persist the result of `session.sandboxRef({ portable: true })`; it contains the sandbox ID and Fabric capability metadata, never Modal tokens. ## Environment variables - `MODAL_TOKEN_ID`: Modal token ID. - `MODAL_TOKEN_SECRET`: Modal token secret. - `MODAL_APP_NAME`: optional application name used by the runnable example. - `MODAL_IMAGE`: optional container image used by the runnable example. Run the credentialed contract with: ```sh FABRIC_MODAL_TEST=1 MODAL_TOKEN_ID=... MODAL_TOKEN_SECRET=... \ pnpm --filter @fabric-harness/connectors test ``` ## See also - [Sandbox connectors](/docs/building/sandbox-connectors#modal) - [Private networking](/docs/operating/private-networking) - [Modal documentation](https://modal.com/docs) --- # Node Canonical: https://harness.techfabric.com/docs/deployment/node Build and run the shared v2 HTTP server as a self-contained Node artifact. The Node target is the simplest production artifact. It packages finite jobs, persistent agents, roles, skills, configuration, and the same HTTP server used by `fh dev`. ## Build ```sh fh build --target node ``` Output: ```text .fabricharness/build/node/ .fabricharness/ jobs/*.mjs agents/*.mjs roles/ skills/ dist/ jobs/*.mjs agents/*.mjs server.mjs manifest.json package.json ``` Definitions are bundled into `.mjs` modules so the runtime can discover them dynamically without depending on the source workspace. ## Run ```sh PORT=8080 OPENAI_API_KEY="$OPENAI_API_KEY" \ node .fabricharness/build/node/dist/server.mjs ``` The server binds `0.0.0.0:3000` by default for container compatibility. ## Invoke a finite job ```sh curl http://localhost:8080/jobs/ask \ -H 'content-type: application/json' \ -d '{"question":"What is durable execution?"}' ``` The default invocation waits for settlement and the response includes `{ result, runId }`. Pass `?wait=false` for a `202 { runId, status, statusUrl, eventsUrl }` queue receipt. ## Invoke a persistent agent ```sh curl -i http://localhost:8080/agents/support/customer-42 \ -H 'content-type: application/json' \ -d '{"message":"Help me understand my bill."}' ``` The default response is `202 { submissionId, streamUrl, offset }`. Add `?wait=true` only when a synchronous bridge is required. Prefer `@fabric-harness/client` for waiting and offset streaming. ## Core routes | Method | Route | Purpose | | --- | --- | --- | | `GET` | `/health` | Liveness probe. | | `GET` | `/ready` | Readiness and workspace root. | | `GET` | `/admin/agents` | List finite jobs and persistent agents with kind. | | `POST` | `/jobs/:name` | Invoke a finite job. | | `POST` | `/agents/:name/:id` | Admit persistent input; `202` by default. | | `POST` | `/agents/:name/:id/dispatch` | Enqueue asynchronous persistent input. | | `GET` | `/agents/:name/:id/conversation` | Read conversation batches by offset. | | `GET` | `/agents/:name/:id/stream?offset=...` | Catch up and tail with SSE. | | `GET` | `/agents/:name/:id/submissions/:submissionId` | Read settlement status. | | `POST` | `/agents/:name/:id/abort` | Request durable abort. | | `GET` | `/sessions` | List persisted sessions. | | `GET` | `/builds/:target/manifest` | Read a build manifest under the workspace build directory. | ## Environment | Variable | Purpose | | --- | --- | | `PORT` | Listen port; default `3000`. | | `DATABRICKS_APP_PORT` | Takes precedence over `PORT` in a generated App artifact. | | `FABRIC_HARNESS_HOST` | Listen address; default `0.0.0.0`. | | `FABRIC_HARNESS_API_TOKEN` | Bearer token for HTTP and WebSocket access; required for protected routes in production unless a custom authorizer is installed. | | `FABRIC_HARNESS_MAX_BODY_BYTES` | JSON/body limit; default 1 MiB. | | `FABRIC_HARNESS_RATE_LIMIT_MAX` | Per-process request limit; `0` disables it. | | `FABRIC_HARNESS_RATE_LIMIT_WINDOW_MS` | Rate-limit window; default 60 seconds. | | `FABRIC_HARNESS_TENANT_REQUIRED=1` | Require `X-Fabric-Tenant`. | ## Production exposure When `NODE_ENV=production` or `FABRIC_ENV=production`, public job and agent routes require `triggers.webhook: true`. Authentication and triggers serve different purposes: the bearer token identifies an allowed caller, while the trigger opts a definition into public HTTP exposure. ```sh NODE_ENV=production \ FABRIC_HARNESS_API_TOKEN="$API_TOKEN" \ node dist/server.mjs ``` ## Container wrapper Copy the complete build directory, not only `dist/`; the embedded workspace contains discoverable definitions, roles, skills, and runtime configuration. ```dockerfile FROM node:22-slim WORKDIR /app COPY . . ENV NODE_ENV=production PORT=8080 EXPOSE 8080 CMD ["node", "dist/server.mjs"] ``` For a generated container and optional image build, use the [Docker target](/docs/deployment/docker). For the full job/agent walkthrough, see [Build and run artifacts](/docs/deployment/build-artifacts). --- # Portable Agent Packages Canonical: https://harness.techfabric.com/docs/deployment/portable-packages Build self-contained agent artifacts that can be handed from an application repository to Databricks, Runway, or another deployment system. A portable agent package is the complete directory emitted by `fh build`. It is a deployment artifact—not an npm package—and is the supported boundary between the repository that authors an agent and the system that deploys it. Consumers stage the directory without cloning the producer repository, resolving its pnpm workspace, or publishing private shared-contract packages. This is useful when one repository owns agent definitions and another owns infrastructure. For example, Fabric GTM Brain can build its jobs once and TechFabric Runway can stage that output into a Unity Catalog Volume before deploying a Databricks App. ## Build the package Run the command from the package that owns `.fabricharness/`: ```sh pnpm exec fh build --target databricks-app ``` Expected output: ```text Build complete Output .fabricharness/build/databricks-app Manifest .fabricharness/build/databricks-app/manifest.json Jobs artifact-generator, campaign-reviewer ``` Use `--target node` for a generic server artifact. Docker, Kubernetes, Azure, Render, Foundry, and Databricks App targets inherit the same definition-bundling behavior from `@fabric-harness/node`. ## What is self-contained Harness bundles each discovered job or persistent agent into an `.mjs` module and bundles the shared v2 HTTP server. A Databricks App artifact includes: ```text .fabricharness/build/databricks-app/ .fabricharness/ config.mjs jobs/*.mjs agents/*.mjs roles/ skills/ dist/ jobs/*.mjs agents/*.mjs server.mjs app.yaml databricks.yml Dockerfile manifest.json package.json DATABRICKS_APP_DEPLOY.md ``` The package contains: - agent and job implementation code; - workspace-owned TypeScript contracts and barrel exports imported by those definitions; - the Harness server and definition loader needed by the selected target; - roles, skills, generated configuration, route metadata, and trigger declarations; and - target descriptors such as `app.yaml`, `databricks.yml`, or a Dockerfile. The manifest records every definition name, kind, trigger, relative entrypoint, and SHA-256 digest. External staging systems should treat the entire output directory as one immutable unit. Databricks App definition bundles are minified without source maps so workspace snapshot export can consume them directly. Harness verifies the 10 MiB Databricks per-file limit for every emitted job, persistent agent, and server bundle during `fh build`; an oversized definition fails the build before the artifact can be handed to Runway or deployed. ## Monorepo contracts Agent packages commonly import schemas from a sibling workspace package: ```ts title=".fabricharness/jobs/campaign-reviewer.ts" import { campaignReviewInput } from '@acme/gtm-agent-contracts'; import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent({ name: 'campaign-reviewer', input: campaignReviewInput, triggers: { webhook: true }, async run({ input }) { return { campaignId: input.campaignId, approved: true }; }, }); ``` ```json title="agents/package.json" { "dependencies": { "@acme/gtm-agent-contracts": "workspace:*", "zod": "catalog:" } } ``` Harness follows dependencies resolved through `workspace:`, `catalog:`, `file:`, `link:`, `portal:`, and `patch:`. Their executable code is bundled and those source-only specifiers are omitted from the generated runtime `package.json`. TypeScript barrels and extensionless workspace imports are resolved during the build, before metadata is read from the emitted definition. Registry dependencies that the target deliberately keeps external remain in `package.json`. Install only those declared dependencies in the detached directory. Do not copy the producer's `node_modules` tree. ## Verify detachment At minimum, make the handoff fail if a source-only protocol or private workspace import remains: ```sh artifact=.fabricharness/build/databricks-app test -s "$artifact/manifest.json" test -s "$artifact/dist/server.mjs" test -s "$artifact/app.yaml" test -s "$artifact/databricks.yml" if grep -R -E '"(workspace|catalog|file|link|portal|patch):' "$artifact/package.json"; then echo 'source-only dependency escaped into the runtime package' >&2 exit 1 fi jq -e '.schemaVersion == 2 and (.jobs | type == "array") and (.agents | type == "array")' \ "$artifact/manifest.json" >/dev/null ``` For a stronger isolation test, copy the artifact outside both repositories and start it without the producer workspace on Node's resolution path: ```sh detached="$(mktemp -d)" cp -R .fabricharness/build/databricks-app/. "$detached/" cd "$detached" npm install --omit=dev PORT=8080 node dist/server.mjs ``` The server may then fail because a required runtime binding is absent—for example Lakebase, `FABRIC_HARNESS_API_TOKEN`, or a model provider credential. That is a deployment-configuration failure, not a packaging failure. A module-resolution error for a workspace package is a packaging failure. ## Hand off to Runway or another deployer The consumer receives only the built directory plus an immutable content digest: ```sh tar -C .fabricharness/build -czf gtm-agents-databricks-app.tgz databricks-app sha256sum gtm-agents-databricks-app.tgz > gtm-agents-databricks-app.tgz.sha256 ``` A deployment system can unpack it, validate `manifest.json`, calculate its own directory digest, and stage the files in an artifact store or Unity Catalog Volume. It must not rebuild agent source, rewrite bundled definitions, or resolve the producer's workspace packages. Environment-specific Databricks resource names and secrets are applied after staging. The artifact is safe to cache by digest. Rebuilding can change generated timestamps or archive bytes, so evidence should bind the exact directory or archive supplied to the deployer rather than assuming two independent builds are byte-identical. ## Databricks runtime bindings Self-contained describes code and package resolution; it does not embed credentials or managed resources. Bind these at deployment time as needed: - App OAuth M2M identity and allowed principals; - OBO user authorization for per-user governance; - Lakebase host, database, endpoint, and credential exchange; - Genie Agent, SQL warehouse, Unity Catalog, and MLflow resources; and - model-provider or AI Gateway configuration. `fh doctor` and the generated Databricks bundle fail closed when the App claims Lakebase or Genie without the corresponding resource binding. Secrets remain references and are never copied into the bundle or model context. ## Failure behavior The build fails before producing a successful manifest when: - an agent definition cannot be bundled or imported from its emitted module; - a workspace dependency cannot be resolved; - two definitions produce an invalid or conflicting public name; or - the target cannot generate its required runtime files. Deployment verification should fail when: - `manifest.json`, the server entrypoint, or target descriptors are missing; - a source-only dependency protocol remains in the generated package; - manifest hashes do not match the shipped definitions; - a production route lacks `triggers.webhook: true`; or - the detached process still imports a private producer package. For the Databricks production path, also require `/api/health`, `/api/ready`, finite-job lifecycle, restart recovery, and any claimed Lakebase/Genie/OBO behavior before promotion. See [Build and run artifacts](/docs/deployment/build-artifacts), [Databricks App deployment](/docs/deployment/databricks-app), and [Build manifest](/docs/reference/build-manifest). --- # Railway Canonical: https://harness.techfabric.com/docs/deployment/railway Deploy a Fabric Docker artifact on Railway, including the environment and networking a persistent agent expects. Point a Railway service at the Docker build artifact or repository Dockerfile and expose port `3000`. Set `NODE_ENV=production`, `FABRIC_HARNESS_API_TOKEN`, model credentials, and `DATABASE_URL` through Railway variables. Use Postgres for durable sessions/submissions and object storage for large artifacts. Configure `/health` and `/ready`, resource limits, private service networking, and restart/redeploy recovery checks. --- # Render Canonical: https://harness.techfabric.com/docs/deployment/render Deploy a TechFabric Harness HTTP server to Render as a Web Service via Blueprint. Render is a one-click PaaS that runs containers (Web Services), Cron Jobs, and Postgres. The TechFabric Harness Render target emits a Blueprint (`render.yaml`) plus a Dockerfile so you can deploy with no Render-specific code. ## Quickstart ```sh fabric-harness build --target render # Output: .fabricharness/build/render/{Dockerfile, render.yaml, RENDER_DEPLOY.md, dist/, ...} ``` Push the bundle to a Git repo, then create a new Web Service on Render pointing at it. Render auto-detects `render.yaml` and provisions the service. ## What ends up in the bundle | File | Purpose | |---|---| | `Dockerfile` | Standard Node 22 container image. | | `render.yaml` | Blueprint declaring a `runtime: docker` Web Service with `/health` healthcheck. | | `RENDER_DEPLOY.md` | Per-bundle deployment notes (env vars, Postgres setup). | | `dist/server.mjs` | The TechFabric Harness HTTP server entry point. | ## Required environment variables Set these in the Render dashboard (or via Blueprint env groups): - `OPENAI_API_KEY` (or other provider keys, depending on your model config) - `DATABASE_URL` — Postgres DSN (Render's managed Postgres works directly) - `FABRIC_HARNESS_SESSION_STORE=postgres` ## Why Postgres for the session store? Render restarts containers and resets the local disk on every redeploy. The default `FileSessionStore` will lose state. Provision a Render Postgres instance and use `PostgresSessionStore` (selected via `FABRIC_HARNESS_SESSION_STORE=postgres` + `DATABASE_URL`). For session histories you can afford to lose (e.g. one-shot CI agents), `InMemorySessionStore` is fine — no Postgres required. ## Health check Render probes `/health` by default; the TechFabric Harness HTTP server exposes that route automatically. No code changes needed. ## When to use Render vs other targets | Pick Render when… | Pick another target when… | |---|---| | You want one-click deploys without managing Kubernetes / containers | You need durable workflows → use `--target temporal-worker` | | Your agent is HTTP-shaped (webhook, REST) | Your agent runs on the edge → use `--target cloudflare` | | You want managed Postgres alongside the app | You're on Azure / AWS / GCP → use `--target aca` / `--target aks` / Docker on ECS | ## Cost sanity Render's free tier sleeps after 15 minutes of inactivity. For production, use Starter (always-on) or higher. Per-call cost telemetry shows up in `fh metrics --breakdown` so you can size your plan correctly. ## See also - [Docker target](/docs/deployment/docker) - [Cost telemetry](/docs/building/model-providers#per-call-cost-telemetry) --- # SST Canonical: https://harness.techfabric.com/docs/deployment/sst Deploy Fabric Node or Docker artifacts with SST-managed AWS infrastructure. Use SST to provision an AWS container service around the Fabric Docker target; do not place the long-running HTTP server in a short-lived function without redesigning durable admission and streaming. Build with `fh build --target docker`, publish the immutable image, and pass secrets through SST/AWS secret bindings. Use VPC networking, task roles, external Postgres, explicit autoscaling and health checks, authenticated production routes, and OpenTelemetry export. Verify that rolling replacement preserves submissions and conversation streams. --- # Temporal Worker Canonical: https://harness.techfabric.com/docs/deployment/temporal-worker Run agent sessions as durable Temporal workflows, so a multi-hour run survives a deploy, a crash or a restart. The Temporal worker target turns sessions into durable Temporal workflows. Prompts, skills, tasks, shell calls, checkpoints, approvals, and cancellation all route through the `SessionRuntime` boundary; deterministic workflow code orchestrates state, and nondeterministic work happens in activities. Use this target for long-running jobs, approval delays, and restart durability. Before rollout, validate namespace authentication, gRPC readiness, worker restart, workflow replay, activity retry, and approval resumption against the Temporal environment you operate. ## Build the worker artifact ```sh fh build --target temporal-worker ``` Output: ``` .fabricharness/build/temporal-worker/ dist/worker.mjs package.json manifest.json ``` The artifact bundles Harness runtime code and declares `@temporalio/client`, `@temporalio/worker`, and `@temporalio/workflow` in its generated `package.json`. Install production dependencies in the artifact directory before moving it to an isolated host or container; do not depend on a monorepo's hoisted `node_modules` layout. ```sh cd .fabricharness/build/temporal-worker npm install --omit=dev node dist/worker.mjs ``` ## Run the worker You can run the prebuilt artifact: ```sh node .fabricharness/build/temporal-worker/dist/worker.mjs ``` Or run a worker against the live workspace (great for development): ```sh fh temporal-worker --task-queue fabric-harness --address localhost:7233 ``` ## Drive an agent on the worker ```sh fh run ask --target temporal-worker --id ask-001 --prompt "What is Temporal?" ``` The CLI: 1. Connects to Temporal, 2. Starts (or resumes) the session workflow with id `ask-001`, 3. Signals it with the prompt, 4. Streams output back. ## Workflow model ```mermaid graph LR A[Session workflow] --> P[Prompt/skill/task request] A --> M[Model activity] A --> T[Tool activity] A --> S[Shell activity] A --> C[Checkpoint activity] A --> W{Approval needed?} W -->|yes| SIG[Wait for approval signal] SIG --> T W -->|no| R[Append result] ``` ### What operators verify Temporal Web or the equivalent history API should show the accepted request, activity attempt, worker interruption, replay, and terminal result. The representative history below makes the no-duplicate-effect expectation explicit. ## Supported runtime operations | Capability | Temporal path | | --- | --- | | `session.prompt()` | Durable workflow request + model/tool activities | | `session.skill()` | Same prompt runtime with skill-loaded instructions | | `session.task()` | Durable task request; child-workflow shape where configured | | `session.shell()` | Shell activity through the selected sandbox | | Checkpoint create/restore | Activity-backed when the sandbox reports support | | Approvals | Workflow waits on approval signals; no worker thread is held | | Cancellation | Workflow/activity cancellation is propagated where provider APIs support it | | Worker restart | Workflow state survives; activities are idempotency-keyed | | Attachments | Stored through the configured durable attachment/session store and remain addressable across worker rotation | | Tenant/cost/audit events | Model-attempt entries include usage and cost; tenant and operation records remain store-backed | Unsupported inline-only features should fail with explicit runtime errors rather than silently degrading. Cancel from the same `AbortSignal` used by the lightweight runtime. Fabric removes the signal and callbacks before serializing workflow input, then cancels the owning workflow when the signal fires: ```ts const controller = new AbortController(); const pending = session.prompt('Build the report', { signal: controller.signal }); controller.abort(new DOMException('Operator cancelled', 'AbortError')); await pending; // rejects with AbortError ``` ## Configuration `.fabricharness/config.ts`: ```ts export default { temporal: { address: 'localhost:7233', taskQueue: 'fabric-harness', namespace: 'default', workflowIdPrefix: 'fabric', promptWorkflowMode: 'hybrid', apiKeyEnv: 'TEMPORAL_API_KEY', // for Temporal Cloud tls: { /* ... */ }, }, }; ``` Environment overrides: | Variable | Purpose | | --- | --- | | `FABRIC_TEMPORAL_ADDRESS` | host:port | | `FABRIC_TEMPORAL_TASK_QUEUE` | task queue name | | `FABRIC_TEMPORAL_NAMESPACE` | namespace | | `FABRIC_TEMPORAL_CONNECT_ATTEMPTS` | Optional bounded retry attempts for client/worker connection startup. | | `FABRIC_TEMPORAL_CONNECT_INITIAL_DELAY_MS` | Optional first retry delay in milliseconds. | | `FABRIC_TEMPORAL_CONNECT_MAX_DELAY_MS` | Optional max retry delay in milliseconds. | ## Temporal Cloud Set `address` to your Temporal Cloud endpoint, configure mTLS or API key, and the worker connects normally: ```ts export default { temporal: { address: 'my-namespace.tmprl.cloud:7233', namespace: 'my-namespace', apiKeyEnv: 'TEMPORAL_API_KEY', tls: { serverName: 'my-namespace.tmprl.cloud' }, }, }; ``` ## Operational notes - Workers are stateless. Run several behind your task queue for throughput. - Approval waits are signal-driven and consume no worker time. - Use Temporal's UI or `temporal workflow show` to inspect history independently of `fh inspect`. - Keep default unit/mock Temporal tests in main CI and run the live conformance suite on the scheduled workflow. It covers prompt, skill, child task, shell, checkpoint, tool and custom approvals, cancellation, activity retry, attachments, usage/cost, and worker restart. For local `temporalio/auto-setup` with Postgres, set `DB_PORT=5432` and wait for a real gRPC connection rather than only checking the TCP port. - For production, test worker restart while a workflow is waiting for approval, retry behavior for failed activities, namespace/auth configuration, and cancellation of long shell/model work. --- # Ecosystem Canonical: https://harness.techfabric.com/docs/ecosystem Tools that extend TechFabric Harness development, evaluation, and operations. TechFabric Harness integrations use normal TypeScript packages and the same job, agent, session, sandbox, and eval APIs as the core framework. This catalog lists integrations backed by current code, a tested structural adapter, or an explicit project-local recipe. The [targets matrix](/docs/ecosystem/targets) lists every sandbox backend and deployment target with its adapter or driver, runnable example, credential-free path, and validation. ## Catalog | Category | First-party surface | Guides | | --- | --- | --- | | [Channels](/docs/ecosystem/channels) | 17 signed first-party adapters across chat, support, commerce, billing, knowledge, and email. | Provider setup and outbound tools. | | [Sandboxes](/docs/ecosystem/sandboxes) | Databricks SQL, Cloudflare, Daytona, E2B, Modal, Vercel, Kubernetes, and the generic remote adapter. | SQL, code, edge, and remote sandbox guides. | | [Databases](/docs/ecosystem/databases) | Postgres/Lakebase stores plus Postgres, MySQL, MongoDB, Redis, and SQLite governed tools. | libSQL, Supabase, Turso, and Valkey guides. | | [Tooling](/docs/ecosystem/tooling) | Fabric evals and OpenTelemetry hooks. | Braintrust, Jetty, OpenTelemetry, Sentry, and Vitest evals. | | [Deployment](/docs/deployment) | Node, Docker, Cloudflare, Azure, Databricks, Render, Kubernetes, and Temporal targets. | Deployment catalog | ## Tooling - [Jetty](/docs/ecosystem/tooling/jetty) grades job output with a separately deployed rubric and stores comparable trajectories. - [Fabric evals](/docs/building/evals) runs deterministic and model-judged quality gates locally or in CI. ## Add integrations `fh add` exposes two explicit modes: ```sh fh add # browse the full recipe catalog fh add --json # machine-readable catalog fh add channel slack # scaffold files directly fh add daytona --print # print a guide for a coding agent fh add daytona | codex # apply the guide with Codex fh add discord --install-deps | codex # install declared dependencies, then apply the guide ``` A scaffold recipe writes files and tests and installs missing dependencies through the detected package manager. `--no-install` updates the manifest only. A connector guide is Markdown for adapting a provider SDK to the current project; `--install-deps` installs its cataloged dependencies before emitting the guide. The catalog labels each entry so these paths are not confused. Keep external credentials in environment variables or secret managers. Do not place them in prompts, job inputs, session history, or uploaded evaluation files. --- # Buzz Canonical: https://harness.techfabric.com/docs/ecosystem/channels/buzz Connect a Buzz Nostr relay to a durable Fabric agent with authenticated forwarding. Buzz is a preview first-party channel adapter. A reconnecting Nostr tail subscribes to the relay and forwards events to the ordinary Fabric HTTP channel route through a timestamped HMAC envelope. The route verifies both that envelope and the inner Schnorr-signed event before dispatching. ```sh fh add channel buzz ``` The recipe creates `.fabricharness/channels/buzz.ts` and `.fabricharness/state/buzz.ts`, and `.fabricharness/transports/buzz-tail.ts`. Recipe v3 wires content-free lifecycle and operational evidence in addition to durable state. Start the Fabric server first, then start the tail from the same trusted deployment boundary: ```ts import { createBuzzTail } from './.fabricharness/transports/buzz-tail.js'; const tail = createBuzzTail(); process.once('SIGTERM', () => tail.close()); process.once('SIGINT', () => tail.close()); ``` Configure: - `BUZZ_RELAY_URL` — the `ws:` or `wss:` relay endpoint. - `BUZZ_PRIVATE_KEY` — the adapter identity's 64-character lowercase hexadecimal secret key. - `BUZZ_COMMUNITY` — the tenant boundary forwarded with each event. - `BUZZ_FORWARD_URL` — the absolute Fabric `/channels/buzz/events` route. - `BUZZ_SHARED_SECRET` — an independently generated secret shared only by the tail and route. - `BUZZ_AGENT` — the persistent agent name, defaulting to `assistant`. - `BUZZ_CONSUMER_ID` — stable identity for this deployed tail and its durable state. - `DATABASE_URL` or standard `PG*` variables — PostgreSQL/Databricks Lakebase connection. Run the first-class integration preflight before starting or deploying the tail: ```sh fh doctor --target buzz --json fh doctor --target buzz --live ``` The default check is network-free and fails closed for unsafe transport, placeholder credentials, empty or duplicate channel scope, process-memory state, and obsolete recipe wiring. `--live` adds a bounded, read-only certification pass: NIP-11 capability discovery, signed NIP-98 queries, NIP-01 integrity verification, relay and configured-channel membership, plus Lakebase/PostgreSQL cursor, dead-letter, and decision-delivery health. Reports redact all private keys, forwarding secrets, database connection strings, passwords, and event content. Configure the SLO with `BUZZ_MAX_RELAY_LAG_SECONDS`, `BUZZ_MAX_CURSOR_AGE_SECONDS`, and `BUZZ_MAX_DEAD_LETTERS`. Use the same server-owned channel allowlist in the tail and route. Applications that post governed decision cards must inject the lookup view of the same durable delivery store used by `postBuzzDecisionCard()` into the route: ```ts import { buzzPublicKey, createBuzzChannel } from '@fabric-harness/channels/buzz'; import { buzzState } from '../state/buzz.js'; const channels = (process.env.BUZZ_CHANNELS ?? '').split(',').filter(Boolean); export default createBuzzChannel({ agent: process.env.BUZZ_AGENT ?? 'assistant', sharedSecret: process.env.BUZZ_SHARED_SECRET ?? '', selfPubkey: buzzPublicKey(process.env.BUZZ_PRIVATE_KEY ?? ''), community: process.env.BUZZ_COMMUNITY ?? 'local', channels, decisionReceiptStore: buzzState.deliveryStore, onLifecycleEvent(notice) { console.info(JSON.stringify({ integration: 'buzz', ...notice })); }, }); ``` Use the built-in PostgreSQL/Lakebase implementation for production bridge state: ```ts import { createPostgresBuzzPersistence } from '@fabric-harness/channels/buzz-postgres'; import { Pool } from 'pg'; export const buzzState = createPostgresBuzzPersistence({ client: new Pool({ connectionString: process.env.DATABASE_URL }), consumerId: process.env.BUZZ_CONSUMER_ID ?? 'buzz-primary', }); ``` It owns the monotonic tail cursor, unresolved dead-letter backlog, and exact signed decision-card deliveries. It works with `pg.Pool` and Lakebase clients through a narrow `query()` contract, without adding PostgreSQL or Databricks dependencies to core channel authoring. The generated recipe uses this store and refuses to start its tail without a database. Applications whose migration system owns DDL can set `initialize: false` and call `ensurePostgresBuzzTables()` during migration. `inspectPostgresBuzzHealth()` provides the same content-free, read-only evidence surface used by the live doctor. It never selects stored event or card payloads, making it suitable for a least-privilege Lakebase certification principal. ## Protocol lifecycle The default tail observes stock Buzz message edits, NIP-09/NIP-29 event deletions, and channel deletions along with messages and reactions. These lifecycle events never enter agent or model input. The optional `onLifecycleEvent` callback receives only event ids, author pubkey, kind, channel scope, target ids, and `decisionEffect: "none"`. A removed reaction is therefore audit evidence; it cannot reverse a decision already committed by TechFabric Platform. `BUZZ_PROTOCOL_SUPPORT` is the machine-readable compatibility policy. Channel/forum messages and reactions dispatch; edits and deletions are observe-only; membership is re-checked by the governed application action at decision time. Direct messages, media, voice, and free-form approval editing remain unsupported. The stable instance key is `(community, channel, thread root)`. Relay event IDs become durable deduplication keys, author public keys become candidate actors, and events authored by the adapter identity are ignored to prevent reply loops. Candidate identities do not grant authority: resolve an active application binding and re-check the applicable capability grant before any governed action. Outbound helpers include `postInBuzzChannel()`, `replyInBuzzThread()`, `addBuzzReaction()`, and `postBuzzDecisionCard()`. Decision-card posting first persists the exact signed event and receipt, retries that event id after failure, and queries the relay after ambiguous I/O. In channels 0.19+, pass `deliveryStore` rather than the former `receiptStore` when creating this tool. Stock Buzz Desktop reactions contain an `e` target but no `h` channel tag. The route accepts that shape only when the target resolves to exactly one persisted card receipt in the configured channels, then derives the channel from the receipt. Missing and ambiguous matches are ignored, while receipt-store failures remain retryable delivery failures. This correlation recovers transport scope only; it grants no authority. The application must still resolve the attested pubkey, check membership and capability, validate expiry and pinned request state, and commit through its governed compare-and-swap action. This receipt-aware path is also the supported external handoff for approval requests raised by Databricks App-principal schedules, which are intentionally invisible to user-tenant approval discovery. The application's governed approval record associated with the card receipt must retain the exact scheduler session and approval ids and resolve the approved reaction through the normal stored approval boundary. A card is not a second authorization system, and a free-form reply is never an approval. Keep the private key and forwarding secret out of agent definitions, model context, logs, and persistent state. Use TLS in production and close the tail during shutdown so reconnect attempts stop cleanly. The tail pages complete restart snapshots, enforces relay-advertised limits, propagates cancellation and request timeouts, and fails closed when durable state or backfill is unavailable. Persist poison events through `deadLetterStore` and run `reconcileBuzzDeadLetters()` from a bounded scheduled worker; successful replay is acknowledged only after the normal ingress/governed path returns. The tail's `onOperationalEvent` callback reports content-free backfill counts, forwarding outcomes, authentication renewal, reconnect attempts, and shutdown. Callback failures go to `onError` and do not interrupt the durable consumer. The live Buzz doctor adds cursor lag/age, dead-letter depth, and decision-card delivery counts from PostgreSQL/Lakebase. ## Reconcile the dead-letter backlog Preview a bounded batch, then replay it through the ordinary HMAC-signed, Schnorr-verified ingress route: ```sh fh buzz reconcile --dry-run --limit 100 fh buzz reconcile --limit 100 --json ``` The command uses `BUZZ_CONSUMER_ID`, the configured PostgreSQL/Lakebase connection, relay/community, forward URL, and shared secret. It stops on the first unsuccessful replay, leaves that and later records unresolved, and acknowledges each earlier record only after a 2xx response. Its report contains counts and the consumer id, never stored event content. The limit must be between 1 and 1,000, and each HTTP request is time-bounded. Databricks is first-class for the Fabric application side: use Lakebase for bridge state, Databricks service-principal/OBO boundaries for application access, and the existing Harness Databricks deployment/certification paths. The stock Buzz relay itself remains a separately pinned OCI/Kubernetes workload; Databricks Apps is not a compatible host for its NIP-42/WebSocket and image lifecycle requirements. --- # Discord Canonical: https://harness.techfabric.com/docs/ecosystem/channels/discord Dispatch verified Discord interactions and messages to persistent agents. Use the adapter from `@fabric-harness/channels/discord`. Scaffold it with: ```sh fh add channel discord ``` ```ts import { createDiscordChannel } from '@fabric-harness/channels/discord'; export default createDiscordChannel({ applicationId: process.env.DISCORD_APPLICATION_ID!, publicKey: process.env.DISCORD_PUBLIC_KEY!, agent: 'assistant', }); ``` Mount the generated route as `POST /channels/discord/interactions`. The adapter verifies Discord's Ed25519 signature over the timestamp and exact body, answers interaction pings, deduplicates by interaction ID, uses the guild as tenant, records the Discord user as `onBehalfOf`, and keys the persistent instance by application/guild/channel/thread. Bind `replyInDiscord(ref, { botToken })` as a write-effect tool for outbound messages. Keep moderation actions in separate approval-gated tools. Configure the Discord interaction URL to `/channels/discord/interactions` and validate OAuth scopes and the production bot installation before rollout. --- # GitHub Canonical: https://harness.techfabric.com/docs/ecosystem/channels/github Dispatch signed GitHub issue and pull-request events to a persistent agent. ```ts title=".fabricharness/channels/github.ts" import { createGitHubChannel } from '@fabric-harness/channels/github'; export const channel = createGitHubChannel({ secret: process.env.GITHUB_WEBHOOK_SECRET!, agent: 'triage', }); ``` The server mounts the channel at `POST /channels/github/webhook`. GitHub's `X-GitHub-Delivery` becomes the dispatch deduplication key, and the conversation key identifies the repository issue or pull request. Use `commentOnGitHubIssue(ref, { token })` as an outbound tool on the persistent agent. Keep the token in `GITHUB_TOKEN`, scope it to the repositories and write operations the agent needs, and require approval for comment or mutation tools through the agent capability policy. For read-oriented repository access instead of event ingress, use `githubSource()` from `@fabric-harness/connectors/github` or the `github-mcp` connector guide. --- # Google Chat Canonical: https://harness.techfabric.com/docs/ecosystem/channels/google-chat Route authenticated Google Chat events into persistent agent threads, so a conversation in a space keeps its own context. ```sh fh add channel google-chat ``` ```ts title=".fabricharness/channels/google-chat.ts" import { createGoogleChatChannel } from '@fabric-harness/channels/google-chat'; export default createGoogleChatChannel({ audience: process.env.GOOGLE_CHAT_AUDIENCE!, agent: 'assistant', }); ``` Set the Chat app HTTP endpoint to `POST /channels/google-chat/webhook` and use the same endpoint URL or Cloud project number as `GOOGLE_CHAT_AUDIENCE`. The adapter verifies the Google Chat issuer, audience, signature, expiry, and not-before claims. Space is the default tenant, the user is the actor, and space/thread is the persistent key. Use `replyInGoogleChat(ref, { accessToken, space, thread })` for governed asynchronous replies. Use minimal Chat scopes and live-test service-account or delegated credentials in the target Workspace domain. See [Google request verification](https://developers.google.com/workspace/chat/verify-requests-from-chat). --- # Intercom Canonical: https://harness.techfabric.com/docs/ecosystem/channels/intercom Dispatch verified Intercom conversation events to a support agent, keeping the thread and the customer record together. ```sh fh add channel intercom ``` ```ts import { createIntercomChannel } from '@fabric-harness/channels/intercom'; export default createIntercomChannel({ clientSecret: process.env.INTERCOM_CLIENT_SECRET!, agent: 'support', }); ``` Configure the Developer Hub webhook URL as `POST /channels/intercom/webhook`. The adapter verifies Intercom's `X-Hub-Signature` HMAC, deduplicates notification IDs, propagates contact identity, and keys persistent sessions by conversation or ticket. Use `replyInIntercom(ref, { accessToken, conversationId, adminId })` for governed replies. Apply customer-data redaction and retention policy before placing conversation content in model context or telemetry. --- # Linear Canonical: https://harness.techfabric.com/docs/ecosystem/channels/linear Connect Linear issue events to an agent, and give it governed issue tools so it can act rather than only comment. ```sh fh add channel linear ``` ```ts import { createLinearChannel } from '@fabric-harness/channels/linear'; export default createLinearChannel({ signingSecret: process.env.LINEAR_WEBHOOK_SECRET!, agent: 'triage', }); ``` Register `POST /channels/linear/webhook` in the Linear integration. The adapter verifies `Linear-Signature` over the exact body, uses the webhook ID for deduplication, propagates the organization and actor, and keys the session by Linear object ID. Use `commentOnLinearIssue(ref, { apiKey, issueId })` for a governed GraphQL comment tool. Require approval for issue creation, state changes, comments, and destructive mutations according to the workload. --- # Facebook Messenger Canonical: https://harness.techfabric.com/docs/ecosystem/channels/messenger Connect Meta Messenger webhooks to persistent Fabric agents, with signature verification handled before dispatch. ```sh fh add channel messenger ``` ```ts import { createMessengerChannel } from '@fabric-harness/channels/messenger'; export default createMessengerChannel({ appSecret: process.env.MESSENGER_APP_SECRET!, verifyToken: process.env.MESSENGER_VERIFY_TOKEN!, agent: 'support', }); ``` Configure both `GET` and `POST /channels/messenger/webhook`. GET answers Meta's verification challenge; POST verifies `X-Hub-Signature-256`, uses message IDs for deduplication, propagates Page and sender identity, and suppresses Page echo events. Use `replyInMessenger(ref, { pageAccessToken })` for a governed Send API tool. Keep Page tokens host-side and live-test webhook subscription, permissions, token rotation, retries, and deletion/privacy handling. --- # Notion Canonical: https://harness.techfabric.com/docs/ecosystem/channels/notion Handle Notion integration events with page-scoped access, so an agent reads and writes only the pages you granted. ```sh fh add channel notion ``` ```ts import { createNotionChannel } from '@fabric-harness/channels/notion'; export default createNotionChannel({ verificationToken: process.env.NOTION_WEBHOOK_VERIFICATION_TOKEN!, agent: 'knowledge', onVerificationToken: (token) => console.info('Store the Notion verification token:', token), }); ``` Create a webhook subscription for `POST /channels/notion/webhook`, capture its one-time `verification_token` through `onVerificationToken`, and store it in the environment. The adapter answers verification requests, then verifies `X-Notion-Signature`, deduplicates by event ID, and keys sessions by workspace/entity. Use `commentOnNotionPage(ref, { token, parentId })` for governed comments. Restrict the integration to explicitly shared pages and databases. See [Notion webhooks](https://developers.notion.com/reference/webhooks). --- # Resend Canonical: https://harness.techfabric.com/docs/ecosystem/channels/resend Process verified inbound mail and delivery events from Resend, so an agent can hold an email thread rather than fire and forget. ```sh fh add channel resend ``` ```ts import { createResendChannel } from '@fabric-harness/channels/resend'; export default createResendChannel({ signingSecret: process.env.RESEND_WEBHOOK_SECRET!, tenantId: 'acme', agent: 'mail', }); ``` Register `POST /channels/resend/webhook`. The adapter verifies the Svix ID, timestamp, and signature against exact bytes, rejects stale deliveries, deduplicates by `svix-id`, and keys the session by email ID. Use `sendWithResend(ref, { apiKey, from, to })` for governed outbound email. Redact sensitive message bodies and attachments before model, telemetry, or evaluation capture, and live-test domain configuration and delivery retries. --- # Salesforce Marketing Cloud Canonical: https://harness.techfabric.com/docs/ecosystem/channels/salesforce-marketing-cloud Connect Marketing Cloud events to an agent with governed campaign actions, so a send is gated by policy rather than by trust. ```sh fh add channel salesforce-marketing-cloud ``` ```ts import { createSalesforceMarketingCloudChannel } from '@fabric-harness/channels/salesforce-marketing-cloud'; export default createSalesforceMarketingCloudChannel({ signatureKey: process.env.SFMC_ENS_SIGNATURE_KEY!, agent: 'engagement', }); ``` Register and verify the ENS callback at `POST /channels/salesforce-marketing-cloud/webhook`, then store the callback's signature key. The adapter verifies `x-sfmc-ens-signature` over the complete batch, expands events into durable dispatches, propagates MID/business-unit tenancy, and deduplicates by composite ID, event type, and timestamp. Use `sendMarketingCloudMessage(ref, { restBaseUrl, accessToken, definitionKey, recipient })` for a governed transactional send. Treat sends, journey changes, subscriber mutations, and data-extension writes as high-impact operations requiring least-privilege OAuth, audit, and approval. --- # Shopify Canonical: https://harness.techfabric.com/docs/ecosystem/channels/shopify Process signed Shopify commerce webhooks with governed actions, so an agent touching an order passes a policy check first. ```sh fh add channel shopify ``` ```ts import { createShopifyChannel } from '@fabric-harness/channels/shopify'; export default createShopifyChannel({ clientSecret: process.env.SHOPIFY_CLIENT_SECRET!, agent: 'commerce', }); ``` Subscribe the app to `POST /channels/shopify/webhook`. The adapter verifies `X-Shopify-Hmac-Sha256`, uses `X-Shopify-Webhook-Id` for deduplication, records the delivered API version, propagates shop identity, and keys sessions by the GraphQL resource ID. Use `updateShopifyOrderNote(ref, { shop, accessToken, orderId, apiVersion })` for governed writes. Refund, fulfillment, inventory, customer, and order writes require narrow scopes, idempotency, policy, and usually human approval. --- # Slack Canonical: https://harness.techfabric.com/docs/ecosystem/channels/slack Dispatch signed Slack events to a persistent agent and reply in-thread. Create the channel: ```ts title=".fabricharness/channels/slack.ts" import { createSlackChannel } from '@fabric-harness/channels/slack'; export const channel = createSlackChannel({ signingSecret: process.env.SLACK_SIGNING_SECRET!, agent: 'assistant', }); ``` Bind the outbound tool to the addressed Slack thread: ```ts title=".fabricharness/agents/assistant.ts" import { createAgent } from '@fabric-harness/sdk'; import { parseSlackConversationKey, replyInSlackThread } from '@fabric-harness/channels/slack'; export default createAgent(({ id }) => ({ instructions: 'Answer the Slack thread concisely.', tools: [replyInSlackThread(parseSlackConversationKey(id), { botToken: process.env.SLACK_BOT_TOKEN!, })], })); ``` Configure the Slack Event Subscriptions request URL as `/channels/slack/events` and subscribe to `app_mention` or threaded message events. The adapter verifies Slack's signature, uses `event_id` for deduplication, and keys the persistent instance by thread. Required secrets are `SLACK_SIGNING_SECRET` and `SLACK_BOT_TOKEN`. The complete project is under `examples/with-slack-channel`. --- # Stripe Canonical: https://harness.techfabric.com/docs/ecosystem/channels/stripe Route signed Stripe events to an agent under financial-operation controls, because a refund is not a message. ```sh fh add channel stripe ``` ```ts import { createStripeChannel } from '@fabric-harness/channels/stripe'; export default createStripeChannel({ endpointSecret: process.env.STRIPE_WEBHOOK_SECRET!, agent: 'billing', }); ``` Create an event destination for `POST /channels/stripe/webhook`. The adapter verifies every `Stripe-Signature` over exact bytes, applies the standard five-minute replay window, deduplicates by event ID, and uses the connected account and customer/resource as tenant and session identity. Use `updateStripeCustomer(ref, { secretKey, customerId })` as a narrowly scoped governed tool. Never let model output directly choose unrestricted amounts, recipients, or idempotency keys. Refunds, transfers, subscription changes, and other financial writes should require approval. --- # Microsoft Teams Canonical: https://harness.techfabric.com/docs/ecosystem/channels/teams Route validated Bot Framework activities to persistent agents, so a Teams conversation keeps its context across turns. Use the adapter from `@fabric-harness/channels/teams`. The direct recipe configures the built-in Bot Connector JWT verifier: ```sh fh add channel teams ``` ```ts import { createTeamsChannel } from '@fabric-harness/channels/teams'; export default createTeamsChannel({ agent: 'assistant', applicationId: process.env.TEAMS_APP_ID!, }); ``` The adapter discovers Microsoft Bot Connector signing keys and validates the RS256 signature, issuer, App ID audience, token lifetime, activity `serviceUrl`, and channel endorsement. Key metadata is cached for one hour and refreshed once when an unknown key ID appears. Accepted message activities use the Azure tenant as `tenantId`, the AAD/Bot Framework user as `onBehalfOf`, the activity ID for deduplication, and tenant/conversation/reply IDs for the stable persistent instance. Use `authenticate` instead of `applicationId` only when an existing identity gateway performs the same validations before the request reaches TechFabric Harness. Sovereign-cloud deployments can set `botFramework.openIdMetadataUrl` to their Bot Connector metadata endpoint. Use `replyInTeamsConversation(ref, { accessToken })` for outbound Bot Framework replies. The access token resolver can rotate credentials per call. Mount the route at `POST /channels/teams/activities`. Prefer managed identity where supported, restrict Graph/Bot scopes, and policy-gate Graph mutations separately from message replies. --- # Telegram Canonical: https://harness.techfabric.com/docs/ecosystem/channels/telegram Connect Telegram bot updates to durable agent conversations that survive a restart rather than starting over. Use the adapter from `@fabric-harness/channels/telegram`: ```sh fh add channel telegram ``` ```ts import { createTelegramChannel } from '@fabric-harness/channels/telegram'; export default createTelegramChannel({ botId: process.env.TELEGRAM_BOT_ID!, botToken: process.env.TELEGRAM_BOT_TOKEN!, secretToken: process.env.TELEGRAM_WEBHOOK_SECRET!, agent: 'assistant', tenantId: 'acme', }); ``` Telegram must send updates to `POST /channels/telegram/webhook` with the configured `X-Telegram-Bot-Api-Secret-Token`. The adapter deduplicates by update ID, keys sessions by bot/chat/topic, and records the sender as `onBehalfOf`. Use `replyInTelegram(ref, { botToken })` for outbound messages. Keep edit, delete, and administration actions as separately governed tools. --- # Twilio Canonical: https://harness.techfabric.com/docs/ecosystem/channels/twilio Connect Twilio messaging and voice events to Fabric agents, with the signature check done before anything is dispatched. Use the messaging adapter from `@fabric-harness/channels/twilio`: ```sh fh add channel twilio ``` ```ts import { createTwilioChannel } from '@fabric-harness/channels/twilio'; export default createTwilioChannel({ accountSid: process.env.TWILIO_ACCOUNT_SID!, authToken: process.env.TWILIO_AUTH_TOKEN!, webhookUrl: process.env.TWILIO_WEBHOOK_URL!, agent: 'assistant', tenantId: 'acme', }); ``` Mount `POST /channels/twilio/messages`. `webhookUrl` must be the exact public URL configured in Twilio when a proxy rewrites the internal request URL. The adapter validates `X-Twilio-Signature` with HMAC-SHA1 over the URL and sorted form parameters, deduplicates by Message SID, records the sender as actor, and distinguishes SMS from `whatsapp:` addresses. Use `replyWithTwilio(ref, { authToken })` for outbound SMS or Twilio WhatsApp messages. For Media Streams also follow the voice-telephony connector specification. Gate outbound calls, transfers, and recordings separately and apply phone-number/recording privacy controls. --- # WhatsApp Canonical: https://harness.techfabric.com/docs/ecosystem/channels/whatsapp Route verified WhatsApp Cloud API webhooks to persistent agents, so a customer thread keeps its history between messages. Use the Meta Cloud API adapter from `@fabric-harness/channels/whatsapp`: ```sh fh add channel whatsapp ``` ```ts import { createWhatsAppChannel } from '@fabric-harness/channels/whatsapp'; export default createWhatsAppChannel({ appSecret: process.env.WHATSAPP_APP_SECRET!, verifyToken: process.env.WHATSAPP_VERIFY_TOKEN!, agent: 'assistant', }); ``` Configure both `GET` and `POST /channels/whatsapp/webhook`. The GET route completes Meta's verification challenge. The POST route verifies `X-Hub-Signature-256` against the exact body, deduplicates by WhatsApp message ID, uses the business account as tenant, records the sender as `onBehalfOf`, and keys the persistent instance by business account/phone number/sender. Use `replyInWhatsApp(ref, { accessToken })` for text replies. Keep template credentials host-side, govern template sends separately, and live-test phone-number/business permissions before rollout. --- # Zendesk Canonical: https://harness.techfabric.com/docs/ecosystem/channels/zendesk Dispatch verified ticket events to persistent support agents, so the agent sees the whole ticket rather than one comment. ```sh fh add channel zendesk ``` ```ts import { createZendeskChannel } from '@fabric-harness/channels/zendesk'; export default createZendeskChannel({ signingSecret: process.env.ZENDESK_WEBHOOK_SECRET!, subdomain: process.env.ZENDESK_SUBDOMAIN!, agent: 'support', }); ``` Point a Zendesk webhook at `POST /channels/zendesk/webhook`. The adapter signs the timestamp plus exact body, verifies the base64 signature, deduplicates deliveries, and keys sessions by ticket. Use `commentOnZendeskTicket(ref, { subdomain, email, token, ticketId })` for governed public or private comments. Redact attachments and personal data as required, and govern comments, status, assignment, and deletion tools independently. --- # libSQL Canonical: https://harness.techfabric.com/docs/ecosystem/databases/libsql Run the unified Fabric store on local libSQL or a remote compatible service. ```sh pnpm add @fabric-harness/node @libsql/client ``` ```ts title=".fabricharness/config.ts" import { createClient } from '@libsql/client'; import { libsqlPersistence } from '@fabric-harness/node'; export default function config() { const client = createClient({ url: 'file:.fabricharness/fabric.db' }); return { persistence: libsqlPersistence({ client }) }; } ``` The adapter provides the complete bundle and uses version-fenced updates rather than relying on a long interactive transaction. That keeps the same code compatible with local libSQL and remote HTTP clients. Mutations within one persistence surface are atomic; cascade deletion spans several surface rows and is intentionally not one remote transaction. Retry deletion after transport failure, or use Postgres when cross-surface transactionality is mandatory. For model-facing data, run `fh add libsql`. The managed recipe installs `@libsql/client`, creates a fixed-statement governed lookup tool and test, and prints its verification command. Parameterize every value, cap rows and duration, separate reads and writes, propagate tenant filters, and require approval for writes or DDL. --- # MongoDB Canonical: https://harness.techfabric.com/docs/ecosystem/databases/mongodb Expose collection-scoped MongoDB operations as agent tools, so a query is bounded by the collection rather than the connection. ## Runtime persistence ```sh pnpm add @fabric-harness/node mongodb ``` ```ts title=".fabricharness/config.ts" import { mongodbPersistence } from '@fabric-harness/node'; import { MongoClient } from 'mongodb'; export default async function config() { const client = new MongoClient(process.env.MONGODB_URL!); await client.connect(); const collection = client.db('fabric').collection('fabric_harness_snapshots'); return { persistence: mongodbPersistence({ collection, client }) }; } ``` The bundle uses `_id` plus a monotonic version for atomic compare-and-swap, so it works on a standalone server and on replica sets without multi-document transactions. Use majority write concern and retryable writes for production. Payloads are canonical JSON strings, which preserves Fabric's `undefined` semantics and permits arbitrary tool-result keys without Mongo field-name interpretation. Each store surface is one snapshot document. This is appropriate for moderate operational state; choose Postgres for high-contention workloads or very large histories. ## Governed data tools Use the collection-bound MongoDB tool. Scaffold the official driver and adapter: ```sh fh add database mongodb ``` ```ts const lookup = mongoFindTool({ collection: db.collection('accounts'), collectionName: 'accounts', name: 'lookup_account', description: 'Read one tenant-scoped account.', filter: ({ tenantId, accountId }) => ({ tenantId, id: accountId }), projection: { _id: 0, id: 1, status: 1 }, maxRows: 1, }); ``` Host code constructs the filter and projection, so the model cannot submit an arbitrary query document. The adapter applies result/time/byte limits and redacted errors. Writes, indexes, and administration should remain separate approval-gated tools. --- # MySQL Canonical: https://harness.techfabric.com/docs/ecosystem/databases/mysql Add parameterized MySQL tools under a least-privilege grant, so an agent cannot write a query you would not have approved. ## Runtime persistence ```sh pnpm add @fabric-harness/node mysql2 ``` ```ts title=".fabricharness/config.ts" import { mysqlPersistence } from '@fabric-harness/node'; import mysql from 'mysql2/promise'; export default function config() { const pool = mysql.createPool(process.env.MYSQL_URL!); return { persistence: mysqlPersistence({ client: pool }) }; } ``` `mysqlPersistence()` supplies sessions, submissions, conversation streams, binary attachments, runs/events, atomic cost budgets, health, migration, and cascade deletion. It stores one version-fenced JSON snapshot per persistence surface and uses compare-and-swap updates, so multiple replicas cannot both commit the same transition. Use MySQL 8/InnoDB, TLS, backups, and a `max_allowed_packet` larger than your largest attachment snapshot. Snapshot rows favor moderate agent operational state; use Postgres when workloads have very high write concurrency or histories large enough that rewriting a surface snapshot is costly. ## Governed data tools Use the fixed-statement MySQL tool. Scaffold `mysql2` and `@fabric-harness/databases/mysql` with: ```sh fh add database mysql ``` ```ts const lookup = mysqlTool({ client: pool, name: 'lookup_account', description: 'Read one tenant-scoped account.', statement: 'select id, status from accounts where tenant_id = ? and id = ? limit 1', parameters: ({ tenantId, accountId }) => [tenantId, accountId], }); ``` The application owns the SQL; model input only becomes bound parameters. Read tools reject mutations and multi-statements. Use a least-privilege user, keep `multipleStatements: false`, and mark controlled mutations `effect: 'write'` so approvals can gate them. Runtime credentials stay in host configuration and are never added to model-facing tools. --- # Postgres Canonical: https://harness.techfabric.com/docs/ecosystem/databases/postgres Persist Fabric session state and artifacts in Postgres, which is the store to reach for when a run has to outlive the process. ```sh pnpm add @fabric-harness/node pg ``` Configure the unified persistence bundle without placing the connection string in source: ```ts title=".fabricharness/config.ts" import { postgresPersistence, type FabricHarnessConfig } from '@fabric-harness/node'; import { Pool } from 'pg'; export default function config(): FabricHarnessConfig { const pool = new Pool({ connectionString: process.env.DATABASE_URL }); return { persistence: postgresPersistence({ client: pool, tablePrefix: 'fabric_harness', }), }; } ``` `postgresPersistence()` migrates and wires session history, submissions, conversation offsets, attachments, finite run/event records, and cost-budget totals. `fh dev` and generated Node servers consume `persistence.serverOptions()` automatically, health checks can call `persistence.health()`, and server shutdown closes the injected pool. Use a distinct `tablePrefix` per environment or tenant boundary where operational separation is required. The lower-level `PostgresSessionStore`, `PostgresSubmissionStore`, `PostgresConversationStreamStore`, and `PostgresAttachmentStore` remain public for hosts that need to compose stores independently. For a durable single-node deployment, use the same surface with SQLite: ```ts title=".fabricharness/config.ts" import { sqlitePersistence } from '@fabric-harness/node'; export default { persistence: sqlitePersistence({ path: '.fabricharness/fabric-harness.sqlite', }), }; ``` The SQLite bundle includes sessions, submissions, conversation offsets, attachments, workflow run events, and atomic cost-budget totals. Use Postgres or Lakebase when multiple server replicas need to coordinate. For governed model-facing data access, scaffold a fixed-statement tool: ```sh fh add database postgres ``` ```ts import { postgresTool } from '@fabric-harness/databases/postgres'; const lookup = postgresTool({ client: pool, name: 'lookup_account', description: 'Read one account in the current tenant.', statement: 'select id, status from accounts where tenant_id = $1 and id = $2 limit 1', parameters: ({ tenantId, accountId }) => [tenantId, accountId], }); ``` The model supplies parameter values, never SQL text. Read tools reject mutation statements and multiple statements; all tools cap rows, result bytes, and execution time and declare an effect for policy/approval enforcement. See `examples/with-postgres-store` and run `pnpm run run:tool` for a runnable example. The same optional `DATABASE_URL` configuration is used by `examples/react-chat` and `examples/with-channel-adapters`, so the UI and channel examples can be run infrastructure-free or against durable Postgres without changing application code. The CI suite runs the published bundle contract against Postgres 16, including concurrent cost increments, lifecycle CAS behavior, cascade deletion, and close/reopen recovery. --- # Redis Canonical: https://harness.techfabric.com/docs/ecosystem/databases/redis Use Redis for complete runtime persistence or governed agent key-value tools. Redis has two separate integration surfaces: - `redisPersistence()` stores sessions, durable submissions, conversation offsets, attachments, runs, and cost budgets for Node runtimes. - `redisTools()` gives an agent bounded key-value capabilities. It does not expose persistence internals to the model. ## Runtime persistence Install the official Redis client alongside the Node runtime: ```sh pnpm add @fabric-harness/node redis ``` ```ts title=".fabricharness/config.ts" import { redisPersistence, type FabricHarnessConfig } from '@fabric-harness/node'; import { createClient } from 'redis'; export default async function config(): Promise { const client = createClient({ url: process.env.REDIS_URL }); await client.connect(); return { persistence: redisPersistence({ client, namespace: 'production', ttlSeconds: 30 * 24 * 60 * 60, }), }; } ``` All keys share a namespace-specific Redis Cluster hash tag. Mutations use an ownership-checked Lua commit, concurrent cost reservations are atomic, and binary attachments are preserved byte for byte. `ttlSeconds` applies sliding retention to persisted state; omit it when retention is managed externally. Use TLS, ACL credentials limited to the namespace, replication, and a persistence mode appropriate for your recovery objective. The same bundle works with Valkey deployments that support the Redis command and Lua surface used by the injected client. CI runs the complete persistence contract against Redis 7.4, including claims, settlement, fencing, restart recovery, deletion, one-megabyte attachments, and concurrency. ## Governed agent tools Install the namespaced Redis tool recipe: ```sh fh add database redis ``` ```ts const [get, set] = redisTools({ client, prefix: 'prod:acme', maxValueBytes: 64 * 1024, defaultTtlSeconds: 3600, }); ``` Every key is prefixed by application code. Values are size-bounded, writes can receive a TTL, and `redis_set` is marked `effect: 'write'`. The package intentionally exposes no script, admin, flush, or arbitrary-command tool. Use TLS and least-privilege ACL credentials. --- # SQLite Canonical: https://harness.techfabric.com/docs/ecosystem/databases/sqlite Use fixed, parameterized SQLite operations as governed agent tools, which suits a local workspace or a single-tenant deployment. Scaffold `better-sqlite3` with the first-party adapter: ```sh fh add database sqlite ``` ```ts import { sqliteTool } from '@fabric-harness/databases/sqlite'; const lookup = sqliteTool({ client: database, name: 'lookup_account', description: 'Read one tenant-scoped account.', statement: 'select id, status from accounts where tenant_id = ? and id = ? limit 1', parameters: ({ tenantId, accountId }) => [tenantId, accountId], }); ``` The statement is fixed in application code. Read tools reject mutations and multiple statements; row, byte, and time limits protect model context. Mark controlled writes with `effect: 'write'` and attach approval policy as required. This is model-facing data access. For durable Harness sessions, configure the Node `store.backend: 'sqlite'` session store separately. --- # Supabase Canonical: https://harness.techfabric.com/docs/ecosystem/databases/supabase Build Supabase table and RPC tools that respect row-level security, so an agent inherits the policies you already wrote. Run `fh add supabase` to install a compatible client and create a managed, fixed-table lookup tool and test. Preserve Row Level Security through end-user identity when required, and never expose the service-role key to model context. Generate table/RPC-specific tools with schema validation, limits, redaction, and approval for mutations. For Fabric runtime persistence, connect a server-side `pg.Pool` to Supabase's direct Postgres or session-pooler URL and pass it to `postgresPersistence()`. Do not use the browser Supabase client or service-role key in agent tools. Transaction-pooler compatibility depends on the connection mode; the direct connection is the reference configuration for migrations and long-lived Node hosts. --- # Turso Canonical: https://harness.techfabric.com/docs/ecosystem/databases/turso Connect Turso and libSQL with bounded, parameterized operations, so an edge-deployed agent still queries under a policy. Use the same full bundle as libSQL with remote credentials: ```ts const client = createClient({ url: process.env.TURSO_DATABASE_URL!, authToken: process.env.TURSO_AUTH_TOKEN!, }); export default { persistence: libsqlPersistence({ client }) }; ``` Keep URL/token secrets host-side. Mutations use optimistic version fencing and do not require a long-lived interactive transaction. Prefer the primary write URL for durable decisions; replicas can lag. Cascade deletion touches several snapshot rows, so retry it after a partial network failure. For model-facing data, run `fh add turso`. The managed recipe installs compatible libSQL packages, creates a fixed-statement tool and test, and keeps the URL/token in environment variables. Parameterize statements, enforce read/write separation, limits, tenant predicates, and mutation approval. --- # Valkey Canonical: https://harness.techfabric.com/docs/ecosystem/databases/valkey Use Valkey from an agent under ACLs, namespaces and a command policy, so a cache tool cannot become a shell. Run `fh add valkey` to install `iovalkey` and create a managed tenant-prefixed read tool and test. Use TLS/ACLs, command allowlists, value/TTL limits, and administrative/script/flush denial. Treat writes as governed effects. For runtime persistence, use `redisPersistence()` with a Redis-protocol client connected to Valkey; see the [Redis guide](/docs/ecosystem/databases/redis) for the full bundle, retention, cluster key, and recovery configuration. --- # Sandbox adapters Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes Remote execution adapters that implement the common SandboxEnv contract. Fabric owns the sandbox contract while applications own provider clients and credentials. The adapters below accept structural provider handles, so vendor SDKs remain optional peer dependencies. ```sh pnpm add @fabric-harness/connectors ``` | Provider | Helper | Recipe | Live validation | | --- | --- | --- | --- | | [Databricks SQL](/docs/ecosystem/sandboxes/databricks-sql) | `databricksSqlSandbox()` | First-party package | Workspace, Warehouse, and Unity Catalog gate. | | [boxd](/docs/ecosystem/sandboxes/boxd) | Community blueprint — no shipped adapter | `fh add boxd` | Untested blueprint; you implement and validate the adapter. | | [Cloudflare Computer](/docs/ecosystem/sandboxes/cloudflare-computer) | `@fabric-harness/cloudflare/computer` | `fh add cloudflare-computer` | Early preview; Worker Loader beta; Wrangler/account gate. | | [Cloudflare Sandbox](/docs/ecosystem/sandboxes/cloudflare) | `@fabric-harness/cloudflare` | `fh add cloudflare-sandbox` | Wrangler/account gate. | | [Daytona](/docs/ecosystem/sandboxes/daytona) | `daytonaSandbox()` | `fh add daytona` | `FABRIC_DAYTONA_TEST=1` | | [E2B](/docs/ecosystem/sandboxes/e2b) | `e2bSandbox()` | `fh add e2b` | `FABRIC_E2B_TEST=1` | | [exe.dev](/docs/ecosystem/sandboxes/exedev) | Community blueprint — no shipped adapter | `fh add exedev` | Untested blueprint; you implement and validate the adapter. | | [islo](/docs/ecosystem/sandboxes/islo) | Community blueprint — no shipped adapter | `fh add islo` | Untested blueprint; you implement and validate the adapter. | | [Mirage](/docs/ecosystem/sandboxes/mirage) | Community blueprint — no shipped adapter | `fh add mirage` | Untested blueprint; you implement and validate the adapter. | | [Modal](/docs/ecosystem/sandboxes/modal) | `modalSdkSandbox()` | `fh add modal` | `FABRIC_MODAL_TEST=1` plus Modal tokens | | [smolvm](/docs/ecosystem/sandboxes/smolvm) | Community blueprint — no shipped adapter | `fh add smolvm` | Untested blueprint; you implement and validate the adapter. | | [Vercel](/docs/ecosystem/sandboxes/vercel) | `vercelSandbox()` | `fh add vercel` | Contract tests; run a provider smoke before production. | | Kubernetes / AKS | `kubernetesSandbox()` | Package helper | Cluster-gated validation. | | Any provider | `remoteSandbox()` / `remoteSandboxEnv()` | `fh add --category sandbox` | Provider-specific. | All sandbox operations still pass through Fabric capability policy. Provider isolation does not replace filesystem, command, network, approval, timeout, or cleanup policy. Rows marked **Community blueprint** are untested integration guides: TechFabric Harness does not ship or certify an adapter for those providers, and the `fh add` recipe scaffolds a project-owned adapter that you implement and validate yourself. --- # boxd Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/boxd Adapt boxd execution to the complete Fabric remote sandbox contract, covering shell, filesystem and lifecycle. > **Community blueprint — no shipped adapter.** TechFabric Harness does not ship or > certify an adapter for boxd, and nothing here is covered by the conformance > suites. `fh add boxd` scaffolds a project-owned adapter that you implement > and validate yourself with `validateSandboxAdapter()`. See the > [target matrix](/docs/ecosystem/targets) for what is shipped. Run `fh add boxd`. The versioned recipe installs the connector packages and creates a managed `RemoteSandboxApi` adapter plus its contract test. Implement the provider calls for shell exit semantics, binary files, cwd/environment, timeout/abort, lifecycle cleanup, and reconnectable references. Keep boxd credentials host-side, run `validateSandboxAdapter()`, and complete a real create/execute/cleanup smoke before production. --- # Cloudflare Sandbox Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/cloudflare Run Fabric jobs inside Cloudflare container sandboxes, so execution stays on the edge alongside the rest of the deployment. Run `fh add cloudflare-sandbox` to install compatible packages and create the managed binding adapter and test. Configure the binding through the Cloudflare build target and select sandbox mode in Fabric config. Each persistent agent instance is backed by Durable Object SQLite for submissions, conversation offsets, attachments, abort, and restart recovery; the sandbox binding provides the isolated Linux execution environment used by its tools. Enforce container CPU, memory, network, command, and cleanup limits in addition to Fabric capability policy. Run Wrangler and deployed-account execution tests before production. See [Cloudflare deployment](/docs/deployment/cloudflare). --- # Cloudflare Computer Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/cloudflare-computer Durable SQLite-backed workspace and Worker Loader shell for Cloudflare Workers. Cloudflare Computer is an **early-preview** sandbox for experiments and prototypes. It stores one workspace in each Fabric session Durable Object and runs commands through a just-bash Dynamic Worker. It is not a Linux container and should not be treated as production-ready until Cloudflare stabilizes Computer and Worker Loader. Install the managed adapter: ```sh fh add cloudflare-computer ``` Or configure the generated Cloudflare target directly: ```ts title=".fabricharness/config.ts" export default { sandbox: { backend: "cloudflare", mode: "computer", loaderBinding: "LOADER", cwd: "/workspace", }, }; ``` The Cloudflare build emits all required topology: a `worker_loaders` binding, the `experimental` compatibility flag, an entry-module `WorkspaceServiceProxy` export, and `__getWorkspaceStub()` on `FabricHarnessSessionObject`. At runtime Harness constructs the Computer `Workspace` with the Durable Object's SQLite storage, `waitUntil`, `createGitClient()`, and `WorkerShellBackend` loopback `{ binding: "FABRIC_HARNESS_SESSIONS", id }`. Because `exec()` works, the normal Harness tools apply unchanged: `bash`, `grep`, `glob`, `read`, `write`, and `edit`. The default working directory is `/workspace`. The native workspace is available through `cloudflareComputerWorkspace(sessionSandbox)` for typed git or direct filesystem operations. ## Requirements and limits - Install `@cloudflare/computer`, `@platformatic/vfs`, and `@fabric-harness/cloudflare`. - Worker Loader is beta and requires the `experimental` compatibility flag. - just-bash implements shell commands in JavaScript; native binaries and language toolchains require [Cloudflare Sandbox](/docs/ecosystem/sandboxes/cloudflare). - Computer state lives in the Fabric session Durable Object and follows its identity and isolation boundary. - Cancellation rejects promptly, sends `SIGKILL` to the workspace run, consumes late settlement, and disposes the run handle. - Existing `@cloudflare/shell` Workspace data is **not migrated**. Hydrate and verify a fresh Computer workspace before switching traffic. The old `shell-workspace` mode and `fh add cloudflare-shell` command remain deprecated aliases for one release window. New code should use `computer` and `cloudflare-computer`. See `examples/with-cloudflare-shell-workspace` for a runnable migration example. Its historical directory and package names are retained so existing workspace filters do not break. --- # Cloudflare Shell (deprecated) Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/cloudflare-shell Migrate a Cloudflare Shell Workspace project to Cloudflare Computer, and what changes in the sandbox contract when you do. `@cloudflare/shell` support is deprecated in favor of [Cloudflare Computer](/docs/ecosystem/sandboxes/cloudflare-computer). `fh add cloudflare-shell` remains an alias during the migration window, but now installs the Computer adapter. Use sandbox mode `computer` and install `@cloudflare/computer` plus `@platformatic/vfs`. Existing Shell Workspace data is not migrated; hydrate and verify a fresh Computer workspace before switching traffic. --- # Daytona sandbox adapter Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/daytona Run Fabric sessions inside a Daytona-managed development sandbox, so an agent gets a real workspace rather than a bare shell. ```sh pnpm add @fabric-harness/connectors @daytona/sdk fh add daytona ``` ```ts import { Daytona } from '@daytona/sdk'; import { daytonaSandbox } from '@fabric-harness/connectors'; const client = new Daytona({ apiKey: process.env.DAYTONA_API_KEY }); const remote = await client.create({ image: 'node:22' }); const job = await init({ sandbox: daytonaSandbox(remote, { cleanup: true }), }); ``` The adapter maps Daytona files, commands, suspend/resume, and optional cleanup to `SandboxEnv`. Credentials remain on the Daytona client and are not serialized into session history. Use an `encodeRef` only when another process has a registered decoder capable of reconnecting to the remote sandbox. See `examples/with-daytona` for the runnable adapter shape. --- # E2B sandbox adapter Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/e2b Adapt an E2B sandbox to the Fabric shell and filesystem operations, which is the fastest path to running untrusted code. ```sh pnpm add @fabric-harness/connectors @e2b/code-interpreter fh add e2b ``` ```ts import { Sandbox } from '@e2b/code-interpreter'; import { e2bSandbox } from '@fabric-harness/connectors'; const remote = await Sandbox.create({ apiKey: process.env.E2B_API_KEY }); const fabric = await init({ sandbox: e2bSandbox(remote, { cleanup: true }), }); ``` The structural adapter maps E2B command and file APIs, including pause/resume when present. `{ cleanup: true }` invokes the provider's conventional termination method when Fabric disposes the sandbox. Run the connector live suite with `FABRIC_E2B_TEST=1` and `E2B_API_KEY` before promoting an SDK version or template change. --- # exe.dev Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/exedev Adapt exe.dev machines to the Fabric shell and filesystem operations, so a session gets a persistent machine rather than a container. > **Community blueprint — no shipped adapter.** TechFabric Harness does not ship or > certify an adapter for exe.dev, and nothing here is covered by the conformance > suites. `fh add exedev` scaffolds a project-owned adapter that you implement > and validate yourself with `validateSandboxAdapter()`. See the > [target matrix](/docs/ecosystem/targets) for what is shipped. Run `fh add exedev`. The versioned recipe creates a managed `remoteSandboxEnv()` adapter and test; implement the current machine API mapping for cwd, environment allowlists, abort, timeout, binary files, cleanup, and reconnection behavior. Never serialize SSH keys or machine tokens into model context, history, or portable refs. Validate the adapter structurally and live. --- # islo Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/islo Build an islo adapter against the portable Fabric sandbox contract, and what the contract requires before an agent can use it. > **Community blueprint — no shipped adapter.** TechFabric Harness does not ship or > certify an adapter for islo, and nothing here is covered by the conformance > suites. `fh add islo` scaffolds a project-owned adapter that you implement > and validate yourself with `validateSandboxAdapter()`. See the > [target matrix](/docs/ecosystem/targets) for what is shipped. Run `fh add islo`. The versioned recipe creates a managed remote adapter and test; map the provider's current SDK and authentication to Fabric's sandbox contract, policy enforcement, and lifecycle expectations. Define resource/network limits, deterministic cleanup, and portable refs only when another process can securely reconnect. --- # Mirage Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/mirage Adapt Mirage isolated execution to Fabric agents, so a run that touches untrusted input stays inside its own boundary. > **Community blueprint — no shipped adapter.** TechFabric Harness does not ship or > certify an adapter for Mirage, and nothing here is covered by the conformance > suites. `fh add mirage` scaffolds a project-owned adapter that you implement > and validate yourself with `validateSandboxAdapter()`. See the > [target matrix](/docs/ecosystem/targets) for what is shipped. Run `fh add mirage`. The versioned recipe creates a managed remote adapter and test; implement the complete shell/filesystem/lifecycle interface, preserve provider exit/timeout/abort semantics, and keep authentication outside model/session data. Provider isolation supplements rather than replaces Fabric command, filesystem, network, approval, and audit controls. --- # Modal sandbox adapter Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/modal Run Fabric sessions in Modal sandboxes through the first-party TypeScript SDK adapter. ```sh pnpm add @fabric-harness/connectors modal fh add modal ``` Create a Modal sandbox with the provider SDK and pass the native handle to Fabric: ```ts import { ModalClient } from 'modal'; import { modalSdkSandbox } from '@fabric-harness/connectors/modal'; const client = new ModalClient(); const app = await client.apps.fromName('fabric-harness', { createIfMissing: true }); const image = client.images.fromRegistry('node:22-alpine'); const remote = await client.sandboxes.create(app, image, { timeoutMs: 300_000, workdir: '/workspace', }); const sandbox = modalSdkSandbox(remote, { cleanup: true }); const fabric = await init({ sandbox }); ``` The adapter maps Modal's streamed process handles, binary filesystem API, timeout, portable `sandboxId`, reconnect, and termination behavior to `SandboxEnv`. Credentials stay inside `ModalClient`; they are never serialized into a session or model request. The runnable `examples/with-modal` project uses this path, and the protected live suite publishes the nine-check sandbox certification report for Modal SDK 0.9. --- # smolvm Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/smolvm Adapt smolvm execution to the portable Fabric sandbox contract, which suits a deployment where a full container is too heavy. > **Community blueprint — no shipped adapter.** TechFabric Harness does not ship or > certify an adapter for smolvm, and nothing here is covered by the conformance > suites. `fh add smolvm` scaffolds a project-owned adapter that you implement > and validate yourself with `validateSandboxAdapter()`. See the > [target matrix](/docs/ecosystem/targets) for what is shipped. Run `fh add smolvm`. The versioned recipe creates a managed `RemoteSandboxApi` adapter and its contract test. Map the current smolvm client into Fabric's shell, binary file, working-directory, environment, timeout, cancellation, and cleanup operations. Keep credentials at the trusted runtime boundary. Declare the actual filesystem, process, and network isolation the provider supplies; apply Fabric capability policy as an additional boundary. Only emit a portable sandbox reference when a different process can securely reconnect to the same VM. Run `validateSandboxAdapter()` and a real create/execute/abort/cleanup smoke before production. --- # Vercel Sandbox Canonical: https://harness.techfabric.com/docs/ecosystem/sandboxes/vercel Adapt @vercel/sandbox instances to Fabric sessions, so an agent deployed on Vercel executes code without leaving the platform. ```sh pnpm add @fabric-harness/connectors @vercel/sandbox fh add vercel ``` ```ts import { Sandbox } from '@vercel/sandbox'; import { vercelSandbox } from '@fabric-harness/connectors/vercel'; const remote = await Sandbox.create({ runtime: 'node24', timeout: 300_000, }); const fabric = await init({ sandbox: vercelSandbox(remote, { cleanup: true }), }); ``` The connector maps the Vercel 1.x command object, async output readers, output streams, `AbortSignal`, file APIs, and lifecycle operations without exposing provider credentials to the model. The supported range is `@vercel/sandbox >=1.10.1 <2`. `sandboxId` becomes a portable ref automatically. Register the receiving process once: ```ts registerStandardSandboxRefDecoders({ vercel: { connect: ({ sandboxId }) => Sandbox.get({ sandboxId }) }, }); ``` Run `assertSandboxCertification()` from the [sandbox connector guide](/docs/building/sandbox-connectors#certification-helper) in the deployment account. The live workflow writes the secret-free report as a CI artifact. --- # Runtime and deployment targets Canonical: https://harness.techfabric.com/docs/ecosystem/targets Every sandbox backend and deployment target TechFabric Harness supports, with its adapter, runnable example, credential-free path, and validation. {/* Generated by scripts/build-targets-matrix.mjs from packages/sdk/src/types.ts, packages/node/src/build.ts, packages/cli/src/deploy/targets.ts, packages/connectors/src/index.ts, and connectors/sandbox--*.md. Edit the metadata in the script and regenerate with pnpm docs:targets; do not edit this file directly. */} This page lists every runtime/sandbox and deployment target TechFabric Harness supports. Each row names the adapter or driver that implements the target, a runnable example where one exists, the credential-free path, and the validation behind the row. ## Sandbox backends A sandbox is where shell commands and tool file operations execute. It is chosen at `init({ sandbox })` and is independent of the deployment target. Backends that take a provider SDK object keep credentials inside the provider client; they are never serialized into session history. | Backend | Adapter | Example | Credential-free path | Validation | | --- | --- | --- | --- | --- | | [`virtual` (default)](/docs/building/sandboxes) | Built into `@fabric-harness/sdk` | `examples/hello-world/` | Fully local: in-memory filesystem and bash subset, no credentials. | SDK contract suites. | | [`empty`](/docs/reference/sandboxes-matrix) | Built into `@fabric-harness/sdk` | — | Fully local: no filesystem or shell, model and tool calls only. | SDK contract suites. | | [`local`](/docs/building/sandboxes) | Built into `@fabric-harness/node` | `examples/with-local-shell/` | `pnpm --dir examples/with-local-shell run run` uses the mock model and the host shell. | Node runtime contract suites. | | [`docker`](/docs/reference/sandboxes-matrix) | `init({ sandbox: { backend: 'docker', image } })` via `@fabric-harness/node` | `examples/with-docker/` | `pnpm --dir examples/with-docker run build`; a run additionally needs a local Docker daemon. | Container contract suites. | | [E2B](/docs/ecosystem/sandboxes/e2b) | `e2bSandbox()` from `@fabric-harness/connectors`
Provider SDK: `@e2b/code-interpreter` `>=2.6.1 <3` | `examples/with-e2b/` | `pnpm --dir examples/with-e2b run run` uses the mock provider. | Shared sandbox contract suites; set `FABRIC_E2B_TEST=1` for the credentialed smoke. | | [Daytona](/docs/ecosystem/sandboxes/daytona) | `daytonaSandbox()` from `@fabric-harness/connectors`
Provider SDK: `@daytona/sdk` `>=0.195.0 <1` | `examples/with-daytona/` | `pnpm --dir examples/with-daytona run run` uses the mock provider. | Shared sandbox contract suites; set `FABRIC_DAYTONA_TEST=1` for the credentialed smoke. | | [Modal](/docs/ecosystem/sandboxes/modal) | `modalSdkSandbox()` from `@fabric-harness/connectors/modal`
Provider SDK: `modal` `>=0.9.0 <1` | `examples/with-modal/` | `pnpm --dir examples/with-modal run run` uses the mock provider. | Shared sandbox contract suites; `FABRIC_MODAL_TEST=1` plus Modal tokens for the credentialed smoke. | | [Vercel Sandbox](/docs/ecosystem/sandboxes/vercel) | `vercelSandbox()` from `@fabric-harness/connectors/vercel`
Provider SDK: `@vercel/sandbox` `>=1.10.1 <2` | `examples/with-vercel-sandbox/` | `pnpm --dir examples/with-vercel-sandbox run run` uses the mock provider. | Contract suites; run a provider smoke before production. | | [Kubernetes](/docs/ecosystem/sandboxes) | `kubernetesSandbox()` from `@fabric-harness/connectors/k8s`
Provider SDK: `@kubernetes/client-node` `>=0.21.0 <0.22` | `examples/with-kubernetes/` | `pnpm --dir examples/with-kubernetes run run` uses the mock provider. | Contract suites; cluster-gated validation. | | [Cloudflare Sandbox](/docs/ecosystem/sandboxes/cloudflare) | `createCloudflareSandboxEnv()` from `@fabric-harness/cloudflare`
Provider SDK: `@cloudflare/sandbox` `>=0.9.2 <1` | `examples/with-cloudflare-sandbox/` | `pnpm --dir examples/with-cloudflare-sandbox run build:cloudflare`; Miniflare/workerd runs locally. | workerd and Wrangler contract tests; account gate for deployment. | | [Cloudflare Shell Workspace](/docs/ecosystem/sandboxes/cloudflare-shell) | `@fabric-harness/cloudflare/computer`
Provider SDK: `@cloudflare/shell` `>=0.3.7 <0.4` | `examples/with-cloudflare-shell-workspace/` | `pnpm --dir examples/with-cloudflare-shell-workspace run build:cloudflare`. | Early preview on the Worker Loader beta; Wrangler/account gate. | | [Databricks SQL](/docs/ecosystem/sandboxes/databricks-sql) | `databricksSqlSandbox()` from `@fabric-harness/databricks/sql-sandbox` | `examples/with-databricks-compute/` | Mock HTTP contract suites run without a workspace. | Workspace, SQL Warehouse, and Unity Catalog gate. | | [AKS](/docs/ecosystem/sandboxes) | `aksSandbox()` from `@fabric-harness/azure` | — | Structural client tests. | Cluster and identity gate. | | [`azure-container-apps`](/docs/building/sandbox-connectors) | No first-party adapter; connect a project-owned client with `remoteSandbox()`. | — | — | Validate a project-owned adapter with `validateSandboxAdapter()`. | | [`azure-container-instances`](/docs/building/sandbox-connectors) | No first-party adapter; connect a project-owned client with `remoteSandbox()`. | — | — | Validate a project-owned adapter with `validateSandboxAdapter()`. | | [`firecracker`](/docs/building/sandbox-connectors) | No first-party adapter; connect a project-owned client with `remoteSandbox()`. | — | — | Validate a project-owned adapter with `validateSandboxAdapter()`. | | [boxd](/docs/ecosystem/sandboxes/boxd) | Community blueprint — no shipped adapter | — | — | Untested integration guide; `fh add boxd` scaffolds a project-owned adapter that you implement and validate. | | [exe.dev](/docs/ecosystem/sandboxes/exedev) | Community blueprint — no shipped adapter | — | — | Untested integration guide; `fh add exedev` scaffolds a project-owned adapter that you implement and validate. | | [islo](/docs/ecosystem/sandboxes/islo) | Community blueprint — no shipped adapter | — | — | Untested integration guide; `fh add islo` scaffolds a project-owned adapter that you implement and validate. | | [Mirage](/docs/ecosystem/sandboxes/mirage) | Community blueprint — no shipped adapter | — | — | Untested integration guide; `fh add mirage` scaffolds a project-owned adapter that you implement and validate. | | [smolvm](/docs/ecosystem/sandboxes/smolvm) | Community blueprint — no shipped adapter | — | — | Untested integration guide; `fh add smolvm` scaffolds a project-owned adapter that you implement and validate. | Rows marked **Community blueprint** are untested integration guides: TechFabric Harness does not ship or certify an adapter for those providers, and the `fh add` recipe scaffolds a project-owned adapter that you implement and validate yourself. Backends with no first-party adapter (`azure-container-apps`, `azure-container-instances`, `firecracker`) are reserved names in the `SandboxBackend` union; connect a project-owned provider client with `remoteSandbox()` and validate it with `validateSandboxAdapter()`. ## Deployment targets `fh build --target ` produces the deployable artifact offline for every target, and `fh deploy --preview` prints the deployment commands without executing them. Deploying itself requires the target's credentials and account configuration. | Target | Deploy driver | Example | Validation | | --- | --- | --- | --- | | [`node`](/docs/deployment/node) | `NodeDriver` in `@fabric-harness/cli` | `examples/hello-world/` | Source, artifact, and clean-install contract tests. | | [`temporal-worker`](/docs/deployment/temporal-worker) | `TemporalWorkerDriver` in `@fabric-harness/cli` | `examples/with-temporal/` | Local Temporal and replay parity contracts. | | [`docker`](/docs/deployment/docker) | `DockerDriver` in `@fabric-harness/cli` | `examples/with-docker/` | Container contract tests. | | [`foundry-hosted-agent`](/docs/deployment/foundry-hosted-agent) | `FoundryHostedAgentDriver` in `@fabric-harness/cli` | `examples/support-agent-foundry/` | Client and build contracts; subscription, identity, and region gate. | | [`cloudflare`](/docs/deployment/cloudflare) | `CloudflareDriver` in `@fabric-harness/cli` | `examples/with-cloudflare-sandbox/` | workerd/Miniflare and Wrangler tests; account gate. | | [`aks`](/docs/deployment/azure) | `AksDriver` in `@fabric-harness/cli` | — | Structural client tests; cluster, identity, and network-policy gate. | | [`aca`](/docs/deployment/azure) | `AcaDriver` in `@fabric-harness/cli` | — | Structural client tests; subscription and managed-identity gate. | | [`aci`](/docs/deployment/aci) | `AciDriver` in `@fabric-harness/cli` | — | Structural client tests; subscription and managed-identity gate. | | `k8s` | `K8sDriver` in `@fabric-harness/cli` | `examples/with-kubernetes/` | Manifest generation and structural tests; cluster gate. | | [`render`](/docs/deployment/render) | `RenderDriver` in `@fabric-harness/cli` | — | Build contracts; Render account gate. | | [`databricks-app`](/docs/deployment/databricks-app) | `DatabricksAppDriver` in `@fabric-harness/cli` | `examples/with-databricks-app-resources/` | Tier R certification with retained candidate, app, and restart digests. | | [`databricks-serving`](/docs/deployment/databricks) | `DatabricksServingDriver` in `@fabric-harness/cli` | `examples/with-databricks/` | Tier R certification with retained candidate, app, and restart digests. | `DatabricksAppDriver` and `DatabricksServingDriver` activate the optional `@fabric-harness/databricks` peer at deploy time. ## See also - [Sandboxes](/docs/ecosystem/sandboxes) — provider setup guides and live-validation gates. - [Sandboxes matrix](/docs/reference/sandboxes-matrix) — capability axes and certification levels per backend. - [Deployment overview](/docs/deployment) — what each build target produces and how to choose. - [Runnable examples](/docs/examples/runnable) — commands, expected proof, and cleanup for every example above. - [Capability matrix](/docs/reference/capability-matrix) — validation level and operational guidance by area. --- # Tooling Canonical: https://harness.techfabric.com/docs/ecosystem/tooling Evaluation and observability integrations that plug into Fabric evals, events, and telemetry. Fabric owns the eval and telemetry contracts (`@fabric-harness/evals`, `SubmissionTelemetrySink`, OTel span exporters) while applications own vendor accounts and credentials. The integrations below build on those seams, so vendor SDKs remain optional dependencies of your workspace. | Integration | What it adds | Guide | | --- | --- | --- | | [Braintrust](/docs/ecosystem/tooling/braintrust) | Eval logging and experiment comparison for `fh test` suites. | Recipe + env wiring. | | [Jetty](/docs/ecosystem/tooling/jetty) | Grades job output with a separately deployed rubric and stores comparable trajectories. | Deployment + rubric setup. | | [OpenTelemetry](/docs/ecosystem/tooling/opentelemetry) | Span export for prompts, tools, and submissions to any OTLP collector. | Exporter configuration. | | [Sentry](/docs/ecosystem/tooling/sentry) | Error capture for server routes and agent turns. | DSN + event hook wiring. | | [Vitest evals](/docs/ecosystem/tooling/vitest-evals) | Runs eval suites inside your existing Vitest setup. | Suite conventions. | Telemetry integrations observe execution — they never gate it. A sink or exporter failure is reported and swallowed; agent turns and submissions settle regardless. --- # Braintrust Canonical: https://harness.techfabric.com/docs/ecosystem/tooling/braintrust Export Fabric traces and evaluation context to Braintrust, so a run you are debugging and a score you are tracking sit together. Run `fh add braintrust` to install the current SDK and generate a managed, redacted observer plus its contract test. Attach stable job/agent/session/model metadata and keep evaluation datasets separate from production session storage. ```ts import { createObservabilityObserver } from '@fabric-harness/sdk'; import { initLogger } from 'braintrust'; const logger = initLogger({ projectName: 'fabric-harness' }); const onEvent = createObservabilityObserver({ integration: 'braintrust', correlation: { agentId: 'support', jobId: runId, submissionId, tenantId }, send: (record) => logger.log({ input: record.event, metadata: record.correlation }), }); const agent = await init({ onEvent }); ``` Prompt, output, tool, and customer content capture must be explicitly enabled and redacted. Keep the Braintrust API key host-side and flush the client during process shutdown. The default record contains event identity and correlation only. Set `captureData: true` only after reviewing the recursive key/secret redaction policy. A runnable fixture is in `examples/with-observability`. --- # Jetty Canonical: https://harness.techfabric.com/docs/ecosystem/tooling/jetty Grade TechFabric Harness job output and compare results across versions with Jetty. Jetty can grade output from a TechFabric Harness job and store the grading task as a trajectory. Use it when you need a persistent, comparable record of quality across prompts, models, or releases. Use [Fabric evals](/docs/building/evals) for fast local and CI assertions. ## Install ```sh fh add jetty ``` The managed recipe pins the published `@jetty/sdk 0.2.x` contract and creates a typed `gradeOutputWithJetty()` helper and verification test. Create and deploy a Jetty grading runbook before invoking it from TechFabric Harness. The runbook must produce the `grade.json` expected by `gradeWithJetty()`. ## Grade a job response ```ts title=".fabricharness/jobs/evaluate-triage.ts" import { defineAgent, schema } from '@fabric-harness/sdk'; import { gradeWithJetty, JettyClient } from '@jetty/sdk'; interface TriageGrade { total: number; pass: boolean; } const jetty = new JettyClient(); export default defineAgent({ name: 'evaluate-triage', input: schema.object({ ticket: schema.string() }), triggers: { manual: true }, async run({ input, prompt, run }) { const response = await prompt(`Triage this support ticket:\n\n${input.ticket}`); const { grade, trajectoryId } = await gradeWithJetty( jetty, process.env.JETTY_COLLECTION!, process.env.JETTY_GRADE_TASK!, { files: [{ filename: 'case.json', data: JSON.stringify({ ticket: input.ticket, response }), }], useTrialKeys: process.env.JETTY_USE_TRIAL_KEYS === 'true', labels: (result) => ({ 'eval.grade': String(result.total), 'eval.pass': String(result.pass), 'fabric.run_id': run?.runId ?? 'local', }), }, ); return { response, grade, trajectoryId }; }, }); ``` Run it on the Node target: ```sh fh run evaluate-triage --ticket "Customers cannot reset passwords" ``` `@jetty/sdk` requires Node.js. Keep the grader separate from the job being evaluated so a prompt change cannot silently change its own rubric. ## Environment | Variable | Purpose | | --- | --- | | `JETTY_API_TOKEN` | Authenticates the Jetty SDK. The SDK can also use its local token configuration. | | `JETTY_COLLECTION` | Collection that owns the grading task. | | `JETTY_GRADE_TASK` | Deployed grading task identifier. | | `JETTY_USE_TRIAL_KEYS` | Optional; set to `true` to use Jetty trial model keys. | The Fabric job still needs its model-provider credentials. Jetty credentials configure only the grading operation. ## Sensitive data Jetty trajectories may persist uploaded files, inputs, and outputs. Redact credentials, personal data, and regulated content before grading. Put grader credentials in Jetty secret parameters rather than initialization parameters or uploaded files, and review retention and access controls before grading production content. For a credential-free automated fixture using the same correlation and redaction contract, see `examples/with-observability`. --- # OpenTelemetry Canonical: https://harness.techfabric.com/docs/ecosystem/tooling/opentelemetry Export agent, model, tool, task and shell activity as OpenTelemetry spans, so an agent run appears in the tracing you already have. Fabric provides flat event exporters and a hierarchical observer. Your application owns the OpenTelemetry SDK, exporter, sampling, credentials, and shutdown lifecycle. ```sh fh add opentelemetry ``` The managed recipe installs the OpenTelemetry API and creates a hierarchical observer configured with content redaction and Foundry-compatible semantic conventions. ```ts import { trace } from '@opentelemetry/api'; import { init } from '@fabric-harness/sdk'; import { createOpenTelemetryObserver } from '@fabric-harness/sdk/otel-observer'; const observe = createOpenTelemetryObserver({ tracer: trace.getTracer('support-agent'), conventions: 'foundry', correlation: { agentId: 'support', jobId: runId, submissionId, tenantId }, }); const fabric = await init({ onEvent: observe }); ``` The observer creates nested turn, tool, shell, and task spans. `conventions: 'foundry'` emits `gen_ai.*` names and attributes compatible with Azure AI Foundry and OpenTelemetry GenAI consumers. Stable job, agent, session, submission, and tenant IDs are span attributes. Use `openTelemetryExporter()` when one flat span per duration-bearing Fabric event is preferable. Do not export prompts, tool arguments, or results without a deliberate redaction and retention policy. See [Telemetry](/docs/reference/telemetry) for exporters, attributes, and event coverage. --- # Sentry Canonical: https://harness.techfabric.com/docs/ecosystem/tooling/sentry Connect Fabric runtime tracing and errors to Sentry, so a failing agent raises the same alert as the rest of your services. Run `fh add sentry` to install the current Node SDK and generate a managed redacted event observer and test. Initialize Sentry before the Fabric runtime and attach stable job, agent, session, submission, and tenant-safe correlation fields. ```ts import * as Sentry from '@sentry/node'; import { createObservabilityObserver } from '@fabric-harness/sdk'; const onEvent = createObservabilityObserver({ integration: 'sentry', correlation: { agentId: 'support', jobId: runId, submissionId, tenantId }, send(record) { Sentry.addBreadcrumb({ category: 'fabric', message: record.event.type, data: record.correlation }); }, }); ``` Exclude secrets, prompts, tool arguments/results, and customer data unless an explicit scrubbed capture policy permits them. Flush Sentry during graceful shutdown. --- # Vitest Evals Canonical: https://harness.techfabric.com/docs/ecosystem/tooling/vitest-evals Combine Fabric eval suites with focused Vitest regression tests, so a prompt and the code around it are checked in one run. Fabric ships `@fabric-harness/evals` for case/scorer execution and uses Vitest for repository-level regression tests. Keep behavioral eval suites in `*.eval.ts`; use ordinary Vitest tests for deterministic runtime contracts. ```sh fh add vitest-evals ``` The managed recipe creates a credential-free `defineEvalSuite()` fixture and Vitest contract. Add `@fabric-harness/node` when the suite invokes a project agent rather than a pure runner function. ```ts title="test/hello.test.ts" import { describe, expect, it } from 'vitest'; import { runAgent } from '@fabric-harness/node'; describe('hello job', () => { it('runs without provider credentials', async () => { const run = await runAgent({ agent: 'hello', payload: { name: 'Ada' }, mock: true, }); expect(run.result).toContain('Ada'); }); }); ``` For multi-case scoring, use `defineEvalSuite()` and run `fh test`. CI can run both gates: ```sh pnpm vitest run fh test --json > eval-results.json ``` Eval artifacts can include prompts, outputs, tool results, and model judgments. Review them before uploading to CI or a hosted evaluation service. See [Evaluations](/docs/building/evals) and the [eval API](/docs/reference/eval-library). --- # Examples Canonical: https://harness.techfabric.com/docs/examples Runnable agents demonstrating fabric-harness features and deploy targets. Every example below is a self-contained workspace under `examples/` in the restricted [TechFabric Harness source repository](/docs/reference/source-access). You can evaluate the public packages without repository access by generating a project first. If you are learning the framework rather than looking up one integration, follow the [complete learning path](/docs/learning-paths). It orders the examples by lifecycle, capabilities, governance, durability, delivery, deployment, and operations. For the exact current package scripts, expected proof, shared failure behavior, and cleanup contract for every maintained workspace, use [Runnable examples](/docs/examples/runnable). ## Quickstart ```sh npx --yes @fabric-harness/cli@latest init harness-example cd harness-example npm install npx fh agents npx fh run JOB_NAME --mock ``` The table links open the source-access explanation. Authorized customers and partners can request repository access there to run the exact monorepo fixtures. ## By feature | Example | What it shows | Deploy target | | --- | --- | --- | | [`hello-world`](/docs/reference/source-access) | Bare minimum: one agent, one prompt. | Node | | [`minimal`](/docs/reference/source-access) | Smallest headless finite job. | Node | | [`with-config`](/docs/reference/source-access) | Workspace-level `config.ts` overrides. | Node | | [`with-approval`](/docs/reference/source-access) | Imperative approval gate via `session.approval.request()`. | Node | | [`with-checkpoint`](/docs/reference/source-access) | Snapshot a session, restart from a labeled checkpoint. | Node | | [`with-skill`](/docs/reference/source-access) | `session.skill()` invocation with typed result. | Node | | [`with-task`](/docs/reference/source-access) | Long-running tasks with checkpoints. | Node / Temporal | | [`with-tools`](/docs/reference/source-access) | Custom tool schemas. | Node | | [`with-finish-tool`](/docs/reference/source-access) | Schema-validated `finish` and explicit `give_up` result tools. | Node | | [`with-local-shell`](/docs/reference/source-access) | `LocalSandboxEnv` shell tool. | Node | | [`dynamic-agent`](/docs/reference/source-access) | Persistent state, hooks, capability/model changes, streamed data, and finish guards. | Node | | [`react-chat`](/docs/reference/source-access) | Persistent chat and finite runs through the public client and React protocol. | Node / Vite | ## Deploy targets | Example | Target | | --- | --- | | [`with-docker`](/docs/reference/source-access) | Docker sandbox | | [`with-kubernetes`](/docs/reference/source-access) | Kubernetes pod | | [`with-cloudflare-sandbox`](/docs/reference/source-access) | Cloudflare Containers sandbox | | [`with-cloudflare-shell-workspace`](/docs/reference/source-access) | Cloudflare Computer Workspace with just-bash and standard Harness tools | | [`with-cloudflare-workers-ai`](/docs/reference/source-access) | Cloudflare Workers AI binding (zero-API-key) | | [`with-azure`](/docs/reference/source-access) | Azure ACA / AKS | | [`with-daytona`](/docs/reference/source-access) | Daytona remote sandbox | | [`with-e2b`](/docs/reference/source-access) | E2B isolated sandbox with timeout and cleanup | | [`with-modal`](/docs/reference/source-access) | Modal sandbox | | [`with-vercel-sandbox`](/docs/reference/source-access) | Vercel Sandbox with cancellation and cleanup | | [`with-s3-source`](/docs/reference/source-access) | Mount an S3 prefix as a filesystem source | | [`with-temporal`](/docs/reference/source-access) | Durable Temporal worker | | [`with-databricks-simple`](/docs/reference/source-access) | Credential-free Databricks authoring smoke with a mocked model provider | | [`with-databricks-revenue-ops`](/docs/reference/source-access) | Golden Databricks App workload: OBO, Genie, SELECT-only SQL, exact Job approval, Lakebase recovery, and optional Temporal | | [`with-databricks`](/docs/reference/source-access) | Governed SQL/Unity Catalog analytics copilot; live Databricks required | | [`with-databricks-rag`](/docs/reference/source-access) | AI Search plus Unity AI Gateway RAG; live Databricks required | | [`with-databricks-dataeng`](/docs/reference/source-access) | Lakeflow pipeline operations; live Databricks required | | [`with-databricks-cost-attribution`](/docs/reference/source-access) | System Tables cost attribution with a generated Databricks SDK client | | [`with-analytics-copilot`](/docs/reference/source-access) | Credential-free proof of SELECT-only SQL and analytics steward policy; README includes live SP and OBO wiring | | [`with-databricks-managed-mcp`](/docs/reference/source-access) | Managed MCP discovery, rotating OBO auth, fail-closed effects, and governed lineage | | [`with-databricks-compute`](/docs/reference/source-access) | SQL Warehouse, Jobs, notebook, and App execution choices | | [`with-databricks-agent-service`](/docs/reference/source-access) | Unity Catalog Agent Services registration, grants, discovery, and teardown | | [`with-databricks-authoring-admin`](/docs/reference/source-access) | Approval-bound Serving, Unity Catalog, Workspace, and secret-reference administration | | [`with-databricks-genie-authoring`](/docs/reference/source-access) | Governed Genie management plus create → grant → Agent Mode invoke → exact cleanup | | [`with-databricks-jobs-authoring`](/docs/reference/source-access) | Policy-bound multi-task Jobs lifecycle and cleanup | | [`with-databricks-bundle-deploy`](/docs/reference/source-access) | Governed checked-in Asset Bundle validate/deploy/run/destroy with fingerprint drift detection | | [`with-databricks-rag-admin`](/docs/reference/source-access) | AI Search endpoint/index lifecycle plus governed query verification | | [`with-databricks-app-resources`](/docs/reference/source-access) | Native Databricks App resources, least-privilege bindings, preflight, and Bundle cleanup | | [`with-databricks-appkit-interop`](/docs/reference/source-access) | AppKit Beta agent invoking a read-only governed Harness tool through MCP | | [`with-databricks-ontology-export`](/docs/reference/source-access) | Credential-free Genie Ontology export: manifest → plan → feed hydration with idempotent re-run and PII absence proof | | [`with-postgres-store`](/docs/reference/source-access) | Postgres session persistence | | [`with-slack-channel`](/docs/reference/source-access) | Verified Slack event ingress to a persistent agent | | [`with-channel-adapters`](/docs/reference/source-access) | All 18 maintained channel adapters with signed ingress and governed replies | | [`agent-registry`](/docs/reference/source-access) | Vertical-neutral definitions, immutable versions, capability grants, budgets, and autonomy ceilings | | [`with-signal-messages`](/docs/reference/source-access) | Out-of-band typed signal messages | | [`with-packaged-skills`](/docs/reference/source-access) | Packaged skills and lazy resource loading | | [`with-imported-skills`](/docs/reference/source-access) | Build-time `SKILL.md` imports, packaged resources, and `defineSkill()` | | [`finite-jobs`](/docs/reference/source-access) | Typed parent/child jobs, middleware, run identity, and idempotent nested invocation | | [`scheduled-jobs`](/docs/reference/source-access) | Node cron scheduling, Cloudflare Cron build output, and HA lease guidance | | [`database-persistence`](/docs/reference/source-access) | One config selecting local libSQL, Turso, MySQL, or MongoDB unified persistence | | [`application-routes`](/docs/reference/source-access) | Authenticated Fetch routes and middleware composing durable dispatch and finite jobs | | [`with-mounted-agent-router`](/docs/reference/source-access) | Mounting the persistent-agent HTTP surface inside an application-owned server | ## Production and operations patterns | Example | What it proves | | --- | --- | | [`private-networking`](/docs/reference/source-access) | Deny-by-default Docker and Kubernetes egress with an explicit proxy path. | | [`with-observability`](/docs/reference/source-access) | Redacted, correlated Braintrust, Jetty, Sentry, OpenTelemetry, and evaluation evidence. | | [`operational-slos`](/docs/reference/source-access) | Stable operational metrics, policy evaluation, and importable Prometheus/Grafana assets. | ## Realistic use cases | Example | What it does | | --- | --- | | [`code-review`](/docs/reference/source-access) | Review a PR diff, produce inline comments. | | [`issue-triage-ci`](/docs/reference/source-access) | GH Actions agent that triages new issues. | | [`bug-reproducer`](/docs/reference/source-access) | Generate a minimal reproduction from a bug report. | | [`data-analyst`](/docs/reference/source-access) | Mount a CSV; answer SELECT-style questions. | | [`support-agent`](/docs/reference/source-access) | KB-grounded customer support. | | [`support-agent-cloudflare-r2`](/docs/reference/source-access) | Same, deployed on Cloudflare with R2-backed KB. | | [`support-agent-foundry`](/docs/reference/source-access) | Same, on Azure AI Foundry Hosted Agent. | | [`changelog-writer`](/docs/reference/source-access) | Drafts release notes from git log. | | [`incident-runbook`](/docs/reference/source-access) | Runs a runbook against an alert payload. | | [`api-docs-generator`](/docs/reference/source-access) | Generate API docs from source. | | [`schema-migration`](/docs/reference/source-access) | Plan a database schema migration. | | [`test-generator`](/docs/reference/source-access) | Generate Vitest tests from source. | | [`dependency-auditor`](/docs/reference/source-access) | Audit npm dependencies for risk. | | [`coding-agent-lite`](/docs/reference/source-access) | Minimal Claude-Code-style coding agent. | | [`remote-coding-agent`](/docs/reference/source-access) | Coding agent in a remote sandbox. | | [`release-notes`](/docs/reference/source-access) | Compose release notes from PRs and commits. | | [`voice-data-collector`](/docs/reference/source-access) | Voice intake — Realtime API + bring-your-own audio I/O. | ## Need a connector? When no example covers the provider you want, scaffold one in your own project: ```sh fh add daytona | claude fh add https://your-provider.example.com --category sandbox | claude fh add daytona --pr # open a draft PR with a stub ``` See the [connector catalog](/docs/building/connector-catalog) for the spec. ## What "runnable" means Credential-free examples demonstrate local wiring and deterministic model behavior. Provider-backed examples require the named provider, credentials, permissions, and the smoke test documented by that integration. Follow the [Databricks deployment guide](/docs/deployment/databricks) for workspace identity and certification. Each maintained example must identify prerequisites and authentication, a run command, an expected observable result, explicit failure behavior, and cleanup. The examples catalog is checked against the actual top-level workspaces so a shipped example cannot silently disappear from documentation. ## Follow-along guides - [Enterprise controls](/docs/building/enterprise-controls) — combine policy, approvals, tools, and budgets. - [Build and run artifacts](/docs/deployment/build-artifacts) — package finite jobs and persistent agents. - [Databricks App tutorial](/docs/deployment/databricks-app) — scaffold, mock-test, build, deploy, and add Lakebase. The credential-free Databricks examples cover the authoring flow. Configure the credentialed suite to verify Lakebase OAuth database credential exchange, App deployment, workspace permissions, and restart recovery in the target workspace. --- # Agent APIs Canonical: https://harness.techfabric.com/docs/getting-started/api-consistency The canonical APIs for finite, persistent, and provider-backed TechFabric Harness agents. TechFabric Harness has one public builder for each agent lifecycle: | Lifecycle | API | | --- | --- | | Finite, run-once agent | `defineAgent({ ... })` | | Persistent, addressable agent | `createAgent(AgentFunction, staticConfig?)` | | Databricks-backed finite agent | `defineDatabricksAgent({ ... })` | | Azure-backed finite agent | `defineAzureAgent({ ... })` | | Cloudflare-backed finite agent | `defineCloudflareAgent({ ... })` | Finite definitions receive the typed `AgentRunContext` with lazy `session`, `prompt`, `skill`, `task`, `shell`, and `invoke` helpers: ```ts import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ question: string }, string>({ run: ({ input, prompt }) => prompt(input.question), }); ``` Persistent definitions use a synchronous function and hooks. The returned string is the current instruction; static policy and durability remain visible to the host before the function renders: ```ts import { createAgent, useModel, useSandbox } from '@fabric-harness/sdk'; function Assistant() { useModel('anthropic/claude-sonnet-4-6'); useSandbox('virtual'); return 'Resolve the request, verify the answer, and explain the next step.'; } export default createAgent(Assistant, { durability: { maxAttempts: 5, timeoutMs: 60 * 60_000 }, }); ``` Provider definers accept typed custom control flow and inject their resolved bundle: ```ts import { defineDatabricksAgent } from '@fabric-harness/databricks'; export default defineDatabricksAgent<{ question: string }, string>({ run: async ({ databricks, input, prompt }) => { console.log(`Using ${databricks.tools.length} governed Databricks tools`); return prompt(input.question); }, }); ``` Omitting `run` uses the provider definer's question-and-answer behavior. Explicit provider configuration is resolved first; otherwise the definer uses request environment variables and supports `FABRIC_MOCK=1`. Definition tools override same-named bundle tools, policies compose as security floors, and all standard definition fields—including `target`, `subscriptions`, `middleware`, and `init`—are forwarded consistently. Provider bundle factories remain separate and composable: use `databricks()`, `azure()`, `cloudflare()`, `node()`, `docker()`, or another backend factory when you want to assemble the runtime yourself. `pnpm examples:check` prevents removed aliases from returning to public examples or scaffolds, and smoke-tests a freshly packed `fh init --model mock/test-model --store memory` scaffold: the generated project's own `npm run run` must return a mock response with no `--mock` flag (the gate skips cleanly when the npm registry is unreachable). --- # Configuration Canonical: https://harness.techfabric.com/docs/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` ```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: | Variable | Purpose | | --- | --- | | `FABRIC_MODEL` | Default `provider/model-id` for `fh run`. | | `FABRIC_TARGET` / `FABRIC_HARNESS_TARGET` | Default `--target` for `fh run`. | | `FABRIC_TEMPORAL_TASK_QUEUE` | Default Temporal task queue. | | `FABRIC_TEMPORAL_ADDRESS` | Default Temporal address. | | `FABRIC_TEMPORAL_NAMESPACE` | Default Temporal namespace. | | `FABRIC_DOCKER_TEST` | Gates 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: ```txt .env .env.local .fabricharness/.env .fabricharness/.env.local ``` For local development, put provider keys once in the repo-level `.env.local`: ```sh 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 ` only for overrides; repeatable explicit env files override auto-loaded files but not shell env. ```sh 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: ```ts 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. --- # Your First Agent Canonical: https://harness.techfabric.com/docs/getting-started/first-agent Build a hook-composed persistent agent, then compare the finite typed-job lifecycle. import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; Fabric has two intentional lifecycles. Start with a hook-composed **persistent agent** when the same address receives messages over time. Use a finite `defineAgent({ run })` job when one bounded, schema-validated invocation should return one result. > The runtime (`stateless`, `inline`, `temporal`) is configured at `init()` and is independent of which entrypoint you import from. ## Start with an agent function Create `.fabricharness/agents/assistant.ts`: ```ts import { createAgent, useModel, useSandbox, } from '@fabric-harness/sdk'; function Assistant() { useModel('openai/gpt-5.5'); useSandbox('virtual'); return `Help the user solve their problem. Verify important claims and explain the next concrete step.`; } export default createAgent(Assistant, { durability: { maxAttempts: 5, timeoutMs: 60 * 60_000 }, }); ``` The named function is the readable center of the agent. Its return value becomes the instruction; hooks attach capabilities in composition order. `createAgent()` preserves Harness's explicit, discoverable persistent identity and keeps retry, timeout, policy, trigger, and initial-data metadata available to the host before the function renders. Run two messages against the same address: ```sh fh agents fh describe assistant fh run assistant --id demo --new --prompt "What can TechFabric Harness deploy?" --mock fh run assistant --id demo --prompt "Which target fits a long approval wait?" --mock ``` ### What developers see The executable output remains text so it can be copied into tests and support records. The representative terminal state below shows the evidence a completed run exposes without displaying credentials or provider internals. Use [Dynamic agents and hooks](/docs/building/dynamic-agents) for conditional tools, durable state, lifecycle callbacks, MCP, and subagents. ## Scaffold a project with `fh init` ```sh npx @fabric-harness/cli init my-first-agent cd my-first-agent npm install fh dev --mock ``` `fh init` scaffolds a runnable agent, role, skill, and config. Skip ahead to step 4 below to test it. Choose persistence explicitly when the project needs it: ```sh fh init support-app --template minimal --store memory fh init support-app --template minimal --store sqlite fh init support-app --template minimal --store postgres ``` `memory` is the infrastructure-free unified bundle. `postgres` generates `postgresPersistence()` and reads `DATABASE_URL` from the environment. `file` and `sqlite` configure the existing local session backends; use Postgres or Lakebase when submissions, streams, attachments, and finite runs must survive process replacement. Templates include `default`, `minimal`, `data-analyst`, `support-agent`, `cloudflare`, `temporal`, and `databricks`. ## Build a finite typed job ## 1. Create the workspace (manual) A TechFabric Harness workspace is any directory with a `.fabricharness/` folder. ```sh mkdir my-first-agent cd my-first-agent mkdir -p .fabricharness/jobs npm init -y npm install @fabric-harness/sdk @fabric-harness/cli ``` ## 2. Write the agent Create `.fabricharness/jobs/ask.ts`: ```ts import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'ask', input: schema.object({ question: schema.string() }), output: schema.string(), triggers: { webhook: true }, run: ({ input, prompt }) => prompt(input.question), }); ``` `defineAgent({...})` lazily creates one default session and exposes `prompt`, `skill`, `task`, and `shell` directly in `run`. Use `session()` when you need a named session or another session-level API. Headless defaults still apply through the bare SDK import. The runtime stores and invokes this finite definition as a job. ```ts import { defineAgent, schema } from '@fabric-harness/sdk/strict'; export default defineAgent({ name: 'ask', description: 'Answers a question using the configured model.', input: schema.object({ question: schema.string().describe('Question to answer'), }), output: schema.string(), model: process.env.FABRIC_MODEL ?? 'openai/gpt-5.5', triggers: { webhook: true }, run: async ({ init, input }) => { const fabricAgent = await init({ runtime: 'inline', sandbox: 'local', compaction: { enabled: false }, }); const session = await fabricAgent.session(); return await session.prompt(input.question); }, }); ``` From `/strict` every option is declared in source — nothing implicit. Required for Temporal-backed durability and recommended for compliance workloads. Both forms register a finite job (`fh describe ask` works on either). Either import supports schemas, policy, artifacts, and skills — strict just refuses to inject defaults. `triggers.webhook: true` exposes the job at `POST /jobs/ask` on Node-derived targets and Cloudflare. ## 3. List and describe From the workspace root: ```sh fh agents fh describe ask fh run ask --question "What is TechFabric Harness?" --mock ``` `describe` prints the input/output schema, declared model, default target, and any examples. Use `--json` if you need machine-readable output. ## 4. Run it ```sh fh run ask --question "What is Temporal?" --mock ``` Behind the scenes the CLI: 1. Discovers `.fabricharness/jobs/ask.ts`. 2. Loads workspace config (`.fabricharness/config.ts`, optional). 3. Picks a model — CLI flag → `FABRIC_MODEL` env → config → agent default. 4. Validates the input against the declared Fabric schema. 5. Calls `run({ input, prompt, skill, task, shell, session })`. 6. Validates the output against the declared Fabric schema. 7. Persists the session under `.fabricharness/sessions/`. Other ways to pass payload: ```sh fh run ask --payload '{"question":"What is Temporal?"}' fh run ask question="What is Temporal?" fh run ask --payload-file input.json echo '{"question":"hi"}' | fh run ask --stdin ``` ## 5. Use a real model Put provider keys once in the repo-level `.env.local`; TechFabric Harness auto-loads repo/workspace `.env` and `.env.local` files, and shell env still wins. ```sh cp .env.example .env.local # edit .env.local and set OPENAI_API_KEY=... fh run ask --model openai/gpt-5.5 --question "What is Temporal?" ``` For repeated use, put the model in `.fabricharness/config.ts` so you do not need `--model` either. > **Never** paste API keys into source files or session artifacts. Use `.env.local`, a secret store, or shell environment variables. ## 6. Inspect what happened ```sh fh sessions fh inspect fh logs fh metrics ``` ## Next steps - [Workspace layout](/docs/getting-started/workspace-layout) — the rest of `.fabricharness/`. - [Configuration](/docs/getting-started/configuration) — `config.ts`, env precedence, model defaults. - [Building agents](/docs/building/anatomy) — skills, roles, tools, sandboxes. - [CLI reference](/docs/cli) — every command. --- # TechFabric Harness in 5 minutes Canonical: https://harness.techfabric.com/docs/getting-started/five-minutes Run your first agent in one file with zero credentials, or scaffold a full workspace. The fastest path needs no workspace, no Docker, and no API keys: install the CLI, write one file, run it. The mock model answers offline; add a provider key later without changing the agent. ## 1. Install the CLI ```sh npm install -g @fabric-harness/cli ``` This provides the `fabric-harness` binary (alias `fh`). Inside a project, prefer the version pinned by that project (`npx fh`) over a global install — see [Installation](/docs/getting-started/installation). ## 2a. Run one file (no workspace) Write `agent.ts`: ```ts title="agent.ts" import { defineAgent, schema } from '@fabric-harness/sdk'; export default defineAgent({ name: 'hello', input: schema.object({ message: schema.string() }), output: schema.string(), run: async ({ init, input }) => { const fabric = await init(); const session = await fabric.session(); return session.prompt(input.message); }, }); ``` Run it: ```sh fh run ./agent.ts --message "hi" ``` ```text [fabric-harness] no model credentials resolved; using the mock model (set FABRIC_MODEL or pass --model for a real provider). [fabric-harness] session hello-4edbadf5-… completed (memory store — not persisted). Mock response: hi ``` `fh run` transpiles the file on the fly, resolves `@fabric-harness/sdk` from the nearest `node_modules` (falling back to the CLI's own install), and — because no model credentials resolve — falls back to the deterministic mock model. The full model loop, schema validation, and session lifecycle still execute. See [`fh run` single-file mode](/docs/cli/run#single-file-mode) for multi-export files and payload flags. ## 2b. Or scaffold a workspace A workspace adds discovery, persistent agents, config, and deployment targets. The scaffold and the first run also work offline: ```sh npx @fabric-harness/cli init my-agent --template minimal cd my-agent npm install ``` ```sh npx fabric-harness agents npx fabric-harness run hello --name Preetham --mock ``` ```text hello Greet a user. Mock response: Say hello to Preetham. ``` Validate readiness — Node, ESM setup, dependencies, agent discovery, session storage, model resolution, and tool schemas: ```sh npx fabric-harness doctor --getting-started --tools ``` Or start the HTTP/SSE dev server: ```sh npx fabric-harness dev --mock curl http://localhost:3000/jobs/hello \ -H 'content-type: application/json' \ -d '{"name":"Preetham"}' # {"result":"Mock response: Say hello to Preetham.","runId":"…"} ``` Create more definitions without writing boilerplate: ```sh npx fabric-harness new job summarize-report npx fabric-harness new agent support ``` ## 3. Test without credentials Everything above runs offline. The same mock story extends to unit tests, mock sandbox handles for remote providers, and `fh test` eval suites — see [Test without credentials](/docs/building/test-without-credentials). ## 4. Add a real model Put a provider key in `.env.local`; TechFabric Harness auto-loads it and shell env still wins: ```sh echo 'OPENAI_API_KEY=sk-...' > .env.local npx fabric-harness doctor --live --model openai/gpt-5.5 npx fabric-harness run hello --name Preetham # or: fh run ./agent.ts --message "hi" --model openai/gpt-5.5 ``` See [Model providers](/docs/building/model-providers) for the supported providers and credential resolution order. ## Choose the next runtime | Need | Use | | --- | --- | | Fast no-container agent | `sandbox: 'virtual'` | | CI/repo automation with host tools | `sandbox: 'local'` plus scoped `defineCommand()` commands | | Untrusted code or data analysis | Docker sandbox | | Human approval delays or restart durability | Temporal runtime | | Edge/serverless endpoint | Cloudflare target | Start with the minimal template, then add only the enterprise controls your use case needs: policy, approvals, audit, cost budgets, durable workflows, and deployment attestations. --- # Headless agents with the default import Canonical: https://harness.techfabric.com/docs/getting-started/headless-mode The 10-line path to a working headless agent — defineAgent({...}) with headless defaults injected. TechFabric Harness separates three choices that are easy to mix up: - **Entrypoint** — `@fabric-harness/sdk` for headless defaults, or `@fabric-harness/sdk/strict` for no implicit behaviour. - **Runtime** — `stateless`, `inline`, or `temporal`. - **Target** — where the agent runs, such as `node`, `temporal-worker`, `docker`, or `cloudflare`. This page shows the smallest headless setup: the default `@fabric-harness/sdk` import with headless defaults. The same `init()`, `session.prompt()`, `session.shell()`, `session.skill()`, and `session.task()` APIs work from `@fabric-harness/sdk/strict` too. > **One SDK, two import entrypoints.** The minimal entrypoint is not a separate framework and not a less capable runtime. It keeps imports small and applies headless defaults. Durability still comes from `runtime`, not the import path. ## The 7-line agent ```ts title=".fabricharness/jobs/echo.ts" import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ message: string }>({ name: 'echo', triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init({ model: 'openai/gpt-5.5' })).session(); return { reply: await session.prompt(input.message) }; }, }); ``` Run it: ```bash export FABRIC_MODEL=openai/gpt-5.5 export OPENAI_API_KEY=... fabric-harness run echo --message "hello" ``` Or expose it as a webhook: ```bash fabric-harness dev curl -X POST http://localhost:3000/jobs/echo \ -H "Content-Type: application/json" \ -d '{"message":"hello"}' ``` That's it. No schemas to define, no policy to author, no session store to configure. ### Defaults applied automatically The default `@fabric-harness/sdk` import injects headless defaults so the snippet stays minimal. Each is overridable per call: | Default | Why | Override with | | --- | --- | --- | | `runtime: 'stateless'` | Headless / edge / one-shot agents often do not need persistence | `init({ runtime: 'inline' })` to keep an in-memory session, or `'temporal'` for durable workflows | | `sandbox: 'virtual'` | In-memory bash + filesystem (`grep`, `glob`, `read`, `cat`, `mkdir`, `rm`, `echo`) via [`just-bash`](https://github.com/vercel-labs/just-bash). No host shell access. | `init({ sandbox: 'local' })` for host shell, `'docker'` for isolation, or a `SandboxFactory` | | `loopRuntime: pi-agent-core` | Multi-provider model coverage from [`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai) — Anthropic, OpenAI, Google, OpenAI-compatible proxies, OpenRouter, etc. | `init({ loopRuntime: defaultLoopRuntime })` to use Fabric's `NativeLoopRuntime` (with capability-policy + result-retry hooks) | | `compaction: { enabled: true }` | Long headless sessions compact automatically before they exceed model context limits. | Pass an explicit `compaction` option to `init()` or use `/strict` for fully explicit runtime configuration. | For Temporal-backed agents or workloads that require every runtime option to be explicit, import `defineAgent` from `@fabric-harness/sdk/strict`. Typed I/O, policy, approvals, artifacts, and metadata are available from both entry points. ## What the pieces do ### `defineAgent({...})` `defineAgent({ run })` gives the handler a compile-time input type. Without `input` and `output` schemas, values pass through without runtime validation. Add schemas when inputs cross a trust boundary or other code depends on a stable result shape. ### `runtime: 'stateless'` Disables session persistence. No store writes, no artifact disk persistence, no approval waiting. Each invocation is independent. This is the right choice for: - High-volume webhook handlers where state would just be discarded. - Edge runtimes (Cloudflare Workers, Vercel Edge) with no durable storage attached. - Quick prototypes where conversation continuity isn't yet a concern. In production (`FABRIC_ENV=production` or `NODE_ENV=production`), choosing `inline` without an explicit `SessionStore` will emit a warning unless you set `FABRIC_ALLOW_EPHEMERAL_STATE=1` or pick `runtime: 'stateless'` explicitly. This prevents surprise data loss. ### Default and strict entry points The default entry point exports the complete public SDK and applies friendly headless defaults. `@fabric-harness/sdk/strict` exports the same core primitives but does not inject runtime, sandbox, loop-runtime, or compaction defaults. ## Minimal does not mean feature-light The minimal entrypoint skips import weight and ceremony, not the shared agent primitives. Skills, roles, scoped commands, MCP tools, and tasks all work — they just do not require typed input/output metadata or a policy authoring step. ### Skills (Markdown-defined procedures) Drop a Markdown file under `.fabricharness/skills/` and call it from your agent. Skills are discovered automatically by the workspace loader. ```md title=".fabricharness/skills/triager.md" --- name: triager description: Search the knowledge base for the best matching article and write a concise, friendly reply. --- You are a customer support triager. Steps: 1. Use grep / glob / read over `/workspace/kb` to find articles relevant to the customer's question. 2. Quote the most directly relevant lines. 3. Write a 2–4 sentence reply in the brand's voice (friendly, concise, no jargon). 4. If nothing matches, say so honestly and suggest the customer contact support@example.com. ``` ```ts title=".fabricharness/jobs/support.ts" import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ message?: string }>({ name: 'support', triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init({ runtime: 'stateless' })).session(); const message = input.message ?? ''; const reply = await session.skill('triager', { args: { message } }); return { reply }; }, }); ``` `session.skill('triager', { args })` injects the skill body as the prompt, templates the args in, and returns the model's response. The same primitive exists from both entrypoints. Complete metadata agents can also declare default inline skills with `defineAgent({ skills: [...] })` and can add `result: schema` for typed validation. ### Roles (system-prompt overlays) Roles let you change the agent's voice or expertise without rewriting the prompt every time. Drop a Markdown file under `.fabricharness/roles/`: ```md title=".fabricharness/roles/concise.md" --- name: concise description: Reply in 1-3 sentences. No bullet points unless explicitly asked. Plain prose only. --- You write extremely concise replies. Aim for 1–3 sentences. Use plain prose, not bullet points or headings, unless the user asked for structured output. Never repeat the question back. Never apologize for the length of the answer. ``` Use it on a session, prompt, or skill call: ```ts const session = await agent.session('thread-1', { role: 'concise' }); await session.prompt('What does this code do?'); // uses 'concise' await session.skill('triager', { args, role: 'concise' }); // override on the call ``` Precedence: per-call `role` > session `role` > agent `role`. ### Scoped commands (privileged CLIs) `defineCommand` binds a CLI like `gh` or `npm` with its env (and therefore its secrets) at the *command* level — secrets never enter model context. Grant the command per-call: ```ts import { defineAgent, defineCommand } from '@fabric-harness/sdk'; const gh = defineCommand('gh', { env: { GH_TOKEN: process.env.GH_TOKEN } }); const npm = defineCommand('npm'); export default defineAgent<{ issueNumber?: number }>({ name: 'triage', run: async ({ init, input }) => { const session = await (await init({ sandbox: 'local', runtime: 'stateless' })).session(); const result = await session.skill('triage-issue', { args: { issueNumber: input.issueNumber }, commands: [gh, npm], // available only inside this skill call }); return { result }; }, }); ``` The agent can run `gh issue view 42 ...` because `gh` is in `commands`. It cannot read `GH_TOKEN` directly — the token is bound to the `gh` invocation by the runtime, not exposed to the model. ### Tasks (delegated subagents) `session.task(prompt, options?)` runs a child session with its own message history but the same sandbox/filesystem — perfect for parallel research or focused subgoals. ```ts const research = await session.task('Read /workspace/kb/billing/* and summarize the refund policy in 5 bullets.'); const reply = await session.prompt(`Use this research to answer the customer:\n\n${research}`); ``` Tasks support a `role` and `cwd` override, so you can run them as a "researcher" without changing the parent role. ### Mounting a knowledge base Combine `withFilesystemSources` with the bare `@fabric-harness/sdk` import for a compact support agent in ~25 lines: ```ts import { defineAgent, localDirectorySource, withFilesystemSources } from '@fabric-harness/sdk'; const sandbox = withFilesystemSources('empty', [{ mountAt: '/workspace/kb', source: localDirectorySource('./knowledge-base', { include: (p) => p.endsWith('.md') }), }]); export default defineAgent<{ message?: string }>({ name: 'support', triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init({ sandbox, runtime: 'stateless' })).session(); const reply = await session.skill('triager', { args: { message: input.message ?? '' }, }); return { reply }; }, }); ``` See [Filesystem sources](/docs/reference/filesystem-sources) for more. ### MCP tools `connectMcpServer` works the same from the bare `@fabric-harness/sdk` import — just don't forget to `close()` the connection in a `finally`: ```ts import { connectMcpServer, defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ prompt?: string }>({ name: 'gh-assist', run: async ({ init, input, env }) => { const github = await connectMcpServer('github', { url: 'https://mcp.github.com/mcp', headers: { Authorization: `Bearer ${env?.GITHUB_TOKEN}` }, }); try { const session = await (await init({ tools: github.tools, runtime: 'stateless' })).session(); return await session.prompt(input.prompt ?? ''); } finally { await github.close(); } }, }); ``` ## Progressive disclosure: when to switch to /strict The minimal entrypoint can be a starting point. Add production features one by one as the work demands them: | You want to... | Switch to... | What changes in the agent | | --- | --- | --- | | Validate inputs / outputs | `defineAgent({ input, output, run })` | Add Fabric schemas; definitions without schemas pass values through. | | Restrict shell / tools | `policy: CapabilityPolicy` on `init` or `session.prompt` | Allow/deny/requireApproval lists. | | Bind a privileged CLI | `defineCommand('gh', { env: { GH_TOKEN } })` + `commands: [gh]` | Secrets bound at the command, never exposed to the model. | | Run a Markdown skill | `session.skill('triage', { args, result })` | Drop the skill into `.fabricharness/skills/triage.md`. | | Persist conversations | `runtime: 'inline'` + a `SessionStore` (SQLite/Postgres/file from `@fabric-harness/node`) | Same `init()`, just pass `store`. | | Write durable artifacts | `session.artifact(name, content)` | Requires a store that implements `putArtifact`. | | Survive crashes / restarts | `runtime: 'temporal'` + `@fabric-harness/temporal` | The agent code is unchanged; the runtime swaps. | ## Minimal vs complete entrypoint at a glance ```ts title="Default import: 10 lines" import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent({ name: 'echo', run: async ({ init, input }) => { const session = await (await init({ runtime: 'stateless' })).session(); return { reply: await session.prompt(String(input.message ?? '')) }; }, }); ``` ```ts title="Strict import: typed I/O + policy + artifacts + skills" import { defineAgent, schema } from '@fabric-harness/sdk/strict'; import type { CapabilityPolicy } from '@fabric-harness/sdk/strict'; const policy: CapabilityPolicy = { commandPolicy: { allow: ['git status*', 'git diff*'], deny: ['git push*'], requireApproval: ['gh issue comment**'], }, maxCommandTimeoutMs: 30_000, }; const inputSchema = schema.object({ issueNumber: schema.number(), title: schema.string() }); const outputSchema = schema.object({ severity: schema.enum(['low','medium','high']), summary: schema.string() }); export default defineAgent({ name: 'triage', input: inputSchema, output: outputSchema, model: process.env.FABRIC_MODEL, skills: [{ name: 'triage', content: 'Triage the issue and return a concise structured result.' }], run: async ({ init, input }) => { const session = await (await init({ policy })).session(); const result = await session.skill('triage', { args: input, policy, result: outputSchema }); await session.artifact('triage.md', `# ${input.title}`, { contentType: 'text/markdown' }); return result; }, }); ``` The CLI, dev server, and deploy targets are shared. The SDK entrypoint and runtime choice are independent; see [SDK entrypoints, runtimes, and targets](/docs/reference/sdk-entrypoints-runtimes-targets). ## Anti-patterns - **Don't fork your code into minimal and complete copies.** Graduate features in place when you need typed I/O, policy, durable stores, telemetry, or provider classes. - **Don't use `runtime: 'stateless'` when you need approvals.** Stateless mode has no durable store, so approval waiting and later resolution are unavailable. - **Don't import from both `@fabric-harness/sdk` and `@fabric-harness/sdk/strict` in the same job.** Pick the default-injecting or explicit entry point for that module. - **Don't assume durability from the import path.** Use `runtime: 'temporal'` or a durable store explicitly. ## See also - [examples/minimal](/docs/reference/source-access) — the 10-line example end-to-end. - [examples/support-agent](/docs/reference/source-access) — minimal entrypoint + filesystem-mounted knowledge base. - [SDK entrypoints, runtimes, and targets](/docs/reference/sdk-entrypoints-runtimes-targets) — how the choices fit together. - [Runtime modes](/docs/reference/runtime-modes) — `inline` vs `stateless` vs `temporal`. - [Filesystem sources](/docs/reference/filesystem-sources) — mount read-only content into the sandbox. --- # Installation Canonical: https://harness.techfabric.com/docs/getting-started/installation Install TechFabric Harness from npm and verify the CLI works, which takes about a minute and needs no Docker or cloud account. import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; TechFabric Harness ships as a set of npm packages under the `@fabric-harness/*` scope. The CLI installs a `fabric-harness` (alias `fh`) binary; the SDK is added per-workspace. ## Prerequisites - **Node.js 20.18+** for the core SDK, CLI, and Node runtime - **Node.js 22 LTS recommended** for new projects - **Node.js 22+ required** for `@fabric-harness/databricks` - **npm 10+**, **pnpm 10+**, or **yarn 4+** - *(optional)* **Docker** for the Docker sandbox - *(optional)* **Temporal** (local dev server) for the Temporal worker target - An LLM provider API key (e.g. `OPENAI_API_KEY`) when you want real model calls. Some optional Node APIs have narrower requirements: the built-in SQLite stores need Node 22.5 or newer, and native client WebSocket support needs Node 22 or a polyfill. See [release and documentation status](/docs/reference/release-status) for the package-by-package contract. ## 1. Install the CLI For a new project, run the published CLI directly and let the scaffold install a compatible local CLI and SDK together: ```sh npx --yes @fabric-harness/cli@latest init my-agents cd my-agents npm install npx fh --version ``` Use a global CLI only when you want `fh` available outside a project: ```sh npm install -g @fabric-harness/cli ``` ```sh pnpm add -g @fabric-harness/cli ``` ```sh yarn global add @fabric-harness/cli ``` Inside a project, prefer `npx fh` (or an npm script). It resolves the version pinned by that project and prevents a global CLI update from getting ahead of its SDK and target packages. ## 2. Bootstrap a workspace manually A TechFabric Harness workspace is any directory with a `.fabricharness/` folder. ```sh mkdir my-agents cd my-agents npm init -y mkdir -p .fabricharness/jobs ``` ## 3. Add the SDK The bare `@fabric-harness/sdk` is enough for most agents. Add the deploy-target package only if you need it. ```sh npm install @fabric-harness/sdk ``` ```sh npm install @fabric-harness/sdk @fabric-harness/cloudflare ``` ```sh npm install @fabric-harness/sdk @fabric-harness/temporal ``` ```sh npm install @fabric-harness/sdk @fabric-harness/azure ``` > **Strict mode** (`@fabric-harness/sdk/strict`) is a sub-path export of the same package — no separate install needed. ### All published packages | Package | Purpose | |---|---| | `@fabric-harness/cli` | The `fh` / `fabric-harness` binary. | | `@fabric-harness/sdk` | Core SDK. Default + `/strict` entry points. | | `@fabric-harness/client` | Typed HTTP, SSE, and WebSocket client for jobs and persistent agents. | | `@fabric-harness/node` | Node deploy target, HTTP server, SQLite/Postgres session stores. | | `@fabric-harness/agent-registry` | Runtime-neutral agent definitions, immutable versions, enrollment, capability grants, budgets, and identity bindings. | | `@fabric-harness/channels` | Slack, GitHub, Teams, Discord, Telegram, WhatsApp, and other channel adapters. | | `@fabric-harness/react` | React hooks and components for the TechFabric Harness protocol. | | `@fabric-harness/databases` | Database integrations and discoverable database configuration helpers. | | `@fabric-harness/temporal` | Temporal worker target + activities. | | `@fabric-harness/cloudflare` | Cloudflare Worker target, R2 sources, Cloudflare Sandbox helpers. | | `@fabric-harness/azure` | Azure OpenAI provider, Key Vault secret resolver, Foundry hosted agent target. | | `@fabric-harness/connectors` | Sandbox connectors (Daytona, E2B, Modal), object-storage sources (S3, Azure Blob). | | `@fabric-harness/databricks` | Unity AI Gateway, SQL, Unity Catalog, AI Search/RAG, Lakebase, Jobs, Asset Bundle lifecycle, and Databricks Apps. | | `@fabric-harness/evals` | Evaluation harness. | | `@fabric-harness/vite` | Optional Vite composition for Harness development and portable builds. | ## 4. Verify Run the doctor command from your workspace: ```sh npx fh doctor --tools ``` No provider key is required to run agents — `--mock` (and single-file auto-mock) keeps everything offline; see [TechFabric Harness in 5 minutes](/docs/getting-started/five-minutes) and [Test without credentials](/docs/building/test-without-credentials). To verify a real model end-to-end: ```sh echo 'OPENAI_API_KEY=sk-...' > .env.local npx fh doctor --live --model openai/gpt-5.5 ``` ## 5. Write your first agent Persistent agents are ordinary synchronous functions. Hooks compose the harness; the returned string is the instruction rendered for the current interaction: ```ts title=".fabricharness/agents/assistant.ts" import { createAgent, useModel, useSandbox } from '@fabric-harness/sdk'; function Assistant() { useModel('openai/gpt-5.5'); useSandbox('virtual'); return 'Answer clearly, verify important claims, and keep the conversation moving.'; } export default createAgent(Assistant, { durability: { maxAttempts: 5, timeoutMs: 60 * 60_000 }, }); ``` ```sh npx fh agents npx fh describe assistant npx fh run assistant --id first-conversation --new --prompt "What is Temporal?" npx fh run assistant --id first-conversation --prompt "Why would I use it?" ``` The second message addresses the same persistent instance, so it continues the conversation. If the configured model responds, you're ready for [your first agent](/docs/getting-started/first-agent). ## Updating ```sh npm update -g @fabric-harness/cli # CLI npm update @fabric-harness/sdk # SDK + add-ons in your workspace ``` The runtime reliability update is a coordinated portable-runtime release: `@fabric-harness/sdk@6.2.0`, `@fabric-harness/node@6.2.0`, `@fabric-harness/cloudflare@2.4.0`, and `@fabric-harness/cli@6.7.0`. CLI `6.7.0` generates Databricks projects on the independently versioned `@fabric-harness/databricks@^7.1.1` line. Upgrading the portable runtime does not change Databricks workload source, deployment configuration, or its optional peer range. Releases follow semver, and the npm registry exposes each package's current version and release history. See [release and documentation status](/docs/reference/release-status) for the current package matrix and migration links. --- # Workspace Layout Canonical: https://harness.techfabric.com/docs/getting-started/workspace-layout What lives in the .fabricharness directory and why, so you can find an agent, a role or a skill without searching for it. TechFabric Harness uses `.fabricharness/` as the embedded workspace directory. The CLI walks up from your current working directory to find the nearest workspace root. ## Directory shape ```txt .fabricharness/ jobs/ # Finite defineAgent({ run }) definitions ask.ts agents/ # Persistent createAgent() definitions support.ts roles/ # Markdown role overlays engineer.md reviewer.md skills/ # Reusable Markdown procedures triage-issue/ SKILL.md fix-tests/ SKILL.md policies/ # Optional capability/security policies default.ts production.ts sandboxes/ # Project-specific sandbox factories local.ts docker.ts sessions/ # Persisted session state (gitignore-friendly) build/ # Emitted build artifacts (gitignored) config.ts # Optional central config (model, target, temporal, ...) AGENTS.md # Repo-level agent guidelines (cross-tool standard) ``` ## What each folder does ### `jobs/` Each `.ts` file default-exports `defineAgent({...})`. These agents have a finite `run` handler and are admitted by the runtime at `POST /jobs/:name`. ### `agents/` Persistent, addressable agents default-export `createAgent(AgentFunction, staticConfig?)`. The named function uses hooks to compose capabilities and returns its current instruction. Sessions survive individual messages and are addressed at `/agents/:name/:id`. See [Agent anatomy](/docs/building/anatomy). ### `roles/` Markdown files with optional YAML frontmatter. Roles are **system-prompt overlays**, not user messages. Precedence is **call role → session role → agent role**. ### `skills/` Each skill lives in its own directory with a `SKILL.md`. Frontmatter declares name, description, and (optionally) model. The body is the instructional prompt. ### `policies/` Optional. Capability policies that scope filesystem reads/writes, allowed commands, network egress, and required approvals. ### `sandboxes/` Project-specific factories that return a `SandboxEnv`. Use this when the built-in `local`/`docker`/`empty` sandboxes don't cover your needs. ### `sessions/` Session history, tasks, approvals, checkpoints, and artifacts persisted by the file-backed session store. SQLite and Postgres stores are also available — see [Session stores](/docs/reference/session-stores). ### `build/` Output of `fh build`. Each target produces its own subdirectory: ```txt .fabricharness/build/ node/ docker/ temporal-worker/ cloudflare/ foundry-hosted-agent/ ``` ### `config.ts` Optional. See [Configuration](/docs/getting-started/configuration). ### `AGENTS.md` A repo-level Markdown file that tools across the agent ecosystem look for. Use it to capture project-wide guidelines (preferred libraries, security expectations, never-do's). --- # Audit export Canonical: https://harness.techfabric.com/docs/operating/audit-export Stream session audit logs to JSONL, CSV, Datadog Logs, or any HTTP collector. Every state-changing action a fabric-harness session takes — model calls, tool calls, approvals, webhook deliveries, errors — lands as a `SessionEntry` in the session log. `fh export-audit` walks that log and emits one row per entry, with normalized columns. ## Local export ```sh fh export-audit # JSONL to stdout fh export-audit --format csv --output audit.csv # CSV to file ``` Pipe to `jq` for ad-hoc filtering: ```sh fh export-audit ask-1f4f... | jq -c 'select(.type=="model_attempt") | {model, costUsd}' ``` ## Datadog Logs Ship straight to the Datadog HTTP intake: ```sh fh export-audit \ --to datadog \ --datadog-api-key env://DATADOG_API_KEY \ --datadog-site us5.datadoghq.com \ --service my-saas ``` - Batches in groups of 500 rows. - Adds `ddsource: 'fabric-harness'`, `service`, and `ddtags: 'session:,tenant:'`. - Defaults `--datadog-site` to `datadoghq.com` (US1). ## Splunk HEC ```sh fh export-audit \ --to splunk \ --splunk-url https://splunk.example.com:8088/services/collector/event \ --splunk-token env://SPLUNK_HEC_TOKEN \ --splunk-source fabric-harness \ --splunk-sourcetype fabric:audit ``` Each row is wrapped in a Splunk HEC envelope (`{ event, source, sourcetype, time }`) and POSTed in batches of 200. The `time` field uses `entry.timestamp` (epoch seconds) so Splunk indexes events at their original time. ## BigQuery ```sh fh export-audit \ --to bigquery \ --bigquery-project my-gcp-project \ --bigquery-dataset audit \ --bigquery-table fabric_harness \ --gcp-access-token env://GCP_TOKEN ``` Uses BigQuery's `tabledata.insertAll` REST endpoint. Caller supplies a pre-issued OAuth access token (Workload Identity, ADC, GCS impersonation, etc.) — fabric-harness doesn't bake in `google-auth-library`. Batches at 500 rows per request; each row gets a deterministic `insertId` so retries deduplicate cleanly. Schema in BigQuery should match the audit row shape; missing columns are tolerated via `ignoreUnknownValues: true`. ## Generic HTTP collector For Splunk HEC, Logflare, an internal NDJSON ingestor, etc., point `--to http`: ```sh fh export-audit \ --to http \ --url https://collector.internal/audit \ --auth-token env://COLLECTOR_TOKEN ``` Posts a single NDJSON body (`application/x-ndjson`) with each row as one line. Bearer-token auth is optional. ## Row shape Every row carries these columns when populated: | Column | Source | |---|---| | `timestamp`, `type`, `sessionId`, `entryId`, `parentId` | session entry envelope | | `tenantId` | session-level tenant id | | `tool`, `command`, `model`, `provider`, `durationMs` | per-entry metadata | | `inputTokens`, `outputTokens`, `cachedInputTokens`, `cacheWriteTokens`, `costUsd` | usage from `model_attempt` entries | | `approvalId`, `audience` | approval lifecycle entries | | `eventType`, `idempotencyKey` | webhook deliveries | | `errorMessage` | error entries | Streams line-by-line — handles large sessions without buffering. ## Backfill / replay `fh export-audit` reads from any configured `SessionStore` — file-backed, SQLite, or Postgres. Run it as a periodic job to push the last hour's sessions to your SIEM, or on-demand when investigating an incident. --- # Cost Attribution Canonical: https://harness.techfabric.com/docs/operating/cost-attribution Enforce budgets against real Databricks spend and attribute cost by agent, user, and tenant. The SDK cost-budget tracks per-call USD from a static price table — good for immediate, synchronous protection, but it doesn't know your **real** Databricks spend (model serving, SQL, AI Search, AI Functions, Genie, Lakeflow, Feature Serving — all measured in DBUs in System Tables). Cost reconciliation closes that gap: enforce `perScope` budgets against actuals while keeping estimates for `perCall`/`perSession`. ## Hybrid enforcement The key idea maps the existing limit tiers to what each can know: - **`perCall` / `perSession`** stay estimate-based → immediate, synchronous soft caps. They catch a runaway agent **now**. - **`perScope`** (tenant / agent / user) becomes the real-spend hard cap via an external `ActualCostSource` → retroactive, cross-process. It catches sustained overspend on the **next** call. System Tables lag 15–60 minutes, so actual enforcement is intentionally lagged — but the estimate tiers cover the window. A model call is **never** blocked on a warehouse query: actuals are fetched asynchronously after the response, cached (default 60s), and a violation is enforced before the next call. ## Databricks tenant limit ```ts import { databricksTenantCostLimit } from '@fabric-harness/databricks'; const costLimit = databricksTenantCostLimit(client, warehouseId, tenantId, { perDayUsd: 50, cacheTtlMs: 60_000, }); const fabric = await init({ costLimit /* …model, tools, policy */ }); ``` This returns a `CostLimit` with `scopeSource: 'external'` and a Databricks `ActualCostSource` that queries `system.billing.usage` joined to `system.billing.list_prices`, filtered by `fabric.*` custom tags, cached per scope key. Existing `tenantCostLimit` / `postgresCostBudgetStore` usage is unchanged — `scopeSource` defaults to `incremental`. ## Attribution dimensions Spend is attributed across **agent · user · tenant · model · provider · session · turn**. Stamped onto each `ModelUsage` and tool-call entry, these answer "which agent/user/tenant spent what": ```ts const breakdown = await databricksActualCostSource(client, warehouseId).queryAttribution({ tenantId: 'acme', startDate: '2026-06-01', endDate: '2026-06-23', groupBy: ['agentId', 'userId'], }); // → [{ agentId, userId, tenantId, period, estimatedUsd, actualUsd, actualDbus, deltaUsd, calls }] ``` `queryAttribution` is for offline/ops/dashboard use (it may scan large windows), not inline enforcement. `cost_limit` events carry `actualsFetchedAt` / `cacheTtlMs` so consumers understand the lag. ## Attribution contract Attributing spend to a specific agent/tenant requires Databricks resources to carry `fabric.*` custom tags (which flow into `system.billing.usage.custom_tags`). The Databricks deploy targets can tag the resources they create; for untagged / bring-your-own setups, scope coarsely by warehouse/endpoint + time window. ## See also - [Multi-tenancy](/docs/operating/multi-tenancy) · [Databricks](/docs/deployment/databricks) - Example: `examples/with-databricks-cost-attribution` (runs against a mocked warehouse). --- # Secrets, Retention, and Residency Canonical: https://harness.techfabric.com/docs/operating/data-governance Runtime secret providers, enforceable data retention, residency checks, and signed deletion evidence. ## Runtime secret providers Commands use `secret('NAME')` references. The model and session log see the reference name, never the resolved value. Compose providers in deployment order and pass one resolver into the agent: ```ts import { chainSecretProviders, environmentSecretProvider, secretResolver } from '@fabric-harness/sdk'; import { vaultSecretProvider } from '@fabric-harness/node'; const secrets = chainSecretProviders( environmentSecretProvider({ allow: ['LOCAL_TOKEN'] }), vaultSecretProvider({ address: process.env.VAULT_ADDR!, token: () => workloadIdentityVaultToken(), namespace: 'platform', pathForSecret: (name, tenantId) => `tenants/${tenantId}/${name}`, }), ); const fabric = await init({ resolveSecret: secretResolver(secrets) }); ``` Provider failures stop resolution instead of falling through to a less-governed provider. Use workload identity or a rotating token callback rather than embedding a provider credential in source. ### Azure Key Vault ```ts import { azureKeyVaultSecretProvider } from '@fabric-harness/azure'; const keyVault = azureKeyVaultSecretProvider({ vaultUrl: 'https://my-vault.vault.azure.net', token: () => managedIdentityAccessToken(), }); ``` ### Databricks Secrets ```ts import { databricksSecretsProvider } from '@fabric-harness/databricks'; const workspaceSecrets = databricksSecretsProvider({ host: process.env.DATABRICKS_HOST!, token: () => appServicePrincipalToken(), scope: (_name, tenantId) => `fabric-${tenantId}`, }); ``` The Databricks adapter calls Secret Management at runtime and decodes the returned value inside the provider closure. Workspace tokens and secret values are not added to model messages, events, audit entries, or telemetry. ## Retention policy `enforcePersistenceRetention()` applies independent age limits to sessions, conversation streams, attachments, audit storage, and telemetry storage. External audit and telemetry systems provide a `deleteBefore()` adapter, so a configured rule cannot silently report success without deleting from that system. ```ts import { enforcePersistenceRetention } from '@fabric-harness/node'; const result = await enforcePersistenceRetention(persistence, { sessions: { maxAgeDays: 30 }, conversationStreams: { maxAgeDays: 14 }, attachments: { maxAgeDays: 7 }, audit: { maxAgeDays: 365, target: siemRetentionTarget }, telemetry: { maxAgeDays: 30, target: tracingRetentionTarget }, residency: { region: 'us-west-2', allowedRegions: ['us-west-2'] }, }); ``` Run the coordinator from a singleton scheduled job. Session expiry uses the bundle's cascade deletion path, which removes submissions, conversation streams, and attachments together. Attachment timestamps are used when available; older stored references inherit their session update time. ## Residency `assertDataResidency(region, allowedRegions)` fails before data maintenance or export when the deployment region is not allowed. Use the same configured region for the database, object backup location, audit sink, telemetry sink, and Databricks workspace. Region labels are application policy inputs; cloud network and IAM controls must independently prevent cross-region endpoints. ## Signed deletion evidence Wrap a persistence bundle to emit an append-only completion record after each successful cascade deletion: ```ts import { hmacDeletionEvidenceSigner, postgresDeletionEvidenceStore, postgresPersistence, withDeletionEvidence, } from '@fabric-harness/node'; const base = postgresPersistence({ client: pool }); const persistence = withDeletionEvidence(base, { signer: hmacDeletionEvidenceSigner({ key: process.env.DELETION_EVIDENCE_KEY!, keyId: 'retention-2026-01', }), store: postgresDeletionEvidenceStore(pool), }); ``` The receipt contains deletion counts, completion time, key id, signature, and a digest chained to the previous record. Session and tenant identifiers are stored only as keyed HMAC pseudonyms. Prompts, messages, filenames, attachment bytes, and other deleted content are never copied into the evidence record. Use `ed25519DeletionEvidenceSigner()` when verifiers must validate records without access to the signing key. --- # Backup and Disaster Recovery Canonical: https://harness.techfabric.com/docs/operating/disaster-recovery Versioned Postgres and Lakebase migrations, object backups, readiness, and recovery drills. TechFabric Harness uses the same migration and recovery path for PostgreSQL and Databricks Lakebase. Migrations are ordered, recorded in `fabric_harness_schema_migrations`, and serialized with a PostgreSQL advisory lock. Each version runs in its own transaction. ```ts import { postgresPersistence } from '@fabric-harness/node'; const persistence = postgresPersistence({ client: pool }); await persistence.migrate(); ``` Calling `migrate()` from several replicas is safe. Exactly one connection owns the migration lock, while the other replicas wait and then read the completed ledger. Rollback is available only for versions with an explicit `down` migration; TechFabric Harness refuses a destructive implicit rollback. ## Object backup The logical backup runs in a `REPEATABLE READ`, read-only transaction. Binary attachments and artifacts are encoded without losing bytes. The complete payload receives a SHA-256 digest before it is sent to object storage. ```ts import { backupPostgresPersistence, httpBackupObjectStore, } from '@fabric-harness/node'; const objectStore = httpBackupObjectStore({ // Return a short-lived S3/R2 presigned URL, Azure Blob SAS URL, or an // authenticated internal object-gateway URL for this key. urlForKey: (key) => backupUrlFor(key), headers: async (method, key) => backupHeadersFor(method, key), }); const backup = await backupPostgresPersistence({ client: pool, objectStore, objectKey: `production/${new Date().toISOString()}.json`, }); console.log(backup.sha256, backup.tables, backup.bytes); ``` Lakebase uses the same call after exchanging the Databricks workspace identity for a short-lived database credential. Workspace tokens and database passwords are never written into the backup object. ## Restore Restore verifies the digest and exact TechFabric Harness table set before changing the database. It then takes an exclusive restore lock, truncates the managed tables, restores every row in one transaction, and resets identity sequences. ```ts import { restorePostgresPersistence } from '@fabric-harness/node'; await restorePostgresPersistence({ client: pool, objectStore, objectKey: 'production/2026-07-09T08:00:00.000Z.json', }); ``` Stop application writes before restore. Keep the API unready until restore and post-restore verification finish. ## Readiness `/ready` checks the session and submission stores. A configured persistence bundle also contributes its health result. Add worker and provider dependencies with `readiness`: ```ts await startDevServer({ readiness: async () => ({ temporalWorker: { ok: await temporalWorkerIsPolling() }, modelServing: { ok: await servingEndpointIsReady() }, }), }); ``` Any failed or rejected dependency returns HTTP `503`, so Kubernetes, Databricks Apps, and load balancers stop routing work to an incomplete replica. ## Recovery targets A practical production starting point is: | Workload | Backup interval | Reference RPO | Reference RTO | | --- | ---: | ---: | ---: | | Human-facing agents | 5 minutes | 5 minutes | 30 minutes | | High-value automation | 1 minute plus database WAL/PITR | 1 minute | 15 minutes | | Development | Daily | 24 hours | 2 hours | Use provider-native WAL or point-in-time recovery in addition to TechFabric Harness logical backups when the required RPO is below the backup interval. Exercise the application-level path with `runPostgresRecoveryDrill()` in an isolated database. It creates an object backup, invokes your failure simulation, restores, runs your verification callback, and fails when `maxRpoSeconds` or `maxRtoMs` is exceeded. ```ts const result = await runPostgresRecoveryDrill({ client: drillPool, objectStore, objectKey: `drills/${Date.now()}.json`, maxRpoSeconds: 300, maxRtoMs: 30 * 60_000, simulateFailure: () => destroyDrillDatabaseState(), verify: () => verifyReferenceSessionsAndAttachments(), }); ``` --- # Multi-tenancy Canonical: https://harness.techfabric.com/docs/operating/multi-tenancy Stamp tenant ids on sessions, scope listings and reads per tenant, and gate webhook deliveries by tenant header. fabric-harness exposes a single concept for multi-tenancy: an opaque `tenantId` string. fabric-harness never interprets it — host applications map it to whatever identity model they own (organizations, customers, projects, workspaces). What fabric-harness provides: - Stamping: every entry, event, and approval emitted by a session carries `tenantId`. - Cross-tenant guard: appending to a session that belongs to a different tenant throws. - Listing filter: `listSessionSummariesFromStore(store, { tenantId })` returns only that tenant's sessions. - Server scoping: `fh dev` and generated Node builds read `X-Fabric-Tenant` (or `?tenant=`) and apply the filter plus `404` responses on cross-tenant reads. ## Stamping a session ```ts const fabric = await init({ tenantId: 'tenant-acme', // ...other options }); const session = await fabric.session(); // tenantId inherited // or override per-session: const ad = await fabric.session(undefined, { tenantId: 'tenant-globex' }); ``` `tenantId` propagates from `AgentInit` → `SessionOptions` → every `SessionEntry`, `FabricEvent`, and `ApprovalRequest` the session emits. ## Cross-tenant guard If two `init()` calls (possibly from different hosts) target the same session id but disagree on the tenant, the second one throws `POLICY_DENIED`. This catches accidental cross-tenant writes early — better than silent corruption. ## CLI ```sh fh sessions --tenant tenant-acme # filter listing fh run hello --tenant tenant-acme # stamp on the spawned session fh export-audit # tenantId column appears on every row ``` ## HTTP server ```sh curl -H 'X-Fabric-Tenant: tenant-acme' http://localhost:9111/sessions curl -H 'X-Fabric-Tenant: tenant-acme' -d '{"text":"hi"}' \ http://localhost:9111/agents/edge-summarizer/$(uuidgen) ``` - Listing: only sessions stamped with the matching tenant are returned. - Read: a 404 is returned when the loaded session's tenant differs from the header (no information leak about session existence). - Write: spawned session inherits the header's tenantId. Set `FABRIC_HARNESS_TENANT_REQUIRED=1` to reject any request that omits the header. ## Identity layer is yours fabric-harness deliberately doesn't ship a "tenants table" or auth integration. Bring your own: - Map `X-Fabric-Tenant` to your SaaS tenant ids in your reverse proxy. - Enforce per-tenant cost ceilings via `costLimit.perScope + scopeKey`. Use `tenantId` as the scope key. - Combine with `approvalRules.audience` — emit approvals to per-tenant audience channels (`reviewer:tenant-acme`). ## See also - [Cost budgets → Cross-process aggregation](/docs/building/model-providers#cross-process-aggregation) - [Audit export](/docs/operating/audit-export) - [Rate limiting](/docs/operating/rate-limiting) --- # Operational SLOs Canonical: https://harness.techfabric.com/docs/operating/operational-slos Stable runtime metrics, SLO evaluation, alerts, dashboards, and cross-target conformance. TechFabric Harness defines low-cardinality metrics for the operational signals that matter across Node, Temporal, Cloudflare, and Databricks Apps: | Metric | Meaning | | --- | --- | | `fabric_harness_request_latency_ms` | End-to-end HTTP or application request latency | | `fabric_harness_submission_duration_ms` | Admission-to-settlement duration | | `fabric_harness_queue_age_ms` | Admission-to-worker-start delay | | `fabric_harness_errors_total` | Failed requests, submissions, events, and recovery attempts | | `fabric_harness_approval_wait_ms` | Approval request-to-terminal-decision delay | | `fabric_harness_recovery_duration_ms` | Worker or persistence recovery duration | | `fabric_harness_cost_usd_total` | Attributed model and serving cost | ## Collect and export ```ts import { createOperationalMetricsCollector } from '@fabric-harness/sdk'; const metrics = createOperationalMetricsCollector(); const config = { onEvent: (event) => metrics.recordEvent(event), submissionTelemetry: metrics.submissionSink, }; application.get('/metrics', () => new Response(metrics.openMetrics(), { headers: { 'content-type': 'application/openmetrics-text; version=1.0.0' }, })); ``` Call `recordRequest(durationMs, outcome)` at the HTTP or application boundary and `recordRecovery(durationMs, recovered)` around recovery drills. The collector keeps bounded samples and exports count, sum, p50, p95, and p99. ## Evaluate a service objective ```ts import { evaluateOperationalSlos } from '@fabric-harness/sdk'; const evaluation = evaluateOperationalSlos(metrics.snapshot(), { requestLatencyP95Ms: 2_000, queueAgeP95Ms: 5_000, errorRateMax: 0.01, approvalWaitP95Ms: 4 * 60 * 60_000, recoveryP95Ms: 60_000, costUsdMax: 1_000, }); ``` The runnable `examples/operational-slos` workspace includes an importable Grafana dashboard and Prometheus alert rules for every metric above. Adjust the reference thresholds to the user journey and recovery tier of each deployment. ## Deployment conformance `runDeploymentConformance()` is the same black-box client suite for every deployment target. It checks health, dependency readiness, asynchronous finite job settlement and event offsets, plus persistent-agent submission settlement and conversation offsets. ```ts import { assertDeploymentConformance } from '@fabric-harness/client'; await assertDeploymentConformance({ target: 'databricks-app', baseUrl: process.env.DATABRICKS_APP_URL!, headers: { authorization: `Bearer ${process.env.APP_TOKEN}` }, job: { name: 'analyst', input: { question: 'SELECT 1' } }, timeoutMs: 120_000, pollIntervalMs: 1_000, signal: AbortSignal.timeout(125_000), }); ``` Health and readiness probes retry bounded startup failures (`502`, `503`, `504`), network startup errors, and a non-ready response body until `timeoutMs`. Authentication and routing failures such as `401` and `404` fail immediately. Job and persistent-agent lifecycle probes are never invoked until readiness passes, and `signal` cancels both startup polling and lifecycle waits. The live workflow runs this contract against a local Node host, a real Temporal cluster behind the Node HTTP API, local and deployed Cloudflare Workers, and the reference Databricks App. Each run writes a redacted JSON evidence artifact. --- # Rate limiting Canonical: https://harness.techfabric.com/docs/operating/rate-limiting Token-bucket throttling for outbound provider calls, keyed per API key. When many sessions / agents share a process, they can stampede a single provider API key — bursting past quota and triggering 429s. fabric-harness ships a generic token-bucket primitive that throttles outbound calls per key. ## Configure on a provider ```ts import { OpenAICompatibleModelProvider, tokenBucketRateLimiter } from '@fabric-harness/sdk'; const limiter = tokenBucketRateLimiter({ tokensPerSecond: 50, // sustained throughput burst: 200, // peak capacity }); const provider = new OpenAICompatibleModelProvider({ baseUrl: 'https://api.openai.com/v1', apiKey: process.env.OPENAI_API_KEY!, defaultModel: 'gpt-4o', rateLimiter: limiter, }); ``` `OpenAICompatibleModelProvider` and `AnthropicModelProvider` accept `rateLimiter`. Each call (`generate` and `stream`) calls `await limiter.acquire()` before sending the request. ## Bucket keys The provider hashes the API key into a short opaque string (`:`) and uses that as the bucket key. Practical implications: - Two providers using the same API key share the same bucket — quota stays honest. - Two providers with different API keys (e.g. OpenAI Tier 4 + Tier 1) get separate buckets automatically. - Raw keys never appear in logs or metric labels — only the hash prefix. ## Reusing the limiter elsewhere `tokenBucketRateLimiter()` returns a generic `RateLimiter`. Use it inside connectors, webhook fan-out, or anywhere you want simple throttling: ```ts const httpLimiter = tokenBucketRateLimiter({ tokensPerSecond: 10, burst: 20 }); async function callExternalApi(url: string) { await httpLimiter.acquire(`api:${new URL(url).host}`); return fetch(url); } ``` Aborts mid-wait when an `AbortSignal` is passed to `acquire({ signal })`. ## Cross-process throttling (Redis) `@fabric-harness/node` ships `redisRateLimiter()` for fleets that share an API key — multiple containers, autoscaled workers, multi-region. Same `RateLimiter` interface, atomic Lua-script refill on the Redis side. ```ts import { OpenAICompatibleModelProvider } from '@fabric-harness/sdk'; import { redisRateLimiter } from '@fabric-harness/node'; import Redis from 'ioredis'; // or @upstash/redis — only `eval` is required const limiter = redisRateLimiter({ client: new Redis(process.env.REDIS_URL!), tokensPerSecond: 100, burst: 500, keyPrefix: 'fh:rl', // optional; defaults to fh:rl }); const provider = new OpenAICompatibleModelProvider({ baseUrl: 'https://api.openai.com/v1', apiKey: process.env.OPENAI_API_KEY!, rateLimiter: limiter, }); ``` **Compatible clients:** anything that exposes `eval(script, keys, args)` matching the standard Redis Lua surface. Tested against `ioredis` and `@upstash/redis`. fabric-harness has no dependency on either — bring your own. **Atomicity:** every `acquire` runs a single Lua script that reads the bucket, refills based on elapsed time, and either consumes tokens or returns the wait duration. No race window. **Bucket TTL:** Redis keys auto-expire 60s after the bucket would be fully refilled, so abandoned bucket keys (e.g. one-off API keys) eventually disappear. ## See also - [Cost budgets](/docs/building/model-providers#spend-caps) — for USD ceilings - [Multi-tenancy](/docs/operating/multi-tenancy) --- # Supply-chain Evidence Canonical: https://harness.techfabric.com/docs/operating/supply-chain Release SBOMs, licenses, NOTICE review, vulnerability and secret scans, digests, provenance, and attestations. Every TechFabric Harness release tag runs the `Release supply-chain evidence` workflow. High or critical dependency advisories, a secret finding, a package without Apache-2.0 metadata, an incompatible dependency license, a missing NOTICE file, an import failure, or a digest mismatch blocks the release. The release gate also compares the canonical file contents of every locally packed version that already exists on npm with the registry tarball. Changing package contents without a changeset and version bump therefore fails CI instead of silently creating source/registry drift. For the Databricks package, the gate also rejects JavaScript files left in the ignored `dist` directory by an older build layout. This keeps local release artifacts reproducible with clean CI builds and prevents stale generated files from being included in a tarball accidentally. Run the same evidence generation locally: ```sh pnpm run build pnpm run check:supply-chain ``` The command writes: | Artifact | Contents | | --- | --- | | `release-packages/*.tgz` | Exact npm package subjects used for attestation | | `release-sbom.cdx.json` | CycloneDX 1.5 component inventory | | `release-license-report.json` | Dependency versions, licenses, and package URLs | | `release-notice-review.json` | Per-package NOTICE digest and attribution review | | `release-secret-scan.json` | Packed-package secret-pattern scan result | | `release-vulnerability-report.json` | Complete `pnpm audit` result and severity totals | | `release-provenance.intoto.json` | In-toto statement with SLSA v1 build predicate | | `release-artifact-digests.json` | SHA-256 for every package subject and evidence file | `verify-supply-chain-evidence.mjs` recalculates every digest. CI also runs Gitleaks across repository history. On release tags, GitHub's OIDC identity signs build-provenance and SBOM attestations for the retained tarballs through `actions/attest-build-provenance` and `actions/attest-sbom`. ### Vulnerability waivers `check-vulnerabilities.mjs` fails on any high or critical advisory and derives severity totals from the audit advisories, so pnpm-native waivers apply: list a CVE under `pnpm.auditConfig.ignoreCves` in the root `package.json` only when no fixed release exists and the issue is otherwise remediated (for example by a `patchedDependencies` patch). Every waiver must say why it is safe. Current waivers: `CVE-2025-71329` and `CVE-2025-71330` (`image-size` ICNS/JXL/HEIF infinite loops; no fixed `image-size` release exists, so the parsers are fixed by `patches/image-size@2.0.2.patch`). The gate fails closed: if the audit request itself fails (registry error, timeout, or a non-JSON/incomplete response), it retries with exponential backoff — `VULN_AUDIT_ATTEMPTS` (default 3), `VULN_AUDIT_RETRY_MS` (default 2000, doubling per attempt), `VULN_AUDIT_TIMEOUT_MS` (default 180000) — and exits nonzero without writing a report when no attempt completes. A failed audit can never pass as "zero vulnerabilities". Evidence artifacts are retained for 90 days in GitHub Actions. Copy them to the organization's immutable release archive when policy requires longer retention. npm packages also publish with `publishConfig.provenance: true`, so registry consumers can verify the npm provenance statement independently. ## Verify a release Download the release evidence artifact, then run: ```sh node scripts/verify-supply-chain-evidence.mjs gh attestation verify artifacts/release-packages/*.tgz \ --repo Fabric-Pro/fabric-harness ``` The first command verifies local SHA-256 integrity. The second verifies the keyless GitHub attestation identity and repository binding. --- # Agent behavior Canonical: https://harness.techfabric.com/docs/reference/agent-behavior The default tools, execution environment, message handling, context rules, and runtime limits that govern a TechFabric Harness agent. This page collects the runtime behavior that affects an agent regardless of which API starts it. It describes the model-visible tool contract, queueing, context composition, cancellation, and terminal outcomes. Authoring types and signatures remain in the [API reference](/docs/reference/api). ## SDK entry points The default `@fabric-harness/sdk` entry point supplies documented headless defaults for finite agents. `@fabric-harness/sdk/strict` does not silently inject them: finite agents must configure their model and sandbox explicitly. Persistent `createAgent()` definitions render their resources for each delivered interaction on both entry points. A session has one sandbox environment at a time. Without an executable/filesystem-capable sandbox, the corresponding built-in tools either are absent or fail capability discovery. Skills describe behavior but never grant filesystem, command, network, credential, or connector permissions. ## Built-in tools The model-facing built-ins are bounded even though host-side `session.fs` and `SandboxEnv` methods remain whole-file, programmatic APIs. ### `read` Parameters are `path`, optional `offset`, and optional `limit`. `offset` is a 1-indexed line number. - Output contains at most 2,000 lines or 50 KiB, whichever is reached first. - Ordinary lines are never split. Truncated output names the shown line range and the next offset. - An offset past EOF is an error that includes the actual line count. - If the first requested line alone exceeds 50 KiB, its first valid UTF-8 prefix is returned with a warning that the rest of that line cannot be reached through line-based paging. ### `write` and `edit` `write` replaces a file with the supplied string or bytes. `edit` performs exact text replacement using `path`, `oldText`, `newText`, and optional `replaceAll`. Without `replaceAll`, `oldText` must occur exactly once. Zero matches report an exact-match error; multiple matches ask for more surrounding context. With `replaceAll`, every occurrence is replaced. Writes and edits targeting the same resolved path are serialized in dispatch order. Mutations to different paths remain concurrent. A shell process modifying the same path does not participate in this in-process lock. ### `bash` Parameters are `command`, optional `cwd`, `env`, and `timeout` in milliseconds. - Combined stdout/stderr is bounded to the last 2,000 lines or 50 KiB while exit metadata remains available in the `ShellResult`. - A tool-requested timeout is returned as recoverable exit code `124` so the model can react. - A host cancellation still throws and ends the turn. If a remote process cannot confirm cancellation, the error says it may still be running and its eventual settlement is observed out of band rather than entering model context. ### `grep` Parameters are `pattern`, optional `path`, `include`, `ignoreCase`, `literal`, and `maxMatches`. The tool probes for `rg` once per sandbox and falls back to POSIX `grep`. Results contain file path, line number, and text. The framework returns at most 100 matches and 500 characters per result line, even if a larger `maxMatches` is requested. ### `glob` Parameters are `pattern`, optional `cwd`, and `maxMatches`. Patterns match file names rather than full paths, following `find -name` semantics. Results are deterministically sorted and capped at 1,000 paths. | Limit | Value | | --- | --- | | `read` output | 2,000 lines / 50 KiB, head with continuation offset | | `bash` output | 2,000 lines / 50 KiB, tail | | `grep` output | 100 matches / 500 characters per line | | `glob` output | 1,000 paths | | Nested task depth | 4 | ## Message admission and ordering Persistent interactions are admitted durably as submissions before model work starts. Submissions for the same agent instance and named session are FIFO; separate sessions may run concurrently. One attempt owns a submission at a time through a fenced lease. When a delivery arrives while a response is active, it may join at the next model-turn boundary. If it misses that boundary or joining is disabled, it remains queued as its own submission. A joined delivery records which host submission answered it, and tenant, actor, instance, and named-session boundaries are never crossed. Every admitted submission reaches one canonical terminal outcome: - `completed` — canonical work finished successfully. - `failed` — a permanent error, exhausted retry budget, or execution timeout terminated the work. - `aborted` — durable user/operator abort intent won before terminal settlement. Terminal reservation and finalization are idempotent. A stale or orphaned attempt cannot overwrite the first canonical outcome. ## Cancellation, timeout, and recovery Cancellation propagates through the submission, session, model, tool, sandbox, and deployment adapter when those layers support signals. A signal-aware operation receives one macrotask to surface its own cancellation result. A signal-deaf tool is then abandoned: its late fulfillment or rejection is consumed, discarded, and cannot append output to terminal history. A live submission cannot extend its execution deadline by heartbeating indefinitely. At the first observed timeout or durable abort, the coordinator signals the active attempt. If it still has not settled after 60 seconds, a storage-only supervisor rechecks ownership and force-settles it. Abort takes precedence over timeout when both are present; already-completed canonical work remains completed. Node and generated Cloudflare runtimes use the same observable state machine. ## Context composition At session initialization the runtime composes instructions from agent/session/call roles, with precedence `call > session > agent`. Roles are system-prompt overlays, not persisted user messages. The runtime also contributes the available tool, skill, subagent, and sandbox workspace context. Dynamic resources are recalculated at model-turn boundaries. Changes are appended as resource signals so prior turns keep the instructions and tool set they actually observed. Conditional tool additions caused by a tool-result batch are anchored to that batch's final tool result for providers that support deferred tool loading; the marker is persisted so restart and replay build the same provider history. Default SDK sessions use model-aware compaction near the context window, keeping recent messages verbatim and folding older history into a summary. Strict sessions compact only when explicitly configured. Deterministic Temporal paths apply their documented replay restrictions. ## Telemetry and sensitive data Submission, attempt, turn, and tool correlation metadata is available by default. Prompt, model, tool, and credential content remains opt-in and is sanitized before observer export. Settlement is a telemetry backstop: any span still open for that submission is closed with `fabric.span.forced_close=settlement`; normally closed spans do not carry the attribute. Secrets are resolved only at the narrow trusted runtime boundary. Raw secret values must not enter model context, events, traces, checkpoints, generated projects, or terminal errors. ## Target differences Backend capabilities are discovered rather than assumed. Node, Cloudflare, Docker, Kubernetes, Databricks, and hosted sandboxes may differ in process, filesystem, network, persistence, snapshot, and cleanup support, but unsupported operations fail explicitly. See the [capability matrix](/docs/reference/capability-matrix) and [sandbox matrix](/docs/reference/sandboxes-matrix) before relying on a backend-specific feature. --- # API reference Canonical: https://harness.techfabric.com/docs/reference/api Generated public API inventory for every published TechFabric Harness entrypoint. {/* Generated by scripts/generate-api-reference.mjs. Do not edit by hand. */} This reference is generated from the declaration files shipped in each package. Import from the entrypoint shown in the table; symbols marked `type` are TypeScript-only exports. ## @fabric-harness/agent-boundary ### `@fabric-harness/agent-boundary` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `AgentRunBounds` | `type` | `{ maxWallTimeMs: number; maxTurns: number; maxToolCalls: number; maxExternalCalls: number; maxConcurrentToolCalls: number; maxRunTokens: number; maxCostUsd: number; }` | Type contract for agent run bounds. | | `agentRunBoundsSchema` | `value` | `z.ZodObject<{ maxWallTimeMs: z.ZodNumber; maxTurns: z.ZodNumber; maxToolCalls: z.ZodNumber; maxExternalCalls: z.ZodNumber; maxConcurrentToolCalls: z.ZodNumber; maxRunTokens: z.ZodNumber; maxCostUsd: z.ZodNumber; }, z.core.$strip>` | The complete per-run bound set (collaboration plan D10). Every consuming boundary — MCP tool calls, the ACP/process path, and the model/provider path — enforces from this one shape; no path may carry a looser private subset. | | `AgentRunBudgetStore` | `type` | `AgentRunBudgetStore` | Durable, per-run budget state (collaboration plan D10: budget state is per enrollment/run, durable, and audited). Implementations must make `consume` atomic — two concurrent consumers must not both fit through the last slot of a bound — and must persist revocation so a restarted process cannot resume a revoked run. | | `AgentRunUsage` | `type` | `{ turns: number; toolCalls: number; externalCalls: number; usedTokens: number; usedCostUsd: number; }` | Type contract for agent run usage. | | `AgentRunUsageDelta` | `type` | `AgentRunUsageDelta` | Incremental usage to charge against a run's bounds. | | `agentRunUsageSchema` | `value` | `z.ZodObject<{ turns: z.ZodNumber; toolCalls: z.ZodNumber; externalCalls: z.ZodNumber; usedTokens: z.ZodNumber; usedCostUsd: z.ZodNumber; }, z.core.$strip>` | Cumulative usage recorded against `AgentRunBounds`. | | `BoundaryAuditEvent` | `type` | `{ type: "run-started"; runId: string; enrollmentId: string; tenantId: string; at: string; } \| { type: "bound-exhausted"; runId: string; bound: "turns" \| "wall-time" \| "tool-calls" \| "external-calls" \| "concurrency" \| "tokens" \| "cost"; usage: { turns...` | Type contract for boundary audit event. | | `boundaryAuditEventSchema` | `value` | `z.ZodDiscriminatedUnion<[z.ZodObject<{ type: z.ZodLiteral<"run-started">; runId: z.ZodString; enrollmentId: z.ZodString; tenantId: z.ZodString; at: z.ZodString; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"bound-exhausted">; runId...` | Audit vocabulary for the execution boundary. Every bound exhaustion, refusal, cancellation, revocation, and process termination is recorded — an unaudited stop is a gate failure (collaboration plan D10). | | `BoundaryAuditSink` | `type` | `BoundaryAuditSink` | Where boundary audit events go. Verticals bind this to their audit log. | | `BoundaryRefusal` | `value` | `typeof BoundaryRefusal` | A refusal is a terminal answer for the refused unit of work, never a retry hint. Exhaustion refusals also stop the run itself (the governor aborts), so later model or tool work cannot proceed. | | `BoundaryRefusalCode` | `type` | `BoundaryRefusalCode` | Refusal vocabulary for the governed execution boundary (collaboration plan D10). Every refusal names the exhausted or violated bound; callers must not invent codes outside this union. | | `BoundaryToolDefinition` | `type` | `BoundaryToolDefinition` | Type contract for boundary tool definition. | | `ConsumeResult` | `type` | `ConsumeResult` | Result returned by consume. | | `createRunGovernor` | `value` | `(options: RunGovernorOptions) => Promise<RunGovernor>` | Creates run governor. | | `createToolBoundary` | `value` | `(options: ToolBoundaryOptions) => ToolBoundary` | Build the per-run tool surface. Every call is governed: active-run check, tool-call/external-call/concurrency metering, zod validation, and — for proposal tools — submission through the governed proposal port only. | | `decideConsume` | `value` | `(usage: AgentRunUsage, delta: AgentRunUsageDelta, bounds: AgentRunBounds) => ConsumeResult` | Shared decision core for store implementations (pure). | | `defineProposalTool` | `value` | `<TInput extends z.ZodType>(tool: Omit<ProposalToolDefinition<TInput>, "kind">) => ProposalToolDefinition<TInput>` | Defines proposal tool. | | `defineReadTool` | `value` | `<TInput extends z.ZodType>(tool: Omit<ReadToolDefinition<TInput>, "kind">) => ReadToolDefinition<TInput>` | Defines read tool. | | `emptyAgentRunUsage` | `value` | `{ turns: number; toolCalls: number; externalCalls: number; usedTokens: number; usedCostUsd: number; }` | Runtime API for empty agent run usage; the generated signature shows its accepted inputs and return type. | | `ExhaustedBound` | `type` | `ExhaustedBound` | Type contract for exhausted bound. | | `GuardedModelRequest` | `type` | `GuardedModelRequest` | Input contract for guarded model. | | `GuardedModelResponse` | `type` | `GuardedModelResponse` | Response contract for guarded model. | | `guardModelProvider` | `value` | `<TRequest extends GuardedModelRequest, TResponse extends GuardedModelResponse>(options: GuardModelProviderOptions<TRequest, TResponse>) => (request: TRequest) => Promise<TResponse>` | Model/provider-path enforcement (collaboration plan D10): the budget is checked *before* the provider is invoked, each request is clamped to the policy's per-request output cap, actual usage is recorded immediately after the response, and the run's abort signal reaches the provider call. A run that exhausts its budget cannot start another model turn — stopping is not deferred until a later tool call. | | `GuardModelProviderOptions` | `type` | `GuardModelProviderOptions<TRequest, TResponse>` | Configuration options for guard model provider. | | `inMemoryAgentRunBudgetStore` | `value` | `() => AgentRunBudgetStore` | In-memory reference implementation. Suitable for tests and single-process development runners; production deployments bind a store backed by their durable database. | | `inMemoryBoundaryAuditSink` | `value` | `() => BoundaryAuditSink & { events: BoundaryAuditEvent[]; }` | Test/development sink retaining every event in order. | | `isBoundaryRefusal` | `value` | `(error: unknown) => error is BoundaryRefusal` | Checks whether a value is boundary refusal. | | `McpBoundaryServer` | `type` | `McpBoundaryServer` | Type contract for mcp boundary server. | | `McpBoundaryServerOptions` | `type` | `McpBoundaryServerOptions` | Configuration options for mcp boundary server. | | `ProposalToolDefinition` | `type` | `ProposalToolDefinition<TInput>` | A proposal tool: the only write shape an agent has. It maps validated params to a governed action proposal — the boundary submits through the vertical's `GovernedProposalPort` and nothing else. The tool itself performs no effect. | | `ReadToolDefinition` | `type` | `ReadToolDefinition<TInput>` | A read tool: answers from the vertical's authorized projections. Never mutates. `external` marks reads that leave the deployment boundary (they are metered against `maxExternalCalls`). | | `resolveRunBounds` | `value` | `(policy: AgentVersion["modelPolicy"], options: ResolveRunBoundsOptions) => AgentRunBounds` | Derive the run bounds from an immutable agent version's `modelPolicy` (token/cost budgets come from the registry contract verbatim) plus the execution-shape bounds the enrolling surface supplies. | | `ResolveRunBoundsOptions` | `type` | `ResolveRunBoundsOptions` | Configuration options for resolve run bounds. | | `RunGovernor` | `type` | `RunGovernor` | The per-run enforcement core (collaboration plan D10). One governor guards every consuming boundary of a run: MCP tool calls, the model/provider path, and the supervised process. Exhaustion, cancellation, and revocation all abort the shared signal so in-flight work stops — a stop is never deferred until the next tool call. | | `RunGovernorOptions` | `type` | `RunGovernorOptions` | Configuration options for run governor. | | `serveMcpBoundary` | `value` | `(options: McpBoundaryServerOptions) => Promise<McpBoundaryServer>` | Serve a `ToolBoundary` over MCP. The listing is exactly the boundary's allowlist — a forbidden tool is absent, not refused — and every call flows through the run governor. When the governor stops (cancelled, revoked, exhausted, out of wall time) the transport is closed, so an agent mid-run loses the tool surface entirely (gate B2). | | `superviseAgentProcess` | `value` | `(options: SuperviseProcessOptions) => SupervisedProcess` | ACP/process-path enforcement (collaboration plan D10): the agent child process lives strictly inside its run's governor. Cancellation, revocation, wall-time expiry, and budget exhaustion all abort the governor's signal, which terminates the child (SIGTERM, then SIGKILL after the grace period). Termination is audited. | | `SupervisedProcess` | `type` | `SupervisedProcess` | Type contract for supervised process. | | `SuperviseProcessOptions` | `type` | `SuperviseProcessOptions` | Configuration options for supervise process. | | `ToolBoundary` | `type` | `ToolBoundary` | Type contract for tool boundary. | | `ToolBoundaryOptions` | `type` | `ToolBoundaryOptions` | Configuration options for tool boundary. | | `ToolCallGuard` | `type` | `ToolCallGuard` | Type contract for tool call guard. | | `ToolCallOutcome` | `type` | `ToolCallOutcome` | Type contract for tool call outcome. | ## @fabric-harness/agent-registry ### `@fabric-harness/agent-registry` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `ActionRoute` | `type` | `ActionRoute` | Type contract for action route. | | `actionRouteSchema` | `value` | `z.ZodDiscriminatedUnion<[z.ZodObject<{ status: z.ZodLiteral<"auto-executed">; actionInvocationId: z.ZodString; }, z.core.$strip>, z.ZodObject<{ status: z.ZodLiteral<"awaiting-approval">; approvalRequestId: z.ZodString; reason: z.ZodString...` | Runtime API for action route schema; the generated signature shows its accepted inputs and return type. | | `AGENT_AUTONOMY_RANK` | `value` | `Record<"shadow" \| "draft-only" \| "approval-required" \| "bounded", number>` | Ranks used by subset/ceiling checks. Approval may only lower the rank. | | `AgentAutonomy` | `type` | `"shadow" \| "draft-only" \| "approval-required" \| "bounded"` | Type contract for agent autonomy. | | `agentAutonomySchema` | `value` | `z.ZodEnum<{ shadow: "shadow"; "draft-only": "draft-only"; "approval-required": "approval-required"; bounded: "bounded"; }>` | Autonomy ceiling for a registered agent (ADR §2.3). | | `AgentCapabilityGrantBase` | `type` | `{ grantId: string; readTools: string[]; proposalActions: string[]; executionActions: string[]; skillIds?: string[]; expiresAt?: string; }` | Type contract for agent capability grant base. | | `agentCapabilityGrantBaseSchema` | `value` | `z.ZodObject<{ grantId: z.ZodString; readTools: z.ZodArray<z.ZodString>; proposalActions: z.ZodArray<z.ZodString>; executionActions: z.ZodDefault<z.ZodArray<z.ZodString>>; skillIds: z.ZodOptional<z.ZodArray<z.ZodString>>; expiresAt: z...` | Capability grant with the three-way authority separation — read, propose, execute — preserved as a core guarantee (an agent that may propose cannot silently acquire delivery authority). Scope-free base; verticals extend. | | `AgentDefinition` | `type` | `{ agentDefinitionId: string; name: string; displayName: string; description: string; inputKinds: string[]; outputKinds: string[]; createdAt: string; }` | Type contract for agent definition. | | `agentDefinitionSchema` | `value` | `z.ZodObject<{ agentDefinitionId: z.ZodString; name: z.ZodString; displayName: z.ZodString; description: z.ZodString; inputKinds: z.ZodArray<z.ZodString>; outputKinds: z.ZodArray<z.ZodString>; createdAt: z.ZodString; }, z.core.$strip>` | Runtime API for agent definition schema; the generated signature shows its accepted inputs and return type. | | `AgentEventEnvelope` | `type` | `AgentEventEnvelope<T>` | Type contract for agent event envelope. | | `agentEventEnvelopeSchema` | `value` | `z.ZodObject<{ eventId: z.ZodString; type: z.ZodString; tenantId: z.ZodString; spaceId: z.ZodOptional<z.ZodString>; occurredAt: z.ZodString; correlationId: z.ZodString; event: z.ZodUnknown; }, z.core.$strip>` | The family signed event envelope (ADR §3.7): the single normalized wire form for platform→agent event delivery, converging the origin protocol package's vertical webhook envelopes and the channel-tail envelopes. Signature standard: `X-Fabric-Signature: v1=hex(hmac-sha256(secret, "<unix-seconds>.<raw-body>"))` with the timestamp in `X-Fabric-Timestamp`, verified constant-time within a bounded skew. WebCrypto only — runs on Node and edge. | | `AgentExecutionPrincipal` | `type` | `{ principalId: string; tenantId: string; registrationId: string; agentDefinitionId: string; agentVersionId: string; agentRunId: string; temporalWorkflowId: string; grantId: string; correlationId: string; idempotencyKey?: string; requestHash?: string; causationId?: string;...` | Type contract for agent execution principal. | | `agentExecutionPrincipalSchema` | `value` | `z.ZodObject<{ principalId: z.ZodString; tenantId: z.ZodString; registrationId: z.ZodString; agentDefinitionId: z.ZodString; agentVersionId: z.ZodString; agentRunId: z.ZodString; temporalWorkflowId: z.ZodString; grantId: z.ZodString; idempotencyKey: z.ZodOptional<z.Z...` | Short-lived execution principal minted per agent run. Verbatim (ADR §3.1 P). | | `AgentExecutionUsageRecord` | `type` | `{ usedTokens: number; usedCostUsd: number; inputTokens?: number; outputTokens?: number; maxCallOutputTokens?: number; modelCalls?: number; }` | Type contract for agent execution usage record. | | `agentExecutionUsageSchema` | `value` | `z.ZodObject<{ usedTokens: z.ZodNumber; usedCostUsd: z.ZodNumber; inputTokens: z.ZodOptional<z.ZodNumber>; outputTokens: z.ZodOptional<z.ZodNumber>; maxCallOutputTokens: z.ZodOptional<z.ZodNumber>; modelCalls: z.ZodOptional<z.ZodNumber>; },...` | Runtime API for agent execution usage schema; the generated signature shows its accepted inputs and return type. | | `AgentRunBase` | `type` | `{ agentRunId: string; tenantId: string; registrationId: string; agentDefinitionId: string; agentVersionId: string; temporalWorkflowId: string; trigger: "manual" \| "schedule" \| "event" \| "workflow"; status: "cancelled" \| "queued" \| "running" \| "waiting-for-approval"...` | Type contract for agent run base. | | `agentRunBaseSchema` | `value` | `z.ZodObject<{ agentRunId: z.ZodString; tenantId: z.ZodString; registrationId: z.ZodString; agentDefinitionId: z.ZodString; agentVersionId: z.ZodString; temporalWorkflowId: z.ZodString; idempotencyKey: z.ZodOptional<z.ZodString>; requestHash: z.ZodOptional<z.Zo...` | Agent run base — trigger, lifecycle, budget accounting, skill binding. Scope-free and attestation-free; verticals extend with their subject scope and their attestation schema (ADR §3.1 P-base). | | `agentRunReliabilityMetricSchema` | `value` | `z.ZodDiscriminatedUnion<[z.ZodObject<{ status: z.ZodLiteral<"suppressed">; cohort: z.ZodLiteral<"fewer-than-10">; }, z.core.$strict>, z.ZodObject<{ status: z.ZodLiteral<"available">; cohortSize: z.ZodNumber; succeeded: z.ZodNumber;...` | Runtime API for agent run reliability metric schema; the generated signature shows its accepted inputs and return type. | | `AgentRunStage` | `type` | `"cancelled" \| "queued" \| "failed" \| "loading-inputs" \| "generating" \| "staging-output" \| "applying-mutations" \| "completed"` | Type contract for agent run stage. | | `agentRunStageSchema` | `value` | `z.ZodEnum<{ queued: "queued"; failed: "failed"; cancelled: "cancelled"; "loading-inputs": "loading-inputs"; generating: "generating"; "staging-output": "staging-output"; "applying-mutations": "applying-mutations"; completed: "completed"; }>` | Runtime API for agent run stage schema; the generated signature shows its accepted inputs and return type. | | `agentRunStatusSchema` | `value` | `z.ZodEnum<{ queued: "queued"; running: "running"; "waiting-for-approval": "waiting-for-approval"; succeeded: "succeeded"; failed: "failed"; cancelled: "cancelled"; }>` | Runtime API for agent run status schema; the generated signature shows its accepted inputs and return type. | | `agentStatusSchema` | `value` | `z.ZodEnum<{ disabled: "disabled"; enabled: "enabled"; suspended: "suspended"; }>` | Runtime API for agent status schema; the generated signature shows its accepted inputs and return type. | | `AgentVersion` | `type` | `{ agentVersionId: string; agentDefinitionId: string; version: string; configurationHash: string; promptVersion: string; skillIds: string[]; toolIds: string[]; modelPolicy: { provider: string; model: string; maxInputTokens: number; maxOutputTokens: number; maxCostUsd:...` | Type contract for agent version. | | `agentVersionSchema` | `value` | `z.ZodObject<{ agentVersionId: z.ZodString; agentDefinitionId: z.ZodString; version: z.ZodString; configurationHash: z.ZodString; implementationDigest: z.ZodOptional<z.ZodString>; runtimeVersion: z.ZodOptional<z.ZodString>; promptVersion: z.ZodString; skillI...` | Immutable, hash-pinned agent version with hard model budgets. Verbatim from the origin — `modelPolicy` is the bounded-agent contract the MCP budget meter enforces (collaboration plan D10). | | `approvalIsSubset` | `value` | `<T extends EnrollmentRegistrationLike>(requested: T, approved: T, scopeAccessors?: ReadonlyArray<(registration: T) => readonly string[]>) => boolean` | Approval may narrow an external runtime's requested authority, but can never change its identity or increase any capability, scope, autonomy, or lifetime. Vertical scope dimensions (per-vertical scope-id lists) participate via `scopeAccessors` — each accessor's approved list must be a subset of its requested list. Wire-behavior-identical to the origin when the vertical passes its scope accessors (ADR §3.2, equivalence-tested). | | `ApprovalRequest` | `type` | `{ approvalRequestId: string; tenantId: string; subject: { subjectType: string; subjectId: string; }; proposedActionId: string; proposedParametersHash: string; reason: string; escalation: boolean; requiredCapability: string; options: ("approve" \| "reject" \| "ap...` | Input contract for approval. | | `approvalRequestSchema` | `value` | `z.ZodObject<{ approvalRequestId: z.ZodString; tenantId: z.ZodString; spaceId: z.ZodOptional<z.ZodString>; subject: z.ZodObject<{ subjectType: z.ZodString; subjectId: z.ZodString; }, z.core.$strip>; proposedActionId: z.ZodString; proposedParameters...` | Runtime API for approval request schema; the generated signature shows its accepted inputs and return type. | | `approvalRequestStatusSchema` | `value` | `z.ZodEnum<{ pending: "pending"; granted: "granted"; denied: "denied"; expired: "expired"; }>` | Runtime API for approval request status schema; the generated signature shows its accepted inputs and return type. | | `AttestedIdentity` | `type` | `{ namespace: string; externalId: string; signatureRef?: string; }` | Type contract for attested identity. | | `attestedIdentitySchema` | `value` | `z.ZodObject<{ namespace: z.ZodString; externalId: z.ZodString; signatureRef: z.ZodOptional<z.ZodString>; }, z.core.$strict>` | Runtime API for attested identity schema; the generated signature shows its accepted inputs and return type. | | `BindExternalIdentityParams` | `type` | `{ commandId: string; bindingId: string; principalId: string; namespace: string; externalId: string; verification: "self-asserted" \| "signature" \| "sso"; occurredAt: string; }` | Type contract for bind external identity params. | | `bindExternalIdentitySchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; bindingId: z.ZodString; principalId: z.ZodString; namespace: z.ZodString; externalId: z.ZodString; verification: z.ZodEnum<{ "self-asserted": "self-asserted"; signature: "signature"; sso: "sso"; }>; occurredAt: z.Zo...` | Runtime API for bind external identity schema; the generated signature shows its accepted inputs and return type. | | `CapabilityDescriptor` | `type` | `CapabilityDescriptor` | Action-catalog entry: what exists (grants say what a principal may use). | | `CertificationSchemaOptions` | `type` | `CertificationSchemaOptions<TSchemaVersion, TEvidence, TDefinitionId>` | Configuration options for certification schema. | | `clampRoute` | `value` | `(autonomy: AgentAutonomy, decision: PolicyDecision) => ActionRoute` | Clamp a per-action policy decision to the registration's autonomy ceiling. The registration autonomy is the ceiling; policy routes within it: - `shadow` → every mutation is `rejected` (observe/record only) - `draft-only` → at most `awaiting-approval`; nothing auto-executes - `approval-required` → at most `awaiting-approval` / `escalated` - `bounded` → policy result stands (auto-execution within grant + budget) The returned route for gated decisions carries an empty `approvalRequestId` — the caller creates the ApprovalRequest and fills it in. | | `CompleteExternalAgentActivationParams` | `type` | `{ commandId: string; enrollmentRequestId: string; expectedRequestHash: string; expectedApprovedEnvelopeHash: string; expectedFenceVersion: number; operatorDispatchId: string; activationActionInvocationId: string; }` | Type contract for complete external agent activation params. | | `completeExternalAgentActivationSchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; enrollmentRequestId: z.ZodString; expectedRequestHash: z.ZodString; expectedApprovedEnvelopeHash: z.ZodString; expectedFenceVersion: z.ZodNumber; operatorDispatchId: z.ZodString; activationActionInvocationId: z.ZodString; }, z...` | Runtime API for complete external agent activation schema; the generated signature shows its accepted inputs and return type. | | `CompleteExternalAgentOffboardingParams` | `type` | `{ commandId: string; enrollmentRequestId: string; expectedRequestHash: string; expectedFenceVersion: number; operatorDispatchId: string; terminalDisposition: "revoked" \| "expired"; registrationActionInvocationId?: string; credentialActionInvocationId?: string; }` | Type contract for complete external agent offboarding params. | | `completeExternalAgentOffboardingSchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; enrollmentRequestId: z.ZodString; expectedRequestHash: z.ZodString; expectedFenceVersion: z.ZodNumber; operatorDispatchId: z.ZodString; registrationActionInvocationId: z.ZodOptional<z.ZodString>; credentialActionInvocationId:...` | Runtime API for complete external agent offboarding schema; the generated signature shows its accepted inputs and return type. | | `CompleteExternalAgentProvisioningParams` | `type` | `{ commandId: string; enrollmentRequestId: string; expectedRequestHash: string; expectedApprovedEnvelopeHash: string; expectedFenceVersion: number; operatorDispatchId: string; registrationActionInvocationId: string; credentialActionInvocationId: string; credentialId: strin...` | Type contract for complete external agent provisioning params. | | `completeExternalAgentProvisioningSchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; enrollmentRequestId: z.ZodString; expectedRequestHash: z.ZodString; expectedApprovedEnvelopeHash: z.ZodString; expectedFenceVersion: z.ZodNumber; operatorDispatchId: z.ZodString; registrationActionInvocationId: z.ZodString; credent...` | Runtime API for complete external agent provisioning schema; the generated signature shows its accepted inputs and return type. | | `ContentRef` | `type` | `{ id: string; revision: number; contentHash: string; }` | Type contract for content ref. | | `contentRefSchema` | `value` | `z.ZodObject<{ id: z.ZodString; revision: z.ZodNumber; contentHash: z.ZodString; }, z.core.$strip>` | Content-addressed reference to a revisioned artifact-like subject. | | `CorrelationKey` | `type` | `{ type: string; value: string; }` | Type contract for correlation key. | | `correlationKeySchema` | `value` | `z.ZodObject<{ type: z.ZodString; value: z.ZodString; }, z.core.$strip>` | Runtime API for correlation key schema; the generated signature shows its accepted inputs and return type. | | `createCertificationSchema` | `value` | `<TSchemaVersion extends string, TEvidence extends z.ZodTypeAny, TDefinitionId extends z.ZodTypeAny = z.ZodString>(options: CertificationSchemaOptions<TSchemaVersion, TEvidence, TDefinitionId>) => z.ZodObject<{ schemaVersion: z.ZodLiteral<TSchemaVersio...` | Factory for the immutable certification record (ADR §3.1 P-fact). | | `createEnrollmentContracts` | `value` | `<TRegistration extends z.ZodTypeAny>(options: EnrollmentContractsOptions<TRegistration>) => { submitExternalAgentEnrollmentSchema: z.ZodObject<{ commandId: z.ZodString; enrollmentRequestId: z.ZodString; inviteId: z.ZodString; runtimeKind: z.ZodEnum&...` | Factory for the registration-dependent enrollment contracts. The vertical supplies its registration schema; everything else is neutral (ADR §3.2). | | `CreateExternalAgentInviteParams` | `type` | `{ commandId: string; inviteId: string; inviteRevealId: string; runtimeKind: "hermes" \| "generic-mcp"; expiresAt: string; }` | Type contract for create external agent invite params. | | `createExternalAgentInviteSchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; inviteId: z.ZodString; inviteRevealId: z.ZodString; runtimeKind: z.ZodEnum<{ hermes: "hermes"; "generic-mcp": "generic-mcp"; }>; expiresAt: z.ZodString; }, z.core.$strict>` | Creates external agent invite schema. | | `createOutcomeEvidenceSchema` | `value` | `<TSchemaVersion extends string, TVersionExtension extends z.ZodRawShape = Record<never, never>, TDefinitionId extends z.ZodTypeAny = z.ZodString>(options: OutcomeEvidenceSchemaOptions<TSchemaVersion, TVersionExtension, TDefinitionId>) => z.ZodObject<...` | Creates outcome evidence schema. | | `createSignalOutboxReconciler` | `value` | `(deps: SignalOutboxReconcilerDeps) => () => Promise<{ delivered: number; failed: number; }>` | Idempotent outbox reconciler (plan D16). Run from a worker loop, a Temporal activity, or after the vertical action commits. Safe under concurrent workers and restarts: the checkpoint is a CAS in the store, and receiving workflows dedupe on `approvalRequestId`. | | `createSkillIoSchema` | `value` | `<TSchemaVersion extends string>(schemaVersion: TSchemaVersion) => z.ZodObject<{ schemaVersion: z.ZodLiteral<TSchemaVersion>; fields: z.ZodArray<z.ZodObject<{ name: z.ZodString; type: z.ZodEnum<{ string: "string"; number: "number"; bool...` | IO contract factory — the vertical supplies its schemaVersion literal. | | `createSkillRunnerExecutionInputSchema` | `value` | `<TIo extends z.ZodTypeAny>(ioSchema: TIo) => z.ZodObject<{ skillId: z.ZodString; skillVersion: z.ZodNumber; name: z.ZodString; description: z.ZodString; instructions: z.ZodString; inputSchema: TIo; outputSchema: TIo; allowedActions: z.ZodArray<z.ZodString&g...` | Execution-input factory. `runtimePolicy` promotes verbatim — bounded iterations/timeout/tokens/cost/concurrency with `failureMode: fail_closed` is a core finite-agent guarantee, not a vertical choice. | | `DecisionEvent` | `type` | `{ approvalRequestId: string; tenantId: string; subject: { subjectType: string; subjectId: string; }; occurredAt: string; type: "decision.requested"; escalation: boolean; } \| { approvalRequestId: string; tenantId: string; subject: { subjectType: s...` | Type contract for decision event. | | `decisionEventSchema` | `value` | `z.ZodDiscriminatedUnion<[z.ZodObject<{ approvalRequestId: z.ZodString; tenantId: z.ZodString; subject: z.ZodObject<{ subjectType: z.ZodString; subjectId: z.ZodString; }, z.core.$strip>; occurredAt: z.ZodString; type: z.ZodLiteral<"decision.request...` | Runtime API for decision event schema; the generated signature shows its accepted inputs and return type. | | `decisionOptionSchema` | `value` | `z.ZodEnum<{ approve: "approve"; reject: "reject"; "approve-with-edits": "approve-with-edits"; }>` | Runtime API for decision option schema; the generated signature shows its accepted inputs and return type. | | `DecisionRefusal` | `type` | `DecisionRefusal` | Type contract for decision refusal. | | `DecisionSubject` | `type` | `{ subjectType: string; subjectId: string; }` | Type contract for decision subject. | | `decisionSubjectSchema` | `value` | `z.ZodObject<{ subjectType: z.ZodString; subjectId: z.ZodString; }, z.core.$strip>` | Runtime API for decision subject schema; the generated signature shows its accepted inputs and return type. | | `EnforceExternalAgentEnrollmentRetentionParams` | `type` | `{ commandId: string; cutoffAt: string; limit: number; }` | Type contract for enforce external agent enrollment retention params. | | `enforceExternalAgentEnrollmentRetentionSchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; cutoffAt: z.ZodString; limit: z.ZodNumber; }, z.core.$strict>` | Runtime API for enforce external agent enrollment retention schema; the generated signature shows its accepted inputs and return type. | | `EnrollmentContractsOptions` | `type` | `EnrollmentContractsOptions<TRegistration>` | Configuration options for enrollment contracts. | | `EnrollmentRegistrationLike` | `type` | `EnrollmentRegistrationLike` | Minimal registration shape the subset check operates over. | | `externalActionContractFingerprintSchema` | `value` | `z.ZodString` | Pins the exact action contract an external runtime was approved against. | | `ExternalAgentEnrollmentInviteRecord` | `type` | `{ inviteId: string; runtimeKind: "hermes" \| "generic-mcp"; tokenHash: string; status: "revoked" \| "active" \| "consumed"; createdBy: string; createdAt: string; expiresAt: string; retentionUntil: string; consumedByRequestId?: string; revokedAt?: string; revocationReason?...` | Type contract for external agent enrollment invite record. | | `externalAgentEnrollmentInviteRecordSchema` | `value` | `z.ZodObject<{ inviteId: z.ZodString; runtimeKind: z.ZodEnum<{ hermes: "hermes"; "generic-mcp": "generic-mcp"; }>; tokenHash: z.ZodString; status: z.ZodEnum<{ revoked: "revoked"; active: "active"; consumed: "consumed"; }>; createdBy: z.Zo...` | Runtime API for external agent enrollment invite record schema; the generated signature shows its accepted inputs and return type. | | `ExternalAgentEnrollmentInviteStatus` | `type` | `"revoked" \| "active" \| "consumed"` | Type contract for external agent enrollment invite status. | | `externalAgentEnrollmentInviteStatusSchema` | `value` | `z.ZodEnum<{ revoked: "revoked"; active: "active"; consumed: "consumed"; }>` | Runtime API for external agent enrollment invite status schema; the generated signature shows its accepted inputs and return type. | | `ExternalAgentEnrollmentStatus` | `type` | `"revoked" \| "approved" \| "rejected" \| "active" \| "expired" \| "pending_review" \| "provisioning" \| "claim_ready" \| "claimed_pending_activation" \| "revoking"` | Type contract for external agent enrollment status. | | `externalAgentEnrollmentStatusSchema` | `value` | `z.ZodEnum<{ revoked: "revoked"; rejected: "rejected"; expired: "expired"; approved: "approved"; active: "active"; pending_review: "pending_review"; provisioning: "provisioning"; claim_ready: "claim_ready"; claimed_pending_activation: "claimed_pending_activation"; revok...` | Runtime API for external agent enrollment status schema; the generated signature shows its accepted inputs and return type. | | `ExternalAgentInviteRevealRecord` | `type` | `{ inviteRevealId: string; inviteId: string; ciphertext: string; payloadHash: string; encryptionKeyId: string; associatedDataHash: string; createdAt: string; expiresAt: string; revealedAt?: string; revealedByCommandId?: string; replayUntil?: string; }` | Type contract for external agent invite reveal record. | | `externalAgentInviteRevealRecordSchema` | `value` | `z.ZodObject<{ inviteRevealId: z.ZodString; inviteId: z.ZodString; ciphertext: z.ZodString; payloadHash: z.ZodString; encryptionKeyId: z.ZodString; associatedDataHash: z.ZodString; createdAt: z.ZodString; expiresAt: z.ZodString; revealedAt: z.ZodOptional<z.ZodString&...` | Runtime API for external agent invite reveal record schema; the generated signature shows its accepted inputs and return type. | | `ExternalAgentMutationFence` | `type` | `{ enrollmentRequestId: string; requestHash: string; fenceVersion: number; allowedStatuses: ("revoked" \| "approved" \| "rejected" \| "active" \| "expired" \| "pending_review" \| "provisioning" \| "claim_ready" \| "claimed_pending_activation" \| "revoking")[]; approvedEnve...` | Type contract for external agent mutation fence. | | `externalAgentMutationFenceSchema` | `value` | `z.ZodObject<{ enrollmentRequestId: z.ZodString; requestHash: z.ZodString; approvedEnvelopeHash: z.ZodOptional<z.ZodString>; fenceVersion: z.ZodNumber; allowedStatuses: z.ZodArray<z.ZodEnum<{ revoked: "revoked"; rejected: "rejected"; expired: "expired";...` | Runtime API for external agent mutation fence schema; the generated signature shows its accepted inputs and return type. | | `ExternalAgentOperatorAdmissionRecord` | `type` | `{ admissionId: string; dispatchId: string; enrollmentRequestId: string; workflowId: string; workflowRunId: string; actionId: string; stagedCommandId: string; parameterHash: string; fenceVersion: number; issuedAt: string; expiresAt: string; consumedByActionInvocationId?: s...` | Type contract for external agent operator admission record. | | `externalAgentOperatorAdmissionRecordSchema` | `value` | `z.ZodObject<{ admissionId: z.ZodString; dispatchId: z.ZodString; enrollmentRequestId: z.ZodString; workflowId: z.ZodString; workflowRunId: z.ZodString; actionId: z.ZodString; stagedCommandId: z.ZodString; parameterHash: z.ZodString; fenceVersion: z.ZodNumber; issuedAt:...` | Runtime API for external agent operator admission record schema; the generated signature shows its accepted inputs and return type. | | `ExternalAgentOperatorDispatchRecord` | `type` | `{ dispatchId: string; enrollmentRequestId: string; kind: "provisioning" \| "activation" \| "offboarding"; bindingHash: string; sourceActionInvocationId: string; fenceVersion: number; status: "completed" \| "pending" \| "started"; workflowId: string; createdAt: string; app...` | Type contract for external agent operator dispatch record. | | `externalAgentOperatorDispatchRecordSchema` | `value` | `z.ZodObject<{ dispatchId: z.ZodString; enrollmentRequestId: z.ZodString; kind: z.ZodEnum<{ provisioning: "provisioning"; activation: "activation"; offboarding: "offboarding"; }>; bindingHash: z.ZodString; sourceActionInvocationId: z.ZodString; approvedE...` | Runtime API for external agent operator dispatch record schema; the generated signature shows its accepted inputs and return type. | | `externalAgentOperatorDispatchStatusSchema` | `value` | `z.ZodEnum<{ completed: "completed"; pending: "pending"; started: "started"; }>` | Runtime API for external agent operator dispatch status schema; the generated signature shows its accepted inputs and return type. | | `externalAgentOperatorKindSchema` | `value` | `z.ZodEnum<{ provisioning: "provisioning"; activation: "activation"; offboarding: "offboarding"; }>` | Runtime API for external agent operator kind schema; the generated signature shows its accepted inputs and return type. | | `ExternalAgentRevealEnvelopeRecord` | `type` | `{ revealEnvelopeId: string; enrollmentRequestId: string; registrationId: string; credentialId: string; credentialVersion: string; ciphertext: string; payloadHash: string; purpose: "registration-credential"; encryptionKeyId: string; associatedDataHash: string; createdAt: s...` | Type contract for external agent reveal envelope record. | | `externalAgentRevealEnvelopeRecordSchema` | `value` | `z.ZodObject<{ revealEnvelopeId: z.ZodString; enrollmentRequestId: z.ZodString; registrationId: z.ZodString; credentialId: z.ZodString; credentialVersion: z.ZodString; ciphertext: z.ZodString; payloadHash: z.ZodString; purpose: z.ZodLiteral<"registration-credential"&...` | Runtime API for external agent reveal envelope record schema; the generated signature shows its accepted inputs and return type. | | `ExternalAgentRuntimeKind` | `type` | `"hermes" \| "generic-mcp"` | Type contract for external agent runtime kind. | | `externalAgentRuntimeKindSchema` | `value` | `z.ZodEnum<{ hermes: "hermes"; "generic-mcp": "generic-mcp"; }>` | `generic-mcp` is the runtime kind for channel-hosted ACP + MCP agents. | | `FABRIC_SIGNATURE_HEADER` | `value` | `"x-fabric-signature"` | Constant defining fabric signature header. | | `FABRIC_TIMESTAMP_HEADER` | `value` | `"x-fabric-timestamp"` | Constant defining fabric timestamp header. | | `FieldValue` | `type` | `FieldValue<T, TSource>` | Field value with confidence and provenance — used when an agent submits extracted data so per-action policy can route it (auto-execute, approval, or escalate) based on confidence. Promoted from the origin protocol package (ADR §3.6) with one erratum: the origin's `source` union carries vertical vocabulary, so the neutral form takes an open provenance string and the vertical narrows it in its own re-export (`TSource` defaults to `string`). | | `GovernanceNotice` | `type` | `{ noticeId: string; tenantId: string; kind: "escalation" \| "binding-refused" \| "capability-refused" \| "validation-failed" \| "policy-blocked" \| "budget-exhausted"; reason: string; occurredAt: string; subject?: { subjectType: string; subjectId: string; }; act...` | Type contract for governance notice. | | `governanceNoticeSchema` | `value` | `z.ZodObject<{ noticeId: z.ZodString; tenantId: z.ZodString; subject: z.ZodOptional<z.ZodObject<{ subjectType: z.ZodString; subjectId: z.ZodString; }, z.core.$strip>>; kind: z.ZodEnum<{ escalation: "escalation"; "binding-refused": "binding-...` | Runtime API for governance notice schema; the generated signature shows its accepted inputs and return type. | | `GovernedProposalPort` | `type` | `GovernedProposalPort` | The only write path an agent has: propose a governed Platform action. | | `IdentityBinding` | `type` | `{ bindingId: string; tenantId: string; principalId: string; namespace: string; externalId: string; verification: "self-asserted" \| "signature" \| "sso"; boundAt: string; boundBy: string; revokedAt?: string; revokedBy?: string; revocationReason?: string; }` | Type contract for identity binding. | | `identityBindingSchema` | `value` | `z.ZodObject<{ bindingId: z.ZodString; tenantId: z.ZodString; principalId: z.ZodString; namespace: z.ZodString; externalId: z.ZodString; verification: z.ZodEnum<{ "self-asserted": "self-asserted"; signature: "signature"; sso: "sso"; }>; boundAt: z.ZodStr...` | Runtime API for identity binding schema; the generated signature shows its accepted inputs and return type. | | `identityNamespaceSchema` | `value` | `z.ZodString` | Identity bindings (ADR §3.8): the typed, revocable link between an external surface identity (a Nostr pubkey, Slack member id, email, …) and a Fabric principal. Supersedes untyped actor-id lists for new decisions; binding and revoking are governed actions in each vertical's module, so "who may decide as whom" is itself audited history. | | `IdentityVerification` | `type` | `"self-asserted" \| "signature" \| "sso"` | Type contract for identity verification. | | `identityVerificationSchema` | `value` | `z.ZodEnum<{ "self-asserted": "self-asserted"; signature: "signature"; sso: "sso"; }>` | Runtime API for identity verification schema; the generated signature shows its accepted inputs and return type. | | `idSchema` | `value` | `z.ZodString` | Shared field primitives. Exactly the shapes used by the origin vertical packages so extracted schemas stay wire-identical — see the Fabric Agent Contracts Reconciliation ADR §1. | | `inMemorySignalOutboxStore` | `value` | `() => SignalOutboxStore & { all(): SignalOutboxIntent[]; add(intent: SignalOutboxIntent): void; }` | Test/development outbox store. Not durable — never use in production. | | `isoDateSchema` | `value` | `z.ZodString` | Runtime API for iso date schema; the generated signature shows its accepted inputs and return type. | | `JsonObject` | `type` | `Record<string, unknown>` | Type contract for json object. | | `jsonObjectSchema` | `value` | `z.ZodRecord<z.ZodString, z.ZodUnknown>` | Runtime API for json object schema; the generated signature shows its accepted inputs and return type. | | `MutationCommonInput` | `type` | `MutationCommonInput` | Common metadata every agent-proposed mutation carries (ADR §3.5). | | `NamespacedKind` | `type` | `string` | Type contract for namespaced kind. | | `namespacedKindSchema` | `value` | `z.ZodString` | Namespaced kind identifier: lowercase, dot/dash namespacing, no vertical vocabulary. Wire-identical to the origin `artifactKindSchema` regex so vertical re-exports validate exactly as before (ADR §3.3). | | `OutcomeEvidenceSchemaOptions` | `type` | `OutcomeEvidenceSchemaOptions<TSchemaVersion, TVersionExtension, TDefinitionId>` | Configuration options for outcome evidence schema. | | `PolicyDecision` | `type` | `PolicyDecision` | Type contract for policy decision. | | `PolicyEvaluationInput` | `type` | `PolicyEvaluationInput` | Type contract for policy evaluation input. | | `PolicyHint` | `type` | `PolicyHint` | Type contract for policy hint. | | `RecordExternalAgentClaimParams` | `type` | `{ commandId: string; enrollmentRequestId: string; expectedRequestHash: string; expectedApprovedEnvelopeHash: string; expectedFenceVersion: number; operatorDispatchId: string; credentialId: string; credentialVersion: string; revealEnvelopeId: string; }` | Type contract for record external agent claim params. | | `recordExternalAgentClaimSchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; enrollmentRequestId: z.ZodString; expectedRequestHash: z.ZodString; expectedApprovedEnvelopeHash: z.ZodString; expectedFenceVersion: z.ZodNumber; operatorDispatchId: z.ZodString; credentialId: z.ZodString; credentialVersion: z.ZodS...` | Runtime API for record external agent claim schema; the generated signature shows its accepted inputs and return type. | | `resolveAgentRunTokenBudget` | `value` | `(policy: AgentVersion["modelPolicy"]) => number` | Resolves agent run token budget. | | `ResolvedDecisionContext` | `type` | `ResolvedDecisionContext` | Type contract for resolved decision context. | | `RevokeExternalAgentEnrollmentParams` | `type` | `{ commandId: string; enrollmentRequestId: string; expectedRequestHash: string; reason: string; }` | Type contract for revoke external agent enrollment params. | | `revokeExternalAgentEnrollmentSchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; enrollmentRequestId: z.ZodString; expectedRequestHash: z.ZodString; reason: z.ZodString; }, z.core.$strict>` | Runtime API for revoke external agent enrollment schema; the generated signature shows its accepted inputs and return type. | | `RevokeExternalAgentInviteParams` | `type` | `{ commandId: string; inviteId: string; reason: string; }` | Type contract for revoke external agent invite params. | | `revokeExternalAgentInviteSchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; inviteId: z.ZodString; reason: z.ZodString; }, z.core.$strict>` | Runtime API for revoke external agent invite schema; the generated signature shows its accepted inputs and return type. | | `RevokeExternalIdentityParams` | `type` | `{ commandId: string; bindingId: string; reason: string; occurredAt: string; }` | Type contract for revoke external identity params. | | `revokeExternalIdentitySchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; bindingId: z.ZodString; reason: z.ZodString; occurredAt: z.ZodString; }, z.core.$strict>` | Runtime API for revoke external identity schema; the generated signature shows its accepted inputs and return type. | | `RiskTier` | `type` | `"low" \| "medium" \| "high"` | Type contract for risk tier. | | `riskTierSchema` | `value` | `z.ZodEnum<{ low: "low"; medium: "medium"; high: "high"; }>` | The neutral decision boundary (ADR §2, §3.5, §3.7, §3.8): routing vocabulary, per-action policy contracts, the ApprovalRequest entity, the durable-resume primitive, and the governed decision-ingress factory. Layering (collaboration plan D7): channel adapters carry candidate identities and never authorize; only a vertical's governed decision-ingress action — composed from `createDecisionIngress` — resolves bindings, checks capability, and signals durable workflows. | | `sha256Schema` | `value` | `z.ZodString` | Runtime API for sha256 schema; the generated signature shows its accepted inputs and return type. | | `SignalOutboxIntent` | `type` | `{ intentId: string; tenantId: string; approvalRequestId: string; correlationKey: { type: string; value: string; }; signalName: string; payload: Record<string, unknown>; idempotencyKey: string; createdAt: string; attempts: number; deliveredAt?: string; last...` | Type contract for signal outbox intent. | | `signalOutboxIntentSchema` | `value` | `z.ZodObject<{ intentId: z.ZodString; tenantId: z.ZodString; approvalRequestId: z.ZodString; correlationKey: z.ZodObject<{ type: z.ZodString; value: z.ZodString; }, z.core.$strip>; signalName: z.ZodString; payload: z.ZodRecord<z.ZodString, z.ZodUnknow...` | Durable signal-outbox intent, persisted atomically with the decision. | | `SignalOutboxReconcilerDeps` | `type` | `SignalOutboxReconcilerDeps` | Type contract for signal outbox reconciler deps. | | `SignalOutboxStore` | `type` | `SignalOutboxStore` | Storage contract for signal outbox. | | `SignalPendingStepInput` | `type` | `SignalPendingStepInput` | Type contract for signal pending step input. | | `SignalPendingStepResult` | `type` | `SignalPendingStepResult` | Result returned by signal pending step. | | `signFabricEnvelope` | `value` | `(secret: string, timestampSeconds: number, rawBody: string) => Promise<string>` | Sign a raw body for delivery: returns the `v1=<hex>` header value. | | `SkillActionProposal` | `type` | `{ actionId: string; parameters: Record<string, unknown>; reason: string; }` | Type contract for skill action proposal. | | `skillActionProposalSchema` | `value` | `z.ZodObject<{ actionId: z.ZodString; parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>; reason: z.ZodString; }, z.core.$strict>` | Skill-runner contracts (ADR §3.1 P-fact): bounded, fail-closed skill execution with action proposals. IO-contract literals are vertical-supplied. | | `SkillRunnerOutput` | `type` | `{ output: Record<string, unknown>; proposedActions: { actionId: string; parameters: Record<string, unknown>; reason: string; }[]; }` | Type contract for skill runner output. | | `skillRunnerOutputSchema` | `value` | `z.ZodObject<{ output: z.ZodRecord<z.ZodString, z.ZodUnknown>; proposedActions: z.ZodDefault<z.ZodArray<z.ZodObject<{ actionId: z.ZodString; parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>; reason: z.ZodString; }, z.core.$strict>>...` | Runtime API for skill runner output schema; the generated signature shows its accepted inputs and return type. | | `SubjectContextPort` | `type` | `SubjectContextPort` | Neutral read port keyed by subject reference (ADR §3.4). | | `SubmitExternalDecisionInput` | `type` | `{ commandId: string; approvalRequestId: string; choice: "approve" \| "reject" \| "approve-with-edits"; attestedIdentity: { namespace: string; externalId: string; signatureRef?: string; }; occurredAt: string; edits?: Record<string, unknown>; receipt?: {...` | Type contract for submit external decision input. | | `submitExternalDecisionSchema` | `value` | `z.ZodObject<{ commandId: z.ZodString; approvalRequestId: z.ZodString; choice: z.ZodEnum<{ approve: "approve"; reject: "reject"; "approve-with-edits": "approve-with-edits"; }>; edits: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>; att...` | Runtime API for submit external decision schema; the generated signature shows its accepted inputs and return type. | | `suppressedOutcomeMetricSchema` | `value` | `z.ZodObject<{ status: z.ZodLiteral<"suppressed">; cohort: z.ZodLiteral<"fewer-than-10">; }, z.core.$strict>` | Privacy-safe longitudinal outcome evidence (ADR §3.1 P-fact): cohorts below ten observations expose no exact counts; no tenant, subject, actor, prompt, body, or failure-detail fields. The base carries run reliability; verticals extend per-version entries with their own metric families and pass their schemaVersion literal. | | `TenantAgentRegistrationBase` | `type` | `{ registrationId: string; tenantId: string; agentDefinitionId: string; agentVersionId: string; status: "disabled" \| "enabled" \| "suspended"; autonomy: "shadow" \| "draft-only" \| "approval-required" \| "bounded"; grant: { grantId: string; readTools: string[]; propo...` | Type contract for tenant agent registration base. | | `tenantAgentRegistrationBaseSchema` | `value` | `z.ZodObject<{ registrationId: z.ZodString; tenantId: z.ZodString; agentDefinitionId: z.ZodString; agentVersionId: z.ZodString; status: z.ZodEnum<{ disabled: "disabled"; enabled: "enabled"; suspended: "suspended"; }>; autonomy: z.ZodEnum<{ shadow...` | Tenant-level registration base (scope-free; verticals extend). | | `ValidatedDecision` | `type` | `ValidatedDecision` | Type contract for validated decision. | | `validateExternalDecision` | `value` | `(input: SubmitExternalDecisionInput, context: ResolvedDecisionContext) => ValidatedDecision` | PURE decision validation (plan D16). No I/O, no clock reads, no effects — every input is resolved by the caller first. Returns either a refusal (with the governance notice the caller must emit and audit), expiry, or the exact decision record + signal-outbox intent the caller must persist atomically with its pending→terminal compare-and-set. | | `verifyFabricEnvelope` | `value` | `(secret: string, rawBody: string, headers: { signature: string \| null; timestamp: string \| null; }, options?: { maxSkewSeconds?: number; nowMs?: number; }) => Promise<boolean>` | Constant-time verification of a `v1=` signature within `maxSkewSeconds`. | ## @fabric-harness/azure ### `@fabric-harness/azure` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `AzureAksClusterRef` | `type` | `AzureAksClusterRef` | Type contract for azure aks cluster ref. | | `azureAksRunCommandTool` | `value` | `(client: AzureArmClient, options?: { name?: string; description?: string; apiVersion?: string; }) => ToolDef<AzureAksClusterRef & { command: string; context?: string; }, unknown>` | Model-callable tool or tool factory for azure aks run command. | | `AzureArmClient` | `value` | `typeof AzureArmClient` | Client implementation for azure arm. | | `AzureArmClientOptions` | `type` | `AzureArmClientOptions` | Configuration options for azure arm client. | | `AzureBlobArtifactStore` | `type` | `AzureBlobArtifactStore` | Storage contract for azure blob artifact. | | `AzureBlobArtifactStoreOptions` | `type` | `AzureBlobArtifactStoreOptions` | Configuration options for azure blob artifact store. | | `AzureBundle` | `type` | `AzureBundle` | Type contract for azure bundle. | | `AzureBundleConfig` | `type` | `AzureBundleConfig` | Type contract for azure bundle config. | | `AzureContainerAppsJobRef` | `type` | `AzureContainerAppsJobRef` | Type contract for azure container apps job ref. | | `azureContainerAppsJobTool` | `value` | `(client: AzureArmClient, options?: { name?: string; description?: string; apiVersion?: string; }) => ToolDef<AzureContainerAppsJobRef & { environmentVariables?: Record<string, string>; }, unknown>` | Model-callable tool or tool factory for azure container apps job. | | `azureContainerInstanceExecTool` | `value` | `(client: AzureArmClient, options?: { name?: string; description?: string; apiVersion?: string; }) => ToolDef<AzureContainerInstanceRef & { command: string; }, unknown>` | Model-callable tool or tool factory for azure container instance exec. | | `AzureContainerInstanceRef` | `type` | `AzureContainerInstanceRef` | Type contract for azure container instance ref. | | `azureKeyVaultSecretProvider` | `value` | `(options: AzureKeyVaultSecretResolverOptions) => SecretProvider` | Key Vault adapter for `chainSecretProviders()` and `secretResolver()`. | | `AzureKeyVaultSecretResolverOptions` | `type` | `AzureKeyVaultSecretResolverOptions` | Configuration options for azure key vault secret resolver. | | `AzureOpenAIModelProvider` | `value` | `typeof AzureOpenAIModelProvider` | Provider implementation for azure open aimodel. | | `AzureOpenAIModelProviderOptions` | `type` | `AzureOpenAIModelProviderOptions` | Configuration options for azure open aimodel provider. | | `AzureResourceRef` | `type` | `AzureResourceRef` | Type contract for azure resource ref. | | `createAzureArmClient` | `value` | `(options: AzureArmClientOptions) => AzureArmClient` | Creates azure arm client. | | `createAzureBlobArtifactStore` | `value` | `(options: AzureBlobArtifactStoreOptions) => AzureBlobArtifactStore` | Creates azure blob artifact store. | | `createAzureKeyVaultSecretResolver` | `value` | `(options: AzureKeyVaultSecretResolverOptions) => (name: string) => Promise<string \| undefined>` | Creates azure key vault secret resolver. | | `createFoundryAgentServiceClient` | `value` | `(options: FoundryAgentServiceOptions) => FoundryAgentServiceClient` | Creates foundry agent service client. | | `defineAzureAgent` | `value` | `<TInput = JsonObject, TOutput = unknown>(options?: DefineAzureAgentOptions<TInput, TOutput>) => DefinedAgent<TInput, TOutput>` | Defines azure agent. | | `DefineAzureAgentOptions` | `type` | `DefineAzureAgentOptions<TInput, TOutput>` | Configuration options for define azure agent. | | `FoundryAgentDefinition` | `type` | `FoundryAgentDefinition` | Type contract for foundry agent definition. | | `FoundryAgentInvocationOptions` | `type` | `FoundryAgentInvocationOptions` | Configuration options for foundry agent invocation. | | `FoundryAgentInvocationResult` | `type` | `FoundryAgentInvocationResult` | Result returned by foundry agent invocation. | | `foundryAgentLifecycleTools` | `value` | `(client: FoundryAgentServiceClient) => ToolDef[]` | Runtime API for foundry agent lifecycle tools; the generated signature shows its accepted inputs and return type. | | `FoundryAgentServiceClient` | `value` | `typeof FoundryAgentServiceClient` | Client implementation for foundry agent service. | | `FoundryAgentServiceOptions` | `type` | `FoundryAgentServiceOptions` | Configuration options for foundry agent service. | | `foundryAgentTool` | `value` | `(client: FoundryAgentServiceClient, options?: { name?: string; description?: string; agentId?: string; }) => ToolDef<{ prompt: string; threadId?: string; }, FoundryAgentInvocationResult>` | Model-callable tool or tool factory for foundry agent. | | `FoundryHostedAgentSandboxOptions` | `type` | `FoundryHostedAgentSandboxOptions` | Configuration options for foundry hosted agent sandbox. | | `FoundryRuntimeModelProvider` | `value` | `typeof FoundryRuntimeModelProvider` | Model provider that calls the **Foundry-managed** Azure OpenAI surface using a Bearer token (managed identity) instead of an API key. Designed for the Azure AI Foundry Hosted Agent runtime, but useful on any Azure compute with a managed identity (ACA / AKS / VM) — you don't need the Foundry runtime adapter to use this provider. The runtime injects: - `AZURE_OPENAI_ENDPOINT` — the Foundry-routed Azure OpenAI endpoint. - `AZURE_OPENAI_DEPLOYMENT` — the model deployment name. - `FOUNDRY_AGENT_TOKEN` (or `AZURE_AI_FOUNDRY_TOKEN`) — a pre-issued token when running inside the Hosted Agent contain... | | `FoundryRuntimeModelProviderOptions` | `type` | `FoundryRuntimeModelProviderOptions` | Configuration options for foundry runtime model provider. | | `FoundryThreadMessage` | `type` | `FoundryThreadMessage` | Type contract for foundry thread message. | | `FoundryTokenResolver` | `type` | `FoundryTokenResolver` | Token resolver — returns a Bearer token for the Foundry runtime's managed Azure OpenAI surface. Implementations may cache and refresh. | | `MockAzureModelProvider` | `value` | `typeof MockAzureModelProvider` | A deterministic `ModelProvider` for Azure agent tests and init templates. Returns structured responses without requiring real Azure credentials. | | `MockAzureModelProviderOptions` | `type` | `MockAzureModelProviderOptions` | Configuration options for mock azure model provider. | | `resolveToolRefs` | `value` | `(bundle: AzureBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | ### `@fabric-harness/azure/aks-sandbox` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `aksSandbox` | `value` | `(options: AksSandboxOptions) => Promise<SandboxEnv>` | Sandbox adapter for aks. | | `AksSandboxOptions` | `type` | `AksSandboxOptions` | AKS-flavored Kubernetes sandbox. Pulls cluster credentials from the AKS `listClusterUserCredentials` endpoint, builds a `@kubernetes/client-node` `KubeConfig`, and delegates to `kubernetesSandbox`. Requires both peer deps: ```sh npm install | ### `@fabric-harness/azure/app-insights` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `ApplicationInsightsClientLike` | `type` | `ApplicationInsightsClientLike` | Optional Azure Monitor / Application Insights telemetry exporter. Adapts Fabric's `TelemetrySpan` shape into App Insights `TelemetryClient` `trackDependency` calls. The Azure Monitor SDK is provided by the caller — we don't take a hard dependency. Install peer dep: See the package declarations for an example. Usage: See the package declarations for an example. | | `applicationInsightsExporter` | `value` | `(options: ApplicationInsightsExporterOptions) => TelemetryExporter` | Runtime API for application insights exporter; the generated signature shows its accepted inputs and return type. | | `ApplicationInsightsExporterOptions` | `type` | `ApplicationInsightsExporterOptions` | Configuration options for application insights exporter. | ### `@fabric-harness/azure/foundry-runtime` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `FoundryRuntimeModelProvider` | `value` | `typeof FoundryRuntimeModelProvider` | Model provider that calls the **Foundry-managed** Azure OpenAI surface using a Bearer token (managed identity) instead of an API key. Designed for the Azure AI Foundry Hosted Agent runtime, but useful on any Azure compute with a managed identity (ACA / AKS / VM) — you don't need the Foundry runtime adapter to use this provider. The runtime injects: - `AZURE_OPENAI_ENDPOINT` — the Foundry-routed Azure OpenAI endpoint. - `AZURE_OPENAI_DEPLOYMENT` — the model deployment name. - `FOUNDRY_AGENT_TOKEN` (or `AZURE_AI_FOUNDRY_TOKEN`) — a pre-issued token when running inside the Hosted Agent contain... | | `FoundryRuntimeModelProviderOptions` | `type` | `FoundryRuntimeModelProviderOptions` | Configuration options for foundry runtime model provider. | | `FoundryTokenResolver` | `type` | `FoundryTokenResolver` | Token resolver — returns a Bearer token for the Foundry runtime's managed Azure OpenAI surface. Implementations may cache and refresh. | ### `@fabric-harness/azure/agent` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `azure` | `value` | `(config: AzureBundleConfig) => AzureBundle` | Bundle factory for Azure agents. Returns an `AzureBundle` with a model provider, Azure-specific tools, and a safe default egress policy. | | `AzureBundle` | `type` | `AzureBundle` | Type contract for azure bundle. | | `AzureBundleConfig` | `type` | `AzureBundleConfig` | Type contract for azure bundle config. | | `defineAzureAgent` | `value` | `<TInput = JsonObject, TOutput = unknown>(options?: DefineAzureAgentOptions<TInput, TOutput>) => DefinedAgent<TInput, TOutput>` | Defines azure agent. | | `DefineAzureAgentOptions` | `type` | `DefineAzureAgentOptions<TInput, TOutput>` | Configuration options for define azure agent. | | `resolveToolRefs` | `value` | `(bundle: AzureBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | ## @fabric-harness/channels ### `@fabric-harness/channels` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `bytesToHex` | `value` | `(bytes: Uint8Array) => string` | Runtime API for bytes to hex; the generated signature shows its accepted inputs and return type. | | `Channel` | `type` | `Channel` | Type contract for channel. | | `channelCompatibility` | `value` | `{ readonly slack: { readonly subpath: "slack"; readonly status: "stable"; readonly inboundApi: "Slack Events API"; readonly outboundApi: "Slack Web API"; readonly sdk: "none"; }; readonly github: { readonly subpath: "github"; readonly status: "stable"; read...` | Published channel compatibility contract. Provider payload changes that only add fields are supported without a Fabric release; breaking provider versions are added here before becoming the default. | | `ChannelCompatibility` | `type` | `ChannelCompatibility` | Type contract for channel compatibility. | | `channelCompatibilityPolicy` | `value` | `{ readonly packageRule: "Adapters remain dependency-free subpaths unless a required SDK, runtime incompatibility, or independent release cadence requires a package."; readonly deprecationNoticeDays: 180; readonly removalRule: "Removal occurs only in a major release after...` | Runtime API for channel compatibility policy; the generated signature shows its accepted inputs and return type. | | `ChannelCompatibilityStatus` | `type` | `ChannelCompatibilityStatus` | Type contract for channel compatibility status. | | `ChannelContext` | `type` | `ChannelContext` | Type contract for channel context. | | `ChannelDispatch` | `type` | `ChannelDispatch` | Type contract for channel dispatch. | | `ChannelDispatchRequest` | `type` | `ChannelDispatchRequest` | Input contract for channel dispatch. | | `ChannelRoute` | `type` | `ChannelRoute` | Channels turn platform webhooks (Slack, GitHub, …) into agent dispatches. Handlers are written against the Web `Request`/`Response` API and `crypto.subtle`, so the same channel runs on Node and Cloudflare. A channel is a stateless route container plus a conversation-id (de)serializer — session continuity falls out of the key (same thread → same key → same session). | | `conversationKey` | `value` | `(provider: string, version: string, ...segments: string[]) => string` | Runtime API for conversation key; the generated signature shows its accepted inputs and return type. | | `defineChannel` | `value` | `(channel: Channel) => Channel` | Validates and brands a channel's routes. | | `FirstPartyChannelName` | `type` | `"slack" \| "github" \| "discord" \| "teams" \| "telegram" \| "twilio" \| "whatsapp" \| "googleChat" \| "linear" \| "notion" \| "stripe" \| "zendesk" \| "intercom" \| "shopify" \| "messenger" \| "resend" \| "salesforceMarketingCloud" \| "buzz"` | Type contract for first party channel name. | | `hexToBytes` | `value` | `(hex: string) => Uint8Array` | Runtime API for hex to bytes; the generated signature shows its accepted inputs and return type. | | `hmacSha256` | `value` | `(secret: string \| Uint8Array, message: Uint8Array) => Promise<Uint8Array>` | Runtime API for hmac sha256; the generated signature shows its accepted inputs and return type. | | `parseConversationKey` | `value` | `(key: string) => ParsedConversationKey` | Parses conversation key. | | `ParsedConversationKey` | `type` | `ParsedConversationKey` | Type contract for parsed conversation key. | | `readRequestBody` | `value` | `(request: Request, limitBytes?: number) => Promise<Uint8Array \| undefined>` | Reads the full request body as bytes, or returns undefined if it exceeds `limitBytes`. NOTE: this consumes the request stream (single read). Signature-verifying channels need the *exact* bytes for HMAC and the parsed JSON afterward — don't call `request.json()` as well. Use `readJsonBody` to get both from one read. | | `verifyHmacSha256` | `value` | `(secret: string \| Uint8Array, message: Uint8Array, signature: Uint8Array) => Promise<boolean>` | Constant-time HMAC-SHA256 verification (via `crypto.subtle.verify`). | ### `@fabric-harness/channels/compatibility` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `channelCompatibility` | `value` | `{ readonly slack: { readonly subpath: "slack"; readonly status: "stable"; readonly inboundApi: "Slack Events API"; readonly outboundApi: "Slack Web API"; readonly sdk: "none"; }; readonly github: { readonly subpath: "github"; readonly status: "stable"; read...` | Published channel compatibility contract. Provider payload changes that only add fields are supported without a Fabric release; breaking provider versions are added here before becoming the default. | | `ChannelCompatibility` | `type` | `ChannelCompatibility` | Type contract for channel compatibility. | | `channelCompatibilityPolicy` | `value` | `{ readonly packageRule: "Adapters remain dependency-free subpaths unless a required SDK, runtime incompatibility, or independent release cadence requires a package."; readonly deprecationNoticeDays: 180; readonly removalRule: "Removal occurs only in a major release after...` | Runtime API for channel compatibility policy; the generated signature shows its accepted inputs and return type. | | `ChannelCompatibilityStatus` | `type` | `ChannelCompatibilityStatus` | Type contract for channel compatibility status. | | `FirstPartyChannelName` | `type` | `"slack" \| "github" \| "discord" \| "teams" \| "telegram" \| "twilio" \| "whatsapp" \| "googleChat" \| "linear" \| "notion" \| "stripe" \| "zendesk" \| "intercom" \| "shopify" \| "messenger" \| "resend" \| "salesforceMarketingCloud" \| "buzz"` | Type contract for first party channel name. | ### `@fabric-harness/channels/slack` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createSlackChannel` | `value` | `(options: SlackChannelOptions) => SlackChannel` | Slack events channel. Verifies the `v0` HMAC signature, answers the URL-verification challenge, and dispatches `app_mention` / threaded `message` events to a persistent agent keyed by the Slack thread — with the Slack `event_id` as the dedupe key (exactly-once), the team as tenant, and the user as the acting `actor` (which is what powers on-behalf-of governance downstream). | | `parseSlackConversationKey` | `value` | `(id: string) => SlackThreadRef` | Parse a Slack instance id back into the thread ref (e.g. to bind `replyInSlackThread` at agent init). | | `replyInSlackThread` | `value` | `(ref: SlackThreadRef, options: { botToken: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Outbound tool: reply in the Slack thread this agent is handling. | | `SlackChannel` | `type` | `SlackChannel` | Type contract for slack channel. | | `SlackChannelOptions` | `type` | `SlackChannelOptions` | Configuration options for slack channel. | | `slackConversationKey` | `value` | `(ref: SlackThreadRef) => string` | Serialize a Slack thread into the stable instance id used by `createSlackChannel`. | | `SlackEvent` | `type` | `SlackEvent` | Type contract for slack event. | | `SlackEventsPayload` | `type` | `SlackEventsPayload` | Type contract for slack events payload. | | `SlackThreadRef` | `type` | `SlackThreadRef` | Type contract for slack thread ref. | ### `@fabric-harness/channels/github` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `commentOnGitHubIssue` | `value` | `(ref: GitHubIssueRef, options: { token: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Outbound tool: comment on the GitHub issue / PR this agent is handling. | | `createGitHubChannel` | `value` | `(options: GitHubChannelOptions) => GitHubChannel` | GitHub webhook channel. Verifies the `X-Hub-Signature-256` (`sha256=<hex>` HMAC over the raw body), and dispatches issue / PR / comment events to a persistent agent keyed by `owner/repo/<kind>/<number>` — with `X-GitHub-Delivery` as the dedupe key (exactly-once), the owner as tenant, and the sender as the acting `actor`. Bot senders are ignored to avoid loops; `ping` is acknowledged. | | `GitHubChannel` | `type` | `GitHubChannel` | Type contract for git hub channel. | | `GitHubChannelOptions` | `type` | `GitHubChannelOptions` | Configuration options for git hub channel. | | `githubConversationKey` | `value` | `(ref: GitHubIssueRef) => string` | Runtime API for github conversation key; the generated signature shows its accepted inputs and return type. | | `GitHubIssueRef` | `type` | `GitHubIssueRef` | Type contract for git hub issue ref. | | `GitHubWebhookPayload` | `type` | `GitHubWebhookPayload` | Type contract for git hub webhook payload. | | `NormalizedGitHubEvent` | `type` | `NormalizedGitHubEvent` | Type contract for normalized git hub event. | | `normalizeGitHubEvent` | `value` | `(eventType: string, payload: GitHubWebhookPayload) => NormalizedGitHubEvent \| undefined` | Runtime API for normalize git hub event; the generated signature shows its accepted inputs and return type. | | `parseGitHubConversationKey` | `value` | `(id: string) => GitHubIssueRef` | Parses git hub conversation key. | ### `@fabric-harness/channels/discord` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createDiscordChannel` | `value` | `(options: DiscordChannelOptions) => DiscordChannel` | Creates discord channel. | | `DiscordChannel` | `type` | `DiscordChannel` | Type contract for discord channel. | | `DiscordChannelOptions` | `type` | `DiscordChannelOptions` | Configuration options for discord channel. | | `discordConversationKey` | `value` | `(ref: DiscordConversationRef) => string` | Runtime API for discord conversation key; the generated signature shows its accepted inputs and return type. | | `DiscordConversationRef` | `type` | `DiscordConversationRef` | Type contract for discord conversation ref. | | `DiscordInteractionPayload` | `type` | `DiscordInteractionPayload` | Type contract for discord interaction payload. | | `parseDiscordConversationKey` | `value` | `(id: string) => DiscordConversationRef` | Parses discord conversation key. | | `replyInDiscord` | `value` | `(ref: DiscordConversationRef, options: { botToken: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for reply in discord; the generated signature shows its accepted inputs and return type. | | `verifyDiscordSignature` | `value` | `(publicKeyHex: string, timestamp: string, body: Uint8Array, signatureHex: string) => Promise<boolean>` | Runtime API for verify discord signature; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/channels/teams` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `BotFrameworkAuthenticatorOptions` | `type` | `BotFrameworkAuthenticatorOptions` | Configuration options for bot framework authenticator. | | `createBotFrameworkAuthenticator` | `value` | `(options: BotFrameworkAuthenticatorOptions) => NonNullable<TeamsChannelOptions["authenticate"]>` | Verify Microsoft Bot Connector signatures, issuer, audience, lifetime, service URL, and endorsement. | | `createTeamsChannel` | `value` | `(options: TeamsChannelOptions) => TeamsChannel` | Creates teams channel. | | `parseTeamsConversationKey` | `value` | `(id: string) => TeamsConversationRef` | Parses teams conversation key. | | `replyInTeamsConversation` | `value` | `(ref: TeamsConversationRef, options: { accessToken: string \| (() => string \| Promise<string>); fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for reply in teams conversation; the generated signature shows its accepted inputs and return type. | | `TeamsActivityPayload` | `type` | `TeamsActivityPayload` | Type contract for teams activity payload. | | `TeamsChannel` | `type` | `TeamsChannel` | Type contract for teams channel. | | `TeamsChannelOptions` | `type` | `TeamsChannelOptions` | Configuration options for teams channel. | | `teamsConversationKey` | `value` | `(ref: TeamsConversationRef) => string` | Runtime API for teams conversation key; the generated signature shows its accepted inputs and return type. | | `TeamsConversationRef` | `type` | `TeamsConversationRef` | Type contract for teams conversation ref. | ### `@fabric-harness/channels/telegram` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createTelegramChannel` | `value` | `(options: TelegramChannelOptions) => TelegramChannel` | Creates telegram channel. | | `parseTelegramConversationKey` | `value` | `(id: string) => TelegramConversationRef` | Parses telegram conversation key. | | `replyInTelegram` | `value` | `(ref: TelegramConversationRef, options: { botToken: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for reply in telegram; the generated signature shows its accepted inputs and return type. | | `TelegramChannel` | `type` | `TelegramChannel` | Type contract for telegram channel. | | `TelegramChannelOptions` | `type` | `TelegramChannelOptions` | Configuration options for telegram channel. | | `telegramConversationKey` | `value` | `(ref: TelegramConversationRef) => string` | Runtime API for telegram conversation key; the generated signature shows its accepted inputs and return type. | | `TelegramConversationRef` | `type` | `TelegramConversationRef` | Type contract for telegram conversation ref. | | `TelegramMessagePayload` | `type` | `TelegramMessagePayload` | Type contract for telegram message payload. | | `TelegramUpdatePayload` | `type` | `TelegramUpdatePayload` | Type contract for telegram update payload. | ### `@fabric-harness/channels/twilio` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createTwilioChannel` | `value` | `(options: TwilioChannelOptions) => TwilioChannel` | Creates twilio channel. | | `parseTwilioConversationKey` | `value` | `(id: string) => TwilioConversationRef` | Parses twilio conversation key. | | `replyWithTwilio` | `value` | `(ref: TwilioConversationRef, options: { authToken: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for reply with twilio; the generated signature shows its accepted inputs and return type. | | `TwilioChannel` | `type` | `TwilioChannel` | Type contract for twilio channel. | | `TwilioChannelOptions` | `type` | `TwilioChannelOptions` | Configuration options for twilio channel. | | `twilioConversationKey` | `value` | `(ref: TwilioConversationRef) => string` | Runtime API for twilio conversation key; the generated signature shows its accepted inputs and return type. | | `TwilioConversationRef` | `type` | `TwilioConversationRef` | Type contract for twilio conversation ref. | | `TwilioMessagePayload` | `type` | `TwilioMessagePayload` | Type contract for twilio message payload. | | `verifyTwilioSignature` | `value` | `(authToken: string, url: string, params: URLSearchParams, signature: string) => Promise<boolean>` | Runtime API for verify twilio signature; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/channels/whatsapp` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createWhatsAppChannel` | `value` | `(options: WhatsAppChannelOptions) => WhatsAppChannel` | Creates whats app channel. | | `parseWhatsAppConversationKey` | `value` | `(id: string) => WhatsAppConversationRef` | Parses whats app conversation key. | | `replyInWhatsApp` | `value` | `(ref: WhatsAppConversationRef, options: { accessToken: string; apiVersion?: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for reply in whats app; the generated signature shows its accepted inputs and return type. | | `WhatsAppChannel` | `type` | `WhatsAppChannel` | Type contract for whats app channel. | | `WhatsAppChannelOptions` | `type` | `WhatsAppChannelOptions` | Configuration options for whats app channel. | | `whatsAppConversationKey` | `value` | `(ref: WhatsAppConversationRef) => string` | Runtime API for whats app conversation key; the generated signature shows its accepted inputs and return type. | | `WhatsAppConversationRef` | `type` | `WhatsAppConversationRef` | Type contract for whats app conversation ref. | | `WhatsAppWebhookPayload` | `type` | `WhatsAppWebhookPayload` | Type contract for whats app webhook payload. | ### `@fabric-harness/channels/google-chat` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createGoogleChatChannel` | `value` | `(options: GoogleChatChannelOptions) => GoogleChatChannel` | Creates google chat channel. | | `GoogleChatChannel` | `type` | `GoogleChatChannel` | Type contract for google chat channel. | | `GoogleChatChannelOptions` | `type` | `GoogleChatChannelOptions` | Configuration options for google chat channel. | | `googleChatConversationKey` | `value` | `(ref: GoogleChatConversationRef) => string` | Runtime API for google chat conversation key; the generated signature shows its accepted inputs and return type. | | `GoogleChatConversationRef` | `type` | `GoogleChatConversationRef` | Type contract for google chat conversation ref. | | `GoogleChatEvent` | `type` | `GoogleChatEvent` | Type contract for google chat event. | | `parseGoogleChatConversationKey` | `value` | `(id: string) => GoogleChatConversationRef` | Parses google chat conversation key. | | `replyInGoogleChat` | `value` | `(ref: GoogleChatConversationRef, options: { accessToken: string; space: string; thread?: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for reply in google chat; the generated signature shows its accepted inputs and return type. | | `verifyGoogleChatRequest` | `value` | `(request: Request, options: { audience: string \| readonly string[]; fetchImpl?: typeof fetch \| undefined; now?: (() => number) \| undefined; }) => Promise<boolean>` | Input contract for verify google chat. | ### `@fabric-harness/channels/linear` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `commentOnLinearIssue` | `value` | `(ref: LinearConversationRef, options: { apiKey: string; issueId: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for comment on linear issue; the generated signature shows its accepted inputs and return type. | | `createLinearChannel` | `value` | `(options: LinearChannelOptions) => LinearChannel` | Creates linear channel. | | `LinearChannel` | `type` | `LinearChannel` | Type contract for linear channel. | | `LinearChannelOptions` | `type` | `LinearChannelOptions` | Configuration options for linear channel. | | `linearConversationKey` | `value` | `(ref: LinearConversationRef) => string` | Runtime API for linear conversation key; the generated signature shows its accepted inputs and return type. | | `LinearConversationRef` | `type` | `LinearConversationRef` | Type contract for linear conversation ref. | | `LinearWebhookPayload` | `type` | `LinearWebhookPayload` | Type contract for linear webhook payload. | | `parseLinearConversationKey` | `value` | `(id: string) => SimpleConversationRef` | Parses linear conversation key. | ### `@fabric-harness/channels/notion` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `commentOnNotionPage` | `value` | `(ref: NotionConversationRef, options: { token: string; parentId: string; notionVersion?: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for comment on notion page; the generated signature shows its accepted inputs and return type. | | `createNotionChannel` | `value` | `(options: NotionChannelOptions) => NotionChannel` | Creates notion channel. | | `NotionChannel` | `type` | `NotionChannel` | Type contract for notion channel. | | `NotionChannelOptions` | `type` | `NotionChannelOptions` | Configuration options for notion channel. | | `notionConversationKey` | `value` | `(ref: NotionConversationRef) => string` | Runtime API for notion conversation key; the generated signature shows its accepted inputs and return type. | | `NotionConversationRef` | `type` | `NotionConversationRef` | Type contract for notion conversation ref. | | `NotionWebhookPayload` | `type` | `NotionWebhookPayload` | Type contract for notion webhook payload. | | `parseNotionConversationKey` | `value` | `(id: string) => SimpleConversationRef` | Parses notion conversation key. | ### `@fabric-harness/channels/stripe` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createStripeChannel` | `value` | `(options: StripeChannelOptions) => StripeChannel` | Creates stripe channel. | | `parseStripeConversationKey` | `value` | `(id: string) => SimpleConversationRef` | Parses stripe conversation key. | | `StripeChannel` | `type` | `StripeChannel` | Type contract for stripe channel. | | `StripeChannelOptions` | `type` | `StripeChannelOptions` | Configuration options for stripe channel. | | `stripeConversationKey` | `value` | `(ref: StripeConversationRef) => string` | Runtime API for stripe conversation key; the generated signature shows its accepted inputs and return type. | | `StripeConversationRef` | `type` | `StripeConversationRef` | Type contract for stripe conversation ref. | | `StripeEventPayload` | `type` | `StripeEventPayload` | Type contract for stripe event payload. | | `updateStripeCustomer` | `value` | `(ref: StripeConversationRef, options: { secretKey: string; customerId: string; fetchImpl?: typeof fetch; }) => ToolDef<{ description: string; }, unknown>` | Runtime API for update stripe customer; the generated signature shows its accepted inputs and return type. | | `verifyStripeSignature` | `value` | `(secret: string, raw: Uint8Array, header: string \| null, options?: { toleranceSeconds?: number; now?: () => number; }) => Promise<boolean>` | Runtime API for verify stripe signature; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/channels/zendesk` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `commentOnZendeskTicket` | `value` | `(ref: ZendeskConversationRef, options: { subdomain: string; token: string; email: string; ticketId: string \| number; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; public?: boolean; }, unknown>` | Runtime API for comment on zendesk ticket; the generated signature shows its accepted inputs and return type. | | `createZendeskChannel` | `value` | `(options: ZendeskChannelOptions) => ZendeskChannel` | Creates zendesk channel. | | `parseZendeskConversationKey` | `value` | `(id: string) => SimpleConversationRef` | Parses zendesk conversation key. | | `ZendeskChannel` | `type` | `ZendeskChannel` | Type contract for zendesk channel. | | `ZendeskChannelOptions` | `type` | `ZendeskChannelOptions` | Configuration options for zendesk channel. | | `zendeskConversationKey` | `value` | `(ref: ZendeskConversationRef) => string` | Runtime API for zendesk conversation key; the generated signature shows its accepted inputs and return type. | | `ZendeskConversationRef` | `type` | `ZendeskConversationRef` | Type contract for zendesk conversation ref. | | `ZendeskWebhookPayload` | `type` | `ZendeskWebhookPayload` | Type contract for zendesk webhook payload. | ### `@fabric-harness/channels/intercom` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createIntercomChannel` | `value` | `(options: IntercomChannelOptions) => IntercomChannel` | Creates intercom channel. | | `IntercomChannel` | `type` | `IntercomChannel` | Type contract for intercom channel. | | `IntercomChannelOptions` | `type` | `IntercomChannelOptions` | Configuration options for intercom channel. | | `intercomConversationKey` | `value` | `(ref: IntercomConversationRef) => string` | Runtime API for intercom conversation key; the generated signature shows its accepted inputs and return type. | | `IntercomConversationRef` | `type` | `IntercomConversationRef` | Type contract for intercom conversation ref. | | `IntercomWebhookPayload` | `type` | `IntercomWebhookPayload` | Type contract for intercom webhook payload. | | `parseIntercomConversationKey` | `value` | `(id: string) => SimpleConversationRef` | Parses intercom conversation key. | | `replyInIntercom` | `value` | `(ref: IntercomConversationRef, options: { accessToken: string; conversationId: string; adminId: string; apiVersion?: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for reply in intercom; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/channels/shopify` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createShopifyChannel` | `value` | `(options: ShopifyChannelOptions) => ShopifyChannel` | Creates shopify channel. | | `parseShopifyConversationKey` | `value` | `(id: string) => SimpleConversationRef` | Parses shopify conversation key. | | `ShopifyChannel` | `type` | `ShopifyChannel` | Type contract for shopify channel. | | `ShopifyChannelOptions` | `type` | `ShopifyChannelOptions` | Configuration options for shopify channel. | | `shopifyConversationKey` | `value` | `(ref: ShopifyConversationRef) => string` | Runtime API for shopify conversation key; the generated signature shows its accepted inputs and return type. | | `ShopifyConversationRef` | `type` | `ShopifyConversationRef` | Type contract for shopify conversation ref. | | `ShopifyWebhookPayload` | `type` | `ShopifyWebhookPayload` | Type contract for shopify webhook payload. | | `updateShopifyOrderNote` | `value` | `(ref: ShopifyConversationRef, options: { shop: string; accessToken: string; orderId: string; apiVersion?: string; fetchImpl?: typeof fetch; }) => ToolDef<{ note: string; }, unknown>` | Runtime API for update shopify order note; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/channels/messenger` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createMessengerChannel` | `value` | `(options: MessengerChannelOptions) => MessengerChannel` | Creates messenger channel. | | `MessengerChannel` | `type` | `MessengerChannel` | Type contract for messenger channel. | | `MessengerChannelOptions` | `type` | `MessengerChannelOptions` | Configuration options for messenger channel. | | `messengerConversationKey` | `value` | `(ref: MessengerConversationRef) => string` | Runtime API for messenger conversation key; the generated signature shows its accepted inputs and return type. | | `MessengerConversationRef` | `type` | `MessengerConversationRef` | Type contract for messenger conversation ref. | | `MessengerWebhookPayload` | `type` | `MessengerWebhookPayload` | Type contract for messenger webhook payload. | | `parseMessengerConversationKey` | `value` | `(id: string) => MessengerConversationRef` | Parses messenger conversation key. | | `replyInMessenger` | `value` | `(ref: MessengerConversationRef, options: { pageAccessToken: string; apiVersion?: string; fetchImpl?: typeof fetch; }) => ToolDef<{ text: string; }, unknown>` | Runtime API for reply in messenger; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/channels/resend` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createResendChannel` | `value` | `(options: ResendChannelOptions) => ResendChannel` | Creates resend channel. | | `parseResendConversationKey` | `value` | `(id: string) => SimpleConversationRef` | Parses resend conversation key. | | `ResendChannel` | `type` | `ResendChannel` | Type contract for resend channel. | | `ResendChannelOptions` | `type` | `ResendChannelOptions` | Configuration options for resend channel. | | `resendConversationKey` | `value` | `(ref: ResendConversationRef) => string` | Runtime API for resend conversation key; the generated signature shows its accepted inputs and return type. | | `ResendConversationRef` | `type` | `ResendConversationRef` | Type contract for resend conversation ref. | | `ResendWebhookPayload` | `type` | `ResendWebhookPayload` | Type contract for resend webhook payload. | | `sendWithResend` | `value` | `(ref: ResendConversationRef, options: { apiKey: string; from: string; to: string; fetchImpl?: typeof fetch; }) => ToolDef<{ subject: string; text: string; }, unknown>` | Runtime API for send with resend; the generated signature shows its accepted inputs and return type. | | `verifyResendSignature` | `value` | `(secret: string, raw: Uint8Array, headers: Headers, options?: { toleranceSeconds?: number; now?: () => number; }) => Promise<boolean>` | Runtime API for verify resend signature; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/channels/salesforce-marketing-cloud` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createSalesforceMarketingCloudChannel` | `value` | `(options: SalesforceMarketingCloudChannelOptions) => SalesforceMarketingCloudChannel` | Creates salesforce marketing cloud channel. | | `parseSalesforceMarketingCloudConversationKey` | `value` | `(id: string) => SimpleConversationRef` | Parses salesforce marketing cloud conversation key. | | `SalesforceMarketingCloudChannel` | `type` | `SalesforceMarketingCloudChannel` | Type contract for salesforce marketing cloud channel. | | `SalesforceMarketingCloudChannelOptions` | `type` | `SalesforceMarketingCloudChannelOptions` | Configuration options for salesforce marketing cloud channel. | | `salesforceMarketingCloudConversationKey` | `value` | `(ref: SalesforceMarketingCloudConversationRef) => string` | Runtime API for salesforce marketing cloud conversation key; the generated signature shows its accepted inputs and return type. | | `SalesforceMarketingCloudConversationRef` | `type` | `SalesforceMarketingCloudConversationRef` | Type contract for salesforce marketing cloud conversation ref. | | `SalesforceMarketingCloudEvent` | `type` | `SalesforceMarketingCloudEvent` | Type contract for salesforce marketing cloud event. | | `SalesforceMarketingCloudWebhookPayload` | `type` | `SalesforceMarketingCloudWebhookPayload` | Type contract for salesforce marketing cloud webhook payload. | | `sendMarketingCloudMessage` | `value` | `(ref: SalesforceMarketingCloudConversationRef, options: { restBaseUrl: string; accessToken: string; definitionKey: string; recipient: string; fetchImpl?: typeof fetch; }) => ToolDef<{ attributes: Record<string, string>; }, unknown>` | Runtime API for send marketing cloud message; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/channels/buzz` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `addBuzzReaction` | `value` | `(ref: BuzzThreadRef, config: BuzzPostConfig) => ToolDef<{ emoji: string; targetEventId: string; }, BuzzPostResult>` | Outbound tool: add an emoji reaction to an event in the handled channel. | | `BUZZ_PROTOCOL_SUPPORT` | `value` | `{ readonly channelMessages: "dispatch"; readonly forumMessages: "dispatch"; readonly reactions: "dispatch"; readonly messageEdits: "observe-only"; readonly eventDeletions: "observe-only"; readonly reactionRemoval: "observe-only-no-decision-reversal"; readonly channelDelet...` | Explicit product support policy for stock Buzz protocol surfaces. | | `BuzzChannel` | `type` | `BuzzChannel` | Type contract for buzz channel. | | `BuzzChannelOptions` | `type` | `BuzzChannelOptions` | Configuration options for buzz channel. | | `buzzConversationKey` | `value` | `(ref: BuzzThreadRef) => string` | Serialize a Buzz thread into the stable instance id used by `createBuzzChannel`. | | `BuzzEnvelope` | `type` | `BuzzEnvelope` | Type contract for buzz envelope. | | `BuzzEvent` | `type` | `BuzzEvent` | Nostr event shape (NIP-01). Kept local so the handler path stays SDK-only. | | `buzzHttpUrl` | `value` | `(relayUrl: string) => string` | Convert a relay WebSocket URL to its HTTP origin (Buzz serves both on one port). | | `BuzzLifecycleNotice` | `type` | `BuzzLifecycleNotice` | Content-free lifecycle evidence. Lifecycle events never enter model input and never reverse an immutable Platform decision. Applications may persist this through an operator/audit sink. | | `BuzzLifecycleType` | `type` | `BuzzLifecycleType` | Type contract for buzz lifecycle type. | | `buzzNip98AuthHeader` | `value` | `(secretKeyHex: string, url: string, method: string, bodyText?: string, now?: () => number) => Promise<string>` | Build the `Authorization: Nostr <base64(kind-27235)>` header for a Buzz HTTP-bridge request. Includes the `payload` sha256 tag when a body is given (NIP-98 SHOULD for POST; Buzz verifies it when present). Each call mints a fresh single-use event — the relay replay-guards by event id. | | `BuzzPostConfig` | `type` | `BuzzPostConfig` | Type contract for buzz post config. | | `BuzzPostResult` | `type` | `BuzzPostResult` | Result returned by buzz post. | | `buzzPublicKey` | `value` | `(secretKeyHex: string) => string` | Derive the adapter identity's public key from its secret key (64-char hex). | | `BuzzRelayInfo` | `type` | `BuzzRelayInfo` | NIP-11 relay information document (feature detection — plan §5.5). | | `BuzzThreadRef` | `type` | `BuzzThreadRef` | Type contract for buzz thread ref. | | `classifyBuzzLifecycleEvent` | `value` | `(event: BuzzEvent, channelId?: string \| undefined) => BuzzLifecycleNotice \| undefined` | Classify lifecycle kinds without inspecting or returning event content. | | `createBuzzChannel` | `value` | `(options: BuzzChannelOptions) => BuzzChannel` | Buzz events channel. Verifies the tail envelope HMAC (timestamped, replay bounded), verifies the inner event's Schnorr signature, normalizes stream messages / forum posts / reactions, and dispatches to a persistent agent keyed by (community, channel, thread root) — with the Nostr event id as the dedupe key (exactly-once), the community as tenant, and the author pubkey as the acting `actor`. | | `createSignedBuzzEvent` | `value` | `(config: BuzzPostConfig, template: { kind: number; content: string; tags: string[][]; }) => BuzzEvent` | Build the exact signed event that will be submitted to Buzz. | | `parseBuzzConversationKey` | `value` | `(id: string) => BuzzThreadRef` | Parse a Buzz instance id back into the thread ref. | | `postBuzzDecisionRequest` | `value` | `(ref: BuzzThreadRef, config: BuzzPostConfig) => ToolDef<{ approvalRequestId: string; title: string; body: string; options?: string[]; }, BuzzPostResult>` | Outbound tool: post a decision-request card. | | `postInBuzzChannel` | `value` | `(ref: BuzzThreadRef, config: BuzzPostConfig) => ToolDef<{ text: string; }, BuzzPostResult>` | Outbound tool: post a message in the Buzz channel this agent is handling. | | `postSignedBuzzEvent` | `value` | `(config: BuzzPostConfig, template: { kind: number; content: string; tags: string[][]; }) => Promise<BuzzPostResult>` | Sign a Buzz event with the adapter identity and submit it over the relay HTTP bridge. | | `probeBuzzRelay` | `value` | `(relayUrl: string, fetchImpl?: typeof fetch, options?: { signal?: AbortSignal; requestTimeoutMs?: number; }) => Promise<BuzzRelayInfo>` | Probe a Buzz relay's NIP-11 document. Detect features; never assume them. | | `queryBuzzEvents` | `value` | `(config: BuzzPostConfig, filters: ReadonlyArray<Record<string, unknown>>) => Promise<BuzzEvent[]>` | Authenticated HTTP-bridge query used by recovery and reconciliation paths. | | `replyInBuzzThread` | `value` | `(ref: BuzzThreadRef, config: BuzzPostConfig) => ToolDef<{ text: string; }, BuzzPostResult>` | Outbound tool: reply in the Buzz thread this agent is handling. | | `signBuzzEnvelope` | `value` | `(secret: string, timestampSeconds: number, rawBody: string) => Promise<string>` | Family signed-envelope standard: `v1=hex(hmac-sha256(secret, "<ts>.<body>"))`. | | `submitSignedBuzzEvent` | `value` | `(config: BuzzPostConfig, event: BuzzEvent) => Promise<BuzzPostResult>` | Submit one already-signed event without changing its stable event id. | | `verifyBuzzEvent` | `value` | `(event: BuzzEvent) => boolean` | Verify a complete NIP-01 event id and Schnorr signature. | ### `@fabric-harness/channels/buzz-tail` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `BuzzCursorStore` | `type` | `BuzzCursorStore` | Durable cursor persistence. Implementations must survive process restarts (file, database, durable object …). `inMemoryBuzzCursorStore` exists for tests and explicitly does NOT satisfy plan D15 in production. | | `BuzzDeadLetterReason` | `type` | `BuzzDeadLetterReason` | Type contract for buzz dead letter reason. | | `BuzzDeadLetterRecord` | `type` | `BuzzDeadLetterRecord` | Type contract for buzz dead letter record. | | `BuzzDeadLetterStore` | `type` | `BuzzDeadLetterStore` | Durable dead-letter backlog. Recording and reconciliation marking must be idempotent by event id; listing must return only unresolved records. | | `BuzzTail` | `type` | `BuzzTail` | Type contract for buzz tail. | | `BuzzTailOperationalEvent` | `type` | `BuzzTailOperationalEvent` | Content-free operational events suitable for metrics and certification evidence. | | `BuzzTailOptions` | `type` | `BuzzTailOptions` | Configuration options for buzz tail. | | `inMemoryBuzzCursorStore` | `value` | `(initial?: number) => BuzzCursorStore & { current(): number \| undefined; }` | Test/development cursor store. Not durable — never use in production. | | `reconcileBuzzDeadLetters` | `value` | `(options: ReconcileBuzzDeadLettersOptions) => Promise<{ attempted: number; reconciled: number; }>` | Reconcile one bounded dead-letter batch. Records are acknowledged only after replay succeeds, so failed records remain visible for later repair. | | `ReconcileBuzzDeadLettersOptions` | `type` | `ReconcileBuzzDeadLettersOptions` | Configuration options for reconcile buzz dead letters. | | `startBuzzTail` | `value` | `(options: BuzzTailOptions) => BuzzTail` | Start tailing a Buzz relay with durable, ordered, at-least-once forwarding. | ### `@fabric-harness/channels/buzz-decisions` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `BUZZ_DECISION_EMOJI` | `value` | `Readonly<Record<string, "approve" \| "reject">>` | Fixed reaction→choice table (D14). NIP-25 `+`/`-` are included alongside the emoji the card legend shows. Anything else on a card is `unmapped` — surfaced for audit, never guessed. | | `BuzzCardReceipt` | `type` | `BuzzCardReceipt` | The binding between a posted card and its ApprovalRequest (plan §4 step 2). Stored by the trusted renderer beside the request; the bridge resolves reactions through it and through nothing else. | | `BuzzCardReceiptStore` | `type` | `BuzzCardReceiptStore` | Receipt lookup shared by ingress correlation and the deterministic bridge. | | `BuzzDecisionBridgeOptions` | `type` | `BuzzDecisionBridgeOptions` | Configuration options for buzz decision bridge. | | `BuzzDecisionCandidate` | `type` | `BuzzDecisionCandidate` | Type contract for buzz decision candidate. | | `BuzzDecisionCardDelivery` | `type` | `BuzzDecisionCardDelivery` | Durable outbox record for one canonical decision card. The exact signed event is persisted before relay I/O, making its Nostr id stable across retries and ambiguous network outcomes. | | `buzzDecisionCardDeliveryKey` | `value` | `(community: string, channelId: string, approvalRequestId: string, requestVersion: number) => string` | Stable logical identity for one request version on one Buzz surface. | | `BuzzDecisionCardDeliveryStatus` | `type` | `BuzzDecisionCardDeliveryStatus` | Type contract for buzz decision card delivery status. | | `BuzzDecisionCardDeliveryStore` | `type` | `BuzzDecisionCardDeliveryStore` | Production decision-card store. Implement this beside the vertical's ApprovalRequest. `prepareDelivery` is an immutable put-if-absent by deliveryKey and returns the existing record on retry. Publication marking must be idempotent. | | `BuzzDecisionCardInput` | `type` | `BuzzDecisionCardInput` | Deterministic, model-free decision surface for Buzz (Fabric Buzz Collaboration Plan D14; B1-H items 5–6). A signed reaction is mapped by trusted code from `(community, channel, targetEventId)` to exactly one immutable ApprovalRequest via a **card receipt** stored when the card was posted. A model may explain or acknowledge the result; it never selects the request, choice, principal, edits, or parameters. Free-form replies to a card are **edit proposals** — never approvals — until validated and explicitly confirmed through a structured decision path. Layering: this module performs zero autho... | | `BuzzDecisionResolution` | `type` | `BuzzDecisionResolution` | Type contract for buzz decision resolution. | | `BuzzEditProposal` | `type` | `BuzzEditProposal` | Type contract for buzz edit proposal. | | `BuzzMessageInput` | `type` | `BuzzMessageInput` | Normalized message input as dispatched by the Buzz channel route. | | `BuzzReactionInput` | `type` | `BuzzReactionInput` | Normalized reaction input as dispatched by the Buzz channel route. | | `createBuzzDecisionBridge` | `value` | `(options: BuzzDecisionBridgeOptions) => { resolveReaction: (reaction: BuzzReactionInput) => Promise<BuzzDecisionResolution>; resolveReply: (message: BuzzMessageInput) => Promise<BuzzDecisionResolution>; }` | The deterministic decision bridge (plan §4 steps 4–5). Pure lookup + fixed tables; no clock, no model, no authorization. Returns what the event *is* — the vertical's governed action decides what happens. | | `inMemoryBuzzCardReceiptStore` | `value` | `() => BuzzDecisionCardDeliveryStore & { all(): BuzzCardReceipt[]; deliveries(): BuzzDecisionCardDelivery[]; }` | Test/development receipt store. Not durable — never use in production. | | `postBuzzDecisionCard` | `value` | `(ref: BuzzThreadRef, config: BuzzPostConfig & { deliveryStore: BuzzDecisionCardDeliveryStore; now?: () => number; }) => ToolDef<BuzzDecisionCardInput, BuzzCardReceipt>` | Outbound tool: durably prepare the exact signed event + receipt, submit it, reconcile an ambiguous response by exact event id, then checkpoint publication. Returns the receipt. Posting a card grants nothing by itself. | | `renderBuzzDecisionCard` | `value` | `(input: BuzzDecisionCardInput) => { content: string; tags: string[][]; }` | Render the canonical decision card. Pure and deterministic: identical input yields byte-identical content and tags. The card's human-readable content is informational; all authority derives from the stored receipt, never from parsing this text back. | ### `@fabric-harness/channels/buzz-postgres` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `BuzzPostgresClient` | `type` | `BuzzPostgresClient` | Structural client contract implemented by `pg.Pool` and Lakebase clients. | | `BuzzPostgresHealth` | `type` | `BuzzPostgresHealth` | Content-free operational evidence for one durable Buzz bridge consumer. | | `BuzzPostgresPersistence` | `type` | `BuzzPostgresPersistence` | Type contract for buzz postgres persistence. | | `BuzzPostgresPersistenceOptions` | `type` | `BuzzPostgresPersistenceOptions` | Configuration options for buzz postgres persistence. | | `createPostgresBuzzPersistence` | `value` | `(options: BuzzPostgresPersistenceOptions) => BuzzPostgresPersistence` | Create the durable Buzz bridge state used by PostgreSQL and Databricks Lakebase deployments. No `pg` dependency is loaded by the channels package; applications inject their existing pool/client. | | `ensurePostgresBuzzTables` | `value` | `(client: BuzzPostgresClient, options?: { tablePrefix?: string; }) => Promise<void>` | Runtime API for ensure postgres buzz tables; the generated signature shows its accepted inputs and return type. | | `inspectPostgresBuzzHealth` | `value` | `(client: BuzzPostgresClient, options: InspectPostgresBuzzHealthOptions) => Promise<BuzzPostgresHealth>` | Inspect durable Buzz bridge state without creating tables or reading event, dead-letter, or decision-card payloads. This is safe for read-only certification principals and returns only bounded operational counters. | | `InspectPostgresBuzzHealthOptions` | `type` | `InspectPostgresBuzzHealthOptions` | Configuration options for inspect postgres buzz health. | ### `@fabric-harness/channels/buzz-attestation` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `computeBuzzAuthTag` | `value` | `(ownerSecretKeyHex: string, agentPubkeyHex: string, conditions?: string) => string` | Compute a NIP-OA auth tag as its canonical JSON-array string. Runs anywhere the adapter runs — no Rust toolchain needed for enrollment. Self-attestation (owner == agent) is rejected, matching the relay. | | `parseBuzzAuthTag` | `value` | `(tagJson: string) => [string, string, string, string]` | Parse and shape-check an auth-tag JSON string (from config/env) into the four-string tag array to attach to an AUTH event. Fails fast on malformed input so a mangled tag (the classic shell-sourced-.env bug) surfaces at startup, not as a silent 403 at the relay. | | `validateBuzzAuthConditions` | `value` | `(conditions: string) => void` | Validate a NIP-OA conditions string: empty, or `&`-joined clauses of `kind=<0-65535>`, `created_at<<u32>`, `created_at><u32>`. Canonical decimals only, no whitespace — mirrors `buzz-sdk`'s validation so a tag we mint is a tag the relay accepts. | ### `@fabric-harness/channels/buzz-doctor` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `BuzzDiagnostic` | `type` | `BuzzDiagnostic` | Type contract for buzz diagnostic. | | `diagnoseBuzzConnection` | `value` | `(options: DiagnoseBuzzOptions) => Promise<BuzzDiagnostic[]>` | Runtime API for diagnose buzz connection; the generated signature shows its accepted inputs and return type. | | `DiagnoseBuzzOptions` | `type` | `DiagnoseBuzzOptions` | Configuration options for diagnose buzz. | | `formatBuzzDiagnostics` | `value` | `(diagnostics: BuzzDiagnostic[]) => string` | Render diagnostics as aligned operator-readable lines. | ### `@fabric-harness/channels/buzz-media` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `BuzzAttachment` | `type` | `BuzzAttachment` | Type contract for buzz attachment. | | `buzzAttachmentMarkdown` | `value` | `(attachments: readonly BuzzAttachment[]) => string` | Content lines that make attachments render inline: `![image](url)` / `![video](url)` for media MIME types, a plain markdown link otherwise. | | `buzzImetaTags` | `value` | `(attachments: readonly BuzzAttachment[]) => string[][]` | NIP-92 imeta tags, mirroring the desktop composer's field policy. | | `uploadBuzzAttachment` | `value` | `(config: BuzzPostConfig, data: Uint8Array, options: { contentType: string; filename?: string; }) => Promise<BuzzAttachment>` | Upload one attachment to the relay's Blossom endpoint. Returns the descriptor needed for `buzzImetaTags` / `buzzAttachmentMarkdown`. | ## @fabric-harness/cli ### `@fabric-harness/cli` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | _No named exports_ | | | | ### `@fabric-harness/cli/config` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `defineConfig` | `value` | `<T extends DefineConfigInput>(config: T) => T` | Defines config. | | `DefineConfigInput` | `type` | `DefineConfigInput` | Type contract for define config input. | ## @fabric-harness/cloudflare ### `@fabric-harness/cloudflare` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `cloudflare` | `value` | `(config: CloudflareBundleConfig) => CloudflareBundle` | One-call wiring for a Cloudflare-native agent: model provider, Workers AI binding tools, a safe default egress policy, and an optional Durable Object session store. | | `CLOUDFLARE_BUILD_TARGET` | `value` | `"cloudflare"` | Constant defining cloudflare build target. | | `CLOUDFLARE_SCHEDULE_ACTOR` | `value` | `FabricActor` | Actor stamped on admissions triggered by a scheduled wake-up. | | `CLOUDFLARE_SCHEDULE_SIGNAL_TYPE` | `value` | `"schedule"` | Signal `type` of the delivered message produced by a scheduled wake-up. | | `CloudflareAlarmSchedulerLike` | `type` | `CloudflareAlarmSchedulerLike` | The Durable Object storage alarm surface (`ctx.storage`) this module needs. | | `CloudflareBundle` | `type` | `CloudflareBundle` | Type contract for cloudflare bundle. | | `CloudflareBundleConfig` | `type` | `CloudflareBundleConfig` | Type contract for cloudflare bundle config. | | `CloudflareCronHandlerOptions` | `type` | `CloudflareCronHandlerOptions<TEnv>` | Configuration options for cloudflare cron handler. | | `CloudflareDurableObjectHost` | `type` | `CloudflareDurableObjectHost` | Type contract for cloudflare durable object host. | | `CloudflareDurableObjectHostAdmission` | `type` | `CloudflareDurableObjectHostAdmission` | Type contract for cloudflare durable object host admission. | | `CloudflareDurableObjectHostAdmissionOptions` | `type` | `CloudflareDurableObjectHostAdmissionOptions` | Configuration options for cloudflare durable object host admission. | | `CloudflareDurableObjectHostAlarmOptions` | `type` | `CloudflareDurableObjectHostAlarmOptions` | Configuration options for cloudflare durable object host alarm. | | `CloudflareDurableObjectHostDeleteResult` | `type` | `CloudflareDurableObjectHostDeleteResult` | Result returned by cloudflare durable object host delete. | | `CloudflareDurableObjectHostOptions` | `type` | `CloudflareDurableObjectHostOptions` | Configuration options for cloudflare durable object host. | | `CloudflareDurableObjectNamespaceLike` | `type` | `CloudflareDurableObjectNamespaceLike` | Type contract for cloudflare durable object namespace like. | | `CloudflareDurableObjectSessionStoreOptions` | `type` | `CloudflareDurableObjectSessionStoreOptions` | Configuration options for cloudflare durable object session store. | | `CloudflareDurableObjectSqlStorage` | `type` | `CloudflareDurableObjectSqlStorage` | Type contract for cloudflare durable object sql storage. | | `CloudflareDurablePersistenceStores` | `type` | `CloudflareDurablePersistenceStores` | Type contract for cloudflare durable persistence stores. | | `CloudflareExecutionContextLike` | `type` | `CloudflareExecutionContextLike` | Type contract for cloudflare execution context like. | | `CloudflareExtension` | `type` | `CloudflareExtension` | Type contract for cloudflare extension. | | `CloudflareIndexedRun` | `type` | `CloudflareIndexedRun` | Type contract for cloudflare indexed run. | | `CloudflareIndexedRunStatus` | `type` | `CloudflareIndexedRunStatus` | Type contract for cloudflare indexed run status. | | `CloudflareInstanceSchedule` | `type` | `CloudflareInstanceSchedule` | A durable per-instance schedule row. | | `CloudflareR2BucketLike` | `type` | `CloudflareR2BucketLike` | Type contract for cloudflare r2 bucket like. | | `CloudflareR2ListResultLike` | `type` | `CloudflareR2ListResultLike` | Type contract for cloudflare r2 list result like. | | `CloudflareR2ObjectBodyLike` | `type` | `CloudflareR2ObjectBodyLike` | Type contract for cloudflare r2 object body like. | | `CloudflareRunListOptions` | `type` | `CloudflareRunListOptions` | Configuration options for cloudflare run list. | | `CloudflareRunListPage` | `type` | `CloudflareRunListPage` | Type contract for cloudflare run list page. | | `CloudflareRunRegistry` | `type` | `CloudflareRunRegistry` | Type contract for cloudflare run registry. | | `CloudflareRunRegistryClient` | `type` | `CloudflareRunRegistryClient` | Client implementation for cloudflare run registry. | | `CloudflareSandboxEnvOptions` | `type` | `CloudflareSandboxEnvOptions` | Configuration options for cloudflare sandbox env. | | `CloudflareSandboxExecResult` | `type` | `CloudflareSandboxExecResult` | Result returned by cloudflare sandbox exec. | | `CloudflareSandboxFileInfo` | `type` | `CloudflareSandboxFileInfo` | Type contract for cloudflare sandbox file info. | | `CloudflareSandboxLike` | `type` | `CloudflareSandboxLike` | Type contract for cloudflare sandbox like. | | `CloudflareSandboxProcessLike` | `type` | `CloudflareSandboxProcessLike` | Type contract for cloudflare sandbox process like. | | `CloudflareScheduleCoordinator` | `type` | `CloudflareScheduleCoordinator` | Type contract for cloudflare schedule coordinator. | | `CloudflareScheduleCoordinatorOptions` | `type` | `CloudflareScheduleCoordinatorOptions` | Configuration options for cloudflare schedule coordinator. | | `CloudflareScheduledController` | `type` | `CloudflareScheduledController` | Type contract for cloudflare scheduled controller. | | `CloudflareScheduledJob` | `type` | `CloudflareScheduledJob` | Type contract for cloudflare scheduled job. | | `CloudflareScheduleError` | `value` | `typeof CloudflareScheduleError` | Error raised for cloudflare schedule failures. | | `cloudflareScheduleIdempotencyKey` | `value` | `(job: string, expression: string, scheduledTime: number) => string` | Runtime API for cloudflare schedule idempotency key; the generated signature shows its accepted inputs and return type. | | `CloudflareScheduleInput` | `type` | `CloudflareScheduleInput` | Type contract for cloudflare schedule input. | | `cloudflareScheduleMessage` | `value` | `(schedule: CloudflareInstanceSchedule) => DeliveredMessage` | Render the signal message a scheduled wake-up delivers into the agent's session. | | `createCloudflareCronHandler` | `value` | `<TEnv = unknown>(options: CloudflareCronHandlerOptions<TEnv>) => (controller: CloudflareScheduledController, env: TEnv, context: CloudflareExecutionContextLike) => Promise<JobInvocationReceipt[]>` | Build a Cloudflare `scheduled()` handler that admits matching jobs through the finite-run seam. | | `createCloudflareDurableObjectHost` | `value` | `(options: CloudflareDurableObjectHostOptions) => CloudflareDurableObjectHost` | Compose the generated worker's per-instance Durable Object runtime as one helper. | | `createCloudflareDurableObjectSessionStore` | `value` | `(sql: CloudflareDurableObjectSqlStorage, options?: CloudflareDurableObjectSessionStoreOptions) => SessionStore` | Minimal Durable Object SQL-backed SessionStore used by the Cloudflare build target. It intentionally depends only on the small SQL shape exposed by Workers Durable Objects so Cloudflare SDK types do not leak into the SDK. | | `createCloudflareDurablePersistenceStores` | `value` | `(sql: CloudflareDurableObjectSqlStorage) => CloudflareDurablePersistenceStores` | Durable Object SQLite stores for the v2 submission and stream lifecycle. | | `createCloudflareRunRegistry` | `value` | `(sql: CloudflareDurableObjectSqlStorage) => CloudflareRunRegistry` | Tenant-aware cross-Durable-Object index for finite job runs. Per-run Durable Objects remain authoritative. This index only stores the fields needed for discovery, so a registry outage cannot corrupt a run. | | `createCloudflareRunRegistryClient` | `value` | `(namespace: CloudflareDurableObjectNamespaceLike \| undefined) => CloudflareRunRegistryClient \| undefined` | Creates cloudflare run registry client. | | `createCloudflareRunStore` | `value` | `(sql: CloudflareDurableObjectSqlStorage) => RunStore` | Cloudflare Durable Object SQL-backed RunStore for workflow events. Enforces append-only semantics via a `UNIQUE(run_id, event_index)` primary key on the `fabric_harness_workflow_events` table. Duplicate event indexes for the same runId are rejected at the storage layer. A `BEFORE INSERT` trigger on `fabric_harness_runs` deletes existing events when a run is reset with the same id (same-ID reset behaviour). | | `createCloudflareSandboxEnv` | `value` | `(sandbox: CloudflareSandboxLike, options?: CloudflareSandboxEnvOptions) => SandboxEnv` | Adapt an instance returned by `getSandbox(env.Sandbox, id)` from `@cloudflare/sandbox` into Fabric's provider-neutral SandboxEnv contract. | | `createCloudflareScheduleCoordinator` | `value` | `(sql: CloudflareDurableObjectSqlStorage, alarm: CloudflareAlarmSchedulerLike, options?: CloudflareScheduleCoordinatorOptions) => CloudflareScheduleCoordinator` | Creates cloudflare schedule coordinator. | | `defineCloudflareAgent` | `value` | `<TInput = JsonObject, TOutput = unknown>(options?: DefineCloudflareAgentOptions<TInput, TOutput>) => DefinedAgent<TInput, TOutput>` | Defines cloudflare agent. | | `DefineCloudflareAgentOptions` | `type` | `DefineCloudflareAgentOptions<TInput, TOutput>` | Configuration options for define cloudflare agent. | | `extend` | `value` | `(extension: CloudflareExtension) => CloudflareExtension` | Runtime API for extend; the generated signature shows its accepted inputs and return type. | | `ExtensionClass` | `type` | `ExtensionClass` | Type contract for extension class. | | `handleCloudflareRunRegistryRequest` | `value` | `(registry: CloudflareRunRegistry, request: Request) => Promise<Response>` | Handle the private protocol used between the generated Worker and registry DO. | | `MockCloudflareModelProvider` | `value` | `typeof MockCloudflareModelProvider` | A deterministic `ModelProvider` for Cloudflare agent tests and init templates. Returns structured responses without requiring real Cloudflare credentials. | | `MockCloudflareModelProviderOptions` | `type` | `MockCloudflareModelProviderOptions` | Configuration options for mock cloudflare model provider. | | `parseCloudflareInstanceObjectName` | `value` | `(name: string) => { agent: string; id: string; } \| undefined` | Split a session Durable Object name (`<agent>:<instanceId>`, the routing convention used by the generated Cloudflare worker) back into its parts. The instance id may itself contain colons; the agent name may not. | | `r2FilesystemSource` | `value` | `(bucket: CloudflareR2BucketLike, options?: R2FilesystemSourceOptions) => FilesystemSource` | Read Cloudflare R2 objects as a Fabric filesystem source. Mount it with `withFilesystemSources()` so support agents can grep/read R2-backed knowledge bases through the normal sandbox tools. | | `R2FilesystemSourceOptions` | `type` | `R2FilesystemSourceOptions` | Configuration options for r2 filesystem source. | | `registerCloudflareSandboxRefDecoder` | `value` | `(connect: (data: { id: string; }) => Promise<CloudflareSandboxLike> \| CloudflareSandboxLike) => void` | Register cross-process/Worker attachment for Cloudflare Sandbox IDs. | | `resolveCloudflareExtension` | `value` | `(mod: Record<string, unknown>, name: string, kind: "Agent" \| "Workflow") => ResolvedCloudflareExtension` | Resolves cloudflare extension. | | `ResolvedCloudflareExtension` | `type` | `ResolvedCloudflareExtension` | Type contract for resolved cloudflare extension. | | `resolveToolRefs` | `value` | `(bundle: CloudflareBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | ### `@fabric-harness/cloudflare/agent` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `defineCloudflareAgent` | `value` | `<TInput = JsonObject, TOutput = unknown>(options?: DefineCloudflareAgentOptions<TInput, TOutput>) => DefinedAgent<TInput, TOutput>` | Defines cloudflare agent. | | `DefineCloudflareAgentOptions` | `type` | `DefineCloudflareAgentOptions<TInput, TOutput>` | Configuration options for define cloudflare agent. | | `resolveToolRefs` | `value` | `(bundle: CloudflareBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | ### `@fabric-harness/cloudflare/workers-ai` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `BUILTIN_WORKERS_AI_MODEL_INFO` | `value` | `Record<string, CloudflareWorkersAIModelInfo>` | Constant defining builtin workers ai model info. | | `CLOUDFLARE_WORKERS_AI_MODEL_PREFIX` | `value` | `"cloudflare/"` | Reserved model-string prefix that routes through the Workers AI binding provider. `init({ model: 'cloudflare/@cf/meta/llama-3.1-8b-instruct' })` picks this provider when one is registered with the matching name. | | `CloudflareWorkersAIBindingLike` | `type` | `CloudflareWorkersAIBindingLike` | Structural shape of Cloudflare Workers' AI binding (`env.AI`). The real `Ai` type lives in `@cloudflare/workers-types`; we accept a narrower structural type so this package doesn't peer-dep `workers-types`. The `run()` method accepts the OpenAI Chat Completions request body and returns an OpenAI-shaped response when `stream: false` is passed. | | `CloudflareWorkersAIGatewayOptions` | `type` | `CloudflareWorkersAIGatewayOptions` | Configuration options for cloudflare workers aigateway. | | `CloudflareWorkersAIModelInfo` | `type` | `CloudflareWorkersAIModelInfo` | Type contract for cloudflare workers aimodel info. | | `CloudflareWorkersAIModelProvider` | `value` | `typeof CloudflareWorkersAIModelProvider` | Model provider that dispatches to Cloudflare Workers AI via the platform binding (`env.AI.run()`) instead of HTTP. Use on a Cloudflare Workers deployment to skip API tokens, gain Workers-AI-native rate limiting, and keep inference inside Cloudflare's network. Workers AI accepts the OpenAI Chat Completions request body verbatim, so we serialize through the SDK's `toOpenAIMessage`/`toOpenAITool` helpers and parse the binding's response with `openAIChatCompletionToModelResponse`. See the package declarations for an example. Pair with the `cloudflare/` model prefix to make routing explicit when... | | `CloudflareWorkersAIModelProviderOptions` | `type` | `CloudflareWorkersAIModelProviderOptions` | Configuration options for cloudflare workers aimodel provider. | | `mapReasoningEffort` | `value` | `(level: Exclude<ThinkingLevel, "off">) => WorkersAIReasoningEffort` | Map Fabric's ordinal `ThinkingLevel` to Cloudflare's shared `reasoning_effort` option: `minimal`/`low` → `low`, `medium` → `medium`, `high`/`xhigh` → `high`. `'off'` is handled by the caller (the field is omitted) and never reaches this function. | | `stripCloudflarePrefix` | `value` | `(model: string) => string` | Strip the `cloudflare/` routing prefix from a model id, leaving the raw Workers AI model id (e.g. `@cf/meta/llama-3.1-8b-instruct`). | | `WorkersAIReasoningEffort` | `type` | `WorkersAIReasoningEffort` | Cloudflare Workers AI reasoning-effort wire values. | ### `@fabric-harness/cloudflare/computer` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `CLOUDFLARE_COMPUTER_DEFAULT_CWD` | `value` | `"/workspace"` | Constant defining cloudflare computer default cwd. | | `CloudflareComputerContext` | `type` | `CloudflareComputerContext` | Type contract for cloudflare computer context. | | `CloudflareComputerSandboxEnv` | `type` | `CloudflareComputerSandboxEnv` | Type contract for cloudflare computer sandbox env. | | `CloudflareComputerSandboxOptions` | `type` | `CloudflareComputerSandboxOptions` | Configuration options for cloudflare computer sandbox. | | `CloudflareComputerWorkerLoaderLike` | `type` | `CloudflareComputerWorkerLoaderLike` | Type contract for cloudflare computer worker loader like. | | `cloudflareComputerWorkspace` | `value` | `(sandbox: SandboxEnv) => Workspace` | Runtime API for cloudflare computer workspace; the generated signature shows its accepted inputs and return type. | | `createCloudflareComputerSandboxEnv` | `value` | `(workspace: Workspace, options?: { cwd?: string; portableId?: string; }) => CloudflareComputerSandboxEnv` | Creates cloudflare computer sandbox env. | | `getCloudflareComputerContext` | `value` | `() => CloudflareComputerContext` | Returns cloudflare computer context. | | `getCloudflareComputerSandbox` | `value` | `(options?: CloudflareComputerSandboxOptions) => Promise<{ sandbox: CloudflareComputerSandboxEnv; tools: []; }>` | Returns cloudflare computer sandbox. | | `getCloudflareComputerWorkspaceStub` | `value` | `(id: string) => Promise<import("@cloudflare/computer").WorkspaceStub>` | RPC endpoint used by Computer's WorkspaceServiceProxy and worker shell. | | `getDefaultCloudflareComputerWorkspace` | `value` | `(options?: GetDefaultCloudflareComputerWorkspaceOptions) => Workspace` | Return the memoized Computer workspace hosted by the current Durable Object. The wiring intentionally follows Cloudflare Computer's worker-shell topology: SQLite DO storage, a loopback WorkspaceServiceProxy, and the typed git client. | | `GetDefaultCloudflareComputerWorkspaceOptions` | `type` | `GetDefaultCloudflareComputerWorkspaceOptions` | Configuration options for get default cloudflare computer workspace. | | `runWithCloudflareComputerContext` | `value` | `<T>(context: CloudflareComputerContext, fn: () => T) => T` | Register the current Durable Object as the host for its Computer workspace. | | `Workspace` | `value` | `typeof Workspace` | Runtime API for workspace; the generated signature shows its accepted inputs and return type. | | `WorkspaceOptions` | `type` | `WorkspaceOptions` | Configuration options for workspace. | | `WorkspaceServiceProxy` | `value` | `typeof WorkspaceServiceProxy` | Runtime API for workspace service proxy; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/cloudflare/shell` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `CloudflareShellCodeExecutorLike` | `type` | `CloudflareShellCodeExecutorLike` | Type contract for cloudflare shell code executor like. | | `CloudflareShellCodeInput` | `type` | `CloudflareShellCodeInput` | Type contract for cloudflare shell code input. | | `CloudflareShellCodeToolOptions` | `type` | `CloudflareShellCodeToolOptions` | Configuration options for cloudflare shell code tool. | | `CloudflareShellContext` | `type` | `CloudflareShellContext` | Type contract for cloudflare shell context. | | `CloudflareShellWorkspaceSandbox` | `type` | `CloudflareShellWorkspaceSandbox` | Sandbox adapter for cloudflare shell workspace. | | `CloudflareShellWorkspaceSandboxOptions` | `type` | `CloudflareShellWorkspaceSandboxOptions` | Configuration options for cloudflare shell workspace sandbox. | | `CloudflareWorkerLoaderLike` | `type` | `CloudflareWorkerLoaderLike` | Type contract for cloudflare worker loader like. | | `createCloudflareShellCodeTool` | `value` | `(options: CloudflareShellCodeToolOptions) => Promise<ToolDef<CloudflareShellCodeInput, string>>` | Creates cloudflare shell code tool. | | `createCloudflareShellCodeToolFromExecutor` | `value` | `(executor: CloudflareShellCodeExecutorLike, stateProvider: ResolvedProvider, options?: { stateTypes?: string; }) => ToolDef<CloudflareShellCodeInput, string>` | Creates cloudflare shell code tool from executor. | | `createCloudflareShellWorkspaceSandboxEnv` | `value` | `(workspace: Workspace, options?: { cwd?: string; portableId?: string; }) => Promise<SandboxEnv>` | Creates cloudflare shell workspace sandbox env. | | `getCloudflareShellContext` | `value` | `() => CloudflareShellContext` | Returns cloudflare shell context. | | `getCloudflareShellWorkspaceSandbox` | `value` | `(options: CloudflareShellWorkspaceSandboxOptions) => Promise<CloudflareShellWorkspaceSandbox>` | Returns cloudflare shell workspace sandbox. | | `getDefaultCloudflareWorkspace` | `value` | `(options?: GetDefaultCloudflareWorkspaceOptions) => Promise<Workspace>` | Construct the default | | `GetDefaultCloudflareWorkspaceOptions` | `type` | `GetDefaultCloudflareWorkspaceOptions` | Configuration options for get default cloudflare workspace. | | `hydrateCloudflareWorkspaceFromR2` | `value` | `(workspace: Pick<Workspace, "writeFileBytes">, bucket: Pick<CloudflareR2BucketLike, "list" \| "get">, options?: HydrateCloudflareWorkspaceFromR2Options) => Promise<void>` | Eagerly copy R2 objects into a | | `HydrateCloudflareWorkspaceFromR2Options` | `type` | `HydrateCloudflareWorkspaceFromR2Options` | Configuration options for hydrate cloudflare workspace from r2. | | `registerCloudflareShellWorkspaceRefDecoder` | `value` | `(connect: (data: { workspaceId: string; }) => Promise<Workspace> \| Workspace) => void` | Register attachment for a durable Cloudflare Shell workspace routing ID. | | `runWithCloudflareShellContext` | `value` | `<T>(context: CloudflareShellContext, fn: () => T) => T` | Runs with cloudflare shell context. | ### `@fabric-harness/cloudflare/scheduled` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `CloudflareCronHandlerOptions` | `type` | `CloudflareCronHandlerOptions<TEnv>` | Configuration options for cloudflare cron handler. | | `CloudflareExecutionContextLike` | `type` | `CloudflareExecutionContextLike` | Type contract for cloudflare execution context like. | | `CloudflareScheduledController` | `type` | `CloudflareScheduledController` | Type contract for cloudflare scheduled controller. | | `CloudflareScheduledJob` | `type` | `CloudflareScheduledJob` | Type contract for cloudflare scheduled job. | | `cloudflareScheduleIdempotencyKey` | `value` | `(job: string, expression: string, scheduledTime: number) => string` | Runtime API for cloudflare schedule idempotency key; the generated signature shows its accepted inputs and return type. | | `createCloudflareCronHandler` | `value` | `<TEnv = unknown>(options: CloudflareCronHandlerOptions<TEnv>) => (controller: CloudflareScheduledController, env: TEnv, context: CloudflareExecutionContextLike) => Promise<JobInvocationReceipt[]>` | Build a Cloudflare `scheduled()` handler that admits matching jobs through the finite-run seam. | ### `@fabric-harness/cloudflare/schedule` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `CLOUDFLARE_SCHEDULE_SIGNAL_TYPE` | `value` | `"schedule"` | Signal `type` of the delivered message produced by a scheduled wake-up. | | `CloudflareAlarmSchedulerLike` | `type` | `CloudflareAlarmSchedulerLike` | The Durable Object storage alarm surface (`ctx.storage`) this module needs. | | `CloudflareInstanceSchedule` | `type` | `CloudflareInstanceSchedule` | A durable per-instance schedule row. | | `CloudflareScheduleCoordinator` | `type` | `CloudflareScheduleCoordinator` | Type contract for cloudflare schedule coordinator. | | `CloudflareScheduleCoordinatorOptions` | `type` | `CloudflareScheduleCoordinatorOptions` | Configuration options for cloudflare schedule coordinator. | | `CloudflareScheduleError` | `value` | `typeof CloudflareScheduleError` | Error raised for cloudflare schedule failures. | | `CloudflareScheduleInput` | `type` | `CloudflareScheduleInput` | Type contract for cloudflare schedule input. | | `cloudflareScheduleMessage` | `value` | `(schedule: CloudflareInstanceSchedule) => DeliveredMessage` | Render the signal message a scheduled wake-up delivers into the agent's session. | | `createCloudflareScheduleCoordinator` | `value` | `(sql: CloudflareDurableObjectSqlStorage, alarm: CloudflareAlarmSchedulerLike, options?: CloudflareScheduleCoordinatorOptions) => CloudflareScheduleCoordinator` | Creates cloudflare schedule coordinator. | | `parseCloudflareInstanceObjectName` | `value` | `(name: string) => { agent: string; id: string; } \| undefined` | Split a session Durable Object name (`<agent>:<instanceId>`, the routing convention used by the generated Cloudflare worker) back into its parts. The instance id may itself contain colons; the agent name may not. | ### `@fabric-harness/cloudflare/persistence` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `CloudflareDurablePersistenceStores` | `type` | `CloudflareDurablePersistenceStores` | Type contract for cloudflare durable persistence stores. | | `createCloudflareDurablePersistenceStores` | `value` | `(sql: CloudflareDurableObjectSqlStorage) => CloudflareDurablePersistenceStores` | Durable Object SQLite stores for the v2 submission and stream lifecycle. | ## @fabric-harness/connectors ### `@fabric-harness/connectors` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `assertRetainableSandboxCertification` | `value` | `(report: SandboxCertificationReport, expectation: RetainedSandboxCertificationExpectation) => SandboxCertificationReport` | Fail closed before a credentialed report is retained as release evidence. | | `assertSandboxCertification` | `value` | `(env: SandboxEnv, options: SandboxCertificationOptions) => Promise<SandboxCertificationReport>` | Validates sandbox certification and throws when the requirement is not met. | | `AzureBlobBodyLike` | `type` | `AzureBlobBodyLike` | Type contract for azure blob body like. | | `AzureBlobFilesystemClientLike` | `type` | `AzureBlobFilesystemClientLike` | Type contract for azure blob filesystem client like. | | `azureBlobFilesystemSource` | `value` | `(client: AzureBlobFilesystemClientLike, options?: ObjectStorageFilesystemSourceOptions) => FilesystemSource` | Data or filesystem source for azure blob filesystem. | | `AzureBlobListResultLike` | `type` | `AzureBlobListResultLike` | Type contract for azure blob list result like. | | `certifySandboxAdapter` | `value` | `(env: SandboxEnv, options: SandboxCertificationOptions) => Promise<SandboxCertificationReport>` | Exercise the portable Fabric sandbox contract and return secret-free, machine-readable evidence suitable for a CI artifact. | | `daytonaSandbox` | `value` | `(sandbox: DaytonaSandboxLike, options?: DaytonaSandboxOptions) => SandboxEnv` | Sandbox adapter for daytona. | | `daytonaSandboxFactory` | `value` | `(sandbox: DaytonaSandboxLike, options?: DaytonaSandboxOptions) => Promise<SandboxFactory>` | Factory for daytona sandbox. | | `DaytonaSandboxLike` | `type` | `DaytonaSandboxLike` | Type contract for daytona sandbox like. | | `DaytonaSandboxOptions` | `type` | `DaytonaSandboxOptions` | Configuration options for daytona sandbox. | | `e2bSandbox` | `value` | `(sandbox: E2BSandboxLike, options?: RemoteAdapterOptions) => SandboxEnv` | Sandbox adapter for e2b. | | `E2BSandboxLike` | `type` | `E2BSandboxLike` | Type contract for e2 bsandbox like. | | `FilesystemSource` | `type` | `FilesystemSource` | A read-only content source that can be mounted into a sandbox at sandbox-creation time. The agent then has built-in `read`, `glob`, and `grep` tools available over the mounted content — no retrieval pipeline, no embeddings, no vector store required. Sources are intentionally minimal: they yield (path, content) pairs. Implementations decide how to enumerate (eager vs lazy is up to the source author) — the mount step pulls the full set into the sandbox. | | `ModalFileInfoLike` | `type` | `ModalFileInfoLike` | Type contract for modal file info like. | | `ModalFilesystemLike` | `type` | `ModalFilesystemLike` | Type contract for modal filesystem like. | | `ModalProcessLike` | `type` | `ModalProcessLike` | Type contract for modal process like. | | `ModalReadStreamLike` | `type` | `ModalReadStreamLike<T>` | Type contract for modal read stream like. | | `modalSandbox` | `value` | `(sandbox: ModalSandboxLike, options?: RemoteAdapterOptions) => SandboxEnv` | Sandbox adapter for modal. | | `ModalSandboxLike` | `type` | `ModalSandboxLike` | Type contract for modal sandbox like. | | `modalSdkSandbox` | `value` | `(sandbox: ModalSdkSandboxLike, options?: ModalSdkSandboxOptions) => SandboxEnv` | Adapt a native Modal TypeScript SDK `Sandbox` without exposing credentials to the Fabric runtime or model context. | | `ModalSdkSandboxLike` | `type` | `ModalSdkSandboxLike` | Structural subset implemented by `modal` 0.9 `Sandbox`. | | `ModalSdkSandboxOptions` | `type` | `ModalSdkSandboxOptions` | Configuration options for modal sdk sandbox. | | `ObjectStorageFilesystemSourceOptions` | `type` | `ObjectStorageFilesystemSourceOptions` | Configuration options for object storage filesystem source. | | `ProviderCleanupOptions` | `type` | `ProviderCleanupOptions` | Configuration options for provider cleanup. | | `RemoteAdapterOptions` | `type` | `RemoteAdapterOptions` | Configuration options for remote adapter. | | `remoteSandbox` | `value` | `(api: RemoteSandboxApi, options?: RemoteSandboxConnectorOptions) => SandboxFactory` | Dependency-free structural connector for provider-owned remote sandboxes. Provider-specific packages can keep their SDK/client types private and map them to RemoteSandboxApi, then return this SandboxFactory. Credentials stay in the provider client and are never serialized into Fabric session history. | | `RemoteSandboxApi` | `type` | `RemoteSandboxApi` | Type contract for remote sandbox api. | | `RemoteSandboxConnectorOptions` | `type` | `RemoteSandboxConnectorOptions` | Configuration options for remote sandbox connector. | | `remoteSandboxEnv` | `value` | `(api: RemoteSandboxApi, options?: RemoteAdapterOptions) => SandboxEnv` | Runtime API for remote sandbox env; the generated signature shows its accepted inputs and return type. | | `RemoteSandboxOptions` | `type` | `RemoteSandboxOptions` | Configuration options for remote sandbox. | | `RetainedSandboxCertificationExpectation` | `type` | `RetainedSandboxCertificationExpectation` | Type contract for retained sandbox certification expectation. | | `S3FilesystemClientLike` | `type` | `S3FilesystemClientLike` | Type contract for s3 filesystem client like. | | `s3FilesystemSource` | `value` | `(client: S3FilesystemClientLike, options?: ObjectStorageFilesystemSourceOptions) => FilesystemSource` | Data or filesystem source for s3 filesystem. | | `S3ObjectBodyLike` | `type` | `S3ObjectBodyLike` | Type contract for s3 object body like. | | `S3ObjectListResultLike` | `type` | `S3ObjectListResultLike` | Type contract for s3 object list result like. | | `SANDBOX_CERTIFICATION_CHECKS` | `value` | `readonly SandboxCertificationCheckName[]` | Constant defining sandbox certification checks. | | `SANDBOX_PROVIDER_COMPATIBILITY` | `value` | `{ readonly daytona: { readonly package: "@daytona/sdk"; readonly range: ">=0.195.0 <1"; readonly supportedMajors: readonly [0]; readonly tested: readonly ["0.195.0"]; }; readonly e2b: { readonly package: "@e2b/code-interpreter"; readonly range: ">=...` | Constant defining sandbox provider compatibility. | | `SandboxAdapterValidationOptions` | `type` | `SandboxAdapterValidationOptions` | Configuration options for sandbox adapter validation. | | `SandboxAdapterValidationResult` | `type` | `SandboxAdapterValidationResult` | Result returned by sandbox adapter validation. | | `SandboxCertificationCheck` | `type` | `SandboxCertificationCheck` | Type contract for sandbox certification check. | | `SandboxCertificationCheckName` | `type` | `SandboxCertificationCheckName` | Type contract for sandbox certification check name. | | `SandboxCertificationError` | `value` | `typeof SandboxCertificationError` | Error raised for sandbox certification failures. | | `SandboxCertificationOptions` | `type` | `SandboxCertificationOptions` | Configuration options for sandbox certification. | | `SandboxCertificationReport` | `type` | `SandboxCertificationReport` | Type contract for sandbox certification report. | | `SandboxFactory` | `type` | `SandboxFactory` | Factory for sandbox. | | `validateSandboxAdapter` | `value` | `(env: SandboxEnv, options?: SandboxAdapterValidationOptions) => Promise<SandboxAdapterValidationResult>` | Runtime API for validate sandbox adapter; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/connectors/s3` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `s3Source` | `value` | `(options: S3SourceOptions) => FilesystemSource` | Read-only S3 connector. Mount with `session.mount(mountAt, s3Source(...))`. The agent's built-in `read`, `grep`, `glob`, and `bash` tools then operate over the mounted prefix as if it were a local directory. | | `S3SourceOptions` | `type` | `S3SourceOptions` | Concrete S3 connector backed by `@aws-sdk/client-s3`. Users pass bucket config; this module constructs the SDK client internally and adapts it to TechFabric Harness's `FilesystemSource` contract. Install peer dep: ```sh npm install | | `s3Writer` | `value` | `(options: S3WriterOptions) => S3Writer` | Writer implementation for s3. | | `S3Writer` | `type` | `S3Writer` | Writer implementation for s3. | | `S3WriterOptions` | `type` | `S3WriterOptions` | Write-side helper for S3. Use to publish artifacts or mount a writable view. See the package declarations for an example. | ### `@fabric-harness/connectors/azure-blob` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `azureBlobSource` | `value` | `(options: AzureBlobSourceOptions) => FilesystemSource` | Data or filesystem source for azure blob. | | `AzureBlobSourceOptions` | `type` | `AzureBlobSourceOptions` | Concrete Azure Blob connector backed by `@azure/storage-blob`. Install peer deps: ```sh npm install | | `azureBlobWriter` | `value` | `(options: AzureBlobWriterOptions) => AzureBlobWriter` | Writer implementation for azure blob. | | `AzureBlobWriter` | `type` | `AzureBlobWriter` | Writer implementation for azure blob. | | `AzureBlobWriterOptions` | `type` | `AzureBlobWriterOptions` | Configuration options for azure blob writer. | ### `@fabric-harness/connectors/gcs` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `gcsSource` | `value` | `(options: GcsSourceOptions) => FilesystemSource` | Data or filesystem source for gcs. | | `GcsSourceOptions` | `type` | `GcsSourceOptions` | Concrete Google Cloud Storage connector backed by `@google-cloud/storage`. Install peer dep: ```sh npm install | | `gcsWriter` | `value` | `(options: GcsWriterOptions) => GcsWriter` | Writer implementation for gcs. | | `GcsWriter` | `type` | `GcsWriter` | Writer implementation for gcs. | | `GcsWriterOptions` | `type` | `GcsWriterOptions` | Configuration options for gcs writer. | ### `@fabric-harness/connectors/github` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `githubSource` | `value` | `(options: GithubSourceOptions) => FilesystemSource` | Data or filesystem source for github. | | `GithubSourceOptions` | `type` | `GithubSourceOptions` | Read-only GitHub repository connector backed by `octokit`. Mounts a repository (at a given ref) as files inside the sandbox. Uses the Git Trees API in recursive mode for efficient enumeration. Install peer dep: See the package declarations for an example. | ### `@fabric-harness/connectors/databricks-volume` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `databricksVolumeSource` | `value` | `(options: DatabricksVolumeSourceOptions) => FilesystemSource` | Data or filesystem source for databricks volume. | | `DatabricksVolumeSourceOptions` | `type` | `DatabricksVolumeSourceOptions` | Databricks Unity Catalog Volume connector backed by the Files API (`/api/2.0/fs/files/...`). No SDK dependency — uses `fetch` directly. Volume paths are addressed as `/Volumes/<catalog>/<schema>/<volume>/<path>`. Usage: See the package declarations for an example. | | `databricksVolumeWriter` | `value` | `(options: DatabricksVolumeWriterOptions) => DatabricksVolumeWriter` | Writer implementation for databricks volume. | | `DatabricksVolumeWriter` | `type` | `DatabricksVolumeWriter` | Writer implementation for databricks volume. | | `DatabricksVolumeWriterOptions` | `type` | `DatabricksVolumeWriterOptions` | Configuration options for databricks volume writer. | ### `@fabric-harness/connectors/k8s` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createKubernetesEgressNetworkPolicy` | `value` | `(options: KubernetesEgressNetworkPolicyOptions) => KubernetesNetworkPolicyManifest` | Build a deny-by-default Kubernetes egress boundary. Domain filtering belongs in the selected proxy; Kubernetes NetworkPolicy is intentionally limited to DNS, that proxy, and explicit private endpoint CIDRs. | | `createKubernetesPod` | `value` | `(options: CreateKubernetesPodOptions) => KubernetesPodLike` | Creates kubernetes pod. | | `createKubernetesPodFromImage` | `value` | `(options: CreateKubernetesPodFromImageOptions) => Promise<KubernetesPodLike>` | Creates kubernetes pod from image. | | `CreateKubernetesPodFromImageOptions` | `type` | `CreateKubernetesPodFromImageOptions` | Provision an ephemeral pod from an image and return a `KubernetesPodLike` ready for `kubernetesSandbox()`. Works against any cluster reachable via the resolved kubeconfig — in-cluster, `$KUBECONFIG`, or `~/.kube/config`. The pod is created with `restartPolicy: Never` and runs `sleep infinity` so it stays attachable. `cleanup()` (when wired via `kubernetesSandbox`'s `cleanup: true`) deletes the pod. For Azure-managed clusters, prefer `aksSandbox()` from `@fabric-harness/azure/aks-sandbox` which adds ARM-resolved kubeconfig. See the package declarations for an example. | | `CreateKubernetesPodOptions` | `type` | `CreateKubernetesPodOptions` | Convenience helper: build a `KubernetesPodLike` from a `@kubernetes/client-node` `KubeConfig` plus pod identity. Suitable when `kubectl` already gets you in the door — for AKS, prefer `aksSandbox()` from `@fabric-harness/azure`. Files are transferred over `exec` using base64-encoded `cat` / `tee`. Works for text and small binaries; for large objects mount external storage via `s3Source` / `gcsSource` / `azureBlobSource` instead. | | `KubernetesEgressNetworkPolicyOptions` | `type` | `KubernetesEgressNetworkPolicyOptions` | Configuration options for kubernetes egress network policy. | | `KubernetesNetworkPolicyManifest` | `type` | `KubernetesNetworkPolicyManifest` | Type contract for kubernetes network policy manifest. | | `KubernetesPodLike` | `type` | `KubernetesPodLike` | Structural Kubernetes pod adapter. The caller wires up `@kubernetes/client-node` (or any SPDY/exec-capable client) and supplies an object that satisfies `KubernetesPodLike`. Why structural: cluster auth, RBAC, and the exec wire format vary too much across environments (in-cluster, kubeconfig, AKS managed identity, GKE Workload Identity, EKS IRSA, …) for a single concrete adapter to be sensible. Pattern matches `daytonaSandbox` / `e2bSandbox`. For Azure-hosted clusters use the higher-level `aksSandbox()` from `@fabric-harness/azure`, which wires this adapter to Azure-managed credentials. | | `kubernetesSandbox` | `value` | `(pod: KubernetesPodLike, options?: KubernetesSandboxOptions) => SandboxEnv` | Sandbox adapter for kubernetes. | | `KubernetesSandboxOptions` | `type` | `KubernetesSandboxOptions` | Configuration options for kubernetes sandbox. | ### `@fabric-harness/connectors/vercel` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `vercelSandbox` | `value` | `(sandbox: VercelSandboxLike, options?: VercelSandboxOptions) => SandboxEnv` | Wrap a Vercel Sandbox instance as a TechFabric Harness `SandboxEnv`. The sandbox's filesystem and shell exec are mapped to the fabric contract; `cleanup: true` calls `sandbox.stop()` when the Fabric session tears down. See the package declarations for an example. Vercel's `runCommand` accepts cwd, env, AbortSignal, and output streams. Fabric maps its millisecond timeout to an AbortSignal and resolves the command object's async `stdout()`/`stderr()` methods used by SDK 1.x. | | `vercelSandboxFactory` | `value` | `(create: () => Promise<VercelSandboxLike> \| VercelSandboxLike, options?: VercelSandboxOptions) => SandboxFactory` | Convenience factory that returns a `SandboxFactory`, suitable for `init({ sandbox: vercelSandboxFactory(...) })`. Provisions a fresh sandbox on first use via the supplied `create()` callback. | | `VercelSandboxLike` | `type` | `VercelSandboxLike` | Structural shape of `@vercel/sandbox`'s `Sandbox` instance, kept narrow so this package doesn't peer-dep on `@vercel/sandbox` directly. Pass any object satisfying this contract — the real `Sandbox` from `@vercel/sandbox` does. See https://vercel.com/docs/vercel-sandbox/sdk-reference for the upstream API. This adapter targets the post-GA shape (`runCommand`, `fs.*`). | | `VercelSandboxOptions` | `type` | `VercelSandboxOptions` | Configuration options for vercel sandbox. | ### `@fabric-harness/connectors/modal` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `ModalFileInfoLike` | `type` | `ModalFileInfoLike` | Type contract for modal file info like. | | `ModalFilesystemLike` | `type` | `ModalFilesystemLike` | Type contract for modal filesystem like. | | `ModalProcessLike` | `type` | `ModalProcessLike` | Type contract for modal process like. | | `ModalReadStreamLike` | `type` | `ModalReadStreamLike<T>` | Type contract for modal read stream like. | | `modalSdkSandbox` | `value` | `(sandbox: ModalSdkSandboxLike, options?: ModalSdkSandboxOptions) => SandboxEnv` | Adapt a native Modal TypeScript SDK `Sandbox` without exposing credentials to the Fabric runtime or model context. | | `ModalSdkSandboxLike` | `type` | `ModalSdkSandboxLike` | Structural subset implemented by `modal` 0.9 `Sandbox`. | | `ModalSdkSandboxOptions` | `type` | `ModalSdkSandboxOptions` | Configuration options for modal sdk sandbox. | ### `@fabric-harness/connectors/sandbox-refs` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `RegisterStandardDecodersOptions` | `type` | `RegisterStandardDecodersOptions` | Standard cross-process sandbox-ref decoders for the connectors that ship here. Call this once at startup in any process that needs to attach to sandboxes encoded by `session.sandboxRef({ portable: true })`. Each `connect*` callback is responsible for hydrating a provider-native client object from `providerData`; the connectors package wraps that client in a `SandboxEnv` exactly the way the upstream factory functions do (`daytonaSandbox`, `e2bSandbox`, `modalSandbox`, `kubernetesSandbox`). See the package declarations for an example. | | `registerStandardSandboxRefDecoders` | `value` | `(options: RegisterStandardDecodersOptions) => void` | Registers standard sandbox ref decoders. | ### `@fabric-harness/connectors/sandbox-certification` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `assertRetainableSandboxCertification` | `value` | `(report: SandboxCertificationReport, expectation: RetainedSandboxCertificationExpectation) => SandboxCertificationReport` | Fail closed before a credentialed report is retained as release evidence. | | `assertSandboxCertification` | `value` | `(env: SandboxEnv, options: SandboxCertificationOptions) => Promise<SandboxCertificationReport>` | Validates sandbox certification and throws when the requirement is not met. | | `certifySandboxAdapter` | `value` | `(env: SandboxEnv, options: SandboxCertificationOptions) => Promise<SandboxCertificationReport>` | Exercise the portable Fabric sandbox contract and return secret-free, machine-readable evidence suitable for a CI artifact. | | `RetainedSandboxCertificationExpectation` | `type` | `RetainedSandboxCertificationExpectation` | Type contract for retained sandbox certification expectation. | | `SANDBOX_CERTIFICATION_CHECKS` | `value` | `readonly SandboxCertificationCheckName[]` | Constant defining sandbox certification checks. | | `SandboxCertificationCheck` | `type` | `SandboxCertificationCheck` | Type contract for sandbox certification check. | | `SandboxCertificationCheckName` | `type` | `SandboxCertificationCheckName` | Type contract for sandbox certification check name. | | `SandboxCertificationError` | `value` | `typeof SandboxCertificationError` | Error raised for sandbox certification failures. | | `SandboxCertificationOptions` | `type` | `SandboxCertificationOptions` | Configuration options for sandbox certification. | | `SandboxCertificationReport` | `type` | `SandboxCertificationReport` | Type contract for sandbox certification report. | ## @fabric-harness/databases ### `@fabric-harness/databases` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `assertReadOnlyStatement` | `value` | `(statement: string) => void` | Validates read only statement and throws when the requirement is not met. | | `governedDatabaseTool` | `value` | `<TInput, TOutput>(options: GovernedDatabaseToolOptions<TInput, TOutput>) => ToolDef<TInput, TOutput>` | Common database tool boundary: effect metadata, timeout, size cap, and redacted failures. | | `GovernedDatabaseToolOptions` | `type` | `GovernedDatabaseToolOptions<TInput, TOutput>` | Configuration options for governed database tool. | | `MongoCollectionLike` | `type` | `MongoCollectionLike<T>` | Type contract for mongo collection like. | | `MongoCursorLike` | `type` | `MongoCursorLike<T>` | Type contract for mongo cursor like. | | `mongoFindTool` | `value` | `<TInput = JsonObject, TDocument = JsonObject>(options: MongoFindToolOptions<TInput, TDocument>) => ToolDef<TInput, { documents: TDocument[]; }>` | Collection-bound find tool. Host code constructs the filter and projection. | | `MongoFindToolOptions` | `type` | `MongoFindToolOptions<TInput, TDocument>` | Configuration options for mongo find tool. | | `MysqlClientLike` | `type` | `MysqlClientLike` | Type contract for mysql client like. | | `mysqlTool` | `value` | `<TInput = JsonObject, TRow = JsonObject>(options: MysqlToolOptions<TInput, TRow>) => ToolDef<TInput, { rows: TRow[]; }>` | Model-callable tool or tool factory for mysql. | | `MysqlToolOptions` | `type` | `MysqlToolOptions<TInput, TRow>` | Configuration options for mysql tool. | | `PostgresClientLike` | `type` | `PostgresClientLike` | Type contract for postgres client like. | | `postgresTool` | `value` | `<TInput = JsonObject, TRow = JsonObject>(options: PostgresToolOptions<TInput, TRow>) => ToolDef<TInput, { rows: TRow[]; rowCount: number; }>` | Fixed-statement Postgres tool. The model supplies values, never SQL text. | | `PostgresToolOptions` | `type` | `PostgresToolOptions<TInput, TRow>` | Configuration options for postgres tool. | | `RedisClientLike` | `type` | `RedisClientLike` | Type contract for redis client like. | | `RedisToolOptions` | `type` | `RedisToolOptions` | Configuration options for redis tool. | | `redisTools` | `value` | `(options: RedisToolOptions) => Array<ToolDef>` | Runtime API for redis tools; the generated signature shows its accepted inputs and return type. | | `SqliteClientLike` | `type` | `SqliteClientLike` | Type contract for sqlite client like. | | `SqliteStatementLike` | `type` | `SqliteStatementLike` | Type contract for sqlite statement like. | | `sqliteTool` | `value` | `<TInput = JsonObject, TRow = JsonObject>(options: SqliteToolOptions<TInput, TRow>) => ToolDef<TInput, { rows?: TRow[]; result?: unknown; }>` | Model-callable tool or tool factory for sqlite. | | `SqliteToolOptions` | `type` | `SqliteToolOptions<TInput, TRow>` | Configuration options for sqlite tool. | ### `@fabric-harness/databases/postgres` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `PostgresClientLike` | `type` | `PostgresClientLike` | Type contract for postgres client like. | | `postgresTool` | `value` | `<TInput = JsonObject, TRow = JsonObject>(options: PostgresToolOptions<TInput, TRow>) => ToolDef<TInput, { rows: TRow[]; rowCount: number; }>` | Fixed-statement Postgres tool. The model supplies values, never SQL text. | | `PostgresToolOptions` | `type` | `PostgresToolOptions<TInput, TRow>` | Configuration options for postgres tool. | ### `@fabric-harness/databases/mysql` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `MysqlClientLike` | `type` | `MysqlClientLike` | Type contract for mysql client like. | | `mysqlTool` | `value` | `<TInput = JsonObject, TRow = JsonObject>(options: MysqlToolOptions<TInput, TRow>) => ToolDef<TInput, { rows: TRow[]; }>` | Model-callable tool or tool factory for mysql. | | `MysqlToolOptions` | `type` | `MysqlToolOptions<TInput, TRow>` | Configuration options for mysql tool. | ### `@fabric-harness/databases/sqlite` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `SqliteClientLike` | `type` | `SqliteClientLike` | Type contract for sqlite client like. | | `SqliteStatementLike` | `type` | `SqliteStatementLike` | Type contract for sqlite statement like. | | `sqliteTool` | `value` | `<TInput = JsonObject, TRow = JsonObject>(options: SqliteToolOptions<TInput, TRow>) => ToolDef<TInput, { rows?: TRow[]; result?: unknown; }>` | Model-callable tool or tool factory for sqlite. | | `SqliteToolOptions` | `type` | `SqliteToolOptions<TInput, TRow>` | Configuration options for sqlite tool. | ### `@fabric-harness/databases/mongodb` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `MongoCollectionLike` | `type` | `MongoCollectionLike<T>` | Type contract for mongo collection like. | | `MongoCursorLike` | `type` | `MongoCursorLike<T>` | Type contract for mongo cursor like. | | `mongoFindTool` | `value` | `<TInput = JsonObject, TDocument = JsonObject>(options: MongoFindToolOptions<TInput, TDocument>) => ToolDef<TInput, { documents: TDocument[]; }>` | Collection-bound find tool. Host code constructs the filter and projection. | | `MongoFindToolOptions` | `type` | `MongoFindToolOptions<TInput, TDocument>` | Configuration options for mongo find tool. | ### `@fabric-harness/databases/redis` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `RedisClientLike` | `type` | `RedisClientLike` | Type contract for redis client like. | | `RedisToolOptions` | `type` | `RedisToolOptions` | Configuration options for redis tool. | | `redisTools` | `value` | `(options: RedisToolOptions) => Array<ToolDef>` | Runtime API for redis tools; the generated signature shows its accepted inputs and return type. | ## @fabric-harness/databricks ### `@fabric-harness/databricks` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `analyticsCopilotGovernance` | `value` | `(options: AnalyticsCopilotGovernanceOptions) => AnalyticsCopilotGovernance` | Governance defaults for the analytics-copilot path. Safe Genie questions and `sql_read` carry a read effect and remain interactive; arbitrary SQL execution and Genie lifecycle tools retain steward approval. Enabling another authoring service with this pack fails bundle initialization until the caller deliberately expands its approval scope. | | `AnalyticsCopilotGovernance` | `type` | `AnalyticsCopilotGovernance` | Type contract for analytics copilot governance. | | `AnalyticsCopilotGovernanceOptions` | `type` | `AnalyticsCopilotGovernanceOptions` | Configuration options for analytics copilot governance. | | `applyModuleOntologyExport` | `value` | `(plan: DatabricksOntologyExportPlan, options: DatabricksOntologyApplyOptions) => Promise<DatabricksOntologyExportResult>` | Apply a deterministic ontology export plan through the governed authoring seams. See the module header for the approval, conflict, SQL-policy, provenance, and no-op contracts. | | `appServicePrincipalFromEnv` | `value` | `(env?: Record<string, string \| undefined>) => Extract<DatabricksPrincipal, { kind: "service-principal"; }> \| undefined` | The service principal a Databricks App runs as, from the standard app runtime environment (`DATABRICKS_HOST` / `DATABRICKS_CLIENT_ID` / `DATABRICKS_CLIENT_SECRET`). Returns `undefined` when any variable is missing, so callers can fall back to explicit configuration. | | `assetEventRecordFromEnvelope` | `value` | `(envelope: AssetEventEnvelope, namespace?: string) => DatabricksOntologyAssetEventRecord` | Map a Platform `AssetEventEnvelope` (`@fabricorg/platform/events`, consumed type-only) onto the feed's asset-event record fields. The envelope `payload` is the vertical's raw event body: it flows to the producer (which owns redaction, including any upcasting — design Q3) and is dropped by the publishable-field allowlist before anything lands. `namespace` is supplied by the caller because the envelope does not carry the module namespace. | | `attestOntologyDrift` | `value` | `(plan: DatabricksOntologyExportPlan, options: DatabricksOntologyDriftAttestationOptions) => Promise<DatabricksOntologyDriftAttestationRecord>` | Read the knowledge store through the injected client, compare it against the declared plan, and append one attestation record routed to steward review (P2-2; design §4 rule 3, §5 append-only audit evidence). Hard invariant: this function performs no write other than the single `evidence.append`. The knowledge-store interface is read-only by construction, and no Genie Agent spec, metric view, glossary, or manifest mutation path exists in this module — drift never auto-applies; re-export stays behind the P0-6 fingerprinted conflict contract. | | `buildMlflowTrace` | `value` | `(input: MlflowTraceInput) => MlflowTracePayload` | Build the MLflow V3 `POST /api/3.0/mlflow/traces` payload for one settled submission. Pure and deterministic: trace/span ids derive from the submission id (+ span index) via SHA-256, so replaying the same settled submission produces byte-identical ids. The root span covers the whole submission; buffered `TelemetrySpan`s become its children. | | `chooseDatabricksSqlWarehouse` | `value` | `(warehouses: readonly DatabricksSqlWarehouse[]) => DatabricksSqlWarehouse \| undefined` | Runtime API for choose databricks sql warehouse; the generated signature shows its accepted inputs and return type. | | `compareOntologyDrift` | `value` | `(input: DatabricksOntologyDriftComparisonInput) => DatabricksOntologyDriftComparison` | Pure declared-vs-inferred comparison (P2-1). No network, no clock, no randomness — the knowledge-store fetch is the caller's concern and is injected; this function runs credential-free against plain data. Matching rules: a synonym maps onto a declared term, an expression onto a declared measure, preferring the concept's `target` over its `name`. A mapped inference whose label collides with a *different* declared entry than its target is a `conflict`; otherwise it is `analytics-only`. An inference with no declared counterpart (including every inferred expert — experts are never declared voca... | | `ConnectDatabricksManagedMcpOptions` | `type` | `ConnectDatabricksManagedMcpOptions` | Configuration options for connect databricks managed mcp. | | `connectDatabricksManagedMcpServer` | `value` | `(options: ConnectDatabricksManagedMcpOptions) => Promise<McpServerConnection>` | Connect to one Databricks managed MCP endpoint with a rotating OBO or service token. Remote tools are classified before they can enter a governed bundle; unknown effects fail closed. | | `ConsumptionGroupBy` | `type` | `ConsumptionGroupBy` | Type contract for consumption group by. | | `ConsumptionSummary` | `type` | `ConsumptionSummary` | Type contract for consumption summary. | | `ConsumptionSummaryOptions` | `type` | `ConsumptionSummaryOptions` | Configuration options for consumption summary. | | `createDatabricksAppUserAuthenticator` | `value` | `(options: DatabricksAppUserAuthenticatorOptions) => (request: { headers: Headers \| Record<string, string \| string[] \| undefined>; }) => Promise<DatabricksAppAuthenticatedPrincipal \| false \| undefined>` | Authenticate Databricks Apps forwarded user tokens and isolate each user by default. Validation calls the workspace current-user API once per token digest; raw tokens are never stored as cache keys or returned to TechFabric Harness. | | `createDatabricksAuthenticatedFetch` | `value` | `(options: DatabricksAuthenticatedFetchOptions) => typeof fetch` | Fetch adapter for third-party SDKs that require a standard fetch surface. A fresh principal token is resolved per attempt and one auth refresh retry is bounded to 401/403. | | `createDatabricksAuthoringCertificationChecks` | `value` | `(fixtures: DatabricksAuthoringCertificationFixtures) => DatabricksCertificationCheck[]` | Creates databricks authoring certification checks. | | `createDatabricksRagChain` | `value` | `(options: DatabricksRagChainResolvedOptions) => DatabricksRagChain` | Thin orchestration of Databricks-native AI Search + Model Serving for the online RAG inference chain documented in the Databricks AI Cookbook. Prefer `databricksRagChain` from the package root when you have a `databricks({ aiSearch })` config — it wires the bundle for you. Does **not** implement offline chunking/indexing (use Databricks Jobs/Lakeflow). Does **not** replace Mosaic Agent Evaluation — export turns with rag-eval helpers. | | `databricks` | `value` | `(config: DatabricksBundleConfig) => DatabricksBundle` | One-call wiring for a Databricks-native agent: model serving, a UC principal threaded through model + data + state, governed tools, an approval/egress policy, and (optionally) Lakebase-backed durable state. Also registers `databricks/*` model refs. Everything is layered on Unity Catalog — never a replacement for it. | | `DATABRICKS_AGENT_SERVICE_SECURABLE` | `value` | `"AGENT_SERVICE"` | Constant defining databricks agent service securable. | | `DATABRICKS_AGENT_SERVICES_API` | `value` | `"/api/2.1/unity-catalog/agent-services"` | Constant defining databricks agent services api. | | `DATABRICKS_API_VERSIONS` | `value` | `{ readonly sdkJs: string; readonly jobs: "2.2"; readonly sqlStatements: "2.0"; readonly unityCatalog: "2.1"; readonly workspace: "2.0"; readonly mlflow: "2.0"; readonly lakebaseCredentials: "2.0"; readonly apps: "2.0"; readonly responses: "agent/v1/responses"; readonly ai...` | Constant defining databricks api versions. | | `DATABRICKS_APP_USER_PERMISSIONS` | `value` | `readonly ["agent:invoke", "approval:read", "approval:write", "artifact:read", "mcp:invoke", "session:abort", "session:delete", "session:read"]` | Constant defining databricks app user permissions. | | `DATABRICKS_AUTH_MODES` | `value` | `readonly [{ readonly mode: "oauth-m2m"; readonly production: true; readonly use: "External services and CI service principals."; }, { readonly mode: "app-service-principal"; readonly production: true; readonly use: "Databricks Apps runtime identity."; }, &#...` | Constant defining databricks auth modes. | | `DATABRICKS_AUTHORING_CERTIFICATION_CHECKS` | `value` | `readonly ["approval-provenance", "jobs-authoring", "lakeflow-authoring", "ai-search-admin", "serving-admin", "uc-admin-obo-execution", "workspace-write", "secrets-write", "genie-authoring"]` | Constant defining databricks authoring certification checks. | | `DATABRICKS_CAPABILITIES` | `value` | `readonly DatabricksCapability[]` | Public capability registry. `contractClouds` describes designed API portability; `clouds` is deliberately narrower and is derived only from retained evidence linked to that capability. | | `DATABRICKS_CAPABILITY_EVIDENCE` | `value` | `readonly DatabricksCapabilityEvidenceReference[]` | Constant defining databricks capability evidence. | | `DATABRICKS_CERTIFICATION_RESOURCE_PREFIX` | `value` | `"fabric-harness-authoring-cert-"` | Constant defining databricks certification resource prefix. | | `DATABRICKS_ONTOLOGY_EXPORT_PLAN_VERSION` | `value` | `"1"` | Durable generation of the module-ontology export plan shape. Bump when the serialized plan changes in a way plan-diff consumers must detect. | | `DATABRICKS_OPTIONAL_CERTIFICATION_CHECKS` | `value` | `readonly ["agent-services", "rag-evaluation", "responses-agent", "ai-search", "genie-agent-mode", "feature-serving", "lakeflow", "jobs", "notebook", "jobs-classic-authoring", "ai-search-delta-sync-admin", "serving-provisioned-throughput-admin"]` | Tier O checks are preview, SKU-specific, or not part of the default product spine. | | `DATABRICKS_PACKAGE_COMPATIBILITY` | `value` | `{ readonly node: ">=22.0.0"; readonly package: "@fabric-harness/databricks"; readonly packageRange: ">=7.0.0 <8"; readonly pg: "^8.11.0 (only for Lakebase)"; }` | Constant defining databricks package compatibility. | | `DATABRICKS_PLATFORM_DOMAINS` | `value` | `readonly DatabricksPlatformDomain[]` | Whole-platform inventory. A domain remains listed even when its current Harness coverage is empty, preventing documentation and release claims from silently omitting native Databricks product families. | | `DATABRICKS_RELEASE_CERTIFICATION_CHECKS` | `value` | `readonly ["identity", "ai-gateway", "sql", "unity-catalog", "uc-denial", "uc-allowed-select", "catalog-preflight-denial", "mutation-approval", "model-serving", "rag", "genie", "managed-mcp", "volumes", "lakebase", "lakebase-app-restart", "dynamic-agent", "lineage", "obo", "sys...` | Tier R checks prove the supported Databricks consumption path. A release certification cannot pass when one of these checks fails or is not configured. | | `DATABRICKS_SDK_VERSION` | `value` | `string` | Exact modular Databricks SDK release used by every generated service client. | | `databricksActualCostSource` | `value` | `(client: DatabricksStatementClient, warehouseId: string, options?: DatabricksActualCostSourceOptions) => ActualCostSource` | Create a Databricks-backed `ActualCostSource` that queries `system.billing.usage` joined to `system.billing.list_prices` for real spend data. Results are cached per-scope-key for `cacheTtlMs` (default 60s) to avoid hammering the SQL warehouse. | | `DatabricksActualCostSourceOptions` | `type` | `DatabricksActualCostSourceOptions` | Configuration options for databricks actual cost source. | | `DatabricksAgentEndpointClient` | `value` | `typeof DatabricksAgentEndpointClient` | Bounded OpenResponses invocation for an existing Databricks agent endpoint. The endpoint remains owned and permissioned by Databricks; Harness only treats it as a governed read/subagent tool. | | `DatabricksAgentEndpointInvocation` | `type` | `DatabricksAgentEndpointInvocation` | Type contract for databricks agent endpoint invocation. | | `DatabricksAgentEndpointResponse` | `type` | `DatabricksAgentEndpointResponse` | Response contract for databricks agent endpoint. | | `DatabricksAgentEntity` | `type` | `DatabricksAgentEntity` | Type contract for databricks agent entity. | | `DatabricksAgentService` | `type` | `DatabricksAgentService` | Type contract for databricks agent service. | | `DatabricksAgentServiceConfig` | `type` | `DatabricksAgentServiceConfig` | Type contract for databricks agent service config. | | `DatabricksAgentServiceConnection` | `type` | `DatabricksAgentServiceConnection` | Type contract for databricks agent service connection. | | `DatabricksAgentServiceCreateOptions` | `type` | `DatabricksAgentServiceCreateOptions` | Configuration options for databricks agent service create. | | `DatabricksAgentServiceGrantChange` | `type` | `DatabricksAgentServiceGrantChange` | Type contract for databricks agent service grant change. | | `DatabricksAgentServiceList` | `type` | `DatabricksAgentServiceList` | Type contract for databricks agent service list. | | `DatabricksAgentServicePermission` | `type` | `DatabricksAgentServicePermission` | Type contract for databricks agent service permission. | | `DatabricksAgentServicePermissions` | `type` | `DatabricksAgentServicePermissions` | Type contract for databricks agent service permissions. | | `DatabricksAgentServicePrivilege` | `type` | `DatabricksAgentServicePrivilege` | Type contract for databricks agent service privilege. | | `DatabricksAgentServices` | `value` | `typeof DatabricksAgentServices` | Typed lifecycle client for Unity Catalog Agent Services. Databricks currently supports registration, discovery and grants only. This client intentionally has no invoke method until runtime invocation is part of the Agent Services API. | | `DatabricksAgentServicesOptions` | `type` | `DatabricksAgentServicesOptions` | Configuration options for databricks agent services. | | `DatabricksAgentServiceUpdateOptions` | `type` | `DatabricksAgentServiceUpdateOptions` | Configuration options for databricks agent service update. | | `DatabricksAiGatewayUpdate` | `type` | `DatabricksAiGatewayUpdate` | Type contract for databricks ai gateway update. | | `DatabricksAiQueryPolicy` | `type` | `DatabricksAiQueryPolicy` | Type contract for databricks ai query policy. | | `databricksAiQueryTool` | `value` | `(client: DatabricksStatementClient, endpointPolicy: DatabricksAiQueryPolicy, options: DatabricksAiQueryToolOptions) => ToolDef<{ endpoint: string; request: string; }, unknown>` | `ai_query(endpoint, request)` — run model inference inside the SQL warehouse against a serving endpoint. Drives both serving and SQL-warehouse consumption. Uses named SQL parameters, so the endpoint and request are never string-interpolated into SQL. | | `DatabricksAiQueryToolOptions` | `type` | `DatabricksAiQueryToolOptions` | Configuration options for databricks ai query tool. | | `databricksAiSearch` | `value` | `(options: DatabricksAiSearchOptions) => DatabricksAiSearchRetriever` | Databricks AI Search as a `Retriever`. Runs under the bundle's Unity Catalog principal. | | `DatabricksAiSearchAdmin` | `value` | `typeof DatabricksAiSearchAdmin` | Runtime API for databricks ai search admin; the generated signature shows its accepted inputs and return type. | | `DatabricksAiSearchAdminClient` | `type` | `DatabricksAiSearchAdminClient` | Client implementation for databricks ai search admin. | | `DatabricksAiSearchAdminOperation` | `type` | `DatabricksAiSearchAdminOperation` | One model-callable AI Search administration operation. | | `DatabricksAiSearchAdminPolicy` | `type` | `DatabricksAiSearchAdminPolicy` | Bounds the model-callable AI Search admin tools. `allowedOperations` decides which tools exist at all; the index/endpoint arms pin the resource names those tools may name. An index or endpoint dimension no registered operation uses may be omitted; omitting the embedding arm instead withholds delta-sync index creation (see `DatabricksAiSearchEmbeddingArm`). `{ allowAnyAiSearchAdmin: true }` is the deliberate, greppable unbounded opt-out. | | `databricksAiSearchAdminTools` | `value` | `(client: DatabricksAiSearchAdminClient, policy: DatabricksAiSearchAdminPolicy) => ToolDef[]` | Model-callable AI Search administration, bounded by an explicit policy. `allowedOperations` filters which tools are registered at all, and every resource name is pinned into the tool's input schema and re-checked at call time before the Vector Search API is touched. The typed `DatabricksAiSearchAdmin` client stays unbounded. | | `DatabricksAiSearchInputMode` | `type` | `DatabricksAiSearchInputMode` | Type contract for databricks ai search input mode. | | `DatabricksAiSearchOptions` | `type` | `DatabricksAiSearchOptions` | Configuration options for databricks ai search. | | `DatabricksAiSearchQueryOptions` | `type` | `DatabricksAiSearchQueryOptions` | Configuration options for databricks ai search query. | | `DatabricksAiSearchQueryResult` | `type` | `DatabricksAiSearchQueryResult` | Result returned by databricks ai search query. | | `DatabricksAiSearchRetriever` | `type` | `DatabricksAiSearchRetriever` | Type contract for databricks ai search retriever. | | `DatabricksAiSearchStrategy` | `type` | `DatabricksAiSearchStrategy` | Type contract for databricks ai search strategy. | | `databricksAnthropicGatewayBaseUrl` | `value` | `(host: string) => string` | Runtime API for databricks anthropic gateway base url; the generated signature shows its accepted inputs and return type. | | `DatabricksApiFidelity` | `type` | `DatabricksApiFidelity` | Type contract for databricks api fidelity. | | `databricksApp` | `value` | `(options?: DatabricksAppOptions) => DatabricksAppRuntime` | Runtime API for databricks app; the generated signature shows its accepted inputs and return type. | | `DatabricksAppAuthenticatedPrincipal` | `type` | `DatabricksAppAuthenticatedPrincipal` | Type contract for databricks app authenticated principal. | | `DatabricksAppOptions` | `type` | `DatabricksAppOptions` | Production preset for agents hosted on Databricks Apps (v2, workstream C5). One call resolves the runtime from the standard app environment: the app's service principal (client-credentials OAuth), official workspace SDK clients and serving-endpoint model provider, Lakebase-backed persistence for sessions + submissions + conversation streams, and submission-keyed telemetry — all running as one governed identity that Unity Catalog enforces. See the package declarations for an example. | | `DatabricksAppRecoveryEvidence` | `type` | `DatabricksAppRecoveryEvidence` | Type contract for databricks app recovery evidence. | | `DatabricksApprovalRuleOptions` | `type` | `DatabricksApprovalRuleOptions` | Configuration options for databricks approval rule. | | `databricksApprovalRules` | `value` | `(tools: ToolDef[], options: DatabricksApprovalRuleOptions) => ApprovalPolicyRule[]` | Builds approval rules (one per gated tool) for `CapabilityPolicy.toolPolicy.approvalRules`. | | `DatabricksAppRuntime` | `type` | `DatabricksAppRuntime` | Type contract for databricks app runtime. | | `DatabricksAppUserAuthenticatorOptions` | `type` | `DatabricksAppUserAuthenticatorOptions` | Configuration options for databricks app user authenticator. | | `DatabricksAppUserAuthorizationInspection` | `type` | `DatabricksAppUserAuthorizationInspection` | Type contract for databricks app user authorization inspection. | | `DatabricksAppUserIsolationEvidence` | `type` | `DatabricksAppUserIsolationEvidence` | Type contract for databricks app user isolation evidence. | | `DatabricksAssetBundleEntry` | `type` | `DatabricksAssetBundleEntry` | One checked-in Asset Bundle as configured on `databricks({ assetBundles })`. | | `databricksAssetBundleLifecycle` | `value` | `(options: DatabricksAssetBundleOptions) => DatabricksAssetBundleLifecycle` | Runtime API for databricks asset bundle lifecycle; the generated signature shows its accepted inputs and return type. | | `DatabricksAssetBundleLifecycle` | `value` | `typeof DatabricksAssetBundleLifecycle` | Governed lifecycle for a checked-in Databricks Asset Bundle (DAB). Harness does not generate bundle YAML — it makes validate/deploy/run/destroy of an existing bundle a fingerprinted, approval-gated operation: - `fingerprint()` hashes the bundle source tree (sorted relative paths + content), excluding `.databricks/` CLI state, `node_modules/`, and `dist/`. - `deploy()` validates, deploys, then upserts the managed-resource record. When the caller passes `expectedFingerprint` and a record exists with a different fingerprint, deploy fails with `DatabricksManagedResourceConflictError` (optimisti... | | `databricksAssetBundleLifecycles` | `value` | `(options: DatabricksAssetBundleMapOptions, defaults?: Omit<DatabricksAssetBundleOptions, "bundleDir" \| "instanceName">) => Map<string, DatabricksAssetBundleLifecycle>` | Build one lifecycle per named bundle. Names are validated (they reach the model as tool input and the managed-resource store as ids) and sorted, so tool enums and dispatch stay deterministic. `defaults` are applied under each entry, letting a caller set one `principalLabel` for every bundle. | | `DatabricksAssetBundleMapOptions` | `type` | `DatabricksAssetBundleMapOptions` | Several checked-in bundles keyed by logical name; the key becomes the lifecycle's `instanceName`. | | `DatabricksAssetBundleOptions` | `type` | `DatabricksAssetBundleOptions` | Configuration options for databricks asset bundle. | | `databricksAssetBundleTools` | `value` | `(options: DatabricksAssetBundleOptions \| DatabricksAssetBundleLifecycle \| DatabricksAssetBundleMapOptions \| Map<string, DatabricksAssetBundleLifecycle>) => ToolDef[]` | Model-facing tools for the governed bundle lifecycle. Write tools are approval-gated by the `databricks()` bundle like every other authoring surface. A single bundle keeps bundle-free tool schemas; a named map adds a required `bundle` selector to every schema (even with one entry, so the schema and its approval digests stay stable when a second bundle is added) and governs only the bundle the call actually names. | | `DatabricksAuthenticatedFetchOptions` | `type` | `DatabricksAuthenticatedFetchOptions` | Configuration options for databricks authenticated fetch. | | `DatabricksAuthoringCertificationFixtures` | `type` | `DatabricksAuthoringCertificationFixtures` | Type contract for databricks authoring certification fixtures. | | `DatabricksAuthoringLifecycle` | `type` | `DatabricksAuthoringLifecycle<Resource, Mutation>` | Type contract for databricks authoring lifecycle. | | `DatabricksAuthoringLifecycleEvidence` | `type` | `DatabricksAuthoringLifecycleEvidence` | Type contract for databricks authoring lifecycle evidence. | | `DatabricksBundle` | `type` | `DatabricksBundle` | Type contract for databricks bundle. | | `DatabricksBundleConfig` | `type` | `DatabricksBundleConfig` | Type contract for databricks bundle config. | | `DatabricksCapability` | `type` | `DatabricksCapability` | Type contract for databricks capability. | | `DatabricksCapabilityEvidenceReference` | `type` | `DatabricksCapabilityEvidenceReference` | Type contract for databricks capability evidence reference. | | `DatabricksCapabilityStatus` | `type` | `DatabricksCapabilityStatus` | Type contract for databricks capability status. | | `DatabricksCertificationBlockingTier` | `type` | `DatabricksCertificationBlockingTier` | Type contract for databricks certification blocking tier. | | `DatabricksCertificationCheck` | `type` | `DatabricksCertificationCheck` | Type contract for databricks certification check. | | `DatabricksCertificationCleanupLedger` | `value` | `typeof DatabricksCertificationCleanupLedger` | Reverse-order cleanup ledger for live lifecycle certification. | | `DatabricksCertificationEnvironmentIssue` | `type` | `DatabricksCertificationEnvironmentIssue` | Type contract for databricks certification environment issue. | | `DatabricksCertificationEvidence` | `type` | `DatabricksCertificationEvidence` | Type contract for databricks certification evidence. | | `DatabricksCertificationLevel` | `type` | `DatabricksCertificationLevel` | Type contract for databricks certification level. | | `DatabricksCertificationResult` | `type` | `DatabricksCertificationResult` | Result returned by databricks certification. | | `DatabricksCertificationStatus` | `type` | `DatabricksCertificationStatus` | Type contract for databricks certification status. | | `DatabricksCertificationSweepClients` | `type` | `DatabricksCertificationSweepClients` | Type contract for databricks certification sweep clients. | | `DatabricksCertificationSweepOptions` | `type` | `DatabricksCertificationSweepOptions` | Configuration options for databricks certification sweep. | | `DatabricksCertificationSweepResult` | `type` | `DatabricksCertificationSweepResult` | Result returned by databricks certification sweep. | | `databricksCertificationTier` | `value` | `(checkId: string) => DatabricksCertificationTier` | Return the default certification tier for a built-in check. Custom checks default to Tier O. | | `DatabricksCertificationTier` | `type` | `DatabricksCertificationTier` | Type contract for databricks certification tier. | | `DatabricksCertificationWorkspaceSweepOptions` | `type` | `DatabricksCertificationWorkspaceSweepOptions` | Configuration options for databricks certification workspace sweep. | | `DatabricksCleanupResource` | `type` | `DatabricksCleanupResource` | Type contract for databricks cleanup resource. | | `DatabricksCloud` | `type` | `string` | Type contract for databricks cloud. | | `DatabricksCommandResult` | `type` | `DatabricksCommandResult` | Result returned by databricks command. | | `DatabricksCommandRunner` | `type` | `DatabricksCommandRunner` | Type contract for databricks command runner. | | `databricksCompatibilityRecord` | `value` | `(evidence: DatabricksCertificationEvidence) => DatabricksWorkspaceCompatibilityRecord` | Convert successful, fully identified certification evidence into a publishable matrix row. | | `DatabricksComputePolicy` | `type` | `DatabricksComputePolicy` | Type contract for databricks compute policy. | | `databricksConsumption` | `value` | `(client: DatabricksStatementClient, options: DatabricksConsumptionOptions) => { summary(opts: ConsumptionSummaryOptions): Promise<ConsumptionSummary>; }` | System-Tables consumption reporting. Reads `system.billing.usage` joined to `list_prices` to report real DBUs + list cost — the "prove the consumption" artifact for chargeback and partner credit. | | `DatabricksConsumption` | `type` | `{ summary(opts: ConsumptionSummaryOptions): Promise<ConsumptionSummary>; }` | Type contract for databricks consumption. | | `DatabricksConsumptionOptions` | `type` | `DatabricksConsumptionOptions` | Configuration options for databricks consumption. | | `databricksConsumptionTool` | `value` | `(client: DatabricksStatementClient, options: DatabricksConsumptionToolOptions) => ToolDef<{ days?: number; startDate?: string; endDate?: string; groupBy?: ConsumptionGroupBy; }, unknown>` | Agent-callable consumption report over the last `days` (default 30) or an explicit date window. | | `DatabricksConsumptionToolOptions` | `type` | `DatabricksConsumptionToolOptions` | Configuration options for databricks consumption tool. | | `DatabricksCostReconciliationOptions` | `type` | `DatabricksCostReconciliationOptions` | Configuration options for databricks cost reconciliation. | | `DatabricksCostReconciliationResult` | `type` | `DatabricksCostReconciliationResult` | Result returned by databricks cost reconciliation. | | `DatabricksCreatedJob` | `type` | `DatabricksCreatedJob` | Type contract for databricks created job. | | `DatabricksCreateJobOptions` | `type` | `DatabricksCreateJobOptions` | Configuration options for databricks create job. | | `DatabricksCrossTierEvidenceManifest` | `type` | `DatabricksCrossTierEvidenceManifest` | Type contract for databricks cross tier evidence manifest. | | `DatabricksCustomModelEntity` | `type` | `DatabricksCustomModelEntity` | Type contract for databricks custom model entity. | | `DatabricksDbtTaskSpec` | `type` | `DatabricksDbtTaskSpec` | Type contract for databricks dbt task spec. | | `DatabricksDomainAssignment` | `type` | `DatabricksDomainAssignment` | Binding of a module namespace to its UC domain (one domain per namespace; the `domain` option overrides the default), generated by `ontology-glossary.ts` (P0-4). | | `DatabricksDynamicAgentEvidence` | `type` | `DatabricksDynamicAgentEvidence` | Type contract for databricks dynamic agent evidence. | | `databricksEmbeddings` | `value` | `(options: DatabricksEmbeddingsOptions) => EmbeddingProvider` | Embeddings via a Mosaic AI serving **embedding** endpoint. Databricks exposes the OpenAI-compatible embeddings surface at `<host>/serving-endpoints/embeddings` with the endpoint name as `model`. Reuses the bundle's generated Model Serving Query client, so it inherits the rotating UC-principal credential. (URL/response schema worth a smoke test against a live embedding endpoint — chat and embeddings share the OpenAI-compatible convention but endpoint families can differ.) | | `DatabricksEmbeddingsOptions` | `type` | `DatabricksEmbeddingsOptions` | Configuration options for databricks embeddings. | | `DatabricksExternalModelEntity` | `type` | `DatabricksExternalModelEntity` | Type contract for databricks external model entity. | | `databricksFeatureLookupTool` | `value` | `(client: DatabricksModelServingQueryClient, options: DatabricksFeatureLookupToolOptions) => ToolDef<{ records: JsonObject[]; }, unknown>` | Low-latency feature lookup from a Databricks **Feature Serving** endpoint (backed by an Online Table). The model passes primary-key records; the endpoint returns the served feature values. Drives serving consumption and keeps features governed by Unity Catalog under the bundle principal. | | `DatabricksFeatureLookupToolOptions` | `type` | `DatabricksFeatureLookupToolOptions` | Configuration options for databricks feature lookup tool. | | `DatabricksFeedTableSpec` | `type` | `DatabricksFeedTableSpec` | One operational-truth feed table spec (design §3.7), generated by `ontology-feed.ts` (P1-1). The DDL is deterministic and append-only; the governed apply path executes it through the same approval/provenance seams as the metric-view DDL. | | `databricksFoundationModelProvider` | `value` | `(options: DatabricksModelOptions) => ModelProvider` | Databricks inference provider supporting both Unity AI Gateway model services and custom Model Serving endpoints. In `auto` mode, fully-qualified `system.ai.*` models use AI Gateway and other endpoint names retain the `/serving-endpoints` route. | | `databricksGenie` | `value` | `(client: DatabricksGenieSdkClient, options: DatabricksGenieClientOptions) => DatabricksGenieClient` | Runtime API for databricks genie; the generated signature shows its accepted inputs and return type. | | `DatabricksGenieAccessControl` | `type` | `DatabricksGenieAccessControl` | Type contract for databricks genie access control. | | `DatabricksGenieAdmin` | `value` | `typeof DatabricksGenieAdmin` | Runtime API for databricks genie admin; the generated signature shows its accepted inputs and return type. | | `DatabricksGenieAdminOptions` | `type` | `DatabricksGenieAdminOptions` | Configuration options for databricks genie admin. | | `DatabricksGenieAgent` | `type` | `DatabricksGenieAgent` | Type contract for databricks genie agent. | | `DatabricksGenieAgentModeClient` | `value` | `typeof DatabricksGenieAgentModeClient` | Client implementation for databricks genie agent mode. | | `DatabricksGenieAgentModeClientOptions` | `type` | `DatabricksGenieAgentModeClientOptions` | Configuration options for databricks genie agent mode client. | | `DatabricksGenieAgentModeCompletedEvent` | `type` | `DatabricksGenieAgentModeCompletedEvent` | Type contract for databricks genie agent mode completed event. | | `DatabricksGenieAgentModeCreatedEvent` | `type` | `DatabricksGenieAgentModeCreatedEvent` | Type contract for databricks genie agent mode created event. | | `DatabricksGenieAgentModeErrorInfo` | `type` | `DatabricksGenieAgentModeErrorInfo` | Type contract for databricks genie agent mode error info. | | `DatabricksGenieAgentModeEvent` | `type` | `DatabricksGenieAgentModeEvent` | Type contract for databricks genie agent mode event. | | `DatabricksGenieAgentModeFailedEvent` | `type` | `DatabricksGenieAgentModeFailedEvent` | Type contract for databricks genie agent mode failed event. | | `DatabricksGenieAgentModeItemPage` | `type` | `DatabricksGenieAgentModeItemPage` | Type contract for databricks genie agent mode item page. | | `DatabricksGenieAgentModeOutputEvent` | `type` | `DatabricksGenieAgentModeOutputEvent` | Type contract for databricks genie agent mode output event. | | `DatabricksGenieAgentModeProtocolError` | `value` | `typeof DatabricksGenieAgentModeProtocolError` | Error raised for databricks genie agent mode protocol failures. | | `DatabricksGenieAgentModeResponse` | `type` | `DatabricksGenieAgentModeResponse` | Response contract for databricks genie agent mode. | | `DatabricksGenieAgentModeResponseError` | `value` | `typeof DatabricksGenieAgentModeResponseError` | Error raised for databricks genie agent mode response failures. | | `DatabricksGenieAgentModeTimeoutError` | `value` | `typeof DatabricksGenieAgentModeTimeoutError` | Error raised for databricks genie agent mode timeout failures. | | `databricksGenieAgentModeTool` | `value` | `(client: DatabricksGenieAgentModeClient, agentId: string, options?: DatabricksGenieAgentModeToolOptions) => ToolDef` | Model-callable tool or tool factory for databricks genie agent mode. | | `DatabricksGenieAgentModeToolOptions` | `type` | `DatabricksGenieAgentModeToolOptions` | Configuration options for databricks genie agent mode tool. | | `DatabricksGenieAgentModeUnknownEvent` | `type` | `DatabricksGenieAgentModeUnknownEvent` | Type contract for databricks genie agent mode unknown event. | | `DatabricksGenieAgentPage` | `type` | `DatabricksGenieAgentPage` | Type contract for databricks genie agent page. | | `DatabricksGenieAgentReference` | `type` | `DatabricksGenieAgentReference` | Type contract for databricks genie agent reference. | | `DatabricksGenieAgentSpecV2` | `type` | `DatabricksGenieAgentSpecV2` | Type contract for databricks genie agent spec v2. | | `DatabricksGenieAgentUpdate` | `type` | `DatabricksGenieAgentUpdate` | Type contract for databricks genie agent update. | | `DatabricksGenieAskInput` | `type` | `DatabricksGenieAskInput` | Type contract for databricks genie ask input. | | `DatabricksGenieAttachment` | `type` | `DatabricksGenieAttachment` | Type contract for databricks genie attachment. | | `DatabricksGenieAuthoringToolOptions` | `type` | `DatabricksGenieAuthoringToolOptions` | Configuration options for databricks genie authoring tool. | | `DatabricksGenieBenchmark` | `type` | `DatabricksGenieBenchmark` | Type contract for databricks genie benchmark. | | `DatabricksGenieClient` | `value` | `typeof DatabricksGenieClient` | Client implementation for databricks genie. | | `DatabricksGenieClientOptions` | `type` | `DatabricksGenieClientOptions` | Configuration options for databricks genie client. | | `DatabricksGenieColumnSpec` | `type` | `DatabricksGenieColumnSpec` | Type contract for databricks genie column spec. | | `DatabricksGenieCommentPage` | `type` | `DatabricksGenieCommentPage` | Type contract for databricks genie comment page. | | `DatabricksGenieConfig` | `type` | `DatabricksGenieConfig` | Type contract for databricks genie config. | | `DatabricksGenieConversationPage` | `type` | `DatabricksGenieConversationPage` | Type contract for databricks genie conversation page. | | `DatabricksGenieConversationSummary` | `type` | `DatabricksGenieConversationSummary` | Type contract for databricks genie conversation summary. | | `DatabricksGenieDataSource` | `type` | `DatabricksGenieDataSource` | Data or filesystem source for databricks genie data. | | `DatabricksGenieExport` | `type` | `DatabricksGenieExport` | Type contract for databricks genie export. | | `DatabricksGenieInferredConcept` | `type` | `DatabricksGenieInferredConcept` | One inferred concept read from the Genie knowledge store. Plain data: the preview wire shape is the caller's adapter concern (design Q1). | | `DatabricksGenieInferredConceptKind` | `type` | `DatabricksGenieInferredConceptKind` | Inferred concept kinds the Genie knowledge store learns (design §4). | | `DatabricksGenieInferredKnowledge` | `type` | `DatabricksGenieInferredKnowledge` | The knowledge store's inferred concepts, as plain data. | | `DatabricksGenieJoinSide` | `type` | `DatabricksGenieJoinSide` | Type contract for databricks genie join side. | | `DatabricksGenieJoinSpec` | `type` | `DatabricksGenieJoinSpec` | Type contract for databricks genie join spec. | | `DatabricksGenieKnowledgeStoreReader` | `type` | `DatabricksGenieKnowledgeStoreReader` | Injectable read-only knowledge-store client (design Q1). The interface has exactly one method and no write surface: drift detection can never mutate the knowledge store, a Genie Agent spec, or any declared definition through this seam. Callers plug in whatever the preview API exposes. | | `DatabricksGenieManagementConfig` | `type` | `DatabricksGenieManagementConfig` | Type contract for databricks genie management config. | | `DatabricksGenieMessageComment` | `type` | `DatabricksGenieMessageComment` | Type contract for databricks genie message comment. | | `DatabricksGenieMessageError` | `value` | `typeof DatabricksGenieMessageError` | Error raised for databricks genie message failures. | | `DatabricksGenieMessagePage` | `type` | `DatabricksGenieMessagePage` | Type contract for databricks genie message page. | | `DatabricksGenieMessageStatus` | `type` | `string` | Type contract for databricks genie message status. | | `DatabricksGenieMessageSummary` | `type` | `DatabricksGenieMessageSummary` | Type contract for databricks genie message summary. | | `DatabricksGenieOwnershipContext` | `type` | `DatabricksGenieOwnershipContext` | Type contract for databricks genie ownership context. | | `DatabricksGeniePermissionChange` | `type` | `DatabricksGeniePermissionChange` | Type contract for databricks genie permission change. | | `DatabricksGeniePermissionLevel` | `type` | `DatabricksGeniePermissionLevel` | Type contract for databricks genie permission level. | | `DatabricksGeniePermissions` | `type` | `DatabricksGeniePermissions` | Type contract for databricks genie permissions. | | `DatabricksGenieProtocolError` | `value` | `typeof DatabricksGenieProtocolError` | Error raised for databricks genie protocol failures. | | `DatabricksGenieQueryAttachment` | `type` | `DatabricksGenieQueryAttachment` | Type contract for databricks genie query attachment. | | `DatabricksGenieQueryResult` | `type` | `DatabricksGenieQueryResult` | Result returned by databricks genie query. | | `DatabricksGenieResponse` | `type` | `DatabricksGenieResponse` | Response contract for databricks genie. | | `DatabricksGenieResponseLimitError` | `value` | `typeof DatabricksGenieResponseLimitError` | Error raised for databricks genie response limit failures. | | `DatabricksGenieSqlExample` | `type` | `DatabricksGenieSqlExample` | Type contract for databricks genie sql example. | | `DatabricksGenieSqlFunction` | `type` | `DatabricksGenieSqlFunction` | Type contract for databricks genie sql function. | | `DatabricksGenieSqlPolicy` | `type` | `DatabricksGenieSqlPolicy` | Type contract for databricks genie sql policy. | | `DatabricksGenieSqlPolicyInput` | `type` | `DatabricksGenieSqlPolicyInput` | Type contract for databricks genie sql policy input. | | `DatabricksGenieSqlPolicyResult` | `type` | `DatabricksGenieSqlPolicyResult` | Result returned by databricks genie sql policy. | | `DatabricksGenieSqlSnippet` | `type` | `DatabricksGenieSqlSnippet` | Type contract for databricks genie sql snippet. | | `DatabricksGenieSqlSnippets` | `type` | `DatabricksGenieSqlSnippets` | Type contract for databricks genie sql snippets. | | `DatabricksGenieSuggestedQuestionsAttachment` | `type` | `DatabricksGenieSuggestedQuestionsAttachment` | Type contract for databricks genie suggested questions attachment. | | `DatabricksGenieTextAttachment` | `type` | `DatabricksGenieTextAttachment` | Type contract for databricks genie text attachment. | | `DatabricksGenieTimeoutError` | `value` | `typeof DatabricksGenieTimeoutError` | Error raised for databricks genie timeout failures. | | `databricksGenieTool` | `value` | `(client: DatabricksGenieSdkClient, options: DatabricksGenieToolOptions) => ToolDef<{ question: string; conversationId?: string; }, DatabricksGenieResponse>` | Genie Agents — delegate a natural-language analytics question to a governed Genie Agent. Genie generates and runs SQL on the warehouse and returns typed answer, query, result, and visualization attachments. Pass `conversationId` to continue a multi-turn thread. | | `DatabricksGenieToolOptions` | `type` | `DatabricksGenieToolOptions` | Configuration options for databricks genie tool. | | `DatabricksGenieUnknownAttachment` | `type` | `DatabricksGenieUnknownAttachment` | Type contract for databricks genie unknown attachment. | | `DatabricksGenieVisualizationAttachment` | `type` | `DatabricksGenieVisualizationAttachment` | Type contract for databricks genie visualization attachment. | | `DatabricksGlossaryTerm` | `type` | `DatabricksGlossaryTerm` | A Unity Catalog glossary term upsert payload, generated by `ontology-glossary.ts` (P0-4). Plan data only — the governed publish path lands with the apply ticket. | | `DatabricksGlossaryTermKind` | `type` | `DatabricksGlossaryTermKind` | Which manifest vocabulary group a glossary term was derived from (design §3.3). | | `DatabricksGovernanceMetadata` | `type` | `DatabricksGovernanceMetadata` | Type contract for databricks governance metadata. | | `DatabricksGovernanceOptions` | `type` | `DatabricksGovernanceOptions` | Configuration options for databricks governance. | | `databricksGovernancePolicy` | `value` | `(options: DatabricksGovernancePolicyOptions) => CapabilityPolicy` | Assembles a `CapabilityPolicy` for a Databricks tool set: approval routing for sensitive operations (if `stewardAudience` is set) plus an egress allowlist pinned to the workspace host(s). Used by the `databricks()` bundle; can also be merged into an agent's own policy. | | `DatabricksGovernancePolicyOptions` | `type` | `DatabricksGovernancePolicyOptions` | Configuration options for databricks governance policy. | | `DatabricksGovernanceResourceDescriptor` | `type` | `DatabricksGovernanceResourceDescriptor` | Type contract for databricks governance resource descriptor. | | `DatabricksGovernedResource` | `type` | `DatabricksGovernedResource` | Type contract for databricks governed resource. | | `databricksHostFromCliProfile` | `value` | `(profile?: string) => Promise<string>` | Workspace host resolved from a Databricks CLI profile (`~/.databrickscfg` or `DATABRICKS_CONFIG_FILE`), normalized to the workspace origin. `DATABRICKS_*` environment variables overlay the file per the official SDK credential chain. | | `databricksIdentity` | `value` | `(principal: DatabricksPrincipal) => DatabricksTokenProvider` | Builds a rotating bearer-token provider from the same native credential used by SDK clients. | | `DatabricksInferenceMode` | `type` | `DatabricksInferenceMode` | Type contract for databricks inference mode. | | `DatabricksJobField` | `type` | `DatabricksJobField` | Type contract for databricks job field. | | `DatabricksJobRunPolicy` | `type` | `DatabricksJobRunPolicy` | Bound for triggering existing jobs. Ids, not names: the narrow run client cannot resolve names, and call-time resolution would be a TOCTOU hole. `allowAnyJobId` is the explicit opt-out. | | `databricksJobs` | `value` | `(client: DatabricksJobsClient, options?: DatabricksJobsOptions) => DatabricksJobs` | Runtime API for databricks jobs; the generated signature shows its accepted inputs and return type. | | `DatabricksJobs` | `value` | `typeof DatabricksJobs` | Runtime API for databricks jobs; the generated signature shows its accepted inputs and return type. | | `databricksJobsAuthoring` | `value` | `(client: DatabricksJobsAuthoringClient, computePolicy?: DatabricksComputePolicy) => DatabricksJobsAuthoring` | Runtime API for databricks jobs authoring; the generated signature shows its accepted inputs and return type. | | `DatabricksJobsAuthoring` | `value` | `typeof DatabricksJobsAuthoring` | Runtime API for databricks jobs authoring; the generated signature shows its accepted inputs and return type. | | `databricksJobsAuthoringTools` | `value` | `(client: DatabricksJobsAuthoringClient, computePolicy?: DatabricksComputePolicy, options?: { oneOffCompute?: boolean; }) => ToolDef[]` | Runtime API for databricks jobs authoring tools; the generated signature shows its accepted inputs and return type. | | `DatabricksJobSchedule` | `type` | `DatabricksJobSchedule` | Type contract for databricks job schedule. | | `DatabricksJobsClient` | `type` | `DatabricksJobsClient` | Client implementation for databricks jobs. | | `DatabricksJobsOptions` | `type` | `DatabricksJobsOptions` | Configuration options for databricks jobs. | | `DatabricksJobSpec` | `type` | `DatabricksJobSpec` | Type contract for databricks job spec. | | `DatabricksJobsWaitOptions` | `type` | `DatabricksJobsWaitOptions` | Configuration options for databricks jobs wait. | | `DatabricksJobTask` | `type` | `DatabricksJobTask` | Type contract for databricks job task. | | `DatabricksJobUpdate` | `type` | `DatabricksJobUpdate` | Type contract for databricks job update. | | `DatabricksLakeflowAuthoring` | `value` | `typeof DatabricksLakeflowAuthoring` | Runtime API for databricks lakeflow authoring; the generated signature shows its accepted inputs and return type. | | `databricksLakeflowAuthoringTools` | `value` | `(client: DatabricksPipelinesAuthoringClient, options?: { warehouseId?: string; statements?: DatabricksStatementClient; }) => ToolDef[]` | Runtime API for databricks lakeflow authoring tools; the generated signature shows its accepted inputs and return type. | | `databricksLakeflowTools` | `value` | `(client: DatabricksPipelinesClient, runPolicy?: DatabricksPipelineRunPolicy) => ToolDef[]` | The default Lakeflow tool set. Omitting runPolicy is intentionally read-only. | | `DatabricksLifecycleOperation` | `type` | `DatabricksLifecycleOperation` | Type contract for databricks lifecycle operation. | | `DatabricksLineageEvidenceRow` | `type` | `DatabricksLineageEvidenceRow` | Type contract for databricks lineage evidence row. | | `DatabricksLineageRecord` | `type` | `DatabricksLineageRecord` | Governance for Databricks tools is **layered on top of Unity Catalog, never a replacement.** UC enforces table/row/column ACLs natively via the acting principal (see identity.ts). These helpers add the things UC doesn't: an **audit/lineage** stamp on every tool call, **approval routing** for sensitive operations, and an **egress allowlist** pinned to the workspace — all expressed through the SDK's existing `CapabilityPolicy`, so the loop enforces them without a bespoke engine. | | `DatabricksManagedAgentKind` | `type` | `DatabricksManagedAgentKind` | Type contract for databricks managed agent kind. | | `databricksManagedAgentTool` | `value` | `(client: DatabricksAgentEndpointClient, options: DatabricksManagedAgentToolOptions) => ToolDef<{ question: string; previousResponseId?: string; }, DatabricksManagedAgentToolResult>` | Project an existing Supervisor Agent, Knowledge Assistant, or Responses-compatible endpoint. | | `DatabricksManagedAgentToolOptions` | `type` | `DatabricksManagedAgentToolOptions` | Configuration options for databricks managed agent tool. | | `DatabricksManagedAgentToolResult` | `type` | `DatabricksManagedAgentToolResult` | Result returned by databricks managed agent tool. | | `DatabricksManagedMcpBundle` | `type` | `DatabricksManagedMcpBundle` | Type contract for databricks managed mcp bundle. | | `DatabricksManagedMcpEndpoint` | `type` | `DatabricksManagedMcpEndpoint` | Type contract for databricks managed mcp endpoint. | | `DatabricksManagedMcpServerConfig` | `type` | `DatabricksManagedMcpServerConfig` | Type contract for databricks managed mcp server config. | | `databricksManagedMcpUrl` | `value` | `(host: string, endpoint: DatabricksManagedMcpEndpoint) => URL` | Build a workspace-local managed MCP or Unity AI Gateway MCP Service endpoint. | | `databricksManagedMemory` | `value` | `(client: DatabricksRawProtocolClient, options: DatabricksManagedMemoryOptions) => DatabricksManagedMemoryClient` | Runtime API for databricks managed memory; the generated signature shows its accepted inputs and return type. | | `DatabricksManagedMemoryClient` | `value` | `typeof DatabricksManagedMemoryClient` | Explicit managed long-term memory client. Scope is required on every entry operation and is never inferred from model input, keeping tenant partitioning at the trusted application boundary. | | `DatabricksManagedMemoryOptions` | `type` | `DatabricksManagedMemoryOptions` | Configuration options for databricks managed memory. | | `DatabricksManagedResourceConflictError` | `value` | `typeof DatabricksManagedResourceConflictError` | Error raised for databricks managed resource conflict failures. | | `DatabricksManagedResourceRecord` | `type` | `DatabricksManagedResourceRecord` | Type contract for databricks managed resource record. | | `DatabricksManagedResourceStore` | `type` | `DatabricksManagedResourceStore` | Storage contract for databricks managed resource. | | `DatabricksMemoryEntry` | `type` | `DatabricksMemoryEntry` | Type contract for databricks memory entry. | | `DatabricksMemoryEntryEdit` | `type` | `DatabricksMemoryEntryEdit` | Type contract for databricks memory entry edit. | | `DatabricksMemoryEntryPage` | `type` | `DatabricksMemoryEntryPage` | Type contract for databricks memory entry page. | | `DatabricksMemoryStore` | `type` | `DatabricksMemoryStore` | Storage contract for databricks memory. | | `DatabricksMemoryStorePage` | `type` | `DatabricksMemoryStorePage` | Type contract for databricks memory store page. | | `databricksMlflowLogMetricTool` | `value` | `(client: DatabricksExperimentsClient, runPolicy: DatabricksMlflowRunPolicy, options?: { name?: string; description?: string; }) => ToolDef<{ runId: string; key: string; value: number; step?: number; timestamp?: number; }, unknown>` | Model-callable tool or tool factory for databricks mlflow log metric. | | `databricksMlflowLogParamTool` | `value` | `(client: DatabricksExperimentsClient, runPolicy: DatabricksMlflowRunPolicy, options?: { name?: string; description?: string; }) => ToolDef<{ runId: string; key: string; value: string; }, unknown>` | Model-callable tool or tool factory for databricks mlflow log param. | | `DatabricksMlflowRunPolicy` | `type` | `DatabricksMlflowRunPolicy` | Type contract for databricks mlflow run policy. | | `databricksModelBaseUrl` | `value` | `(host: string, mode: Exclude<DatabricksInferenceMode, "auto">) => string` | Build the OpenAI-compatible base URL used for one Databricks inference mode. | | `DatabricksModelOptions` | `type` | `DatabricksModelOptions` | Configuration options for databricks model. | | `DatabricksModelProviderService` | `type` | `DatabricksModelProviderService` | Type contract for databricks model provider service. | | `databricksModelProviderSupportsAnthropic` | `value` | `(service: DatabricksModelProviderService) => boolean` | Runtime API for databricks model provider supports anthropic; the generated signature shows its accepted inputs and return type. | | `DatabricksModelService` | `type` | `DatabricksModelService` | Type contract for databricks model service. | | `DatabricksModelServiceDiscoveryOptions` | `type` | `DatabricksModelServiceDiscoveryOptions` | Configuration options for databricks model service discovery. | | `databricksNativeModelId` | `value` | `(model: string \| undefined) => string \| undefined` | Strip the `databricks/` routing prefix from a model reference at the wire boundary. Callers may keep the full `databricks/<endpoint>` form (config `run.model`, job `model`); mode selection and the serving/gateway request must see the workspace-native name — serving endpoints 404 (`ENDPOINT_NOT_FOUND`) on the prefixed form. | | `DatabricksNewClusterSpec` | `type` | `DatabricksNewClusterSpec` | Type contract for databricks new cluster spec. | | `DatabricksNotebookImport` | `type` | `DatabricksNotebookImport` | Type contract for databricks notebook import. | | `DatabricksNotebookRunPolicy` | `type` | `DatabricksNotebookRunPolicy` | Bound for one-off notebook submission. `allowAnyNotebookPath` is the explicit opt-out. | | `DatabricksNotebookTaskSpec` | `type` | `DatabricksNotebookTaskSpec` | Type contract for databricks notebook task spec. | | `databricksNotebookTool` | `value` | `(client: DatabricksJobsClient, notebookPolicy: DatabricksNotebookRunPolicy, options?: { name?: string; description?: string; existingClusterId?: string; }) => ToolDef<{ notebookPath: string; idempotencyToken?: string; baseParameters?: JsonObject; runName?:...` | Submit a one-off Databricks notebook run. `notebookPolicy` is required for the same reason the run-job tool requires one, and more strongly: an unbounded notebook path executes arbitrary workspace code as the calling principal. | | `DatabricksOntologyActionInvocationRecord` | `type` | `DatabricksOntologyActionInvocationRecord` | Minimal ActionInvocation record the feed pipeline consumes. Raw parameters travel only to the vertical's producer; the feed table carries `redacted_parameters` only (design §3.7, KD-10). | | `DatabricksOntologyAppliedFeedTable` | `type` | `DatabricksOntologyAppliedFeedTable` | One feed table after apply (or after no-op detection). | | `DatabricksOntologyAppliedGenieAgent` | `type` | `DatabricksOntologyAppliedGenieAgent` | The Genie Agent after apply. | | `DatabricksOntologyAppliedGlossaryDomain` | `type` | `DatabricksOntologyAppliedGlossaryDomain` | One glossary domain after apply (or after no-op detection / publisher-less apply). | | `DatabricksOntologyAppliedMetricView` | `type` | `DatabricksOntologyAppliedMetricView` | One metric view after apply (or after no-op detection). | | `DatabricksOntologyApplyApproval` | `type` | `DatabricksOntologyApplyApproval` | Approval gate invoked before every apply write. Return/resolve to approve; throw to deny. This is the caller's hook into the existing steward approval flow — apply itself never approves. | | `DatabricksOntologyApplyApprovalRequest` | `type` | `DatabricksOntologyApplyApprovalRequest` | Approval request for one authoring write, mirroring the governance metadata the authoring ToolDefs declare (`effect`, governed resource, principal). | | `DatabricksOntologyApplyGenieOptions` | `type` | `DatabricksOntologyApplyGenieOptions` | Genie wiring for apply: the fingerprinted authoring client plus an optional existing agent. | | `DatabricksOntologyApplyOperation` | `type` | `DatabricksOntologyApplyOperation` | Writes apply can perform; each maps to one approval request. | | `DatabricksOntologyApplyOptions` | `type` | `DatabricksOntologyApplyOptions` | Configuration options for databricks ontology apply. | | `DatabricksOntologyAssetEventRecord` | `type` | `DatabricksOntologyAssetEventRecord` | Minimal AssetEvent record the feed pipeline consumes (design §3.7). `event_id` is required — it is the replay key — and any additional raw fields pass through to the vertical's producer untouched (raw payloads, PII-bearing fields) to be redacted or dropped there; the publishable-field allowlist is the last line. | | `DatabricksOntologyDriftAttestationOptions` | `type` | `DatabricksOntologyDriftAttestationOptions` | Options for the attestation entry point (P2-2). | | `DatabricksOntologyDriftAttestationRecord` | `type` | `DatabricksOntologyDriftAttestationRecord` | One append-only drift attestation record (design §5). `runId` is a content fingerprint of the plan, the findings, and the steward audience, so the record is deterministic for an identical comparison; every run still appends its own record — historical evidence is never rewritten. | | `DatabricksOntologyDriftComparison` | `type` | `DatabricksOntologyDriftComparison` | Deterministic comparison result: findings plus per-kind counts for steward triage. | | `DatabricksOntologyDriftComparisonInput` | `type` | `DatabricksOntologyDriftComparisonInput` | Input for the pure comparison: the declared plan plus plain inferred data. | | `DatabricksOntologyDriftDeclaredReference` | `type` | `DatabricksOntologyDriftDeclaredReference` | Reference to the declared side of a finding (from the export plan). | | `DatabricksOntologyDriftEvidenceSink` | `type` | `DatabricksOntologyDriftEvidenceSink` | Append-only audit sink for drift attestation records (design §5). Each `attestOntologyDrift` run appends exactly one record; the sink contract is append-only — historical records are never read back or rewritten here. | | `DatabricksOntologyDriftFinding` | `type` | `DatabricksOntologyDriftFinding` | One classified drift finding, carrying both references and steward-reviewable evidence. | | `DatabricksOntologyDriftFindingKind` | `type` | `DatabricksOntologyDriftFindingKind` | Drift finding taxonomy (design §4; P2-1 acceptance). | | `DatabricksOntologyDriftInferredReference` | `type` | `DatabricksOntologyDriftInferredReference` | Reference to the inferred side of a finding (from the knowledge store). | | `DatabricksOntologyDriftSeverity` | `type` | `DatabricksOntologyDriftSeverity` | Finding severity, encoding the §4 precedence: - `conflict` — the inference contradicts a declared definition (e.g. a learned synonym whose label collides with a different declared term than its target). The manifest stays authoritative; steward review required. - `analytics-only` — a tolerated inference mapped onto a declared definition; it may improve answer quality and never touches mutation semantics. - `informational` — no counterpart on one side; observation only. | | `DatabricksOntologyExportGenieOptions` | `type` | `DatabricksOntologyExportGenieOptions` | Genie Agent wiring for an ontology export. `admin` is the existing fingerprinted authoring client; `applyModuleOntologyExport` (`ontology-apply.ts`) routes every spec write through it with `expectedFingerprint` conflict detection. | | `DatabricksOntologyExportOptions` | `type` | `DatabricksOntologyExportOptions` | Configuration options for databricks ontology export. | | `DatabricksOntologyExportPlan` | `type` | `DatabricksOntologyExportPlan` | Deterministic export plan (design §3.2, KD-6). `metricViewDdl` and `policyClassifications` are populated by the P0-2/P0-3 generators (`ontology-metric-view.ts`); `glossaryTerms` and `domainAssignments` by the P0-4 generator (`ontology-glossary.ts`); `genieSpec` by the P0-5 derivation (`ontology-genie-spec.ts`, only when `options.genie` is present); `feedTables` by the P1-1 generator (`ontology-feed.ts`, only when `options.feed` is present). | | `DatabricksOntologyExportResult` | `type` | `DatabricksOntologyExportResult` | Apply outcome: applied artifacts, provenance record ids, and post-apply fingerprints. | | `DatabricksOntologyFeedHistory` | `type` | `DatabricksOntologyFeedHistory` | Recorded Platform history, grouped by feed table kind. | | `DatabricksOntologyFeedHydrationInput` | `type` | `DatabricksOntologyFeedHydrationInput` | Input for feed hydration planning. | | `DatabricksOntologyFeedHydrationPlan` | `type` | `DatabricksOntologyFeedHydrationPlan` | A deterministic feed hydration plan: merge-ready rows and statements per table. | | `DatabricksOntologyFeedOptions` | `type` | `DatabricksOntologyFeedOptions` | Feed planning options (design §3.7). The plan generator (`ontology-feed.ts`, P1-1) is pure and deterministic; the redacted-record producer is deliberately NOT a plan option — redaction is a runtime boundary owned by the vertical (P1-3) and a function here would break the plan's canonical fingerprint. Row materialization requires it instead. | | `DatabricksOntologyFeedRecordProducer` | `type` | `DatabricksOntologyFeedRecordProducer` | The vertical's redacted-record producer (P1-3) — the fabric-autorefi `redactActionParameters` pattern generalized to feed records. The producer receives one raw durable history record (AssetEvent, ActionInvocation, or PolicyEvaluation) and returns the redacted, publishable candidate. Harness defines no redaction policy of its own and never sees the producer's input again; only the producer's output is allowlist-projected. | | `DatabricksOntologyFeedTableHydration` | `type` | `DatabricksOntologyFeedTableHydration` | Hydration output for one feed table. | | `DatabricksOntologyFeedTableKind` | `type` | `DatabricksOntologyFeedTableKind` | Operational-truth feed tables a module can publish, per the exporter design §3.7. | | `DatabricksOntologyGlossaryPublisher` | `type` | `DatabricksOntologyGlossaryPublisher` | Glossary/domain publish client (design Q6: the UC glossary REST surface is still preview-tracked). Callers inject the governed client; when omitted, glossary and domain artifacts are reported as planned-but-unpublished and no glossary write occurs. | | `DatabricksOntologyModuleTarget` | `type` | `DatabricksOntologyModuleTarget` | Option-derived export target for one manifest, in bundle declaration order. | | `DatabricksOntologyPolicyClass` | `type` | `DatabricksOntologyPolicyClass` | Policy classification per design §3.4. | | `DatabricksOntologyPolicyClassification` | `type` | `DatabricksOntologyPolicyClassification` | Explainable classification record for one manifest policy (design §3.4). Classification is conservative: ambiguity defaults to a glossary business rule, and a compliance gate must never silently become a KPI. | | `DatabricksOntologyPolicyEvaluationRecord` | `type` | `DatabricksOntologyPolicyEvaluationRecord` | Minimal PolicyEvaluation record the feed pipeline consumes — decision, declared-safe reasons, evaluator identity/version, and failure mode; no facts payload beyond declared-safe fields (design §3.7). | | `DatabricksPermissionChange` | `type` | `DatabricksPermissionChange` | Type contract for databricks permission change. | | `databricksPersistence` | `value` | `(options: DatabricksPersistenceOptions) => DatabricksPersistence` | One-call Lakebase persistence for Databricks-hosted agents. See the package declarations for an example. The Postgres store implementations come from `@fabric-harness/node` (optional peer) and run unchanged against Lakebase — the only Databricks specifics are database-credential exchange, refresh caching, and TLS defaults from `lakebaseClient`. | | `DatabricksPersistence` | `type` | `DatabricksPersistence` | Everything the v2 runtime persists, on Lakebase, in one adapter: sessions (canonical conversation state), durable agent submissions (admission/FIFO/leases/settlement), and offset-addressable conversation streams. Implements the SDK `PersistenceAdapter` contract, so it plugs straight into `init({ persistence })`; the extra `connect*` methods feed `startDevServer({ submissionStore, conversationStreamStore })`. | | `DatabricksPersistenceOptions` | `type` | `DatabricksPersistenceOptions` | Configuration options for databricks persistence. | | `DatabricksPersistenceStoreModule` | `type` | `DatabricksPersistenceStoreModule` | The slice of `@fabric-harness/node` this adapter assembles. Loaded dynamically (node is an optional peer — Databricks Apps always run on Node, but this package stays importable without it); injectable for tests. | | `DatabricksPipelineLibrary` | `type` | `DatabricksPipelineLibrary` | Type contract for databricks pipeline library. | | `databricksPipelineListTool` | `value` | `(client: DatabricksPipelinesClient, options?: ToolMeta) => ToolDef<{ maxResults?: number; filter?: string; }, unknown>` | Lakeflow Declarative Pipelines (formerly DLT). These drive heavy continuous-compute consumption. `start`/`stop` mutate pipeline state (`effect: 'execute'`, governable); `list`/`status` are reads. | | `DatabricksPipelineRunPolicy` | `type` | `DatabricksPipelineRunPolicy` | Type contract for databricks pipeline run policy. | | `DatabricksPipelinesClient` | `type` | `DatabricksPipelinesClient` | Client implementation for databricks pipelines. | | `DatabricksPipelineSpec` | `type` | `DatabricksPipelineSpec` | Type contract for databricks pipeline spec. | | `databricksPipelineStartTool` | `value` | `(client: DatabricksPipelinesClient, runPolicy: DatabricksPipelineRunPolicy, options?: ToolMeta) => ToolDef<{ pipelineId: string; fullRefresh?: boolean; }, unknown>` | Model-callable tool or tool factory for databricks pipeline start. | | `databricksPipelineStatusTool` | `value` | `(client: DatabricksPipelinesClient, options?: ToolMeta) => ToolDef<{ pipelineId: string; }, unknown>` | Model-callable tool or tool factory for databricks pipeline status. | | `databricksPipelineStopTool` | `value` | `(client: DatabricksPipelinesClient, runPolicy: DatabricksPipelineRunPolicy, options?: ToolMeta) => ToolDef<{ pipelineId: string; }, unknown>` | Model-callable tool or tool factory for databricks pipeline stop. | | `DatabricksPlatformDomain` | `type` | `DatabricksPlatformDomain` | Type contract for databricks platform domain. | | `DatabricksPlatformDomainId` | `type` | `DatabricksPlatformDomainId` | Type contract for databricks platform domain id. | | `DatabricksPrincipal` | `type` | `DatabricksPrincipal` | Type contract for databricks principal. | | `DatabricksPrincipalEnvOptions` | `type` | `DatabricksPrincipalEnvOptions` | Configuration options for databricks principal env. | | `databricksPrincipalFromEnv` | `value` | `(env?: Record<string, string \| undefined>, options?: DatabricksPrincipalEnvOptions) => Extract<DatabricksPrincipal, { kind: "pat" \| "service-principal" \| "cli-profile"; }>` | Resolve a PAT or OAuth M2M principal consistently across CLIs, recipes, Apps, and tests. | | `DatabricksProvisionedThroughputEntity` | `type` | `DatabricksProvisionedThroughputEntity` | Type contract for databricks provisioned throughput entity. | | `DatabricksPythonWheelTaskSpec` | `type` | `DatabricksPythonWheelTaskSpec` | Type contract for databricks python wheel task spec. | | `databricksRagChain` | `value` | `(options: DatabricksRagChainOptions) => import("./rag-chain.js").DatabricksRagChain` | Cookbook-style online RAG chain over **native** Databricks AI Search + Model Serving. See the package declarations for an example. | | `DatabricksRagChain` | `type` | `DatabricksRagChain` | Type contract for databricks rag chain. | | `DatabricksRagChainOptions` | `type` | `DatabricksRagChainOptions` | Configuration options for databricks rag chain. | | `DatabricksRagChainResolvedOptions` | `type` | `DatabricksRagChainResolvedOptions` | Inputs once a bundle (or explicit retriever + model) is resolved. | | `DatabricksRagInput` | `type` | `DatabricksRagInput` | Type contract for databricks rag input. | | `DatabricksRagRetrievalOptions` | `type` | `DatabricksRagRetrievalOptions` | Configuration options for databricks rag retrieval. | | `DatabricksReleaseEvidenceValidation` | `type` | `DatabricksReleaseEvidenceValidation` | Type contract for databricks release evidence validation. | | `DatabricksRequestTags` | `type` | `DatabricksRequestTags` | Type contract for databricks request tags. | | `databricksResourceFingerprint` | `value` | `(value: unknown) => Promise<string>` | Runtime API for databricks resource fingerprint; the generated signature shows its accepted inputs and return type. | | `DatabricksResourceNotAllowedError` | `value` | `typeof DatabricksResourceNotAllowedError` | Error raised for databricks resource not allowed failures. | | `DatabricksResponsesContent` | `type` | `DatabricksResponsesContent` | Type contract for databricks responses content. | | `DatabricksResponsesOutputItem` | `type` | `DatabricksResponsesOutputItem` | Type contract for databricks responses output item. | | `databricksResponsesText` | `value` | `(response: DatabricksAgentEndpointResponse) => string` | Runtime API for databricks responses text; the generated signature shows its accepted inputs and return type. | | `DatabricksRollingEvidenceReport` | `type` | `DatabricksRollingEvidenceReport` | Type contract for databricks rolling evidence report. | | `databricksRunJobTool` | `value` | `(client: DatabricksJobsClient, runPolicy: DatabricksJobRunPolicy, options?: { name?: string; description?: string; }) => ToolDef<{ jobId: number; idempotencyToken?: string; notebookParams?: JsonObject; pythonParams?: string[]; jarParams?: string[]; },...` | Trigger an existing Databricks job. `runPolicy` is required: the run target is model-supplied, so the bound is part of constructing the tool rather than an option a caller can forget. The pinned schema is a model-facing hint; `databricksJobs()` re-checks the id before calling the Jobs API. | | `DatabricksRunLifeCycleState` | `type` | `string` | Type contract for databricks run life cycle state. | | `DatabricksRunNotAllowedError` | `value` | `typeof DatabricksRunNotAllowedError` | Raised before the Jobs API is called when a run target falls outside the configured bound. | | `DatabricksRunOutput` | `type` | `DatabricksRunOutput` | Type contract for databricks run output. | | `DatabricksRunReceipt` | `type` | `DatabricksRunReceipt` | Type contract for databricks run receipt. | | `DatabricksRunResultState` | `type` | `string` | Type contract for databricks run result state. | | `DatabricksRunState` | `type` | `DatabricksRunState` | Type contract for databricks run state. | | `DatabricksRunTimeoutError` | `value` | `typeof DatabricksRunTimeoutError` | Error raised for databricks run timeout failures. | | `databricksSdk` | `value` | `(options: DatabricksSdkOptions) => DatabricksSdkClients` | Build the official modular Databricks SDK clients under one governed identity. SDK-gap protocols remain private to Fabric's explicit raw protocol adapters. | | `DatabricksSdkClients` | `type` | `DatabricksSdkClients` | Generated Databricks service clients exposed to application code. | | `DatabricksSdkOptions` | `type` | `DatabricksSdkOptions` | Configuration options for databricks sdk. | | `DatabricksSearchIndexSpec` | `type` | `DatabricksSearchIndexSpec` | Type contract for databricks search index spec. | | `DatabricksSecretsAuthoring` | `value` | `typeof DatabricksSecretsAuthoring` | Runtime API for databricks secrets authoring; the generated signature shows its accepted inputs and return type. | | `databricksSecretsAuthoringTools` | `value` | `(client: DatabricksSecretsClient, provider: SecretProvider) => ToolDef[]` | Runtime API for databricks secrets authoring tools; the generated signature shows its accepted inputs and return type. | | `databricksSecretsProvider` | `value` | `(options: DatabricksSecretsProviderOptions) => SecretProvider` | Databricks Secret Management adapter. Secret values are decoded only at runtime. | | `DatabricksSecretsProviderOptions` | `type` | `DatabricksSecretsProviderOptions` | Configuration options for databricks secrets provider. | | `DatabricksSecurableType` | `type` | `DatabricksSecurableType` | Type contract for databricks securable type. | | `DatabricksServingAdmin` | `value` | `typeof DatabricksServingAdmin` | Runtime API for databricks serving admin; the generated signature shows its accepted inputs and return type. | | `databricksServingAdminTools` | `value` | `(client: DatabricksServingAdminClient) => ToolDef[]` | Runtime API for databricks serving admin tools; the generated signature shows its accepted inputs and return type. | | `DatabricksServingEndpointSpec` | `type` | `DatabricksServingEndpointSpec` | Type contract for databricks serving endpoint spec. | | `DatabricksSparkJarTaskSpec` | `type` | `DatabricksSparkJarTaskSpec` | Type contract for databricks spark jar task spec. | | `DatabricksSqlClient` | `type` | `DatabricksSqlClient` | Client implementation for databricks sql. | | `DatabricksSqlExecutionPolicy` | `type` | `DatabricksSqlExecutionPolicy` | Type contract for databricks sql execution policy. | | `databricksSqlReadTool` | `value` | `(client: DatabricksSqlClient, options: DatabricksSqlReadToolOptions) => ToolDef<{ statement: string; catalog?: string; schema?: string; }, unknown>` | Run one read-only query on a Databricks SQL Warehouse. The tool accepts SELECT (including SELECT-ending CTEs), rejects mutation/administration keywords, and denies multiple statements before resolving credentials or calling Statement Execution. | | `DatabricksSqlReadToolOptions` | `type` | `DatabricksSqlToolOptions` | Configuration options for databricks sql read tool. | | `databricksSqlSandbox` | `value` | `(options: DatabricksSqlSandboxOptions) => SandboxEnv` | Sandbox adapter for databricks sql. | | `DatabricksSqlSandboxOptions` | `type` | `DatabricksSqlSandboxOptions` | Sandbox backend that maps `exec(command)` to a Databricks SQL Statement Execution API call against a SQL Warehouse. Useful for data agents whose "shell" is a query interface. Behavior: - `exec(sql)` runs the SQL synchronously (with a timeout) and returns the serialized result set as `stdout` (newline-delimited JSON rows by default, or CSV when `resultFormat: 'csv'`). - File operations are intentionally minimal: the sandbox-virtual filesystem keeps a small in-memory map. SQL warehouses are not file servers; mount actual data via `databricksVolumeSource` from `@fabric-harness/connectors`. Usa... | | `DatabricksSqlSandboxRefData` | `type` | `DatabricksSqlSandboxRefData` | Type contract for databricks sql sandbox ref data. | | `DatabricksSqlSandboxRegistrationOptions` | `type` | `DatabricksSqlSandboxRegistrationOptions` | Configuration options for databricks sql sandbox registration. | | `DatabricksSqlStatementInput` | `type` | `DatabricksSqlStatementInput` | Type contract for databricks sql statement input. | | `DatabricksSqlTaskSpec` | `type` | `DatabricksSqlTaskSpec` | Type contract for databricks sql task spec. | | `databricksSqlTool` | `value` | `(client: DatabricksSqlClient, policy: DatabricksSqlExecutionPolicy, options: DatabricksSqlToolOptions) => ToolDef<DatabricksSqlStatementInput, unknown>` | Model-callable tool or tool factory for databricks sql. | | `DatabricksSqlToolOptions` | `type` | `DatabricksSqlToolOptions` | Configuration options for databricks sql tool. | | `DatabricksSqlWarehouse` | `type` | `DatabricksSqlWarehouse` | Type contract for databricks sql warehouse. | | `DatabricksStatementClient` | `type` | `DatabricksStatementClient` | Client implementation for databricks statement. | | `DatabricksSupervisorAgentListOptions` | `type` | `DatabricksSupervisorAgentListOptions` | Configuration options for databricks supervisor agent list. | | `databricksSupervisorAgents` | `value` | `(sdk: SupervisorAgentsClient, endpoints: DatabricksAgentEndpointClient, options: DatabricksSupervisorAgentsOptions) => DatabricksSupervisorAgents` | Runtime API for databricks supervisor agents; the generated signature shows its accepted inputs and return type. | | `DatabricksSupervisorAgents` | `value` | `typeof DatabricksSupervisorAgents` | Guarded composition boundary over the official generated Supervisor Agents SDK. | | `DatabricksSupervisorAgentsOptions` | `type` | `DatabricksSupervisorAgentsOptions` | Configuration options for databricks supervisor agents. | | `DatabricksSupportTier` | `type` | `DatabricksSupportTier` | Type contract for databricks support tier. | | `databricksTableInfoTool` | `value` | `(client: DatabricksTablesClient, options?: { name?: string; description?: string; }) => ToolDef<{ fullName: string; }, unknown>` | Model-callable tool or tool factory for databricks table info. | | `databricksTelemetry` | `value` | `(options: DatabricksTelemetryOptions) => DatabricksTelemetry` | Runtime API for databricks telemetry; the generated signature shows its accepted inputs and return type. | | `DatabricksTelemetry` | `type` | `DatabricksTelemetry` | Type contract for databricks telemetry. | | `DatabricksTelemetryOptions` | `type` | `DatabricksTelemetryOptions` | Cost + lineage as core telemetry (v2, workstream C4): submission lifecycle events and governed tool-call lineage land in Lakebase tables keyed by the same `submissionId` that drives events, settlement, and audit — so spend, lineage, and outcomes join on one stable key. Writes are fire-and-forget: a telemetry failure must never affect execution. | | `databricksTenantCostLimit` | `value` | `(client: DatabricksStatementClient, warehouseId: string, tenantId: string, options: { perHourUsd?: number; perDayUsd?: number; perMonthUsd?: number; cacheTtlMs?: number; onExceed?: "throw" \| "approve"; }) => CostLimit` | Runtime API for databricks tenant cost limit; the generated signature shows its accepted inputs and return type. | | `DatabricksTokenProvider` | `type` | `DatabricksTokenProvider` | A bearer-token resolver awaited per request. Fabric uses the same native-SDK credential across generated service clients, model calls, preview streaming, and Lakebase credential exchange. | | `DatabricksTransientServingRetryOptions` | `type` | `DatabricksTransientServingRetryOptions` | Configuration options for databricks transient serving retry. | | `DatabricksUnityCatalogAdmin` | `value` | `typeof DatabricksUnityCatalogAdmin` | Runtime API for databricks unity catalog admin; the generated signature shows its accepted inputs and return type. | | `databricksUnityCatalogAdminTools` | `value` | `(client: DatabricksUnityCatalogAdminClients, options?: { destructive?: boolean; }) => ToolDef[]` | Runtime API for databricks unity catalog admin tools; the generated signature shows its accepted inputs and return type. | | `DatabricksUnmanagedResourceError` | `value` | `typeof DatabricksUnmanagedResourceError` | Error raised for databricks unmanaged resource failures. | | `DatabricksUpstreamMaturity` | `type` | `DatabricksUpstreamMaturity` | Type contract for databricks upstream maturity. | | `databricksWithManagedMcp` | `value` | `(config: DatabricksBundleConfig, scope?: { tokenProvider: DatabricksTokenProvider; principal: FabricPrincipal; }) => Promise<DatabricksManagedMcpBundle>` | Build a Databricks bundle after discovering and classifying managed MCP tools. | | `databricksWorkspaceApi` | `value` | `(options: DatabricksWorkspaceApiOptions) => DatabricksWorkspaceApi` | Runtime API for databricks workspace api; the generated signature shows its accepted inputs and return type. | | `DatabricksWorkspaceApi` | `type` | `DatabricksWorkspaceApi` | Credential-safe native Databricks REST escape hatch. Prefer the generated clients from `databricksSdk` when one exists. This client preserves access to newly released or uncommon Databricks APIs without waiting for a Harness wrapper. It is deliberately not a model tool: applications must validate requests and place governed mutations behind their own explicit tool/action boundary. | | `DatabricksWorkspaceApiMethod` | `type` | `DatabricksWorkspaceApiMethod` | Type contract for databricks workspace api method. | | `DatabricksWorkspaceApiOptions` | `type` | `DatabricksWorkspaceApiOptions` | Configuration options for databricks workspace api. | | `DatabricksWorkspaceApiRequestOptions` | `type` | `DatabricksWorkspaceApiRequestOptions` | Configuration options for databricks workspace api request. | | `DatabricksWorkspaceCompatibilityRecord` | `type` | `DatabricksWorkspaceCompatibilityRecord` | Type contract for databricks workspace compatibility record. | | `databricksWorkspaceOrigin` | `value` | `(host: string) => string` | Normalize a workspace hostname or URL to its HTTPS origin. | | `DatabricksWorkspaceSourceOptions` | `type` | `DatabricksWorkspaceSourceOptions` | Configuration options for databricks workspace source. | | `defaultDatabricksCertificationChecks` | `value` | `(options?: { agentServices?: boolean; authoring?: boolean; }) => string[]` | Required checks used by the protected Databricks certification workflow. | | `defineDatabricksAgent` | `value` | `<TInput = JsonObject, TOutput = unknown>(options?: DefineDatabricksAgentOptions<TInput, TOutput>) => DefinedAgent<TInput, TOutput>` | Defines databricks agent. | | `DefineDatabricksAgentOptions` | `type` | `DefineDatabricksAgentOptions<TInput, TOutput>` | Configuration options for define databricks agent. | | `deployDatabricksAppArtifact` | `value` | `(options: DeployDatabricksAppArtifactOptions) => Promise<DeployDatabricksAppArtifactResult>` | Deploy an already-built TechFabric Harness Databricks App artifact. This is the programmatic counterpart of `fh deploy --target databricks-app`. It intentionally does not rebuild the artifact: release orchestrators can verify the immutable digest first, then use this function for the Databricks side effect. | | `DeployDatabricksAppArtifactOptions` | `type` | `DeployDatabricksAppArtifactOptions` | Configuration options for deploy databricks app artifact. | | `DeployDatabricksAppArtifactResult` | `type` | `DeployDatabricksAppArtifactResult` | Result returned by deploy databricks app artifact. | | `destroyDatabricksAppArtifact` | `value` | `(options: DestroyDatabricksAppArtifactOptions) => Promise<DestroyDatabricksAppArtifactResult>` | Destroy only resources declared by an already-built Databricks App bundle. | | `DestroyDatabricksAppArtifactOptions` | `type` | `DestroyDatabricksAppArtifactOptions` | Configuration options for destroy databricks app artifact. | | `DestroyDatabricksAppArtifactResult` | `type` | `DestroyDatabricksAppArtifactResult` | Result returned by destroy databricks app artifact. | | `digestDatabricksArtifact` | `value` | `(target: string) => Promise<string>` | Digest a release artifact using the standard SHA-256 file digest. Directory targets use a deterministic, tagged tree digest so deployment bundles can be certified without archiving them. | | `ensureDatabricksTelemetryTables` | `value` | `(client: LakebaseClient) => Promise<void>` | Create the telemetry tables when absent. Idempotent. | | `exportAgentEvaluationJsonl` | `value` | `(records: LegacyAgentEvaluationRecord[]) => string` | Serialize evaluation records as JSONL for MLflow / Agent Evaluation import. | | `exportMlflow3EvaluationJsonl` | `value` | `(records: Mlflow3RagEvaluationRecord[]) => string` | Serialize structured MLflow 3 evaluation rows as newline-delimited JSON. | | `extractDatabricksGovernedResources` | `value` | `(tool: ToolDef, input: unknown) => DatabricksGovernedResource[]` | Runtime API for extract databricks governed resources; the generated signature shows its accepted inputs and return type. | | `fabricPrincipalFor` | `value` | `(principal: DatabricksPrincipal, overrides?: FabricPrincipalOverrides) => FabricPrincipal` | Map a Databricks principal onto the SDK's `FabricPrincipal` so the governed identity rides submissions → tool calls → lineage/cost records. Never carries a token — ids and labels only. | | `FabricPrincipalOverrides` | `type` | `FabricPrincipalOverrides` | Type contract for fabric principal overrides. | | `getDatabricksCapability` | `value` | `(id: string) => DatabricksCapability \| undefined` | Returns databricks capability. | | `governanceMetadata` | `value` | `(tool: ToolDef) => DatabricksGovernanceMetadata \| undefined` | Runtime API for governance metadata; the generated signature shows its accepted inputs and return type. | | `inferenceTableUsageQuery` | `value` | `(options: InferenceTableUsageQueryOptions) => string` | SQL aggregating a serving endpoint's inference/payload table by `client_request_id` — one row per submission with the request count and the first/last request timestamps — for offline joins against `fh_submission_telemetry.submission_id`. Join contract: callers MUST send the submission id as the serving request's `client_request_id` (e.g. the `client_request_id` field on the serving-endpoint invocation) — the inference table records it verbatim, and this query's `submission_id` column only joins when that convention holds. Rows without a `client_request_id` (traffic from other callers) are... | | `InferenceTableUsageQueryOptions` | `type` | `InferenceTableUsageQueryOptions` | Configuration options for inference table usage query. | | `inspectDatabricksAppUserAuthorization` | `value` | `(options: { headers: Headers \| Record<string, string \| string[] \| undefined>; host: string; fetchImpl?: typeof fetch; now?: () => number; }) => Promise<DatabricksAppUserAuthorizationInspection>` | Validate a Databricks Apps forwarded user token and return non-secret identity/lifetime metadata suitable for OBO lifecycle certification. The access token is never returned or included in an error. | | `isDatabricksModelService` | `value` | `(model: string \| undefined) => boolean` | True for Unity Catalog model-service identifiers accepted by Unity AI Gateway. | | `isTransientDatabricksServingError` | `value` | `(error: unknown) => boolean` | True for failures a patient read-only caller can outlast: HTTP 429/5xx and transport-level failures (for example undici `fetch failed`) that carry no HTTP status. Client errors such as 400/401/403/404 are permanent and are not retried. | | `lakebaseClient` | `value` | `(options: LakebaseClientOptions) => LakebaseClient` | Client implementation for lakebase. | | `LakebaseClient` | `type` | `LakebaseClient` | Client implementation for lakebase. | | `LakebaseClientOptions` | `type` | `LakebaseClientOptions` | Configuration options for lakebase client. | | `lakebaseCredentialProvider` | `value` | `(options: LakebaseCredentialProviderOptions) => () => Promise<string>` | Exchange a workspace OAuth token for a Lakebase database credential. The result is cached, refreshed early with jitter, and refreshes are single-flight. | | `LakebaseCredentialProviderOptions` | `type` | `LakebaseCredentialProviderOptions` | Configuration options for lakebase credential provider. | | `LakebaseDatabricksManagedResourceStore` | `value` | `typeof LakebaseDatabricksManagedResourceStore` | Durable managed-resource manifest backed by Lakebase or ordinary PostgreSQL. | | `LakebaseDatabricksManagedResourceStoreOptions` | `type` | `LakebaseDatabricksManagedResourceStoreOptions` | Configuration options for lakebase databricks managed resource store. | | `LakebasePoolConfig` | `type` | `LakebasePoolConfig` | Type contract for lakebase pool config. | | `LakebasePoolFactory` | `type` | `LakebasePoolFactory` | Factory for lakebase pool. | | `LegacyAgentEvaluationRecord` | `type` | `LegacyAgentEvaluationRecord` | One row in the shape commonly used with Databricks / MLflow GenAI evaluation tables (request / response / retrieved_context). This is an **export** for Mosaic Agent Evaluation and notebooks — not a reimplementation of judges. | | `listDatabricksCapabilities` | `value` | `(options?: { status?: DatabricksCapabilityStatus; tier?: DatabricksSupportTier; apiFidelity?: DatabricksApiFidelity; domain?: DatabricksPlatformDomainId; }) => DatabricksCapability[]` | Lists databricks capabilities. | | `MemoryDatabricksManagedResourceStore` | `value` | `typeof MemoryDatabricksManagedResourceStore` | In-process store for tests and single-process development. Production callers should inject persistence. | | `missingDatabricksCapabilityEvidence` | `value` | `(capability: DatabricksCapability, evidence?: readonly DatabricksCapabilityEvidenceReference[]) => string[]` | Runtime API for missing databricks capability evidence; the generated signature shows its accepted inputs and return type. | | `Mlflow3RagEvaluationRecord` | `type` | `Mlflow3RagEvaluationRecord` | MLflow 3 evaluation-dataset row with structured inputs, outputs, and expectations. | | `MlflowTraceExporter` | `type` | `MlflowTraceExporter` | Type contract for mlflow trace exporter. | | `MlflowTraceInput` | `type` | `MlflowTraceInput` | Type contract for mlflow trace input. | | `MlflowTracePayload` | `type` | `MlflowTracePayload` | Type contract for mlflow trace payload. | | `MockDatabricksModelProvider` | `value` | `typeof MockDatabricksModelProvider` | A deterministic `ModelProvider` for Databricks agent tests and init templates. Returns structured responses for SQL/table-info tool calls without requiring real Databricks credentials. | | `MockDatabricksModelProviderOptions` | `type` | `MockDatabricksModelProviderOptions` | Configuration options for mock databricks model provider. | | `normalizeDatabricksGenieAgentSpec` | `value` | `(spec: DatabricksGenieAgentSpecV2) => Promise<DatabricksGenieAgentSpecV2>` | Runtime API for normalize databricks genie agent spec; the generated signature shows its accepted inputs and return type. | | `normalizeModuleManifests` | `value` | `(manifest: ModuleManifest \| ModuleManifestBundle) => ModuleManifest[]` | Normalize a manifest or bundle into a declaration-ordered manifest list. | | `onBehalfOfFromHeaders` | `value` | `(headers: Headers \| Record<string, string \| string[] \| undefined>) => Extract<DatabricksPrincipal, { kind: "on-behalf-of"; }> \| undefined` | On-behalf-of principal from Databricks Apps user-authorization headers: the platform forwards the signed-in user's access token as `x-forwarded-access-token` (plus `x-forwarded-email`/`x-forwarded-user`). Returns `undefined` when the request carries no user token (e.g. app service-to-service traffic) so callers fall back to the app principal. | | `parseStatementRows` | `value` | `(response: unknown) => JsonObject[]` | Map a statement response's columns + rows into objects keyed by column name. | | `planModuleOntologyExport` | `value` | `(options: DatabricksOntologyExportOptions) => Promise<DatabricksOntologyExportPlan>` | Build the deterministic ontology export plan. Pure: no network, no clock, no randomness — identical inputs produce a byte-identical plan. Async only because the canonical fingerprint helper (`databricksResourceFingerprint`, SHA-256 over canonical JSON) is async; the computation itself is a pure function of `options`. | | `planOntologyFeedHydration` | `value` | `(input: DatabricksOntologyFeedHydrationInput) => Promise<DatabricksOntologyFeedHydrationPlan>` | Plan replay-safe hydration of recorded Platform history into the module's feed tables. Pure and credential-free: identical inputs produce a byte-identical plan, and applying the emitted `MERGE` statements is idempotent by construction (`WHEN NOT MATCHED THEN INSERT` on the replay key). Live execution is the caller's wiring — run each statement through the governed statement seam with a per-tenant service-principal client (design §5), exactly as the P0-6 apply path executes feed DDL. | | `queryDatabricksLineageEvidence` | `value` | `(client: LakebaseClient, submissionId: string) => Promise<DatabricksLineageEvidenceRow[]>` | Join governed object access to the submission actor, outcome, and model/tool cost. | | `RagChainPostProcessOptions` | `type` | `RagChainPostProcessOptions` | Configuration options for rag chain post process. | | `RagChainPromptOptions` | `type` | `RagChainPromptOptions` | Configuration options for rag chain prompt. | | `RagEvalExpected` | `type` | `RagEvalExpected` | Type contract for rag eval expected. | | `RagPreprocess` | `type` | `RagPreprocess` | Type contract for rag preprocess. | | `RagStreamEvent` | `type` | `RagStreamEvent` | Incremental event from `DatabricksRagChain.stream`. `delta` events carry raw first-pass model output for live UI. They are emitted **before** citation validation, bounded repair, truncation, and the sources footer run, so the concatenated deltas may differ from the final validated answer. The terminal `turn` event is authoritative — use it for persistence, evaluation export, and cost telemetry, exactly like the SDK's `ModelStreamChunk.done` contract. | | `RagTurn` | `type` | `RagTurn` | Structured result of one online RAG inference turn. Mirrors the Databricks AI Cookbook chain: preprocess → retrieve (AI Search) → prompt augment → generate → post-process. Fabric does **not** reimplement AI Search or Model Serving — this is a thin orchestration over native Databricks APIs already exposed by this package. | | `ragTurnCitationsScorer` | `value` | `(name?: string) => (input: { output: RagTurn; }) => RagTurnScore` | Runtime API for rag turn citations scorer; the generated signature shows its accepted inputs and return type. | | `ragTurnContainsScorer` | `value` | `(name?: string) => (input: { case: { expected?: RagEvalExpected \| string; }; output: RagTurn; }) => RagTurnScore` | Adapter for `@fabric-harness/evals` scorers when the suite output is a `RagTurn`. Keep heavy quality judges in Databricks Agent Evaluation; use these for CI smoke. | | `RagTurnScore` | `type` | `RagTurnScore` | Type contract for rag turn score. | | `reconcileDatabricksCost` | `value` | `(options: DatabricksCostReconciliationOptions) => Promise<DatabricksCostReconciliationResult>` | Compare immediate estimates with delayed System Tables actuals and apply an explicit outage policy. | | `registerDatabricksModelProvider` | `value` | `() => void` | Register `databricks/<model>` model references. | | `registerDatabricksSqlSandboxBackend` | `value` | `(registration?: DatabricksSqlSandboxRegistrationOptions) => void` | Register `sandbox: 'databricks'` and its credential-safe portable-ref decoder. | | `requireDatabricksManagedResource` | `value` | `(input: { store: DatabricksManagedResourceStore; resourceType: string; resourceId: string; expectedFingerprint?: string; }) => Promise<DatabricksManagedResourceRecord>` | Runtime API for require databricks managed resource; the generated signature shows its accepted inputs and return type. | | `resolveDatabricksRequiredChecks` | `value` | `(requiredTiers: readonly DatabricksCertificationBlockingTier[], explicitlyRequired?: readonly string[]) => string[]` | Resolve blocking-tier checks plus explicit additions. Explicit ids never remove tier defaults. | | `resolveToolRefs` | `value` | `(bundle: DatabricksBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | | `retryDatabricksTransientServingRead` | `value` | `<T>(call: () => Promise<T>, options?: DatabricksTransientServingRetryOptions) => Promise<T>` | Retry a read-only serving call through scale-to-zero cold starts. Feature Serving endpoints configured with `scale_to_zero_enabled` report READY while scaled down, and the first queries after an idle window can fail at the transport layer or with 5xx for minutes while the endpoint scales back up. The default schedule waits at most ~3 minutes across 7 attempts. | | `runDatabricksAuthoringLifecycle` | `value` | `<Resource, Mutation = Resource>(lifecycle: DatabricksAuthoringLifecycle<Resource, Mutation>, ledger?: DatabricksCertificationCleanupLedger) => Promise<DatabricksAuthoringLifecycleEvidence>` | Exercise a destructive authoring capability with mandatory verification and reverse-order cleanup. Callers should perform each operation through the same governed ToolDef path used in production. | | `runDatabricksCertification` | `value` | `(options: RunDatabricksCertificationOptions) => Promise<DatabricksCertificationEvidence>` | Run live capability checks and produce stable, secret-redacted CI evidence. | | `RunDatabricksCertificationOptions` | `type` | `RunDatabricksCertificationOptions` | Configuration options for run databricks certification. | | `runDatabricksCommand` | `value` | `(command: string, args: readonly string[], options: { cwd: string; env: NodeJS.ProcessEnv; }) => Promise<DatabricksCommandResult>` | Runs databricks command. | | `RunDatabricksJobInput` | `type` | `RunDatabricksJobInput` | Type contract for run databricks job input. | | `runStatement` | `value` | `(client: DatabricksStatementClient, warehouseId: string, statement: string, parameters: SqlParameter[], poll: StatementPoll) => Promise<unknown>` | Submit a parameterized SQL statement and poll to a terminal state. Named parameters → injection-safe. | | `scoreRagTurn` | `value` | `(turn: RagTurn, expected?: RagEvalExpected) => RagTurnScore[]` | Lightweight local checks before/alongside Databricks Agent Evaluation. | | `serializeDatabricksGenieAgentSpec` | `value` | `(spec: DatabricksGenieAgentSpecV2) => Promise<string>` | Serializes databricks genie agent spec. | | `servingUsageCapture` | `value` | `(options: ServingUsageCaptureOptions) => (event: FabricEvent) => void` | Build an `onEvent` fan-in that turns model-usage events into `submission_usage` telemetry. For every `FabricEvent` carrying `data.usage` (`{ inputTokens?, outputTokens?, costUsd? }`, at least one numeric field) — and optionally `data.model` — while an ambient `currentSubmissionContext` is set, it emits one `submission_usage` event stamped with the submission correlation (submission/attempt ids, agent identity, tenant, actor). Events observed outside a submission context are dropped silently — not every session turn belongs to a submission. The submission context does not carry the... | | `ServingUsageCaptureOptions` | `type` | `ServingUsageCaptureOptions` | Serving usage capture (v2 migration, workstream C7): attribute model/serving spend to submissions through the ambient submission context. | | `SqlParameter` | `type` | `SqlParameter` | Type contract for sql parameter. | | `StatementPoll` | `type` | `StatementPoll` | Type contract for statement poll. | | `SubmitDatabricksNotebookInput` | `type` | `SubmitDatabricksNotebookInput` | Type contract for submit databricks notebook input. | | `sweepDatabricksAuthoringCertification` | `value` | `(clients: DatabricksCertificationSweepClients, options?: DatabricksCertificationSweepOptions) => Promise<DatabricksCertificationSweepResult>` | Remove only resources carrying the reserved protected-certification prefix. | | `sweepDatabricksAuthoringCertificationWorkspace` | `value` | `(options: DatabricksCertificationWorkspaceSweepOptions) => Promise<DatabricksCertificationSweepResult>` | Build the official generated clients plus the private Workspace-object adapter and sweep one workspace. This is the supported operational entrypoint; callers never construct raw transport. | | `toAgentEvaluationRecord` | `value` | `(turn: RagTurn, options?: { expectedAnswer?: string; tags?: Record<string, string>; }) => LegacyAgentEvaluationRecord` | Convert a `RagTurn` into a Databricks-friendly evaluation record. Upload JSONL of these rows to MLflow / Agent Evaluation rather than building a parallel judge stack in Fabric. | | `toMlflow3EvaluationRecord` | `value` | `(turn: RagTurn, options?: { expectedAnswer?: string; expectedRetrievedContext?: Array<{ doc_uri?: string; content: string; }>; tags?: Record<string, string>; traceId?: string; submissionId?: string; }) => Mlflow3RagEvaluationRecord` | Convert a RAG turn into the structured MLflow 3 evaluation-dataset shape. | | `UcVolumesAttachmentStore` | `value` | `typeof UcVolumesAttachmentStore` | Storage contract for uc volumes attachment. | | `UcVolumesAttachmentStoreOptions` | `type` | `UcVolumesAttachmentStoreOptions` | Unity Catalog Volumes attachment backend (v2 migration, workstream C2). Implements the SDK `AttachmentStore` contract on a UC Volume via the Databricks Files API, so attachment bytes are governed by Unity Catalog grants like every other Databricks asset. Layout under the volume: See the package declarations for an example. The bare `<digest>` file holds the raw bytes; the `<digest>.json` sidecar holds the `AttachmentRef` metadata and doubles as the record's existence marker: `put` is first-write-wins per `(scope, digest)` — when the sidecar already exists the put is a no-op, so... | | `unityCatalogTablesTool` | `value` | `(client: DatabricksTablesClient, options?: { name?: string; description?: string; }) => ToolDef<{ catalog: string; schema: string; }, unknown>` | Model-callable tool or tool factory for unity catalog tables. | | `unregisterDatabricksSqlSandboxBackend` | `value` | `() => void` | Remove both process-local registrations, primarily for tests and controlled shutdown. | | `validateDatabricksAppArtifact` | `value` | `(options: ValidateDatabricksAppArtifactOptions) => Promise<ValidateDatabricksAppArtifactResult>` | Validate an already-built Databricks App artifact without mutating the workspace. | | `ValidateDatabricksAppArtifactOptions` | `type` | `ValidateDatabricksAppArtifactOptions` | Configuration options for validate databricks app artifact. | | `ValidateDatabricksAppArtifactResult` | `type` | `ValidateDatabricksAppArtifactResult` | Result returned by validate databricks app artifact. | | `validateDatabricksAppRecoveryEvidence` | `value` | `(evidence: DatabricksAppRecoveryEvidence) => void` | Assert that App restart evidence proves durable state, approval recovery, and cascade cleanup. | | `validateDatabricksAppUserIsolationEvidence` | `value` | `(evidence: DatabricksAppUserIsolationEvidence) => void` | Assert that retained App evidence proves distinct principals and cross-user denial. | | `validateDatabricksCertificationEnvironment` | `value` | `(environment: Environment, requiredChecks: readonly string[]) => DatabricksCertificationEnvironmentIssue[]` | Return actionable, secret-free preflight failures for a protected certification environment. The certification runner remains authoritative for runtime configuration and service behavior. | | `validateDatabricksComputePolicy` | `value` | `(policy: DatabricksComputePolicy) => void` | Runtime API for validate databricks compute policy; the generated signature shows its accepted inputs and return type. | | `validateDatabricksCrossTierEvidence` | `value` | `(options: ValidateDatabricksCrossTierEvidenceOptions) => DatabricksCrossTierEvidenceManifest` | Fail closed unless Tier R and Tier A exercised the same immutable package tarball and commit. | | `ValidateDatabricksCrossTierEvidenceOptions` | `type` | `ValidateDatabricksCrossTierEvidenceOptions` | Configuration options for validate databricks cross tier evidence. | | `validateDatabricksDynamicAgentEvidence` | `value` | `(evidence: DatabricksDynamicAgentEvidence) => void` | Assert that Tier R exercised hook-authored agents across a real App restart. | | `validateDatabricksGenieSqlReferences` | `value` | `(spec: DatabricksGenieAgentSpecV2, policy: DatabricksGenieSqlPolicy) => Promise<void>` | Runtime API for validate databricks genie sql references; the generated signature shows its accepted inputs and return type. | | `validateDatabricksGovernanceDescriptor` | `value` | `(tool: ToolDef, required?: boolean) => void` | Validate descriptor syntax and that each path can be traversed in the declared input schema. | | `validateDatabricksJobRunPolicy` | `value` | `(policy: DatabricksJobRunPolicy) => void` | Runtime API for validate databricks job run policy; the generated signature shows its accepted inputs and return type. | | `validateDatabricksNotebookRunPolicy` | `value` | `(policy: DatabricksNotebookRunPolicy) => void` | Runtime API for validate databricks notebook run policy; the generated signature shows its accepted inputs and return type. | | `validateDatabricksReleaseEvidence` | `value` | `(options: ValidateDatabricksReleaseEvidenceOptions) => DatabricksReleaseEvidenceValidation` | Fail closed unless retained Databricks evidence proves the exact release commit and artifacts. | | `ValidateDatabricksReleaseEvidenceOptions` | `type` | `ValidateDatabricksReleaseEvidenceOptions` | Configuration options for validate databricks release evidence. | | `validateDatabricksRollingEvidence` | `value` | `(options: ValidateDatabricksRollingEvidenceOptions) => DatabricksRollingEvidenceReport` | Require daily Tier R evidence plus at least two same-candidate Tier R/A proofs in the rolling public-claim window. Every Tier R record must bind two-user App isolation. | | `ValidateDatabricksRollingEvidenceOptions` | `type` | `ValidateDatabricksRollingEvidenceOptions` | Configuration options for validate databricks rolling evidence. | | `validateJobSpec` | `value` | `(spec: DatabricksJobSpec, policy: DatabricksComputePolicy) => void` | Runtime API for validate job spec; the generated signature shows its accepted inputs and return type. | | `withGovernance` | `value` | `<I, O>(tool: ToolDef<I, O>, options?: DatabricksGovernanceOptions) => ToolDef<I, O>` | Wraps one Databricks tool to stamp lineage/audit and enforce the optional catalog allowlist. | | `withGovernanceTools` | `value` | `(tools: ToolDef[], options?: DatabricksGovernanceOptions) => ToolDef[]` | Wraps a set of Databricks tools with `withGovernance`. | ### `@fabric-harness/databricks/agent` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `defineDatabricksAgent` | `value` | `<TInput = JsonObject, TOutput = unknown>(options?: DefineDatabricksAgentOptions<TInput, TOutput>) => DefinedAgent<TInput, TOutput>` | Defines databricks agent. | | `DefineDatabricksAgentOptions` | `type` | `DefineDatabricksAgentOptions<TInput, TOutput>` | Configuration options for define databricks agent. | | `resolveToolRefs` | `value` | `(bundle: DatabricksBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | ### `@fabric-harness/databricks/sql-sandbox` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `databricksSqlSandbox` | `value` | `(options: DatabricksSqlSandboxOptions) => SandboxEnv` | Sandbox adapter for databricks sql. | | `DatabricksSqlSandboxOptions` | `type` | `DatabricksSqlSandboxOptions` | Sandbox backend that maps `exec(command)` to a Databricks SQL Statement Execution API call against a SQL Warehouse. Useful for data agents whose "shell" is a query interface. Behavior: - `exec(sql)` runs the SQL synchronously (with a timeout) and returns the serialized result set as `stdout` (newline-delimited JSON rows by default, or CSV when `resultFormat: 'csv'`). - File operations are intentionally minimal: the sandbox-virtual filesystem keeps a small in-memory map. SQL warehouses are not file servers; mount actual data via `databricksVolumeSource` from `@fabric-harness/connectors`. Usa... | | `DatabricksSqlSandboxRefData` | `type` | `DatabricksSqlSandboxRefData` | Type contract for databricks sql sandbox ref data. | | `DatabricksSqlSandboxRegistrationOptions` | `type` | `DatabricksSqlSandboxRegistrationOptions` | Configuration options for databricks sql sandbox registration. | | `registerDatabricksSqlSandboxBackend` | `value` | `(registration?: DatabricksSqlSandboxRegistrationOptions) => void` | Register `sandbox: 'databricks'` and its credential-safe portable-ref decoder. | | `unregisterDatabricksSqlSandboxBackend` | `value` | `() => void` | Remove both process-local registrations, primarily for tests and controlled shutdown. | ### `@fabric-harness/databricks/app-user-authorization` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createDatabricksAppUserAuthenticator` | `value` | `(options: DatabricksAppUserAuthenticatorOptions) => (request: { headers: Headers \| Record<string, string \| string[] \| undefined>; }) => Promise<DatabricksAppAuthenticatedPrincipal \| false \| undefined>` | Authenticate Databricks Apps forwarded user tokens and isolate each user by default. Validation calls the workspace current-user API once per token digest; raw tokens are never stored as cache keys or returned to TechFabric Harness. | | `DATABRICKS_APP_USER_PERMISSIONS` | `value` | `readonly ["agent:invoke", "approval:read", "approval:write", "artifact:read", "mcp:invoke", "session:abort", "session:delete", "session:read"]` | Constant defining databricks app user permissions. | | `DatabricksAppAuthenticatedPrincipal` | `type` | `DatabricksAppAuthenticatedPrincipal` | Type contract for databricks app authenticated principal. | | `DatabricksAppUserAuthenticatorOptions` | `type` | `DatabricksAppUserAuthenticatorOptions` | Configuration options for databricks app user authenticator. | | `DatabricksAppUserAuthorizationInspection` | `type` | `DatabricksAppUserAuthorizationInspection` | Type contract for databricks app user authorization inspection. | | `databricksPrincipalTenantId` | `value` | `(kind: "user" \| "service-principal" \| "app", id: string) => string` | Stable, non-reversible tenant scope for Databricks App principals. | | `inspectDatabricksAppUserAuthorization` | `value` | `(options: { headers: Headers \| Record<string, string \| string[] \| undefined>; host: string; fetchImpl?: typeof fetch; now?: () => number; }) => Promise<DatabricksAppUserAuthorizationInspection>` | Validate a Databricks Apps forwarded user token and return non-secret identity/lifetime metadata suitable for OBO lifecycle certification. The access token is never returned or included in an error. | ### `@fabric-harness/databricks/platform` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createDatabricksMutationGovernanceResolver` | `value` | `(options: DatabricksMutationGovernanceOptions) => MutationGovernanceResolver` | Platform resolver backed by Databricks resource identities but no Databricks network calls. | | `DATABRICKS_PLATFORM_GOVERNANCE_BRIDGE_VERSION` | `value` | `"1"` | Durable generation of the Harness-to-Platform Databricks governance bridge. | | `DatabricksAttestationInput` | `type` | `DatabricksAttestationInput` | Type contract for databricks attestation input. | | `databricksExecutionAttestation` | `value` | `(input: DatabricksAttestationInput) => ExecutionAttestation` | Runtime API for databricks execution attestation; the generated signature shows its accepted inputs and return type. | | `databricksExecutionPrincipal` | `value` | `(principal: DatabricksPrincipal, delegatedBy?: ExecutionPrincipal, explicitId?: string) => ExecutionPrincipal` | Audit-safe Databricks identity. Tokens and secrets are deliberately never represented. | | `databricksGovernanceRuntimeEvidence` | `value` | `(overrides?: Pick<GovernanceRuntimeEvidence, "hostPackageVersion" \| "policyRulesetVersion">) => Partial<GovernanceRuntimeEvidence>` | Runtime evidence applications pass directly to `createGovernedActionHost`. | | `DatabricksMutationGovernanceOptions` | `type` | `DatabricksMutationGovernanceOptions` | Configuration options for databricks mutation governance. | | `DatabricksPlatformResource` | `type` | `DatabricksPlatformResource` | Type contract for databricks platform resource. | | `databricksPlatformResourceRef` | `value` | `(workspaceHost: string, resource: Omit<DatabricksPlatformResource, "operation" \| "dataClassifications">) => ExternalResourceRef` | Runtime API for databricks platform resource ref; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/databricks/runtime` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `chooseDatabricksSqlWarehouse` | `value` | `(warehouses: readonly DatabricksSqlWarehouse[]) => DatabricksSqlWarehouse \| undefined` | Runtime API for choose databricks sql warehouse; the generated signature shows its accepted inputs and return type. | | `createDatabricksAuthenticatedFetch` | `value` | `(options: DatabricksAuthenticatedFetchOptions) => typeof fetch` | Fetch adapter for third-party SDKs that require a standard fetch surface. A fresh principal token is resolved per attempt and one auth refresh retry is bounded to 401/403. | | `databricksAnthropicGatewayBaseUrl` | `value` | `(host: string) => string` | Runtime API for databricks anthropic gateway base url; the generated signature shows its accepted inputs and return type. | | `DatabricksAuthenticatedFetchOptions` | `type` | `DatabricksAuthenticatedFetchOptions` | Configuration options for databricks authenticated fetch. | | `databricksControlPlane` | `value` | `(options: DatabricksControlPlaneOptions) => { aiGateway: { ensure: () => Promise<void>; listModelServices: (discoveryOptions?: DatabricksModelServiceDiscoveryOptions) => Promise<DatabricksModelService[]>; listModelProviderServices: () => Promi...` | A compact Databricks control-plane client that deliberately excludes Harness build, deployment, and agent-authoring code. Use this entrypoint from application bundles such as Next.js. | | `DatabricksControlPlaneOptions` | `type` | `DatabricksControlPlaneOptions` | Runtime-only control-plane configuration for applications and server frameworks. | | `databricksIdentity` | `value` | `(principal: DatabricksPrincipal) => DatabricksTokenProvider` | Builds a rotating bearer-token provider from the same native credential used by SDK clients. | | `DatabricksModelProviderService` | `type` | `DatabricksModelProviderService` | Type contract for databricks model provider service. | | `databricksModelProviderSupportsAnthropic` | `value` | `(service: DatabricksModelProviderService) => boolean` | Runtime API for databricks model provider supports anthropic; the generated signature shows its accepted inputs and return type. | | `DatabricksModelService` | `type` | `DatabricksModelService` | Type contract for databricks model service. | | `DatabricksModelServiceDiscoveryOptions` | `type` | `DatabricksModelServiceDiscoveryOptions` | Configuration options for databricks model service discovery. | | `DatabricksPrincipal` | `type` | `DatabricksPrincipal` | Type contract for databricks principal. | | `databricksPrincipalFromEnv` | `value` | `(env?: Record<string, string \| undefined>, options?: DatabricksPrincipalEnvOptions) => Extract<DatabricksPrincipal, { kind: "pat" \| "service-principal" \| "cli-profile"; }>` | Resolve a PAT or OAuth M2M principal consistently across CLIs, recipes, Apps, and tests. | | `databricksSdk` | `value` | `(options: DatabricksSdkOptions) => DatabricksSdkClients` | Build the official modular Databricks SDK clients under one governed identity. SDK-gap protocols remain private to Fabric's explicit raw protocol adapters. | | `DatabricksSdkClients` | `type` | `DatabricksSdkClients` | Generated Databricks service clients exposed to application code. | | `DatabricksSdkOptions` | `type` | `DatabricksSdkOptions` | Configuration options for databricks sdk. | | `DatabricksSqlWarehouse` | `type` | `DatabricksSqlWarehouse` | Type contract for databricks sql warehouse. | | `DatabricksTokenProvider` | `type` | `DatabricksTokenProvider` | A bearer-token resolver awaited per request. Fabric uses the same native-SDK credential across generated service clients, model calls, preview streaming, and Lakebase credential exchange. | | `databricksWorkspaceOrigin` | `value` | `(host: string) => string` | Normalize a workspace hostname or URL to its HTTPS origin. | | `lakebaseCredentialProvider` | `value` | `(options: LakebaseCredentialProviderOptions) => () => Promise<string>` | Exchange a workspace OAuth token for a Lakebase database credential. The result is cached, refreshed early with jitter, and refreshes are single-flight. | | `parseStatementRows` | `value` | `(response: unknown) => JsonObject[]` | Map a statement response's columns + rows into objects keyed by column name. | | `runStatement` | `value` | `(client: DatabricksStatementClient, warehouseId: string, statement: string, parameters: SqlParameter[], poll: StatementPoll) => Promise<unknown>` | Submit a parameterized SQL statement and poll to a terminal state. Named parameters → injection-safe. | | `SqlParameter` | `type` | `SqlParameter` | Type contract for sql parameter. | | `StatementPoll` | `type` | `StatementPoll` | Type contract for statement poll. | ## @fabric-harness/node ### `@fabric-harness/node` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `AGENT_FILE_EXTENSIONS` | `value` | `readonly [".ts", ".mts", ".js", ".mjs"]` | File extensions `fh run <path>` can load directly, without a workspace. | | `AgentDescription` | `type` | `AgentDescription` | Type contract for agent description. | | `AgentFileExport` | `type` | `AgentFileExport` | Type contract for agent file export. | | `AgentFileModule` | `type` | `AgentFileModule` | Type contract for agent file module. | | `AgentModule` | `type` | `AgentModule` | Type contract for agent module. | | `AgentNotFoundError` | `value` | `typeof AgentNotFoundError` | Error raised for agent not found failures. | | `AgentSummary` | `type` | `AgentSummary` | Type contract for agent summary. | | `applyEnvModelProvider` | `value` | `(options: AgentInit, env?: NodeJS.ProcessEnv, modelOptions?: EnvModelOptions) => AgentInit` | Provider implementation for apply env model. | | `ApprovalSummary` | `type` | `ApprovalSummary` | Type contract for approval summary. | | `asJsonObject` | `value` | `(value: unknown) => JsonObject` | Runtime API for as json object; the generated signature shows its accepted inputs and return type. | | `assertDataResidency` | `value` | `(region: string, allowedRegions: readonly string[]) => void` | Validates data residency and throws when the requirement is not met. | | `BackupObjectStore` | `type` | `BackupObjectStore` | Storage contract for backup object. | | `backupPostgresPersistence` | `value` | `(input: { client: PostgresClientLike; objectStore: BackupObjectStore; objectKey: string; tablePrefix?: string; }) => Promise<PostgresBackupRecord>` | Create a transactionally consistent logical backup and write it to object storage. | | `BuildBundleStrategy` | `type` | `BuildBundleStrategy` | Type contract for build bundle strategy. | | `BuildManifest` | `type` | `BuildManifest` | Type contract for build manifest. | | `BuildManifestAgent` | `type` | `BuildManifestAgent` | Type contract for build manifest agent. | | `BuildManifestFile` | `type` | `BuildManifestFile` | Type contract for build manifest file. | | `BuildManifestRole` | `type` | `BuildManifestRole` | Type contract for build manifest role. | | `BuildManifestSkill` | `type` | `BuildManifestSkill` | Type contract for build manifest skill. | | `BuildSummary` | `type` | `BuildSummary` | Type contract for build summary. | | `BuildTarget` | `type` | `BuildTarget` | Type contract for build target. | | `buildWorkspace` | `value` | `(options?: BuildWorkspaceOptions) => Promise<BuildWorkspaceResult>` | Runtime API for build workspace; the generated signature shows its accepted inputs and return type. | | `BuildWorkspaceOptions` | `type` | `BuildWorkspaceOptions` | Configuration options for build workspace. | | `BuildWorkspaceResult` | `type` | `BuildWorkspaceResult` | Result returned by build workspace. | | `cancelSessionTask` | `value` | `(workspaceRoot: string, sessionId: string, taskId: string, reason?: string, actor?: string) => Promise<TaskSummary>` | Runtime API for cancel session task; the generated signature shows its accepted inputs and return type. | | `cancelTaskInStore` | `value` | `(store: SessionStore, sessionId: string, taskId: string, reason?: string, actor?: string) => Promise<TaskSummary>` | Storage contract for cancel task in. | | `CheckpointSummary` | `type` | `CheckpointSummary` | Type contract for checkpoint summary. | | `compactPersistedSession` | `value` | `(workspaceRoot: string, sessionId: string, options?: CompactPersistedSessionOptions) => Promise<PersistedCompactionResult>` | Runtime API for compact persisted session; the generated signature shows its accepted inputs and return type. | | `CompactPersistedSessionOptions` | `type` | `CompactPersistedSessionOptions` | Configuration options for compact persisted session. | | `compactSessionInStore` | `value` | `(store: SessionStore, sessionId: string, options?: CompactPersistedSessionOptions) => Promise<PersistedCompactionResult>` | Storage contract for compact session in. | | `CompiledSkill` | `type` | `CompiledSkill` | Type contract for compiled skill. | | `compileSkill` | `value` | `(options: CompileSkillOptions) => Promise<CompiledSkill>` | Compile one `SKILL.md` and its sibling files into a `Skill`. The Markdown body becomes `content`, the frontmatter becomes `metadata` (with `name`, `description`, and `model` lifted to their typed fields), and every other file in the directory becomes a packaged resource the model can read on demand. | | `CompileSkillOptions` | `type` | `CompileSkillOptions` | Configuration options for compile skill. | | `createConfiguredSessionStore` | `value` | `(options: CreateConfiguredSessionStoreOptions) => Promise<SessionStore>` | Creates configured session store. | | `CreateConfiguredSessionStoreOptions` | `type` | `CreateConfiguredSessionStoreOptions` | Configuration options for create configured session store. | | `createFabricRunContext` | `value` | `(options: CreateFabricRunContextOptions) => Promise<FabricContext>` | Creates fabric run context. | | `CreateFabricRunContextOptions` | `type` | `CreateFabricRunContextOptions` | Configuration options for create fabric run context. | | `createMcpHttpServer` | `value` | `(tools: ToolDef[], options?: FabricMcpHttpServerOptions) => Promise<FabricMcpHttpServer>` | Expose governed Harness tools through stateless MCP Streamable HTTP. | | `createPersistentDispatchProcessor` | `value` | `(options: PersistentDispatchProcessorOptions) => DispatchProcessor` | Build a `DispatchProcessor` that applies dispatched inputs to a persistent instance session. Idempotent by `dispatchId`: a marker entry is appended to the instance session after a dispatch is applied, and re-delivery of the same `dispatchId` is skipped. The marker lives in the shared session store, so dedup holds across separate processings (and survives restart when the store is durable). | | `createPersistentSubmissionExecutor` | `value` | `(options: PersistentSubmissionExecutorOptions) => SubmissionExecutor` | The `SubmissionExecutor` that applies durable submissions to persistent instance sessions. `execute` runs a real session turn (`session.prompt` is idempotent by submission id, so a recovered attempt resumes instead of double-applying its input); everything else operates store-level so reconciliation never needs a live agent. | | `createPrivateNetworkFetch` | `value` | `(options?: PrivateNetworkFetchOptions) => PrivateNetworkFetchClient` | Create an outbound Node client with one policy and transport trust path. Credentials and PEM material remain in the dispatcher and are never placed in request URLs, Fabric events, or model messages. | | `createResponsesDeltaEvent` | `value` | `(itemId: string, delta: string) => JsonObject` | Creates responses delta event. | | `createResponsesDoneEvent` | `value` | `(itemId: string, text: string) => JsonObject` | Creates responses done event. | | `createResponsesOutputItem` | `value` | `(itemId: string, text: string) => FabricResponsesOutputItem` | Creates responses output item. | | `createResponsesResponse` | `value` | `(input: { submissionId: string; itemId: string; text: string; customOutputs?: JsonObject; includeTraceId?: boolean; }) => JsonObject` | Creates responses response. | | `currentMcpRequestContext` | `value` | `() => FabricMcpRequestContext` | Runtime API for current mcp request context; the generated signature shows its accepted inputs and return type. | | `databricksAppsOidcAuthenticator` | `value` | `(options: DatabricksAppsOidcAuthenticatorOptions) => (request: IncomingMessage) => Promise<ServerPrincipal \| false \| undefined>` | Databricks workspace OIDC preset for Apps ingress and workspace-scoped RBAC claims. | | `DatabricksAppsOidcAuthenticatorOptions` | `type` | `DatabricksAppsOidcAuthenticatorOptions` | Configuration options for databricks apps oidc authenticator. | | `daytona` | `value` | `(config: DaytonaBundleConfig, isMock?: boolean) => DaytonaBundle` | One-call wiring for a Daytona-native agent: resolves the model provider from config or env, includes Daytona-specific workspace tools, and sets a safe default egress policy. | | `DaytonaBundle` | `type` | `DaytonaBundle` | Type contract for daytona bundle. | | `DaytonaBundleConfig` | `type` | `DaytonaBundleConfig` | Type contract for daytona bundle config. | | `defineApplication` | `value` | `(application: FabricApplication) => FabricApplication` | Identity helper that preserves route/middleware inference in workspace config. | | `defineDaytonaAgent` | `value` | `(options?: DefineDaytonaAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines daytona agent. | | `DefineDaytonaAgentOptions` | `type` | `DefineDaytonaAgentOptions` | Configuration options for define daytona agent. | | `defineDockerAgent` | `value` | `(options?: DefineDockerAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines docker agent. | | `DefineDockerAgentOptions` | `type` | `DefineDockerAgentOptions` | Configuration options for define docker agent. | | `defineE2bAgent` | `value` | `(options?: DefineE2bAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines e2b agent. | | `DefineE2bAgentOptions` | `type` | `DefineE2bAgentOptions` | Configuration options for define e2b agent. | | `defineK8sAgent` | `value` | `(options?: DefineK8sAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines k8s agent. | | `DefineK8sAgentOptions` | `type` | `DefineK8sAgentOptions` | Configuration options for define k8s agent. | | `defineModalAgent` | `value` | `(options?: DefineModalAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines modal agent. | | `DefineModalAgentOptions` | `type` | `DefineModalAgentOptions` | Configuration options for define modal agent. | | `defineNodeAgent` | `value` | `(options?: DefineNodeAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines node agent. | | `DefineNodeAgentOptions` | `type` | `DefineNodeAgentOptions` | Configuration options for define node agent. | | `DeletionEvidenceSigner` | `type` | `DeletionEvidenceSigner` | Type contract for deletion evidence signer. | | `DeletionEvidenceStore` | `type` | `DeletionEvidenceStore` | Storage contract for deletion evidence. | | `describeAgentFile` | `value` | `(options: LoadAgentModuleOptions) => Promise<AgentDescription>` | Runtime API for describe agent file; the generated signature shows its accepted inputs and return type. | | `DevServerHandle` | `type` | `DevServerHandle` | Type contract for dev server handle. | | `DevServerOptions` | `type` | `DevServerOptions` | Configuration options for dev server. | | `discoverWorkspace` | `value` | `(startDir?: string) => Promise<WorkspaceInfo>` | Runtime API for discover workspace; the generated signature shows its accepted inputs and return type. | | `docker` | `value` | `(config: DockerBundleConfig, isMock?: boolean) => DockerBundle` | One-call wiring for a Docker-native agent: resolves the model provider from config or env, includes Docker-specific container tools, and sets a safe default egress policy. | | `DockerBundle` | `type` | `DockerBundle` | Type contract for docker bundle. | | `DockerBundleConfig` | `type` | `DockerBundleConfig` | Type contract for docker bundle config. | | `e2b` | `value` | `(config: E2bBundleConfig, isMock?: boolean) => E2bBundle` | One-call wiring for an E2B-native agent: resolves the model provider from config or env, includes built-in tools, and sets a safe default egress policy. | | `E2bBundle` | `type` | `E2bBundle` | Type contract for e2b bundle. | | `E2bBundleConfig` | `type` | `E2bBundleConfig` | Type contract for e2b bundle config. | | `ed25519DeletionEvidenceSigner` | `value` | `(options: { privateKey: KeyObject \| string \| Buffer; identityKey: string \| Uint8Array; keyId: string; }) => DeletionEvidenceSigner` | Runtime API for ed25519 deletion evidence signer; the generated signature shows its accepted inputs and return type. | | `enforcePersistenceRetention` | `value` | `(persistence: PersistenceBundle, policy: FabricRetentionPolicy, options?: { now?: Date; }) => Promise<RetentionResult>` | Enforce durable data retention. Use a deletion-evidence-wrapped bundle for signed session receipts. | | `ensurePostgresAttachmentTables` | `value` | `(client: PostgresClientLike) => Promise<void>` | Create the attachments table when absent. Idempotent. | | `ensurePostgresConversationStreamTables` | `value` | `(client: PostgresClientLike) => Promise<void>` | Create the conversation stream tables when absent. Idempotent. | | `ensurePostgresSubmissionTables` | `value` | `(client: PostgresClientLike) => Promise<void>` | Create the submission tables and indexes when absent. Idempotent. | | `ensureSqliteAttachmentTables` | `value` | `(db: SqliteDatabaseLike) => void` | Create the attachments table when absent. Idempotent. | | `ensureSqliteConversationStreamTables` | `value` | `(db: SqliteDatabaseLike) => void` | Create the conversation stream tables when absent. Idempotent. | | `ensureSqliteSubmissionTables` | `value` | `(db: SqliteDatabaseLike) => void` | Create the submission tables and indexes when absent. Idempotent. | | `entraIdAuthenticator` | `value` | `(options: EntraIdAuthenticatorOptions) => (request: IncomingMessage) => Promise<ServerPrincipal \| false \| undefined>` | Microsoft Entra ID v2 preset with tenant, roles, groups, and app/user identity mapping. | | `EntraIdAuthenticatorOptions` | `type` | `EntraIdAuthenticatorOptions` | Configuration options for entra id authenticator. | | `ExternalRetentionTarget` | `type` | `ExternalRetentionTarget` | Type contract for external retention target. | | `FABRIC_HTTP_ROUTE_SURFACE` | `value` | `readonly RouteSurfaceEntry[]` | Routes shared by the Node server and the generated Cloudflare worker. Deliberately excludes surfaces that are Node-only by design (the operator console, MCP server, OpenAPI document, and Responses API bridge), which the worker does not host. | | `FabricApplication` | `type` | `FabricApplication` | Type contract for fabric application. | | `FabricApplicationMiddleware` | `type` | `FabricApplicationMiddleware` | Middleware for fabric application. | | `FabricApplicationNext` | `type` | `FabricApplicationNext` | Type contract for fabric application next. | | `FabricApplicationPublicMiddleware` | `type` | `FabricApplicationPublicMiddleware` | Middleware for fabric application public. | | `FabricApplicationPublicRequestContext` | `type` | `FabricApplicationPublicRequestContext` | Type contract for fabric application public request context. | | `FabricApplicationRequestContext` | `type` | `FabricApplicationRequestContext` | Type contract for fabric application request context. | | `FabricApplicationRoute` | `type` | `FabricApplicationRoute` | Type contract for fabric application route. | | `FabricApplicationStores` | `type` | `FabricApplicationStores` | Type contract for fabric application stores. | | `FabricBuildContext` | `type` | `FabricBuildContext` | Type contract for fabric build context. | | `FabricBuildError` | `value` | `typeof FabricBuildError` | Error raised for fabric build failures. | | `FabricBuildErrorCode` | `type` | `FabricBuildErrorCode` | Type contract for fabric build error code. | | `FabricBuildPlugin` | `type` | `FabricBuildPlugin` | Type contract for fabric build plugin. | | `FabricHarnessConfig` | `type` | `FabricHarnessConfig` | Type contract for fabric harness config. | | `FabricHarnessDatabricksAiSearchAppResourceConfig` | `type` | `FabricHarnessDatabricksAiSearchAppResourceConfig` | Type contract for fabric harness databricks ai search app resource config. | | `FabricHarnessDatabricksAppConfig` | `type` | `FabricHarnessDatabricksAppConfig` | Type contract for fabric harness databricks app config. | | `FabricHarnessDatabricksAppResourceApp` | `type` | `FabricHarnessDatabricksAppResourceApp` | Type contract for fabric harness databricks app resource app. | | `FabricHarnessDatabricksAppResourceConfig` | `type` | `FabricHarnessDatabricksAppResourceConfig` | A Databricks-native App resource plus its `app.yaml` environment projection. Native field and permission names intentionally match the Databricks Bundle schema. | | `FabricHarnessDatabricksAppResourceDatabase` | `type` | `FabricHarnessDatabricksAppResourceDatabase` | Type contract for fabric harness databricks app resource database. | | `FabricHarnessDatabricksAppResourceExperiment` | `type` | `FabricHarnessDatabricksAppResourceExperiment` | Type contract for fabric harness databricks app resource experiment. | | `FabricHarnessDatabricksAppResourceGenieSpace` | `type` | `FabricHarnessDatabricksAppResourceGenieSpace` | Type contract for fabric harness databricks app resource genie space. | | `FabricHarnessDatabricksAppResourceJob` | `type` | `FabricHarnessDatabricksAppResourceJob` | Type contract for fabric harness databricks app resource job. | | `FabricHarnessDatabricksAppResourceKind` | `type` | `"postgres" \| "app" \| "job" \| "database" \| "experiment" \| "genie_space" \| "secret" \| "serving_endpoint" \| "sql_warehouse" \| "uc_securable"` | Type contract for fabric harness databricks app resource kind. | | `FabricHarnessDatabricksAppResourcePostgres` | `type` | `FabricHarnessDatabricksAppResourcePostgres` | Type contract for fabric harness databricks app resource postgres. | | `FabricHarnessDatabricksAppResourceSecret` | `type` | `FabricHarnessDatabricksAppResourceSecret` | Type contract for fabric harness databricks app resource secret. | | `FabricHarnessDatabricksAppResourceServingEndpoint` | `type` | `FabricHarnessDatabricksAppResourceServingEndpoint` | Type contract for fabric harness databricks app resource serving endpoint. | | `FabricHarnessDatabricksAppResourceSqlWarehouse` | `type` | `FabricHarnessDatabricksAppResourceSqlWarehouse` | Type contract for fabric harness databricks app resource sql warehouse. | | `FabricHarnessDatabricksAppResourceUcSecurable` | `type` | `FabricHarnessDatabricksAppResourceUcSecurable` | Type contract for fabric harness databricks app resource uc securable. | | `FabricHarnessDatabricksConfig` | `type` | `FabricHarnessDatabricksConfig` | Type contract for fabric harness databricks config. | | `FabricHarnessDatabricksGenieAppResourceConfig` | `type` | `FabricHarnessDatabricksGenieAppResourceConfig` | Type contract for fabric harness databricks genie app resource config. | | `FabricHarnessDatabricksServingConfig` | `type` | `FabricHarnessDatabricksServingConfig` | Type contract for fabric harness databricks serving config. | | `FabricHarnessEnvironmentConfig` | `type` | `FabricHarnessEnvironmentConfig` | Type contract for fabric harness environment config. | | `FabricHarnessPersistenceConfig` | `type` | `FabricHarnessPersistenceConfig` | Type contract for fabric harness persistence config. | | `FabricHarnessSandboxConfig` | `type` | `FabricHarnessSandboxConfig` | Type contract for fabric harness sandbox config. | | `FabricHarnessStoreConfig` | `type` | `FabricHarnessStoreConfig` | Type contract for fabric harness store config. | | `FabricHarnessTemporalConfig` | `type` | `FabricHarnessTemporalConfig` | Type contract for fabric harness temporal config. | | `FabricMcpHttpServer` | `type` | `FabricMcpHttpServer` | Type contract for fabric mcp http server. | | `FabricMcpHttpServerOptions` | `type` | `FabricMcpHttpServerOptions` | Configuration options for fabric mcp http server. | | `FabricMcpRequestContext` | `type` | `FabricMcpRequestContext` | Type contract for fabric mcp request context. | | `FabricMcpToolContextRequest` | `type` | `FabricMcpToolContextRequest` | Input contract for fabric mcp tool context. | | `FabricMcpToolContextResolution` | `type` | `FabricMcpToolContextResolution` | Type contract for fabric mcp tool context resolution. | | `FabricPersistence` | `type` | `FabricPersistence` | Type contract for fabric persistence. | | `FabricPersistenceError` | `value` | `typeof FabricPersistenceError` | Error raised for fabric persistence failures. | | `FabricPersistenceErrorCode` | `type` | `FabricPersistenceErrorCode` | Type contract for fabric persistence error code. | | `FabricPersistenceHealth` | `type` | `PersistenceHealth` | Type contract for fabric persistence health. | | `fabricPostgresMigrations` | `value` | `(tablePrefix?: string) => PostgresMigration[]` | Runtime API for fabric postgres migrations; the generated signature shows its accepted inputs and return type. | | `FabricResponsesConfig` | `type` | `FabricResponsesConfig` | Type contract for fabric responses config. | | `FabricResponsesInputItem` | `type` | `FabricResponsesInputItem` | Type contract for fabric responses input item. | | `FabricResponsesOutputItem` | `type` | `FabricResponsesOutputItem` | Type contract for fabric responses output item. | | `FabricResponsesRequest` | `type` | `FabricResponsesRequest` | Input contract for fabric responses. | | `FabricRetentionPolicy` | `type` | `FabricRetentionPolicy` | Type contract for fabric retention policy. | | `FileAttachmentStore` | `value` | `typeof FileAttachmentStore` | Storage contract for file attachment. | | `FileAttachmentStoreOptions` | `type` | `FileAttachmentStoreOptions` | Configuration options for file attachment store. | | `FileConversationStreamStore` | `value` | `typeof FileConversationStreamStore` | Storage contract for file conversation stream. | | `FileConversationStreamStoreOptions` | `type` | `FileConversationStreamStoreOptions` | Configuration options for file conversation stream store. | | `FileSessionStore` | `value` | `typeof FileSessionStore` | Storage contract for file session. | | `FileSessionStoreOptions` | `type` | `FileSessionStoreOptions` | Configuration options for file session store. | | `findWorkspaceRoot` | `value` | `(startDir?: string) => Promise<string>` | Runtime API for find workspace root; the generated signature shows its accepted inputs and return type. | | `forkSessionAtStep` | `value` | `(store: SessionStore, sourceSessionId: string, stepId: string, options?: { newSessionId: string; metadata?: JsonObject; }) => Promise<ForkSessionAtStepResult>` | Forks a session at the given step into a new session in the same store. The new session contains the active-path entries up to and including `stepId`, and its `leafId` is set to `stepId`. Used by `fh replay --rerun`. If a `user_prompt` entry exists immediately after the cut on the original active path, its text is returned as `resumePromptText` so the caller can resubmit it against the forked session. | | `ForkSessionAtStepResult` | `type` | `ForkSessionAtStepResult` | Result returned by fork session at step. | | `formatWorkspaceDiagnostics` | `value` | `(diagnostics: readonly WorkspaceDiagnostic[]) => string` | Format findings for terminal output, one block per finding. | | `getMetricsFromStore` | `value` | `(store: SessionStore, sessionId: string) => Promise<SessionMetrics \| undefined>` | Returns metrics from store. | | `getRequiredAgentDefinition` | `value` | `(value: unknown, agentPath: string) => AgentDefinition<unknown, unknown>` | Returns required agent definition. | | `getSessionApprovalState` | `value` | `(workspaceRoot: string, sessionId: string, approvalId: string) => Promise<ApprovalState \| undefined>` | Returns session approval state. | | `getSessionArtifact` | `value` | `(workspaceRoot: string, sessionId: string, artifactIdOrName: string) => Promise<{ ref: ArtifactRef; content: Uint8Array; } \| undefined>` | Returns session artifact. | | `getSessionMetrics` | `value` | `(workspaceRoot: string, sessionId: string) => Promise<SessionMetrics \| undefined>` | Returns session metrics. | | `getSessionTask` | `value` | `(workspaceRoot: string, sessionId: string, taskId: string) => Promise<TaskSummary \| undefined>` | Returns session task. | | `getSessionTimeline` | `value` | `(workspaceRoot: string, sessionId: string) => Promise<SessionTimeline \| undefined>` | Returns session timeline. | | `getTaskFromStore` | `value` | `(store: SessionStore, sessionId: string, taskId: string) => Promise<TaskSummary \| undefined>` | Returns task from store. | | `hmacDeletionEvidenceSigner` | `value` | `(options: { key: string \| Uint8Array; keyId: string; }) => DeletionEvidenceSigner` | Runtime API for hmac deletion evidence signer; the generated signature shows its accepted inputs and return type. | | `httpBackupObjectStore` | `value` | `(options: { urlForKey: (key: string) => string \| URL; headers?: (method: "GET" \| "PUT", key: string, metadata?: Record<string, string>) => BackupHeadersInit \| Promise<BackupHeadersInit>; fetch?: typeof globalThis.fetch; }) => BackupObjectStore` | HTTP PUT/GET object store for presigned S3/R2, Azure Blob SAS, or an internal object gateway. | | `HttpRateLimitClass` | `type` | `HttpRateLimitClass` | Type contract for http rate limit class. | | `HttpRateLimitConfig` | `type` | `HttpRateLimitConfig` | Type contract for http rate limit config. | | `HttpRateLimitContext` | `type` | `HttpRateLimitContext` | Type contract for http rate limit context. | | `HttpRateLimitDecision` | `type` | `HttpRateLimitDecision` | Type contract for http rate limit decision. | | `HttpRateLimiter` | `type` | `HttpRateLimiter` | Type contract for http rate limiter. | | `HttpRateLimitRule` | `type` | `HttpRateLimitRule` | Type contract for http rate limit rule. | | `inspectReplay` | `value` | `(workspaceRoot: string, sessionId: string) => Promise<ReplayInspection \| undefined>` | Runtime API for inspect replay; the generated signature shows its accepted inputs and return type. | | `inspectReplayFromStore` | `value` | `(store: SessionStore, sessionId: string) => Promise<ReplayInspection \| undefined>` | Storage contract for inspect replay from. | | `inspectSession` | `value` | `(workspaceRoot: string, sessionId: string) => Promise<SessionData \| undefined>` | Runtime API for inspect session; the generated signature shows its accepted inputs and return type. | | `inspectSessionFromStore` | `value` | `(store: SessionStore, sessionId: string) => Promise<SessionData \| undefined>` | Storage contract for inspect session from. | | `isDefinedAgent` | `value` | `(value: unknown) => value is DefinedAgent` | Checks whether a value is defined agent. | | `isPersistentAgent` | `value` | `(workspaceRoot: string, agent: string) => Promise<boolean>` | Checks whether a value is persistent agent. | | `JobScheduler` | `type` | `JobScheduler` | Type contract for job scheduler. | | `JobSchedulerOptions` | `type` | `JobSchedulerOptions` | Configuration options for job scheduler. | | `k8s` | `value` | `(config: K8sBundleConfig, isMock?: boolean) => K8sBundle` | One-call wiring for a Kubernetes-native agent: resolves the model provider from config or env, includes K8s-specific kubectl tools, and sets a safe default egress policy. | | `K8sBundle` | `type` | `K8sBundle` | Type contract for k8s bundle. | | `K8sBundleConfig` | `type` | `K8sBundleConfig` | Type contract for k8s bundle config. | | `libsqlPersistence` | `value` | `(options: LibSqlPersistenceOptions) => FabricPersistence` | Full local libSQL or remote Turso bundle using optimistic version fencing. | | `LibSqlPersistenceClient` | `type` | `LibSqlPersistenceClient` | Client implementation for lib sql persistence. | | `LibSqlPersistenceOptions` | `type` | `LibSqlPersistenceOptions` | Configuration options for lib sql persistence. | | `LibSqlResultSet` | `type` | `LibSqlResultSet` | Type contract for lib sql result set. | | `listAgentFiles` | `value` | `(workspaceRoot: string) => Promise<string[]>` | Lists agent files. | | `listAgentSummaries` | `value` | `(workspaceRoot: string) => Promise<AgentSummary[]>` | Lists agent summaries. | | `listApprovalsFromStore` | `value` | `(store: SessionStore, sessionId: string) => Promise<ApprovalSummary[]>` | Lists approvals from store. | | `listApprovalStatesFromStore` | `value` | `(store: SessionStore, sessionId: string) => Promise<import("@fabric-harness/sdk").ApprovalState[]>` | Lists approval states from store. | | `listBuilds` | `value` | `(workspaceRoot: string) => Promise<BuildSummary[]>` | Lists builds. | | `listCheckpointsFromStore` | `value` | `(store: SessionStore, sessionId: string) => Promise<CheckpointSummary[]>` | Lists checkpoints from store. | | `listSessionApprovals` | `value` | `(workspaceRoot: string, sessionId: string) => Promise<ApprovalSummary[]>` | Lists session approvals. | | `listSessionApprovalStates` | `value` | `(workspaceRoot: string, sessionId: string) => Promise<ApprovalState[]>` | Lists session approval states. | | `listSessionArtifacts` | `value` | `(workspaceRoot: string, sessionId: string) => Promise<ArtifactRef[]>` | Lists session artifacts. | | `listSessionCheckpoints` | `value` | `(workspaceRoot: string, sessionId: string) => Promise<CheckpointSummary[]>` | Lists session checkpoints. | | `listSessions` | `value` | `(workspaceRoot: string) => Promise<SessionSummary[]>` | Lists sessions. | | `listSessionSummariesFromStore` | `value` | `(store: SessionStore, options?: ListSessionSummariesOptions) => Promise<SessionSummary[]>` | Lists session summaries from store. | | `listSessionTasks` | `value` | `(workspaceRoot: string, sessionId: string) => Promise<TaskSummary[]>` | Lists session tasks. | | `listTasksFromStore` | `value` | `(store: SessionStore, sessionId: string) => Promise<TaskSummary[]>` | Lists tasks from store. | | `loadAgentFile` | `value` | `(filePath: string, options?: { cacheBust?: boolean; }) => Promise<AgentFileModule>` | Load an arbitrary agent file outside a `.fabricharness/` workspace: transpile TypeScript into a temp build dir, then discover every exported `defineAgent()`/`createAgent()` value. Package imports (including `@fabric-harness/sdk`) resolve from the nearest `node_modules` to the file. | | `loadAgentModule` | `value` | `(options: LoadAgentModuleOptions) => Promise<AgentModule>` | Loads agent module. | | `LoadAgentModuleOptions` | `type` | `LoadAgentModuleOptions` | Configuration options for load agent module. | | `loadFabricHarnessConfig` | `value` | `(options: LoadFabricHarnessConfigOptions) => Promise<FabricHarnessConfig>` | Loads fabric harness config. | | `LoadFabricHarnessConfigOptions` | `type` | `LoadFabricHarnessConfigOptions` | Configuration options for load fabric harness config. | | `loadRoles` | `value` | `(workspaceRoot: string) => Promise<Role[]>` | Loads roles. | | `loadSkills` | `value` | `(workspaceRoot: string) => Promise<Skill[]>` | Loads skills. | | `mapOidcPrincipal` | `value` | `(context: OidcPrincipalContext, options: Pick<OidcJwtAuthenticatorOptions, "claims" \| "groupRoles" \| "rolePermissions" \| "provider">) => ServerPrincipal \| false` | Runtime API for map oidc principal; the generated signature shows its accepted inputs and return type. | | `markdownImportPlugin` | `value` | `(options?: MarkdownImportPluginOptions) => Plugin` | esbuild plugin compiling `.md` and `SKILL.md` imports. Bundler-native suffixed specifiers (`?raw`, `?url`) are left alone so a project that already uses them keeps its existing behavior. | | `MarkdownImportPluginOptions` | `type` | `MarkdownImportPluginOptions` | Configuration options for markdown import plugin. | | `memoryDeletionEvidenceStore` | `value` | `() => DeletionEvidenceStore` | Storage contract for memory deletion evidence. | | `memoryPersistence` | `value` | `() => FabricPersistence` | Infrastructure-free unified bundle for tests and lightweight applications. | | `memorySchedulerLeaseStore` | `value` | `() => SchedulerLeaseStore` | Storage contract for memory scheduler lease. | | `migratePostgresPersistence` | `value` | `(client: PostgresClientLike, options?: { tablePrefix?: string; migrations?: PostgresMigration[]; targetVersion?: number; }) => Promise<PostgresMigrationResult>` | Runtime API for migrate postgres persistence; the generated signature shows its accepted inputs and return type. | | `MockDaytonaModelProvider` | `value` | `typeof MockDaytonaModelProvider` | A deterministic `ModelProvider` for Daytona agent tests and init templates. Returns structured responses without requiring real API credentials. | | `MockDaytonaModelProviderOptions` | `type` | `MockDaytonaModelProviderOptions` | Configuration options for mock daytona model provider. | | `MockDockerModelProvider` | `value` | `typeof MockDockerModelProvider` | A deterministic `ModelProvider` for Docker agent tests and init templates. Returns structured responses without requiring real API credentials. | | `MockDockerModelProviderOptions` | `type` | `MockDockerModelProviderOptions` | Configuration options for mock docker model provider. | | `MockE2bModelProvider` | `value` | `typeof MockE2bModelProvider` | A deterministic `ModelProvider` for E2B agent tests and init templates. Returns structured responses without requiring real API credentials. | | `MockE2bModelProviderOptions` | `type` | `MockE2bModelProviderOptions` | Configuration options for mock e2b model provider. | | `MockK8sModelProvider` | `value` | `typeof MockK8sModelProvider` | A deterministic `ModelProvider` for Kubernetes agent tests and init templates. Returns structured responses without requiring real API credentials. | | `MockK8sModelProviderOptions` | `type` | `MockK8sModelProviderOptions` | Configuration options for mock k8s model provider. | | `MockModalModelProvider` | `value` | `typeof MockModalModelProvider` | A deterministic `ModelProvider` for Modal agent tests and init templates. Returns structured responses without requiring real API credentials. | | `MockModalModelProviderOptions` | `type` | `MockModalModelProviderOptions` | Configuration options for mock modal model provider. | | `MockNodeModelProvider` | `value` | `typeof MockNodeModelProvider` | A deterministic `ModelProvider` for Node agent tests and init templates. Returns structured responses without requiring real API credentials. | | `MockNodeModelProviderOptions` | `type` | `MockNodeModelProviderOptions` | Configuration options for mock node model provider. | | `modal` | `value` | `(config: ModalBundleConfig, isMock?: boolean) => ModalBundle` | One-call wiring for a Modal-native agent: resolves the model provider from config or env, includes built-in tools, and sets a safe default egress policy. | | `ModalBundle` | `type` | `ModalBundle` | Type contract for modal bundle. | | `ModalBundleConfig` | `type` | `ModalBundleConfig` | Type contract for modal bundle config. | | `mongodbPersistence` | `value` | `(options: MongoPersistenceOptions) => FabricPersistence` | Full bundle over a MongoDB collection using `_id` + version compare-and-swap. | | `MongoPersistenceClient` | `type` | `MongoPersistenceClient` | Client implementation for mongo persistence. | | `MongoPersistenceCollection` | `type` | `MongoPersistenceCollection` | Type contract for mongo persistence collection. | | `MongoPersistenceOptions` | `type` | `MongoPersistenceOptions` | Configuration options for mongo persistence. | | `mysqlPersistence` | `value` | `(options: MySqlPersistenceOptions) => FabricPersistence` | Full bundle over a MySQL 8 compatible database using version-fenced snapshot rows. | | `MySqlPersistenceClient` | `type` | `MySqlPersistenceClient` | Client implementation for my sql persistence. | | `MySqlPersistenceOptions` | `type` | `MySqlPersistenceOptions` | Configuration options for my sql persistence. | | `nextScheduledAt` | `value` | `(expression: string, currentDate?: Date, timezone?: string) => Date` | Runtime API for next scheduled at; the generated signature shows its accepted inputs and return type. | | `node` | `value` | `(config: NodeBundleConfig, isMock?: boolean) => NodeBundle` | One-call wiring for a Node-native agent: resolves the model provider from config or env, includes built-in file/shell tools, and sets a safe default egress policy. | | `NodeBundle` | `type` | `NodeBundle` | Type contract for node bundle. | | `NodeBundleConfig` | `type` | `NodeBundleConfig` | Type contract for node bundle config. | | `OidcClaimMapping` | `type` | `OidcClaimMapping` | Type contract for oidc claim mapping. | | `oidcJwtAuthenticator` | `value` | `(options: OidcJwtAuthenticatorOptions) => (request: IncomingMessage) => Promise<ServerPrincipal \| false \| undefined>` | Validate Bearer JWTs with a local or remote JWKS and map claims into server RBAC. | | `OidcJwtAuthenticatorOptions` | `type` | `OidcJwtAuthenticatorOptions` | Configuration options for oidc jwt authenticator. | | `OidcPrincipalContext` | `type` | `OidcPrincipalContext` | Type contract for oidc principal context. | | `parseCookie` | `value` | `(req: http.IncomingMessage, name: string) => string \| undefined` | Parse the `Cookie` header on an IncomingMessage and return a named cookie's value, or undefined when missing. Use inside a custom `extractAuthToken` to validate session cookies set by your existing identity layer. | | `ParsedFabricResponsesRequest` | `type` | `ParsedFabricResponsesRequest` | Input contract for parsed fabric responses. | | `parseFabricResponsesRequest` | `value` | `(value: unknown) => ParsedFabricResponsesRequest` | Parses fabric responses request. | | `parseFrontmatter` | `value` | `(markdown: string) => FrontmatterResult` | Parses frontmatter. | | `pathExists` | `value` | `(filePath: string) => Promise<boolean>` | Runtime API for path exists; the generated signature shows its accepted inputs and return type. | | `PersistedCompactionResult` | `type` | `PersistedCompactionResult` | Result returned by persisted compaction. | | `PersistentDispatchProcessorOptions` | `type` | `PersistentDispatchProcessorOptions` | Configuration options for persistent dispatch processor. | | `PersistentPromptOptions` | `type` | `PersistentPromptOptions` | Configuration options for persistent prompt. | | `PersistentPromptResult` | `type` | `PersistentPromptResult` | Result returned by persistent prompt. | | `PersistentSessionBusyError` | `value` | `typeof PersistentSessionBusyError` | Error raised for persistent session busy failures. | | `PersistentSubmissionExecutorOptions` | `type` | `PersistentSubmissionExecutorOptions` | Configuration options for persistent submission executor. | | `PersistentTaskOptions` | `type` | `PersistentTaskOptions` | Configuration options for persistent task. | | `PersistentTaskResult` | `type` | `PersistentTaskResult` | Result returned by persistent task. | | `PostgresAttachmentStore` | `value` | `typeof PostgresAttachmentStore` | Storage contract for postgres attachment. | | `PostgresAttachmentStoreOptions` | `type` | `PostgresAttachmentStoreOptions` | Configuration options for postgres attachment store. | | `PostgresBackupRecord` | `type` | `PostgresBackupRecord` | Type contract for postgres backup record. | | `PostgresClientLike` | `type` | `PostgresClientLike` | Type contract for postgres client like. | | `PostgresConversationStreamStore` | `value` | `typeof PostgresConversationStreamStore` | Storage contract for postgres conversation stream. | | `PostgresConversationStreamStoreOptions` | `type` | `PostgresConversationStreamStoreOptions` | Configuration options for postgres conversation stream store. | | `postgresCostBudgetStore` | `value` | `(options: PostgresCostBudgetStoreOptions) => CostBudgetStore` | Postgres-backed cost budget store. Pair with `init({ costLimit: { perScope, scopeKey, store } })` to enforce a budget that survives process restarts — per-tenant, per-day, per-organization caps, etc. The table holds one row per scope key: `(scope TEXT PRIMARY KEY, total_usd NUMERIC, updated_at TIMESTAMPTZ)`. Increments use ON CONFLICT UPDATE for atomic compare-and-set semantics. | | `PostgresCostBudgetStoreOptions` | `type` | `PostgresCostBudgetStoreOptions` | Configuration options for postgres cost budget store. | | `postgresDeletionEvidenceStore` | `value` | `(client: PostgresClientLike, options?: { tablePrefix?: string; }) => DeletionEvidenceStore` | Storage contract for postgres deletion evidence. | | `PostgresMigration` | `type` | `PostgresMigration` | Type contract for postgres migration. | | `PostgresMigrationResult` | `type` | `PostgresMigrationResult` | Result returned by postgres migration. | | `postgresPersistence` | `value` | `(options: PostgresPersistenceOptions) => FabricPersistence` | One Postgres/Lakebase bundle for every durable Node server store. | | `PostgresPersistenceOptions` | `type` | `PostgresPersistenceOptions` | Configuration options for postgres persistence. | | `PostgresRestoreResult` | `type` | `PostgresRestoreResult` | Result returned by postgres restore. | | `postgresSandboxOwnershipLeaseStore` | `value` | `(client: SandboxOwnershipPostgresClient, options?: { tableName?: string; }) => SandboxOwnershipLeaseStore` | Atomic, expiry-aware ownership leases for portable sandboxes. | | `postgresSchedulerLeaseStore` | `value` | `(client: SchedulerPostgresClient, options?: { tableName?: string; }) => SchedulerLeaseStore` | Postgres-backed scheduler leases for horizontally scaled Node deployments. | | `postgresSessionMemory` | `value` | `(options: PostgresSessionMemoryOptions) => SessionMemory` | Postgres-backed `SessionMemory`. Persistent across process restarts; scoped by tenantId. Pair with `init({ memory })` to share recall across a fleet of agents. Schema: CREATE TABLE fabric_harness_session_memory ( tenant_id TEXT NOT NULL DEFAULT '', key TEXT NOT NULL, value JSONB NOT NULL, metadata JSONB, expires_at TIMESTAMPTZ, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (tenant_id, key) ); Set/Get scrub expired rows lazily on access. Run a scheduled `DELETE WHERE expires_at < NOW()` if you have many TTL'd entries. | | `PostgresSessionMemoryOptions` | `type` | `PostgresSessionMemoryOptions` | Configuration options for postgres session memory. | | `PostgresSessionStore` | `value` | `typeof PostgresSessionStore` | Storage contract for postgres session. | | `PostgresSessionStoreOptions` | `type` | `PostgresSessionStoreOptions` | Configuration options for postgres session store. | | `PostgresSubmissionStore` | `value` | `typeof PostgresSubmissionStore` | Storage contract for postgres submission. | | `PostgresSubmissionStoreOptions` | `type` | `PostgresSubmissionStoreOptions` | Configuration options for postgres submission store. | | `principalHasPermission` | `value` | `(principal: ServerPrincipal, permission: ServerPermission) => boolean` | Runtime API for principal has permission; the generated signature shows its accepted inputs and return type. | | `principalToActor` | `value` | `(principal: ServerPrincipal) => FabricActor` | Runtime API for principal to actor; the generated signature shows its accepted inputs and return type. | | `principalToApprovalActor` | `value` | `(principal: ServerPrincipal) => ActorIdentity` | Runtime API for principal to approval actor; the generated signature shows its accepted inputs and return type. | | `PrivateNetworkFetchClient` | `type` | `PrivateNetworkFetchClient` | Client implementation for private network fetch. | | `PrivateNetworkFetchOptions` | `type` | `PrivateNetworkFetchOptions` | Configuration options for private network fetch. | | `PrivateNetworkProxyOptions` | `type` | `PrivateNetworkProxyOptions` | Configuration options for private network proxy. | | `PrivateNetworkTlsOptions` | `type` | `PrivateNetworkTlsOptions` | Configuration options for private network tls. | | `readBuildManifest` | `value` | `(workspaceRoot: string, target: string) => Promise<BuildManifest \| undefined>` | Runtime API for read build manifest; the generated signature shows its accepted inputs and return type. | | `redisApprovalNotificationStore` | `value` | `(options: RedisApprovalNotificationStoreOptions) => ApprovalNotificationDeliveryStore` | Distributed dedupe state for `approvalNotificationHandler()`. | | `RedisApprovalNotificationStoreOptions` | `type` | `RedisApprovalNotificationStoreOptions` | Configuration options for redis approval notification store. | | `RedisClientLike` | `type` | `RedisClientLike` | Cross-process token-bucket rate limiter backed by Redis. Pair with `OpenAICompatibleModelProvider` / `AnthropicModelProvider` to enforce a shared API-key quota across a fleet of containers. `RedisClientLike` only requires an `eval` method — both `ioredis` and `@upstash/redis` ship a compatible signature. fabric-harness does NOT depend on either; users pass their own client. | | `redisHttpRateLimiter` | `value` | `(options: RedisHttpRateLimiterOptions) => HttpRateLimiter` | Creates an atomic, cross-process HTTP limiter for `startDevServer`. The caller supplies its Redis client so the Node package has no Redis SDK dependency. | | `RedisHttpRateLimiterOptions` | `type` | `RedisHttpRateLimiterOptions` | Configuration options for redis http rate limiter. | | `redisPersistence` | `value` | `(options: RedisPersistenceOptions) => FabricPersistence` | Redis/Valkey bundle with cluster-safe keys, binary attachments, and optional retention TTL. | | `RedisPersistenceClient` | `type` | `RedisPersistenceClient` | Client implementation for redis persistence. | | `RedisPersistenceOptions` | `type` | `RedisPersistenceOptions` | Configuration options for redis persistence. | | `redisRateLimiter` | `value` | `(options: RedisRateLimiterOptions) => RateLimiter` | Runtime API for redis rate limiter; the generated signature shows its accepted inputs and return type. | | `RedisRateLimiterOptions` | `type` | `RedisRateLimiterOptions` | Configuration options for redis rate limiter. | | `renderOperatorConsole` | `value` | `() => string` | Runtime API for render operator console; the generated signature shows its accepted inputs and return type. | | `renderResponsesInput` | `value` | `(input: string \| FabricResponsesInputItem[]) => string` | Runtime API for render responses input; the generated signature shows its accepted inputs and return type. | | `ReplayInspection` | `type` | `ReplayInspection` | Type contract for replay inspection. | | `resolveAgentPath` | `value` | `(workspaceRoot: string, agent: string) => Promise<string>` | Resolves agent path. | | `resolveApprovalInStore` | `value` | `(store: SessionStore, sessionId: string, approvalId: string, decision: "approved" \| "denied", reason?: string, actor?: ActorIdentity \| string) => Promise<ApprovalSummary>` | Resolves approval in store. | | `resolveConfigPath` | `value` | `(workspaceRoot: string) => Promise<string \| undefined>` | Resolves config path. | | `resolveDatabricksAppResourceBindings` | `value` | `(input: readonly FabricHarnessDatabricksAppResourceConfig[] \| undefined, options?: ResolveDatabricksAppResourceBindingsOptions) => ResolvedDatabricksAppResourceBinding[]` | Validate and normalize native Databricks App resource bindings without network access. | | `ResolveDatabricksAppResourceBindingsOptions` | `type` | `ResolveDatabricksAppResourceBindingsOptions` | Configuration options for resolve databricks app resource bindings. | | `resolveDaytonaToolRefs` | `value` | `(bundle: DaytonaBundle, refs: string[]) => ToolDef[]` | Resolves daytona tool refs. | | `ResolvedDatabricksAppResourceBinding` | `type` | `ResolvedDatabricksAppResourceBinding` | Type contract for resolved databricks app resource binding. | | `ResolvedDatabricksAppResourceVariable` | `type` | `ResolvedDatabricksAppResourceVariable` | Type contract for resolved databricks app resource variable. | | `resolveDockerToolRefs` | `value` | `(bundle: DockerBundle, refs: string[]) => ToolDef[]` | Resolves docker tool refs. | | `resolveE2bToolRefs` | `value` | `(bundle: E2bBundle, refs: string[]) => ToolDef[]` | Resolves e2b tool refs. | | `resolveK8sToolRefs` | `value` | `(bundle: K8sBundle, refs: string[]) => ToolDef[]` | Resolves k8s tool refs. | | `resolveModalToolRefs` | `value` | `(bundle: ModalBundle, refs: string[]) => ToolDef[]` | Resolves modal tool refs. | | `resolvePrincipalTenant` | `value` | `(principal: ServerPrincipal, requestedTenantId: string \| undefined) => { tenantId?: string; forbidden: boolean; }` | Resolves principal tenant. | | `resolveServerPermission` | `value` | `(method: string \| undefined, path: string) => ServerPermission` | Resolves server permission. | | `resolveSessionApproval` | `value` | `(workspaceRoot: string, sessionId: string, approvalId: string, decision: "approved" \| "denied", reason?: string, actor?: ActorIdentity \| string) => Promise<ApprovalSummary>` | Resolves session approval. | | `resolveSseKeepaliveMs` | `value` | `(env?: NodeJS.ProcessEnv) => number` | Resolve the SSE keepalive interval from the environment. Returns the parsed `FABRIC_HARNESS_SSE_KEEPALIVE_MS` value, or the 15000ms default. Negative or unparseable values fall back to the default. Returns `0` when explicitly set to `0`, disabling keepalive. | | `resolveToolRefs` | `value` | `(bundle: NodeBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | | `resolveWorkspacePackageImport` | `value` | `(workspaceRoot: string, packageName: string) => Promise<string \| undefined>` | Resolve an installed package's ESM entrypoint from the workspace dependency tree. | | `responseIdForSubmission` | `value` | `(submissionId: string) => string` | Runtime API for response id for submission; the generated signature shows its accepted inputs and return type. | | `responseTraceIdForSubmission` | `value` | `(submissionId: string) => string` | Matches the deterministic trace id emitted by the Databricks MLflow trace exporter. | | `restorePostgresPersistence` | `value` | `(input: { client: PostgresClientLike; objectStore: BackupObjectStore; objectKey: string; tablePrefix?: string; }) => Promise<PostgresRestoreResult>` | Verify and restore a logical backup under an exclusive advisory lock and transaction. | | `RetentionResult` | `type` | `RetentionResult` | Result returned by retention. | | `RetentionRule` | `type` | `RetentionRule` | Type contract for retention rule. | | `RouteScope` | `type` | `RouteScope` | The canonical HTTP route surface every TechFabric Harness runtime target serves. Node and Cloudflare reach this surface through different code: the Node target boots `server.ts` directly, while the Cloudflare target runs a worker generated by `build.ts`. Two implementations of one surface drift silently, so the surface is declared here as data and asserted against both — see `test/route-surface-parity.test.ts`. This table is the contract, not a description of either implementation. Add a route here first, then make both targets serve it. Scope of the current enforcement: the parity test runs th... | | `RouteSurfaceEntry` | `type` | `RouteSurfaceEntry` | Type contract for route surface entry. | | `runAgent` | `value` | `(options: RunAgentOptions) => Promise<RunAgentResult>` | Runs agent. | | `runAgentFile` | `value` | `(options: RunAgentFileOptions) => Promise<RunAgentFileResult>` | Run a finite `defineAgent()` agent straight from a file, with no workspace. | | `RunAgentFileOptions` | `type` | `RunAgentFileOptions` | Configuration options for run agent file. | | `RunAgentFileResult` | `type` | `RunAgentFileResult` | Result returned by run agent file. | | `RunAgentOptions` | `type` | `RunAgentOptions` | Configuration options for run agent. | | `RunAgentResult` | `type` | `RunAgentResult` | Result returned by run agent. | | `runPersistentPrompt` | `value` | `(options: PersistentPromptOptions) => Promise<PersistentPromptResult>` | Runs persistent prompt. | | `runPersistentTask` | `value` | `(options: PersistentTaskOptions) => Promise<PersistentTaskResult>` | Invoke a hook-registered persistent-agent specialist through the normal bounded task runtime. | | `runPostgresRecoveryDrill` | `value` | `(input: { client: PostgresClientLike; objectStore: BackupObjectStore; objectKey: string; tablePrefix?: string; simulateFailure: () => Promise<void>; verify: () => Promise<void>; maxRtoMs?: number; maxRpoSeconds?: number; }) => Promise<{ b...` | Runs postgres recovery drill. | | `SandboxOwnershipPostgresClient` | `type` | `SandboxOwnershipPostgresClient` | Client implementation for sandbox ownership postgres. | | `SchedulerLeaseStore` | `type` | `SchedulerLeaseStore` | Storage contract for scheduler lease. | | `SchedulerPostgresClient` | `type` | `SchedulerPostgresClient` | Client implementation for scheduler postgres. | | `ServerAuthorizationContext` | `type` | `ServerAuthorizationContext` | Type contract for server authorization context. | | `ServerPermission` | `type` | `ServerPermission` | Type contract for server permission. | | `ServerPrincipal` | `type` | `ServerPrincipal` | Type contract for server principal. | | `SessionMetrics` | `type` | `SessionMetrics` | Type contract for session metrics. | | `sessionRunStore` | `value` | `(store: SessionStore) => RunStore` | Storage contract for session run. | | `SessionSummary` | `type` | `SessionSummary` | Type contract for session summary. | | `SessionTimeline` | `type` | `SessionTimeline` | Type contract for session timeline. | | `sharedRouteSurface` | `value` | `() => readonly RouteSurfaceEntry[]` | Routes both targets must serve. | | `SqliteAttachmentStore` | `value` | `typeof SqliteAttachmentStore` | Storage contract for sqlite attachment. | | `SqliteAttachmentStoreOptions` | `type` | `SqliteAttachmentStoreOptions` | Configuration options for sqlite attachment store. | | `SqliteConversationStreamStore` | `value` | `typeof SqliteConversationStreamStore` | Storage contract for sqlite conversation stream. | | `SqliteConversationStreamStoreOptions` | `type` | `SqliteConversationStreamStoreOptions` | Configuration options for sqlite conversation stream store. | | `SqliteCostBudgetStore` | `value` | `typeof SqliteCostBudgetStore` | Atomic cross-process cost totals for a single-node SQLite deployment. | | `SqliteCostBudgetStoreOptions` | `type` | `SqliteCostBudgetStoreOptions` | Configuration options for sqlite cost budget store. | | `SqliteDatabaseLike` | `type` | `SqliteDatabaseLike` | The slice of `node:sqlite`'s `DatabaseSync` this store uses. | | `sqlitePersistence` | `value` | `(options: SqlitePersistenceOptions) => FabricPersistence` | Unified durable bundle for local and single-node deployments. | | `SqlitePersistenceOptions` | `type` | `SqlitePersistenceOptions` | Configuration options for sqlite persistence. | | `SQLiteSessionStore` | `value` | `typeof SQLiteSessionStore` | Storage contract for sqlite session. | | `SQLiteSessionStoreOptions` | `type` | `SQLiteSessionStoreOptions` | Configuration options for sqlite session store. | | `SqliteSubmissionStore` | `value` | `typeof SqliteSubmissionStore` | Storage contract for sqlite submission. | | `SqliteSubmissionStoreOptions` | `type` | `SqliteSubmissionStoreOptions` | Configuration options for sqlite submission store. | | `SSE_KEEPALIVE_DEFAULT_MS` | `value` | `15000` | Constant defining sse keepalive default ms. | | `startDevServer` | `value` | `(options?: DevServerOptions) => Promise<DevServerHandle>` | Runtime API for start dev server; the generated signature shows its accepted inputs and return type. | | `startJobScheduler` | `value` | `(options: JobSchedulerOptions) => Promise<JobScheduler>` | Start an in-process cron scheduler for finite job `triggers.schedule` values. | | `submissionIdFromResponseId` | `value` | `(responseId: string) => string \| undefined` | Runtime API for submission id from response id; the generated signature shows its accepted inputs and return type. | | `targetOnlyRouteSurface` | `value` | `(target: "node" \| "cloudflare") => readonly RouteSurfaceEntry[]` | Routes one target serves and the other deliberately does not. | | `TaskStatus` | `type` | `TaskStatus` | Type contract for task status. | | `TaskSummary` | `type` | `TaskSummary` | Type contract for task summary. | | `TimelineItem` | `type` | `TimelineItem` | Type contract for timeline item. | | `transpileAgent` | `value` | `(options: TranspileAgentOptions) => Promise<string>` | Runtime API for transpile agent; the generated signature shows its accepted inputs and return type. | | `TranspileAgentOptions` | `type` | `TranspileAgentOptions` | Configuration options for transpile agent. | | `validateWorkspace` | `value` | `(options?: ValidateWorkspaceOptions) => Promise<WorkspaceDiagnostic[]>` | Validate a workspace without running it. Returns findings ordered by file. An empty array means every check passed; it does not mean the workspace has no problems a running agent would find. | | `ValidateWorkspaceOptions` | `type` | `ValidateWorkspaceOptions` | Configuration options for validate workspace. | | `vaultSecretProvider` | `value` | `(options: VaultSecretProviderOptions) => SecretProvider` | HashiCorp Vault KV v2 provider. Vault tokens remain in the adapter closure. | | `VaultSecretProviderOptions` | `type` | `VaultSecretProviderOptions` | Configuration options for vault secret provider. | | `verifyAttestation` | `value` | `(pathOrDir: string) => Promise<{ ok: true; manifestPath: string; attestationPath: string; manifestSha256: string; }>` | Runtime API for verify attestation; the generated signature shows its accepted inputs and return type. | | `verifyProvenance` | `value` | `(pathOrDir: string) => Promise<{ ok: true; manifestPath: string; provenancePath: string; manifestSha256: string; }>` | Runtime API for verify provenance; the generated signature shows its accepted inputs and return type. | | `withDeletionEvidence` | `value` | `(persistence: PersistenceBundle, options: { signer: DeletionEvidenceSigner; store: DeletionEvidenceStore; }) => PersistenceBundle` | Add signed, append-only deletion evidence to any persistence bundle. | | `withPostgresConnection` | `value` | `<T>(client: PostgresClientLike, operation: (connection: PostgresClientLike) => Promise<T>) => Promise<T>` | Runtime API for with postgres connection; the generated signature shows its accepted inputs and return type. | | `WorkspaceDiagnostic` | `type` | `WorkspaceDiagnostic` | Type contract for workspace diagnostic. | | `WorkspaceDiagnosticSeverity` | `type` | `WorkspaceDiagnosticSeverity` | Static validation of a workspace, before anything runs. A class of mistakes here is only discovered at model time: a skill activated by a name that no file defines, a role that does not exist, a Node built-in imported into a build targeting a runtime without it. Each of those fails late — after a run has started, sometimes after a deploy — when they are all decidable from the source. These checks read source text rather than executing it: a workspace must be checkable without credentials, without network, and without the side effects of importing agent modules. | | `WorkspaceInfo` | `type` | `WorkspaceInfo` | Type contract for workspace info. | ### `@fabric-harness/node/agent` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `defineNodeAgent` | `value` | `(options?: DefineNodeAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines node agent. | | `DefineNodeAgentOptions` | `type` | `DefineNodeAgentOptions` | Configuration options for define node agent. | | `node` | `value` | `(config: NodeBundleConfig, isMock?: boolean) => NodeBundle` | One-call wiring for a Node-native agent: resolves the model provider from config or env, includes built-in file/shell tools, and sets a safe default egress policy. | | `NodeBundle` | `type` | `NodeBundle` | Type contract for node bundle. | | `NodeBundleConfig` | `type` | `NodeBundleConfig` | Type contract for node bundle config. | | `resolveToolRefs` | `value` | `(bundle: NodeBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | ### `@fabric-harness/node/docker-agent` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `defineDockerAgent` | `value` | `(options?: DefineDockerAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines docker agent. | | `DefineDockerAgentOptions` | `type` | `DefineDockerAgentOptions` | Configuration options for define docker agent. | | `docker` | `value` | `(config: DockerBundleConfig, isMock?: boolean) => DockerBundle` | One-call wiring for a Docker-native agent: resolves the model provider from config or env, includes Docker-specific container tools, and sets a safe default egress policy. | | `DockerBundle` | `type` | `DockerBundle` | Type contract for docker bundle. | | `DockerBundleConfig` | `type` | `DockerBundleConfig` | Type contract for docker bundle config. | | `resolveDockerToolRefs` | `value` | `(bundle: DockerBundle, refs: string[]) => ToolDef[]` | Resolves docker tool refs. | ### `@fabric-harness/node/k8s-agent` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `defineK8sAgent` | `value` | `(options?: DefineK8sAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines k8s agent. | | `DefineK8sAgentOptions` | `type` | `DefineK8sAgentOptions` | Configuration options for define k8s agent. | | `k8s` | `value` | `(config: K8sBundleConfig, isMock?: boolean) => K8sBundle` | One-call wiring for a Kubernetes-native agent: resolves the model provider from config or env, includes K8s-specific kubectl tools, and sets a safe default egress policy. | | `K8sBundle` | `type` | `K8sBundle` | Type contract for k8s bundle. | | `K8sBundleConfig` | `type` | `K8sBundleConfig` | Type contract for k8s bundle config. | | `resolveK8sToolRefs` | `value` | `(bundle: K8sBundle, refs: string[]) => ToolDef[]` | Resolves k8s tool refs. | ## @fabric-harness/sdk ### `@fabric-harness/sdk` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `actionAsTool` | `value` | `<TInput, TOutput>(action: ActionDefinition<TInput, TOutput>, host: ActionHost) => ToolDef<unknown, TOutput>` | Expose an action to the model as a tool on an agent profile. The tool's JSON schema comes from the action's input schema; execution validates input/output exactly like `runAction`. | | `ActionContext` | `type` | `ActionContext<TInput>` | Context passed to an action's `run`. Unlike a tool's `execute` (a leaf capability invoked by the model), an action receives the harness itself and can orchestrate: prompt models, spawn sessions, call other actions. | | `ActionDefinition` | `type` | `ActionDefinition<TInput, TOutput>` | A named, schema-validated unit of harness work created with `defineAction`. First-class in v2: registrable on agent profiles as a tool, callable from jobs and agents, evaluable via `fh test`, and deployable as a platform job task. | | `ActionError` | `value` | `typeof ActionError` | Error raised for action failures. | | `ActionHost` | `type` | `ActionHost` | What an action runs against: the harness entry point (`init` can prompt models, spawn sessions, and call tools) plus the platform environment. Jobs, agents, and servers all satisfy this — it is the harness slice of `FabricContext`. | | `ActionOptions` | `type` | `ActionOptions<TInput, TOutput>` | Configuration options for action. | | `ActivateSkillInput` | `type` | `ActivateSkillInput` | Type contract for activate skill input. | | `ActorIdentity` | `type` | `ActorIdentity` | Type contract for actor identity. | | `ActualCostSource` | `type` | `ActualCostSource` | External source for actual (non-estimated) spend. Implementations can query provider billing APIs, Databricks usage tables, or other real-time cost data. | | `admitSubmissionWithBackend` | `value` | `<Row extends SubmissionAdmissionRow>(input: AgentSubmissionInput, backend: SubmissionAdmissionBackend<Row>) => AgentDispatchAdmission \| Promise<AgentDispatchAdmission>` | Shared submission admission algorithm for row-oriented backends: dispatch-receipt check → insert-or-ignore → read-back → payload compare (idempotent replay vs. conflict). The message payload is stored as JSON verbatim; payload identity is deep JSON equality, so a backend that normalizes stored JSON (e.g. Postgres JSONB key ordering) still recognizes an exact replay. The caller owns transaction scoping — invoke this inside one transaction and pass callbacks bound to it. When every callback is synchronous the result is returned synchronously, so the algorithm also fits synchronous backends. | | `AgentAttemptMarker` | `type` | `AgentAttemptMarker` | Harness-owned durable evidence that a submission attempt was started and has not yet settled. A coordinator inserts a marker immediately before starting an attempt and deletes it when the attempt settles; reconciliation treats a fresh marker as proof that the attempt may still be running and must not be reconciled as interrupted. | | `AgentDefinition` | `type` | `AgentDefinition<TInput, TOutput>` | Type contract for agent definition. | | `AgentDispatchAdmission` | `type` | `AgentDispatchAdmission` | Type contract for agent dispatch admission. | | `AgentDispatchReceipt` | `type` | `AgentDispatchReceipt` | Type contract for agent dispatch receipt. | | `AgentDispatchRequest` | `type` | `AgentDispatchRequest` | Async delivery request to a persistent agent instance + session. | | `AgentEvent` | `type` | `AgentEvent` | Type contract for agent event. | | `AgentEventBase` | `type` | `AgentEventBase` | Common envelope shared by every event variant. | | `AgentEventCallback` | `type` | `AgentEventCallback` | Callback signature accepted by `init({ onEvent })`, `agent.session(id, { onEvent })`, and `session.prompt(text, { onEvent })`. | | `AgentEventType` | `type` | `"error" \| "agent_start" \| "session_start" \| "prompt_start" \| "prompt_end" \| "turn_start" \| "turn_end" \| "model_attempt" \| "text_delta" \| "toolcall_delta" \| "submission_queued" \| "submission_running" \| "submission_recovery" \| "submission_settled" \| "cost_limit" \|...` | Type contract for agent event type. | | `AgentInit` | `type` | `AgentInit` | Type contract for agent init. | | `agentInstancePath` | `value` | `(agent: string, instanceId: string) => string` | Base path for one persistent instance, with both segments escaped. | | `AgentLoopRuntime` | `type` | `AgentLoopRuntime` | Type contract for agent loop runtime. | | `AgentMiddleware` | `type` | `(context: AgentRunContext<TInput>, next: () => Promise<TOutput>) => Promise<TOutput> \| TOutput` | Middleware for agent. | | `AgentProfile` | `type` | `AgentProfile` | Type contract for agent profile. | | `AgentProfileOptions` | `type` | `AgentProfileOptions` | Configuration options for agent profile. | | `AgentRouteMatch` | `type` | `AgentRouteMatch` | Type contract for agent route match. | | `AgentRouteSection` | `type` | `AgentRouteSection` | Subroutes under `/agents/:name/:instanceId`. | | `agentRouteSession` | `value` | `(searchParams: URLSearchParams) => string` | Session name carried by `?session=`, defaulting to `default`. | | `AgentRunContext` | `type` | `AgentRunContext<TInput>` | Runtime-ready context for finite agents. The default session is initialized lazily. | | `AgentSubmission` | `type` | `AgentSubmission` | Type contract for agent submission. | | `AgentSubmissionDurability` | `type` | `AgentSubmissionDurability` | Type contract for agent submission durability. | | `AgentSubmissionInput` | `type` | `AgentSubmissionInput` | One admitted agent submission — the persisted operational payload for both transports. `kind` records how the submission arrived (`'dispatch'` via `dispatch()`, `'direct'` via the agent HTTP route); a dispatch's `submissionId` is the public `dispatchId` from its receipt. | | `agentSubmissionReceipt` | `value` | `(input: AgentSubmissionReceiptInput) => AgentSubmissionReceipt` | Build the `202` admission receipt. `streamUrl` and `conversationUrl` are the same URL; the former is retained for compatibility with clients written against the earlier shape. | | `AgentSubmissionReceipt` | `type` | `AgentSubmissionReceipt` | Type contract for agent submission receipt. | | `AgentSubmissionReceiptInput` | `type` | `AgentSubmissionReceiptInput` | Type contract for agent submission receipt input. | | `AgentSubmissionStatus` | `type` | `AgentSubmissionStatus` | Type contract for agent submission status. | | `AgentSubmissionStore` | `type` | `AgentSubmissionStore` | Durable submission lifecycle storage. Stability: the lease method group mirrors the durable-execution engine and is subject to change until 1.0. This applies to every backend equally. | | `AgentTriggers` | `type` | `AgentTriggers` | Type contract for agent triggers. | | `aiGateway` | `value` | `(options: AIGatewayOptions) => OpenAICompatibleModelProvider` | Generic OpenAI-compatible AI gateway helper. Use for **any** gateway that speaks the OpenAI Chat Completions request/response shape: Helicone, Portkey, LiteLLM (self-hosted), Cloudflare AI Gateway, internal corp proxies, etc. See the package declarations for an example. For Vercel AI Gateway, prefer the `vercelAIGateway` preset — same factory under the hood with the gateway URL pre-baked. | | `AIGatewayOptions` | `type` | `AIGatewayOptions` | Configuration options for aigateway. | | `AnthropicModelProvider` | `value` | `typeof AnthropicModelProvider` | Provider implementation for anthropic model. | | `AnthropicProviderOptions` | `type` | `AnthropicProviderOptions` | Configuration options for anthropic provider. | | `applyEstimatedCost` | `value` | `<T extends { costUsd?: number; } \| undefined>(modelRef: string \| undefined, usage: T) => T` | Idempotently populate `usage.costUsd` from the static price table. Mutates `usage` and returns it. No-op when: - `usage` is undefined, - `usage.costUsd` is already set (provider supplied it directly), - no price row matches `modelRef`. | | `ApprovalCallback` | `type` | `ApprovalCallback` | Type contract for approval callback. | | `ApprovalDecision` | `type` | `ApprovalDecision` | Type contract for approval decision. | | `ApprovalGrant` | `type` | `ApprovalGrant` | Durable provenance for one approved logical tool operation. A grant may be replayed for the same logical operation after a crash, but must never authorize a different tool call, input, or executing principal. | | `approvalGrantFromJson` | `value` | `(value: unknown) => ApprovalGrant \| undefined` | Parse persisted provenance without trusting a partial or malformed object. | | `approvalGrantToJson` | `value` | `(grant: ApprovalGrant) => JsonObject` | Runtime API for approval grant to json; the generated signature shows its accepted inputs and return type. | | `approvalInputDigest` | `value` | `(input: unknown) => string` | Deterministic digest shared by inline and durable approval runtimes. | | `ApprovalNotification` | `type` | `ApprovalNotification` | Type contract for approval notification. | | `ApprovalNotificationDeadLetter` | `type` | `ApprovalNotificationDeadLetter` | Type contract for approval notification dead letter. | | `ApprovalNotificationDeliveryStore` | `type` | `ApprovalNotificationDeliveryStore` | Storage contract for approval notification delivery. | | `approvalNotificationFromEvent` | `value` | `(event: FabricEvent, baseUrl?: string) => ApprovalNotification \| undefined` | Runtime API for approval notification from event; the generated signature shows its accepted inputs and return type. | | `approvalNotificationHandler` | `value` | `(options: ApprovalNotificationHandlerOptions) => FabricEventCallback` | Convert approval events into retryable, deduplicated notifications. This callback never throws. | | `ApprovalNotificationHandlerOptions` | `type` | `ApprovalNotificationHandlerOptions` | Configuration options for approval notification handler. | | `ApprovalNotificationState` | `type` | `ApprovalNotificationState` | Type contract for approval notification state. | | `ApprovalNotifier` | `type` | `ApprovalNotifier` | Type contract for approval notifier. | | `ApprovalOptions` | `type` | `ApprovalOptions` | Configuration options for approval. | | `ApprovalPolicyRule` | `type` | `ApprovalPolicyRule` | Per-pattern approval metadata. Lets policy authors route specific tools/commands to a named audience (e.g. `'reviewer'`, `'compliance-team'`, `'project-admin'`). The audience id is opaque to fabric-harness — host applications map ids to humans via their own identity layer. | | `ApprovalRequest` | `type` | `ApprovalRequest` | Input contract for approval. | | `ApprovalResponse` | `type` | `ApprovalResponse` | Response contract for approval. | | `ApprovalRisk` | `type` | `ApprovalRisk` | Type contract for approval risk. | | `ApprovalState` | `type` | `ApprovalState` | Type contract for approval state. | | `approvalStatesFromEntries` | `value` | `(sessionId: string, entries: SessionEntry[]) => ApprovalState[]` | Runtime API for approval states from entries; the generated signature shows its accepted inputs and return type. | | `ApprovalStateStatus` | `type` | `ApprovalStateStatus` | Type contract for approval state status. | | `ApprovalUnavailableStrategy` | `type` | `ApprovalUnavailableStrategy` | Type contract for approval unavailable strategy. | | `ApprovalVote` | `type` | `ApprovalVote` | Type contract for approval vote. | | `ArtifactCreateOptions` | `type` | `ArtifactCreateOptions` | Configuration options for artifact create. | | `ArtifactRef` | `type` | `ArtifactRef` | Type contract for artifact ref. | | `assertEnforceableNetworkPolicy` | `value` | `(policy: CapabilityPolicy \| undefined, sandbox: SandboxEnv \| Pick<SandboxCapabilities, "network" \| "networkEnforcement" \| "networkBoundary"> \| undefined, requirement?: NetworkEnforcementRequirement) => void` | Refuse production network policy when it can be bypassed by code in the sandbox. This validates an operator assertion; the named network boundary must still be provisioned by Docker, Kubernetes, or the cloud provider. | | `attachmentDigest` | `value` | `(bytes: Uint8Array) => Promise<string>` | Lowercase hex SHA-256 of the bytes (WebCrypto). | | `AttachmentLimitError` | `value` | `typeof AttachmentLimitError` | Error raised for attachment limit failures. | | `AttachmentPutInput` | `type` | `AttachmentPutInput` | Type contract for attachment put input. | | `AttachmentRef` | `type` | `AttachmentRef` | Content-addressed descriptor of one stored attachment. | | `AttachmentStore` | `type` | `AttachmentStore` | Durable content-addressed attachment storage. - `put` is idempotent by `(scope, digest)` — re-putting the same content succeeds without duplicating storage (the first stored ref metadata is retained). It MUST verify the digest against the bytes and reject a mismatch with `AttachmentStoreError('DIGEST_MISMATCH')` before writing. - `get`/`getByAttachmentId` return `null` on a miss. - `delete` removes one stored attachment and throws `AttachmentStoreError('NOT_FOUND')` when nothing is stored under `(scope, digest)`. | | `AttachmentStoreError` | `value` | `typeof AttachmentStoreError` | Error raised for attachment store failures. | | `attachSandbox` | `value` | `(ref: SandboxRef \| SerializedSandboxRef, options?: AttachSandboxOptions) => SandboxFactory` | Build a `SandboxFactory` that, when invoked, returns an `AttachedSandboxEnv` delegating to the registered sandbox without owning its lifecycle. Calling `cleanup()` on the attached env unregisters this attachment but does NOT tear down the underlying sandbox. Pass an in-process `SandboxRef` to attach within the same process, or a `SerializedSandboxRef` (from `session.sandboxRef({ portable: true })`) to rehydrate a sandbox handed off from another process. Cross-process refs require a decoder registered for `serialized.provider` via `registerSandboxRefDecoder()`. | | `AttachSandboxOptions` | `type` | `AttachSandboxOptions` | Configuration options for attach sandbox. | | `AttributionQuery` | `type` | `AttributionQuery` | Query filters for retrieving aggregated cost attribution rows. | | `AutonomyMode` | `type` | `AutonomyMode` | Type contract for autonomy mode. | | `AutonomyOptions` | `type` | `AutonomyOptions` | Configuration options for autonomy. | | `AzureOpenAIModelProvider` | `value` | `typeof AzureOpenAIModelProvider` | Provider implementation for azure open aimodel. | | `AzureOpenAIProviderOptions` | `type` | `AzureOpenAIProviderOptions` | Configuration options for azure open aiprovider. | | `BashInput` | `type` | `BashInput` | Type contract for bash input. | | `bashTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<BashInput, ShellResult>` | Model-callable tool or tool factory for bash. | | `BedrockModelProvider` | `value` | `typeof BedrockModelProvider` | Provider implementation for bedrock model. | | `BedrockProviderOptions` | `type` | `BedrockProviderOptions` | Configuration options for bedrock provider. | | `buildModelMessagesFromHistory` | `value` | `(data: SessionData \| undefined, role?: Role) => ModelMessage[]` | Runtime API for build model messages from history; the generated signature shows its accepted inputs and return type. | | `buildResultFollowUpPrompt` | `value` | `() => string` | Follow-up prompt sent when the LLM ends a turn without calling `finish` or `give_up`. | | `buildResultFooter` | `value` | `() => string` | Footer appended to user prompts/skill bodies when a `result` schema is set. | | `buildResultRetryPrompt` | `value` | `(error: unknown, extraction?: boolean \| ResultExtractionOptions) => string` | Runtime API for build result retry prompt; the generated signature shows its accepted inputs and return type. | | `BUILTIN_BASH_MAX_BYTES` | `value` | `number` | Constant defining builtin bash max bytes. | | `BUILTIN_BASH_MAX_LINES` | `value` | `2000` | Constant defining builtin bash max lines. | | `BUILTIN_GLOB_MAX_RESULTS` | `value` | `1000` | Constant defining builtin glob max results. | | `BUILTIN_GREP_MAX_LINE_LENGTH` | `value` | `500` | Constant defining builtin grep max line length. | | `BUILTIN_GREP_MAX_MATCHES` | `value` | `100` | Constant defining builtin grep max matches. | | `BUILTIN_READ_MAX_BYTES` | `value` | `number` | Constant defining builtin read max bytes. | | `BUILTIN_READ_MAX_LINES` | `value` | `2000` | Public built-in tool limits; documentation and tests consume these constants. | | `BuiltinFileTool` | `type` | `BuiltinFileTool` | Model-callable tool or tool factory for builtin file. | | `BuiltinTool` | `type` | `BuiltinTool` | Model-callable tool or tool factory for builtin. | | `bytesToHex` | `value` | `(bytes: Uint8Array) => string` | Runtime API for bytes to hex; the generated signature shows its accepted inputs and return type. | | `CapabilityPolicy` | `type` | `CapabilityPolicy` | Type contract for capability policy. | | `CartesiaSttProvider` | `value` | `typeof CartesiaSttProvider` | Provider implementation for cartesia stt. | | `CartesiaSttProviderOptions` | `type` | `CartesiaSttProviderOptions` | Configuration options for cartesia stt provider. | | `CartesiaTtsProvider` | `value` | `typeof CartesiaTtsProvider` | Provider implementation for cartesia tts. | | `CartesiaTtsProviderOptions` | `type` | `CartesiaTtsProviderOptions` | Configuration options for cartesia tts provider. | | `chainSecretProviders` | `value` | `(...providers: Array<SecretProvider \| undefined>) => SecretProvider` | Resolve from providers in order; errors fail closed instead of falling through. | | `Channel` | `type` | `Channel` | Type contract for channel. | | `ChannelContext` | `type` | `ChannelContext` | Type contract for channel context. | | `ChannelDispatch` | `type` | `ChannelDispatch` | Type contract for channel dispatch. | | `ChannelDispatchRequest` | `type` | `ChannelDispatchRequest` | Input contract for channel dispatch. | | `ChannelRoute` | `type` | `ChannelRoute` | Channels turn platform webhooks (Slack, GitHub, …) into agent dispatches. Handlers are written against the Web `Request`/`Response` API and `crypto.subtle`, so the same channel runs on Node and Cloudflare. A channel is a stateless route container plus a conversation-id (de)serializer — session continuity falls out of the key (same thread → same key → same session). | | `CheckpointCreateOptions` | `type` | `CheckpointCreateOptions` | Configuration options for checkpoint create. | | `CheckpointRestoreOptions` | `type` | `CheckpointRestoreOptions` | Configuration options for checkpoint restore. | | `CheckpointResult` | `type` | `CheckpointResult` | Result returned by checkpoint. | | `claimSandboxOwnership` | `value` | `(ref: SerializedSandboxRef, env: SandboxEnv, options: SandboxOwnershipOptions) => Promise<SandboxEnv>` | Claim exclusive ownership of an already-connected portable sandbox. | | `clampCommandTimeout` | `value` | `(timeout: number \| undefined, policy?: CapabilityPolicy) => number \| undefined` | Runtime API for clamp command timeout; the generated signature shows its accepted inputs and return type. | | `clampReadLimit` | `value` | `(limit: number \| undefined) => number` | Runtime API for clamp read limit; the generated signature shows its accepted inputs and return type. | | `classifySubmissionState` | `value` | `(path: readonly SessionEntry[], submissionId: string) => SubmissionInspection` | Classify how far a persisted submission input progressed. - `absent` — the input entry never landed in session history: the attempt crashed before applying it. Safe to requeue for a clean first attempt. - `completed` — finished work: a canonical settlement entry exists, an assistant response follows the input with no unresolved trailing tool batch, or a later user input shows the conversation moved on. Settle as success; never retry (retrying completed work is the one unrecoverable corruption). - `continuable` — the trailing turn carries unresolved tool calls. The next `session.prompt()` re... | | `CohereModelProvider` | `value` | `typeof CohereModelProvider` | Provider implementation for cohere model. | | `CohereProviderOptions` | `type` | `CohereProviderOptions` | Configuration options for cohere provider. | | `combineSubmissionTelemetrySinks` | `value` | `(...sinks: SubmissionTelemetrySink[]) => SubmissionTelemetrySink` | Fan one event out to several sinks. | | `Command` | `type` | `Command<TInput>` | Type contract for command. | | `CommandEnvValue` | `type` | `CommandEnvValue` | Type contract for command env value. | | `CommandPolicy` | `type` | `CommandPolicy` | Type contract for command policy. | | `CommandToolInput` | `type` | `CommandToolInput` | Type contract for command tool input. | | `CommandToolOptions` | `type` | `CommandToolOptions` | Configuration options for command tool. | | `CompactionOptions` | `type` | `CompactionOptions` | Configuration options for compaction. | | `CompactionResult` | `type` | `CompactionResult` | Result returned by compaction. | | `configureDispatchRuntime` | `value` | `(runtime: DispatchRuntime) => void` | Configure the ambient dispatch queue used by `dispatch`. | | `configureJobInvocationRuntime` | `value` | `(next: JobInvocationRuntime) => void` | Runtime API for configure job invocation runtime; the generated signature shows its accepted inputs and return type. | | `connectFabricVoice` | `value` | `(options: VoiceWsClientOptions) => VoiceWsClientHandle` | Runtime API for connect fabric voice; the generated signature shows its accepted inputs and return type. | | `connectFabricWs` | `value` | `(options: WsClientOptions) => WsClientHandle` | Runtime API for connect fabric ws; the generated signature shows its accepted inputs and return type. | | `connectMcpServer` | `value` | `(name: string, options: McpServerOptions) => Promise<McpServerConnection>` | Runtime API for connect mcp server; the generated signature shows its accepted inputs and return type. | | `consoleTelemetryExporter` | `value` | `(prefix?: string) => TelemetryExporter` | Telemetry exporter that writes spans through the SDK logger (default `console`-backed). Useful for local development and as a fallback when no OpenTelemetry collector is wired up. Use `openTelemetryExporter` or `langfuseExporter` for production. | | `ContextBudget` | `type` | `ContextBudget` | Type contract for context budget. | | `ContextBudgetOptions` | `type` | `ContextBudgetOptions` | Configuration options for context budget. | | `CONVERSATION_STREAM_DEFAULT_READ_LIMIT` | `value` | `100` | Constant defining conversation stream default read limit. | | `CONVERSATION_STREAM_FORMAT_VERSION` | `value` | `1` | Constant defining conversation stream format version. | | `CONVERSATION_STREAM_MAX_READ_LIMIT` | `value` | `1000` | Constant defining conversation stream max read limit. | | `ConversationFoldCheckpoint` | `type` | `ConversationFoldCheckpoint` | Disposable durable cache of a folded conversation at one committed batch. | | `conversationKey` | `value` | `(provider: string, version: string, ...segments: string[]) => string` | Runtime API for conversation key; the generated signature shows its accepted inputs and return type. | | `ConversationMessage` | `type` | `ConversationMessage` | Type contract for conversation message. | | `ConversationMessageDisplay` | `type` | `ConversationMessageDisplay` | Type contract for conversation message display. | | `ConversationMessagePurpose` | `type` | `ConversationMessagePurpose` | Type contract for conversation message purpose. | | `ConversationMessageRole` | `type` | `ConversationMessageRole` | Type contract for conversation message role. | | `ConversationPart` | `type` | `ConversationPart` | Type contract for conversation part. | | `ConversationProducerClaim` | `type` | `ConversationProducerClaim` | Type contract for conversation producer claim. | | `ConversationProjector` | `value` | `typeof ConversationProjector` | Runtime API for conversation projector; the generated signature shows its accepted inputs and return type. | | `ConversationReply` | `type` | `ConversationReply` | Type contract for conversation reply. | | `ConversationSettlement` | `type` | `ConversationSettlement` | Type contract for conversation settlement. | | `ConversationSnapshot` | `type` | `ConversationSnapshot` | Type contract for conversation snapshot. | | `ConversationStreamAppendInput` | `type` | `ConversationStreamAppendInput` | Type contract for conversation stream append input. | | `ConversationStreamBatch` | `type` | `ConversationStreamBatch` | Type contract for conversation stream batch. | | `ConversationStreamIdentity` | `type` | `ConversationStreamIdentity` | Type contract for conversation stream identity. | | `ConversationStreamMeta` | `type` | `ConversationStreamMeta` | Type contract for conversation stream meta. | | `conversationStreamPath` | `value` | `(storeSessionId: string) => string` | Stream path for a session's conversation projection. | | `ConversationStreamReadResult` | `type` | `ConversationStreamReadResult` | Result returned by conversation stream read. | | `ConversationStreamRecord` | `type` | `ConversationStreamRecord` | Append-only conversation stream — the durable, offset-addressable projection of a session's active path (v2 migration, phase A4). The SessionEntry DAG remains the single source of truth for model context; this stream exists so clients can read a conversation with offsets (catch-up + live tail), across processes, without count-based replay. The projection appends one record per active-path entry, and — because the DAG can branch (fork/replay/checkpoint-restore) while a stream cannot — an explicit `truncated` record whenever the active path rewinds, paired with a producer-epoch bump so stale... | | `ConversationStreamStore` | `type` | `ConversationStreamStore` | Durable append-only conversation stream storage. **Batch atomicity is a hard contract requirement**: every record in an `append` must be persisted together under one offset, all-or-nothing. First-party adapters satisfy this by serializing the batch into a single row/document write; an adapter that splits records across non-atomic writes violates the contract. **Producer fencing**: `acquireProducer` bumps the producer epoch; appends carrying a stale epoch are rejected. The (path, producerId, epoch, sequence) uniqueness makes redelivered appends idempotent — a retried append with the same coo... | | `ConversationStreamStoreError` | `value` | `typeof ConversationStreamStoreError` | Error raised for conversation stream store failures. | | `CostAttribution` | `type` | `CostAttribution` | Attribution dimensions for a single cost observation. All fields are optional so callers can tag as much or as little metadata as they have. | | `CostAttributionRow` | `type` | `CostAttributionRow` | A single row of aggregated cost attribution data. | | `CostBudgetStore` | `type` | `CostBudgetStore` | Async store for cross-process spend aggregation. Pair with `CostLimit.scopeKey` + `CostLimit.perScope` to enforce a budget that survives process restarts — "tenant:acme spends ≤ $50 today" or "company-wide ≤ $100 this hour". Built-in implementations: - `inMemoryCostBudgetStore()` — process-local; default. - `@fabric-harness/node` exposes `postgresCostBudgetStore({ pool })`. | | `CostBudgetTracker` | `value` | `typeof CostBudgetTracker` | Tracks cumulative session spend. Cheap to construct; one per session. | | `CostLimit` | `type` | `CostLimit` | Type contract for cost limit. | | `CostLimitContext` | `type` | `CostLimitContext` | Type contract for cost limit context. | | `CostLimitExceededError` | `value` | `typeof CostLimitExceededError` | Error raised for cost limit exceeded failures. | | `createActivateSkillTool` | `value` | `(skillNames: string[], activate: (name: string) => Promise<string>) => ToolDef<ActivateSkillInput, string>` | Creates activate skill tool. | | `createAgent` | `value` | `<TEnv = Record<string, string>>(initialize: ((context: PersistentAgentContext<TEnv>) => PersistentAgentConfig \| Promise<PersistentAgentConfig>) \| DynamicAgentFunction<TEnv>, definition?: PersistentAgentConfig) => CreatedAgent<TEnv>` | Define a persistent, URL-addressable agent. Files in `.fabricharness/agents/` default-export `createAgent(...)`; the runtime resolves a fresh config per interaction and keeps sessions across direct prompts and dispatched inputs. | | `createApprovalGrant` | `value` | `(input: { approvalId: string; toolCallId: string; toolInput: unknown; principal: FabricPrincipal; response: ApprovalResponse; createdAt: string; ttlSeconds?: number; decidedAt?: string; }) => ApprovalGrant` | Creates approval grant. | | `createApprovalGrantForState` | `value` | `(state: ApprovalState, response: ApprovalResponse) => ApprovalGrant \| undefined` | Build the terminal grant after a store reaches approval quorum. | | `createAttachmentRef` | `value` | `(input: { id: string; mimeType: string; bytes: Uint8Array; filename?: string; }) => Promise<AttachmentRef>` | Build an `AttachmentRef` for the given bytes, computing the SHA-256 digest via WebCrypto (`crypto.subtle`) so the SDK stays runtime-agnostic. | | `createBuiltinTools` | `value` | `(sandbox: SandboxEnv, packagedSkills?: Record<string, PackagedSkillDirectory>) => BuiltinTool[]` | Creates builtin tools. | | `createCommandTools` | `value` | `(commands: Command[], options?: CommandToolOptions) => ToolDef<CommandToolInput, ShellResult>[]` | Creates command tools. | | `createConsoleLogger` | `value` | `(level?: LogLevel) => Logger` | Build a Console-backed logger with an explicit level. Useful for tests that want to capture or silence SDK output without touching globals. | | `CreatedAgent` | `type` | `CreatedAgent<TEnv>` | A persistent, addressable agent created with `createAgent`. Distinct from a finite `defineAgent({ run })` job: it has no `run` — the initializer returns configuration, and the runtime maintains sessions across interactions. | | `createDirectAgentSubmissionInput` | `value` | `(options: { agent: string; id: string; session?: string; message: DeliveredMessage; initialData?: JsonValue; uid?: string \| null; joinWhileBusy?: boolean; tenantId?: string; actor?: FabricActor; durability?: AgentSubmissionDurability; }) => AgentSubmissionInput` | Mint a direct-prompt submission input with a fresh submission id. | | `createDispatchAgentSubmissionInput` | `value` | `(dispatch: DispatchInput) => AgentSubmissionInput` | Map a `DispatchInput` onto the persisted submission input shape. | | `createErrorReference` | `value` | `(now?: number) => string` | Mint an opaque, sortable correlation reference for one transported error. | | `createFabricAgentRouter` | `value` | `(backend: FabricAgentRouterBackend, options?: FabricAgentRouterOptions) => FabricAgentRouter` | Mount the persistent-agent HTTP surface on any fetch-capable host. See the package declarations for an example. | | `createFabricContext` | `value` | `<TPayload extends JsonObject = JsonObject>(payload: TPayload) => FabricContext<TPayload>` | Creates fabric context. | | `createFabricFs` | `value` | `(sandboxLike: SandboxEnv \| Promise<SandboxEnv> \| (() => SandboxEnv \| Promise<SandboxEnv>)) => FabricFs` | Adapt a sandbox into the public filesystem convenience surface. | | `createFileTools` | `value` | `(sandbox: SandboxEnv, packagedSkills?: Record<string, PackagedSkillDirectory>) => BuiltinFileTool[]` | Creates file tools. | | `createMcpAuthorizationCodeAuth` | `value` | `(options: McpAuthorizationCodeOptions) => OAuthClientProvider` | Authorization-code + PKCE provider; the MCP SDK refreshes stored tokens automatically. | | `createMcpClientCredentialsAuth` | `value` | `(options: McpClientCredentialsOptions) => OAuthClientProvider` | OAuth client-credentials provider with MCP SDK token refresh handling. | | `createMcpTools` | `value` | `(client: McpClientLike, options?: CreateMcpToolsOptions) => Promise<ToolDef[]>` | Creates mcp tools. | | `CreateMcpToolsOptions` | `type` | `CreateMcpToolsOptions` | Configuration options for create mcp tools. | | `createObservabilityObserver` | `value` | `(options: ObservabilityObserverOptions) => FabricEventCallback` | Create a fail-open event observer suitable for Braintrust, Sentry, Jetty, or a custom sink. | | `createObservabilityRecord` | `value` | `(event: FabricEvent, options: Pick<ObservabilityObserverOptions, "integration" \| "correlation" \| "captureData" \| "additionalSecrets">) => FabricObservabilityRecord` | Convert a Fabric event into a vendor-neutral, low-cardinality record. | | `createOperationalMetricsCollector` | `value` | `() => OperationalMetricsCollector` | Low-cardinality operational metrics collector suitable for OTel/Prometheus bridging. | | `createRemoteSandboxEnv` | `value` | `(api: RemoteSandboxApi, options?: RemoteSandboxOptions) => SandboxEnv` | Wrap a provider-owned remote sandbox client in Fabric's SandboxEnv contract. Provider credentials and SDK objects remain outside model context/history; Fabric only sees the narrow file/shell/snapshot API exposed here. | | `createResultTools` | `value` | `<TResult>(validator: ResultValidator<TResult>) => ResultToolBundle<TResult>` | Produce the per-call `finish` and `give_up` tool pair for a given ResultValidator. - `finish`'s parameters are a generic JSON Schema object because we can't derive a precise schema from `ResultValidator`. The validator's `safeParse` handles actual validation. - First successful `finish` (or `give_up`) call wins. Subsequent calls return an error tool result rather than throwing, to keep the conversation transcript natural. | | `createSandboxEnv` | `value` | `(options?: SandboxFactoryOptions) => Promise<SandboxEnv>` | Creates sandbox env. | | `createScopedSandboxEnv` | `value` | `(sandbox: SandboxEnv, cwd?: string) => SandboxEnv` | Return a view of a sandbox with a narrower default cwd. Relative file paths and shell cwd values are resolved from this scoped cwd while the underlying sandbox still enforces its workspace boundary. | | `createSearchTool` | `value` | `(retriever: Retriever, options?: SearchToolOptions) => ToolDef<SearchToolInput, SearchToolResult>` | Exposes a `Retriever` to the model as a `search` tool. The tool is read-only; wrap it with a governance decorator to stamp lineage or route approvals. | | `createSessionSubmissionExecutor` | `value` | `(options: SessionSubmissionExecutorOptions) => SubmissionExecutor` | Provider-neutral durable submission executor for hosts that can open a Fabric session themselves. Node, Durable Objects, and custom runtimes share the same recovery and conservative interrupted-tool settlement behavior. | | `createStdioMcpClient` | `value` | `(options: StdioMcpClientOptions) => StdioMcpClient` | Creates stdio mcp client. | | `createSubmissionRunner` | `value` | `(options: SubmissionRunnerOptions) => SubmissionRunner` | Creates submission runner. | | `createUnifiedInMemoryStore` | `value` | `() => UnifiedInMemoryStore` | Factory that returns a fresh `UnifiedInMemoryStore`. The returned object can be passed as `store`, `streamChunkStore`, and `runStore` simultaneously. | | `createVirtualSandboxEnv` | `value` | `(options?: SandboxFactoryOptions & { initialFiles?: Record<string, string \| Uint8Array>; }) => VirtualSandboxEnv` | Creates virtual sandbox env. | | `CredentialMissingStrategy` | `type` | `"fail"` | Type contract for credential missing strategy. | | `currentJobInvocation` | `value` | `() => JobInvocationContext \| undefined` | Runtime API for current job invocation; the generated signature shows its accepted inputs and return type. | | `currentSubmissionContext` | `value` | `() => SubmissionContext \| undefined` | The submission owning the current execution, or `undefined` outside one. | | `DeepgramSttProvider` | `value` | `typeof DeepgramSttProvider` | Provider implementation for deepgram stt. | | `DeepgramSttProviderOptions` | `type` | `DeepgramSttProviderOptions` | Configuration options for deepgram stt provider. | | `DEFAULT_HEADLESS_PREAMBLE` | `value` | `"You are running in headless autonomous mode (background-agent mode) with no human operator assumed. Work autonomously: Do not ask clarifying questions or wait for in-band user input. Make safe, reasonable assumptions when possible; if blocked by missing credentials, unavailab...` | Constant defining default headless preamble. | | `defaultAgentProfile` | `value` | `AgentProfile` | Runtime API for default agent profile; the generated signature shows its accepted inputs and return type. | | `defaultLoopRuntime` | `value` | `NativeLoopRuntime` | Runtime API for default loop runtime; the generated signature shows its accepted inputs and return type. | | `defaultModelProvider` | `value` | `MockModelProvider` | Provider implementation for default model. | | `defaultSessionStore` | `value` | `InMemorySessionStore` | Storage contract for default session. | | `defineAction` | `value` | `<TInput = unknown, TOutput = unknown>(options: ActionOptions<TInput, TOutput>) => ActionDefinition<TInput, TOutput>` | Define an action — the harness-context counterpart to `defineTool`. A tool is a leaf capability the model calls; an action holds the harness (`context.init`) and can prompt, spawn sessions, and compose other work. Input/output use the harness `schema` builders and are validated on every `runAction` call; outputs must be JSON-serializable. | | `defineAgent` | `value` | `<TInput = JsonObject, TOutput = unknown>(definition: AgentDefinition<TInput, TOutput>) => DefinedAgent<TInput, TOutput>` | Defaults-injecting finite-agent builder exported from the bare SDK entry point. | | `defineAgentProfile` | `value` | `(options: AgentProfileOptions) => AgentProfile` | Defines agent profile. | | `defineChannel` | `value` | `(channel: Channel) => Channel` | Validates and brands a channel's routes. | | `defineCommand` | `value` | `<TInput = CommandToolInput>(name: string, options?: Omit<Command<TInput>, "name">) => Command<TInput>` | Defines command. | | `DefinedAgent` | `type` | `DefinedAgent<TInput, TOutput>` | Type contract for defined agent. | | `defineMcpConnection` | `value` | `(definition: McpConnectionDefinition) => McpConnectionDefinition` | Defines mcp connection. | | `defineSkill` | `value` | `(input: DefineSkillInput) => Skill` | Build a `Skill` from explicit fields. Throws when `name` or `instructions` is empty — a skill the model cannot name, or one that carries no instruction, is a silent no-op at activation time, so it fails here instead. | | `DefineSkillInput` | `type` | `DefineSkillInput` | Type contract for define skill input. | | `defineSubagent` | `value` | `(definition: SubagentDefinition) => SubagentDefinition` | Defines subagent. | | `defineTool` | `value` | `{ <TInput = unknown, TOutput = unknown>(tool: ToolDef<TInput, TOutput>): ToolDef<TInput, TOutput>; <TInput = unknown, TOutput = unknown, THarness extends boolean = false, TDurable extends boolean = false>(tool: HookToolDefinition<TInput, TOutput...` | Defines tool. | | `defineWebhookSubscription` | `value` | `<TPayload = JsonObject>(definition: WebhookSubscriptionDefinition<TPayload>) => WebhookSubscriptionDefinition<TPayload>` | Helper that returns the definition unchanged. Useful for type inference and to keep agent files declarative. See the package declarations for an example. | | `DeletionCompletionRecord` | `type` | `DeletionCompletionRecord` | Type contract for deletion completion record. | | `DeliveredAttachment` | `type` | `DeliveredAttachment` | One attachment on a `kind: 'user'` message. Today the only supported attachment is an image, carried either inline (`data`, base64) or as a durable content-addressed reference (`ref`) once an attachment store is configured — admission materializes inline bytes into refs. An attachment must carry `data` or `ref` (or both, transiently during materialization). | | `DeliveredAttachmentRef` | `type` | `DeliveredAttachmentRef` | Durable reference to attachment bytes in an attachment store. | | `DeliveredMessage` | `type` | `DeliveredMessage` | DeliveredMessage — the single unified input shape for everything that enters a persistent agent's session: direct HTTP prompts, dispatch, channels/webhooks, Databricks events, SDK clients, and tests. `kind: 'user'` is a direct user talking to the assistant (1:1 chat surface), optionally carrying attachments. `kind: 'signal'` models everything beyond that direct exchange — a Slack thread or a Lakeflow job event is activity the agent observes, not the assistant's own user speaking. Sender identity and structured metadata go in `attributes`; the message itself in `body`. Signals render into mo... | | `deliveredSignalToEntryData` | `value` | `(message: Extract<DeliveredMessage, { kind: "signal"; }>) => SignalEntryData` | Map a signal-kind message onto the persisted `signal` entry's data shape. | | `deriveCompactionDefaults` | `value` | `(input: { contextWindowTokens: number; maxOutputTokens?: number; }) => { reserveTokens: number; keepRecentTokens: number; }` | Compute model-aware compaction defaults. Reserve is capped at the model's max output because reserving more than the model can emit in one turn wastes context; the preserved tail stays flat because recent-context fidelity depends on the active work, not on the model's total window size. | | `dispatch` | `value` | `{ (agent: CreatedAgent, request: AgentDispatchRequest): Promise<DispatchReceipt>; (request: NamedAgentDispatchRequest): Promise<DispatchReceipt>; }` | Runtime API for dispatch; the generated signature shows its accepted inputs and return type. | | `DispatchInput` | `type` | `DispatchInput` | Internal enqueued form, carrying correlation + isolation metadata. | | `DispatchProcessor` | `type` | `DispatchProcessor` | Consumes enqueued dispatches and applies them to an instance session. | | `DispatchQueue` | `type` | `DispatchQueue` | Admission queue for dispatches. The default is in-process; durable backends implement the same shape. | | `DispatchReceipt` | `type` | `DispatchReceipt` | Acceptance confirmation for an enqueued dispatch. | | `DockerSandboxEnv` | `value` | `typeof DockerSandboxEnv` | Runtime API for docker sandbox env; the generated signature shows its accepted inputs and return type. | | `DockerSandboxOptions` | `type` | `DockerSandboxOptions` | Configuration options for docker sandbox. | | `DURABILITY_DEFAULT_MAX_ATTEMPTS` | `value` | `10` | Default maximum total attempts before terminalization. | | `DURABILITY_DEFAULT_TIMEOUT_MS` | `value` | `3600000` | Default submission timeout in milliseconds (one hour). | | `DurableSessionRuntime` | `type` | `DurableSessionRuntime` | Structural delegate for durable session execution. When `init()` is given a `sessionRuntime` factory that produces one of these, the SDK's session calls (`prompt`, `task`, `shell`, `checkpoint.*`) are routed through the runtime instead of executing inline. This is the seam for Temporal workflows, external orchestration runtimes, or test fakes. `mount`, `history`, `artifact`, and `compact` remain SDK-local concerns and are not delegated — they operate against the local session store. | | `DurableSessionRuntimeFactory` | `type` | `DurableSessionRuntimeFactory` | Factory for durable session runtime. | | `DynamicAgentExecutionDescriptor` | `type` | `DynamicAgentExecutionDescriptor` | JSON-safe identity required to re-render a persistent dynamic agent at a trusted durable-runtime boundary. Hook functions, tool implementations, credentials, and resolved MCP connections are deliberately excluded. | | `DynamicAgentFinishContext` | `type` | `DynamicAgentFinishContext` | Type contract for dynamic agent finish context. | | `DynamicAgentFunction` | `type` | `DynamicAgentFunction<TEnv>` | Type contract for dynamic agent function. | | `DynamicAgentProps` | `type` | `DynamicAgentProps<TEnv>` | Dynamic persistent-agent composition. The runtime keeps Fabric's builders, policies, persistence contracts, and backend-neutral types while allowing capabilities to evolve per interaction. | | `DynamicAgentRefreshInput` | `type` | `DynamicAgentRefreshInput` | Type contract for dynamic agent refresh input. | | `DynamicAgentRenderOptions` | `type` | `DynamicAgentRenderOptions` | Configuration options for dynamic agent render. | | `DynamicAgentResponse` | `type` | `DynamicAgentResponse` | Response contract for dynamic agent. | | `DynamicAgentRuntime` | `type` | `DynamicAgentRuntime` | Type contract for dynamic agent runtime. | | `DynamicAgentStartContext` | `type` | `DynamicAgentStartContext` | Type contract for dynamic agent start context. | | `DynamicLifecycleContext` | `type` | `DynamicLifecycleContext` | Type contract for dynamic lifecycle context. | | `DynamicMetadataCallback` | `type` | `DynamicMetadataCallback` | Type contract for dynamic metadata callback. | | `editFileTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<EditInput, void>` | Model-callable tool or tool factory for edit file. | | `EditInput` | `type` | `EditInput` | Type contract for edit input. | | `ElevenLabsTtsProvider` | `value` | `typeof ElevenLabsTtsProvider` | Provider implementation for eleven labs tts. | | `ElevenLabsTtsProviderOptions` | `type` | `ElevenLabsTtsProviderOptions` | Configuration options for eleven labs tts provider. | | `EmbeddingProvider` | `type` | `EmbeddingProvider` | Embeddings seam. Feeds self-managed-embedding vector indexes (embed the query → query vector) and any bring-your-own retrieval pipeline. Returns one vector per input text, order-preserving. | | `emitOpenTelemetrySpan` | `value` | `(tracer: Tracer, span: TelemetrySpan, attributes?: Record<string, string \| number \| boolean>, conventions?: "fabric" \| "foundry") => Span` | Runtime API for emit open telemetry span; the generated signature shows its accepted inputs and return type. | | `emitSubmissionTelemetry` | `value` | `(sink: SubmissionTelemetrySink \| undefined, event: SubmissionTelemetryEvent, onError?: (error: unknown) => void) => void` | Deliver an event to a sink, swallowing (and reporting) sink failures. | | `EmptySandboxEnv` | `value` | `typeof EmptySandboxEnv` | Runtime API for empty sandbox env; the generated signature shows its accepted inputs and return type. | | `enqueueDispatch` | `value` | `(queue: DispatchQueue, request: NamedAgentDispatchRequest, extra?: { tenantId?: string; actor?: FabricActor; dispatchId?: string; }) => Promise<DispatchReceipt>` | Validate + normalize a named request and enqueue it, generating the dispatch id. | | `ensurePersistentInstanceIdentity` | `value` | `(options: { store: SessionStore; agentName: string; instanceId: string; uid?: string \| null; tenantId?: string; actor?: FabricActor; }) => Promise<PersistentInstanceIdentity>` | Atomically resolve or create one tenant-scoped persistent instance generation. | | `entryToTelemetrySpan` | `value` | `(sessionId: string, entry: SessionEntry) => TelemetrySpan \| undefined` | Runtime API for entry to telemetry span; the generated signature shows its accepted inputs and return type. | | `environmentSecretProvider` | `value` | `(options?: EnvironmentSecretProviderOptions) => SecretProvider` | Runtime-only environment provider with optional prefix and explicit allowlist. | | `EnvironmentSecretProviderOptions` | `type` | `EnvironmentSecretProviderOptions` | Configuration options for environment secret provider. | | `estimateCostUsd` | `value` | `(modelRef: string, usage: ModelPricingUsage) => number` | Estimate USD cost for a single model call. Returns `0` when no row matches `modelRef` — callers should treat 0 as "unknown" and not overwrite an existing `costUsd` from the provider. | | `estimateModelMessagesTokens` | `value` | `(messages: ModelMessage[]) => number` | Runtime API for estimate model messages tokens; the generated signature shows its accepted inputs and return type. | | `estimateSessionEntriesTokens` | `value` | `(entries: SessionEntry[]) => number` | Runtime API for estimate session entries tokens; the generated signature shows its accepted inputs and return type. | | `estimateTextTokens` | `value` | `(text: string) => number` | Runtime API for estimate text tokens; the generated signature shows its accepted inputs and return type. | | `evaluateCommandPolicy` | `value` | `(command: string \| undefined, policy?: CapabilityPolicy) => PolicyDecision` | Runtime API for evaluate command policy; the generated signature shows its accepted inputs and return type. | | `evaluateContextBudget` | `value` | `(messages: ModelMessage[], options?: ContextBudgetOptions) => ContextBudget` | Runtime API for evaluate context budget; the generated signature shows its accepted inputs and return type. | | `evaluateNetworkPolicy` | `value` | `(input: string \| URL \| Request, policy?: CapabilityPolicy) => PolicyDecision` | Evaluate a URL or `Request` against the configured network policy. Returns `{ allowed: true }` when the request is permitted, otherwise a denial with the reason and matched pattern. | | `evaluateOperationalSlos` | `value` | `(snapshot: OperationalMetricsSnapshot, targets: OperationalSloTargets) => OperationalSloEvaluation` | Runtime API for evaluate operational slos; the generated signature shows its accepted inputs and return type. | | `evaluateToolCallPolicy` | `value` | `(call: ToolCall, policy?: CapabilityPolicy) => PolicyDecision` | Runtime API for evaluate tool call policy; the generated signature shows its accepted inputs and return type. | | `eventToTelemetrySpan` | `value` | `(event: FabricEvent) => TelemetrySpan \| undefined` | Runtime API for event to telemetry span; the generated signature shows its accepted inputs and return type. | | `execSandboxCommand` | `value` | `(sandbox: SandboxEnv, command: string, options?: SandboxExecOptions) => Promise<ShellResult>` | Reject promptly on cancellation even when a remote provider cannot cancel its command. The underlying promise remains observed and reports its final, redacted settlement through `onOrphanSettled`. | | `ExistsInput` | `type` | `ExistsInput` | Type contract for exists input. | | `existsTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<ExistsInput, boolean>` | Model-callable tool or tool factory for exists. | | `extractResultValue` | `value` | `(value: unknown, extraction?: boolean \| ResultExtractionOptions) => unknown` | Runtime API for extract result value; the generated signature shows its accepted inputs and return type. | | `FABRIC_OPERATIONAL_METRICS` | `value` | `{ readonly requestLatencyMs: "fabric_harness_request_latency_ms"; readonly submissionDurationMs: "fabric_harness_submission_duration_ms"; readonly queueAgeMs: "fabric_harness_queue_age_ms"; readonly errorsTotal: "fabric_harness_errors_total"; readonly approvalWaitMs: "fab...` | Constant defining fabric operational metrics. | | `FabricActor` | `type` | `FabricActor` | Type contract for fabric actor. | | `FabricAgent` | `type` | `FabricAgent` | Type contract for fabric agent. | | `FabricAgentAddress` | `type` | `FabricAgentAddress` | Identity of one addressed conversation. | | `FabricAgentAdmission` | `type` | `FabricAgentAdmission` | Type contract for fabric agent admission. | | `FabricAgentAdmissionResult` | `type` | `FabricAgentAdmissionResult` | Result returned by fabric agent admission. | | `FabricAgentConversationPage` | `type` | `FabricAgentConversationPage` | Type contract for fabric agent conversation page. | | `FabricAgentDeletion` | `type` | `FabricAgentDeletion` | Type contract for fabric agent deletion. | | `FabricAgentRouter` | `type` | `FabricAgentRouter` | Type contract for fabric agent router. | | `FabricAgentRouterBackend` | `type` | `FabricAgentRouterBackend` | The host-specific half of the router. Every method may throw; the router maps a thrown error to `500` with a generic body rather than leaking host internals to the caller. | | `FabricAgentRouterOptions` | `type` | `FabricAgentRouterOptions` | Configuration options for fabric agent router. | | `FabricAgentSubmissionStatus` | `type` | `FabricAgentSubmissionStatus` | Type contract for fabric agent submission status. | | `FabricContext` | `type` | `FabricContext<TPayload>` | Type contract for fabric context. | | `FabricError` | `value` | `typeof FabricError` | Error raised for fabric failures. | | `FabricErrorCode` | `type` | `FabricErrorCode` | Type contract for fabric error code. | | `FabricErrorOptions` | `type` | `FabricErrorOptions` | Configuration options for fabric error. | | `FabricEvent` | `type` | `FabricEvent<TData>` | Type contract for fabric event. | | `FabricEventCallback` | `type` | `FabricEventCallback` | Type contract for fabric event callback. | | `FabricEventType` | `type` | `FabricEventType` | Type contract for fabric event type. | | `FabricFs` | `type` | `FabricFs` | Out-of-band filesystem surface for a session sandbox. These operations do not write to conversation history and are intended for host-side plumbing: staging files, collecting artifacts, and preparing scratch space. If the model should reason about a file, prompt it to use the normal read/write/edit tools instead. | | `FabricObservabilityRecord` | `type` | `FabricObservabilityRecord` | Type contract for fabric observability record. | | `FabricPrincipal` | `type` | `FabricPrincipal` | The governed identity a piece of work runs as (v2). Distinct from `ActorIdentity` (who asked): the principal is what the platform's access control enforces — a human user, a machine service principal, or a hosted app's own identity. `ucPrincipal` carries the catalog-governance principal name when the platform has one (e.g. Unity Catalog). | | `FabricRuntime` | `type` | `FabricRuntime` | Execution runtime selection. - `inline` (default): single-process execution. Uses the configured `SessionStore` (in-memory by default) for history, artifacts, approvals. - `stateless`: explicit headless / ephemeral mode. No session store, no artifact persistence, no approval waiting. Each invocation is independent. Use for high-volume webhook agents and edge runtimes where state would just be discarded anyway. In production (`FABRIC_ENV=production` or `NODE_ENV=production`) this mode must be selected explicitly — `inline` without an explicit store will warn or fail depending on `FABRIC_ALLO... | | `FabricSession` | `type` | `FabricSession` | Type contract for fabric session. | | `FallbackModelProvider` | `value` | `typeof FallbackModelProvider` | Provider implementation for fallback model. | | `FallbackModelProviderOptions` | `type` | `FallbackModelProviderOptions` | Configuration options for fallback model provider. | | `FileStat` | `type` | `FileStat` | Type contract for file stat. | | `FilesystemEntry` | `type` | `FilesystemEntry` | Type contract for filesystem entry. | | `FilesystemPolicy` | `type` | `FilesystemPolicy` | Type contract for filesystem policy. | | `FilesystemSource` | `type` | `FilesystemSource` | A read-only content source that can be mounted into a sandbox at sandbox-creation time. The agent then has built-in `read`, `glob`, and `grep` tools available over the mounted content — no retrieval pipeline, no embeddings, no vector store required. Sources are intentionally minimal: they yield (path, content) pairs. Implementations decide how to enumerate (eager vs lazy is up to the source author) — the mount step pulls the full set into the sandbox. | | `findSubmissionInputIndex` | `value` | `(path: readonly SessionEntry[], submissionId: string) => number` | Index of the last canonical user or signal input carrying the submission id, or -1. | | `findTrailingDanglingToolCalls` | `value` | `(path: SessionEntry[]) => SessionEntry[]` | Find trailing `tool_call` entries on the active path that were never settled — no matching `tool_result` (paired by `toolCallId`, falling back to tool name) and no subsequent `error` entry for the same tool. A dangling call means a model turn died (crash/abort) between recording the call and recording its outcome. Left in place it produces an assistant `tool_use` with no `tool_result` on resume, which providers reject — the repair path appends synthetic interrupted outcomes for exactly the entries returned here. Conservative by construction: only the window after the last turn boundary (use... | | `findTrailingUnfinishedTasks` | `value` | `(path: SessionEntry[]) => SessionEntry[]` | Trailing `task_start` entries in the same window with no matching `task_end` — a subtask that was in flight when the turn died. These do not corrupt model context (task entries are bookkeeping), but settling them keeps UI/audit state coherent. | | `formatSchemaIssues` | `value` | `(issues: SchemaIssue[]) => string` | Runtime API for format schema issues; the generated signature shows its accepted inputs and return type. | | `formatStreamOffset` | `value` | `(offset: number) => string` | Runtime API for format stream offset; the generated signature shows its accepted inputs and return type. | | `fumadocsSource` | `value` | `(contentRoot: string, options?: { name?: string; stripFrontmatter?: boolean; include?: (relativePath: string) => boolean; }) => FilesystemSource` | Mount a local Fumadocs content directory as a knowledge base. Strips MDX frontmatter by default for cleaner agent context. For a published Fumadocs site, fetch its `llms.txt` / sitemap and pass the URLs to `httpFilesystemSource`. | | `GeminiModelProvider` | `value` | `typeof GeminiModelProvider` | Provider implementation for gemini model. | | `GeminiProviderOptions` | `type` | `GeminiProviderOptions` | Configuration options for gemini provider. | | `GeneralSubagent` | `value` | `SubagentDefinition` | Runtime API for general subagent; the generated signature shows its accepted inputs and return type. | | `generateAffinityKey` | `value` | `(agentId: string, sessionId: string) => string` | Generate a deterministic `aff_\u003cULID\u003e` affinity key from an `(agentId, sessionId)` pair. The same pair always produces the same key, which is stable across restarts. Different pairs produce different keys with overwhelming probability. | | `generateWithRuntime` | `value` | `(provider: ModelProvider, request: ModelRequest, options?: ModelRuntimeOptions) => Promise<ModelResponse>` | Runtime API for generate with runtime; the generated signature shows its accepted inputs and return type. | | `getAgentDefinition` | `value` | `(value: unknown) => AgentDefinition<unknown, unknown> \| undefined` | Returns agent definition. | | `getCreatedAgent` | `value` | `(value: unknown) => CreatedAgent \| undefined` | Return the `CreatedAgent` carried by a value, or `undefined`. | | `getLogger` | `value` | `() => Logger` | Get the currently configured logger. | | `getVirtualSandbox` | `value` | `(source: FilesystemSource, options?: { mountAt?: string; }) => SandboxFactory` | One-liner helper for the most common pattern: mount a single read-only source into a virtual sandbox. Equivalent to: See the package declarations for an example. Used for support agents, runbook lookup, FAQ assistants — anywhere a small Markdown corpus needs to be searchable via the agent's built-in `grep`/`glob`/`read` tools. See the package declarations for an example. | | `GlobInput` | `type` | `GlobInput` | Type contract for glob input. | | `globTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<GlobInput, string[]>` | Model-callable tool or tool factory for glob. | | `GrepInput` | `type` | `GrepInput` | Type contract for grep input. | | `GrepMatch` | `type` | `GrepMatch` | Type contract for grep match. | | `grepTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<GrepInput, GrepMatch[]>` | Model-callable tool or tool factory for grep. | | `hasSubmissionSettledEntry` | `value` | `(path: readonly SessionEntry[], submissionId: string) => boolean` | True when the path carries a canonical `submission_settled` entry for the id. | | `hexToBytes` | `value` | `(hex: string) => Uint8Array` | Runtime API for hex to bytes; the generated signature shows its accepted inputs and return type. | | `hmacSha256` | `value` | `(secret: string \| Uint8Array, message: Uint8Array) => Promise<Uint8Array>` | Runtime API for hmac sha256; the generated signature shows its accepted inputs and return type. | | `HookToolContext` | `type` | `HookToolContext<TInput, THarness, TDurable>` | Type contract for hook tool context. | | `HookToolDefinition` | `type` | `HookToolDefinition<TInput, TOutput, THarness, TDurable>` | Hook-oriented tool declaration supported by `defineTool()` and `useTool()`. | | `httpFilesystemSource` | `value` | `(resources: HttpResource[] \| (() => Promise<HttpResource[]>), options?: { name?: string; fetchImpl?: typeof fetch; }) => FilesystemSource` | Fetch a list of URLs and mount each response body as a file. Useful for pulling a small published docs set into the sandbox so the built-in `read`/`grep`/`glob` tools can search it like local files. | | `HttpResource` | `type` | `HttpResource` | Type contract for http resource. | | `init` | `value` | `(options?: AgentInit) => Promise<FabricAgent>` | Initialize a runtime-neutral Fabric agent from explicit model, sandbox, policy, store, identity, and lifecycle options. Call `agent.session()` on the returned value to create or resume a session. Supplying both `store` and `persistence` is invalid; a persistence adapter is connected before the agent is returned and connection failures propagate to the caller. | | `initializePersistentAgent` | `value` | `<TEnv>(created: CreatedAgent<TEnv>, context: PersistentAgentContext<TEnv>, overrides?: AgentInit) => Promise<{ config: PersistentAgentConfig; agent: FabricAgent; }>` | Resolve a persistent agent's config for an instance and build a `FabricAgent`. Runtime-specific resources (session store, workspace roles/skills, loop runtime) are layered by the host that calls this. | | `inMemoryApprovalNotificationStore` | `value` | `() => ApprovalNotificationDeliveryStore` | Process-local atomic delivery state for development and single-process hosts. | | `InMemoryAttachmentStore` | `value` | `typeof InMemoryAttachmentStore` | In-memory attachment store (dev / `runtime: 'stateless'` / tests). | | `InMemoryConversationStreamStore` | `value` | `typeof InMemoryConversationStreamStore` | In-memory conversation stream store (dev / `runtime: 'stateless'` / tests). | | `inMemoryCostBudgetStore` | `value` | `() => CostBudgetStore` | Process-local cost budget store. Default when `store` is not provided. | | `InMemoryDispatchQueue` | `value` | `typeof InMemoryDispatchQueue` | In-process dispatch queue: microtask-drained, concurrent across sessions, serialized within a single session. Suitable for the `inline`/`stateless` runtimes and dev. Durable delivery (surviving restarts) is provided by the Temporal-backed queue, which implements this same interface. | | `inMemorySessionMemory` | `value` | `() => SessionMemory` | Process-local in-memory implementation. Default when `init({ memory })` is not configured — pair with Postgres for durability across restarts. | | `InMemorySessionStore` | `value` | `typeof InMemorySessionStore` | Storage contract for in memory session. | | `inMemorySource` | `value` | `(files: Record<string, string \| Uint8Array>, options?: { name?: string; }) => FilesystemSource` | Build a source from an in-memory map of `path -> content`. Useful for tests, fixtures, and small static knowledge bases bundled into the agent module itself. | | `InMemoryStreamChunkStore` | `value` | `typeof InMemoryStreamChunkStore` | Storage contract for in memory stream chunk. | | `InMemorySubmissionStore` | `value` | `typeof InMemorySubmissionStore` | Storage contract for in memory submission. | | `InterruptedToolCallRef` | `type` | `InterruptedToolCallRef` | A tool call settled with an explicit interrupted-outcome marker at terminalization. | | `InvalidDeliveredMessageError` | `value` | `typeof InvalidDeliveredMessageError` | Thrown by `parseDeliveredMessage` on malformed input. | | `invoke` | `value` | `{ <TInput = JsonObject, TOutput = unknown>(job: DefinedAgent<TInput, TOutput>, options: JobInvocationOptions<TInput>): Promise<JobInvocationReceipt>; <TInput = JsonObject>(request: NamedJobInvocation<TInput>): Promise<JobInvocationRe...` | Runtime API for invoke; the generated signature shows its accepted inputs and return type. | | `isActionDefinition` | `value` | `(value: unknown) => value is ActionDefinition` | Checks whether a value is action definition. | | `isContextOverflowError` | `value` | `(error: unknown) => boolean` | Checks whether a value is context overflow error. | | `isCreatedAgent` | `value` | `(value: unknown) => value is CreatedAgent` | Whether a value is a `CreatedAgent`. | | `isDeliveredMessageShape` | `value` | `(value: unknown) => boolean` | True when a raw value already looks like a `DeliveredMessage` (has a valid `kind`). | | `isDynamicAgentRendering` | `value` | `() => boolean` | Checks whether a value is dynamic agent rendering. | | `isEvent` | `value` | `<T extends AgentEventType>(event: AgentEvent, type: T) => event is Extract<AgentEvent, { type: T; }>` | Type guard: narrow an `AgentEvent` to a specific variant. See the package declarations for an example. | | `isFabricError` | `value` | `(error: unknown) => error is FabricError` | Checks whether a value is fabric error. | | `isInMemoryStore` | `value` | `(store: SessionStore \| undefined) => boolean` | Returns true when `store` is the in-memory default (no `appendEntry` persistence beyond memory). Used by stateless mode to skip writes. | | `isStatelessRuntime` | `value` | `(runtime: FabricRuntime \| undefined) => boolean` | Checks whether a value is stateless runtime. | | `isSubmissionPayload` | `value` | `(input: unknown, ctx: SubmissionPayloadContext) => input is AgentSubmissionInput` | Validate that a parsed JSON payload matches the expected submission shape. Used after deserializing a persisted payload to verify the object is a well-formed `AgentSubmissionInput` that is consistent with the stored submission metadata. Both dispatch and direct payloads carry the same `message: DeliveredMessage` field — validated identically here regardless of transport `kind`. | | `isValidAffinityKey` | `value` | `(key: string) => boolean` | Checks whether a value is valid affinity key. | | `JobInvocationContext` | `type` | `JobInvocationContext` | Type contract for job invocation context. | | `JobInvocationOptions` | `type` | `JobInvocationOptions<TInput>` | Configuration options for job invocation. | | `JobInvocationReceipt` | `type` | `JobInvocationReceipt` | Type contract for job invocation receipt. | | `JobInvocationRuntime` | `type` | `JobInvocationRuntime` | Type contract for job invocation runtime. | | `JournalCallbacks` | `type` | `JournalCallbacks` | Type contract for journal callbacks. | | `jsonDeepEqual` | `value` | `(a: unknown, b: unknown) => boolean` | Structural equality over JSON values (objects compared key-order-insensitively). | | `JsonObject` | `type` | `JsonObject` | Type contract for json object. | | `JsonPrimitive` | `type` | `JsonPrimitive` | Type contract for json primitive. | | `JsonSchemaObject` | `type` | `JsonSchemaObject` | Type contract for json schema object. | | `JsonValue` | `type` | `JsonValue` | Type contract for json value. | | `LangfuseClientLike` | `type` | `LangfuseClientLike` | Optional Langfuse exporter. Adapts Fabric's `TelemetrySpan` shape to Langfuse's tracing API. The Langfuse client is provided by the caller — we don't take a hard dependency. Install peer dep: See the package declarations for an example. Usage: See the package declarations for an example. | | `langfuseExporter` | `value` | `(options: LangfuseExporterOptions) => TelemetryExporter` | Runtime API for langfuse exporter; the generated signature shows its accepted inputs and return type. | | `LangfuseExporterOptions` | `type` | `LangfuseExporterOptions` | Configuration options for langfuse exporter. | | `LEASE_DURATION_MS` | `value` | `30000` | Default lease duration for submission ownership in milliseconds (30 seconds). | | `listModelPrices` | `value` | `() => ModelPriceRow[]` | All currently-registered rows (newest-last). Returns a copy. | | `listSandboxBackendFactories` | `value` | `() => SandboxBackend[]` | Return provider backend names currently available to `createSandboxEnv()`. | | `listSandboxRefDecoders` | `value` | `() => string[]` | Returns the list of currently registered providers. | | `localDirectorySource` | `value` | `(hostPath: string, options?: { name?: string; include?: (relativePath: string) => boolean; }) => FilesystemSource` | Read a host directory recursively as a read-only source. `include` is called for each candidate file path (relative to `hostPath`). Return `false` to skip. Defaults to including everything. | | `LocalSandboxEnv` | `value` | `typeof LocalSandboxEnv` | Runtime API for local sandbox env; the generated signature shows its accepted inputs and return type. | | `LocalSandboxOptions` | `type` | `LocalSandboxOptions` | Configuration options for local sandbox. | | `Logger` | `type` | `Logger` | Minimal logger seam used by the SDK for non-event diagnostic output (warnings, deprecation notices, telemetry fallbacks). All `console.*` inside the SDK should route through `getLogger()` so ops teams can redirect or silence messages in production. The default logger writes to `console` and respects `FABRIC_HARNESS_LOG_LEVEL=debug\|info\|warn\|error\|silent` (default `warn`). | | `LogLevel` | `type` | `LogLevel` | Type contract for log level. | | `lookupModelPrice` | `value` | `(modelRef: string) => ModelPriceRow \| undefined` | Look up the most recently-registered row matching `modelRef`. `modelRef` can be: - `'provider/model'` (preferred, e.g. `'openai/gpt-4o'`) - `'model'` alone (e.g. `'gpt-4o'`) — first row whose model matches wins Provider matching is case-insensitive. Model matching is exact. | | `matchAgentRoute` | `value` | `(pathname: string) => AgentRouteMatch \| undefined` | Parse a pathname against the agent route surface. Returns `undefined` when the path is not an agent route, so a caller can fall through to its other route families. Percent-decoding happens here: a target that matched the raw segments would treat `ticket%2F1` as a different instance than the one the client addressed. | | `materializeMessageAttachments` | `value` | `(message: DeliveredMessage, store: AttachmentStore, options: { scope: string; idPrefix: string; maxCount?: number; maxAttachmentBytes?: number; maxTotalBytes?: number; }) => Promise<DeliveredMessage>` | Materialize a message's inline attachments into durable refs: decode the base64 data, store the bytes under `scope`, and return a NEW message whose attachments carry `{ type, mimeType, filename?, ref }` and no `data`. Deterministic by construction — attachment ids are `${idPrefix}_${index}` and digests derive from content — so an exact redelivery of the same message produces an identical materialized payload (admission idempotency). Messages without inline attachments are returned unchanged (same reference). | | `MAX_ATTACHMENT_DATA_LENGTH` | `value` | `number` | Maximum accepted base64 length for a single inline attachment. | | `McpAuthorizationCodeOptions` | `type` | `McpAuthorizationCodeOptions` | Configuration options for mcp authorization code. | | `McpAuthorizationCodeState` | `type` | `McpAuthorizationCodeState` | Type contract for mcp authorization code state. | | `McpClientCredentialsOptions` | `type` | `McpClientCredentialsOptions` | Configuration options for mcp client credentials. | | `McpClientLike` | `type` | `McpClientLike` | Type contract for mcp client like. | | `McpConnectionDefinition` | `type` | `McpConnectionDefinition` | Type contract for mcp connection definition. | | `McpServerConnection` | `type` | `McpServerConnection` | Type contract for mcp server connection. | | `McpServerOptions` | `type` | `McpServerOptions` | Configuration options for mcp server. | | `McpToolDescriptor` | `type` | `McpToolDescriptor` | Type contract for mcp tool descriptor. | | `McpTransport` | `type` | `McpTransport` | Type contract for mcp transport. | | `memorySandboxOwnershipLeaseStore` | `value` | `() => SandboxOwnershipLeaseStore` | Process-local lease store for tests and single-replica durable workers. | | `mergeCapabilityPolicies` | `value` | `(definition: CapabilityPolicy \| undefined, invocation: CapabilityPolicy \| undefined) => CapabilityPolicy \| undefined` | Treat a definition policy as a security floor. Invocation policy can add denials and approval requirements, but cannot replace definition allowlists. | | `mergeSessionEntryBatch` | `value` | `(existing: SessionData, entries: readonly SessionEntry[], expectedLeafId?: string, enforceExpectedLeaf?: boolean) => SessionData \| false` | Merge one idempotent, leaf-fenced entry batch into a session snapshot. Exported for first-party storage adapters so every backend applies the same conflict and exact-replay semantics before its single atomic write. | | `messageHasDataAttachments` | `value` | `(message: DeliveredMessage) => boolean` | True when the message carries at least one inline (base64) attachment. | | `mintlifySource` | `value` | `(contentRoot: string, options?: { name?: string; include?: (relativePath: string) => boolean; }) => FilesystemSource` | Mount a checked-out Mintlify content directory. For a hosted Mintlify MCP server, use `connectMcpServer('mintlify', { url, transport: 'streamable-http' })` instead. | | `MissingInputStrategy` | `type` | `MissingInputStrategy` | Type contract for missing input strategy. | | `MkdirInput` | `type` | `MkdirInput` | Type contract for mkdir input. | | `mkdirTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<MkdirInput, void>` | Model-callable tool or tool factory for mkdir. | | `ModelAttemptEvent` | `type` | `ModelAttemptEvent` | Type contract for model attempt event. | | `ModelConfig` | `type` | `ModelConfig` | Type contract for model config. | | `ModelMessage` | `type` | `ModelMessage` | Type contract for model message. | | `ModelMessageRole` | `type` | `ModelMessageRole` | Type contract for model message role. | | `ModelMetadata` | `type` | `ModelMetadata` | Type contract for model metadata. | | `ModelPriceRow` | `type` | `ModelPriceRow` | Static USD price table for model providers. Used to populate `ModelUsage.costUsd` on responses that don't include billing info from the provider directly (most providers — only `pi-loop-runtime` and a handful of gateways report cost). Prices are stamped with `effectiveAt`. The table is best-effort: real billing reconciliation should use vendor invoices. Override or extend at runtime with `registerModelPrices` for custom-rate contracts. | | `ModelPricingUsage` | `type` | `ModelPricingUsage` | Type contract for model pricing usage. | | `ModelProvider` | `type` | `ModelProvider` | Provider implementation for model. | | `ModelProviderFactory` | `type` | `ModelProviderFactory` | Resolves a parsed `provider/model-id` ref into a concrete provider. Registered factories let out-of-core packages (e.g. | | `ModelProviderResolver` | `type` | `ModelProviderResolver` | Type contract for model provider resolver. | | `ModelRequest` | `type` | `ModelRequest` | Input contract for model. | | `ModelResponse` | `type` | `ModelResponse` | Response contract for model. | | `ModelRuntimeOptions` | `type` | `ModelRuntimeOptions` | Configuration options for model runtime. | | `ModelStreamChunk` | `type` | `ModelStreamChunk` | Type contract for model stream chunk. | | `ModelToolCall` | `type` | `ModelToolCall` | Type contract for model tool call. | | `ModelToolSchema` | `type` | `ModelToolSchema` | Type contract for model tool schema. | | `ModelUsage` | `type` | `ModelUsage` | Type contract for model usage. | | `MountedSource` | `type` | `MountedSource` | Data or filesystem source for mounted. | | `MountResult` | `type` | `MountResult` | Result returned by mount. | | `NamedAgentDispatchRequest` | `type` | `NamedAgentDispatchRequest` | A dispatch request that names its target agent. | | `NamedJobInvocation` | `type` | `NamedJobInvocation<TInput>` | Type contract for named job invocation. | | `NativeLoopRuntime` | `value` | `typeof NativeLoopRuntime` | Runtime API for native loop runtime; the generated signature shows its accepted inputs and return type. | | `negotiateSandboxContinuity` | `value` | `(value: SandboxEnv \| SandboxRef \| SerializedSandboxRef) => SandboxContinuityCapabilities` | Report the continuity operations that a backend or serialized ref can support. | | `NetworkEnforcementLayer` | `type` | `NetworkEnforcementLayer` | Type contract for network enforcement layer. | | `NetworkEnforcementRequirement` | `type` | `NetworkEnforcementRequirement` | Type contract for network enforcement requirement. | | `NetworkPolicy` | `type` | `NetworkPolicy` | Type contract for network policy. | | `noopSessionStore` | `value` | `NoopSessionStore` | Storage contract for noop session. | | `NoopSessionStore` | `value` | `typeof NoopSessionStore` | No-op session store for `runtime: 'stateless'` mode. All writes are discarded; reads always return the empty initial session. Use this when the agent is intended as a pure request/response handler with no persistence (typical for high-volume webhooks and edge runtimes). Approvals and artifact retrieval are not supported — wiring those up requires a real store. Callers in stateless mode should not rely on artifact persistence or approval gating. | | `normalizeDeliveredMessage` | `value` | `(input: unknown) => DeliveredMessage` | Normalize legacy inputs into a `DeliveredMessage`: - a string → a user message with that body - a value with a `kind` discriminator → validated as a DeliveredMessage - any other JSON value → a user message with the JSON-stringified body (matching the historical dispatch rendering, so behavior is unchanged for pre-DeliveredMessage callers) | | `ObservabilityCorrelation` | `type` | `ObservabilityCorrelation` | Type contract for observability correlation. | | `ObservabilityObserverOptions` | `type` | `ObservabilityObserverOptions` | Configuration options for observability observer. | | `OpenAIChatCompletion` | `type` | `OpenAIChatCompletion` | Type contract for open aichat completion. | | `openAIChatCompletionToModelResponse` | `value` | `(json: OpenAIChatCompletion) => ModelResponse` | Response contract for open aichat completion to model. | | `OpenAICompatibleModelProvider` | `value` | `typeof OpenAICompatibleModelProvider` | Provider implementation for open aicompatible model. | | `OpenAICompatibleProviderOptions` | `type` | `OpenAICompatibleProviderOptions` | Configuration options for open aicompatible provider. | | `OpenAIRealtimeVoiceProvider` | `value` | `typeof OpenAIRealtimeVoiceProvider` | OpenAI Realtime voice provider. Connects via WebSocket; emits `audio_delta` / `text_delta` / `transcript` / `tool_call` / `response_done` events. No transitive dependency on `ws` — uses the global `WebSocket` available on Node 22+ and browsers. See the package declarations for an example. | | `OpenAIRealtimeVoiceProviderOptions` | `type` | `OpenAIRealtimeVoiceProviderOptions` | Configuration options for open airealtime voice provider. | | `openTelemetryExporter` | `value` | `(options: OpenTelemetryExporterOptions) => TelemetryExporter` | Bridge Fabric's SDK-neutral TelemetrySpan into a real | | `OpenTelemetryExporterOptions` | `type` | `OpenTelemetryExporterOptions` | Configuration options for open telemetry exporter. | | `OperationalMetricsCollector` | `type` | `OperationalMetricsCollector` | Type contract for operational metrics collector. | | `OperationalMetricsSnapshot` | `type` | `OperationalMetricsSnapshot` | Type contract for operational metrics snapshot. | | `OperationalSloEvaluation` | `type` | `OperationalSloEvaluation` | Type contract for operational slo evaluation. | | `OperationalSloTargets` | `type` | `OperationalSloTargets` | Type contract for operational slo targets. | | `PackagedSkillDirectory` | `type` | `PackagedSkillDirectory` | Type contract for packaged skill directory. | | `parseConversationKey` | `value` | `(key: string) => ParsedConversationKey` | Parses conversation key. | | `ParsedConversationKey` | `type` | `ParsedConversationKey` | Type contract for parsed conversation key. | | `parseDeliveredMessage` | `value` | `(value: unknown) => DeliveredMessage` | Validate a raw value as a `DeliveredMessage`. Shared by dispatch admission and the direct HTTP route so every transport produces the same structured error on bad input. | | `ParsedModelRef` | `type` | `ParsedModelRef` | Type contract for parsed model ref. | | `ParsedScopeKey` | `type` | `ParsedScopeKey` | Type contract for parsed scope key. | | `parseModelRef` | `value` | `(model: string) => ParsedModelRef \| undefined` | Parses model ref. | | `parsePersistentSessionId` | `value` | `(storeSessionId: string) => PersistentSessionIdentity \| undefined` | Inverse of `persistentStoreSessionId`: decode a store session id back into `{ agent, instanceId, session }`, or `undefined` if it is not a persistent-instance key. Useful for admin surfaces that list raw session ids. | | `parseRetryAfterMs` | `value` | `(headerValue: string \| null \| undefined) => number \| undefined` | Parse a `Retry-After` header value (RFC 7231) into milliseconds. Accepts both delta-seconds and HTTP-date forms. Returns undefined when the value is missing or unparseable. | | `parseScopeKey` | `value` | `(scopeKey: string) => ParsedScopeKey \| undefined` | Parse a scope key into its structured components. Recognized patterns: tenant:<id>:day:YYYY-MM-DD tenant:<id>:hour:YYYY-MM-DDTHH:00Z tenant:<id>:month:YYYY-MM agent:<id>:day:YYYY-MM-DD agent:<id>:hour:YYYY-MM-DDTHH:00Z agent:<id>:month:YYYY-MM user:<id>:day:YYYY-MM-DD user:<id>:hour:YYYY-MM-DDTHH:00Z user:<id>:month:YYYY-MM Unknown prefixes fall back to `kind: 'custom'` with `raw: scopeKey`. Returns `undefined` for empty strings. | | `parseStreamOffset` | `value` | `(offset: string \| undefined) => number` | Parses stream offset. | | `persistenceAdapter` | `value` | `() => PersistenceAdapter` | Create an in-memory `PersistenceAdapter` backed by a fresh `InMemorySessionStore`. This is the default when no persistence is configured. The returned adapter's `connect()` always returns the same store instance. | | `PersistenceAdapter` | `type` | `PersistenceAdapter` | A persistence adapter abstracts over storage backends (SQLite, Postgres, file, etc.). The SDK only requires `connect() → SessionStore`. Optional methods `connectRunStore` and `connectRunRegistry` are used by workflow backends (Temporal, Cloudflare). The optional `migrate()` hook is called once at startup to ensure schema exists, and `close()` releases resources. | | `PersistenceBundle` | `type` | `PersistenceBundle` | Complete persistence surface consumed by a Fabric host. | | `PersistenceDeleteResult` | `type` | `PersistenceDeleteResult` | Result returned by persistence delete. | | `PersistenceHealth` | `type` | `PersistenceHealth` | Type contract for persistence health. | | `PersistentAgentConfig` | `type` | `PersistentAgentConfig` | Runtime configuration returned by a `createAgent` initializer. Mirrors the agent-level slice of `AgentInit`; `instructions` becomes the session system prompt (a role), and `subagents` map to named roles. | | `PersistentAgentContext` | `type` | `PersistentAgentContext<TEnv>` | Per-interaction context passed to a `createAgent` initializer. `id` is the URL `<id>` of the addressed instance (or the dispatch target id); `env` is the platform environment supplied by the runtime. | | `PersistentAgentDurabilityConfig` | `type` | `PersistentAgentDurabilityConfig` | Static retry and wall-clock budget applied to every durable submission. | | `persistentAgentSubmissionDurability` | `value` | `(created: CreatedAgent, acceptedAt: number) => import("./submission-store.js").AgentSubmissionDurability \| undefined` | Resolve a static policy into the store's absolute durability stamp. | | `PersistentAgentTriggers` | `type` | `PersistentAgentTriggers` | Public triggers supported by persistent agents. Scheduling requires a concrete instance id and message, so cron belongs on a finite dispatcher job. | | `persistentConfigToAgentInit` | `value` | `(config: PersistentAgentConfig, id: string) => AgentInit` | Translate a `PersistentAgentConfig` into an `AgentInit`. | | `PersistentInstanceIdentity` | `type` | `PersistentInstanceIdentity` | Type contract for persistent instance identity. | | `persistentInstanceStoreId` | `value` | `(agentName: string, instanceId: string) => string` | Instance-scoped metadata key shared by every named session of one persistent agent. | | `PersistentSessionIdentity` | `type` | `PersistentSessionIdentity` | Decoded identity of a persistent instance session store key. | | `persistentStoreSessionId` | `value` | `(agentName: string, instanceId: string, sessionName?: string) => string` | Store-session key for a persistent instance's named session. Collapses the `(agentName, instanceId, sessionName)` identity onto Fabric's single-string `sessionId`, keeping persistent sessions inside the existing session stores. | | `PipelineVoiceProvider` | `value` | `typeof PipelineVoiceProvider` | Provider implementation for pipeline voice. | | `PipelineVoiceProviderOptions` | `type` | `PipelineVoiceProviderOptions` | Configuration options for pipeline voice provider. | | `policiedFetch` | `value` | `(fetchImpl: typeof fetch, policy?: CapabilityPolicy, options?: PoliciedFetchOptions) => typeof fetch` | Wrap a Fetch implementation with URL, protocol, host, redirect, and optional DNS-answer checks from a capability policy. This wrapper governs only calls made through the returned function; it does not intercept global Fetch, Axios, raw sockets, subprocesses, or third-party clients. Pair it with a container, cluster, or provider egress boundary for untrusted production workloads. | | `PoliciedFetchOptions` | `type` | `PoliciedFetchOptions` | Wrap a `fetch`-like function with `CapabilityPolicy` enforcement. Tools and connectors that make outbound HTTP should accept a custom `fetch` and pass the result of `policiedFetch(fetch, policy)`. Throws a `FabricError` (`POLICY_DENIED`) when a request violates the policy; never sends a forbidden request. | | `PolicyDecision` | `type` | `PolicyDecision` | Type contract for policy decision. | | `projectConversationRecords` | `value` | `(records: readonly ConversationStreamRecord[]) => ConversationSnapshot` | Project canonical session records into a stable, UI-oriented protocol. | | `PromptOptions` | `type` | `PromptOptions<TResult>` | Configuration options for prompt. | | `PromptRunInput` | `type` | `PromptRunInput` | Type contract for prompt run input. | | `PromptRunResult` | `type` | `PromptRunResult` | Result returned by prompt run. | | `ProviderHttpError` | `value` | `typeof ProviderHttpError` | Error raised for provider http failures. | | `ProvidersConfig` | `type` | `ProvidersConfig` | Type contract for providers config. | | `ProviderSettings` | `type` | `ProviderSettings` | Type contract for provider settings. | | `pruneSnapshots` | `value` | `(snapshotRoot: string, options?: SnapshotPruneOptions) => Promise<SnapshotPruneResult>` | Runtime API for prune snapshots; the generated signature shows its accepted inputs and return type. | | `RateLimiter` | `type` | `RateLimiter` | Type contract for rate limiter. | | `RateLimiterAcquireOptions` | `type` | `RateLimiterAcquireOptions` | Process-local rate limiter for outbound provider calls. Use to prevent a fleet of agents from stampeding a single API key when the host runs many sessions in parallel. The default token-bucket implementation is in-memory; `@fabric-harness/node` exports `redisRateLimiter` for shared limits across processes. fabric-harness ships this as a generic primitive — the same limiter can be reused for outbound HTTP calls inside connectors, webhook fan-out, or anywhere else throttling is useful. | | `readConversationFromFold` | `value` | `(store: ConversationStreamStore, path: string, options?: { offset?: string; limit?: number; }) => Promise<ConversationStreamReadResult>` | Read a conversation from its newest validated fold checkpoint plus the log suffix. Non-origin offsets always use the raw store so resume semantics stay unchanged. Invalid checkpoints are disposable and fall back to full replay. | | `readConversationReply` | `value` | `(snapshot: ConversationSnapshot, submissionId: string) => ConversationReply` | Read the canonical assistant reply for a durable submission. Submission ids are used when available. The positional fallback supports conversations written by older Harness servers that predate submission correlation on individual entries. | | `ReaddirInput` | `type` | `ReaddirInput` | Type contract for readdir input. | | `readdirTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<ReaddirInput, string[]>` | Model-callable tool or tool factory for readdir. | | `ReadFileBufferInput` | `type` | `ReadFileBufferInput` | Type contract for read file buffer input. | | `readFileBufferTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<ReadFileBufferInput, Uint8Array>` | Model-callable tool or tool factory for read file buffer. | | `ReadFileInput` | `type` | `ReadFileInput` | Type contract for read file input. | | `readFileTool` | `value` | `(sandbox?: SandboxEnv, packagedSkills?: Record<string, PackagedSkillDirectory>) => ToolDef<ReadFileInput, string>` | Model-callable tool or tool factory for read file. | | `readJsonBody` | `value` | `(request: Request, limitBytes?: number) => Promise<RequestBody \| undefined>` | Reads the body once and returns the raw bytes, the decoded text, and the parsed JSON together — so a channel can HMAC-verify the exact bytes and use the JSON without re-reading the (already consumed) stream. Returns undefined only when the body exceeds `limitBytes`. | | `readRequestBody` | `value` | `(request: Request, limitBytes?: number) => Promise<Uint8Array \| undefined>` | Reads the full request body as bytes, or returns undefined if it exceeds `limitBytes`. NOTE: this consumes the request stream (single read). Signature-verifying channels need the *exact* bytes for HMAC and the parsed JSON afterward — don't call `request.json()` as well. Use `readJsonBody` to get both from one read. | | `ReconstructedPartialAssistantMessage` | `type` | `ReconstructedPartialAssistantMessage` | Type contract for reconstructed partial assistant message. | | `reconstructInterruptedStream` | `value` | `(segments: Array<{ segmentIndex: number; body: string; }>, streamKey: string) => { partial: ReconstructedPartialAssistantMessage; interrupted: SignalEntryData; continued: SignalEntryData; } \| null` | Runtime API for reconstruct interrupted stream; the generated signature shows its accepted inputs and return type. | | `redactError` | `value` | `(error: unknown, options?: RedactionOptions) => JsonObject` | Error raised for redact failures. | | `RedactionOptions` | `type` | `RedactionOptions` | Configuration options for redaction. | | `redactJson` | `value` | `<T>(value: T, options?: RedactionOptions) => T` | Runtime API for redact json; the generated signature shows its accepted inputs and return type. | | `redactText` | `value` | `(value: string, options?: RedactionOptions) => string` | Runtime API for redact text; the generated signature shows its accepted inputs and return type. | | `registerCreatedAgentName` | `value` | `(agent: CreatedAgent, name: string) => void` | Register a name for a `CreatedAgent` so `dispatch(agent, ...)` can resolve it. | | `registeredModelProviders` | `value` | `() => string[]` | Names of externally registered providers, for diagnostics. | | `registerJobName` | `value` | `<TInput, TOutput>(job: DefinedAgent<TInput, TOutput>, name: string) => void` | Registers job name. | | `registerModelPrices` | `value` | `(rows: ModelPriceRow[]) => void` | Add or override price rows. Later rows take precedence over earlier ones. | | `registerModelProvider` | `value` | `(name: string, factory: ModelProviderFactory) => void` | Register a model provider resolvable via `FABRIC_MODEL=<name>/<model-id>`. Built-in providers always take precedence; registering a name a built-in already owns has no effect on routing. Idempotent by name (last registration wins). Call at module import time. | | `registerSandbox` | `value` | `(env: SandboxEnv, options?: { ownerSessionId?: string; }) => SandboxRef` | Register a sandbox in the in-process registry and return a portable ref. Subsequent calls for the same env return the same ref. | | `registerSandboxBackendFactory` | `value` | `(backend: SandboxBackend, factory: SandboxFactory) => void` | Register an implementation for a non-core `SandboxBackend` name. Provider packages use this hook so the shared runtime can resolve backends such as `databricks` without depending on them. | | `registerSandboxRefDecoder` | `value` | `(provider: string, decoder: SandboxRefDecoder) => void` | Register a decoder for `provider` so `attachSandbox(serialized)` can rehydrate a sandbox from another process. Typically called once at startup by the package that owns the provider integration (e.g. `@fabric-harness/connectors/e2b` registers the `e2b` provider). | | `RemoteSandboxApi` | `type` | `RemoteSandboxApi` | Type contract for remote sandbox api. | | `RemoteSandboxOptions` | `type` | `RemoteSandboxOptions` | Configuration options for remote sandbox. | | `renderDeliveredMessage` | `value` | `(message: DeliveredMessage) => string` | Render a delivered message to the prompt text form. User messages pass their body through verbatim; signals render as their XML envelope via the shared `renderSignalMessage` machinery. | | `RequestBody` | `type` | `RequestBody` | Type contract for request body. | | `resetDispatchRuntime` | `value` | `() => void` | Clear the ambient dispatch runtime (tests/teardown). | | `resetJobInvocationRuntime` | `value` | `() => void` | Runtime API for reset job invocation runtime; the generated signature shows its accepted inputs and return type. | | `resetModelPricesToBuiltins` | `value` | `() => void` | Reset the registry to the built-in seed (test/utility). | | `ResolvedDynamicModelProvider` | `type` | `ResolvedDynamicModelProvider` | Provider and normalized model selected for a dynamically rendered model reference. | | `ResolvedModelProvider` | `type` | `ResolvedModelProvider` | Provider implementation for resolved model. | | `resolveModelProvider` | `value` | `(options?: ResolveModelProviderOptions) => ResolvedModelProvider` | Resolves model provider. | | `ResolveModelProviderOptions` | `type` | `ResolveModelProviderOptions` | Configuration options for resolve model provider. | | `resolveRuntimeMode` | `value` | `(options: Pick<AgentInit, "runtime" \| "store" \| "persistence">, env?: Record<string, string \| undefined>) => RuntimeModeResolution` | Resolve the effective runtime mode for an `init()` call, applying production safety rules: - In production (`FABRIC_ENV=production` or `NODE_ENV=production`), choosing `stateless` is allowed but logged as an explicit choice. - `inline` (the default) without an explicit `SessionStore` falls back to in-memory storage. In production this emits a warning unless `FABRIC_ALLOW_EPHEMERAL_STATE=1` is set or runtime is explicitly `'stateless'`. - Unknown runtime values fall through to `'inline'` with a warning. | | `RESULT_END_DELIMITER` | `value` | `"---RESULT_END---"` | Constant defining result end delimiter. | | `RESULT_START_DELIMITER` | `value` | `"---RESULT_START---"` | Constant defining result start delimiter. | | `ResultExtractionOptions` | `type` | `ResultExtractionOptions` | Configuration options for result extraction. | | `ResultOutcome` | `type` | `ResultOutcome<TResult>` | Type contract for result outcome. | | `ResultToolBundle` | `type` | `ResultToolBundle<TResult>` | Type contract for result tool bundle. | | `ResultUnavailableError` | `value` | `typeof ResultUnavailableError` | Thrown when the LLM calls the `give_up` tool, indicating it cannot produce a result that conforms to the required schema. | | `ResultValidator` | `type` | `ResultValidator<TResult>` | Type contract for result validator. | | `RetrievedChunk` | `type` | `RetrievedChunk` | Generic, provider-agnostic retrieval seam. RAG is query-time, so it does NOT fit `FilesystemSource` (an eager full-dump mount) — a retriever resolves the top matches for a query on demand. Databricks AI Search is the flagship implementation, but this is reusable for any vector store. | | `RetrieveOptions` | `type` | `RetrieveOptions` | Configuration options for retrieve. | | `Retriever` | `type` | `Retriever` | Type contract for retriever. | | `RmInput` | `type` | `RmInput` | Type contract for rm input. | | `rmTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<RmInput, void>` | Model-callable tool or tool factory for rm. | | `Role` | `type` | `Role` | Type contract for role. | | `runAction` | `value` | `<TInput, TOutput>(action: ActionDefinition<TInput, TOutput>, host: ActionHost, input?: unknown) => Promise<TOutput>` | Validate input, run the action against `host`, validate + JSON-clone the output. The returned value is always safely serializable (a fresh JSON clone), so callers can persist or transmit it without sharing references. | | `RunEvent` | `type` | `RunEvent` | A workflow event with append-only identity enforced by (runId, eventIndex). | | `RunRegistry` | `type` | `RunRegistry` | Minimal interface for a workflow run registry. Used by durable runtime backends to index and track run statuses. | | `RunStore` | `type` | `RunStore` | Minimal interface for a workflow/event run store. Used by durable runtime backends (Temporal, Cloudflare, etc.) to persist run metadata and events. | | `RuntimeModeResolution` | `type` | `RuntimeModeResolution` | Type contract for runtime mode resolution. | | `runWithJobInvocation` | `value` | `<T>(context: JobInvocationContext, fn: () => Promise<T> \| T) => Promise<T> \| T` | Runs with job invocation. | | `runWithSubmissionContext` | `value` | `<T>(context: SubmissionContext, fn: () => Promise<T> \| T) => Promise<T> \| T` | Run `fn` with `context` as the ambient submission correlation. | | `sameApprovalOperation` | `value` | `(grant: ApprovalGrant, input: { toolCallId: string; toolInput: unknown; principal: FabricPrincipal; }) => boolean` | Runtime API for same approval operation; the generated signature shows its accepted inputs and return type. | | `SandboxAdapterDescriptor` | `type` | `SandboxAdapterDescriptor` | Adapter expectations: - Every backend must expose the SandboxEnv contract above and map paths into a scoped workspace. - Secrets and provider credentials must stay in adapter-owned environment/config, not model context. - exec should enforce backend-specific command, network, and timeout policy before process launch. - snapshot/restore is optional because not all targets support filesystem or VM snapshots. - Future adapters should be added without changing session/runtime code. Planned backends: local, Docker, Azure Container Apps, Azure Container Instances, AKS, Databricks, E2B, Daytona, C... | | `SandboxBackend` | `type` | `SandboxBackend` | Type contract for sandbox backend. | | `SandboxCapabilities` | `type` | `SandboxCapabilities` | Type contract for sandbox capabilities. | | `SandboxContinuityCapabilities` | `type` | `SandboxContinuityCapabilities` | Type contract for sandbox continuity capabilities. | | `SandboxContinuityMode` | `type` | `SandboxContinuityMode` | Type contract for sandbox continuity mode. | | `SandboxEnv` | `type` | `SandboxEnv` | Type contract for sandbox env. | | `SandboxExecOptions` | `type` | `SandboxExecOptions` | Configuration options for sandbox exec. | | `SandboxFactory` | `type` | `SandboxFactory` | Factory for sandbox. | | `SandboxFactoryOptions` | `type` | `SandboxFactoryOptions` | Configuration options for sandbox factory. | | `SandboxFork` | `type` | `SandboxFork` | Type contract for sandbox fork. | | `SandboxOrphanSettlement` | `type` | `SandboxOrphanSettlement` | Type contract for sandbox orphan settlement. | | `SandboxOwnershipLeaseStore` | `type` | `SandboxOwnershipLeaseStore` | Storage contract for sandbox ownership lease. | | `SandboxOwnershipOptions` | `type` | `SandboxOwnershipOptions` | Configuration options for sandbox ownership. | | `SandboxRef` | `type` | `SandboxRef` | Type contract for sandbox ref. | | `SandboxRefDecoder` | `type` | `SandboxRefDecoder` | Decoder for a `SerializedSandboxRef.provider`. Returns a SandboxFactory that, when invoked, produces a SandboxEnv connected to the existing remote sandbox identified by `providerData`. Decoders SHOULD attach without owning the remote sandbox's lifecycle — the returned env's `cleanup()` should detach, not destroy. | | `SandboxSnapshot` | `type` | `SandboxSnapshot` | Type contract for sandbox snapshot. | | `sanitizeObservabilityData` | `value` | `(data: JsonObject, additionalSecrets?: string[]) => JsonObject` | Runtime API for sanitize observability data; the generated signature shows its accepted inputs and return type. | | `sanitizePublicJson` | `value` | `<T>(value: T) => T` | Runtime API for sanitize public json; the generated signature shows its accepted inputs and return type. | | `sanitizePublicText` | `value` | `(value: string) => string` | Remove credentials and host filesystem locations from caller-visible text. | | `schema` | `value` | `{ string(): Schema<string>; number(): Schema<number>; boolean(): Schema<boolean>; unknown(): Schema<unknown>; enum<const T extends readonly [string, ...string[]]>(values: T): Schema<T[number]>; array<T>(item: Schema<T>): Sch...` | Runtime API for schema; the generated signature shows its accepted inputs and return type. | | `Schema` | `type` | `Schema<T>` | Type contract for schema. | | `SchemaIssue` | `type` | `SchemaIssue` | Type contract for schema issue. | | `SchemaValidationError` | `value` | `typeof SchemaValidationError` | Error raised for schema validation failures. | | `SearchToolInput` | `type` | `SearchToolInput` | Type contract for search tool input. | | `SearchToolOptions` | `type` | `SearchToolOptions` | Configuration options for search tool. | | `SearchToolResult` | `type` | `SearchToolResult` | Result returned by search tool. | | `secret` | `value` | `(name: string) => SecretRef` | Runtime API for secret; the generated signature shows its accepted inputs and return type. | | `SecretProvider` | `type` | `SecretProvider` | Provider implementation for secret. | | `SecretRef` | `type` | `SecretRef` | Type contract for secret ref. | | `SecretResolutionContext` | `type` | `SecretResolutionContext` | Type contract for secret resolution context. | | `secretResolver` | `value` | `(provider: SecretProvider, context?: SecretResolutionContext) => (ref: SecretRef) => Promise<string \| undefined>` | Adapt a provider to the existing `init({ resolveSecret })` callback. | | `SerializedFabricError` | `type` | `SerializedFabricError` | Error raised for serialized fabric failures. | | `SerializedSandboxRef` | `type` | `SerializedSandboxRef` | Cross-process / cross-machine sandbox reference. Created by `session.sandboxRef({ portable: true })` and re-attached via `attachSandbox(serialized)` in a separate process. Each `provider` string maps to a decoder registered via `registerSandboxRefDecoder()`. | | `serializeFabricError` | `value` | `(error: unknown, audience?: "public" \| "developer", fallback?: Omit<FabricErrorOptions, "cause">) => SerializedFabricError` | Convert any thrown value into the stable public/developer transport shape. | | `serializeSandboxRef` | `value` | `(ref: SandboxRef, ownerSessionId?: string, tenantId?: string) => SerializedSandboxRef` | Serialize an in-process `SandboxRef` into the cross-process form. Requires the underlying sandbox to implement `encodeRef()`. Throws `SANDBOX_UNAVAILABLE` if the backend is in-process-only. | | `SessionData` | `type` | `SessionData` | Type contract for session data. | | `SessionEntry` | `type` | `SessionEntry<TData>` | Type contract for session entry. | | `SessionEntryType` | `type` | `SessionEntryType` | Type contract for session entry type. | | `SessionHistory` | `value` | `typeof SessionHistory` | Runtime API for session history; the generated signature shows its accepted inputs and return type. | | `SessionMemory` | `type` | `SessionMemory` | Type contract for session memory. | | `SessionMemoryEntry` | `type` | `SessionMemoryEntry<TValue>` | Persistent key/value store for facts an agent should remember across sessions — borrower preferences, prior outcomes, learned task history. Distinct from `SessionEntry` (which is the audit log): memory is for *recall*, entries are for *audit*. Memory writes do NOT land in the session log, so they don't pollute prompt context unless the agent explicitly reads them. Tenancy: every operation accepts an optional `tenantId`. Two tenants with the same `key` get isolated values. `tenantId` defaults to the empty string for non-tenant deployments. | | `SessionMemoryFilter` | `type` | `SessionMemoryFilter` | Type contract for session memory filter. | | `SessionMemoryGetOptions` | `type` | `SessionMemoryGetOptions` | Configuration options for session memory get. | | `SessionMemorySetInput` | `type` | `SessionMemorySetInput<TValue>` | Type contract for session memory set input. | | `SessionOptions` | `type` | `SessionOptions` | Configuration options for session. | | `SessionStore` | `type` | `SessionStore` | Storage contract for session. | | `SessionSubmissionExecutorOptions` | `type` | `SessionSubmissionExecutorOptions` | Configuration options for session submission executor. | | `setLogger` | `value` | `(logger: Logger) => void` | Replace the global SDK logger. Call once at startup before any `init()`. Pass a custom Logger to redirect to your structured logging system. | | `ShellOptions` | `type` | `ShellOptions` | Configuration options for shell. | | `shellQuote` | `value` | `(value: string) => string` | Runtime API for shell quote; the generated signature shows its accepted inputs and return type. | | `ShellResult` | `type` | `ShellResult` | Result returned by shell. | | `Skill` | `type` | `Skill` | Type contract for skill. | | `SkillOptions` | `type` | `SkillOptions<TResult>` | Configuration options for skill. | | `slackApprovalNotifier` | `value` | `(options: { webhookUrl: string; fetch?: typeof fetch; }) => ApprovalNotifier` | Slack incoming-webhook notifier. The webhook URL remains in host configuration, never event data. | | `SnapshotPruneOptions` | `type` | `SnapshotPruneOptions` | Configuration options for snapshot prune. | | `SnapshotPruneResult` | `type` | `SnapshotPruneResult` | Result returned by snapshot prune. | | `StateSetter` | `type` | `StateSetter<T>` | Type contract for state setter. | | `StatInput` | `type` | `StatInput` | Type contract for stat input. | | `statTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<StatInput, FileStat>` | Model-callable tool or tool factory for stat. | | `StdioMcpClient` | `value` | `typeof StdioMcpClient` | Client implementation for stdio mcp. | | `StdioMcpClientOptions` | `type` | `StdioMcpClientOptions` | Configuration options for stdio mcp client. | | `StoredAttachment` | `type` | `StoredAttachment` | Type contract for stored attachment. | | `StreamChunkStore` | `type` | `StreamChunkStore` | Storage contract for stream chunk. | | `StreamChunkWriter` | `value` | `typeof StreamChunkWriter` | Writer implementation for stream chunk. | | `StreamListenerRegistry` | `value` | `typeof StreamListenerRegistry` | Process-local listener registry shared by store implementations — registration, unsubscribe-and-prune, and error-swallowing notify. | | `SttEvent` | `type` | `SttEvent` | Type contract for stt event. | | `SttProvider` | `type` | `SttProvider` | Provider implementation for stt. | | `SttSession` | `type` | `SttSession` | Type contract for stt session. | | `SttSessionOptions` | `type` | `SttSessionOptions` | Configuration options for stt session. | | `SttSessionUsage` | `type` | `SttSessionUsage` | Type contract for stt session usage. | | `SubagentDefinition` | `type` | `SubagentDefinition` | Type contract for subagent definition. | | `SubmissionAbortedError` | `value` | `typeof SubmissionAbortedError` | Error raised for submission aborted failures. | | `SubmissionAdmissionBackend` | `type` | `SubmissionAdmissionBackend<Row>` | Storage callbacks for `admitSubmissionWithBackend`. Every callback runs inside the transaction the caller has already opened (or the backend's equivalent atomicity scope). Callbacks may return plain values (synchronous backends) or native `Promise`s — non-native thenables are not supported. | | `SubmissionAdmissionRow` | `type` | `SubmissionAdmissionRow` | The minimal shape `admitSubmissionWithBackend` needs from a persisted submission row: the transport `kind` and persisted `payload` it compares against the incoming admission. `payload` may be the serialized JSON string or an already-deserialized object (e.g. a Postgres JSONB column). | | `SubmissionAttemptRef` | `type` | `SubmissionAttemptRef` | Type contract for submission attempt ref. | | `SubmissionClaimRef` | `type` | `SubmissionClaimRef` | Type contract for submission claim ref. | | `SubmissionContext` | `type` | `SubmissionContext` | Type contract for submission context. | | `SubmissionDurability` | `type` | `SubmissionDurability` | Type contract for submission durability. | | `SubmissionExecuteOptions` | `type` | `SubmissionExecuteOptions` | Configuration options for submission execute. | | `SubmissionExecutor` | `type` | `SubmissionExecutor` | How the runner touches sessions. `execute` applies the submission's input to the addressed instance session and resolves with the turn result; everything else is store-level and must not require a live agent. Contract requirements: - `execute` must be idempotent by submission id (a resumed attempt whose input entry already exists must not append it again). - `recordTerminal` settles the conversation to a deterministic rest state (unresolved trailing tool calls get explicit interrupted-outcome markers — NEVER re-executed) and appends a terminal advisory. - `appendSettlement` appends the cano... | | `SubmissionInsertRow` | `type` | `SubmissionInsertRow` | The queued row that `admitSubmissionWithBackend` writes on first admission. | | `SubmissionInspection` | `type` | `SubmissionInspection` | Coarse persisted-progress classification consumed by reconciliation. | | `SubmissionInterruptedError` | `value` | `typeof SubmissionInterruptedError` | Error raised for submission interrupted failures. | | `SubmissionInterruption` | `type` | `SubmissionInterruption` | Type contract for submission interruption. | | `SubmissionPayloadContext` | `type` | `SubmissionPayloadContext` | Context needed for submission payload validation. Implementations extract these fields from their storage-specific row/document type before calling `isSubmissionPayload`. | | `SubmissionRetryExhaustedError` | `value` | `typeof SubmissionRetryExhaustedError` | Error raised for submission retry exhausted failures. | | `SubmissionRunner` | `type` | `SubmissionRunner` | Type contract for submission runner. | | `SubmissionRunnerOptions` | `type` | `SubmissionRunnerOptions` | Configuration options for submission runner. | | `submissionSessionKey` | `value` | `(input: Pick<AgentSubmissionInput, "agent" \| "id" \| "session">) => string` | Store-session FIFO key of a submission (re-exported convenience). | | `SubmissionSettledRecord` | `type` | `SubmissionSettledRecord` | Minimal canonical settlement record for a direct submission. The conversation-stream phase reuses this shape as the durable terminal record a reconnecting waiter observes. | | `SubmissionSettlement` | `type` | `SubmissionSettlement` | Type contract for submission settlement. | | `submissionSettlementEntryId` | `value` | `(submissionId: string) => string` | Deterministic canonical settlement entry id for a submission. | | `SubmissionSettlementObligation` | `type` | `SubmissionSettlementObligation` | Type contract for submission settlement obligation. | | `submissionStoreSessionId` | `value` | `(input: Pick<AgentSubmissionInput, "agent" \| "id" \| "session">) => string` | The harness identity string (`agent:<name>:<id>:<session>`) targeted by a submission input. This is the `persistentStoreSessionId` of the addressed instance session and the per-session FIFO key of the store. | | `SubmissionTelemetryEvent` | `type` | `SubmissionTelemetryEvent` | Type contract for submission telemetry event. | | `SubmissionTelemetrySink` | `type` | `SubmissionTelemetrySink` | Type contract for submission telemetry sink. | | `SubmissionTimeoutError` | `value` | `typeof SubmissionTimeoutError` | Error raised for submission timeout failures. | | `TaskOptions` | `type` | `TaskOptions<TResult>` | Configuration options for task. | | `TelemetryExporter` | `type` | `TelemetryExporter` | Type contract for telemetry exporter. | | `TelemetrySpan` | `type` | `TelemetrySpan` | Type contract for telemetry span. | | `tenantCostLimit` | `value` | `(tenantId: string, options: TenantCostLimit) => CostLimit` | Sugar over `CostLimit.perScope + scopeKey + store` for the common "per-tenant ceiling per period" pattern. Pick one of `perDayUsd`, `perHourUsd`, or `perMonthUsd`; when multiple are set, the most restrictive (smallest absolute) wins. Scope key convention: `tenant:<id>:<period>` where `<period>` is `day:YYYY-MM-DD`, `hour:YYYY-MM-DDTHH:00Z`, or `month:YYYY-MM`. Reset semantics (rollover) are the host's job — call `store.reset(scopeKey)` from a scheduled task to clear the period total. See the package declarations for an example. | | `TenantCostLimit` | `type` | `TenantCostLimit` | Type contract for tenant cost limit. | | `ThinkingLevel` | `type` | `ThinkingLevel` | Reasoning-effort input level, ordered from least to most thinking. Maps to each provider's native control (Workers AI / OpenAI `reasoning_effort`, Anthropic `thinking.budget_tokens`, Gemini `thinkingConfig`). `'off'` (the default when unset) requests no reasoning. Providers that don't support reasoning ignore the level — see `ModelMetadata.supportsReasoning`. | | `toFabricError` | `value` | `(error: unknown, fallback: Omit<FabricErrorOptions, "cause">) => FabricError` | Error raised for to fabric failures. | | `tokenBucketRateLimiter` | `value` | `(options: TokenBucketRateLimiterOptions) => RateLimiter` | In-memory token-bucket rate limiter. Each key has its own bucket — keys are independent (waiting on one key doesn't block another). Buckets refill continuously at `tokensPerSecond`. | | `TokenBucketRateLimiterOptions` | `type` | `TokenBucketRateLimiterOptions` | Configuration options for token bucket rate limiter. | | `ToolCall` | `type` | `ToolCall<TInput>` | Type contract for tool call. | | `ToolCallResult` | `type` | `ToolCallResult<TOutput>` | Result returned by tool call. | | `ToolContext` | `type` | `ToolContext` | Type contract for tool context. | | `ToolDef` | `type` | `ToolDef<TInput, TOutput>` | Type contract for tool def. | | `ToolEffect` | `type` | `ToolEffect` | Type contract for tool effect. | | `ToolHarness` | `type` | `ToolHarness` | Type contract for tool harness. | | `ToolPolicy` | `type` | `ToolPolicy` | Type contract for tool policy. | | `ToolProgressLogger` | `type` | `ToolProgressLogger` | Type contract for tool progress logger. | | `ToolStep` | `type` | `ToolStep` | Type contract for tool step. | | `toolsToModelSchemas` | `value` | `(tools: Iterable<ToolDef>) => ModelToolSchema[]` | Runtime API for tools to model schemas; the generated signature shows its accepted inputs and return type. | | `toOpenAIMessage` | `value` | `(message: ModelMessage) => Record<string, unknown>` | Runtime API for to open aimessage; the generated signature shows its accepted inputs and return type. | | `toOpenAITool` | `value` | `(tool: ModelToolSchema) => Record<string, unknown>` | Model-callable tool or tool factory for to open ai. | | `TtsProvider` | `type` | `TtsProvider` | Provider implementation for tts. | | `TtsSynthesisOptions` | `type` | `TtsSynthesisOptions` | Configuration options for tts synthesis. | | `TtsSynthesisUsage` | `type` | `TtsSynthesisUsage` | Type contract for tts synthesis usage. | | `TurnJournalState` | `type` | `TurnJournalState` | Type contract for turn journal state. | | `UnifiedInMemoryStore` | `value` | `typeof UnifiedInMemoryStore` | A unified in-memory store that implements `SessionStore`, `StreamChunkStore`, and `RunStore`. Useful for testing and dev environments where a single object needs to be passed as `store`, `streamChunkStore`, and `runStore`. Backed by separate Maps for each concern so that stream chunks and run data do not pollute session state. | | `UnimplementedSandboxEnv` | `value` | `typeof UnimplementedSandboxEnv` | Runtime API for unimplemented sandbox env; the generated signature shows its accepted inputs and return type. | | `unregisterSandbox` | `value` | `(refId: string) => void` | Mark a registered sandbox as dead so future attach attempts fail. Called from the owner session's cleanup path. | | `unregisterSandboxBackendFactory` | `value` | `(backend: SandboxBackend) => void` | Remove a provider-owned backend factory, primarily for tests and controlled shutdown. | | `unregisterSandboxRefDecoder` | `value` | `(provider: string) => void` | Test/internal: remove a decoder. | | `useAgentFinish` | `value` | `(run: (context: DynamicAgentFinishContext) => void \| Promise<void>) => void` | Runtime API for use agent finish; the generated signature shows its accepted inputs and return type. | | `useAgentStart` | `value` | `(run: (context: DynamicAgentStartContext) => void \| Promise<void>) => void` | Runtime API for use agent start; the generated signature shows its accepted inputs and return type. | | `useDataWriter` | `value` | `<T>(name: string, options?: { schema?: Schema<T>; }) => (data: T) => void` | Writer implementation for use data. | | `useDelivery` | `value` | `() => DeliveredMessage` | Runtime API for use delivery; the generated signature shows its accepted inputs and return type. | | `useDispatchMessage` | `value` | `() => (message: DeliveredMessage \| string) => Promise<import("./dispatch.js").DispatchReceipt>` | Runtime API for use dispatch message; the generated signature shows its accepted inputs and return type. | | `useInitialData` | `value` | `<T = unknown>() => T` | Runtime API for use initial data; the generated signature shows its accepted inputs and return type. | | `useInstruction` | `value` | `(text: string) => void` | Runtime API for use instruction; the generated signature shows its accepted inputs and return type. | | `useMcpConnection` | `value` | `(definition: McpConnectionDefinition) => void` | Runtime API for use mcp connection; the generated signature shows its accepted inputs and return type. | | `useModel` | `value` | `(model: NonNullable<AgentInit["model"]>, options?: UseModelOptions) => void` | Runtime API for use model; the generated signature shows its accepted inputs and return type. | | `UseModelOptions` | `type` | `UseModelOptions` | Configuration options for use model. | | `usePersistentState` | `value` | `<T>(name: string, defaultValue: T, options?: { schema?: Schema<T>; }) => [T, StateSetter<T>]` | Runtime API for use persistent state; the generated signature shows its accepted inputs and return type. | | `useResponseFinish` | `value` | `(run: DynamicMetadataCallback) => void` | Runtime API for use response finish; the generated signature shows its accepted inputs and return type. | | `useResponseStart` | `value` | `(run: DynamicMetadataCallback) => void` | Runtime API for use response start; the generated signature shows its accepted inputs and return type. | | `useSandbox` | `value` | `(sandbox: SandboxBackend \| SandboxFactory \| SandboxEnv, options?: UseSandboxOptions) => void` | Sandbox adapter for use. | | `UseSandboxOptions` | `type` | `UseSandboxOptions` | Configuration options for use sandbox. | | `useSkill` | `value` | `(skill: Skill) => void` | Runtime API for use skill; the generated signature shows its accepted inputs and return type. | | `useSubagent` | `value` | `(definition: SubagentDefinition) => void` | Runtime API for use subagent; the generated signature shows its accepted inputs and return type. | | `useTool` | `value` | `<TInput = unknown, TOutput = unknown, THarness extends boolean = false, TDurable extends boolean = false>(tool: ToolDef<TInput, TOutput> \| HookToolDefinition<TInput, TOutput, THarness, TDurable>) => void` | Model-callable tool or tool factory for use. | | `validatePersistentAgentDurability` | `value` | `(durability: PersistentAgentDurabilityConfig) => PersistentAgentDurabilityConfig` | Validate and normalize a persistent agent's static submission policy. | | `validatePersistentInitialData` | `value` | `(created: CreatedAgent, initialData: unknown) => JsonValue` | Validate and normalize creation data before an instance generation is admitted. | | `validatePersistentInstanceContact` | `value` | `(uid: string \| null \| undefined, initialData: unknown) => void` | Reject contradictory existing-incarnation and instance-creation inputs. | | `validateResult` | `value` | `<TResult>(value: unknown, validator?: ResultValidator<TResult>, extraction?: boolean \| ResultExtractionOptions) => Promise<TResult>` | Result returned by validate. | | `VERCEL_AI_GATEWAY_BASE_URL` | `value` | `"https://ai-gateway.vercel.sh/v1"` | Default base URL for Vercel AI Gateway's OpenAI-compatible Chat Completions endpoint. The gateway accepts the standard OpenAI request body and routes through to the configured provider; switching from OpenAI to the gateway is just a base-URL change. See https://vercel.com/docs/ai-gateway/sdks-and-apis/openai-compat | | `vercelAIGateway` | `value` | `(options: VercelAIGatewayProviderOptions) => OpenAICompatibleModelProvider` | Vercel AI Gateway model provider. The gateway is an OpenAI-compatible HTTP endpoint that brokers between your agent and any of the major model providers (OpenAI, Anthropic, Google, xAI, Groq, etc.) with a single key, observability, caching, and spend controls. Use this provider on any deploy target — Node, Cloudflare Workers, Vercel — to route inference through the gateway. See the package declarations for an example. Returns an `OpenAICompatibleModelProvider` configured for the gateway — use it anywhere a `ModelProvider` is accepted. Compatible with fabric-harness's tool-calling, retries,... | | `VercelAIGatewayProviderOptions` | `type` | `VercelAIGatewayProviderOptions` | Configuration options for vercel aigateway provider. | | `verifyAttachmentBytes` | `value` | `(ref: AttachmentRef, bytes: Uint8Array) => Promise<void>` | Verify that `bytes` match the ref's digest (and declared size), throwing `AttachmentStoreError('DIGEST_MISMATCH')` otherwise. Every store's `put` MUST run this check before persisting. | | `verifyHmacSha256` | `value` | `(secret: string \| Uint8Array, message: Uint8Array, signature: Uint8Array) => Promise<boolean>` | Constant-time HMAC-SHA256 verification (via `crypto.subtle.verify`). | | `VertexAIModelProvider` | `value` | `typeof VertexAIModelProvider` | Provider implementation for vertex aimodel. | | `VertexAIProviderOptions` | `type` | `VertexAIProviderOptions` | Configuration options for vertex aiprovider. | | `VirtualSandboxEnv` | `value` | `typeof VirtualSandboxEnv` | Virtual sandbox backend powered by [just-bash](https://github.com/vercel-labs/just-bash). Provides an in-memory filesystem and a bash subset (`grep`, `glob`, `cat`, `read`, `mkdir`, `rm`, `ls`, `echo`, etc.) without shelling out to the host. The backend is fast, cheap, safe, and high-concurrency. Selected automatically by the bare `@fabric-harness/sdk` import when the caller doesn't pass `sandbox`. Override with `'local'`, `'docker'`, a `SandboxFactory`, or a `SandboxEnv` when you need real shell access. | | `VoiceAudioFormat` | `type` | `VoiceAudioFormat` | Bidirectional voice / audio streaming surface. fabric-harness ships an OpenAI Realtime implementation; bring-your-own-vendor for Anthropic / Gemini Live / on-prem TTS+ASR pipelines. Audio frames flow in raw bytes — the standard format is PCM 16-bit little-endian at 24kHz mono (OpenAI Realtime default). Telephony bridges (Twilio Media Streams μ-law 8kHz, etc.) resample at the edge. Tool execution is the *caller's* responsibility: a `tool_call` event surfaces, the host code runs the tool through whatever governance gates apply (approvals, cost caps, rate limits), then calls `submitToolResult(... | | `VoiceConnectOptions` | `type` | `VoiceConnectOptions` | Configuration options for voice connect. | | `VoiceEvent` | `type` | `VoiceEvent` | Events streamed from a `VoiceSession`. `audio_delta` carries raw audio bytes; `text_delta` and `transcript` carry text; `tool_call` and `response_done` mark structured boundaries; `error` is fatal. | | `VoiceProvider` | `type` | `VoiceProvider` | Provider implementation for voice. | | `VoiceSession` | `type` | `VoiceSession` | Type contract for voice session. | | `VoiceToolResultInput` | `type` | `VoiceToolResultInput` | Type contract for voice tool result input. | | `VoiceWsClientEvent` | `type` | `VoiceWsClientEvent` | Type contract for voice ws client event. | | `VoiceWsClientHandle` | `type` | `VoiceWsClientHandle` | Type contract for voice ws client handle. | | `VoiceWsClientOptions` | `type` | `VoiceWsClientOptions` | Lightweight WebSocket client for the Node server's `WS /sessions/:id/voice` endpoint. Server-side bridge owns the provider connection and API keys; this client just streams audio + control messages over WS. Works in browsers and on Node 22+ (uses the global `WebSocket`). | | `webhookApprovalNotifier` | `value` | `(options: { url: string; headers?: Record<string, string>; fetch?: typeof fetch; }) => ApprovalNotifier` | Runtime API for webhook approval notifier; the generated signature shows its accepted inputs and return type. | | `WebhookSubscriptionContext` | `type` | `WebhookSubscriptionContext<TPayload>` | Generic webhook subscription primitive — wakes an agent on inbound events from any external system (event bus, queue, scheduler, third-party SaaS webhook, your own application's domain events). fabric-harness consumes a JSON payload and dispatches to the user-provided handler. The host event system decides which payloads land here; fabric-harness has no opinion on event taxonomy or producer. | | `WebhookSubscriptionDefinition` | `type` | `WebhookSubscriptionDefinition<TPayload>` | Type contract for webhook subscription definition. | | `withConversationProjection` | `value` | `(store: SessionStore, streams: ConversationStreamStore, options?: { producerId?: string; onError?: (error: unknown) => void; }) => SessionStore` | Wrap a `SessionStore` so active-path appends are mirrored into an append-only `ConversationStreamStore` projection (v2 A4). The SessionEntry DAG stays the single source of truth; the stream gives clients offset-based catch-up + live tail. Two rules keep them coherent: 1. **Idempotent by entryId** — a crash between the DAG write and the stream write is repaired on the next append: the projector diffs the stream tail against the active path and re-emits anything missing. 2. **Truncation is explicit** — the DAG can branch (fork/replay/ checkpoint-restore rewrite `leafId`); the stream cannot. W... | | `withFilesystemSources` | `value` | `(base: SandboxBackend \| SandboxFactory \| SandboxEnv, sources: MountedSource[]) => SandboxFactory` | Runtime API for with filesystem sources; the generated signature shows its accepted inputs and return type. | | `WriteFileInput` | `type` | `WriteFileInput` | Type contract for write file input. | | `writeFileTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<WriteFileInput, void>` | Model-callable tool or tool factory for write file. | | `WsClientCommand` | `type` | `WsClientCommand` | Type contract for ws client command. | | `WsClientHandle` | `type` | `WsClientHandle` | Type contract for ws client handle. | | `WsClientOptions` | `type` | `WsClientOptions` | Lightweight WebSocket client for the Node server's `WS /sessions/:id/ws` endpoint. Works in browsers and on Node 22+ (uses the global `WebSocket`). Does NOT depend on the `ws` package — that's the server side's optional peer dep. | ### `@fabric-harness/sdk/strict` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `actionAsTool` | `value` | `<TInput, TOutput>(action: ActionDefinition<TInput, TOutput>, host: ActionHost) => ToolDef<unknown, TOutput>` | Expose an action to the model as a tool on an agent profile. The tool's JSON schema comes from the action's input schema; execution validates input/output exactly like `runAction`. | | `ActionContext` | `type` | `ActionContext<TInput>` | Context passed to an action's `run`. Unlike a tool's `execute` (a leaf capability invoked by the model), an action receives the harness itself and can orchestrate: prompt models, spawn sessions, call other actions. | | `ActionDefinition` | `type` | `ActionDefinition<TInput, TOutput>` | A named, schema-validated unit of harness work created with `defineAction`. First-class in v2: registrable on agent profiles as a tool, callable from jobs and agents, evaluable via `fh test`, and deployable as a platform job task. | | `ActionError` | `value` | `typeof ActionError` | Error raised for action failures. | | `ActionHost` | `type` | `ActionHost` | What an action runs against: the harness entry point (`init` can prompt models, spawn sessions, and call tools) plus the platform environment. Jobs, agents, and servers all satisfy this — it is the harness slice of `FabricContext`. | | `ActionOptions` | `type` | `ActionOptions<TInput, TOutput>` | Configuration options for action. | | `ActorIdentity` | `type` | `ActorIdentity` | Type contract for actor identity. | | `admitSubmissionWithBackend` | `value` | `<Row extends SubmissionAdmissionRow>(input: AgentSubmissionInput, backend: SubmissionAdmissionBackend<Row>) => AgentDispatchAdmission \| Promise<AgentDispatchAdmission>` | Shared submission admission algorithm for row-oriented backends: dispatch-receipt check → insert-or-ignore → read-back → payload compare (idempotent replay vs. conflict). The message payload is stored as JSON verbatim; payload identity is deep JSON equality, so a backend that normalizes stored JSON (e.g. Postgres JSONB key ordering) still recognizes an exact replay. The caller owns transaction scoping — invoke this inside one transaction and pass callbacks bound to it. When every callback is synchronous the result is returned synchronously, so the algorithm also fits synchronous backends. | | `AgentAttemptMarker` | `type` | `AgentAttemptMarker` | Harness-owned durable evidence that a submission attempt was started and has not yet settled. A coordinator inserts a marker immediately before starting an attempt and deletes it when the attempt settles; reconciliation treats a fresh marker as proof that the attempt may still be running and must not be reconciled as interrupted. | | `AgentDefinition` | `type` | `AgentDefinition<TInput, TOutput>` | Type contract for agent definition. | | `AgentDispatchAdmission` | `type` | `AgentDispatchAdmission` | Type contract for agent dispatch admission. | | `AgentDispatchReceipt` | `type` | `AgentDispatchReceipt` | Type contract for agent dispatch receipt. | | `AgentDispatchRequest` | `type` | `AgentDispatchRequest` | Async delivery request to a persistent agent instance + session. | | `AgentEvent` | `type` | `AgentEvent` | Type contract for agent event. | | `AgentEventBase` | `type` | `AgentEventBase` | Common envelope shared by every event variant. | | `AgentEventCallback` | `type` | `AgentEventCallback` | Callback signature accepted by `init({ onEvent })`, `agent.session(id, { onEvent })`, and `session.prompt(text, { onEvent })`. | | `AgentEventType` | `type` | `"error" \| "agent_start" \| "session_start" \| "prompt_start" \| "prompt_end" \| "turn_start" \| "turn_end" \| "model_attempt" \| "text_delta" \| "toolcall_delta" \| "submission_queued" \| "submission_running" \| "submission_recovery" \| "submission_settled" \| "cost_limit" \|...` | Type contract for agent event type. | | `AgentInit` | `type` | `AgentInit` | Type contract for agent init. | | `agentInstancePath` | `value` | `(agent: string, instanceId: string) => string` | Base path for one persistent instance, with both segments escaped. | | `AgentLoopRuntime` | `type` | `AgentLoopRuntime` | Type contract for agent loop runtime. | | `AgentMiddleware` | `type` | `(context: AgentRunContext<TInput>, next: () => Promise<TOutput>) => Promise<TOutput> \| TOutput` | Middleware for agent. | | `AgentRouteMatch` | `type` | `AgentRouteMatch` | Type contract for agent route match. | | `AgentRouteSection` | `type` | `AgentRouteSection` | Subroutes under `/agents/:name/:instanceId`. | | `agentRouteSession` | `value` | `(searchParams: URLSearchParams) => string` | Session name carried by `?session=`, defaulting to `default`. | | `AgentRunContext` | `type` | `AgentRunContext<TInput>` | Runtime-ready context for finite agents. The default session is initialized lazily. | | `AgentSubmission` | `type` | `AgentSubmission` | Type contract for agent submission. | | `AgentSubmissionDurability` | `type` | `AgentSubmissionDurability` | Type contract for agent submission durability. | | `AgentSubmissionInput` | `type` | `AgentSubmissionInput` | One admitted agent submission — the persisted operational payload for both transports. `kind` records how the submission arrived (`'dispatch'` via `dispatch()`, `'direct'` via the agent HTTP route); a dispatch's `submissionId` is the public `dispatchId` from its receipt. | | `agentSubmissionReceipt` | `value` | `(input: AgentSubmissionReceiptInput) => AgentSubmissionReceipt` | Build the `202` admission receipt. `streamUrl` and `conversationUrl` are the same URL; the former is retained for compatibility with clients written against the earlier shape. | | `AgentSubmissionReceipt` | `type` | `AgentSubmissionReceipt` | Type contract for agent submission receipt. | | `AgentSubmissionReceiptInput` | `type` | `AgentSubmissionReceiptInput` | Type contract for agent submission receipt input. | | `AgentSubmissionStatus` | `type` | `AgentSubmissionStatus` | Type contract for agent submission status. | | `AgentSubmissionStore` | `type` | `AgentSubmissionStore` | Durable submission lifecycle storage. Stability: the lease method group mirrors the durable-execution engine and is subject to change until 1.0. This applies to every backend equally. | | `AgentTriggers` | `type` | `AgentTriggers` | Type contract for agent triggers. | | `aiGateway` | `value` | `(options: AIGatewayOptions) => OpenAICompatibleModelProvider` | Generic OpenAI-compatible AI gateway helper. Use for **any** gateway that speaks the OpenAI Chat Completions request/response shape: Helicone, Portkey, LiteLLM (self-hosted), Cloudflare AI Gateway, internal corp proxies, etc. See the package declarations for an example. For Vercel AI Gateway, prefer the `vercelAIGateway` preset — same factory under the hood with the gateway URL pre-baked. | | `AIGatewayOptions` | `type` | `AIGatewayOptions` | Configuration options for aigateway. | | `AnthropicModelProvider` | `value` | `typeof AnthropicModelProvider` | Provider implementation for anthropic model. | | `AnthropicProviderOptions` | `type` | `AnthropicProviderOptions` | Configuration options for anthropic provider. | | `applyEstimatedCost` | `value` | `<T extends { costUsd?: number; } \| undefined>(modelRef: string \| undefined, usage: T) => T` | Idempotently populate `usage.costUsd` from the static price table. Mutates `usage` and returns it. No-op when: - `usage` is undefined, - `usage.costUsd` is already set (provider supplied it directly), - no price row matches `modelRef`. | | `ApprovalCallback` | `type` | `ApprovalCallback` | Type contract for approval callback. | | `ApprovalDecision` | `type` | `ApprovalDecision` | Type contract for approval decision. | | `ApprovalGrant` | `type` | `ApprovalGrant` | Durable provenance for one approved logical tool operation. A grant may be replayed for the same logical operation after a crash, but must never authorize a different tool call, input, or executing principal. | | `approvalGrantFromJson` | `value` | `(value: unknown) => ApprovalGrant \| undefined` | Parse persisted provenance without trusting a partial or malformed object. | | `approvalGrantToJson` | `value` | `(grant: ApprovalGrant) => JsonObject` | Runtime API for approval grant to json; the generated signature shows its accepted inputs and return type. | | `approvalInputDigest` | `value` | `(input: unknown) => string` | Deterministic digest shared by inline and durable approval runtimes. | | `ApprovalNotification` | `type` | `ApprovalNotification` | Type contract for approval notification. | | `ApprovalNotificationDeadLetter` | `type` | `ApprovalNotificationDeadLetter` | Type contract for approval notification dead letter. | | `ApprovalNotificationDeliveryStore` | `type` | `ApprovalNotificationDeliveryStore` | Storage contract for approval notification delivery. | | `approvalNotificationFromEvent` | `value` | `(event: FabricEvent, baseUrl?: string) => ApprovalNotification \| undefined` | Runtime API for approval notification from event; the generated signature shows its accepted inputs and return type. | | `approvalNotificationHandler` | `value` | `(options: ApprovalNotificationHandlerOptions) => FabricEventCallback` | Convert approval events into retryable, deduplicated notifications. This callback never throws. | | `ApprovalNotificationHandlerOptions` | `type` | `ApprovalNotificationHandlerOptions` | Configuration options for approval notification handler. | | `ApprovalNotificationState` | `type` | `ApprovalNotificationState` | Type contract for approval notification state. | | `ApprovalNotifier` | `type` | `ApprovalNotifier` | Type contract for approval notifier. | | `ApprovalOptions` | `type` | `ApprovalOptions` | Configuration options for approval. | | `ApprovalPolicyRule` | `type` | `ApprovalPolicyRule` | Per-pattern approval metadata. Lets policy authors route specific tools/commands to a named audience (e.g. `'reviewer'`, `'compliance-team'`, `'project-admin'`). The audience id is opaque to fabric-harness — host applications map ids to humans via their own identity layer. | | `ApprovalRequest` | `type` | `ApprovalRequest` | Input contract for approval. | | `ApprovalResponse` | `type` | `ApprovalResponse` | Response contract for approval. | | `ApprovalRisk` | `type` | `ApprovalRisk` | Type contract for approval risk. | | `ApprovalState` | `type` | `ApprovalState` | Type contract for approval state. | | `approvalStatesFromEntries` | `value` | `(sessionId: string, entries: SessionEntry[]) => ApprovalState[]` | Runtime API for approval states from entries; the generated signature shows its accepted inputs and return type. | | `ApprovalStateStatus` | `type` | `ApprovalStateStatus` | Type contract for approval state status. | | `ApprovalUnavailableStrategy` | `type` | `ApprovalUnavailableStrategy` | Type contract for approval unavailable strategy. | | `ApprovalVote` | `type` | `ApprovalVote` | Type contract for approval vote. | | `ArtifactCreateOptions` | `type` | `ArtifactCreateOptions` | Configuration options for artifact create. | | `ArtifactRef` | `type` | `ArtifactRef` | Type contract for artifact ref. | | `assertEnforceableNetworkPolicy` | `value` | `(policy: CapabilityPolicy \| undefined, sandbox: SandboxEnv \| Pick<SandboxCapabilities, "network" \| "networkEnforcement" \| "networkBoundary"> \| undefined, requirement?: NetworkEnforcementRequirement) => void` | Refuse production network policy when it can be bypassed by code in the sandbox. This validates an operator assertion; the named network boundary must still be provisioned by Docker, Kubernetes, or the cloud provider. | | `attachmentDigest` | `value` | `(bytes: Uint8Array) => Promise<string>` | Lowercase hex SHA-256 of the bytes (WebCrypto). | | `AttachmentLimitError` | `value` | `typeof AttachmentLimitError` | Error raised for attachment limit failures. | | `AttachmentPutInput` | `type` | `AttachmentPutInput` | Type contract for attachment put input. | | `AttachmentRef` | `type` | `AttachmentRef` | Content-addressed descriptor of one stored attachment. | | `AttachmentStore` | `type` | `AttachmentStore` | Durable content-addressed attachment storage. - `put` is idempotent by `(scope, digest)` — re-putting the same content succeeds without duplicating storage (the first stored ref metadata is retained). It MUST verify the digest against the bytes and reject a mismatch with `AttachmentStoreError('DIGEST_MISMATCH')` before writing. - `get`/`getByAttachmentId` return `null` on a miss. - `delete` removes one stored attachment and throws `AttachmentStoreError('NOT_FOUND')` when nothing is stored under `(scope, digest)`. | | `AttachmentStoreError` | `value` | `typeof AttachmentStoreError` | Error raised for attachment store failures. | | `attachSandbox` | `value` | `(ref: SandboxRef \| SerializedSandboxRef, options?: AttachSandboxOptions) => SandboxFactory` | Build a `SandboxFactory` that, when invoked, returns an `AttachedSandboxEnv` delegating to the registered sandbox without owning its lifecycle. Calling `cleanup()` on the attached env unregisters this attachment but does NOT tear down the underlying sandbox. Pass an in-process `SandboxRef` to attach within the same process, or a `SerializedSandboxRef` (from `session.sandboxRef({ portable: true })`) to rehydrate a sandbox handed off from another process. Cross-process refs require a decoder registered for `serialized.provider` via `registerSandboxRefDecoder()`. | | `AutonomyMode` | `type` | `AutonomyMode` | Type contract for autonomy mode. | | `AutonomyOptions` | `type` | `AutonomyOptions` | Configuration options for autonomy. | | `AzureOpenAIModelProvider` | `value` | `typeof AzureOpenAIModelProvider` | Provider implementation for azure open aimodel. | | `AzureOpenAIProviderOptions` | `type` | `AzureOpenAIProviderOptions` | Configuration options for azure open aiprovider. | | `BashInput` | `type` | `BashInput` | Type contract for bash input. | | `bashTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<BashInput, ShellResult>` | Model-callable tool or tool factory for bash. | | `BedrockModelProvider` | `value` | `typeof BedrockModelProvider` | Provider implementation for bedrock model. | | `BedrockProviderOptions` | `type` | `BedrockProviderOptions` | Configuration options for bedrock provider. | | `buildModelMessagesFromHistory` | `value` | `(data: SessionData \| undefined, role?: Role) => ModelMessage[]` | Runtime API for build model messages from history; the generated signature shows its accepted inputs and return type. | | `buildResultFollowUpPrompt` | `value` | `() => string` | Follow-up prompt sent when the LLM ends a turn without calling `finish` or `give_up`. | | `buildResultFooter` | `value` | `() => string` | Footer appended to user prompts/skill bodies when a `result` schema is set. | | `buildResultRetryPrompt` | `value` | `(error: unknown, extraction?: boolean \| ResultExtractionOptions) => string` | Runtime API for build result retry prompt; the generated signature shows its accepted inputs and return type. | | `BUILTIN_BASH_MAX_BYTES` | `value` | `number` | Constant defining builtin bash max bytes. | | `BUILTIN_BASH_MAX_LINES` | `value` | `2000` | Constant defining builtin bash max lines. | | `BUILTIN_GLOB_MAX_RESULTS` | `value` | `1000` | Constant defining builtin glob max results. | | `BUILTIN_GREP_MAX_LINE_LENGTH` | `value` | `500` | Constant defining builtin grep max line length. | | `BUILTIN_GREP_MAX_MATCHES` | `value` | `100` | Constant defining builtin grep max matches. | | `BUILTIN_READ_MAX_BYTES` | `value` | `number` | Constant defining builtin read max bytes. | | `BUILTIN_READ_MAX_LINES` | `value` | `2000` | Public built-in tool limits; documentation and tests consume these constants. | | `BuiltinFileTool` | `type` | `BuiltinFileTool` | Model-callable tool or tool factory for builtin file. | | `BuiltinTool` | `type` | `BuiltinTool` | Model-callable tool or tool factory for builtin. | | `bytesToHex` | `value` | `(bytes: Uint8Array) => string` | Runtime API for bytes to hex; the generated signature shows its accepted inputs and return type. | | `CapabilityPolicy` | `type` | `CapabilityPolicy` | Type contract for capability policy. | | `CartesiaSttProvider` | `value` | `typeof CartesiaSttProvider` | Provider implementation for cartesia stt. | | `CartesiaSttProviderOptions` | `type` | `CartesiaSttProviderOptions` | Configuration options for cartesia stt provider. | | `CartesiaTtsProvider` | `value` | `typeof CartesiaTtsProvider` | Provider implementation for cartesia tts. | | `CartesiaTtsProviderOptions` | `type` | `CartesiaTtsProviderOptions` | Configuration options for cartesia tts provider. | | `chainSecretProviders` | `value` | `(...providers: Array<SecretProvider \| undefined>) => SecretProvider` | Resolve from providers in order; errors fail closed instead of falling through. | | `Channel` | `type` | `Channel` | Type contract for channel. | | `ChannelContext` | `type` | `ChannelContext` | Type contract for channel context. | | `ChannelDispatch` | `type` | `ChannelDispatch` | Type contract for channel dispatch. | | `ChannelDispatchRequest` | `type` | `ChannelDispatchRequest` | Input contract for channel dispatch. | | `ChannelRoute` | `type` | `ChannelRoute` | Channels turn platform webhooks (Slack, GitHub, …) into agent dispatches. Handlers are written against the Web `Request`/`Response` API and `crypto.subtle`, so the same channel runs on Node and Cloudflare. A channel is a stateless route container plus a conversation-id (de)serializer — session continuity falls out of the key (same thread → same key → same session). | | `CheckpointCreateOptions` | `type` | `CheckpointCreateOptions` | Configuration options for checkpoint create. | | `CheckpointRestoreOptions` | `type` | `CheckpointRestoreOptions` | Configuration options for checkpoint restore. | | `CheckpointResult` | `type` | `CheckpointResult` | Result returned by checkpoint. | | `clampCommandTimeout` | `value` | `(timeout: number \| undefined, policy?: CapabilityPolicy) => number \| undefined` | Runtime API for clamp command timeout; the generated signature shows its accepted inputs and return type. | | `clampReadLimit` | `value` | `(limit: number \| undefined) => number` | Runtime API for clamp read limit; the generated signature shows its accepted inputs and return type. | | `classifySubmissionState` | `value` | `(path: readonly SessionEntry[], submissionId: string) => SubmissionInspection` | Classify how far a persisted submission input progressed. - `absent` — the input entry never landed in session history: the attempt crashed before applying it. Safe to requeue for a clean first attempt. - `completed` — finished work: a canonical settlement entry exists, an assistant response follows the input with no unresolved trailing tool batch, or a later user input shows the conversation moved on. Settle as success; never retry (retrying completed work is the one unrecoverable corruption). - `continuable` — the trailing turn carries unresolved tool calls. The next `session.prompt()` re... | | `CohereModelProvider` | `value` | `typeof CohereModelProvider` | Provider implementation for cohere model. | | `CohereProviderOptions` | `type` | `CohereProviderOptions` | Configuration options for cohere provider. | | `combineSubmissionTelemetrySinks` | `value` | `(...sinks: SubmissionTelemetrySink[]) => SubmissionTelemetrySink` | Fan one event out to several sinks. | | `Command` | `type` | `Command<TInput>` | Type contract for command. | | `CommandEnvValue` | `type` | `CommandEnvValue` | Type contract for command env value. | | `CommandPolicy` | `type` | `CommandPolicy` | Type contract for command policy. | | `CommandToolInput` | `type` | `CommandToolInput` | Type contract for command tool input. | | `CommandToolOptions` | `type` | `CommandToolOptions` | Configuration options for command tool. | | `CompactionOptions` | `type` | `CompactionOptions` | Configuration options for compaction. | | `CompactionResult` | `type` | `CompactionResult` | Result returned by compaction. | | `configureDispatchRuntime` | `value` | `(runtime: DispatchRuntime) => void` | Configure the ambient dispatch queue used by `dispatch`. | | `configureJobInvocationRuntime` | `value` | `(next: JobInvocationRuntime) => void` | Runtime API for configure job invocation runtime; the generated signature shows its accepted inputs and return type. | | `connectFabricVoice` | `value` | `(options: VoiceWsClientOptions) => VoiceWsClientHandle` | Runtime API for connect fabric voice; the generated signature shows its accepted inputs and return type. | | `connectFabricWs` | `value` | `(options: WsClientOptions) => WsClientHandle` | Runtime API for connect fabric ws; the generated signature shows its accepted inputs and return type. | | `connectMcpServer` | `value` | `(name: string, options: McpServerOptions) => Promise<McpServerConnection>` | Runtime API for connect mcp server; the generated signature shows its accepted inputs and return type. | | `consoleTelemetryExporter` | `value` | `(prefix?: string) => TelemetryExporter` | Telemetry exporter that writes spans through the SDK logger (default `console`-backed). Useful for local development and as a fallback when no OpenTelemetry collector is wired up. Use `openTelemetryExporter` or `langfuseExporter` for production. | | `ContextBudget` | `type` | `ContextBudget` | Type contract for context budget. | | `ContextBudgetOptions` | `type` | `ContextBudgetOptions` | Configuration options for context budget. | | `CONVERSATION_STREAM_DEFAULT_READ_LIMIT` | `value` | `100` | Constant defining conversation stream default read limit. | | `CONVERSATION_STREAM_FORMAT_VERSION` | `value` | `1` | Constant defining conversation stream format version. | | `CONVERSATION_STREAM_MAX_READ_LIMIT` | `value` | `1000` | Constant defining conversation stream max read limit. | | `ConversationFoldCheckpoint` | `type` | `ConversationFoldCheckpoint` | Disposable durable cache of a folded conversation at one committed batch. | | `conversationKey` | `value` | `(provider: string, version: string, ...segments: string[]) => string` | Runtime API for conversation key; the generated signature shows its accepted inputs and return type. | | `ConversationMessage` | `type` | `ConversationMessage` | Type contract for conversation message. | | `ConversationMessageDisplay` | `type` | `ConversationMessageDisplay` | Type contract for conversation message display. | | `ConversationMessagePurpose` | `type` | `ConversationMessagePurpose` | Type contract for conversation message purpose. | | `ConversationMessageRole` | `type` | `ConversationMessageRole` | Type contract for conversation message role. | | `ConversationPart` | `type` | `ConversationPart` | Type contract for conversation part. | | `ConversationProducerClaim` | `type` | `ConversationProducerClaim` | Type contract for conversation producer claim. | | `ConversationProjector` | `value` | `typeof ConversationProjector` | Runtime API for conversation projector; the generated signature shows its accepted inputs and return type. | | `ConversationReply` | `type` | `ConversationReply` | Type contract for conversation reply. | | `ConversationSettlement` | `type` | `ConversationSettlement` | Type contract for conversation settlement. | | `ConversationSnapshot` | `type` | `ConversationSnapshot` | Type contract for conversation snapshot. | | `ConversationStreamAppendInput` | `type` | `ConversationStreamAppendInput` | Type contract for conversation stream append input. | | `ConversationStreamBatch` | `type` | `ConversationStreamBatch` | Type contract for conversation stream batch. | | `ConversationStreamIdentity` | `type` | `ConversationStreamIdentity` | Type contract for conversation stream identity. | | `ConversationStreamMeta` | `type` | `ConversationStreamMeta` | Type contract for conversation stream meta. | | `conversationStreamPath` | `value` | `(storeSessionId: string) => string` | Stream path for a session's conversation projection. | | `ConversationStreamReadResult` | `type` | `ConversationStreamReadResult` | Result returned by conversation stream read. | | `ConversationStreamRecord` | `type` | `ConversationStreamRecord` | Append-only conversation stream — the durable, offset-addressable projection of a session's active path (v2 migration, phase A4). The SessionEntry DAG remains the single source of truth for model context; this stream exists so clients can read a conversation with offsets (catch-up + live tail), across processes, without count-based replay. The projection appends one record per active-path entry, and — because the DAG can branch (fork/replay/checkpoint-restore) while a stream cannot — an explicit `truncated` record whenever the active path rewinds, paired with a producer-epoch bump so stale... | | `ConversationStreamStore` | `type` | `ConversationStreamStore` | Durable append-only conversation stream storage. **Batch atomicity is a hard contract requirement**: every record in an `append` must be persisted together under one offset, all-or-nothing. First-party adapters satisfy this by serializing the batch into a single row/document write; an adapter that splits records across non-atomic writes violates the contract. **Producer fencing**: `acquireProducer` bumps the producer epoch; appends carrying a stale epoch are rejected. The (path, producerId, epoch, sequence) uniqueness makes redelivered appends idempotent — a retried append with the same coo... | | `ConversationStreamStoreError` | `value` | `typeof ConversationStreamStoreError` | Error raised for conversation stream store failures. | | `CostBudgetStore` | `type` | `CostBudgetStore` | Async store for cross-process spend aggregation. Pair with `CostLimit.scopeKey` + `CostLimit.perScope` to enforce a budget that survives process restarts — "tenant:acme spends ≤ $50 today" or "company-wide ≤ $100 this hour". Built-in implementations: - `inMemoryCostBudgetStore()` — process-local; default. - `@fabric-harness/node` exposes `postgresCostBudgetStore({ pool })`. | | `CostBudgetTracker` | `value` | `typeof CostBudgetTracker` | Tracks cumulative session spend. Cheap to construct; one per session. | | `CostLimit` | `type` | `CostLimit` | Type contract for cost limit. | | `CostLimitContext` | `type` | `CostLimitContext` | Type contract for cost limit context. | | `CostLimitExceededError` | `value` | `typeof CostLimitExceededError` | Error raised for cost limit exceeded failures. | | `createAgent` | `value` | `<TEnv = Record<string, string>>(initialize: ((context: PersistentAgentContext<TEnv>) => PersistentAgentConfig \| Promise<PersistentAgentConfig>) \| DynamicAgentFunction<TEnv>, definition?: PersistentAgentConfig) => CreatedAgent<TEnv>` | Define a persistent, URL-addressable agent. Files in `.fabricharness/agents/` default-export `createAgent(...)`; the runtime resolves a fresh config per interaction and keeps sessions across direct prompts and dispatched inputs. | | `createApprovalGrant` | `value` | `(input: { approvalId: string; toolCallId: string; toolInput: unknown; principal: FabricPrincipal; response: ApprovalResponse; createdAt: string; ttlSeconds?: number; decidedAt?: string; }) => ApprovalGrant` | Creates approval grant. | | `createApprovalGrantForState` | `value` | `(state: ApprovalState, response: ApprovalResponse) => ApprovalGrant \| undefined` | Build the terminal grant after a store reaches approval quorum. | | `createAttachmentRef` | `value` | `(input: { id: string; mimeType: string; bytes: Uint8Array; filename?: string; }) => Promise<AttachmentRef>` | Build an `AttachmentRef` for the given bytes, computing the SHA-256 digest via WebCrypto (`crypto.subtle`) so the SDK stays runtime-agnostic. | | `createBuiltinTools` | `value` | `(sandbox: SandboxEnv, packagedSkills?: Record<string, PackagedSkillDirectory>) => BuiltinTool[]` | Creates builtin tools. | | `createCommandTools` | `value` | `(commands: Command[], options?: CommandToolOptions) => ToolDef<CommandToolInput, ShellResult>[]` | Creates command tools. | | `createConsoleLogger` | `value` | `(level?: LogLevel) => Logger` | Build a Console-backed logger with an explicit level. Useful for tests that want to capture or silence SDK output without touching globals. | | `CreatedAgent` | `type` | `CreatedAgent<TEnv>` | A persistent, addressable agent created with `createAgent`. Distinct from a finite `defineAgent({ run })` job: it has no `run` — the initializer returns configuration, and the runtime maintains sessions across interactions. | | `createDirectAgentSubmissionInput` | `value` | `(options: { agent: string; id: string; session?: string; message: DeliveredMessage; initialData?: JsonValue; uid?: string \| null; joinWhileBusy?: boolean; tenantId?: string; actor?: FabricActor; durability?: AgentSubmissionDurability; }) => AgentSubmissionInput` | Mint a direct-prompt submission input with a fresh submission id. | | `createDispatchAgentSubmissionInput` | `value` | `(dispatch: DispatchInput) => AgentSubmissionInput` | Map a `DispatchInput` onto the persisted submission input shape. | | `createErrorReference` | `value` | `(now?: number) => string` | Mint an opaque, sortable correlation reference for one transported error. | | `createFabricAgentRouter` | `value` | `(backend: FabricAgentRouterBackend, options?: FabricAgentRouterOptions) => FabricAgentRouter` | Mount the persistent-agent HTTP surface on any fetch-capable host. See the package declarations for an example. | | `createFabricContext` | `value` | `<TPayload extends JsonObject = JsonObject>(payload: TPayload) => FabricContext<TPayload>` | Creates fabric context. | | `createFabricFs` | `value` | `(sandboxLike: SandboxEnv \| Promise<SandboxEnv> \| (() => SandboxEnv \| Promise<SandboxEnv>)) => FabricFs` | Adapt a sandbox into the public filesystem convenience surface. | | `createFileTools` | `value` | `(sandbox: SandboxEnv, packagedSkills?: Record<string, PackagedSkillDirectory>) => BuiltinFileTool[]` | Creates file tools. | | `createMcpAuthorizationCodeAuth` | `value` | `(options: McpAuthorizationCodeOptions) => OAuthClientProvider` | Authorization-code + PKCE provider; the MCP SDK refreshes stored tokens automatically. | | `createMcpClientCredentialsAuth` | `value` | `(options: McpClientCredentialsOptions) => OAuthClientProvider` | OAuth client-credentials provider with MCP SDK token refresh handling. | | `createMcpTools` | `value` | `(client: McpClientLike, options?: CreateMcpToolsOptions) => Promise<ToolDef[]>` | Creates mcp tools. | | `CreateMcpToolsOptions` | `type` | `CreateMcpToolsOptions` | Configuration options for create mcp tools. | | `createObservabilityObserver` | `value` | `(options: ObservabilityObserverOptions) => FabricEventCallback` | Create a fail-open event observer suitable for Braintrust, Sentry, Jetty, or a custom sink. | | `createObservabilityRecord` | `value` | `(event: FabricEvent, options: Pick<ObservabilityObserverOptions, "integration" \| "correlation" \| "captureData" \| "additionalSecrets">) => FabricObservabilityRecord` | Convert a Fabric event into a vendor-neutral, low-cardinality record. | | `createOperationalMetricsCollector` | `value` | `() => OperationalMetricsCollector` | Low-cardinality operational metrics collector suitable for OTel/Prometheus bridging. | | `createPiAgentLoopRuntime` | `value` | `(options?: PiAgentLoopRuntimeOptions) => PiAgentLoopRuntime` | Creates pi agent loop runtime. | | `createRemoteSandboxEnv` | `value` | `(api: RemoteSandboxApi, options?: RemoteSandboxOptions) => SandboxEnv` | Wrap a provider-owned remote sandbox client in Fabric's SandboxEnv contract. Provider credentials and SDK objects remain outside model context/history; Fabric only sees the narrow file/shell/snapshot API exposed here. | | `createResultTools` | `value` | `<TResult>(validator: ResultValidator<TResult>) => ResultToolBundle<TResult>` | Produce the per-call `finish` and `give_up` tool pair for a given ResultValidator. - `finish`'s parameters are a generic JSON Schema object because we can't derive a precise schema from `ResultValidator`. The validator's `safeParse` handles actual validation. - First successful `finish` (or `give_up`) call wins. Subsequent calls return an error tool result rather than throwing, to keep the conversation transcript natural. | | `createSandboxEnv` | `value` | `(options?: SandboxFactoryOptions) => Promise<SandboxEnv>` | Creates sandbox env. | | `createScopedSandboxEnv` | `value` | `(sandbox: SandboxEnv, cwd?: string) => SandboxEnv` | Return a view of a sandbox with a narrower default cwd. Relative file paths and shell cwd values are resolved from this scoped cwd while the underlying sandbox still enforces its workspace boundary. | | `createSearchTool` | `value` | `(retriever: Retriever, options?: SearchToolOptions) => ToolDef<SearchToolInput, SearchToolResult>` | Exposes a `Retriever` to the model as a `search` tool. The tool is read-only; wrap it with a governance decorator to stamp lineage or route approvals. | | `createStdioMcpClient` | `value` | `(options: StdioMcpClientOptions) => StdioMcpClient` | Creates stdio mcp client. | | `createSubmissionRunner` | `value` | `(options: SubmissionRunnerOptions) => SubmissionRunner` | Creates submission runner. | | `createVirtualSandboxEnv` | `value` | `(options?: SandboxFactoryOptions & { initialFiles?: Record<string, string \| Uint8Array>; }) => VirtualSandboxEnv` | Creates virtual sandbox env. | | `CredentialMissingStrategy` | `type` | `"fail"` | Type contract for credential missing strategy. | | `currentJobInvocation` | `value` | `() => JobInvocationContext \| undefined` | Runtime API for current job invocation; the generated signature shows its accepted inputs and return type. | | `currentSubmissionContext` | `value` | `() => SubmissionContext \| undefined` | The submission owning the current execution, or `undefined` outside one. | | `DeepgramSttProvider` | `value` | `typeof DeepgramSttProvider` | Provider implementation for deepgram stt. | | `DeepgramSttProviderOptions` | `type` | `DeepgramSttProviderOptions` | Configuration options for deepgram stt provider. | | `DEFAULT_HEADLESS_PREAMBLE` | `value` | `"You are running in headless autonomous mode (background-agent mode) with no human operator assumed. Work autonomously: Do not ask clarifying questions or wait for in-band user input. Make safe, reasonable assumptions when possible; if blocked by missing credentials, unavailab...` | Constant defining default headless preamble. | | `defaultLoopRuntime` | `value` | `NativeLoopRuntime` | Runtime API for default loop runtime; the generated signature shows its accepted inputs and return type. | | `defaultModelProvider` | `value` | `MockModelProvider` | Provider implementation for default model. | | `defaultSessionStore` | `value` | `InMemorySessionStore` | Storage contract for default session. | | `defineAction` | `value` | `<TInput = unknown, TOutput = unknown>(options: ActionOptions<TInput, TOutput>) => ActionDefinition<TInput, TOutput>` | Define an action — the harness-context counterpart to `defineTool`. A tool is a leaf capability the model calls; an action holds the harness (`context.init`) and can prompt, spawn sessions, and compose other work. Input/output use the harness `schema` builders and are validated on every `runAction` call; outputs must be JSON-serializable. | | `defineAgent` | `value` | `<TInput = JsonObject, TOutput = unknown>(definition: AgentDefinition<TInput, TOutput>) => DefinedAgent<TInput, TOutput>` | No-defaults finite-agent builder with lazy default-session helpers. The runtime admits these finite definitions through its job/run protocol, but authors define an agent. Use `createAgent` for a persistent, URL-addressable agent whose sessions span multiple submissions. | | `defineChannel` | `value` | `(channel: Channel) => Channel` | Validates and brands a channel's routes. | | `defineCommand` | `value` | `<TInput = CommandToolInput>(name: string, options?: Omit<Command<TInput>, "name">) => Command<TInput>` | Defines command. | | `DefinedAgent` | `type` | `DefinedAgent<TInput, TOutput>` | Type contract for defined agent. | | `defineMcpConnection` | `value` | `(definition: McpConnectionDefinition) => McpConnectionDefinition` | Defines mcp connection. | | `defineSkill` | `value` | `(input: DefineSkillInput) => Skill` | Build a `Skill` from explicit fields. Throws when `name` or `instructions` is empty — a skill the model cannot name, or one that carries no instruction, is a silent no-op at activation time, so it fails here instead. | | `DefineSkillInput` | `type` | `DefineSkillInput` | Type contract for define skill input. | | `defineSubagent` | `value` | `(definition: SubagentDefinition) => SubagentDefinition` | Defines subagent. | | `defineTool` | `value` | `{ <TInput = unknown, TOutput = unknown>(tool: ToolDef<TInput, TOutput>): ToolDef<TInput, TOutput>; <TInput = unknown, TOutput = unknown, THarness extends boolean = false, TDurable extends boolean = false>(tool: HookToolDefinition<TInput, TOutput...` | Defines tool. | | `defineWebhookSubscription` | `value` | `<TPayload = JsonObject>(definition: WebhookSubscriptionDefinition<TPayload>) => WebhookSubscriptionDefinition<TPayload>` | Helper that returns the definition unchanged. Useful for type inference and to keep agent files declarative. See the package declarations for an example. | | `DeletionCompletionRecord` | `type` | `DeletionCompletionRecord` | Type contract for deletion completion record. | | `DeliveredAttachment` | `type` | `DeliveredAttachment` | One attachment on a `kind: 'user'` message. Today the only supported attachment is an image, carried either inline (`data`, base64) or as a durable content-addressed reference (`ref`) once an attachment store is configured — admission materializes inline bytes into refs. An attachment must carry `data` or `ref` (or both, transiently during materialization). | | `DeliveredAttachmentRef` | `type` | `DeliveredAttachmentRef` | Durable reference to attachment bytes in an attachment store. | | `DeliveredMessage` | `type` | `DeliveredMessage` | DeliveredMessage — the single unified input shape for everything that enters a persistent agent's session: direct HTTP prompts, dispatch, channels/webhooks, Databricks events, SDK clients, and tests. `kind: 'user'` is a direct user talking to the assistant (1:1 chat surface), optionally carrying attachments. `kind: 'signal'` models everything beyond that direct exchange — a Slack thread or a Lakeflow job event is activity the agent observes, not the assistant's own user speaking. Sender identity and structured metadata go in `attributes`; the message itself in `body`. Signals render into mo... | | `deliveredSignalToEntryData` | `value` | `(message: Extract<DeliveredMessage, { kind: "signal"; }>) => SignalEntryData` | Map a signal-kind message onto the persisted `signal` entry's data shape. | | `deriveCompactionDefaults` | `value` | `(input: { contextWindowTokens: number; maxOutputTokens?: number; }) => { reserveTokens: number; keepRecentTokens: number; }` | Compute model-aware compaction defaults. Reserve is capped at the model's max output because reserving more than the model can emit in one turn wastes context; the preserved tail stays flat because recent-context fidelity depends on the active work, not on the model's total window size. | | `dispatch` | `value` | `{ (agent: CreatedAgent, request: AgentDispatchRequest): Promise<DispatchReceipt>; (request: NamedAgentDispatchRequest): Promise<DispatchReceipt>; }` | Runtime API for dispatch; the generated signature shows its accepted inputs and return type. | | `DispatchInput` | `type` | `DispatchInput` | Internal enqueued form, carrying correlation + isolation metadata. | | `DispatchProcessor` | `type` | `DispatchProcessor` | Consumes enqueued dispatches and applies them to an instance session. | | `DispatchQueue` | `type` | `DispatchQueue` | Admission queue for dispatches. The default is in-process; durable backends implement the same shape. | | `DispatchReceipt` | `type` | `DispatchReceipt` | Acceptance confirmation for an enqueued dispatch. | | `DockerSandboxEnv` | `value` | `typeof DockerSandboxEnv` | Runtime API for docker sandbox env; the generated signature shows its accepted inputs and return type. | | `DockerSandboxOptions` | `type` | `DockerSandboxOptions` | Configuration options for docker sandbox. | | `DURABILITY_DEFAULT_MAX_ATTEMPTS` | `value` | `10` | Default maximum total attempts before terminalization. | | `DURABILITY_DEFAULT_TIMEOUT_MS` | `value` | `3600000` | Default submission timeout in milliseconds (one hour). | | `DurableSessionRuntime` | `type` | `DurableSessionRuntime` | Structural delegate for durable session execution. When `init()` is given a `sessionRuntime` factory that produces one of these, the SDK's session calls (`prompt`, `task`, `shell`, `checkpoint.*`) are routed through the runtime instead of executing inline. This is the seam for Temporal workflows, external orchestration runtimes, or test fakes. `mount`, `history`, `artifact`, and `compact` remain SDK-local concerns and are not delegated — they operate against the local session store. | | `DurableSessionRuntimeFactory` | `type` | `DurableSessionRuntimeFactory` | Factory for durable session runtime. | | `DynamicAgentExecutionDescriptor` | `type` | `DynamicAgentExecutionDescriptor` | JSON-safe identity required to re-render a persistent dynamic agent at a trusted durable-runtime boundary. Hook functions, tool implementations, credentials, and resolved MCP connections are deliberately excluded. | | `DynamicAgentFinishContext` | `type` | `DynamicAgentFinishContext` | Type contract for dynamic agent finish context. | | `DynamicAgentFunction` | `type` | `DynamicAgentFunction<TEnv>` | Type contract for dynamic agent function. | | `DynamicAgentProps` | `type` | `DynamicAgentProps<TEnv>` | Dynamic persistent-agent composition. The runtime keeps Fabric's builders, policies, persistence contracts, and backend-neutral types while allowing capabilities to evolve per interaction. | | `DynamicAgentRefreshInput` | `type` | `DynamicAgentRefreshInput` | Type contract for dynamic agent refresh input. | | `DynamicAgentRenderOptions` | `type` | `DynamicAgentRenderOptions` | Configuration options for dynamic agent render. | | `DynamicAgentResponse` | `type` | `DynamicAgentResponse` | Response contract for dynamic agent. | | `DynamicAgentRuntime` | `type` | `DynamicAgentRuntime` | Type contract for dynamic agent runtime. | | `DynamicAgentStartContext` | `type` | `DynamicAgentStartContext` | Type contract for dynamic agent start context. | | `DynamicLifecycleContext` | `type` | `DynamicLifecycleContext` | Type contract for dynamic lifecycle context. | | `DynamicMetadataCallback` | `type` | `DynamicMetadataCallback` | Type contract for dynamic metadata callback. | | `editFileTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<EditInput, void>` | Model-callable tool or tool factory for edit file. | | `EditInput` | `type` | `EditInput` | Type contract for edit input. | | `ElevenLabsTtsProvider` | `value` | `typeof ElevenLabsTtsProvider` | Provider implementation for eleven labs tts. | | `ElevenLabsTtsProviderOptions` | `type` | `ElevenLabsTtsProviderOptions` | Configuration options for eleven labs tts provider. | | `EmbeddingProvider` | `type` | `EmbeddingProvider` | Embeddings seam. Feeds self-managed-embedding vector indexes (embed the query → query vector) and any bring-your-own retrieval pipeline. Returns one vector per input text, order-preserving. | | `emitOpenTelemetrySpan` | `value` | `(tracer: Tracer, span: TelemetrySpan, attributes?: Record<string, string \| number \| boolean>, conventions?: "fabric" \| "foundry") => Span` | Runtime API for emit open telemetry span; the generated signature shows its accepted inputs and return type. | | `emitSubmissionTelemetry` | `value` | `(sink: SubmissionTelemetrySink \| undefined, event: SubmissionTelemetryEvent, onError?: (error: unknown) => void) => void` | Deliver an event to a sink, swallowing (and reporting) sink failures. | | `EmptySandboxEnv` | `value` | `typeof EmptySandboxEnv` | Runtime API for empty sandbox env; the generated signature shows its accepted inputs and return type. | | `enqueueDispatch` | `value` | `(queue: DispatchQueue, request: NamedAgentDispatchRequest, extra?: { tenantId?: string; actor?: FabricActor; dispatchId?: string; }) => Promise<DispatchReceipt>` | Validate + normalize a named request and enqueue it, generating the dispatch id. | | `ensurePersistentInstanceIdentity` | `value` | `(options: { store: SessionStore; agentName: string; instanceId: string; uid?: string \| null; tenantId?: string; actor?: FabricActor; }) => Promise<PersistentInstanceIdentity>` | Atomically resolve or create one tenant-scoped persistent instance generation. | | `entryToTelemetrySpan` | `value` | `(sessionId: string, entry: SessionEntry) => TelemetrySpan \| undefined` | Runtime API for entry to telemetry span; the generated signature shows its accepted inputs and return type. | | `environmentSecretProvider` | `value` | `(options?: EnvironmentSecretProviderOptions) => SecretProvider` | Runtime-only environment provider with optional prefix and explicit allowlist. | | `EnvironmentSecretProviderOptions` | `type` | `EnvironmentSecretProviderOptions` | Configuration options for environment secret provider. | | `estimateCostUsd` | `value` | `(modelRef: string, usage: ModelPricingUsage) => number` | Estimate USD cost for a single model call. Returns `0` when no row matches `modelRef` — callers should treat 0 as "unknown" and not overwrite an existing `costUsd` from the provider. | | `estimateModelMessagesTokens` | `value` | `(messages: ModelMessage[]) => number` | Runtime API for estimate model messages tokens; the generated signature shows its accepted inputs and return type. | | `estimateSessionEntriesTokens` | `value` | `(entries: SessionEntry[]) => number` | Runtime API for estimate session entries tokens; the generated signature shows its accepted inputs and return type. | | `estimateTextTokens` | `value` | `(text: string) => number` | Runtime API for estimate text tokens; the generated signature shows its accepted inputs and return type. | | `evaluateCommandPolicy` | `value` | `(command: string \| undefined, policy?: CapabilityPolicy) => PolicyDecision` | Runtime API for evaluate command policy; the generated signature shows its accepted inputs and return type. | | `evaluateContextBudget` | `value` | `(messages: ModelMessage[], options?: ContextBudgetOptions) => ContextBudget` | Runtime API for evaluate context budget; the generated signature shows its accepted inputs and return type. | | `evaluateNetworkPolicy` | `value` | `(input: string \| URL \| Request, policy?: CapabilityPolicy) => PolicyDecision` | Evaluate a URL or `Request` against the configured network policy. Returns `{ allowed: true }` when the request is permitted, otherwise a denial with the reason and matched pattern. | | `evaluateOperationalSlos` | `value` | `(snapshot: OperationalMetricsSnapshot, targets: OperationalSloTargets) => OperationalSloEvaluation` | Runtime API for evaluate operational slos; the generated signature shows its accepted inputs and return type. | | `evaluateToolCallPolicy` | `value` | `(call: ToolCall, policy?: CapabilityPolicy) => PolicyDecision` | Runtime API for evaluate tool call policy; the generated signature shows its accepted inputs and return type. | | `eventToTelemetrySpan` | `value` | `(event: FabricEvent) => TelemetrySpan \| undefined` | Runtime API for event to telemetry span; the generated signature shows its accepted inputs and return type. | | `execSandboxCommand` | `value` | `(sandbox: SandboxEnv, command: string, options?: SandboxExecOptions) => Promise<ShellResult>` | Reject promptly on cancellation even when a remote provider cannot cancel its command. The underlying promise remains observed and reports its final, redacted settlement through `onOrphanSettled`. | | `ExistsInput` | `type` | `ExistsInput` | Type contract for exists input. | | `existsTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<ExistsInput, boolean>` | Model-callable tool or tool factory for exists. | | `extractResultValue` | `value` | `(value: unknown, extraction?: boolean \| ResultExtractionOptions) => unknown` | Runtime API for extract result value; the generated signature shows its accepted inputs and return type. | | `FABRIC_OPERATIONAL_METRICS` | `value` | `{ readonly requestLatencyMs: "fabric_harness_request_latency_ms"; readonly submissionDurationMs: "fabric_harness_submission_duration_ms"; readonly queueAgeMs: "fabric_harness_queue_age_ms"; readonly errorsTotal: "fabric_harness_errors_total"; readonly approvalWaitMs: "fab...` | Constant defining fabric operational metrics. | | `FabricActor` | `type` | `FabricActor` | Type contract for fabric actor. | | `FabricAgent` | `type` | `FabricAgent` | Type contract for fabric agent. | | `FabricAgentAddress` | `type` | `FabricAgentAddress` | Identity of one addressed conversation. | | `FabricAgentAdmission` | `type` | `FabricAgentAdmission` | Type contract for fabric agent admission. | | `FabricAgentAdmissionResult` | `type` | `FabricAgentAdmissionResult` | Result returned by fabric agent admission. | | `FabricAgentConversationPage` | `type` | `FabricAgentConversationPage` | Type contract for fabric agent conversation page. | | `FabricAgentDeletion` | `type` | `FabricAgentDeletion` | Type contract for fabric agent deletion. | | `FabricAgentRouter` | `type` | `FabricAgentRouter` | Type contract for fabric agent router. | | `FabricAgentRouterBackend` | `type` | `FabricAgentRouterBackend` | The host-specific half of the router. Every method may throw; the router maps a thrown error to `500` with a generic body rather than leaking host internals to the caller. | | `FabricAgentRouterOptions` | `type` | `FabricAgentRouterOptions` | Configuration options for fabric agent router. | | `FabricAgentSubmissionStatus` | `type` | `FabricAgentSubmissionStatus` | Type contract for fabric agent submission status. | | `FabricContext` | `type` | `FabricContext<TPayload>` | Type contract for fabric context. | | `FabricError` | `value` | `typeof FabricError` | Error raised for fabric failures. | | `FabricErrorCode` | `type` | `FabricErrorCode` | Type contract for fabric error code. | | `FabricErrorOptions` | `type` | `FabricErrorOptions` | Configuration options for fabric error. | | `FabricEvent` | `type` | `FabricEvent<TData>` | Type contract for fabric event. | | `FabricEventCallback` | `type` | `FabricEventCallback` | Type contract for fabric event callback. | | `FabricEventType` | `type` | `FabricEventType` | Type contract for fabric event type. | | `FabricFs` | `type` | `FabricFs` | Out-of-band filesystem surface for a session sandbox. These operations do not write to conversation history and are intended for host-side plumbing: staging files, collecting artifacts, and preparing scratch space. If the model should reason about a file, prompt it to use the normal read/write/edit tools instead. | | `FabricObservabilityRecord` | `type` | `FabricObservabilityRecord` | Type contract for fabric observability record. | | `FabricPrincipal` | `type` | `FabricPrincipal` | The governed identity a piece of work runs as (v2). Distinct from `ActorIdentity` (who asked): the principal is what the platform's access control enforces — a human user, a machine service principal, or a hosted app's own identity. `ucPrincipal` carries the catalog-governance principal name when the platform has one (e.g. Unity Catalog). | | `FabricRuntime` | `type` | `FabricRuntime` | Execution runtime selection. - `inline` (default): single-process execution. Uses the configured `SessionStore` (in-memory by default) for history, artifacts, approvals. - `stateless`: explicit headless / ephemeral mode. No session store, no artifact persistence, no approval waiting. Each invocation is independent. Use for high-volume webhook agents and edge runtimes where state would just be discarded anyway. In production (`FABRIC_ENV=production` or `NODE_ENV=production`) this mode must be selected explicitly — `inline` without an explicit store will warn or fail depending on `FABRIC_ALLO... | | `FabricSession` | `type` | `FabricSession` | Type contract for fabric session. | | `FallbackModelProvider` | `value` | `typeof FallbackModelProvider` | Provider implementation for fallback model. | | `FallbackModelProviderOptions` | `type` | `FallbackModelProviderOptions` | Configuration options for fallback model provider. | | `FileStat` | `type` | `FileStat` | Type contract for file stat. | | `FilesystemEntry` | `type` | `FilesystemEntry` | Type contract for filesystem entry. | | `FilesystemPolicy` | `type` | `FilesystemPolicy` | Type contract for filesystem policy. | | `FilesystemSource` | `type` | `FilesystemSource` | A read-only content source that can be mounted into a sandbox at sandbox-creation time. The agent then has built-in `read`, `glob`, and `grep` tools available over the mounted content — no retrieval pipeline, no embeddings, no vector store required. Sources are intentionally minimal: they yield (path, content) pairs. Implementations decide how to enumerate (eager vs lazy is up to the source author) — the mount step pulls the full set into the sandbox. | | `findSubmissionInputIndex` | `value` | `(path: readonly SessionEntry[], submissionId: string) => number` | Index of the last canonical user or signal input carrying the submission id, or -1. | | `findTrailingDanglingToolCalls` | `value` | `(path: SessionEntry[]) => SessionEntry[]` | Find trailing `tool_call` entries on the active path that were never settled — no matching `tool_result` (paired by `toolCallId`, falling back to tool name) and no subsequent `error` entry for the same tool. A dangling call means a model turn died (crash/abort) between recording the call and recording its outcome. Left in place it produces an assistant `tool_use` with no `tool_result` on resume, which providers reject — the repair path appends synthetic interrupted outcomes for exactly the entries returned here. Conservative by construction: only the window after the last turn boundary (use... | | `findTrailingUnfinishedTasks` | `value` | `(path: SessionEntry[]) => SessionEntry[]` | Trailing `task_start` entries in the same window with no matching `task_end` — a subtask that was in flight when the turn died. These do not corrupt model context (task entries are bookkeeping), but settling them keeps UI/audit state coherent. | | `formatSchemaIssues` | `value` | `(issues: SchemaIssue[]) => string` | Runtime API for format schema issues; the generated signature shows its accepted inputs and return type. | | `formatStreamOffset` | `value` | `(offset: number) => string` | Runtime API for format stream offset; the generated signature shows its accepted inputs and return type. | | `fumadocsSource` | `value` | `(contentRoot: string, options?: { name?: string; stripFrontmatter?: boolean; include?: (relativePath: string) => boolean; }) => FilesystemSource` | Mount a local Fumadocs content directory as a knowledge base. Strips MDX frontmatter by default for cleaner agent context. For a published Fumadocs site, fetch its `llms.txt` / sitemap and pass the URLs to `httpFilesystemSource`. | | `GeminiModelProvider` | `value` | `typeof GeminiModelProvider` | Provider implementation for gemini model. | | `GeminiProviderOptions` | `type` | `GeminiProviderOptions` | Configuration options for gemini provider. | | `GeneralSubagent` | `value` | `SubagentDefinition` | Runtime API for general subagent; the generated signature shows its accepted inputs and return type. | | `generateAffinityKey` | `value` | `(agentId: string, sessionId: string) => string` | Generate a deterministic `aff_\u003cULID\u003e` affinity key from an `(agentId, sessionId)` pair. The same pair always produces the same key, which is stable across restarts. Different pairs produce different keys with overwhelming probability. | | `generateWithRuntime` | `value` | `(provider: ModelProvider, request: ModelRequest, options?: ModelRuntimeOptions) => Promise<ModelResponse>` | Runtime API for generate with runtime; the generated signature shows its accepted inputs and return type. | | `getAgentDefinition` | `value` | `(value: unknown) => AgentDefinition<unknown, unknown> \| undefined` | Returns agent definition. | | `getCreatedAgent` | `value` | `(value: unknown) => CreatedAgent \| undefined` | Return the `CreatedAgent` carried by a value, or `undefined`. | | `getLogger` | `value` | `() => Logger` | Get the currently configured logger. | | `getVirtualSandbox` | `value` | `(source: FilesystemSource, options?: { mountAt?: string; }) => SandboxFactory` | One-liner helper for the most common pattern: mount a single read-only source into a virtual sandbox. Equivalent to: See the package declarations for an example. Used for support agents, runbook lookup, FAQ assistants — anywhere a small Markdown corpus needs to be searchable via the agent's built-in `grep`/`glob`/`read` tools. See the package declarations for an example. | | `GlobInput` | `type` | `GlobInput` | Type contract for glob input. | | `globTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<GlobInput, string[]>` | Model-callable tool or tool factory for glob. | | `GrepInput` | `type` | `GrepInput` | Type contract for grep input. | | `GrepMatch` | `type` | `GrepMatch` | Type contract for grep match. | | `grepTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<GrepInput, GrepMatch[]>` | Model-callable tool or tool factory for grep. | | `hasSubmissionSettledEntry` | `value` | `(path: readonly SessionEntry[], submissionId: string) => boolean` | True when the path carries a canonical `submission_settled` entry for the id. | | `hexToBytes` | `value` | `(hex: string) => Uint8Array` | Runtime API for hex to bytes; the generated signature shows its accepted inputs and return type. | | `hmacSha256` | `value` | `(secret: string \| Uint8Array, message: Uint8Array) => Promise<Uint8Array>` | Runtime API for hmac sha256; the generated signature shows its accepted inputs and return type. | | `HookToolContext` | `type` | `HookToolContext<TInput, THarness, TDurable>` | Type contract for hook tool context. | | `HookToolDefinition` | `type` | `HookToolDefinition<TInput, TOutput, THarness, TDurable>` | Hook-oriented tool declaration supported by `defineTool()` and `useTool()`. | | `httpFilesystemSource` | `value` | `(resources: HttpResource[] \| (() => Promise<HttpResource[]>), options?: { name?: string; fetchImpl?: typeof fetch; }) => FilesystemSource` | Fetch a list of URLs and mount each response body as a file. Useful for pulling a small published docs set into the sandbox so the built-in `read`/`grep`/`glob` tools can search it like local files. | | `HttpResource` | `type` | `HttpResource` | Type contract for http resource. | | `init` | `value` | `(options?: AgentInit) => Promise<FabricAgent>` | Initialize a runtime-neutral Fabric agent from explicit model, sandbox, policy, store, identity, and lifecycle options. Call `agent.session()` on the returned value to create or resume a session. Supplying both `store` and `persistence` is invalid; a persistence adapter is connected before the agent is returned and connection failures propagate to the caller. | | `initializePersistentAgent` | `value` | `<TEnv>(created: CreatedAgent<TEnv>, context: PersistentAgentContext<TEnv>, overrides?: AgentInit) => Promise<{ config: PersistentAgentConfig; agent: FabricAgent; }>` | Resolve a persistent agent's config for an instance and build a `FabricAgent`. Runtime-specific resources (session store, workspace roles/skills, loop runtime) are layered by the host that calls this. | | `inMemoryApprovalNotificationStore` | `value` | `() => ApprovalNotificationDeliveryStore` | Process-local atomic delivery state for development and single-process hosts. | | `InMemoryAttachmentStore` | `value` | `typeof InMemoryAttachmentStore` | In-memory attachment store (dev / `runtime: 'stateless'` / tests). | | `InMemoryConversationStreamStore` | `value` | `typeof InMemoryConversationStreamStore` | In-memory conversation stream store (dev / `runtime: 'stateless'` / tests). | | `inMemoryCostBudgetStore` | `value` | `() => CostBudgetStore` | Process-local cost budget store. Default when `store` is not provided. | | `InMemoryDispatchQueue` | `value` | `typeof InMemoryDispatchQueue` | In-process dispatch queue: microtask-drained, concurrent across sessions, serialized within a single session. Suitable for the `inline`/`stateless` runtimes and dev. Durable delivery (surviving restarts) is provided by the Temporal-backed queue, which implements this same interface. | | `inMemorySessionMemory` | `value` | `() => SessionMemory` | Process-local in-memory implementation. Default when `init({ memory })` is not configured — pair with Postgres for durability across restarts. | | `InMemorySessionStore` | `value` | `typeof InMemorySessionStore` | Storage contract for in memory session. | | `inMemorySource` | `value` | `(files: Record<string, string \| Uint8Array>, options?: { name?: string; }) => FilesystemSource` | Build a source from an in-memory map of `path -> content`. Useful for tests, fixtures, and small static knowledge bases bundled into the agent module itself. | | `InMemorySubmissionStore` | `value` | `typeof InMemorySubmissionStore` | Storage contract for in memory submission. | | `InterruptedToolCallRef` | `type` | `InterruptedToolCallRef` | A tool call settled with an explicit interrupted-outcome marker at terminalization. | | `InvalidDeliveredMessageError` | `value` | `typeof InvalidDeliveredMessageError` | Thrown by `parseDeliveredMessage` on malformed input. | | `invoke` | `value` | `{ <TInput = JsonObject, TOutput = unknown>(job: DefinedAgent<TInput, TOutput>, options: JobInvocationOptions<TInput>): Promise<JobInvocationReceipt>; <TInput = JsonObject>(request: NamedJobInvocation<TInput>): Promise<JobInvocationRe...` | Runtime API for invoke; the generated signature shows its accepted inputs and return type. | | `isActionDefinition` | `value` | `(value: unknown) => value is ActionDefinition` | Checks whether a value is action definition. | | `isContextOverflowError` | `value` | `(error: unknown) => boolean` | Checks whether a value is context overflow error. | | `isCreatedAgent` | `value` | `(value: unknown) => value is CreatedAgent` | Whether a value is a `CreatedAgent`. | | `isDeliveredMessageShape` | `value` | `(value: unknown) => boolean` | True when a raw value already looks like a `DeliveredMessage` (has a valid `kind`). | | `isDynamicAgentRendering` | `value` | `() => boolean` | Checks whether a value is dynamic agent rendering. | | `isEvent` | `value` | `<T extends AgentEventType>(event: AgentEvent, type: T) => event is Extract<AgentEvent, { type: T; }>` | Type guard: narrow an `AgentEvent` to a specific variant. See the package declarations for an example. | | `isFabricError` | `value` | `(error: unknown) => error is FabricError` | Checks whether a value is fabric error. | | `isInMemoryStore` | `value` | `(store: SessionStore \| undefined) => boolean` | Returns true when `store` is the in-memory default (no `appendEntry` persistence beyond memory). Used by stateless mode to skip writes. | | `isStatelessRuntime` | `value` | `(runtime: FabricRuntime \| undefined) => boolean` | Checks whether a value is stateless runtime. | | `isSubmissionPayload` | `value` | `(input: unknown, ctx: SubmissionPayloadContext) => input is AgentSubmissionInput` | Validate that a parsed JSON payload matches the expected submission shape. Used after deserializing a persisted payload to verify the object is a well-formed `AgentSubmissionInput` that is consistent with the stored submission metadata. Both dispatch and direct payloads carry the same `message: DeliveredMessage` field — validated identically here regardless of transport `kind`. | | `isValidAffinityKey` | `value` | `(key: string) => boolean` | Checks whether a value is valid affinity key. | | `JobInvocationContext` | `type` | `JobInvocationContext` | Type contract for job invocation context. | | `JobInvocationOptions` | `type` | `JobInvocationOptions<TInput>` | Configuration options for job invocation. | | `JobInvocationReceipt` | `type` | `JobInvocationReceipt` | Type contract for job invocation receipt. | | `JobInvocationRuntime` | `type` | `JobInvocationRuntime` | Type contract for job invocation runtime. | | `JournalCallbacks` | `type` | `JournalCallbacks` | Type contract for journal callbacks. | | `jsonDeepEqual` | `value` | `(a: unknown, b: unknown) => boolean` | Structural equality over JSON values (objects compared key-order-insensitively). | | `JsonObject` | `type` | `JsonObject` | Type contract for json object. | | `JsonPrimitive` | `type` | `JsonPrimitive` | Type contract for json primitive. | | `JsonSchemaObject` | `type` | `JsonSchemaObject` | Type contract for json schema object. | | `JsonValue` | `type` | `JsonValue` | Type contract for json value. | | `LangfuseClientLike` | `type` | `LangfuseClientLike` | Optional Langfuse exporter. Adapts Fabric's `TelemetrySpan` shape to Langfuse's tracing API. The Langfuse client is provided by the caller — we don't take a hard dependency. Install peer dep: See the package declarations for an example. Usage: See the package declarations for an example. | | `langfuseExporter` | `value` | `(options: LangfuseExporterOptions) => TelemetryExporter` | Runtime API for langfuse exporter; the generated signature shows its accepted inputs and return type. | | `LangfuseExporterOptions` | `type` | `LangfuseExporterOptions` | Configuration options for langfuse exporter. | | `LEASE_DURATION_MS` | `value` | `30000` | Default lease duration for submission ownership in milliseconds (30 seconds). | | `listModelPrices` | `value` | `() => ModelPriceRow[]` | All currently-registered rows (newest-last). Returns a copy. | | `listSandboxBackendFactories` | `value` | `() => SandboxBackend[]` | Return provider backend names currently available to `createSandboxEnv()`. | | `listSandboxRefDecoders` | `value` | `() => string[]` | Returns the list of currently registered providers. | | `localDirectorySource` | `value` | `(hostPath: string, options?: { name?: string; include?: (relativePath: string) => boolean; }) => FilesystemSource` | Read a host directory recursively as a read-only source. `include` is called for each candidate file path (relative to `hostPath`). Return `false` to skip. Defaults to including everything. | | `LocalSandboxEnv` | `value` | `typeof LocalSandboxEnv` | Runtime API for local sandbox env; the generated signature shows its accepted inputs and return type. | | `LocalSandboxOptions` | `type` | `LocalSandboxOptions` | Configuration options for local sandbox. | | `Logger` | `type` | `Logger` | Minimal logger seam used by the SDK for non-event diagnostic output (warnings, deprecation notices, telemetry fallbacks). All `console.*` inside the SDK should route through `getLogger()` so ops teams can redirect or silence messages in production. The default logger writes to `console` and respects `FABRIC_HARNESS_LOG_LEVEL=debug\|info\|warn\|error\|silent` (default `warn`). | | `LogLevel` | `type` | `LogLevel` | Type contract for log level. | | `lookupModelPrice` | `value` | `(modelRef: string) => ModelPriceRow \| undefined` | Look up the most recently-registered row matching `modelRef`. `modelRef` can be: - `'provider/model'` (preferred, e.g. `'openai/gpt-4o'`) - `'model'` alone (e.g. `'gpt-4o'`) — first row whose model matches wins Provider matching is case-insensitive. Model matching is exact. | | `matchAgentRoute` | `value` | `(pathname: string) => AgentRouteMatch \| undefined` | Parse a pathname against the agent route surface. Returns `undefined` when the path is not an agent route, so a caller can fall through to its other route families. Percent-decoding happens here: a target that matched the raw segments would treat `ticket%2F1` as a different instance than the one the client addressed. | | `materializeMessageAttachments` | `value` | `(message: DeliveredMessage, store: AttachmentStore, options: { scope: string; idPrefix: string; maxCount?: number; maxAttachmentBytes?: number; maxTotalBytes?: number; }) => Promise<DeliveredMessage>` | Materialize a message's inline attachments into durable refs: decode the base64 data, store the bytes under `scope`, and return a NEW message whose attachments carry `{ type, mimeType, filename?, ref }` and no `data`. Deterministic by construction — attachment ids are `${idPrefix}_${index}` and digests derive from content — so an exact redelivery of the same message produces an identical materialized payload (admission idempotency). Messages without inline attachments are returned unchanged (same reference). | | `MAX_ATTACHMENT_DATA_LENGTH` | `value` | `number` | Maximum accepted base64 length for a single inline attachment. | | `McpAuthorizationCodeOptions` | `type` | `McpAuthorizationCodeOptions` | Configuration options for mcp authorization code. | | `McpAuthorizationCodeState` | `type` | `McpAuthorizationCodeState` | Type contract for mcp authorization code state. | | `McpClientCredentialsOptions` | `type` | `McpClientCredentialsOptions` | Configuration options for mcp client credentials. | | `McpClientLike` | `type` | `McpClientLike` | Type contract for mcp client like. | | `McpConnectionDefinition` | `type` | `McpConnectionDefinition` | Type contract for mcp connection definition. | | `McpServerConnection` | `type` | `McpServerConnection` | Type contract for mcp server connection. | | `McpServerOptions` | `type` | `McpServerOptions` | Configuration options for mcp server. | | `McpToolDescriptor` | `type` | `McpToolDescriptor` | Type contract for mcp tool descriptor. | | `McpTransport` | `type` | `McpTransport` | Type contract for mcp transport. | | `mergeCapabilityPolicies` | `value` | `(definition: CapabilityPolicy \| undefined, invocation: CapabilityPolicy \| undefined) => CapabilityPolicy \| undefined` | Treat a definition policy as a security floor. Invocation policy can add denials and approval requirements, but cannot replace definition allowlists. | | `mergeSessionEntryBatch` | `value` | `(existing: SessionData, entries: readonly SessionEntry[], expectedLeafId?: string, enforceExpectedLeaf?: boolean) => SessionData \| false` | Merge one idempotent, leaf-fenced entry batch into a session snapshot. Exported for first-party storage adapters so every backend applies the same conflict and exact-replay semantics before its single atomic write. | | `messageHasDataAttachments` | `value` | `(message: DeliveredMessage) => boolean` | True when the message carries at least one inline (base64) attachment. | | `mintlifySource` | `value` | `(contentRoot: string, options?: { name?: string; include?: (relativePath: string) => boolean; }) => FilesystemSource` | Mount a checked-out Mintlify content directory. For a hosted Mintlify MCP server, use `connectMcpServer('mintlify', { url, transport: 'streamable-http' })` instead. | | `MissingInputStrategy` | `type` | `MissingInputStrategy` | Type contract for missing input strategy. | | `MkdirInput` | `type` | `MkdirInput` | Type contract for mkdir input. | | `mkdirTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<MkdirInput, void>` | Model-callable tool or tool factory for mkdir. | | `MockModelProvider` | `value` | `typeof MockModelProvider` | Provider implementation for mock model. | | `MockModelProviderOptions` | `type` | `MockModelProviderOptions` | Configuration options for mock model provider. | | `MockScriptEntry` | `type` | `MockScriptEntry` | Type contract for mock script entry. | | `MockScriptMatch` | `type` | `MockScriptMatch` | Match criteria for a scripted mock entry. Every specified field must match. | | `MockScriptResponse` | `type` | `MockScriptResponse` | Response contract for mock script. | | `MockScriptToolCall` | `type` | `MockScriptToolCall` | Type contract for mock script tool call. | | `ModelAttemptEvent` | `type` | `ModelAttemptEvent` | Type contract for model attempt event. | | `ModelConfig` | `type` | `ModelConfig` | Type contract for model config. | | `ModelMessage` | `type` | `ModelMessage` | Type contract for model message. | | `ModelMessageRole` | `type` | `ModelMessageRole` | Type contract for model message role. | | `ModelMetadata` | `type` | `ModelMetadata` | Type contract for model metadata. | | `ModelPriceRow` | `type` | `ModelPriceRow` | Static USD price table for model providers. Used to populate `ModelUsage.costUsd` on responses that don't include billing info from the provider directly (most providers — only `pi-loop-runtime` and a handful of gateways report cost). Prices are stamped with `effectiveAt`. The table is best-effort: real billing reconciliation should use vendor invoices. Override or extend at runtime with `registerModelPrices` for custom-rate contracts. | | `ModelPricingUsage` | `type` | `ModelPricingUsage` | Type contract for model pricing usage. | | `ModelProvider` | `type` | `ModelProvider` | Provider implementation for model. | | `ModelProviderFactory` | `type` | `ModelProviderFactory` | Resolves a parsed `provider/model-id` ref into a concrete provider. Registered factories let out-of-core packages (e.g. | | `ModelProviderResolver` | `type` | `ModelProviderResolver` | Type contract for model provider resolver. | | `ModelRequest` | `type` | `ModelRequest` | Input contract for model. | | `ModelResponse` | `type` | `ModelResponse` | Response contract for model. | | `ModelRuntimeOptions` | `type` | `ModelRuntimeOptions` | Configuration options for model runtime. | | `ModelStreamChunk` | `type` | `ModelStreamChunk` | Type contract for model stream chunk. | | `ModelToolCall` | `type` | `ModelToolCall` | Type contract for model tool call. | | `ModelToolSchema` | `type` | `ModelToolSchema` | Type contract for model tool schema. | | `ModelUsage` | `type` | `ModelUsage` | Type contract for model usage. | | `MountedSource` | `type` | `MountedSource` | Data or filesystem source for mounted. | | `MountResult` | `type` | `MountResult` | Result returned by mount. | | `NamedAgentDispatchRequest` | `type` | `NamedAgentDispatchRequest` | A dispatch request that names its target agent. | | `NamedJobInvocation` | `type` | `NamedJobInvocation<TInput>` | Type contract for named job invocation. | | `NativeLoopRuntime` | `value` | `typeof NativeLoopRuntime` | Runtime API for native loop runtime; the generated signature shows its accepted inputs and return type. | | `NetworkEnforcementLayer` | `type` | `NetworkEnforcementLayer` | Type contract for network enforcement layer. | | `NetworkEnforcementRequirement` | `type` | `NetworkEnforcementRequirement` | Type contract for network enforcement requirement. | | `NetworkPolicy` | `type` | `NetworkPolicy` | Type contract for network policy. | | `noopSessionStore` | `value` | `NoopSessionStore` | Storage contract for noop session. | | `NoopSessionStore` | `value` | `typeof NoopSessionStore` | No-op session store for `runtime: 'stateless'` mode. All writes are discarded; reads always return the empty initial session. Use this when the agent is intended as a pure request/response handler with no persistence (typical for high-volume webhooks and edge runtimes). Approvals and artifact retrieval are not supported — wiring those up requires a real store. Callers in stateless mode should not rely on artifact persistence or approval gating. | | `normalizeDeliveredMessage` | `value` | `(input: unknown) => DeliveredMessage` | Normalize legacy inputs into a `DeliveredMessage`: - a string → a user message with that body - a value with a `kind` discriminator → validated as a DeliveredMessage - any other JSON value → a user message with the JSON-stringified body (matching the historical dispatch rendering, so behavior is unchanged for pre-DeliveredMessage callers) | | `ObservabilityCorrelation` | `type` | `ObservabilityCorrelation` | Type contract for observability correlation. | | `ObservabilityObserverOptions` | `type` | `ObservabilityObserverOptions` | Configuration options for observability observer. | | `openAIChatCompletionToModelResponse` | `value` | `(json: OpenAIChatCompletion) => ModelResponse` | Response contract for open aichat completion to model. | | `OpenAICompatibleModelProvider` | `value` | `typeof OpenAICompatibleModelProvider` | Provider implementation for open aicompatible model. | | `OpenAICompatibleProviderOptions` | `type` | `OpenAICompatibleProviderOptions` | Configuration options for open aicompatible provider. | | `OpenAIRealtimeVoiceProvider` | `value` | `typeof OpenAIRealtimeVoiceProvider` | OpenAI Realtime voice provider. Connects via WebSocket; emits `audio_delta` / `text_delta` / `transcript` / `tool_call` / `response_done` events. No transitive dependency on `ws` — uses the global `WebSocket` available on Node 22+ and browsers. See the package declarations for an example. | | `OpenAIRealtimeVoiceProviderOptions` | `type` | `OpenAIRealtimeVoiceProviderOptions` | Configuration options for open airealtime voice provider. | | `openTelemetryExporter` | `value` | `(options: OpenTelemetryExporterOptions) => TelemetryExporter` | Bridge Fabric's SDK-neutral TelemetrySpan into a real | | `OpenTelemetryExporterOptions` | `type` | `OpenTelemetryExporterOptions` | Configuration options for open telemetry exporter. | | `OperationalMetricsCollector` | `type` | `OperationalMetricsCollector` | Type contract for operational metrics collector. | | `OperationalMetricsSnapshot` | `type` | `OperationalMetricsSnapshot` | Type contract for operational metrics snapshot. | | `OperationalSloEvaluation` | `type` | `OperationalSloEvaluation` | Type contract for operational slo evaluation. | | `OperationalSloTargets` | `type` | `OperationalSloTargets` | Type contract for operational slo targets. | | `PackagedSkillDirectory` | `type` | `PackagedSkillDirectory` | Type contract for packaged skill directory. | | `parseConversationKey` | `value` | `(key: string) => ParsedConversationKey` | Parses conversation key. | | `ParsedConversationKey` | `type` | `ParsedConversationKey` | Type contract for parsed conversation key. | | `parseDeliveredMessage` | `value` | `(value: unknown) => DeliveredMessage` | Validate a raw value as a `DeliveredMessage`. Shared by dispatch admission and the direct HTTP route so every transport produces the same structured error on bad input. | | `ParsedModelRef` | `type` | `ParsedModelRef` | Type contract for parsed model ref. | | `parseMockScript` | `value` | `(json: string) => MockScriptEntry[]` | Parse and validate a scripted-mock fixture file (JSON text). Accepts a bare array of entries or an aimock-style `{ "fixtures": [...] }` wrapper. Throws with an entry index when the shape is invalid. | | `parseModelRef` | `value` | `(model: string) => ParsedModelRef \| undefined` | Parses model ref. | | `parsePersistentSessionId` | `value` | `(storeSessionId: string) => PersistentSessionIdentity \| undefined` | Inverse of `persistentStoreSessionId`: decode a store session id back into `{ agent, instanceId, session }`, or `undefined` if it is not a persistent-instance key. Useful for admin surfaces that list raw session ids. | | `parseRetryAfterMs` | `value` | `(headerValue: string \| null \| undefined) => number \| undefined` | Parse a `Retry-After` header value (RFC 7231) into milliseconds. Accepts both delta-seconds and HTTP-date forms. Returns undefined when the value is missing or unparseable. | | `parseStreamOffset` | `value` | `(offset: string \| undefined) => number` | Parses stream offset. | | `PersistenceBundle` | `type` | `PersistenceBundle` | Complete persistence surface consumed by a Fabric host. | | `PersistenceDeleteResult` | `type` | `PersistenceDeleteResult` | Result returned by persistence delete. | | `PersistenceHealth` | `type` | `PersistenceHealth` | Type contract for persistence health. | | `PersistentAgentConfig` | `type` | `PersistentAgentConfig` | Runtime configuration returned by a `createAgent` initializer. Mirrors the agent-level slice of `AgentInit`; `instructions` becomes the session system prompt (a role), and `subagents` map to named roles. | | `PersistentAgentContext` | `type` | `PersistentAgentContext<TEnv>` | Per-interaction context passed to a `createAgent` initializer. `id` is the URL `<id>` of the addressed instance (or the dispatch target id); `env` is the platform environment supplied by the runtime. | | `PersistentAgentDurabilityConfig` | `type` | `PersistentAgentDurabilityConfig` | Static retry and wall-clock budget applied to every durable submission. | | `persistentAgentSubmissionDurability` | `value` | `(created: CreatedAgent, acceptedAt: number) => import("./submission-store.js").AgentSubmissionDurability \| undefined` | Resolve a static policy into the store's absolute durability stamp. | | `PersistentAgentTriggers` | `type` | `PersistentAgentTriggers` | Public triggers supported by persistent agents. Scheduling requires a concrete instance id and message, so cron belongs on a finite dispatcher job. | | `persistentConfigToAgentInit` | `value` | `(config: PersistentAgentConfig, id: string) => AgentInit` | Translate a `PersistentAgentConfig` into an `AgentInit`. | | `PersistentInstanceIdentity` | `type` | `PersistentInstanceIdentity` | Type contract for persistent instance identity. | | `persistentInstanceStoreId` | `value` | `(agentName: string, instanceId: string) => string` | Instance-scoped metadata key shared by every named session of one persistent agent. | | `PersistentSessionIdentity` | `type` | `PersistentSessionIdentity` | Decoded identity of a persistent instance session store key. | | `persistentStoreSessionId` | `value` | `(agentName: string, instanceId: string, sessionName?: string) => string` | Store-session key for a persistent instance's named session. Collapses the `(agentName, instanceId, sessionName)` identity onto Fabric's single-string `sessionId`, keeping persistent sessions inside the existing session stores. | | `PiAgentLoopRuntime` | `value` | `typeof PiAgentLoopRuntime` | Runtime API for pi agent loop runtime; the generated signature shows its accepted inputs and return type. | | `PiAgentLoopRuntimeOptions` | `type` | `PiAgentLoopRuntimeOptions` | Configuration options for pi agent loop runtime. | | `PiCustomModel` | `type` | `PiCustomModel` | Type contract for pi custom model. | | `PipelineVoiceProvider` | `value` | `typeof PipelineVoiceProvider` | Provider implementation for pipeline voice. | | `PipelineVoiceProviderOptions` | `type` | `PipelineVoiceProviderOptions` | Configuration options for pipeline voice provider. | | `policiedFetch` | `value` | `(fetchImpl: typeof fetch, policy?: CapabilityPolicy, options?: PoliciedFetchOptions) => typeof fetch` | Wrap a Fetch implementation with URL, protocol, host, redirect, and optional DNS-answer checks from a capability policy. This wrapper governs only calls made through the returned function; it does not intercept global Fetch, Axios, raw sockets, subprocesses, or third-party clients. Pair it with a container, cluster, or provider egress boundary for untrusted production workloads. | | `PoliciedFetchOptions` | `type` | `PoliciedFetchOptions` | Wrap a `fetch`-like function with `CapabilityPolicy` enforcement. Tools and connectors that make outbound HTTP should accept a custom `fetch` and pass the result of `policiedFetch(fetch, policy)`. Throws a `FabricError` (`POLICY_DENIED`) when a request violates the policy; never sends a forbidden request. | | `policiedSandboxEnv` | `value` | `(inner: SandboxEnv, policy: CapabilityPolicy \| undefined) => SandboxEnv` | Wrap a `SandboxEnv` with `CapabilityPolicy` enforcement at the sandbox layer. Without this decorator, agent code that calls `(await session.sandbox).exec(...)` directly bypasses the policy that `session.shell()` and tool dispatch enforce. `policiedSandboxEnv()` closes that gap by re-running the same policy evaluation against `exec` / `readFile` / `writeFile` / `mkdir` / `rm` / etc. Throws `FabricError`: - `COMMAND_DENIED` when an exec is denied or requires approval. - `POLICY_DENIED` when a filesystem op is denied or requires approval. The decorator does NOT auto-resolve `requireApproval` p... | | `PolicyDecision` | `type` | `PolicyDecision` | Type contract for policy decision. | | `projectConversationRecords` | `value` | `(records: readonly ConversationStreamRecord[]) => ConversationSnapshot` | Project canonical session records into a stable, UI-oriented protocol. | | `PromptOptions` | `type` | `PromptOptions<TResult>` | Configuration options for prompt. | | `PromptRunInput` | `type` | `PromptRunInput` | Type contract for prompt run input. | | `PromptRunResult` | `type` | `PromptRunResult` | Result returned by prompt run. | | `ProviderHttpError` | `value` | `typeof ProviderHttpError` | Error raised for provider http failures. | | `ProvidersConfig` | `type` | `ProvidersConfig` | Type contract for providers config. | | `ProviderSettings` | `type` | `ProviderSettings` | Type contract for provider settings. | | `pruneSnapshots` | `value` | `(snapshotRoot: string, options?: SnapshotPruneOptions) => Promise<SnapshotPruneResult>` | Runtime API for prune snapshots; the generated signature shows its accepted inputs and return type. | | `RateLimiter` | `type` | `RateLimiter` | Type contract for rate limiter. | | `RateLimiterAcquireOptions` | `type` | `RateLimiterAcquireOptions` | Process-local rate limiter for outbound provider calls. Use to prevent a fleet of agents from stampeding a single API key when the host runs many sessions in parallel. The default token-bucket implementation is in-memory; `@fabric-harness/node` exports `redisRateLimiter` for shared limits across processes. fabric-harness ships this as a generic primitive — the same limiter can be reused for outbound HTTP calls inside connectors, webhook fan-out, or anywhere else throttling is useful. | | `readConversationFromFold` | `value` | `(store: ConversationStreamStore, path: string, options?: { offset?: string; limit?: number; }) => Promise<ConversationStreamReadResult>` | Read a conversation from its newest validated fold checkpoint plus the log suffix. Non-origin offsets always use the raw store so resume semantics stay unchanged. Invalid checkpoints are disposable and fall back to full replay. | | `readConversationReply` | `value` | `(snapshot: ConversationSnapshot, submissionId: string) => ConversationReply` | Read the canonical assistant reply for a durable submission. Submission ids are used when available. The positional fallback supports conversations written by older Harness servers that predate submission correlation on individual entries. | | `ReaddirInput` | `type` | `ReaddirInput` | Type contract for readdir input. | | `readdirTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<ReaddirInput, string[]>` | Model-callable tool or tool factory for readdir. | | `ReadFileBufferInput` | `type` | `ReadFileBufferInput` | Type contract for read file buffer input. | | `readFileBufferTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<ReadFileBufferInput, Uint8Array>` | Model-callable tool or tool factory for read file buffer. | | `ReadFileInput` | `type` | `ReadFileInput` | Type contract for read file input. | | `readFileTool` | `value` | `(sandbox?: SandboxEnv, packagedSkills?: Record<string, PackagedSkillDirectory>) => ToolDef<ReadFileInput, string>` | Model-callable tool or tool factory for read file. | | `readJsonBody` | `value` | `(request: Request, limitBytes?: number) => Promise<RequestBody \| undefined>` | Reads the body once and returns the raw bytes, the decoded text, and the parsed JSON together — so a channel can HMAC-verify the exact bytes and use the JSON without re-reading the (already consumed) stream. Returns undefined only when the body exceeds `limitBytes`. | | `readRequestBody` | `value` | `(request: Request, limitBytes?: number) => Promise<Uint8Array \| undefined>` | Reads the full request body as bytes, or returns undefined if it exceeds `limitBytes`. NOTE: this consumes the request stream (single read). Signature-verifying channels need the *exact* bytes for HMAC and the parsed JSON afterward — don't call `request.json()` as well. Use `readJsonBody` to get both from one read. | | `redactError` | `value` | `(error: unknown, options?: RedactionOptions) => JsonObject` | Error raised for redact failures. | | `RedactionOptions` | `type` | `RedactionOptions` | Configuration options for redaction. | | `redactJson` | `value` | `<T>(value: T, options?: RedactionOptions) => T` | Runtime API for redact json; the generated signature shows its accepted inputs and return type. | | `redactText` | `value` | `(value: string, options?: RedactionOptions) => string` | Runtime API for redact text; the generated signature shows its accepted inputs and return type. | | `registerCreatedAgentName` | `value` | `(agent: CreatedAgent, name: string) => void` | Register a name for a `CreatedAgent` so `dispatch(agent, ...)` can resolve it. | | `registeredModelProviders` | `value` | `() => string[]` | Names of externally registered providers, for diagnostics. | | `registerJobName` | `value` | `<TInput, TOutput>(job: DefinedAgent<TInput, TOutput>, name: string) => void` | Registers job name. | | `registerModelPrices` | `value` | `(rows: ModelPriceRow[]) => void` | Add or override price rows. Later rows take precedence over earlier ones. | | `registerModelProvider` | `value` | `(name: string, factory: ModelProviderFactory) => void` | Register a model provider resolvable via `FABRIC_MODEL=<name>/<model-id>`. Built-in providers always take precedence; registering a name a built-in already owns has no effect on routing. Idempotent by name (last registration wins). Call at module import time. | | `registerSandbox` | `value` | `(env: SandboxEnv, options?: { ownerSessionId?: string; }) => SandboxRef` | Register a sandbox in the in-process registry and return a portable ref. Subsequent calls for the same env return the same ref. | | `registerSandboxBackendFactory` | `value` | `(backend: SandboxBackend, factory: SandboxFactory) => void` | Register an implementation for a non-core `SandboxBackend` name. Provider packages use this hook so the shared runtime can resolve backends such as `databricks` without depending on them. | | `registerSandboxRefDecoder` | `value` | `(provider: string, decoder: SandboxRefDecoder) => void` | Register a decoder for `provider` so `attachSandbox(serialized)` can rehydrate a sandbox from another process. Typically called once at startup by the package that owns the provider integration (e.g. `@fabric-harness/connectors/e2b` registers the `e2b` provider). | | `RemoteSandboxApi` | `type` | `RemoteSandboxApi` | Type contract for remote sandbox api. | | `RemoteSandboxOptions` | `type` | `RemoteSandboxOptions` | Configuration options for remote sandbox. | | `renderDeliveredMessage` | `value` | `(message: DeliveredMessage) => string` | Render a delivered message to the prompt text form. User messages pass their body through verbatim; signals render as their XML envelope via the shared `renderSignalMessage` machinery. | | `RequestBody` | `type` | `RequestBody` | Type contract for request body. | | `resetDispatchRuntime` | `value` | `() => void` | Clear the ambient dispatch runtime (tests/teardown). | | `resetJobInvocationRuntime` | `value` | `() => void` | Runtime API for reset job invocation runtime; the generated signature shows its accepted inputs and return type. | | `resetModelPricesToBuiltins` | `value` | `() => void` | Reset the registry to the built-in seed (test/utility). | | `ResolvedDynamicModelProvider` | `type` | `ResolvedDynamicModelProvider` | Provider and normalized model selected for a dynamically rendered model reference. | | `ResolvedModelProvider` | `type` | `ResolvedModelProvider` | Provider implementation for resolved model. | | `resolveModelProvider` | `value` | `(options?: ResolveModelProviderOptions) => ResolvedModelProvider` | Resolves model provider. | | `ResolveModelProviderOptions` | `type` | `ResolveModelProviderOptions` | Configuration options for resolve model provider. | | `resolveRuntimeMode` | `value` | `(options: Pick<AgentInit, "runtime" \| "store" \| "persistence">, env?: Record<string, string \| undefined>) => RuntimeModeResolution` | Resolve the effective runtime mode for an `init()` call, applying production safety rules: - In production (`FABRIC_ENV=production` or `NODE_ENV=production`), choosing `stateless` is allowed but logged as an explicit choice. - `inline` (the default) without an explicit `SessionStore` falls back to in-memory storage. In production this emits a warning unless `FABRIC_ALLOW_EPHEMERAL_STATE=1` is set or runtime is explicitly `'stateless'`. - Unknown runtime values fall through to `'inline'` with a warning. | | `RESULT_END_DELIMITER` | `value` | `"---RESULT_END---"` | Constant defining result end delimiter. | | `RESULT_START_DELIMITER` | `value` | `"---RESULT_START---"` | Constant defining result start delimiter. | | `ResultExtractionOptions` | `type` | `ResultExtractionOptions` | Configuration options for result extraction. | | `ResultOutcome` | `type` | `ResultOutcome<TResult>` | Type contract for result outcome. | | `ResultToolBundle` | `type` | `ResultToolBundle<TResult>` | Type contract for result tool bundle. | | `ResultUnavailableError` | `value` | `typeof ResultUnavailableError` | Thrown when the LLM calls the `give_up` tool, indicating it cannot produce a result that conforms to the required schema. | | `ResultValidator` | `type` | `ResultValidator<TResult>` | Type contract for result validator. | | `RetrievedChunk` | `type` | `RetrievedChunk` | Generic, provider-agnostic retrieval seam. RAG is query-time, so it does NOT fit `FilesystemSource` (an eager full-dump mount) — a retriever resolves the top matches for a query on demand. Databricks AI Search is the flagship implementation, but this is reusable for any vector store. | | `RetrieveOptions` | `type` | `RetrieveOptions` | Configuration options for retrieve. | | `Retriever` | `type` | `Retriever` | Type contract for retriever. | | `RmInput` | `type` | `RmInput` | Type contract for rm input. | | `rmTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<RmInput, void>` | Model-callable tool or tool factory for rm. | | `Role` | `type` | `Role` | Type contract for role. | | `runAction` | `value` | `<TInput, TOutput>(action: ActionDefinition<TInput, TOutput>, host: ActionHost, input?: unknown) => Promise<TOutput>` | Validate input, run the action against `host`, validate + JSON-clone the output. The returned value is always safely serializable (a fresh JSON clone), so callers can persist or transmit it without sharing references. | | `RuntimeModeResolution` | `type` | `RuntimeModeResolution` | Type contract for runtime mode resolution. | | `runWithJobInvocation` | `value` | `<T>(context: JobInvocationContext, fn: () => Promise<T> \| T) => Promise<T> \| T` | Runs with job invocation. | | `runWithSubmissionContext` | `value` | `<T>(context: SubmissionContext, fn: () => Promise<T> \| T) => Promise<T> \| T` | Run `fn` with `context` as the ambient submission correlation. | | `sameApprovalOperation` | `value` | `(grant: ApprovalGrant, input: { toolCallId: string; toolInput: unknown; principal: FabricPrincipal; }) => boolean` | Runtime API for same approval operation; the generated signature shows its accepted inputs and return type. | | `SandboxAdapterDescriptor` | `type` | `SandboxAdapterDescriptor` | Adapter expectations: - Every backend must expose the SandboxEnv contract above and map paths into a scoped workspace. - Secrets and provider credentials must stay in adapter-owned environment/config, not model context. - exec should enforce backend-specific command, network, and timeout policy before process launch. - snapshot/restore is optional because not all targets support filesystem or VM snapshots. - Future adapters should be added without changing session/runtime code. Planned backends: local, Docker, Azure Container Apps, Azure Container Instances, AKS, Databricks, E2B, Daytona, C... | | `SandboxBackend` | `type` | `SandboxBackend` | Type contract for sandbox backend. | | `SandboxCapabilities` | `type` | `SandboxCapabilities` | Type contract for sandbox capabilities. | | `SandboxEnv` | `type` | `SandboxEnv` | Type contract for sandbox env. | | `SandboxExecOptions` | `type` | `SandboxExecOptions` | Configuration options for sandbox exec. | | `SandboxFactory` | `type` | `SandboxFactory` | Factory for sandbox. | | `SandboxFactoryOptions` | `type` | `SandboxFactoryOptions` | Configuration options for sandbox factory. | | `SandboxFork` | `type` | `SandboxFork` | Type contract for sandbox fork. | | `SandboxOrphanSettlement` | `type` | `SandboxOrphanSettlement` | Type contract for sandbox orphan settlement. | | `SandboxRef` | `type` | `SandboxRef` | Type contract for sandbox ref. | | `SandboxRefDecoder` | `type` | `SandboxRefDecoder` | Decoder for a `SerializedSandboxRef.provider`. Returns a SandboxFactory that, when invoked, produces a SandboxEnv connected to the existing remote sandbox identified by `providerData`. Decoders SHOULD attach without owning the remote sandbox's lifecycle — the returned env's `cleanup()` should detach, not destroy. | | `SandboxSnapshot` | `type` | `SandboxSnapshot` | Type contract for sandbox snapshot. | | `sanitizeObservabilityData` | `value` | `(data: JsonObject, additionalSecrets?: string[]) => JsonObject` | Runtime API for sanitize observability data; the generated signature shows its accepted inputs and return type. | | `sanitizePublicJson` | `value` | `<T>(value: T) => T` | Runtime API for sanitize public json; the generated signature shows its accepted inputs and return type. | | `sanitizePublicText` | `value` | `(value: string) => string` | Remove credentials and host filesystem locations from caller-visible text. | | `schema` | `value` | `{ string(): Schema<string>; number(): Schema<number>; boolean(): Schema<boolean>; unknown(): Schema<unknown>; enum<const T extends readonly [string, ...string[]]>(values: T): Schema<T[number]>; array<T>(item: Schema<T>): Sch...` | Runtime API for schema; the generated signature shows its accepted inputs and return type. | | `Schema` | `type` | `Schema<T>` | Type contract for schema. | | `SchemaIssue` | `type` | `SchemaIssue` | Type contract for schema issue. | | `SchemaValidationError` | `value` | `typeof SchemaValidationError` | Error raised for schema validation failures. | | `SearchToolInput` | `type` | `SearchToolInput` | Type contract for search tool input. | | `SearchToolOptions` | `type` | `SearchToolOptions` | Configuration options for search tool. | | `SearchToolResult` | `type` | `SearchToolResult` | Result returned by search tool. | | `secret` | `value` | `(name: string) => SecretRef` | Runtime API for secret; the generated signature shows its accepted inputs and return type. | | `SecretProvider` | `type` | `SecretProvider` | Provider implementation for secret. | | `SecretRef` | `type` | `SecretRef` | Type contract for secret ref. | | `SecretResolutionContext` | `type` | `SecretResolutionContext` | Type contract for secret resolution context. | | `secretResolver` | `value` | `(provider: SecretProvider, context?: SecretResolutionContext) => (ref: SecretRef) => Promise<string \| undefined>` | Adapt a provider to the existing `init({ resolveSecret })` callback. | | `SerializedFabricError` | `type` | `SerializedFabricError` | Error raised for serialized fabric failures. | | `SerializedSandboxRef` | `type` | `SerializedSandboxRef` | Cross-process / cross-machine sandbox reference. Created by `session.sandboxRef({ portable: true })` and re-attached via `attachSandbox(serialized)` in a separate process. Each `provider` string maps to a decoder registered via `registerSandboxRefDecoder()`. | | `serializeFabricError` | `value` | `(error: unknown, audience?: "public" \| "developer", fallback?: Omit<FabricErrorOptions, "cause">) => SerializedFabricError` | Convert any thrown value into the stable public/developer transport shape. | | `serializeSandboxRef` | `value` | `(ref: SandboxRef, ownerSessionId?: string, tenantId?: string) => SerializedSandboxRef` | Serialize an in-process `SandboxRef` into the cross-process form. Requires the underlying sandbox to implement `encodeRef()`. Throws `SANDBOX_UNAVAILABLE` if the backend is in-process-only. | | `SessionData` | `type` | `SessionData` | Type contract for session data. | | `SessionEntry` | `type` | `SessionEntry<TData>` | Type contract for session entry. | | `SessionEntryType` | `type` | `SessionEntryType` | Type contract for session entry type. | | `SessionHistory` | `value` | `typeof SessionHistory` | Runtime API for session history; the generated signature shows its accepted inputs and return type. | | `SessionMemory` | `type` | `SessionMemory` | Type contract for session memory. | | `SessionMemoryEntry` | `type` | `SessionMemoryEntry<TValue>` | Persistent key/value store for facts an agent should remember across sessions — borrower preferences, prior outcomes, learned task history. Distinct from `SessionEntry` (which is the audit log): memory is for *recall*, entries are for *audit*. Memory writes do NOT land in the session log, so they don't pollute prompt context unless the agent explicitly reads them. Tenancy: every operation accepts an optional `tenantId`. Two tenants with the same `key` get isolated values. `tenantId` defaults to the empty string for non-tenant deployments. | | `SessionMemoryFilter` | `type` | `SessionMemoryFilter` | Type contract for session memory filter. | | `SessionMemoryGetOptions` | `type` | `SessionMemoryGetOptions` | Configuration options for session memory get. | | `SessionMemorySetInput` | `type` | `SessionMemorySetInput<TValue>` | Type contract for session memory set input. | | `SessionOptions` | `type` | `SessionOptions` | Configuration options for session. | | `SessionStore` | `type` | `SessionStore` | Storage contract for session. | | `setLogger` | `value` | `(logger: Logger) => void` | Replace the global SDK logger. Call once at startup before any `init()`. Pass a custom Logger to redirect to your structured logging system. | | `ShellOptions` | `type` | `ShellOptions` | Configuration options for shell. | | `shellQuote` | `value` | `(value: string) => string` | Runtime API for shell quote; the generated signature shows its accepted inputs and return type. | | `ShellResult` | `type` | `ShellResult` | Result returned by shell. | | `Skill` | `type` | `Skill` | Type contract for skill. | | `SkillOptions` | `type` | `SkillOptions<TResult>` | Configuration options for skill. | | `slackApprovalNotifier` | `value` | `(options: { webhookUrl: string; fetch?: typeof fetch; }) => ApprovalNotifier` | Slack incoming-webhook notifier. The webhook URL remains in host configuration, never event data. | | `SnapshotPruneOptions` | `type` | `SnapshotPruneOptions` | Configuration options for snapshot prune. | | `SnapshotPruneResult` | `type` | `SnapshotPruneResult` | Result returned by snapshot prune. | | `StateSetter` | `type` | `StateSetter<T>` | Type contract for state setter. | | `StatInput` | `type` | `StatInput` | Type contract for stat input. | | `statTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<StatInput, FileStat>` | Model-callable tool or tool factory for stat. | | `StdioMcpClient` | `value` | `typeof StdioMcpClient` | Client implementation for stdio mcp. | | `StdioMcpClientOptions` | `type` | `StdioMcpClientOptions` | Configuration options for stdio mcp client. | | `StoredAttachment` | `type` | `StoredAttachment` | Type contract for stored attachment. | | `StreamListenerRegistry` | `value` | `typeof StreamListenerRegistry` | Process-local listener registry shared by store implementations — registration, unsubscribe-and-prune, and error-swallowing notify. | | `SttEvent` | `type` | `SttEvent` | Type contract for stt event. | | `SttProvider` | `type` | `SttProvider` | Provider implementation for stt. | | `SttSession` | `type` | `SttSession` | Type contract for stt session. | | `SttSessionOptions` | `type` | `SttSessionOptions` | Configuration options for stt session. | | `SttSessionUsage` | `type` | `SttSessionUsage` | Type contract for stt session usage. | | `StubFabricAgent` | `value` | `typeof StubFabricAgent` | Runtime API for stub fabric agent; the generated signature shows its accepted inputs and return type. | | `StubFabricSession` | `value` | `typeof StubFabricSession` | Runtime API for stub fabric session; the generated signature shows its accepted inputs and return type. | | `SubagentDefinition` | `type` | `SubagentDefinition` | Type contract for subagent definition. | | `SubmissionAbortedError` | `value` | `typeof SubmissionAbortedError` | Error raised for submission aborted failures. | | `SubmissionAdmissionBackend` | `type` | `SubmissionAdmissionBackend<Row>` | Storage callbacks for `admitSubmissionWithBackend`. Every callback runs inside the transaction the caller has already opened (or the backend's equivalent atomicity scope). Callbacks may return plain values (synchronous backends) or native `Promise`s — non-native thenables are not supported. | | `SubmissionAdmissionRow` | `type` | `SubmissionAdmissionRow` | The minimal shape `admitSubmissionWithBackend` needs from a persisted submission row: the transport `kind` and persisted `payload` it compares against the incoming admission. `payload` may be the serialized JSON string or an already-deserialized object (e.g. a Postgres JSONB column). | | `SubmissionAttemptRef` | `type` | `SubmissionAttemptRef` | Type contract for submission attempt ref. | | `SubmissionClaimRef` | `type` | `SubmissionClaimRef` | Type contract for submission claim ref. | | `SubmissionContext` | `type` | `SubmissionContext` | Type contract for submission context. | | `SubmissionDurability` | `type` | `SubmissionDurability` | Type contract for submission durability. | | `SubmissionExecuteOptions` | `type` | `SubmissionExecuteOptions` | Configuration options for submission execute. | | `SubmissionExecutor` | `type` | `SubmissionExecutor` | How the runner touches sessions. `execute` applies the submission's input to the addressed instance session and resolves with the turn result; everything else is store-level and must not require a live agent. Contract requirements: - `execute` must be idempotent by submission id (a resumed attempt whose input entry already exists must not append it again). - `recordTerminal` settles the conversation to a deterministic rest state (unresolved trailing tool calls get explicit interrupted-outcome markers — NEVER re-executed) and appends a terminal advisory. - `appendSettlement` appends the cano... | | `SubmissionInsertRow` | `type` | `SubmissionInsertRow` | The queued row that `admitSubmissionWithBackend` writes on first admission. | | `SubmissionInspection` | `type` | `SubmissionInspection` | Coarse persisted-progress classification consumed by reconciliation. | | `SubmissionInterruptedError` | `value` | `typeof SubmissionInterruptedError` | Error raised for submission interrupted failures. | | `SubmissionInterruption` | `type` | `SubmissionInterruption` | Type contract for submission interruption. | | `SubmissionPayloadContext` | `type` | `SubmissionPayloadContext` | Context needed for submission payload validation. Implementations extract these fields from their storage-specific row/document type before calling `isSubmissionPayload`. | | `SubmissionRetryExhaustedError` | `value` | `typeof SubmissionRetryExhaustedError` | Error raised for submission retry exhausted failures. | | `SubmissionRunner` | `type` | `SubmissionRunner` | Type contract for submission runner. | | `SubmissionRunnerOptions` | `type` | `SubmissionRunnerOptions` | Configuration options for submission runner. | | `submissionSessionKey` | `value` | `(input: Pick<AgentSubmissionInput, "agent" \| "id" \| "session">) => string` | Store-session FIFO key of a submission (re-exported convenience). | | `SubmissionSettledRecord` | `type` | `SubmissionSettledRecord` | Minimal canonical settlement record for a direct submission. The conversation-stream phase reuses this shape as the durable terminal record a reconnecting waiter observes. | | `SubmissionSettlement` | `type` | `SubmissionSettlement` | Type contract for submission settlement. | | `submissionSettlementEntryId` | `value` | `(submissionId: string) => string` | Deterministic canonical settlement entry id for a submission. | | `SubmissionSettlementObligation` | `type` | `SubmissionSettlementObligation` | Type contract for submission settlement obligation. | | `submissionStoreSessionId` | `value` | `(input: Pick<AgentSubmissionInput, "agent" \| "id" \| "session">) => string` | The harness identity string (`agent:<name>:<id>:<session>`) targeted by a submission input. This is the `persistentStoreSessionId` of the addressed instance session and the per-session FIFO key of the store. | | `SubmissionTelemetryEvent` | `type` | `SubmissionTelemetryEvent` | Type contract for submission telemetry event. | | `SubmissionTelemetrySink` | `type` | `SubmissionTelemetrySink` | Type contract for submission telemetry sink. | | `SubmissionTimeoutError` | `value` | `typeof SubmissionTimeoutError` | Error raised for submission timeout failures. | | `SuspendingSandboxEnv` | `value` | `typeof SuspendingSandboxEnv` | Decorator that adds idle-based auto-suspend to any `SandboxEnv` whose underlying implementation supports `suspend()` / `resume()`. If the inner env doesn't implement them, the decorator is a no-op pass-through (the idle timer never fires anything). The decorator tracks a `lastAccessAt` timestamp on every operation. After `idleSuspendMs` elapses without activity, it calls `inner.suspend()`. The next operation transparently calls `inner.resume()` first (unless `autoResumeOnAccess: false`). `cleanup()` cancels the idle timer. | | `SuspendingSandboxOptions` | `type` | `SuspendingSandboxOptions` | Configuration options for suspending sandbox. | | `TaskOptions` | `type` | `TaskOptions<TResult>` | Configuration options for task. | | `TelemetryExporter` | `type` | `TelemetryExporter` | Type contract for telemetry exporter. | | `TelemetrySpan` | `type` | `TelemetrySpan` | Type contract for telemetry span. | | `tenantCostLimit` | `value` | `(tenantId: string, options: TenantCostLimit) => CostLimit` | Sugar over `CostLimit.perScope + scopeKey + store` for the common "per-tenant ceiling per period" pattern. Pick one of `perDayUsd`, `perHourUsd`, or `perMonthUsd`; when multiple are set, the most restrictive (smallest absolute) wins. Scope key convention: `tenant:<id>:<period>` where `<period>` is `day:YYYY-MM-DD`, `hour:YYYY-MM-DDTHH:00Z`, or `month:YYYY-MM`. Reset semantics (rollover) are the host's job — call `store.reset(scopeKey)` from a scheduled task to clear the period total. See the package declarations for an example. | | `TenantCostLimit` | `type` | `TenantCostLimit` | Type contract for tenant cost limit. | | `toFabricError` | `value` | `(error: unknown, fallback: Omit<FabricErrorOptions, "cause">) => FabricError` | Error raised for to fabric failures. | | `tokenBucketRateLimiter` | `value` | `(options: TokenBucketRateLimiterOptions) => RateLimiter` | In-memory token-bucket rate limiter. Each key has its own bucket — keys are independent (waiting on one key doesn't block another). Buckets refill continuously at `tokensPerSecond`. | | `TokenBucketRateLimiterOptions` | `type` | `TokenBucketRateLimiterOptions` | Configuration options for token bucket rate limiter. | | `ToolCall` | `type` | `ToolCall<TInput>` | Type contract for tool call. | | `ToolCallResult` | `type` | `ToolCallResult<TOutput>` | Result returned by tool call. | | `ToolContext` | `type` | `ToolContext` | Type contract for tool context. | | `ToolDef` | `type` | `ToolDef<TInput, TOutput>` | Type contract for tool def. | | `ToolEffect` | `type` | `ToolEffect` | Type contract for tool effect. | | `ToolHarness` | `type` | `ToolHarness` | Type contract for tool harness. | | `ToolPolicy` | `type` | `ToolPolicy` | Type contract for tool policy. | | `ToolProgressLogger` | `type` | `ToolProgressLogger` | Type contract for tool progress logger. | | `ToolStep` | `type` | `ToolStep` | Type contract for tool step. | | `toolsToModelSchemas` | `value` | `(tools: Iterable<ToolDef>) => ModelToolSchema[]` | Runtime API for tools to model schemas; the generated signature shows its accepted inputs and return type. | | `toOpenAIMessage` | `value` | `(message: ModelMessage) => Record<string, unknown>` | Runtime API for to open aimessage; the generated signature shows its accepted inputs and return type. | | `toOpenAITool` | `value` | `(tool: ModelToolSchema) => Record<string, unknown>` | Model-callable tool or tool factory for to open ai. | | `TtsProvider` | `type` | `TtsProvider` | Provider implementation for tts. | | `TtsSynthesisOptions` | `type` | `TtsSynthesisOptions` | Configuration options for tts synthesis. | | `TtsSynthesisUsage` | `type` | `TtsSynthesisUsage` | Type contract for tts synthesis usage. | | `TurnJournalState` | `type` | `TurnJournalState` | Type contract for turn journal state. | | `UnimplementedSandboxEnv` | `value` | `typeof UnimplementedSandboxEnv` | Runtime API for unimplemented sandbox env; the generated signature shows its accepted inputs and return type. | | `unregisterSandbox` | `value` | `(refId: string) => void` | Mark a registered sandbox as dead so future attach attempts fail. Called from the owner session's cleanup path. | | `unregisterSandboxBackendFactory` | `value` | `(backend: SandboxBackend) => void` | Remove a provider-owned backend factory, primarily for tests and controlled shutdown. | | `unregisterSandboxRefDecoder` | `value` | `(provider: string) => void` | Test/internal: remove a decoder. | | `useAgentFinish` | `value` | `(run: (context: DynamicAgentFinishContext) => void \| Promise<void>) => void` | Runtime API for use agent finish; the generated signature shows its accepted inputs and return type. | | `useAgentStart` | `value` | `(run: (context: DynamicAgentStartContext) => void \| Promise<void>) => void` | Runtime API for use agent start; the generated signature shows its accepted inputs and return type. | | `useDataWriter` | `value` | `<T>(name: string, options?: { schema?: Schema<T>; }) => (data: T) => void` | Writer implementation for use data. | | `useDelivery` | `value` | `() => DeliveredMessage` | Runtime API for use delivery; the generated signature shows its accepted inputs and return type. | | `useDispatchMessage` | `value` | `() => (message: DeliveredMessage \| string) => Promise<import("./dispatch.js").DispatchReceipt>` | Runtime API for use dispatch message; the generated signature shows its accepted inputs and return type. | | `useInitialData` | `value` | `<T = unknown>() => T` | Runtime API for use initial data; the generated signature shows its accepted inputs and return type. | | `useInstruction` | `value` | `(text: string) => void` | Runtime API for use instruction; the generated signature shows its accepted inputs and return type. | | `useMcpConnection` | `value` | `(definition: McpConnectionDefinition) => void` | Runtime API for use mcp connection; the generated signature shows its accepted inputs and return type. | | `useModel` | `value` | `(model: NonNullable<AgentInit["model"]>, options?: UseModelOptions) => void` | Runtime API for use model; the generated signature shows its accepted inputs and return type. | | `UseModelOptions` | `type` | `UseModelOptions` | Configuration options for use model. | | `usePersistentState` | `value` | `<T>(name: string, defaultValue: T, options?: { schema?: Schema<T>; }) => [T, StateSetter<T>]` | Runtime API for use persistent state; the generated signature shows its accepted inputs and return type. | | `useResponseFinish` | `value` | `(run: DynamicMetadataCallback) => void` | Runtime API for use response finish; the generated signature shows its accepted inputs and return type. | | `useResponseStart` | `value` | `(run: DynamicMetadataCallback) => void` | Runtime API for use response start; the generated signature shows its accepted inputs and return type. | | `useSandbox` | `value` | `(sandbox: SandboxBackend \| SandboxFactory \| SandboxEnv, options?: UseSandboxOptions) => void` | Sandbox adapter for use. | | `UseSandboxOptions` | `type` | `UseSandboxOptions` | Configuration options for use sandbox. | | `useSkill` | `value` | `(skill: Skill) => void` | Runtime API for use skill; the generated signature shows its accepted inputs and return type. | | `useSubagent` | `value` | `(definition: SubagentDefinition) => void` | Runtime API for use subagent; the generated signature shows its accepted inputs and return type. | | `useTool` | `value` | `<TInput = unknown, TOutput = unknown, THarness extends boolean = false, TDurable extends boolean = false>(tool: ToolDef<TInput, TOutput> \| HookToolDefinition<TInput, TOutput, THarness, TDurable>) => void` | Model-callable tool or tool factory for use. | | `validatePersistentAgentDurability` | `value` | `(durability: PersistentAgentDurabilityConfig) => PersistentAgentDurabilityConfig` | Validate and normalize a persistent agent's static submission policy. | | `validatePersistentInitialData` | `value` | `(created: CreatedAgent, initialData: unknown) => JsonValue` | Validate and normalize creation data before an instance generation is admitted. | | `validatePersistentInstanceContact` | `value` | `(uid: string \| null \| undefined, initialData: unknown) => void` | Reject contradictory existing-incarnation and instance-creation inputs. | | `validateResult` | `value` | `<TResult>(value: unknown, validator?: ResultValidator<TResult>, extraction?: boolean \| ResultExtractionOptions) => Promise<TResult>` | Result returned by validate. | | `VERCEL_AI_GATEWAY_BASE_URL` | `value` | `"https://ai-gateway.vercel.sh/v1"` | Default base URL for Vercel AI Gateway's OpenAI-compatible Chat Completions endpoint. The gateway accepts the standard OpenAI request body and routes through to the configured provider; switching from OpenAI to the gateway is just a base-URL change. See https://vercel.com/docs/ai-gateway/sdks-and-apis/openai-compat | | `vercelAIGateway` | `value` | `(options: VercelAIGatewayProviderOptions) => OpenAICompatibleModelProvider` | Vercel AI Gateway model provider. The gateway is an OpenAI-compatible HTTP endpoint that brokers between your agent and any of the major model providers (OpenAI, Anthropic, Google, xAI, Groq, etc.) with a single key, observability, caching, and spend controls. Use this provider on any deploy target — Node, Cloudflare Workers, Vercel — to route inference through the gateway. See the package declarations for an example. Returns an `OpenAICompatibleModelProvider` configured for the gateway — use it anywhere a `ModelProvider` is accepted. Compatible with fabric-harness's tool-calling, retries,... | | `VercelAIGatewayProviderOptions` | `type` | `VercelAIGatewayProviderOptions` | Configuration options for vercel aigateway provider. | | `verifyAttachmentBytes` | `value` | `(ref: AttachmentRef, bytes: Uint8Array) => Promise<void>` | Verify that `bytes` match the ref's digest (and declared size), throwing `AttachmentStoreError('DIGEST_MISMATCH')` otherwise. Every store's `put` MUST run this check before persisting. | | `verifyHmacSha256` | `value` | `(secret: string \| Uint8Array, message: Uint8Array, signature: Uint8Array) => Promise<boolean>` | Constant-time HMAC-SHA256 verification (via `crypto.subtle.verify`). | | `VertexAIModelProvider` | `value` | `typeof VertexAIModelProvider` | Provider implementation for vertex aimodel. | | `VertexAIProviderOptions` | `type` | `VertexAIProviderOptions` | Configuration options for vertex aiprovider. | | `VirtualSandboxEnv` | `value` | `typeof VirtualSandboxEnv` | Virtual sandbox backend powered by [just-bash](https://github.com/vercel-labs/just-bash). Provides an in-memory filesystem and a bash subset (`grep`, `glob`, `cat`, `read`, `mkdir`, `rm`, `ls`, `echo`, etc.) without shelling out to the host. The backend is fast, cheap, safe, and high-concurrency. Selected automatically by the bare `@fabric-harness/sdk` import when the caller doesn't pass `sandbox`. Override with `'local'`, `'docker'`, a `SandboxFactory`, or a `SandboxEnv` when you need real shell access. | | `VoiceAudioFormat` | `type` | `VoiceAudioFormat` | Bidirectional voice / audio streaming surface. fabric-harness ships an OpenAI Realtime implementation; bring-your-own-vendor for Anthropic / Gemini Live / on-prem TTS+ASR pipelines. Audio frames flow in raw bytes — the standard format is PCM 16-bit little-endian at 24kHz mono (OpenAI Realtime default). Telephony bridges (Twilio Media Streams μ-law 8kHz, etc.) resample at the edge. Tool execution is the *caller's* responsibility: a `tool_call` event surfaces, the host code runs the tool through whatever governance gates apply (approvals, cost caps, rate limits), then calls `submitToolResult(... | | `VoiceConnectOptions` | `type` | `VoiceConnectOptions` | Configuration options for voice connect. | | `VoiceEvent` | `type` | `VoiceEvent` | Events streamed from a `VoiceSession`. `audio_delta` carries raw audio bytes; `text_delta` and `transcript` carry text; `tool_call` and `response_done` mark structured boundaries; `error` is fatal. | | `VoiceProvider` | `type` | `VoiceProvider` | Provider implementation for voice. | | `VoiceSession` | `type` | `VoiceSession` | Type contract for voice session. | | `VoiceToolResultInput` | `type` | `VoiceToolResultInput` | Type contract for voice tool result input. | | `VoiceWsClientEvent` | `type` | `VoiceWsClientEvent` | Type contract for voice ws client event. | | `VoiceWsClientHandle` | `type` | `VoiceWsClientHandle` | Type contract for voice ws client handle. | | `VoiceWsClientOptions` | `type` | `VoiceWsClientOptions` | Lightweight WebSocket client for the Node server's `WS /sessions/:id/voice` endpoint. Server-side bridge owns the provider connection and API keys; this client just streams audio + control messages over WS. Works in browsers and on Node 22+ (uses the global `WebSocket`). | | `webhookApprovalNotifier` | `value` | `(options: { url: string; headers?: Record<string, string>; fetch?: typeof fetch; }) => ApprovalNotifier` | Runtime API for webhook approval notifier; the generated signature shows its accepted inputs and return type. | | `WebhookSubscriptionContext` | `type` | `WebhookSubscriptionContext<TPayload>` | Generic webhook subscription primitive — wakes an agent on inbound events from any external system (event bus, queue, scheduler, third-party SaaS webhook, your own application's domain events). fabric-harness consumes a JSON payload and dispatches to the user-provided handler. The host event system decides which payloads land here; fabric-harness has no opinion on event taxonomy or producer. | | `WebhookSubscriptionDefinition` | `type` | `WebhookSubscriptionDefinition<TPayload>` | Type contract for webhook subscription definition. | | `withConversationProjection` | `value` | `(store: SessionStore, streams: ConversationStreamStore, options?: { producerId?: string; onError?: (error: unknown) => void; }) => SessionStore` | Wrap a `SessionStore` so active-path appends are mirrored into an append-only `ConversationStreamStore` projection (v2 A4). The SessionEntry DAG stays the single source of truth; the stream gives clients offset-based catch-up + live tail. Two rules keep them coherent: 1. **Idempotent by entryId** — a crash between the DAG write and the stream write is repaired on the next append: the projector diffs the stream tail against the active path and re-emits anything missing. 2. **Truncation is explicit** — the DAG can branch (fork/replay/ checkpoint-restore rewrite `leafId`); the stream cannot. W... | | `withFilesystemSources` | `value` | `(base: SandboxBackend \| SandboxFactory \| SandboxEnv, sources: MountedSource[]) => SandboxFactory` | Runtime API for with filesystem sources; the generated signature shows its accepted inputs and return type. | | `withIdleSuspend` | `value` | `(inner: SandboxEnv, options: SuspendingSandboxOptions \| undefined) => SandboxEnv` | Wrap any `SandboxEnv` with idle-based auto-suspend. Returns the inner env unchanged when `idleSuspendMs` is undefined or the inner env doesn't implement `suspend()`. | | `WriteFileInput` | `type` | `WriteFileInput` | Type contract for write file input. | | `writeFileTool` | `value` | `(sandbox?: SandboxEnv) => ToolDef<WriteFileInput, void>` | Model-callable tool or tool factory for write file. | | `WsClientCommand` | `type` | `WsClientCommand` | Type contract for ws client command. | | `WsClientHandle` | `type` | `WsClientHandle` | Type contract for ws client handle. | | `WsClientOptions` | `type` | `WsClientOptions` | Lightweight WebSocket client for the Node server's `WS /sessions/:id/ws` endpoint. Works in browsers and on Node 22+ (uses the global `WebSocket`). Does NOT depend on the `ws` package — that's the server side's optional peer dep. | ### `@fabric-harness/sdk/cloudflare` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `CloudflareR2BucketLike` | `type` | `CloudflareR2BucketLike` | Type contract for cloudflare r2 bucket like. | | `CloudflareR2ListResultLike` | `type` | `CloudflareR2ListResultLike` | Type contract for cloudflare r2 list result like. | | `CloudflareR2ObjectBodyLike` | `type` | `CloudflareR2ObjectBodyLike` | Type contract for cloudflare r2 object body like. | | `r2FilesystemSource` | `value` | `(bucket: CloudflareR2BucketLike, options?: R2FilesystemSourceOptions) => FilesystemSource` | Read Cloudflare R2 objects as a Fabric filesystem source. Mount it with `withFilesystemSources()` (or `getVirtualSandbox(...)`) so agents can grep/read R2-backed knowledge bases through the normal sandbox tools. See the package declarations for an example. | | `R2FilesystemSourceOptions` | `type` | `R2FilesystemSourceOptions` | Configuration options for r2 filesystem source. | ### `@fabric-harness/sdk/channel` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `bytesToHex` | `value` | `(bytes: Uint8Array) => string` | Runtime API for bytes to hex; the generated signature shows its accepted inputs and return type. | | `Channel` | `type` | `Channel` | Type contract for channel. | | `ChannelContext` | `type` | `ChannelContext` | Type contract for channel context. | | `ChannelDispatch` | `type` | `ChannelDispatch` | Type contract for channel dispatch. | | `ChannelDispatchRequest` | `type` | `ChannelDispatchRequest` | Input contract for channel dispatch. | | `ChannelRoute` | `type` | `ChannelRoute` | Channels turn platform webhooks (Slack, GitHub, …) into agent dispatches. Handlers are written against the Web `Request`/`Response` API and `crypto.subtle`, so the same channel runs on Node and Cloudflare. A channel is a stateless route container plus a conversation-id (de)serializer — session continuity falls out of the key (same thread → same key → same session). | | `conversationKey` | `value` | `(provider: string, version: string, ...segments: string[]) => string` | Runtime API for conversation key; the generated signature shows its accepted inputs and return type. | | `defineChannel` | `value` | `(channel: Channel) => Channel` | Validates and brands a channel's routes. | | `defineTool` | `value` | `<TInput = unknown, TOutput = unknown>(tool: ToolDef<TInput, TOutput>) => ToolDef<TInput, TOutput>` | Edge-safe identity helper equivalent to the root SDK's `defineTool`. | | `hexToBytes` | `value` | `(hex: string) => Uint8Array` | Runtime API for hex to bytes; the generated signature shows its accepted inputs and return type. | | `hmacSha256` | `value` | `(secret: string \| Uint8Array, message: Uint8Array) => Promise<Uint8Array>` | Runtime API for hmac sha256; the generated signature shows its accepted inputs and return type. | | `parseConversationKey` | `value` | `(key: string) => ParsedConversationKey` | Parses conversation key. | | `ParsedConversationKey` | `type` | `ParsedConversationKey` | Type contract for parsed conversation key. | | `readJsonBody` | `value` | `(request: Request, limitBytes?: number) => Promise<RequestBody \| undefined>` | Reads the body once and returns the raw bytes, the decoded text, and the parsed JSON together — so a channel can HMAC-verify the exact bytes and use the JSON without re-reading the (already consumed) stream. Returns undefined only when the body exceeds `limitBytes`. | | `readRequestBody` | `value` | `(request: Request, limitBytes?: number) => Promise<Uint8Array \| undefined>` | Reads the full request body as bytes, or returns undefined if it exceeds `limitBytes`. NOTE: this consumes the request stream (single read). Signature-verifying channels need the *exact* bytes for HMAC and the parsed JSON afterward — don't call `request.json()` as well. Use `readJsonBody` to get both from one read. | | `RequestBody` | `type` | `RequestBody` | Type contract for request body. | | `ToolDef` | `type` | `ToolDef<TInput, TOutput>` | Type contract for tool def. | | `ToolEffect` | `type` | `ToolEffect` | Type contract for tool effect. | | `verifyHmacSha256` | `value` | `(secret: string \| Uint8Array, message: Uint8Array, signature: Uint8Array) => Promise<boolean>` | Constant-time HMAC-SHA256 verification (via `crypto.subtle.verify`). | ### `@fabric-harness/sdk/conversation` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `ConversationMessage` | `type` | `ConversationMessage` | Type contract for conversation message. | | `ConversationMessageDisplay` | `type` | `ConversationMessageDisplay` | Type contract for conversation message display. | | `ConversationMessagePurpose` | `type` | `ConversationMessagePurpose` | Type contract for conversation message purpose. | | `ConversationMessageRole` | `type` | `ConversationMessageRole` | Type contract for conversation message role. | | `ConversationPart` | `type` | `ConversationPart` | Type contract for conversation part. | | `ConversationReply` | `type` | `ConversationReply` | Type contract for conversation reply. | | `ConversationSettlement` | `type` | `ConversationSettlement` | Type contract for conversation settlement. | | `ConversationSnapshot` | `type` | `ConversationSnapshot` | Type contract for conversation snapshot. | | `projectConversationRecords` | `value` | `(records: readonly ConversationStreamRecord[]) => ConversationSnapshot` | Project canonical session records into a stable, UI-oriented protocol. | | `readConversationReply` | `value` | `(snapshot: ConversationSnapshot, submissionId: string) => ConversationReply` | Read the canonical assistant reply for a durable submission. Submission ids are used when available. The positional fallback supports conversations written by older Harness servers that predate submission correlation on individual entries. | ### `@fabric-harness/sdk/experimental` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createPiAgentLoopRuntime` | `value` | `(options?: PiAgentLoopRuntimeOptions) => PiAgentLoopRuntime` | Creates pi agent loop runtime. | | `PiAgentLoopRuntime` | `value` | `typeof PiAgentLoopRuntime` | Runtime API for pi agent loop runtime; the generated signature shows its accepted inputs and return type. | | `PiAgentLoopRuntimeOptions` | `type` | `PiAgentLoopRuntimeOptions` | Configuration options for pi agent loop runtime. | | `PiCustomModel` | `type` | `PiCustomModel` | Type contract for pi custom model. | | `policiedSandboxEnv` | `value` | `(inner: SandboxEnv, policy: CapabilityPolicy \| undefined) => SandboxEnv` | Wrap a `SandboxEnv` with `CapabilityPolicy` enforcement at the sandbox layer. Without this decorator, agent code that calls `(await session.sandbox).exec(...)` directly bypasses the policy that `session.shell()` and tool dispatch enforce. `policiedSandboxEnv()` closes that gap by re-running the same policy evaluation against `exec` / `readFile` / `writeFile` / `mkdir` / `rm` / etc. Throws `FabricError`: - `COMMAND_DENIED` when an exec is denied or requires approval. - `POLICY_DENIED` when a filesystem op is denied or requires approval. The decorator does NOT auto-resolve `requireApproval` p... | | `SuspendingSandboxEnv` | `value` | `typeof SuspendingSandboxEnv` | Decorator that adds idle-based auto-suspend to any `SandboxEnv` whose underlying implementation supports `suspend()` / `resume()`. If the inner env doesn't implement them, the decorator is a no-op pass-through (the idle timer never fires anything). The decorator tracks a `lastAccessAt` timestamp on every operation. After `idleSuspendMs` elapses without activity, it calls `inner.suspend()`. The next operation transparently calls `inner.resume()` first (unless `autoResumeOnAccess: false`). `cleanup()` cancels the idle timer. | | `SuspendingSandboxOptions` | `type` | `SuspendingSandboxOptions` | Configuration options for suspending sandbox. | | `withIdleSuspend` | `value` | `(inner: SandboxEnv, options: SuspendingSandboxOptions \| undefined) => SandboxEnv` | Wrap any `SandboxEnv` with idle-based auto-suspend. Returns the inner env unchanged when `idleSuspendMs` is undefined or the inner env doesn't implement `suspend()`. | ### `@fabric-harness/sdk/otel-observer` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `createOpenTelemetryObserver` | `value` | `(options?: OpenTelemetryObserverOptions) => FabricEventCallback` | Creates open telemetry observer. | | `OpenTelemetryObserverOptions` | `type` | `OpenTelemetryObserverOptions` | Build a hierarchical OpenTelemetry trace from Fabric's event stream. Unlike `openTelemetryExporter` (which emits one flat span per duration-bearing event), this observer nests spans into a tree: `prompt`/`skill` operations contain `turn`s, which contain `tool` / `shell` spans, with `task` sub-work nested under the active operation. The result is a single parent trace per operation that visualizes the full agent run. This module lives on the `@fabric-harness/sdk/otel-observer` subpath (not the main entry) because building parent contexts requires `@opentelemetry/api` at runtime; the main SDK... | ### `@fabric-harness/sdk/testing` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `MockModelProvider` | `value` | `typeof MockModelProvider` | Provider implementation for mock model. | | `MockModelProviderOptions` | `type` | `MockModelProviderOptions` | Configuration options for mock model provider. | | `MockScriptEntry` | `type` | `MockScriptEntry` | Type contract for mock script entry. | | `MockScriptMatch` | `type` | `MockScriptMatch` | Match criteria for a scripted mock entry. Every specified field must match. | | `MockScriptResponse` | `type` | `MockScriptResponse` | Response contract for mock script. | | `MockScriptToolCall` | `type` | `MockScriptToolCall` | Type contract for mock script tool call. | | `parseMockScript` | `value` | `(json: string) => MockScriptEntry[]` | Parse and validate a scripted-mock fixture file (JSON text). Accepts a bare array of entries or an aimock-style `{ "fixtures": [...] }` wrapper. Throws with an entry index when the shape is invalid. | | `StubFabricAgent` | `value` | `typeof StubFabricAgent` | Runtime API for stub fabric agent; the generated signature shows its accepted inputs and return type. | | `StubFabricSession` | `value` | `typeof StubFabricSession` | Runtime API for stub fabric session; the generated signature shows its accepted inputs and return type. | ### `@fabric-harness/sdk/testing/contracts` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `AttachmentStoreContractHandle` | `type` | `AttachmentStoreContractHandle` | Type contract for attachment store contract handle. | | `ChannelContractDispatch` | `type` | `ChannelContractDispatch` | Type contract for channel contract dispatch. | | `ChannelContractFixture` | `type` | `ChannelContractFixture` | Type contract for channel contract fixture. | | `ChannelContractRequest` | `type` | `ChannelContractRequest` | Input contract for channel contract. | | `ConversationStreamStoreContractHandle` | `type` | `ConversationStreamStoreContractHandle` | Type contract for conversation stream store contract handle. | | `defineAttachmentStoreContractTests` | `value` | `(name: string, factory: () => Promise<AttachmentStoreContractHandle>) => void` | Register the standard `AttachmentStore` contract tests under the given describe label. Each test gets a fresh store from `factory()`. | | `defineChannelContractTests` | `value` | `(fixture: ChannelContractFixture) => void` | Shared behavioral contract for first-party and community channel adapters. | | `defineConversationStreamStoreContractTests` | `value` | `(name: string, factory: () => Promise<ConversationStreamStoreContractHandle>) => void` | Register the standard `ConversationStreamStore` contract tests under the given describe label. Each test gets a fresh store from `factory()`. | | `definePersistenceBundleContractTests` | `value` | `(name: string, factory: () => Promise<PersistenceBundleContractHandle>) => void` | Compose all store contracts with bundle health, cost, run, and cascade checks. | | `defineSubmissionStoreContractTests` | `value` | `(name: string, factory: () => Promise<SubmissionStoreContractHandle>) => void` | Register the standard `AgentSubmissionStore` contract tests under the given describe label. Each test gets a fresh store from `factory()`. | | `PersistenceBundleContractHandle` | `type` | `PersistenceBundleContractHandle` | Type contract for persistence bundle contract handle. | | `SubmissionStoreContractHandle` | `type` | `SubmissionStoreContractHandle` | Type contract for submission store contract handle. | ### `@fabric-harness/sdk/markdown` Ambient module declarations. Reference once per project with `/// `; it exports no symbols. | Declared module | Kind | Default export | Purpose | | --- | --- | --- | --- | | `*/SKILL.md` | `ambient` | `import("@fabric-harness/sdk").Skill` | An import resolving to a file named SKILL.md compiles the whole skill directory: the Markdown body becomes the instructional prompt, the frontmatter becomes metadata, and every sibling file is packaged as a resource the model can read on demand. | | `*.md` | `ambient` | `string` | Every other bare Markdown import loads as a text module. Compose it with defineSkill() when the file is not a SKILL.md, or use it as prompt text. | ## @fabric-harness/temporal ### `@fabric-harness/temporal` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `ActivityIdempotency` | `type` | `ActivityIdempotency` | Type contract for activity idempotency. | | `ActivityTimeoutPolicy` | `type` | `ActivityTimeoutPolicy` | Type contract for activity timeout policy. | | `adaptSessionRuntime` | `value` | `(runtime: SessionRuntime, capabilities?: { dynamicAgents?: boolean; }) => DurableSessionRuntime` | Adapt any `SessionRuntime` (Temporal-backed, Mock, or otherwise) into the SDK's `DurableSessionRuntime` shape. The two interfaces are structurally identical, but the type bridging keeps SDK types out of the temporal package's public API. | | `AppendSessionEntryActivityInput` | `type` | `AppendSessionEntryActivityInput` | Type contract for append session entry activity input. | | `AppendSessionEntryActivityResult` | `type` | `AppendSessionEntryActivityResult` | Result returned by append session entry activity. | | `AppendSessionEventActivityInput` | `type` | `AppendSessionEventActivityInput` | Type contract for append session event activity input. | | `APPROVAL_SIGNAL` | `value` | `"approval"` | Constant defining approval signal. | | `approvalSignal` | `value` | `SignalDefinition<[ApprovalSignal], string>` | Runtime API for approval signal; the generated signature shows its accepted inputs and return type. | | `ApprovalSignal` | `type` | `ApprovalSignal` | Type contract for approval signal. | | `BuildContextActivityInput` | `type` | `BuildContextActivityInput` | Type contract for build context activity input. | | `BuildContextActivityResult` | `type` | `BuildContextActivityResult` | Result returned by build context activity. | | `CHECKPOINT_CREATE_WORKFLOW_NAME` | `value` | `"checkpointCreateWorkflow"` | Constant defining checkpoint create workflow name. | | `CHECKPOINT_RESTORE_WORKFLOW_NAME` | `value` | `"checkpointRestoreWorkflow"` | Constant defining checkpoint restore workflow name. | | `CheckpointActivityInput` | `type` | `CheckpointActivityInput` | Type contract for checkpoint activity input. | | `CheckpointActivityResult` | `type` | `CheckpointActivityResult` | Result returned by checkpoint activity. | | `checkpointCreateWorkflow` | `value` | `(input: SessionRuntimeCheckpointCreateInput & { sessionId: string; idempotency: { idempotencyKey: string; }; }) => Promise<import("@fabric-harness/sdk").CheckpointResult>` | Runtime API for checkpoint create workflow; the generated signature shows its accepted inputs and return type. | | `checkpointRestoreWorkflow` | `value` | `(input: SessionRuntimeCheckpointRestoreInput & { sessionId: string; idempotency: { idempotencyKey: string; }; }) => Promise<import("@fabric-harness/sdk").CheckpointResult>` | Runtime API for checkpoint restore workflow; the generated signature shows its accepted inputs and return type. | | `CompactSessionActivityInput` | `type` | `CompactSessionActivityInput` | Type contract for compact session activity input. | | `CompactSessionActivityResult` | `type` | `CompactSessionActivityResult` | Result returned by compact session activity. | | `connectTemporalWithRetry` | `value` | `<T>(connect: () => Promise<T>, options?: TemporalConnectRetryOptions) => Promise<T>` | Runtime API for connect temporal with retry; the generated signature shows its accepted inputs and return type. | | `createInlineSessionRuntime` | `value` | `(session: FabricSession) => SessionRuntime` | Creates inline session runtime. | | `createLocalTemporalActivities` | `value` | `(options: LocalTemporalActivitiesOptions) => TemporalActivities` | Creates local temporal activities. | | `createMockTemporalRuntime` | `value` | `(options?: MockTemporalRuntimeOptions) => MockTemporalRuntime` | Creates mock temporal runtime. | | `createTemporalClient` | `value` | `(options?: TemporalClientOptions) => Promise<TemporalClientHandle>` | Creates temporal client. | | `createTemporalClientConnectionOptions` | `value` | `(config?: TemporalConnectionConfig) => ConnectionOptions` | Creates temporal client connection options. | | `createTemporalDispatchActivities` | `value` | `(options: CreateTemporalDispatchActivitiesOptions) => TemporalDispatchActivities` | Wrap a `DispatchProcessor` as a Temporal activity. The processor is idempotent by `dispatchId`, so Temporal retries are safe. | | `CreateTemporalDispatchActivitiesOptions` | `type` | `CreateTemporalDispatchActivitiesOptions` | Configuration options for create temporal dispatch activities. | | `createTemporalSessionRuntimeActivities` | `value` | `(options: CreateTemporalSessionRuntimeActivitiesOptions) => TemporalSessionRuntimeActivities` | Creates temporal session runtime activities. | | `CreateTemporalSessionRuntimeActivitiesOptions` | `type` | `CreateTemporalSessionRuntimeActivitiesOptions` | Configuration options for create temporal session runtime activities. | | `createTemporalWorkerConnectionOptions` | `value` | `(config?: TemporalConnectionConfig) => NativeConnectionOptions` | Creates temporal worker connection options. | | `CUSTOM_APPROVAL_WORKFLOW_NAME` | `value` | `"customApprovalWorkflow"` | Constant defining custom approval workflow name. | | `customApprovalWorkflow` | `value` | `(input: CustomApprovalWorkflowInput) => Promise<ApprovalResponse \| undefined>` | Durable custom approval gate used by `session.approval.request()`. | | `CustomApprovalWorkflowInput` | `type` | `CustomApprovalWorkflowInput` | Type contract for custom approval workflow input. | | `DEFAULT_TEMPORAL_ACTIVITY_TIMEOUTS` | `value` | `TemporalActivityTimeouts` | Constant defining default temporal activity timeouts. | | `DEFAULT_TEMPORAL_ADDRESS` | `value` | `"localhost:7233"` | Default Temporal frontend address used by CLI / build scaffolds when nothing is configured. | | `DEFAULT_TEMPORAL_NAMESPACE` | `value` | `"default"` | Default namespace. | | `DEFAULT_TEMPORAL_TASK_QUEUE` | `value` | `"fabric-harness"` | Default task queue name. | | `defineTemporalAgent` | `value` | `(options?: DefineTemporalAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines temporal agent. | | `DefineTemporalAgentOptions` | `type` | `DefineTemporalAgentOptions` | Configuration options for define temporal agent. | | `DISPATCH_WORKFLOW_NAME` | `value` | `"dispatchWorkflow"` | Constant defining dispatch workflow name. | | `dispatchWorkflow` | `value` | `(input: DispatchInput) => Promise<void>` | Durable dispatch: applies one dispatched input to a persistent instance via the `processDispatch` activity. The activity is idempotent by `dispatchId`, so Temporal retries (and worker restarts) won't double-apply. | | `ExecuteToolActivityInput` | `type` | `ExecuteToolActivityInput` | Type contract for execute tool activity input. | | `ExecuteToolActivityResult` | `type` | `ExecuteToolActivityResult` | Result returned by execute tool activity. | | `HYBRID_PROMPT_WORKFLOW_NAME` | `value` | `"hybridPromptWorkflow"` | Constant defining hybrid prompt workflow name. | | `hybridPromptWorkflow` | `value` | `(input: PromptWorkflowInput, sharedEventState?: EventIndexState) => Promise<PromptWorkflowResult>` | Hybrid durable prompt workflow. The workflow owns deterministic turn orchestration while activities perform nondeterministic effects: context construction, model calls, tool execution, approval policy checks, and durable entry/event appends. | | `InlineSessionRuntime` | `value` | `typeof InlineSessionRuntime` | Runtime API for inline session runtime; the generated signature shows its accepted inputs and return type. | | `LoadSessionActivityInput` | `type` | `LoadSessionActivityInput` | Type contract for load session activity input. | | `LocalTemporalActivitiesOptions` | `type` | `LocalTemporalActivitiesOptions` | Configuration options for local temporal activities. | | `MockTemporalClient` | `value` | `typeof MockTemporalClient` | Minimal mock Temporal client that satisfies enough of the TemporalClientHandle interface for agent tests. Delegates SessionRuntime calls to MockTemporalRuntime. | | `MockTemporalModelProvider` | `value` | `typeof MockTemporalModelProvider` | Minimal mock model provider for Temporal agent tests. Returns deterministic responses based on the latest user message. | | `MockTemporalRuntime` | `value` | `typeof MockTemporalRuntime` | Runtime API for mock temporal runtime; the generated signature shows its accepted inputs and return type. | | `MockTemporalRuntimeOptions` | `type` | `MockTemporalRuntimeOptions` | Configuration options for mock temporal runtime. | | `ModelGenerateActivityInput` | `type` | `ModelGenerateActivityInput` | Type contract for model generate activity input. | | `ModelGenerateActivityResult` | `type` | `ModelGenerateActivityResult` | Result returned by model generate activity. | | `PendingApprovalState` | `type` | `PendingApprovalState` | Type contract for pending approval state. | | `PROMPT_WORKFLOW_NAME` | `value` | `"promptWorkflow"` | Constant defining prompt workflow name. | | `promptWorkflow` | `value` | `(input: PromptWorkflowInput) => Promise<PromptWorkflowResult>` | Coarse one-shot prompt workflow. Useful as a compatibility path while the hybrid loop is still gaining lower-level activity implementations. | | `PromptWorkflowInput` | `type` | `PromptWorkflowInput` | Type contract for prompt workflow input. | | `PromptWorkflowResult` | `type` | `PromptWorkflowResult` | Result returned by prompt workflow. | | `requireIdempotency` | `value` | `(input: { idempotency?: ActivityIdempotency; }, activityName: string) => ActivityIdempotency` | Runtime API for require idempotency; the generated signature shows its accepted inputs and return type. | | `ResolvedTemporalConnectionConfig` | `type` | `ResolvedTemporalConnectionConfig` | Type contract for resolved temporal connection config. | | `ResolveSecretActivityInput` | `type` | `ResolveSecretActivityInput` | Type contract for resolve secret activity input. | | `resolveTemporalConnectionConfig` | `value` | `(options?: TemporalConnectionConfig) => ResolvedTemporalConnectionConfig` | Resolves temporal connection config. | | `resolveToolRefs` | `value` | `(bundle: TemporalBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | | `RuntimeCheckpointCreateActivityInput` | `type` | `RuntimeCheckpointCreateActivityInput` | Type contract for runtime checkpoint create activity input. | | `RuntimeCheckpointRestoreActivityInput` | `type` | `RuntimeCheckpointRestoreActivityInput` | Type contract for runtime checkpoint restore activity input. | | `RuntimePromptActivityInput` | `type` | `RuntimePromptActivityInput` | Type contract for runtime prompt activity input. | | `RuntimeShellActivityInput` | `type` | `RuntimeShellActivityInput` | Type contract for runtime shell activity input. | | `SESSION_STATE_QUERY` | `value` | `"sessionState"` | Constant defining session state query. | | `SessionRuntime` | `type` | `SessionRuntime` | Type contract for session runtime. | | `SessionRuntimeApprovalInput` | `type` | `SessionRuntimeApprovalInput` | Type contract for session runtime approval input. | | `SessionRuntimeCheckpointCreateInput` | `type` | `SessionRuntimeCheckpointCreateInput` | Type contract for session runtime checkpoint create input. | | `SessionRuntimeCheckpointRestoreInput` | `type` | `SessionRuntimeCheckpointRestoreInput` | Type contract for session runtime checkpoint restore input. | | `SessionRuntimeFactory` | `type` | `SessionRuntimeFactory` | Factory for session runtime. | | `SessionRuntimePromptInput` | `type` | `SessionRuntimePromptInput<TResult>` | Type contract for session runtime prompt input. | | `SessionRuntimeShellInput` | `type` | `SessionRuntimeShellInput` | Type contract for session runtime shell input. | | `SessionRuntimeTaskInput` | `type` | `SessionRuntimeTaskInput<TResult>` | Type contract for session runtime task input. | | `sessionStateQuery` | `value` | `QueryDefinition<TemporalWorkflowQueryState, [], string>` | Runtime API for session state query; the generated signature shows its accepted inputs and return type. | | `sessionWorkflow` | `value` | `(input: TemporalSessionWorkflowInput) => Promise<void>` | Long-lived session coordination workflow. This first production Temporal integration supports approval signaling and state queries. Prompt/shell/checkpoint operations are workflows below. | | `SessionWorkflowDefinition` | `type` | `SessionWorkflowDefinition` | Type contract for session workflow definition. | | `SHELL_WORKFLOW_NAME` | `value` | `"shellWorkflow"` | Constant defining shell workflow name. | | `shellWorkflow` | `value` | `(input: SessionRuntimeShellInput & { sessionId: string; idempotency: { idempotencyKey: string; }; }) => Promise<import("@fabric-harness/sdk").ShellResult>` | Runtime API for shell workflow; the generated signature shows its accepted inputs and return type. | | `SnapshotRef` | `type` | `SnapshotRef` | Type contract for snapshot ref. | | `startTemporalWorker` | `value` | `(options?: TemporalWorkerOptions) => Promise<TemporalWorkerHandle>` | Runtime API for start temporal worker; the generated signature shows its accepted inputs and return type. | | `TASK_WORKFLOW_NAME` | `value` | `"taskWorkflow"` | Constant defining task workflow name. | | `taskWorkflow` | `value` | `(input: TaskWorkflowInput) => Promise<PromptWorkflowResult>` | Runtime API for task workflow; the generated signature shows its accepted inputs and return type. | | `TaskWorkflowInput` | `type` | `TaskWorkflowInput` | Type contract for task workflow input. | | `temporal` | `value` | `(config: TemporalBundleConfig) => Promise<TemporalBundle>` | Runtime API for temporal; the generated signature shows its accepted inputs and return type. | | `TemporalActivities` | `type` | `TemporalActivities` | Type contract for temporal activities. | | `TemporalActivityTimeouts` | `type` | `TemporalActivityTimeouts` | Type contract for temporal activity timeouts. | | `TemporalBundle` | `type` | `TemporalBundle` | Type contract for temporal bundle. | | `TemporalBundleConfig` | `type` | `TemporalBundleConfig` | Type contract for temporal bundle config. | | `TemporalClientHandle` | `type` | `TemporalClientHandle` | Type contract for temporal client handle. | | `TemporalClientOptions` | `type` | `TemporalClientOptions` | Configuration options for temporal client. | | `TemporalConnectionConfig` | `type` | `TemporalConnectionConfig` | Type contract for temporal connection config. | | `TemporalConnectRetryOptions` | `type` | `TemporalConnectRetryOptions` | Configuration options for temporal connect retry. | | `TemporalDispatchActivities` | `type` | `TemporalDispatchActivities` | Activity that durably applies a dispatched input to a persistent instance. | | `TemporalDispatchClientLike` | `type` | `TemporalDispatchClientLike` | Minimal Temporal client surface needed to start a dispatch workflow. | | `temporalDispatchQueue` | `value` | `(options: TemporalDispatchQueueOptions) => DispatchQueue` | Durable dispatch queue. `enqueue` starts a `dispatchWorkflow` keyed by the `dispatchId`, so delivery survives worker/process restarts and a duplicate `dispatchId` maps to the same workflow id (idempotent admission). Implements the SDK's `DispatchQueue`; pair with `createTemporalDispatchActivities` on the worker. When `runtime: 'temporal'` is configured, this is the default dispatch queue (D4) unless an explicit queue is supplied. | | `TemporalDispatchQueueOptions` | `type` | `TemporalDispatchQueueOptions` | Configuration options for temporal dispatch queue. | | `TemporalIntegrationMode` | `type` | `TemporalIntegrationMode` | Type contract for temporal integration mode. | | `TemporalPromptWorkflowMode` | `type` | `TemporalPromptWorkflowMode` | Type contract for temporal prompt workflow mode. | | `TemporalRunStatus` | `type` | `TemporalRunStatus` | Type contract for temporal run status. | | `TemporalRuntimeOptions` | `type` | `TemporalRuntimeOptions` | Configuration options for temporal runtime. | | `temporalSessionRuntime` | `value` | `(options?: TemporalClientOptions) => DurableSessionRuntimeFactory` | Build a `DurableSessionRuntimeFactory` for `init({ sessionRuntime })` that delegates each session's `prompt`/`task`/`shell`/`checkpoint` calls to a Temporal workflow. The Temporal client connection is opened lazily on the first session and shared across all sessions produced by this factory. Pair with `runtime: 'temporal'` for production deployments. For tests, pass `mode: 'mock'` to use the in-process mock runtime. See the package declarations for an example. | | `TemporalSessionRuntime` | `value` | `typeof TemporalSessionRuntime` | Runtime API for temporal session runtime; the generated signature shows its accepted inputs and return type. | | `TemporalSessionRuntimeActivities` | `type` | `TemporalSessionRuntimeActivities` | Type contract for temporal session runtime activities. | | `TemporalSessionWorkflowInput` | `type` | `TemporalSessionWorkflowInput` | Type contract for temporal session workflow input. | | `TemporalSignalClient` | `type` | `TemporalSignalClient` | Client implementation for temporal signal. | | `TemporalTlsConfig` | `type` | `TemporalTlsConfig` | Type contract for temporal tls config. | | `TemporalWorkerHandle` | `type` | `TemporalWorkerHandle` | Type contract for temporal worker handle. | | `TemporalWorkerOptions` | `type` | `TemporalWorkerOptions` | Configuration options for temporal worker. | | `TemporalWorkflowQueryState` | `type` | `TemporalWorkflowQueryState` | Type contract for temporal workflow query state. | | `ToolApprovalRequest` | `type` | `ToolApprovalRequest` | Input contract for tool approval. | ### `@fabric-harness/temporal/agent` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `defineTemporalAgent` | `value` | `(options?: DefineTemporalAgentOptions) => DefinedAgent<JsonObject, unknown>` | Defines temporal agent. | | `DefineTemporalAgentOptions` | `type` | `DefineTemporalAgentOptions` | Configuration options for define temporal agent. | | `resolveToolRefs` | `value` | `(bundle: TemporalBundle, refs: string[]) => ToolDef[]` | Resolves tool refs. | | `temporal` | `value` | `(config: TemporalBundleConfig) => Promise<TemporalBundle>` | Runtime API for temporal; the generated signature shows its accepted inputs and return type. | | `TemporalBundle` | `type` | `TemporalBundle` | Type contract for temporal bundle. | | `TemporalBundleConfig` | `type` | `TemporalBundleConfig` | Type contract for temporal bundle config. | ## @fabric-harness/vite ### `@fabric-harness/vite` | Export | Kind | TypeScript signature | Purpose | | --- | --- | --- | --- | | `fabricHarness` | `value` | `(options?: FabricHarnessViteOptions) => Plugin` | Compose Harness with Vite without replacing `fh dev`, `fh build`, explicit agent builders, or the portable target registry. | | `FabricHarnessViteApi` | `type` | `FabricHarnessViteApi` | Type contract for fabric harness vite api. | | `FabricHarnessViteOptions` | `type` | `FabricHarnessViteOptions` | Configuration options for fabric harness vite. | | `fabricHarnessWorkerConfig` | `value` | `() => FabricHarnessWorkerConfigCustomizer` | Narrow customizer for `@cloudflare/vite-plugin`. It contributes only the Harness-generated worker entry and node compatibility flag; user bindings, migrations, and deployment settings remain untouched. | | `FabricHarnessWorkerConfigCustomizer` | `type` | `FabricHarnessWorkerConfigCustomizer` | Type contract for fabric harness worker config customizer. | --- # Build Manifest Canonical: https://harness.techfabric.com/docs/reference/build-manifest Schema-v2 manifest emitted by fh build for jobs, persistent agents, files, and provenance. Every `fh build` writes `manifest.json` at the artifact root. Schema v2 separates finite jobs from persistent agents and records every emitted file for verification. ## Current shape ```jsonc { "schemaVersion": 2, "createdAt": "2026-07-09T21:59:56.279Z", "target": "databricks-app", "workspaceRoot": "/source/analytics-agent", "outDir": "/source/analytics-agent/.fabricharness/build/databricks-app", "entrypoint": "dist/server.mjs", "agentsManifestSha256": "46df8f...", "config": { "source": ".fabricharness/config.ts", "agent": { "model": "databricks/analytics-model" }, "sandbox": "local" }, "jobs": [ { "name": "analyst", "kind": "job", "source": ".fabricharness/jobs/analyst.mjs", "entry": "jobs/analyst.mjs", "sha256": "68d820...", "triggers": { "webhook": true, "manual": true } } ], "agents": [ { "name": "copilot", "kind": "agent", "source": ".fabricharness/agents/copilot.mjs", "entry": "agents/copilot.mjs", "sha256": "bba012..." } ], "roles": [ { "name": "data-analyst", "path": ".fabricharness/roles/data-analyst.md", "description": "Analyze governed data." } ], "skills": [ { "name": "analyze-table", "path": ".fabricharness/skills/analyze-table/SKILL.md" } ], "files": [ { "path": "dist/server.mjs", "bytes": 3874732, "sha256": "b5b8ab..." } ], "package": { "name": "analytics-agent", "version": "1.0.0", "type": "module", "dependencies": {} } } ``` `agentsManifestSha256` is retained as the compatibility field name, but its digest covers both `jobs` and `agents` in schema v2. ## Inspect a build ```sh jq '{schemaVersion, target, jobs, agents, entrypoint}' \ .fabricharness/build/node/manifest.json ``` List every local build: ```sh fh builds ``` The Node admin API can read manifests that remain under the active workspace build directory: ```sh curl http://localhost:4317/builds/node/manifest ``` For a standalone artifact deployed elsewhere, read `manifest.json` from the artifact filesystem or publish it through your deployment platform. The shared v2 server does not expose a root `GET /manifest` route. ## Schema-v1 compatibility `readBuildManifest()` normalizes legacy manifests by treating the old `agents` collection as finite jobs and returning schema-v2 data: ```ts import { readBuildManifest } from '@fabric-harness/node'; const manifest = await readBuildManifest(process.cwd(), 'node'); for (const job of manifest?.jobs ?? []) { console.log('job', job.name); } for (const agent of manifest?.agents ?? []) { console.log('persistent agent', agent.name); } ``` External manifest consumers should migrate explicitly rather than assuming every definition is an agent. ## Supply-chain verification Build with metadata: ```sh fh build --target docker \ --provenance \ --attestation \ --sbom ``` Then verify: ```sh fh verify-provenance .fabricharness/build/docker fh verify-attestation .fabricharness/build/docker ``` Provenance and attestations include definition name, kind, source, and digest. The `files` list lets deployment tooling independently verify the emitted tree. ## See also - [Build and run artifacts](/docs/deployment/build-artifacts) - [Node deployment](/docs/deployment/node) - [Security hardening](/docs/reference/security-hardening) --- # Capability Matrix Canonical: https://harness.techfabric.com/docs/reference/capability-matrix Which runtime behaviour and deployment requirements apply to each feature on each target, so you can check before you commit. Use this page to choose a runtime, sandbox, integration, and validation path. Hosted services require credentials and permissions in the account where the agent will run. ## Core runtime | Capability | Runtime behavior | Deployment requirement | | --- | --- | --- | | Finite agents in `.fabricharness/jobs/` | `defineAgent({ run })`, typed input/output, `POST /jobs/:name`. | Configure authentication and request limits on public servers. | | Persistent agents | Durable `202` submissions, FIFO execution, offset streams, abort, and WebSocket. | Select a durable session, submission, and stream store. | | Durable state and attachments | In-memory, file, SQLite, Postgres, and UC Volumes implementations. | Configure backup, retention, deletion, and recovery objectives. | | `@fabric-harness/client` | Send, wait, status, history, observe, abort, and job invocation. | Supply the server token or application authentication headers. | | Node runtime | Shared HTTP server for development and Node-derived build targets. | Configure auth, rate limits, durable stores, backup, and monitoring. | | Enterprise principal/RBAC/deletion | Tenant-bound principals, scoped permissions, actor propagation, and cascade deletion. | Map the application identity provider to explicit Fabric permissions. | | MCP server exposure | Authenticated Streamable HTTP for jobs, persistent agents, and custom tools. | Restrict exposed tools and authenticate every remote client. | | Cron scheduler | Timezone-aware schedules, overlap prevention, payload resolver, graceful shutdown. | Run one scheduler leader or provide deployment-level leader election. | | Operator console | Session and tenant inspection, approval count, abort, and deletion at `/admin`. | Grant only `admin:read`, `session:abort`, and `session:delete` as needed. | | `fh build` | Schema-v2 manifests and shared-server artifacts for jobs and persistent agents. | Verify the artifact attestation and environment configuration before deploy. | | Temporal runtime | Durable prompt, skill, child task, shell, checkpoint, tool/custom approval, cancellation, activity retry, attachment, and usage/cost paths. | Run the credentialed conformance suite against the deployment namespace and validate worker restart. | | Policies, approvals, audit, cost budgets | Definition controls combine with invocation controls as enforcement floors. | Route mutating operations through explicit policy and approval rules. | | Tools, skills, roles, tasks, MCP | Built-in tools, Markdown skills, role overlays, nested tasks, and remote MCP clients. | Validate remote MCP authentication and tool allowlists. | | Evals and telemetry | Built-in scorers, OpenTelemetry, Langfuse, cost, and session metrics. | Configure the chosen telemetry sink and its retention policy. | ## Sandboxes and targets | Backend or target | Runtime behavior | Deployment requirement | | --- | --- | --- | | Virtual sandbox | Fast in-memory filesystem and shell subset. | Use when process isolation is unnecessary. | | Local sandbox | Host filesystem and process execution, workspace-root confinement with an `allowedPaths` escape hatch. | Restrict to trusted code and scoped working directories; confinement is a static guardrail, not a hard isolation boundary. | | Docker sandbox | Per-session container filesystem and commands. | Verify the selected image, resource limits, network policy, and cleanup. | | Cloudflare | Durable finite runs and persistent submissions with FIFO leases, restart reconciliation, offset streams, attachments, abort, and deletion using Workers AI, Durable Objects, R2, Sandbox, and Shell Workspace. | Configure bindings and run the workerd plus account smoke commands from the deployment guide. | | Azure Container Instances | ACR build and managed-identity deployment automation. | Configure subscription, identity, registry, network, and resource-group access. | | Daytona / E2B / Modal | Remote sandbox adapters for provider-managed execution. | Pin the provider SDK and verify lifecycle, timeout, file, and cleanup behavior. | | Kubernetes / AKS | Pod-backed sandbox execution. | Configure cluster identity, namespace policy, quotas, networking, and pod cleanup. | | Azure / Foundry | AKS sandbox, Azure targets, managed-identity model provider, and Foundry Agent Service helpers. | Validate tenant identity, role assignments, networking, and regional service availability. | ## Databricks Databricks capability metadata distinguishes **contract targets** from **live-certified clouds**. `contractClouds` names the clouds targeted by the typed API contract. `clouds` contains only clouds present in linked, retained certification evidence. A capability can therefore target AWS, Azure, and GCP while showing only Azure as live-certified; never interpret contract portability as cross-cloud operational evidence. | Capability | Runtime behavior | Deployment requirement | | --- | --- | --- | | Databricks inference provider | Unity AI Gateway at `/ai-gateway/mlflow/v1` for `system.ai.*`; explicit custom endpoints retain `/serving-endpoints`. Both use rotating bearer credentials. | Grant access to the selected model service or custom endpoint. | | PAT, OAuth M2M, Apps identity, and OBO | Service and user identity helpers with token refresh. | Configure the required scopes and enable Databricks user authorization when using OBO. | | SQL and Unity Catalog tools | Governed discovery and statement execution; Unity Catalog remains authoritative. | Grant catalog/schema/object access and require approval for arbitrary SQL. | | Unity Catalog Agent Services | Explicit-Beta create/get/list/update/grant/revoke/delete client for externally hosted agents; no runtime invocation is claimed. | Enable the account preview, create an HTTP connection, and grant parent-schema plus connection privileges. | | AI Search, embeddings, AI Functions, and Genie | Retrieval, embedding, warehouse inference, and conversational analytics tools. | Grant endpoint, index, warehouse, and Genie Agent access. | | Lakeflow and Feature Serving | Read and execute tools with effect metadata for policy routing. | Grant job, pipeline, and endpoint permissions to the runtime principal. | | Consumption and cost reconciliation | System Tables reads for delayed actual-cost reconciliation. | Grant System Tables access and retain estimated budgets for real-time enforcement. | | Databricks Apps build/deploy | Shared-server artifact with separate jobs and persistent agents. | Configure App resources, environment variables, identity, and health probes. | | Model Serving build/deploy | MLflow `ResponsesAgent` proxy to an externally hosted Fabric agent. | Deploy the TypeScript runtime separately and secure the proxy-to-runtime connection. | | Lakebase persistence | OAuth database credential exchange plus session, submission, and stream stores. | Configure endpoint coordinates, database grants, migrations, backup, and restart recovery. | | Databricks SQL sandbox | `exec()` uses SQL Statement Execution; filesystem operations remain in memory. | Select a warehouse and Unity Catalog scope appropriate for the agent. | | Certification evidence | Secret-redacted JSON evidence for configured workspace capabilities. | Run the credentialed certification workflow in [authoring certification](/docs/databricks/authoring-certification) with the services required by the deployment. | ## Channels and databases | Capability | Runtime behavior | Deployment requirement | | --- | --- | --- | | Slack, GitHub, Discord, Teams, Telegram, Twilio, WhatsApp | Authentication, event normalization, identity propagation, deduplication, and governed replies. | Configure provider credentials, webhook verification, retry handling, and application installation. | | Postgres, MySQL, SQLite, MongoDB, Redis data tools | Fixed SQL operations, host-built filters, namespaced keys, limits, effects, and redacted failures. | Use least-privilege database credentials and apply tenant scoping to every operation. | ## Databricks deployment validation Run the Databricks certification workflow in the target workspace before rollout. Include identity, restart recovery, Unity Catalog denial cases, tool approvals, retry behavior, and cost attribution in the deployment record. --- # Context Compaction Canonical: https://harness.techfabric.com/docs/reference/compaction Automatic, event-emitting context compaction for long sessions. Default import enables it; /strict opts in explicitly. Threshold and overflow modes. import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; When a session's message history grows past the model's context window, an agent will start failing or thrashing. TechFabric Harness solves this with automatic compaction: older session entries are summarized into a single compact entry, recent entries are kept verbatim, and the agent keeps running. ## Defaults | SDK | Default | Why | |---|---|---| | **Default import** (`@fabric-harness/sdk`) | `enabled: true` | Headless agents are often webhook/serverless handlers. Failing at the context window is the wrong default. | | **Strict import** (`@fabric-harness/sdk/strict`) | not injected — `undefined` until you set it | Required for Temporal replay determinism: auto-compaction is non-deterministic across replays. Opt in only when you don't need replay safety. | > ⚠️ Selecting `runtime: 'temporal'` from the default import emits a one-time `console.warn` because of this exact reason. Either switch to `/strict` or pass `compaction: { enabled: false }` explicitly. ## Trigger modes 1. **Threshold** — before each model call, the harness estimates token usage from session history. When estimated tokens exceed `compactAtTokens` (auto-derived as `contextWindowTokens - reserveTokens` if not set), it compacts before sending the next prompt. 2. **Overflow** — if the model returns a `context overflow` error anyway, the harness compacts and retries the prompt once. Set `recoverFromOverflow: false` to disable. Both paths emit a typed `compaction` [event](/docs/reference/events) with `reason: 'threshold' | 'overflow'`, `messagesBefore`, `messagesAfter`, and `tokensBefore`. ## Configuration ```ts import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ message: string }>({ name: 'long-running', run: async ({ init, input }) => { // Compaction is on by default. Override only if you need to. const session = await (await init({ compaction: { enabled: true, reserveTokens: 8192, // default 20000 keepRecentEntries: 30, // default 20 // compactAtTokens auto-derived from contextWindow if not set }, })).session(); return { reply: await session.prompt(input.message) }; }, }); ``` To disable: `init({ compaction: { enabled: false } })`. ```ts import { defineAgent, schema } from '@fabric-harness/sdk/strict'; export default defineAgent({ name: 'long-running', input: schema.object({ message: schema.string() }), run: async ({ init, input }) => { // Off by default in /strict — opt in explicitly. Avoid for Temporal. const session = await (await init({ runtime: 'inline', sandbox: 'local', compaction: { enabled: true, reserveTokens: 16_384, keepRecentEntries: 30, recoverFromOverflow: true, }, })).session(); return await session.prompt(input.message); }, }); ``` ## `CompactionSettings` reference | Field | Type | Default | Purpose | |---|---|---|---| | `enabled` | `boolean` | Default import: `true`; `/strict`: not injected | Master switch. | | `compactAtTokens` | `number` | derived from `contextWindowTokens - reserveTokens` | Trigger threshold. | | `reserveTokens` | `number` | `20000` | Headroom kept below the model's context window. | | `keepRecentTokens` | `number` | `8000` | Tokens of recent context kept verbatim during compaction. Older entries get folded into the summary. | | `keepRecentEntries` | `number` | `20` | Recent entries kept verbatim during compaction. Older entries get folded into the summary. | | `recoverFromOverflow` | `boolean` | `true` | Catch provider context-overflow errors, compact, and retry once. | All fields can also be set per-prompt via `session.prompt(text, { compactAtTokens, reserveTokens, compactionKeepRecentEntries, recoverContextOverflow })`. Per-prompt values win. ## Subscribing to compaction events ```ts import { init, isEvent, type AgentEvent } from '@fabric-harness/sdk'; const fabric = await init({ onEvent: (event: AgentEvent) => { if (isEvent(event, 'compaction')) { console.log( `compacted ${event.data.messagesBefore} → ${event.data.messagesAfter}`, `(reason: ${event.data.reason}, ${event.data.tokensBefore} tokens)`, ); } }, }); ``` See the [Events reference](/docs/reference/events) for the full event taxonomy. ## Manual compaction You can also force compaction outside the auto-loop: ```ts const result = await session.compact({ keepRecentEntries: 10, generateSummary: true, reason: 'manual', }); console.log(result.summary, result.compactedEntries); ``` ## How the summary is generated The summary is produced by the configured model with a deterministic fallback when no model is available. Compaction never breaks an active tool-call/tool-result pair — those move atomically into the kept-recent window. References to files read or modified are appended as a separate block so the agent can re-discover them after compaction. The summary entry replaces the compacted slice in the session history; subsequent prompts see only the summary plus the recent entries you chose to keep. ## When *not* to enable compaction - Short prompts that always fit (one-shot classifiers). - Agents that need an exact, replayable conversation history (legal/audit). Use Temporal-backed durability instead. - Tasks where summary loss could change the outcome (e.g., the agent must remember a specific identifier mentioned 50 turns ago). In that case, persist key facts as artifacts and reference them by name. ## See also - [Events](/docs/reference/events) — typed `compaction` event payload - [Sessions and prompts](/docs/building/sessions-prompts) — where `prompt()` evaluates the budget - [Telemetry](/docs/reference/telemetry) — exporting compaction metrics --- # Errors Canonical: https://harness.techfabric.com/docs/reference/errors Handle stable Fabric error codes without exposing secrets or host paths. Fabric errors have a stable `code`, retryability, and optional structured details. Match codes, not message text: ```ts import { FabricError } from '@fabric-harness/sdk'; try { await session.prompt('Run the report'); } catch (error) { if (error instanceof FabricError && error.code === 'MODEL_RATE_LIMITED') { await retryLater(); } throw error; } ``` Use `serializeFabricError(error, 'public')` at an HTTP or queue boundary. Public serialization uses the safe message and public details, removes filesystem paths, and redacts authorization values, tokens, API keys, passwords, credentials, and known provider-key formats. Developer serialization retains diagnostic context but still redacts secrets. ```ts import { serializeFabricError } from '@fabric-harness/sdk'; return Response.json( { error: serializeFabricError(error, 'public') }, { status: 500 }, ); ``` The Node package exports two specialized subclasses: | Class | Stable codes | | --- | --- | | `FabricBuildError` | `BUILD_FAILED`, `BUILD_INVALID_TARGET`, `BUILD_VERIFICATION_FAILED` | | `FabricPersistenceError` | `PERSISTENCE_CONFLICT`, `PERSISTENCE_UNAVAILABLE`, `PERSISTENCE_INVALID_CONFIG`, `SESSION_NOT_FOUND` | `PERSISTENCE_CONFLICT` is retryable when an ownership lease or optimistic version loses a race. Configuration and verification errors are not retryable until the caller changes input or the artifact. `@fabric-harness/client` preserves server `code`, `details`, and `retryable` on `FabricClientError`, so browser and service clients can use the same branching logic. --- # Eval Library Canonical: https://harness.techfabric.com/docs/reference/eval-library The API reference for @fabric-harness/evals, covering scorers, judges and the assertions you write a suite against. Install `@fabric-harness/evals` and import all APIs from the package root. ## Suite API ```ts import { defineEvalSuite, runEvalSuite } from '@fabric-harness/evals'; ``` - `defineEvalSuite(suite)` preserves generic inference and returns the suite unchanged. - `runEvalSuite(suite)` runs cases sequentially and returns `EvalSuiteResult`. - `EvalSuite` contains `name`, `cases`, `runner`, `scorers`, optional `passThreshold`, and optional metadata. - `EvalCase` contains `id`, `input`, optional `expected`, tags, and metadata. - `EvalScore` contains `name`, a `0..1` score, optional `passed`, reason, and metadata. A case passes when no scorer explicitly returns `passed: false` and its average score meets `passThreshold` (default `0.8`). A runner or scorer error records a failed case instead of aborting the remaining suite. ## Built-in scorers ```ts exactMatchScorer(name?) containsTextScorer(expectedText?, name?) regexMatchScorer(pattern, { name?, flags? }) jsonShapeMatchScorer(shape, { name? }) llmAsJudgeScorer({ judge, model, rubric, name?, passThreshold? }) ``` `containsTextScorer()` uses the case's string `expected` value when no fixed text is provided. `jsonShapeMatchScorer()` checks required keys and primitive types while allowing extra keys. `llmAsJudgeScorer()` expects a model provider with `generate()` and treats malformed judge output as a zero score. ## Custom scorer ```ts import type { EvalScorer } from '@fabric-harness/evals'; const concise: EvalScorer = ({ output }) => ({ name: 'concise', score: output.length <= 200 ? 1 : 0, passed: output.length <= 200, reason: `${output.length} characters`, }); ``` See [Evaluations](/docs/building/evals) for job execution and CLI examples. --- # Agent Events Canonical: https://harness.techfabric.com/docs/reference/events Subscribe to a typed event stream from any TechFabric Harness agent. Text deltas, tool calls, shell commands, approvals, tasks and errors. import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; Every TechFabric Harness agent emits a structured event stream as it runs. The same callback shape is accepted at every level — `init({ onEvent })`, `agent.session(id, { onEvent })`, and `session.prompt(text, { onEvent })` — and propagates downward, so wiring once at `init()` is usually enough. ## Quick start ```ts import { defineAgent, isEvent, type AgentEvent } from '@fabric-harness/sdk'; export default defineAgent<{ message: string }>({ name: 'echo', run: async ({ init, input }) => { const fabric = await init({ onEvent: (event: AgentEvent) => { if (isEvent(event, 'text_delta')) process.stdout.write(event.data.delta); if (isEvent(event, 'tool_start')) console.error(`> ${event.data.toolName}`); if (isEvent(event, 'compaction')) console.error(`compacted ${event.data.messagesBefore} → ${event.data.messagesAfter}`); }, }); const session = await fabric.session(); return { reply: await session.prompt(input.message) }; }, }); ``` ```ts import { defineAgent, isEvent, schema, type AgentEvent } from '@fabric-harness/sdk'; export default defineAgent({ name: 'echo', input: schema.object({ message: schema.string() }), output: schema.string(), run: async ({ init, input }) => { const fabric = await init({ onEvent: (event: AgentEvent) => { if (isEvent(event, 'tool_end') && event.data.isError) { console.error(`tool ${event.data.toolName} failed`, event.data.result); } if (isEvent(event, 'approval_requested')) { console.error(`approval needed for ${event.data.subject}`); } }, }); const session = await fabric.session(); return await session.prompt(input.message); }, }); ``` ## Event types All events share a common envelope: ```ts interface AgentEventBase { id: string; // stable id for this occurrence timestamp: string; // ISO-8601 sessionId?: string; parentSessionId?: string; // set on child task events taskId?: string; // set on child task events } ``` The `type` discriminator narrows `data` automatically: | Type | Data shape | When it fires | |---|---|---| | `agent_start` | — | `init()` resolves | | `session_start` | `{ id?: string }` | `agent.session()` resolves | | `prompt_start` | `{ text?: string }` | start of `session.prompt()` | | `prompt_end` | `{ text?: string; result?: unknown }` | end of `session.prompt()` | | `turn_start` / `turn_end` | `{ stopReason?: string }` | each model turn inside the harness loop | | `model_attempt` | provider-shaped | each model call (incl. retries) | | `text_delta` | `{ delta: string }` | streaming text from the model | | `tool_start` | `{ toolName, toolCallId?, args? }` | a tool call begins | | `tool_end` | `{ toolName, toolCallId?, isError?, result? }` | a tool call resolves | | `command_start` | `{ command: string; cwd? }` | `session.shell()` or scoped command begins | | `command_end` | `{ command: string; exitCode: number; durationMs? }` | shell command resolves | | `skill_start` / `skill_end` | `{ name, result? }` | `session.skill()` lifecycle | | `task_start` | `{ taskId, depth }` | `session.task()` spawns a child agent | | `task_end` | `{ taskId, depth, durationMs? }` | child task resolves | | `task_failed` / `task_cancelled` | `{ taskId, error? }` | child task fails or is cancelled | | `task_checkpoint` | `{ taskId }` | durable child checkpoint persisted | | `compaction` | `{ reason?: 'threshold' \| 'overflow'; messagesBefore; messagesAfter; tokensBefore?; tokensAfter? }` | context compaction runs (when enabled) | | `artifact_created` | `{ path; contentType? }` | `session.artifact()` persists | | `checkpoint_created` / `checkpoint_restored` | `{ id }` | session checkpoints | | `approval_requested` | `{ approvalId; subject; kind; risk? }` | a `requireApproval` policy match needs human ack | | `approval_voted` | `{ approvalId; outcome }` | someone voted via `fh approve` / `fh reject` | | `approval_granted` / `approval_denied` / `approval_expired` | `{ approvalId }` | approval terminal states | | `metric` | `JsonObject` | counter/gauge/histogram update | | `result` | `{ usage? }` | final result emitted | | `result_retry` | provider-shaped | typed-result schema mismatch caused a retry | | `error` | `{ error: string; cause? }` | thrown by anywhere in the agent loop | ## Type-safe access with `isEvent` ```ts import { isEvent } from '@fabric-harness/sdk'; onEvent: (event) => { if (isEvent(event, 'tool_start')) { // event.data is { toolName: string; toolCallId?: string; args?: JsonObject } console.log(event.data.toolName, event.data.args); } } ``` Or use a `switch` on `event.type` — TS narrows the same way. ## Streaming via `session.stream()` The same events can be consumed as an async generator instead of a callback: ```ts import type { AgentEvent } from '@fabric-harness/sdk'; for await (const event of session.stream('Triage this issue')) { // event: AgentEvent — same union, same narrowing if (event.type === 'text_delta') process.stdout.write(event.data.delta); } ``` `session.stream()` returns an `AsyncGenerator` — the final `return` value is the typed prompt result; the yielded values are the events leading up to it. ## Telemetry alongside events If `onEvent` is configured *and* an OTel exporter is configured (`@fabric-harness/sdk` `telemetry` option), both fire — they aren't mutually exclusive. Events are for in-process subscribers (logs, downstream workers, server-sent-event consumers); OTel is for cross-process observability backends. The runtime remains headless; `fh fiber` and `@fabric-harness/react` are optional clients of the public event protocol. ## Where to go next - [Sessions and prompts](/docs/building/sessions-prompts) — the call surface that emits these events. - [Telemetry](/docs/reference/telemetry) — exporting metrics and traces to Datadog, Grafana, OpenTelemetry collector. - [Approvals](/docs/building/approvals) — for the `approval_*` event variants. --- # Filesystem sources Canonical: https://harness.techfabric.com/docs/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 ```ts import { defineAgent, localDirectorySource, withFilesystemSources } from '@fabric-harness/sdk'; const sandbox = withFilesystemSources('empty', [{ mountAt: '/workspace/kb', source: localDirectorySource('./knowledge-base', { include: (p) => p.endsWith('.md') }), }]); export default defineAgent<{ message?: string }>({ run: async ({ init, input }) => { const fabric = await init({ sandbox, runtime: 'stateless' }); const session = await fabric.session(); const message = input.message ?? ''; return { reply: await session.prompt( `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. ```ts 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. ```ts 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: ```ts import { r2FilesystemSource } from '@fabric-harness/cloudflare'; import { withFilesystemSources } from '@fabric-harness/sdk'; 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`. ### Concrete vendor connectors (recommended) `@fabric-harness/connectors` ships **concrete connectors** for the most common backends. Each is on its own subpath export and peer-deps the vendor SDK so you only install what you use. ```ts import { init } from '@fabric-harness/sdk'; import { s3Source } from '@fabric-harness/connectors/s3'; import { githubSource } from '@fabric-harness/connectors/github'; const fabric = await init({ sandbox: 'local' }); const session = await fabric.session(); // `session.mount()` writes the source's entries into the sandbox at the // given path. mode: 'read' (default) blocks write tools to that prefix. await session.mount('/mnt/logs', s3Source({ bucket: 'app-logs', prefix: '2026/' })); await session.mount('/mnt/repo', githubSource({ owner: 'me', repo: 'demo', ref: 'main' })); ``` Available subpath exports: | Export | Functions | Peer dep | |---|---|---| | `@fabric-harness/connectors/s3` | `s3Source`, `s3Writer` | `@aws-sdk/client-s3` | | `@fabric-harness/connectors/azure-blob` | `azureBlobSource`, `azureBlobWriter` | `@azure/storage-blob` | | `@fabric-harness/connectors/gcs` | `gcsSource`, `gcsWriter` | `@google-cloud/storage` | | `@fabric-harness/connectors/github` | `githubSource` | `octokit` | | `@fabric-harness/connectors/databricks-volume` | `databricksVolumeSource`, `databricksVolumeWriter` | _none_ | ### S3 and Azure Blob structural sources (advanced) For non-standard SDK clients or when you want to adapt an existing client, the older structural helpers remain available. They don't import cloud SDKs; adapt your client calls to the small interface shape. ```ts import { s3FilesystemSource, azureBlobFilesystemSource } from '@fabric-harness/connectors'; const s3 = s3FilesystemSource(s3ClientAdapter, { prefix: 'knowledge-base/' }); const azure = 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: ```ts 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: ```ts 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: ```ts withFilesystemSources('local', [{ mountAt: '/workspace/reference', source: localDirectorySource('./reference'), }]); ``` ## Conventions and limits - **Read-only by default with `session.mount()`.** Calling `session.mount(mountAt, source)` (no options) marks the mount as read-only — write tools (`write`, `edit`, `mkdir`, `rm`) targeting paths under it are rejected at the policy layer. Pass `{ mode: 'write' }` to allow writes. - **Read-only by convention with `withFilesystemSources()`.** The legacy `withFilesystemSources()` factory does not enforce read-only — it relies on the agent's role/skill prompts. For hard enforcement, use `session.mount()` (default) or use a sandbox backend that supports it (Docker `--read-only` mounts via `metadata.mountReadOnly`, for example). - **Eager population.** Both `withFilesystemSources` and `session.mount()` walk the source(s) and write every file into the sandbox. 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. - **Path rerooting.** `session.mount('/mnt/kb', source)` with sandbox cwd `/workspace` is rerooted to `/workspace/mnt/kb` since paths outside the sandbox boundary are blocked. ## See also - [Headless agents with the minimal entrypoint](/docs/getting-started/headless-mode) — the minimal entrypoint story this primitive belongs to. - [examples/support-agent](/docs/reference/source-access) — a runnable end-to-end example. - [Sandboxes](/docs/building/sandboxes) — the broader sandbox model. --- # HTTP Server Canonical: https://harness.techfabric.com/docs/reference/http-server REST, SSE, and WebSocket conventions for finite jobs and persistent agents on Node-derived targets. The Node server and Node-derived build targets share this v2 HTTP surface. Finite jobs support synchronous results or asynchronous run admission at `/jobs/:name`. Persistent agents are addressable instances at `/agents/:name/:id` and use durable, asynchronous admission by default. The Cloudflare target exposes finite jobs and core persistent prompt/read/delete routes with a smaller operational route set. See [Cloudflare Workers + Sandbox](/docs/deployment/cloudflare). Node applications can mount authenticated Fetch-standard routes and middleware without replacing this server. See [HTTP applications](/docs/building/http-applications). ## Routes | Method | Path | Purpose | |---|---|---| | `POST` | `/jobs/:name` | Invoke a finite job with its input payload. Returns `{ result, runId }`; add `?wait=false` for a `202` run receipt. | | `GET` | `/runs` | List tenant-visible finite runs with `?status=&job=&limit=&cursor=`. | | `GET` | `/runs/:runId` | Read tenant-bound run status, output, error, timestamps, actor, and parent linkage. | | `GET` | `/runs/:runId/events` | Read run events with `?offset=&limit=` pagination. | | `POST` | `/runs/:runId/abort` | Propagate cancellation to an active run. | | `POST` | `/agents/:name/:id` | Durably admit `{ message, session? }` to a persistent instance. Returns `202 { submissionId, streamUrl, conversationUrl, updatesUrl, offset }`. Add `?wait=true` for a synchronous bridge. | | `POST` | `/agents/:name/:id/dispatch` | Enqueue `{ input, session? }` for asynchronous delivery. Returns a `202` dispatch receipt. | | `GET` | `/agents/:name/:id` | Read the persistent instance's default session state and history. | | `GET` | `/agents/:name/:id/conversation` | Read incarnation-fenced conversation records with `?session=&offset=&limit=` pagination. | | `GET` | `/agents/:name/:id/stream` | Tail conversation records and stream checkpoints with SSE when `?offset=` is present; without it, stream legacy session events. | | `GET` | `/agents/:name/:id/submissions/:submissionId` | Read queued, running, or settled submission status. | | `POST` | `/agents/:name/:id/abort` | Durably request abort for unsettled work in `{ session? }`. | | `GET` | `/agents/:name/:id/attachments/:digest` | Download a stored attachment when an attachment store is configured. | | `DELETE` | `/agents/:name/:id` | Cascade-delete the tenant-bound instance sessions, submissions, streams, and attachments supported by the configured stores. | | `GET` | `/health` | Liveness probe | | `GET` | `/ready` | Readiness probe with workspace info | | `GET` | `/builds` | List local build manifests | | `GET` | `/builds/:target/manifest` | Read a target's normalized build manifest. | | `GET` | `/sessions` | List sessions (auth-gated) | | `GET` | `/sessions/:id` | Inspect a session by id (regardless of agent name) | | `GET` | `/sessions/:id/events` | SSE stream by session id | | `GET` | `/approvals` | List approvals across sessions visible to the authenticated tenant. Requires `approval:read`. | | `POST` | `/sessions/:id/approvals/:approvalId/approve` (or `/reject`) | Resolve an approval. | ## Invoke a finite job ```sh curl -sS http://localhost:4317/jobs/summarize \ -H 'content-type: application/json' \ -d '{"text":"Durable agents need durable state."}' ``` Each call receives a new `runId`. Finite jobs exist only under `/jobs`; `/agents/:name/:id` addresses persistent agents. For long-running jobs, admit the run and reconnect through the typed client: ```ts const receipt = await client.jobs.invoke( 'summarize', { text: 'Durable agents need durable state.' }, { wait: false, idempotencyKey: 'summary:document-42' }, ); const run = await client.runs.get(receipt.runId); const recent = await client.runs.list({ job: 'summarize', status: 'running', limit: 20 }); const events = await client.runs.events(receipt.runId, { offset: '0' }); await client.runs.abort(receipt.runId); ``` `runs.list()` is reverse chronological and cursor-based. Node reads the configured shared session store and hydrates each projected run from the durable submission lifecycle before applying status filters. A run visible as `completed` through `runs.get()` is therefore immediately visible to `runs.list({ status: 'completed' })`, even while the terminal projection write is still finishing. Cloudflare reads its tenant-filtered pointer registry while direct run reads continue to use the authoritative per-run Durable Object. `Idempotency-Key` scopes duplicate admission by tenant, authenticated principal, and job. Replaying the same key and payload returns the original run; reusing the key with a different payload returns `409 Conflict`. This prevents one principal from observing or taking over another principal's run. `X-Fabric-Parent-Run` links nested work initiated by an application or worker. The referenced run must exist and belong to the selected tenant; otherwise admission returns `400 Bad Request`. Run reads return `404` across tenant boundaries. ## Durable finite-run behavior Asynchronous finite jobs use the same durable submission store and lease coordinator as persistent agent work. This gives `/runs` consistent behavior across process restarts and multiple replicas: - an idempotent run interrupted by a process crash can be claimed and executed again; - a non-idempotent run interrupted after execution began settles as `failed` instead of silently repeating side effects; - an abort request is persisted, reaches an active `session.prompt()` through its abort signal, and reports the terminal outcome after settlement; - scheduled occurrences use deterministic idempotency keys and appear through the same run status and event routes; - `client.runs.observe()` drains the terminal event tail before returning. Use a shared submission store in multi-replica production deployments. In-memory storage provides the same API contract but cannot preserve work across a full process restart. ## Discover tenant approvals `GET /approvals?status=pending&offset=0&limit=50` is the non-admin discovery surface for deployed applications. It returns only approval states from sessions visible to the authenticated tenant and requires `approval:read`; it does not grant access to `/admin` or other operator APIs. Use the session and approval ids in each item with the existing approve, reject, or vote route. ## Work with a persistent agent Prefer the typed client for admission, settlement polling, history, live observation, and aborts: ```ts import { createFabricClient } from '@fabric-harness/client'; const client = createFabricClient({ baseUrl: 'http://localhost:4317', headers: { authorization: `Bearer ${process.env.FABRIC_HARNESS_API_TOKEN}` }, }); const support = client.agent({ agent: 'support', id: 'account-42', session: 'billing', }); const admitted = await support.send('Where is invoice 1007?'); // This can run in a later process with only the durable submission id. const reply = await support.read(admitted.submissionId, { timeoutMs: 30_000 }); console.log(reply.text); ``` `client.agents.prompt(...)` adds `?wait=true` and waits on the HTTP request. Use it for short compatibility flows, not as the default for durable or long-running work. ## Streaming events (SSE) For persistent agents, `client.agents.updates()` is the preferred stream. It catches up durable records from the requested offset, interleaves transient token and reasoning deltas, reconnects with the latest durable offset, and deduplicates replayed delta event ids. In `live: 'auto'` mode it falls back to offset polling when a deployment does not expose SSE. Start at the offset returned by admission to catch up and then tail without a replay gap: ```sh curl -N 'https://my-app.example.com/agents/support/account-42/stream?session=billing&offset=0' ``` ```text data: {"type":"conversation","offset":"1","records":[{"kind":"entry","entry":{"type":"user_prompt","data":{"text":"Where is invoice 1007?"}}}]} data: {"type":"delta","eventId":"event-17","submissionId":"submission-1","kind":"text","delta":"I found "} data: {"type":"conversation","offset":"4","records":[{"kind":"entry","entry":{"type":"assistant_message","data":{"text":"I found invoice 1007."}}}]} ``` With the typed client: ```ts for await (const update of client.agents.updates( { agent: 'support', id, session: 'billing' }, { offset, live: 'auto' }, )) { if (update.type === 'delta') process.stdout.write(update.delta); else console.log(update.records); } ``` `streamUrl` remains the legacy JSON conversation URL. New clients use `conversationUrl` for durable pages and `updatesUrl` for SSE when the receipt supplies them. For SDK session events rather than conversation records and deltas, omit `offset` or use `GET /sessions/:id/events`. Those events use the [`AgentEvent`](/docs/reference/events) taxonomy. ## WebSocket protocol `WS /sessions/:id/ws` opens a bidirectional WebSocket. Server pushes session events as JSON; the client can send commands back (cancel a task, approve a request, ping). Use this for interactive UIs that need to *send* messages, not just receive — for read-only streams, SSE is simpler and sufficient. The server side requires the optional `ws` peer dep (`pnpm add ws`); browsers and Node 22+ use the platform `WebSocket` natively for the client. ### Connecting ```ts import { connectFabricWs } from '@fabric-harness/sdk'; const handle = connectFabricWs({ url: `ws://localhost:4317/sessions/${id}/ws`, authToken: process.env.FH_AUTH_TOKEN, tenantId: 'tenant-acme', replay: 20, // last N events replayed on connect onEvent: (event) => console.log(event), onReplayEnd: () => console.log('live'), onAck: (ack) => console.log('ack', ack), onError: (err) => console.error(err), onClose: () => console.log('closed'), }); // Send commands back to the server: handle.send({ type: 'cancel', taskId: 'task-123', reason: 'user cancelled' }); handle.send({ type: 'approve', approvalId: 'appr-1', decision: 'approved' }); handle.send({ type: 'ping' }); ``` ### Server messages | `type` | Payload | |---|---| | `event` | `{ event: FabricEvent }` | | `replay-end` | sent once after the initial replay buffer is drained | | `pong` | `{ ts: number }` heartbeat | | `ack` | `{ for: 'cancel' \| 'approve', ok: boolean, message?: string }` | | `error` | `{ message: string }` | ### Client messages | `type` | Payload | |---|---| | `cancel` | `{ taskId: string, reason?: string }` | | `approve` | `{ approvalId: string, decision: 'approved' \| 'denied', reason?: string }` | | `ping` | `{ ts?: number }` | ### Auth + tenancy Browsers can't set headers on a WebSocket upgrade, so auth flows through query params: `?token=&tenant=`. The server validates with the same rules as HTTP (`authToken` / `authTokenEnv` options + `FABRIC_HARNESS_TENANT_REQUIRED=1`). Cross-tenant reads return a single `error` message and close. ### Heartbeats Server sends a `pong` every 15s. After 3 missed pings from the client (45s), the server closes the socket. Clients should pong on intervals or send periodic `ping` messages. ## Voice WebSocket `WS /sessions/:id/voice` opens a bidirectional voice bridge. Server creates an OpenAI Realtime connection on behalf of the client (provider API keys stay server-side). Same auth + tenant pipeline as the chat WS; same `ws` peer dep requirement. Query params customize each connection: `?token=&tenant=&voice=alloy&model=gpt-realtime&audioFormat=pcm16&instructions=`. Server requires `OPENAI_API_KEY` in env; missing → `error` message and immediate close. Use `connectFabricVoice` (in `@fabric-harness/sdk`) for browser/Node clients — see [Voice](/docs/building/voice). ## Webhook trigger gating In **production mode** (`FABRIC_ENV=production` or `NODE_ENV=production`, and `FABRIC_MODE` is **not** `local` or `dev`), the server only exposes jobs and persistent agents that declare `triggers: { webhook: true }`. Other definitions return `403 Forbidden` to public invocation routes. Lift the gate locally with one of: ```sh FABRIC_MODE=local fh dev --target node FABRIC_MODE=dev fh dev --target node # Or simply not running in production mode ``` Behavior matrix: | `FABRIC_MODE` | `FABRIC_ENV` / `NODE_ENV` | Public route exposes | |---|---|---| | `local` or `dev` | any | every registered agent | | (unset) | `production` | only definitions with `triggers.webhook === true` | | (unset) | not production | every registered definition | ## Auth The dev server (`fh dev --target node`) accepts a bearer token in `Authorization: Bearer `. It is optional in local/dev mode. In production, requests other than `/health` and `/ready` fail closed with `401` unless a bearer token or custom `extractAuthToken` authorizer accepts them: ```ts import { startDevServer } from '@fabric-harness/node'; await startDevServer({ authToken: process.env.FABRIC_HARNESS_API_TOKEN, }); ``` Enterprise hosts can instead return a tenant-bound principal and scoped permissions. The same principal becomes the session actor, and the same authorization path protects HTTP and WebSocket requests: ```ts await startDevServer({ authenticate: async (req) => ({ id: await subjectFromVerifiedRequest(req), kind: 'user', tenantId: 'acme', permissions: ['agent:invoke', 'session:read', 'approval:read'], }), authorize: ({ principal, permission }) => permission !== 'admin:read' || principal.roles?.includes('operator') === true, }); ``` See [Authentication and RBAC](/docs/operating/auth) for the permission table, multi-tenant selection, and persistent-instance deletion behavior. Node-derived build targets read the same env var: `FABRIC_HARNESS_API_TOKEN`. In production, leaving it unset does not open the server; protected routes return `401`. ## Rate limiting Production mode enables fixed-window limits automatically. The defaults are 120 requests per minute, with separate budgets for prompts (30), streams and WebSockets (20), channel delivery (120), MCP (60), admin operations (60), and reads (300). Local development remains unlimited unless configured. Override the base or individual route classes with `rateLimit`: ```ts await startDevServer({ rateLimit: { windowMs: 60_000, maxRequests: 100, routes: { prompt: { maxRequests: 20 }, admin: { maxRequests: 10 }, }, }, }); ``` The built-in store is process-local. Multi-replica deployments can use the Redis adapter without adding a Redis SDK dependency to TechFabric Harness: ```ts import { redisHttpRateLimiter, startDevServer } from '@fabric-harness/node'; import Redis from 'ioredis'; const redis = new Redis(process.env.REDIS_URL!); await startDevServer({ httpRateLimiter: redisHttpRateLimiter({ client: { eval: (script, keys, args) => redis.eval(script, keys.length, ...keys, ...args) as Promise, }, }), }); ``` Forwarded IP headers are ignored by default. List the direct ingress addresses when a trusted proxy terminates client connections: ```ts await startDevServer({ trustedProxies: ['10.0.4.12', '10.0.4.13'], }); ``` `trustedProxies: true` trusts any direct peer and is only appropriate when network policy prevents clients from reaching the server without passing through your ingress. ## Error responses | Status | Shape | Cause | |---|---|---| | `400` | `{ error: '...' }` | Bad input (e.g. invalid approval decision) | | `202` | `{ submissionId, streamUrl, offset }` | Persistent input was durably admitted and continues asynchronously. | | `401` | `{ error: { type: 'unauthorized', ... } }` | Missing or wrong bearer token | | `403` | `{ error: { type: 'forbidden', ... } }` | Agent has no webhook trigger in production mode | | `404` | `{ error: 'Not found' }` | Unknown session/agent | | `413` | `{ error: { type: 'body_too_large', ... } }` | Request body exceeded `maxBodyBytes` | | `429` | `{ error: { type: 'rate_limited', ... } }` | Rate limiter rejected the request | | `500` | `{ error: { type: 'internal_error', ... } }` | Uncaught exception | | `501` | `{ error: '...' }` | Endpoint exists but the configured store doesn't support it | ## See also - [Events](/docs/reference/events) — `AgentEvent` taxonomy used by the SSE stream - [Triggers](/docs/reference/triggers) — webhook / schedule / cli trigger declarations - [Persistent agents](/docs/building/persistent-agents) — authoring and delivery lifecycle - [Build and run artifacts](/docs/deployment/build-artifacts) — package this server for deployment - [Deployment → Cloudflare](/docs/deployment/cloudflare) — finite-job Worker surface and current limitations --- # License and attribution Canonical: https://harness.techfabric.com/docs/reference/license Apache License 2.0 terms, third-party attribution, and contribution expectations for TechFabric Harness. TechFabric Harness is distributed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). The repository `LICENSE` file is the authoritative license text. Every published package also carries `LICENSE` and `NOTICE` in its npm tarball and enables npm provenance. The license permits use, modification, and distribution subject to its conditions. Distributions must preserve the license and applicable copyright, attribution, and notice material. Modified files should carry appropriate change notices where the license requires them. Third-party packages retain their own licenses. The documentation renderer, for example, uses MIT licensed Mermaid libraries. Dependency license metadata should be included in release review and software-bill-of-materials output. The release gate packs and installs every public package in a clean project, imports each exported entrypoint, scans the tarballs for credential patterns, rejects incompatible or unresolved runtime licenses, and generates a CycloneDX SBOM. Run it before publishing: ```sh pnpm build pnpm check:release ``` Documentation and examples are maintained as independently authored TechFabric Harness material. Do not submit proprietary code or documentation, or material whose license is incompatible with Apache-2.0. Contributors are responsible for preserving any attribution or `NOTICE` obligations that apply to material they introduce. --- # Live tests Canonical: https://harness.techfabric.com/docs/reference/live-tests Environment-gated integration tests for models, sandboxes, Azure, Databricks, Cloudflare, Docker, and Temporal. TechFabric Harness keeps live provider tests opt-in. Default CI uses mocks and structural tests only; live tests require credentials and are skipped unless their `FABRIC_*_TEST=1` flag is set. A green workflow therefore proves only the steps that actually ran. The public [Validation status](/docs/reference/validation-status) records unconfigured suites explicitly; do not interpret a skipped credentialed step as provider evidence. ## Sandbox providers ### Daytona ```sh FABRIC_DAYTONA_TEST=1 \ DAYTONA_API_KEY=... \ pnpm --filter @fabric-harness/connectors test ``` Optional: ```sh DAYTONA_IMAGE=ubuntu:latest ``` The sandbox jobs create a provider resource, wrap it in `SandboxEnv`, and run `assertSandboxCertification()`. The report verifies shell, binary files, cwd/env, timeout, abort, streaming callbacks, portable refs, reconnect, and cleanup. Credentialed reports are uploaded as JSON CI artifacts without credentials or workspace content. ### E2B ```sh FABRIC_E2B_TEST=1 \ E2B_API_KEY=... \ pnpm --filter @fabric-harness/connectors test ``` Optional: ```sh FABRIC_E2B_PACKAGE=@e2b/code-interpreter E2B_TEMPLATE=... ``` ### Modal The Modal suite creates a native TypeScript SDK sandbox and validates the complete portable contract: ```sh FABRIC_MODAL_TEST=1 \ MODAL_TOKEN_ID=... \ MODAL_TOKEN_SECRET=... \ pnpm --filter @fabric-harness/connectors test ``` ## Azure ### Azure OpenAI ```sh FABRIC_AZURE_OPENAI_TEST=1 \ AZURE_OPENAI_ENDPOINT=... \ AZURE_OPENAI_API_KEY=... \ AZURE_OPENAI_DEPLOYMENT=... \ pnpm --filter @fabric-harness/azure test ``` ### Foundry Agent Service ```sh FABRIC_AZURE_FOUNDRY_TEST=1 \ AZURE_FOUNDRY_PROJECT_ENDPOINT=... \ AZURE_FOUNDRY_AGENT_ID=... \ AZURE_TOKEN=... \ pnpm --filter @fabric-harness/azure test ``` Optional: ```sh FABRIC_AZURE_FOUNDRY_POLL=0 ``` ### ARM tools ```sh FABRIC_AZURE_ARM_TEST=1 \ AZURE_SUBSCRIPTION_ID=... \ AZURE_TOKEN=... \ pnpm --filter @fabric-harness/azure test ``` Optional resources enable individual tests: ```sh AZURE_CONTAINER_APPS_JOB_RESOURCE_GROUP=... AZURE_CONTAINER_APPS_JOB_NAME=... AZURE_AKS_RESOURCE_GROUP=... AZURE_AKS_CLUSTER_NAME=... AZURE_AKS_TEST_COMMAND='kubectl get ns' AZURE_ACI_RESOURCE_GROUP=... AZURE_ACI_CONTAINER_GROUP=... AZURE_ACI_CONTAINER_NAME=... AZURE_ACI_TEST_COMMAND='echo fabric-harness-aci-smoke' ``` ## Databricks Use the package suite for low-level API diagnostics: ```sh FABRIC_DATABRICKS_TEST=1 \ DATABRICKS_HOST=https:// \ DATABRICKS_TOKEN=... \ pnpm --filter @fabric-harness/databricks test ``` Optional resources: ```sh DATABRICKS_WAREHOUSE_ID=... DATABRICKS_CATALOG=main DATABRICKS_SCHEMA=default DATABRICKS_JOB_ID=... FABRIC_DATABRICKS_WAIT_FOR_JOB=1 DATABRICKS_NOTEBOOK_PATH=/Repos/acme/smoke DATABRICKS_CLUSTER_ID=... # optional; omit for serverless notebook execution DATABRICKS_MLFLOW_RUN_ID=... DATABRICKS_WORKSPACE_ROOT=/Repos/acme DATABRICKS_AGENT_SERVICES_TEST=1 DATABRICKS_AGENT_SERVICE_CONNECTION=main.agents.fabric_agent_connection DATABRICKS_AGENT_SERVICE_TEST_PRINCIPAL=fabric-agent-consumers # optional ``` Use the certification gate for release evidence. It covers the App, ResponsesAgent proxy, AI Gateway, SQL and UC allow/deny, AI Search and citation-validated RAG, MLflow managed RAG evaluation, Genie, Feature Serving, Lakeflow, Jobs, serverless notebook execution, Volumes, Lakebase, lineage, Unity Catalog Agent Services lifecycle, System Tables, and cost reconciliation: ```sh pnpm databricks:cert:plan FABRIC_DATABRICKS_PROVISION=1 pnpm databricks:cert:provision pnpm databricks:certify ``` Protected CI runs non-user live gates daily and runs Databricks certification for releases or on demand. User-OBO and two-user evidence is operator-attended until an audited JIT broker exists: maintainers force-refresh two named CLI profiles with the repository runbook command, update the protected Environment through stdin, and dispatch immediately. Scheduled Databricks execution reports the credential window as not configured instead of treating an expired static token as a product regression. Certification records retain only the acquisition mode and remaining lifetime, not token values or user identifiers. See [authoring certification](/docs/databricks/authoring-certification) for the public evidence contract. The rolling workflow remains red until every required calendar day and cross-tier date is present. Whether it passes or fails, it retains `databricks-first-class-rolling.json`; a failed report has status `not-established`, missing dates, observed isolation/dynamic bindings, and redacted validation errors. This diagnostic artifact measures progress but never counts as certification. For a bounded customer evaluation, use the exact-artifact [controlled-pilot gate](/docs/databricks/enterprise-adoption#phase-3--pilot) instead of weakening the rolling standard. The burst gate deliberately reaches the production App's `429` boundary. CI then waits one configured rate-limit window before MLflow validates and deploys the ResponsesAgent proxy. Keep that boundary when adapting the workflow: removing it makes a healthy proxy inherit the load probe's exhausted bucket and turns independent release evidence into an order-dependent test. ## Existing live test families Model providers: ```sh FABRIC_OPENAI_TEST=1 OPENAI_API_KEY=... pnpm --filter @fabric-harness/sdk test FABRIC_ANTHROPIC_TEST=1 ANTHROPIC_API_KEY=... pnpm --filter @fabric-harness/sdk test FABRIC_AZURE_OPENAI_TEST=1 AZURE_OPENAI_API_KEY=... AZURE_OPENAI_ENDPOINT=... pnpm --filter @fabric-harness/sdk test ``` Docker sandbox: ```sh FABRIC_DOCKER_TEST=1 pnpm --filter @fabric-harness/sdk test ``` Temporal: ```sh # Local/dev-server workflow smoke. Requires a reachable Temporal frontend. FABRIC_TEMPORAL_TEST=1 \ FABRIC_TEMPORAL_ADDRESS=localhost:7233 \ pnpm --filter @fabric-harness/temporal test -- integration.test.ts # Real-model Temporal smoke. Requires model/provider credentials too. FABRIC_TEMPORAL_REAL_MODEL_TEST=1 pnpm --filter @fabric-harness/temporal test -- live-model.test.ts ``` When using `temporalio/auto-setup` with Postgres in CI, set `DB=postgres12`, `DB_PORT=5432`, `POSTGRES_SEEDS`, `POSTGRES_USER`, and `POSTGRES_PWD`, then wait for a real Temporal gRPC connection before running tests. TCP port-open checks can pass before Temporal is ready. Cloudflare: ```sh FABRIC_CLOUDFLARE_TEST=1 \ FABRIC_CLOUDFLARE_WORKER_URL=... \ pnpm --filter @fabric-harness/cloudflare test ``` ## CI guidance The protected live workflow uploads a `live-status-*` JSON artifact for optional MCP, direct model, remote sandbox, and channel suites. Each artifact lists configured checks, missing environment variable names, and the job outcome without serializing credential values. `executed-passed` is evidence for that run; `unconfigured` is not. - Keep default CI credential-free. - Run live tests in scheduled or manually triggered workflows. - Use isolated resource groups/workspaces/projects. - Prefer read-only tests unless a test is explicitly validating an execution target. - Clean up provider sandboxes with adapter `cleanup: true` where available. - Never echo tokens or provider SDK objects into prompts, logs, artifacts, or session history. - Retain the executed-step summary or certification artifact with the release. Record a missing credential as `unconfigured`, not `passed`. --- # Migrate from legacy agent APIs Canonical: https://harness.techfabric.com/docs/reference/migrating-legacy-apis Update older TechFabric Harness projects to the current finite and persistent agent contracts. This guide is for projects created before the current agent and route model. The unqualified documentation on this site describes the stable releases listed on [release status](/docs/reference/release-status). ## Builder and workspace changes Finite work now uses `defineAgent()` and lives in `.fabricharness/jobs/`. Persistent, addressable agents use `createAgent()` and live in `.fabricharness/agents/`. ```text .fabricharness/ jobs/ nightly-report.ts agents/ support-agent.ts ``` Replace retired finite builders named `agent()`, `job()`, or `defineJob()` with `defineAgent()`. There are no compatibility aliases in the supported public API. ## Route changes - Invoke a finite definition with `POST /jobs/:name`. - Address a persistent definition with `POST /agents/:name/:id`. - Use `@fabric-harness/client` for typed job invocation, durable submissions, conversation reads, observation, cancellation, and persistent-agent prompts. Code that invokes a finite definition through `/agents/:name/:id` must move to `/jobs/:name`. Treat a `410` response from the retired route as a migration error, not as a retryable failure. ## Runtime and package changes 1. Upgrade the CLI first and run `fh capabilities --json`. 2. Keep the SDK, CLI, Node runtime, and generated template ranges emitted by the same CLI release. 3. Check every optional integration independently; package major versions are not synchronized. 4. Rebuild generated targets instead of copying an older `.fabricharness/build/` directory. 5. Run mock tests before enabling provider credentials or live deployment. The default SDK entry point supplies documented headless defaults. The `@fabric-harness/sdk/strict` entry point preserves explicit finite-agent configuration and does not silently inject those defaults. Recheck imports when migrating Temporal or compliance-sensitive workloads. ## Verification ```sh npx fh --version npx fh capabilities --json npx fh doctor --getting-started --tools --model mock/test-model npx fh agents --json ``` Then run the relevant deployment build and inspect its manifest before promotion. See [build artifacts](/docs/deployment/build-artifacts) and [production readiness](/docs/reference/production-readiness). --- # Migrating to TechFabric Harness 6 Canonical: https://harness.techfabric.com/docs/reference/migration-6 Upgrade custom persistence adapters, clients, and persistent agents to the version 6 durable runtime contract. TechFabric Harness 6 is a coordinated major for `@fabric-harness/sdk`, `@fabric-harness/node`, `@fabric-harness/client`, and `@fabric-harness/cli`. Upgrade those packages together. Adapter packages have independent versions; use the versions released from the same certified commit. ## Conversation stream stores Custom `ConversationStreamStore` implementations must persist and return: - `formatVersion: 1` in `ConversationStreamMeta`; - a stable `incarnation` for one stream generation; - the same incarnation in every producer claim and append fence; - optional fold checkpoints fenced by incarnation and format version. Generate a new incarnation only when a deleted stream is recreated. Reject appends from an older incarnation. Run `defineConversationStreamStoreContractTests` from `@fabric-harness/sdk/testing/contracts` against the adapter. The HTTP and client protocols now emit `stream_checkpoint` updates. When `reset` is true, discard the previous projection and resume from the supplied offset; the React store does this automatically. ## Submission stores Custom `AgentSubmissionStore` implementations must implement the turn-boundary joining methods: - `claimJoinableSubmissions()`; - `finalizeJoinedSubmission()`; - `revertJoiningSubmission()`; - `listJoinedSubmissions()`; - `settleJoinedSubmission()`. Joining transitions are ownership-fenced and atomic. Use `defineSubmissionStoreContractTests` to prove FIFO order, adoption, recovery, and settlement. ## Client deadlines Client HTTP requests now default to a 90-second deadline. For a deliberately longer synchronous compatibility call, set an explicit budget: ```ts const fabric = createFabricClient({ baseUrl: process.env.FABRIC_URL!, requestTimeoutMs: 10 * 60_000, }); ``` Prefer asynchronous admission followed by `wait()`, `read()`, or `updates()` for durable work. Set `requestTimeoutMs: 0` only when an external transport already enforces a bounded deadline. ## Persistent-agent changes Declare submission durability statically in `createAgent()`'s second argument. The host reads this policy before render, so it still applies when rendering or worker recovery fails: ```ts export default createAgent( () => { useModel('anthropic/claude-sonnet-4-6'); return 'Handle the durable request.'; }, { durability: { maxAttempts: 5, timeoutMs: 2 * 60 * 60_000 } }, ); ``` A string `uid` can no longer be combined with `initialData`. Use `uid: null` for create-only admission, or send the existing `uid` without creation data. `useAgentStart()` callbacks run concurrently. Work requiring ordering belongs in one callback. Their state writes and appended signals commit atomically after every callback settles, while appended signals are flattened in callback declaration order. Concurrent writes to the same state key follow callback scheduling, so keep dependent or conflicting writes in one callback. Start and finish callbacks receive `signal`, `harness`, and `log`. Dynamic Native-loop model changes now resolve the provider owning the newly selected model. Hosts with custom model routing should supply `modelProviderResolver`; a deliberately fixed `modelProvider` remains fixed unless a resolver is configured. Return `{ provider, model }` from a custom resolver when the provider expects a normalized model id rather than the rendered `provider/model` reference. Static `createAgent()` policy remains authoritative across hook refreshes. Custom persistent hosts must preserve the static definition when they re-render dynamic capabilities; dropping it can remove approval and capability constraints and is unsupported. --- # Policies and Approvals Canonical: https://harness.techfabric.com/docs/reference/policies-approvals Capability policies and approval flows, where each is declared, and which one is consulted at the moment an agent acts. Policies are enforced at tool dispatch and, by default, at the sandbox boundary. Definition-level policies act as a security floor: invocation code may narrow access but cannot replace allowlists or remove denials. ## Available controls - **Scoped commands.** Agents declare commands per call (`commands: [...]`). Anything else is a capability error. - **Capability-aware tools.** `write` and `edit` honor any filesystem write scope on the session. - **Approvals.** `session.approval.request({ reason, risk, timeoutMs })` waits durably (Temporal target) or in-process (inline runtime). The capability policy block can be set on a finite job, `init()`, a session, or one prompt: ```ts import { init, policiedFetch, type CapabilityPolicy } from '@fabric-harness/sdk'; const policy: CapabilityPolicy = { filesystem: { read: ['/workspace/**'], write: ['/workspace/src/**', '/workspace/tests/**'], writeDeny: ['/etc/**', '/usr/**'], writeRequireApproval: ['**/.env*'], }, commandPolicy: { allow: ['npm test', 'git diff', 'git status'], requireApproval: ['git push*', 'rm -rf*'], }, network: { mode: 'allowlist', hosts: ['api.openai.com', '*.anthropic.com', 'api.github.com'], protocols: ['https:'], // defaults to ['http:', 'https:'] }, approvals: { defaultTimeoutMs: 5 * 60_000 }, }; const fabric = await init({ policy }); ``` ### Network policy The `network` block is enforced only for HTTP routed through the SDK's `policiedFetch` helper or a connector that uses it. It does **not** monkey-patch global `fetch`, Axios, third-party SDKs, raw sockets, DNS, or subprocess traffic. A custom tool using one of those paths can bypass the application policy unless you explicitly route it through the policy-aware transport. Wrap every custom `fetch`-like transport: ```ts const safeFetch = policiedFetch(fetch, policy); await safeFetch('https://evil.example.com'); // → throws FabricError { code: 'POLICY_DENIED', ... } ``` For Axios, supply an adapter backed by a policy-aware Fetch implementation, or put the entire agent behind an egress proxy. For production workloads, pair application checks with a container, cluster, or cloud-provider network boundary and call `assertEnforceableNetworkPolicy()` during startup. See [private networking and egress](/docs/operating/private-networking). Modes: - `'allowlist'` — only hosts matching the `hosts` glob list are permitted (default when `hosts` is set). - `'denylist'` — listed hosts are blocked, everything else allowed. - `'none'` — block all outbound network. Useful for sandboxed analysis agents. ### Mount permissions `session.mount(mountAt, source, { mode: 'read' | 'write' })` (read by default) marks a mount as immutable. Write tools (`write`, `edit`, `mkdir`, `rm`) targeting paths under it are rejected by capability policy at the tool-call layer. ### Sandbox-layer enforcement (v0.10+) By default, `init({ policy })` auto-wraps the session's `SandboxEnv` with `policiedSandboxEnv()` so that raw `sandbox.exec` / `sandbox.writeFile` / `sandbox.readFile` calls from inside agent code honor the same `CapabilityPolicy` as tool dispatch. Without this, agent code that called `(await session.sandbox).exec('rm -rf /')` would bypass the policy that would have blocked the equivalent `session.shell()` call. Pass `bypassPolicyEnforcement: true` to `init()` if you have your own enforcement layered above (egress proxy, custom tools, etc.). ```ts import { init } from '@fabric-harness/sdk'; import { policiedSandboxEnv } from '@fabric-harness/sdk/experimental'; const fabric = await init({ policy: { commandPolicy: { deny: ['rm -rf*'] }, filesystem: { writeDeny: ['/etc/**'] }, }, }); const session = await fabric.session(); const sandbox = await session.sandbox; // This now throws COMMAND_DENIED — the same policy that gates session.shell(). await sandbox.exec('rm -rf /tmp/data'); ``` The decorator throws `COMMAND_DENIED` for exec violations and `POLICY_DENIED` for filesystem violations. `requireApproval` patterns at the sandbox layer surface as denials with `details.approvalRequired: true` — the sandbox layer doesn't auto-resolve approvals because it has no session context. Use `session.shell()` / tool calls when you want approvals gated through the full machinery. ## Where to put policy - **Per prompt** — `session.prompt(text, { commands, policy })`. - **Per session** — `agent.session(id, { policy })`. - **Per finite agent** — `defineAgent({ policy, run })`; this is a security floor for `run()` calls to `init()`. - **Per persistent agent** — return `{ policy }` from `createAgent(({ id }) => ({ ... }))`. - **Shared application default** — pass `policy` to `init()` or merge a policy module from `.fabricharness/policies/` in your own config. See [Enterprise controls](/docs/building/enterprise-controls) for a complete definition-level example with tools, approvals, and cost budgets. ## Approvals from the CLI ```sh fh approvals --pending fh approve --actor preetham fh reject --actor preetham --reason "Wrong branch" # Deployed application: discover across the authenticated tenant fh approvals --url "$FABRIC_HARNESS_APP_URL/api" --token-env FABRIC_HARNESS_REMOTE_TOKEN ``` When a model provider omits its own tool-call id, Harness creates a unique id for each logical call and reuses it across approval binding, lineage, tool context, and session history. Two calls to the same tool in one session therefore cannot share an approval grant or idempotency identity by accident. See [Approvals](/docs/building/approvals) and [`fh approvals`](/docs/cli/approvals). --- # Production Readiness Checklist Canonical: https://harness.techfabric.com/docs/reference/production-readiness What to validate before you run TechFabric Harness agents in production, written as the list we actually work through. Use this checklist to validate the exact runtime, providers, credentials, policies, and stores in your deployment environment. Generated Node artifacts use the shared v2 server; hosted targets add their own identity, networking, quota, and recovery requirements. ## Release baseline Before promoting a release: - Review [Validation status](/docs/reference/validation-status), pin the exact package set, and list every capability the client pilot will enable. A passing workflow with skipped credentialed steps is not live provider evidence. - Run `pnpm install --frozen-lockfile`. - Run `pnpm run check`. - Run `pnpm run build`. - Run `pnpm run test`. - Run the package suites with constrained concurrency if the workspace-wide parallel run times out; the current Databricks App persistence and CLI dev-banner tests are sensitive to full-workspace contention. - Pack publishable packages and inspect manifests for semver dependency ranges, not `workspace:*`. - Install `@fabric-harness/sdk@latest`, `@fabric-harness/node@latest`, and `@fabric-harness/cli@latest` in a clean ESM consumer project. - Run the downstream template mock suite against the release candidate version before publishing. - Keep downstream templates on exact package versions and update those pins only after the packed artifact and registry compatibility gates pass. - Verify `fh --help`, SDK subpath imports, and CommonJS resolution of those subpaths through `require.resolve` when CJS-based tooling is in the deployment. - Deploy the Fumadocs site and verify `https://harness.techfabric.com/docs` plus `llms.txt`. ## Choose a deployment path 1. Start with the `node` target and `virtual` sandbox for simple support/routing/extraction agents. 2. Use `local` only when CI/repo automation intentionally needs host tools. 3. Use Docker sandbox for untrusted shell or data-analysis work. 4. Use Temporal for long-running tasks, approval delays, and restart durability. 5. Use Cloudflare for edge and serverless workloads after running the account smoke test. 6. Run the documented environment validation for AKS, ACA, Databricks, E2B, Daytona, and Modal. 7. Use policies and approvals for every mutating command, tool, or external integration. 8. Put definition-wide enforcement controls on `AgentDefinition`; call-level policy may add restrictions but cannot loosen the definition policy or budget. ## Security gate - Define explicit filesystem, command, tool, and network policies. - Prefer deny-by-default command and network policy for unattended agents. - Route risky actions through `requireApproval` or custom approval rules. - Store secrets outside prompts and logs; verify redaction on representative failures. - Prefer Docker or a remote sandbox for untrusted code. Avoid host-local sandbox for untrusted workloads. - Configure tenant IDs when running multiple users/customers through the same deployment. - Return explicit principal permissions from `authenticate`; do not rely on the unrestricted legacy compatibility principal. - Grant operator-console users only the required `admin:read`, `session:abort`, and `session:delete` scopes. - Protect the default branch with pull-request review and blocking CI. Restrict secret-bearing GitHub Environments to protected branches or release tags and disable administrator bypass. - Run `pnpm check:github-actions`; require the current supported Node 24-native action majors, keep self-hosted runners current, and review weekly GitHub Actions Dependabot updates. Do not use `ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION` to prolong an obsolete action runtime. ## Runtime gate - Set request body limits, auth, and rate limits for every public HTTP surface. - Use durable session stores for production deployments; avoid in-memory stores outside tests. - Back up session/artifact stores according to your recovery objectives. - Verify cancellation, retry, and timeout behavior on your target runtime. - For Temporal, test worker restart, workflow retry, approval delay, and namespace/auth configuration. ## Observability gate - Export traces through OpenTelemetry, App Insights, Langfuse, or your chosen collector. - Track token usage, cost, duration, tool calls, approvals, and task lifecycle events. - Add dashboards/alerts for model failures, budget exhaustion, approval timeouts, rate limits, and sandbox failures. - Keep audit exports for compliance-sensitive agents. ## Hosted integration gate Run credentialed tests for every backend in the deployment: - Real model provider smoke tests. - Docker sandbox execution. - Postgres/Redis/session stores under expected concurrency. - Temporal local or cloud namespace tests, using a real gRPC readiness probe before integration tests. - Cloudflare Worker/R2 deployment smoke tests, including Shell Workspace `code` tool execution when using `mode: 'shell-workspace'`. - Azure OpenAI, Foundry, AKS, ACA, or ARM tests as applicable. - Databricks App deploy, Model Serving, SQL, Jobs, Volumes, AI Search, Genie, Lakeflow, Feature Serving, OBO scope/denial, Lakebase, and System Tables through the certification evidence runner. - For a shared Databricks App, require two-user session-isolation evidence and one complete OBO token expiry/refresh cycle. Confirm the generated `sql`, `genie`, and `model-serving` scopes are consented. - Require MLflow tracing in App readiness and an AI Gateway inference table on the ResponsesAgent endpoint. Use the App HTTP limiter because Databricks agent endpoints do not support Gateway rate limits. - E2B, Daytona, Modal, Kubernetes, or other sandbox provider tests as applicable. ## API and release policy gate For every public release: - Publish and follow a SemVer/deprecation policy. - Document supported subpaths, deployment requirements, and behavioral constraints clearly. - Provide migration guides for minor versions with behavioral changes. - Generate public API reference from JSDoc. - Keep example projects runnable against the published npm packages. - Use the protected `sdk` release scope when an independently versioned SDK/CLI package cut must ship while a separate Databricks candidate is awaiting live certification. The scope publishes the SDK before the CLI consumer and cannot include the Databricks package. Record the command output, artifact digest, configuration version, and credentialed test evidence with the release. For Databricks, use the [authoring certification guide](/docs/databricks/authoring-certification) and certification evidence file. --- # Connector Recipes (`fh add`) Canonical: https://harness.techfabric.com/docs/reference/recipes Pipe Markdown connector recipes into your coding agent and have it scaffold a TechFabric Harness sandbox, MCP or data adapter into your project. `fabric-harness add` (alias `fh add`) supports direct scaffold recipes and TTY-aware Markdown connector guides. Use a scaffold when Fabric owns the file shape; use a guide when provider SDK versions, authentication, or project conventions need local adaptation. Recipes today are thin wiring on top of the package helpers — the package owns the tested implementation, the recipe wires it into your specific project layout, env vars, and lifecycle. For most providers you can also import the helper directly without scaffolding (see [Connector catalog](/docs/building/connector-catalog)). ## Common usage ```sh # List all available recipes (and the agent the CLI auto-detected for you) fh add fh add --json # Scaffold implementation + env example + test fh add slack fh add modal fh add channel slack fh add channel discord fh add database postgres fh add databricks lakebase fh add lakehouse fh add sandbox e2b --dir ./service fh add policy safe-defaults fh add channel slack --no-install fh add channel slack --dry-run # Review and apply a managed upgrade fh update slack --dry-run fh update channel slack --dry-run fh update channel slack # Pipe a known recipe to your coding agent fh add daytona | claude fh add github-mcp | codex fh add discord --install-deps | codex fh add mintlify-mcp | cursor-agent fh add fumadocs | aider # Build a brand-new connector from a provider's docs URL fh add https://e2b.dev --category sandbox | claude # Print the markdown without piping (for inspection) fh add daytona --print ``` For a unique managed alias, `fh add ` installs the recipe. Use `--print` to request the legacy Markdown guide explicitly. Names without a managed recipe retain the TTY-aware guide behavior. ## Categories Direct scaffold kinds: | Kind | Current recipes | | --- | --- | | `channel` | 18 maintained provider adapters plus generic webhook | | `database` | Postgres, MySQL, MongoDB, Redis, SQLite, libSQL, Turso, Supabase, Valkey | | `sandbox` | Daytona, E2B, Modal, Vercel, Cloudflare Sandbox, Cloudflare Shell (shipped adapters); Boxd, exe.dev, Islo, Mirage, smolvm (community blueprints — no shipped adapter) | | `databricks` | core, sql, lakebase, ai-search, rag-chain, lakeflow, jobs, bundle, system-tables-cost, apps, agent-services, genie, managed-mcp, analyst (see [Databricks recipes](/docs/databricks/recipes)) | | `tooling` | Braintrust, Jetty, OpenTelemetry, Sentry, Vitest Evals | | `model-provider` | OpenAI, Azure OpenAI | | `skill` | Analyze table | | `policy` | Safe defaults | Connector-guide categories: The Markdown recipes are grouped into four categories that map to TechFabric Harness primitives: | Category | Maps to | Examples | |---|---|---| | `sandbox` | `SandboxFactory` | Daytona, E2B, Modal, Vercel Sandbox | | `mcp` | `connectMcpServer` | GitHub, Linear, Mintlify, Slack | | `kb` | `FilesystemSource` | Fumadocs (also `localDirectorySource`, `r2FilesystemSource`, `s3FilesystemSource`, `azureBlobFilesystemSource`, `httpFilesystemSource` in the SDK) | | `data` | `Command` / `ToolDef` | Postgres, Notion REST | | `channel` | `Channel` + outbound `ToolDef` | Discord, Messenger, Slack, Stripe, Teams, and the remaining channel catalog | | `database` | Scoped data tools and first-party unified persistence | libSQL/Turso, MongoDB, MySQL, Redis/Valkey, Supabase/Postgres | | `tooling` | Event/eval integration | Braintrust, Jetty, OpenTelemetry, Sentry, Vitest evals | ## Auto-detected coding agents `fh add` detects the agent you're running under and shows the matching pipe hint: | Detected | Pipe hint | |---|---| | Claude Code (`CLAUDE_CODE`, `CLAUDE_PROJECT_DIR`) | `\| claude` | | OpenAI Codex (`CODEX_AGENT`, `CODEX_HOME`) | `\| codex` | | Cursor Agent (`CURSOR_AGENT`, `CURSOR_TRACE_ID`) | `\| cursor-agent` | | Aider (`AIDER_RUNNING`) | `\| aider` | | OpenCode (`OPENCODE`) | `\| opencode` | | (none detected) | `\| claude` (canonical default) | Override by passing `--print` and piping yourself. ## Versions and safe updates Direct scaffolds declare aliases, a positive recipe version, compatible package ranges, managed files, upgrade notes, and package-manager-specific verification commands. Generated TypeScript and Markdown begin with `fabric-harness-recipe: /@`. `fh update` reads those markers and creates a complete plan before changing the project. It adopts unmarked legacy files only when they exactly match generated content, stops on user modifications, preserves compatible dependency ranges, and rejects ranges that cannot overlap the recipe contract. Use `--dry-run --json` in CI or automation. ## URL-form recipes When you pass a URL instead of a known recipe name, `fh add` emits a generic "scaffold a connector from these docs" prompt. The agent then fetches the URL and writes the adapter: ```sh fh add https://docs.modal.com --category sandbox | claude fh add https://api.intercom.io --category data | codex ``` The receiving agent gets: 1. The docs URL. 2. The category (so it knows whether to produce a `SandboxFactory`, `connectMcpServer` call, `FilesystemSource`, or `Command`/`ToolDef`). 3. A short template showing the file shape and the `secret()` pattern for credentials. ## Where the recipes live Direct scaffold recipes are typed definitions and ship with the CLI. Connector guides are Markdown files with local and bundled lookup: Recipes are Markdown files in `connectors/` at the repo root. The CLI looks for them in: 1. The user's current project (walking up to find `./connectors/.md`) 2. The CLI's own bundled copy (when developing this repo locally) The installed CLI's managed recipes work without cloning the source repository. Repository-only guides and authoring files require [source access](/docs/reference/source-access); public documentation does not link to the restricted raw GitHub origin. ## Authoring a new recipe 1. For a direct scaffold, add a typed recipe with a version, dependency ranges, managed files, and a verification command. 2. For a guide, create `connectors/--.md`. Use the existing guides as templates: short, agent-friendly, no secrets. 3. Add guide metadata to `CONNECTOR_RECIPES` in `packages/cli/bin/fabric-harness.ts`. 4. Add clean-install and update/conflict fixtures when changing generated files or dependencies. 5. Open a change through the authorized source workflow. Once released, the direct recipe alias and its bundled guide are available from the installed CLI. ## See also - [Filesystem sources](/docs/reference/filesystem-sources) — the `kb` category primitives - [MCP](/docs/reference/mcp) — the `mcp` category primitives - [Capability matrix](/docs/reference/capability-matrix) — what each connector type lets the agent do --- # Release and documentation status Canonical: https://harness.techfabric.com/docs/reference/release-status Current TechFabric Harness package versions, Node.js requirements, documentation scope, and migration links. import { ReleaseStatus } from '@/components/release-status'; This site documents the currently published TechFabric Harness contracts. Package families are versioned independently, so matching major numbers are not a compatibility guarantee. New projects should be created with `@fabric-harness/cli@latest`, which pins a compatible set of packages. Published does not mean that every optional managed provider ran in the latest protected suite. Use [Validation status](/docs/reference/validation-status) to separate deterministic contract coverage, credentialed provider evidence, deployment conformance, and exact-package certification. ## Runtime requirements - **Core minimum:** Node.js 20.18 or newer for the SDK, CLI, Node runtime, and most optional integrations. - **Recommended:** Node.js 22 LTS for new projects and framework development. - **Databricks:** Node.js 22 or newer is required by `@fabric-harness/databricks`. - **Feature-specific:** APIs that depend on the platform `WebSocket` or built-in `node:sqlite` may require a sufficiently recent Node 22 release. The relevant feature page calls this out. The root monorepo uses Node.js 22 or newer for maintenance and release work. That contributor requirement is stricter than the minimum engine supported by the core published packages. ## Documentation version Unqualified guides on this site describe the stable package versions shown above. Historical version numbers appear only in clearly labeled migration or certification records. Databricks evidence pages identify the exact package used for a protected workspace run because that evidence does not automatically transfer to another release. For a project you already have, run: ```sh npx fh --version npx fh capabilities --json npm view @fabric-harness/sdk version engines --json ``` Use [the compatibility contract](/docs/cli/compatibility) to negotiate behavior rather than assuming that a version number alone proves a feature is present. ## Upgrading - [Install or update TechFabric Harness](/docs/getting-started/installation) - [Migrate from legacy agent APIs](/docs/reference/migrating-legacy-apis) - [Check CLI capability compatibility](/docs/cli/compatibility) - [Review Databricks compatibility evidence](/docs/databricks/compatibility) - [Review current client-pilot validation evidence](/docs/reference/validation-status) Each package name in the table links to its public npm release history. Detailed, commit-level changelogs are maintained in the restricted source repository and are available to authorized customers and partners; see [source access](/docs/reference/source-access). --- # Runtime modes Canonical: https://harness.techfabric.com/docs/reference/runtime-modes inline (default), stateless (headless), and temporal (durable). When to use each. `init({ runtime })` accepts three values. Runtime is independent from the SDK import entrypoint: agents from both `@fabric-harness/sdk` and `@fabric-harness/sdk/strict` use the shared session primitives, while runtime controls persistence and durability. | Mode | Default? | Persistence | Use when | | --- | --- | --- | --- | | `inline` | yes for direct `init()` calls | In-memory by default; pluggable `SessionStore` (SQLite/Postgres/file) for durability | You want conversation continuity, artifact persistence, approval gating, and CLI tooling like `fh sessions`/`fh inspect`. | | `stateless` | default injected by bare-import `defineAgent()`; explicit opt-in otherwise | None. Each invocation is independent. | High-volume webhooks, edge runtimes, or prototypes where state would just be discarded. | | `temporal` | no — explicit opt-in | Durable workflow state via Temporal. | Long-running, restartable, multi-day agents that must survive crashes or human approval delays. Requires `@fabric-harness/temporal`. | ## inline (default) ```ts import { init } from '@fabric-harness/sdk'; const agent = await init({ model: 'openai/gpt-5.5', // runtime: 'inline' — implicit }); ``` In-memory `InMemorySessionStore` is used unless you pass `store`. History, artifacts, and approval state live for the lifetime of the process. Pass a real store when you need persistence: ```ts import { FileSessionStore } from '@fabric-harness/node'; const agent = await init({ model: 'openai/gpt-5.5', store: new FileSessionStore({ rootDir: '.fabricharness/sessions' }), }); ``` ### Production safety In production (`FABRIC_ENV=production` or `NODE_ENV=production`), `inline` without an explicit `SessionStore` emits a warning. The runtime still runs — you just lose state on restart. To silence the warning, either: - Configure a `SessionStore` (recommended). - Set `FABRIC_ALLOW_EPHEMERAL_STATE=1` to acknowledge in-memory state explicitly. - Use `runtime: 'stateless'` to opt into ephemeral semantics on purpose. ## stateless (headless) ```ts import { init } from '@fabric-harness/sdk'; const agent = await init({ model: 'openai/gpt-5.5', runtime: 'stateless', }); ``` The session uses `NoopSessionStore` — every write is discarded, every read returns the empty initial state. Use this for: - Webhook handlers where the response is the only output. - Cloudflare Workers / Vercel Edge where there's no durable storage attached. - Prototypes where you don't yet care about conversation continuity. ### What stateless disables - Session entry / event persistence. - Artifact persistence (`session.artifact(...)` falls back to a fingerprint-only `ArtifactRef` with no stored bytes). - Approval waiting via the store. Approvals only work in stateless mode if you pass an `onApproval` callback that returns a synchronous decision. - `fh sessions`, `fh inspect`, `fh logs` will not show stateless runs. If any of those matter, stay on `inline` and configure a store. ## temporal (durable) There are two ways to put an agent on the Temporal runtime — the **direct API** (recommended) and the **CLI-managed** flow. ### What recovery looks like Durability is demonstrated by an interrupted run, deterministic replay, stable idempotency, and a terminal result without repeating the external effect. A normal uninterrupted success does not establish that contract. ### Direct API Wire `temporalSessionRuntime` into `init()` so each `prompt`/`task`/`shell`/`checkpoint.*` routes through Temporal workflows: ```ts import { init } from '@fabric-harness/sdk'; import { temporalSessionRuntime } from '@fabric-harness/temporal'; const fabric = await init({ runtime: 'temporal', sessionRuntime: temporalSessionRuntime({ address: 'localhost:7233', namespace: 'default', taskQueue: 'fabric-harness', }), }); const session = await fabric.session(); await session.prompt('Triage issue #42'); ``` The Temporal client connection is opened lazily on the first session and shared across all sessions produced by the factory. For tests, pass `mode: 'mock'` to use the in-process mock runtime. ### CLI-managed When running under `fabric-harness run --target temporal-worker`, the CLI constructs the Temporal session for you and you only declare the runtime mode: ```ts import { init } from '@fabric-harness/sdk/strict'; const fabric = await init({ runtime: 'temporal' }); ``` Sessions execute as Temporal workflows. The agent code is unchanged — the runtime adapter handles checkpointing, retries, and resume. See [Temporal worker deployment](/docs/deployment/temporal-worker) for setup. Temporal mode requires `@fabric-harness/temporal`, a Temporal cluster (or the bundled mock for tests), and a worker process running `fh temporal-worker`. ## Switching modes Modes are runtime-only. They are separate from the minimal vs complete import entrypoints and separate from deploy targets. Nothing in your agent code changes when you swap: ```ts const dev = await init({ runtime: 'stateless' }); // dev / preview const prod = await init({ runtime: 'inline', store: pgStore }); // prod web const longJob = await init({ runtime: 'temporal' }); // batch / nightly ``` Configure runtime at deploy time via `FABRIC_RUNTIME` env or your `.fabricharness/config.ts`. The agent file stays the same. ## See also - [SDK entrypoints, runtimes, and targets](/docs/reference/sdk-entrypoints-runtimes-targets) — the full conceptual split. - [Headless agents with the minimal entrypoint](/docs/getting-started/headless-mode) — the progressive-disclosure walkthrough. - [Session stores](/docs/reference/session-stores) — pluggable persistence options. - [Temporal worker deployment](/docs/deployment/temporal-worker) — setting up the worker. --- # Sandbox lifecycle Canonical: https://harness.techfabric.com/docs/reference/sandbox-lifecycle Auto-suspend, snapshot/fork, and sandbox refs — managing long-running compute durably. Long-running sandboxes (AKS pods, E2B sandboxes, Daytona workspaces) cost money while they are idle. TechFabric Harness provides suspend, reconnect, snapshot, restore, and fork primitives so applications can reclaim compute without losing state. ## Auto-suspend on idle Pass `idleSuspendMs` to `init()` (or any sandbox factory option). After that many milliseconds with no operation, the sandbox is suspended. The next operation transparently resumes it. ```ts import { init } from '@fabric-harness/sdk'; const fabric = await init({ sandbox: 'docker', idleSuspendMs: 5 * 60_000, // suspend after 5 minutes idle autoResumeOnAccess: true, // default — auto-resume on next call }); ``` Backends that don't implement `suspend()` / `resume()` ignore the option (no-op pass-through). Currently supported: | Backend | Native support | |---|---| | `daytonaSandbox` | Yes, via `stop` / `start` | | `e2bSandbox` | Yes, via `pause` / `resume` | | `modalSandbox` | No native suspend | | `kubernetesSandbox` / `aksSandbox` | No automatic scale-to-zero | | `local` / `docker` / `empty` / `virtual` | Not applicable | ### How it works `createSandboxEnv()` wraps the env in a `SuspendingSandboxEnv` decorator when `idleSuspendMs > 0` and the inner env supports `suspend()`. The decorator: 1. Tracks `lastAccess` on every operation. 2. Schedules a `setTimeout` for `idleSuspendMs` from the last access. 3. Calls `inner.suspend()` when the timer fires. 4. On the next op, calls `inner.resume()` first (auto), then dispatches. 5. Clears the timer in `cleanup()`. The timer is `unref()`'d so it never keeps the Node process alive on its own. ### Manual control You can call `session.sandbox.suspend()` / `resume()` directly when capability is reported: ```ts const sandbox = await session.sandbox; if (sandbox.capabilities?.suspend) { await sandbox.suspend(); } ``` ### Strict mode Set `autoResumeOnAccess: false` to receive a `FabricError` (`SANDBOX_UNAVAILABLE`) instead of transparent resume. Useful when you want to explicitly gate operations on suspension state. ## Snapshot and fork `session.fork(label?)` captures the sandbox state and returns a `SandboxFork` handle. Calling `fork.attach()` spins up an independent session whose sandbox is a fork of the captured state — writes in branch A are invisible to branch B and to the origin. ```ts const session = await fabric.session('experiment'); await session.shell('npm install && npm test'); const fork = await session.fork('after-install'); // Run two parallel experiments from the same checkpoint: const branchA = await fork.attach(); const branchB = await fork.attach(); await Promise.all([ branchA.shell('node bench.js --variant fast'), branchB.shell('node bench.js --variant safe'), ]); ``` ### Capability ```ts const sandbox = await session.sandbox; if (sandbox.capabilities?.fork) { // session.fork() will work } ``` ### Backend support | Backend | Fork supported | |---|---| | `empty` / `virtual` | In-memory snapshot clone | | `local` | On-disk snapshot copied to a fresh workspace temp directory | | `docker` | On-disk snapshot copied to a fresh container workspace | | `e2bSandbox` / `modalSandbox` (provider-managed) | Uses `RemoteSandboxApi.fork()` when the provider supports start-from-snapshot | | `daytonaSandbox` | No; Daytona does not expose start-from-snapshot | | `databricksSqlSandbox` | No; SQL execution is stateless | | `cloudflareSandbox` | Use Durable Object state and R2 artifacts instead of sandbox forks | `session.fork()` throws `FabricError { code: 'SANDBOX_UNAVAILABLE' }` when the sandbox doesn't support fork. ### Cleanup Each forked session owns its own sandbox; calling `branch.sandbox.cleanup()` (or letting it fall out of scope) tears down only that branch. The origin is unaffected. For local/docker, fork creates a fresh temp workspace directory — the fork's `cleanup()` removes it (Docker) or leaves it for caller responsibility (Local). The shared `snapshotRoot` is **not** auto-removed; that's intentional so other forks of the same snapshot remain attachable. ## Sandbox refs Sometimes you want two sessions sharing the *same running sandbox* — not a fork, the actual instance — for multi-agent coordination, observability shadowing, or test isolation. `session.sandboxRef()` returns an opaque handle; pass it to `attachSandbox(ref)` in another session to participate in the same sandbox without taking ownership of its lifecycle. ```ts import { init, attachSandbox } from '@fabric-harness/sdk'; // Owner: creates the sandbox, owns cleanup. const ownerAgent = await init({ sandbox: 'docker', cwd: '/tmp/work' }); const owner = await ownerAgent.session('orchestrator'); await owner.shell('npm install'); const ref = await owner.sandboxRef(); // Attached: shares the same sandbox, does NOT own cleanup. const workerAgent = await init({ sandbox: attachSandbox(ref) }); const worker = await workerAgent.session('worker-1'); await worker.shell('npm test'); // runs in owner's sandbox // worker.cleanup() is a no-op for the underlying sandbox. // owner.cleanup() tears down for everyone. ``` ### Lifecycle rules - The first session to register a ref is the **owner**. Owner cleanup tears down the underlying sandbox. - Any session can `attachSandbox(ref)` to participate. Attached sessions are **non-owning**: their cleanup unregisters the attachment but doesn't touch the underlying sandbox. - After the owner cleanup, attached sessions see `FabricError { code: 'SANDBOX_UNAVAILABLE' }` on subsequent operations. The error message says "no longer alive (owner cleanup ran)" so debugging is unambiguous. - `session.sandboxRef({ portable: true })` returns a cross-process reference when the backend supplies `encodeRef()`. The receiving worker registers the provider decoder and calls `attachSandbox()`. ### When to use - **Multi-agent coordination**: an orchestrator and a worker both operating on the same workspace. - **Observability shadow**: a metrics/log-collecting session attached to a primary session's sandbox. - **Test scaffolding**: a setup phase that pre-populates a sandbox and hands the ref to the test session. When you want **independent branches** instead, use `session.fork()` (Phase B) above. Forks copy state at a point in time; refs share live state. ## Continuity negotiation Use `negotiateSandboxContinuity()` before selecting a recovery strategy. It reports reconnect, snapshot, restore, and fork separately, and returns `modes: ['none']` when the backend cannot preserve state. ```ts import { negotiateSandboxContinuity } from '@fabric-harness/sdk'; const continuity = negotiateSandboxContinuity(await session.sandbox); if (continuity.reconnect) { const ref = await session.sandboxRef({ portable: true }); await durableStore.put(`sandbox:${session.id}`, ref); } ``` ## Worker rotation Portable references include the owning tenant. A mismatched tenant is rejected before TechFabric Harness calls the provider decoder. Durable workers should also use one ownership lease store shared by every replica: ```ts import { attachSandbox } from '@fabric-harness/sdk'; import { postgresSandboxOwnershipLeaseStore } from '@fabric-harness/node'; const factory = attachSandbox(ref, { tenantId: principal.tenantId, ownership: { store: postgresSandboxOwnershipLeaseStore(pg), ownerId: process.env.HOSTNAME!, leaseMs: 60_000, }, }); const sandbox = await factory({ sessionId }); ``` The lease is renewed at every sandbox operation. Once another worker claims an expired lease, the former worker cannot continue. Temporal activity adapters persist and recover portable references automatically when `sandboxOwnership` is configured. ## Reference - `SandboxEnv.suspend?(): Promise` - `SandboxEnv.resume?(): Promise` - `SandboxEnv.fork?(snapshot): Promise` - `SandboxCapabilities.suspend?: boolean` - `SandboxCapabilities.resume?: boolean` - `SandboxCapabilities.fork?: boolean` - `SandboxCapabilities.reconnect?: boolean` - `SandboxFactoryOptions.idleSuspendMs?: number` - `SandboxFactoryOptions.autoResumeOnAccess?: boolean` - `FabricSession.fork(label?): Promise` - `SandboxFork.attach(options?): Promise` - `FabricSession.sandboxRef(): Promise` - `attachSandbox(ref, options?): SandboxFactory` - pass to `init({ sandbox })`. - `negotiateSandboxContinuity(sandboxOrRef)` - inspect recovery modes. - `registerSandbox(env, options?)` / `unregisterSandbox(refId)` — direct registry access for advanced cases. - `SuspendingSandboxEnv` (class) — the suspend/resume decorator. Exported from `@fabric-harness/sdk/experimental`. - `withIdleSuspend(env, { idleSuspendMs })` — helper that wraps when applicable, returns env unchanged otherwise. Exported from `@fabric-harness/sdk/experimental`. --- # Sandboxes matrix Canonical: https://harness.techfabric.com/docs/reference/sandboxes-matrix Every supported sandbox backend at a glance — what it gives you, the example, and the one-liner to enable it. A sandbox is where shell commands and tool calls execute. It's chosen at `init({ sandbox })` and is **independent** of which SDK entrypoint you import from and which runtime you select. | Sandbox | What it gives you | Enable with | Example | |---|---|---|---| | `virtual` (default) | In-memory FS + bash subset (`grep`, `glob`, `read`, `cat`, `mkdir`, `rm`, `echo`) via [`just-bash`](https://github.com/vercel-labs/just-bash). No host shell access. | injected by default; `init({ sandbox: 'virtual' })` to be explicit | `examples/hello-world/` | | `local` | Host filesystem and host shell, confined to the session's workspace root (outside paths denied with `SANDBOX_ESCAPE_BLOCKED`; extra roots via `allowedPaths`). | `init({ sandbox: 'local' })` | `examples/with-local-shell/` | | `docker` | Per-session Docker container; reads/writes scoped to the container. | `init({ sandbox: { backend: 'docker', image: 'node:22' } })` | `examples/with-docker/` | | `cloudflare` | Cloudflare Sandbox container binding for Workers. Edge-native. | `init({ sandbox: createCloudflareSandboxEnv(getSandbox(env.Sandbox, sessionId)) })` (`getSandbox` from `@cloudflare/sandbox`, adapter from `@fabric-harness/cloudflare`) | `examples/with-cloudflare-sandbox/` | | Temporal-driven `local` | Runs through Temporal workflows for replay-determinism, restartability, approvals. | `import { defineAgent } from '@fabric-harness/sdk/strict'` + `init({ runtime: 'temporal', sandbox: 'local', compaction: { enabled: false } })` | `examples/with-temporal/` | | Azure Foundry Hosted | Azure-managed agent runtime; Key Vault secrets, Foundry observability. | `AzureOpenAIModelProvider` + `fabric-harness build --target foundry-hosted-agent` | `examples/with-azure/` | | Daytona | Daytona-managed remote dev sandbox. Per-task ephemeral box. | `init({ sandbox: daytonaSandbox(remote, { cleanup: true }) })` (from `@fabric-harness/connectors`) | `examples/with-daytona/` | | E2B | E2B remote sandbox; native pause/resume. | `init({ sandbox: e2bSandbox(remote, { cleanup: true }) })` (from `@fabric-harness/connectors`) | recipe `connectors/sandbox--e2b.md` | | Modal | Modal serverless sandbox; per-request GPU. | `init({ sandbox: modalSdkSandbox(remote, { cleanup: true }) })` (from `@fabric-harness/connectors/modal`) | `examples/with-modal/` | | Vercel Sandbox | Vercel's ephemeral container compute with streamed output, abort, and portable refs. | `init({ sandbox: vercelSandbox(remote, { cleanup: true }) })` (from `@fabric-harness/connectors/vercel`) | `examples/with-vercel-sandbox/` | | Kubernetes / AKS | Kubernetes pod via `kubernetesSandbox(pod, …)` (or `aksSandbox` from `@fabric-harness/azure`). | `init({ sandbox: kubernetesSandbox(pod, { cleanup: true }) })` (from `@fabric-harness/connectors/k8s`) | `examples/with-kubernetes/` | | Databricks SQL | SQL Warehouse exec-only sandbox; `session.shell()` executes SQL, not bash. | `init({ sandbox: databricksSqlSandbox({ host, principal, warehouseId }) })` (from `@fabric-harness/databricks/sql-sandbox`) | [Databricks SQL sandbox](/docs/ecosystem/sandboxes/databricks-sql) | | `empty` | No filesystem, no shell — pure model + tool-call work. | `init({ sandbox: 'empty' })` | n/a | Provider-backed sandboxes require provider credentials, lifecycle permissions, and the smoke test documented on their setup page. For Databricks SQL, validate Warehouse connectivity and Unity Catalog grants in the target workspace. ## Certification levels Adapter implementation, contract coverage, and credentialed live certification are separate. A hosted provider is live-certified only when every advertised supported SDK major has a retained report with all nine checks passed: shell, binary file, cwd/environment, streaming output, timeout, abort, portable reference, reconnect, and cleanup. Skips and structural mocks do not satisfy that claim. Protected CI reads provider credentials from the `sandbox-live` GitHub Environment, validates the report against `SANDBOX_PROVIDER_COMPATIBILITY`, verifies that the report version is the package actually installed in the run, and emits a digest manifest. Re-certify after SDK-major, credential, account-binding, or lifecycle changes. A provider without current credentials remains available as an adapter but must be described as unverified rather than live-certified. > **Cross-process refs.** Remote backends (E2B, Daytona, Modal, Vercel, Kubernetes, Cloudflare Sandbox, and Cloudflare Shell with a routing ID) can be re-attached from another process with `session.sandboxRef({ portable: true })` + `attachSandbox(serialized)` after registering the receiving-process decoder. See [`@fabric-harness/connectors/sandbox-refs`](/docs/reference/source-access). ## Picking a sandbox - **One-shot webhook / edge worker** — `virtual` (cheap, fast, no host) or `cloudflare` (Workers). - **CI job, dev box** — `local`. - **Coding agent / untrusted shell work** — `docker`, `daytona`, or `modal`. - **Long-running, restartable** — Temporal-driven `local` (use `/strict`). - **Compliance / Azure tenant** — Azure Foundry Hosted Agent. - **Governed analytics where shell means SQL** — Databricks SQL sandbox. ## Capability axes Every sandbox declares a `SandboxCapabilities` shape so agents can adapt: ```ts sandbox.capabilities // { exec, network, filesystem, snapshot, ... } ``` Use this when an agent legitimately needs to know whether shell exec is available before issuing a command. ## See also - [Sandboxes overview](/docs/building/sandboxes) — the conceptual model. - [Sandbox connectors](/docs/building/sandbox-connectors) — building your own `RemoteSandboxApi`. - [Capability matrix](/docs/reference/capability-matrix) — validation level and operational guidance by backend. --- # SDK entrypoints, runtimes, and targets Canonical: https://harness.techfabric.com/docs/reference/sdk-entrypoints-runtimes-targets One default import, an explicit `/strict` opt-out, and orthogonal runtime + target choices. TechFabric Harness has **one SDK** with three independent choices: 1. **Entrypoint** — `@fabric-harness/sdk` (default) or `@fabric-harness/sdk/strict` (no defaults). 2. **Runtime** — `stateless`, `inline`, or `temporal`. Controls persistence and durability. 3. **Target** — `node`, `temporal-worker`, `docker`, `cloudflare`, `foundry-hosted-agent`. Where it runs. Vite is optional build/development composition, not another runtime or deployment target. See [Vite integration](/docs/reference/vite-integration). Keeping these separate lets a 10-line webhook grow into a durable, audited, Temporal-backed background agent without changing the core `init()` / `agent.session()` / `session.prompt()` / `session.skill()` / `session.task()` / `session.shell()` primitives. ## 1. SDK import entrypoints | Entrypoint | Import | Use it when | What's different | |---|---|---|---| | **Default** | `@fabric-harness/sdk` | Almost always. New projects, prototypes, headless edge agents, production webhooks, support agents, even most coding agents. | `defineAgent({...})` auto-injects headless defaults at every `init()`: `runtime: 'stateless'`, `sandbox: 'virtual'`, `loopRuntime: pi-agent-core`, `compaction: { enabled: true }`. Override any value to opt out per call. | | **Strict** | `@fabric-harness/sdk/strict` | Temporal-backed durable agents (replay determinism), compliance / audit / regulated workloads, production agents that prefer no implicit behaviour. | Identical call shape and exports — but `defineAgent({...})` does **not** inject defaults. Every option must be declared explicitly. | > ⚠️ Selecting `runtime: 'temporal'` from the **default** import emits a one-time runtime warning — auto-compaction is non-deterministic across Temporal replay. Use **`/strict`** for Temporal, or pass `compaction: { enabled: false }` explicitly. ```ts title="Default — most agents" import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent({ name: 'echo', run: async ({ init, input }) => { const session = await (await init()).session(); return { reply: await session.prompt(String(input?.message ?? '')) }; }, }); ``` ```ts title="Default — same import, with typed schemas + policy + telemetry" import { defineAgent, schema } from '@fabric-harness/sdk'; import type { CapabilityPolicy } from '@fabric-harness/sdk'; const policy: CapabilityPolicy = { commandPolicy: { allow: ['gh issue view*'], requireApproval: ['gh issue comment*'] }, }; export default defineAgent({ name: 'triage', input: schema.object({ issueNumber: schema.number(), title: schema.string() }), output: schema.object({ severity: schema.enum(['low','medium','high']), summary: schema.string() }), run: async ({ init, input }) => { const fabric = await init({ policy }); const session = await fabric.session(); return await session.prompt(`Triage issue #${input.issueNumber}: ${input.title}`); }, }); ``` ```ts title="Strict — Temporal / compliance" import { defineAgent, schema } from '@fabric-harness/sdk/strict'; export default defineAgent({ name: 'migrate', input: schema.object({ description: schema.string() }), output: schema.object({ filename: schema.string(), upSql: schema.string() }), run: async ({ init, input }) => { // Strict: every option is declared. Nothing implicit. const fabric = await init({ runtime: 'temporal', sandbox: 'local', compaction: { enabled: false }, // explicit; replay-deterministic policy: { commandPolicy: { requireApproval: ['psql*'] } }, }); const session = await fabric.session(); // ... }, }); ``` ## 2. Runtime modes | Runtime | State model | Best for | Tradeoff | |---|---|---|---| | `stateless` | No persisted session history. Each invocation independent. | High-volume webhooks, edge/serverless, simple headless automations, prototypes. | No durable artifacts, no stored approvals, no resumable history. | | `inline` | Runs in the current process. In-memory state by default; configure a `SessionStore` for persistence. | Local dev, Node servers, CI jobs, production web services with SQLite/Postgres/file storage. | Process-local unless you configure a durable store. | | `temporal` | Model calls, shell commands, checkpoints, approvals, and child tasks run through Temporal workflows/activities. | Long-running background agents, restartable jobs, approval-gated workflows, multi-day runs. | Requires a Temporal server and a `fh temporal-worker` process. | Runtime is **not** tied to entrypoint. From the default import, you get `runtime: 'stateless'` unless you override; from `/strict` you must declare it. Both reach the same execution paths. ## 3. Deployment targets | Target | CLI | What it means | |---|---|---| | `node` | `fh run agent --target node` / `fh build --target node` | Run or build a Node HTTP/server process. | | `temporal-worker` | `fh temporal-worker` and `fh run agent --target temporal-worker` | Start a worker; drive agents through Temporal workflows. | | `docker` | `fh build --target docker` | Package a Node build in a Docker-ready output. | | `cloudflare` | `fh build --target cloudflare` | Cloudflare Worker bundle. | | `foundry-hosted-agent` | `fh build --target foundry-hosted-agent` | Hosted-agent deployment artifact for Azure Foundry. | Target is **where** the code runs. Runtime is **how** sessions execute. Entrypoint is **what** the agent imports. The table lists the core targets. `fh build` also supports `aks`, `aca`, `aci`, `k8s`, `render`, `databricks-app`, and `databricks-serving` — see the full [target matrix](/docs/ecosystem/targets). ## Common combinations | Scenario | Entrypoint | Runtime | Target | |---|---|---|---| | 10-line webhook | default | `stateless` | `node` or `cloudflare` | | Support agent with mounted KB | default | `stateless` or `inline` | `node` or `cloudflare` | | CI issue triage | default | `inline` | `node` | | Production Node service | default | `inline` + SQLite/Postgres/file store | `node` or `docker` | | **Durable issue triage** | **`/strict`** | `temporal` | `temporal-worker` | | **Approval-gated background job** | **`/strict`** | `temporal` | `temporal-worker` | | **SOC-2 / HIPAA / FedRAMP-style audit** | **`/strict`** | `inline` | any | ## Moving between import paths Swap one import line. Nothing else changes: ```diff - import { defineAgent } from '@fabric-harness/sdk'; + import { defineAgent } from '@fabric-harness/sdk/strict'; ``` The agent body stays the same. The only effect: defaults are no longer auto-injected, so any field you previously relied on a default for must be declared explicitly. ## Why both exist | Question | Answer | |---|---| | Why have a `/strict` import at all? | **Replay determinism + audit clarity.** Auto-compaction is non-deterministic for Temporal replay. Hidden defaults make compliance reviews harder. Strict makes every choice visible in the agent file. | | Why isn't strict the default? | Most agents don't need it. Asking every user to declare four options on every agent is friction. | | Can I use Cloudflare R2, Docker, Daytona, OTel telemetry, custom stores from the default import? | **Yes.** All of those are values you pass to `init()` or to `defineAgent({...})`. They're independent of which entrypoint you import from. | | Can I move from default to strict later? | Trivially. Change the import, declare any options that were previously defaulting. | | What about heavy provider/Temporal-client deps? | Already in separate packages: `@fabric-harness/temporal`, `@fabric-harness/cloudflare`, `@fabric-harness/azure`, `@fabric-harness/connectors`. The bare SDK is small. | ## See also - [Agent anatomy](/docs/building/anatomy) — the `defineAgent({...})` shape. - [Runtime modes](/docs/reference/runtime-modes) — `stateless` vs `inline` vs `temporal` in detail. - [HTTP server](/docs/reference/http-server) — `/agents/:name/:id` REST + SSE. - [Compaction](/docs/reference/compaction) — when and how auto-compaction triggers. - [Capability matrix](/docs/reference/capability-matrix) — what each piece can do. --- # Security hardening Canonical: https://harness.techfabric.com/docs/reference/security-hardening Complete production hardening guidance for secrets, policy, network boundaries, sandboxes, HTTP ingress, builds, snapshots, and audit evidence. This is the complete public hardening guide. Review it with the deployment-specific security controls for your runtime before promoting an agent. ## Secrets and redaction Never place credentials in agent definitions, serializable workflow inputs, prompts, session artifacts, checkpoints, generated files, or error messages. Use secret references and resolve them at the narrowest trusted runtime boundary. ```ts import { environmentSecretProvider, redactError, redactJson, redactText, secret, secretResolver, } from '@fabric-harness/sdk'; const tokenRef = secret('PROVIDER_TOKEN'); const resolve = secretResolver(environmentSecretProvider()); const token = await resolve(tokenRef); ``` The central redaction helpers cover common secret-shaped keys and values including API keys, tokens, passwords, authorization headers, private keys, and certificate fields. Apply them before untrusted errors or environment-derived metadata enter logs, events, traces, or approval requests. `FabricError` exposes separate `toPublicJSON()` and `toDeveloperJSON()` serializers. Public serialization is suitable for production responses. Developer serialization contains more diagnostics but remains redacted. In production mode, default JSON serialization uses the public audience. ## Capability policy - Declare only the tools and commands the workload needs. - Prefer narrow filesystem scopes such as `/workspace/src/**`, not `/workspace/**`. - Treat definition policy as a security floor; invocation policy may narrow it but must not replace its allowlists. - Gate destructive or externally visible actions such as `git push`, `npm publish`, data mutation, and infrastructure changes with durable approvals bound to the exact operation and actor. - Validate tool arguments and typed results. Model and tool output is untrusted input. - Use governed TechFabric Platform actions for application mutations rather than bypassing the application's mutation boundary. Skills add instructions, not capabilities. Loading a skill must never grant filesystem, shell, network, credential, or connector authority. ## Network enforcement Default to allowlist egress, but do not confuse application policy with a universal network firewall. `policiedFetch()` checks supported HTTP calls routed through it. Global `fetch`, Axios, third-party SDKs, raw sockets, DNS, and subprocess traffic are not automatically intercepted. ```ts import { assertEnforceableNetworkPolicy, policiedFetch, type CapabilityPolicy, } from '@fabric-harness/sdk'; const policy: CapabilityPolicy = { network: { mode: 'allowlist', protocols: ['https:'], hosts: ['api.example.com'], resolveDns: true, }, }; const safeFetch = policiedFetch(fetch, policy); await safeFetch('https://api.example.com/status'); assertEnforceableNetworkPolicy(policy, sandbox, { deployment: 'production', }); ``` For production, enforce egress again outside the process with a Docker network, Kubernetes NetworkPolicy plus proxy, private VNet, or provider firewall. The assertion validates a sandbox's declared boundary; it does not provision that boundary. Test that an allowed proxied request succeeds and a direct or non-allowlisted request fails. See [private networking and egress](/docs/operating/private-networking). ## Sandbox selection There is no single security ranking that applies to every backend. Choose based on the workload's required capabilities and the isolation boundary you can verify: | Backend | Appropriate use | Security boundary | | --- | --- | --- | | `empty` | Model calls and custom tools with no shell or filesystem | No shell/filesystem surface | | `virtual` | Deterministic tests and lightweight in-memory work | Process-level; not for untrusted code | | `docker` or provider container/microVM | Untrusted shell, package installs, generated code, uploaded data | Separate container or managed isolation boundary | | `local` | Trusted repository automation that intentionally needs host tools | Shell/filesystem paths are confined to the workspace root plus any `allowedPaths` (denials raise `SANDBOX_ESCAPE_BLOCKED`), but confinement is a static guardrail: host processes, environment, credentials, and dynamically constructed paths remain reachable | | host execution outside a Harness sandbox | Only when the application owns equivalent controls | No Harness isolation boundary | For untrusted workloads, prefer Docker or a certified provider container/microVM over `local`. `local` may be operationally convenient, but it is not more isolated than Docker. The Docker sandbox defaults to: - network disabled with `--network none`; - read-only root filesystem; - writable `/tmp` tmpfs; - bounded stdout and stderr capture. Review CPU, memory, PID, timeout, mount, output, cleanup, and network limits explicitly for production. Never mount credential directories or a Docker socket into an untrusted session. ## Sandbox-layer policy `init({ policy })` wraps the session sandbox so direct `sandbox.exec`, `readFile`, and `writeFile` calls honor command and filesystem policy. Avoid `bypassPolicyEnforcement: true` unless a stronger, tested enforcement layer replaces it. Approval-required operations should run through `session.shell()` or typed tools, where the session can create and consume durable approvals. A low-level sandbox call can report that approval is required, but it cannot safely resolve one without session identity and history. ## HTTP ingress Generated Node and Cloudflare servers support baseline hardening: ```sh export FABRIC_HARNESS_API_TOKEN='resolve-this-from-a-secret-manager' export FABRIC_HARNESS_MAX_BODY_BYTES=1048576 export FABRIC_HARNESS_RATE_LIMIT_MAX=60 export FABRIC_HARNESS_RATE_LIMIT_WINDOW_MS=60000 export FABRIC_ENV=production ``` - Require authentication on all non-health routes. - Set body-size and per-client rate limits. - In production, expose only definitions with explicit webhook triggers. - Require tenant identity and reject cross-tenant reads. - Verify channel/webhook signatures before dispatch. - Put internet-facing deployments behind an identity-aware gateway, WAF, and distributed rate limiter. The built-in in-memory limiter is not a shared multi-instance control. The local server exposes equivalent flags: ```sh fabric-harness dev \ --auth-token-env FABRIC_HARNESS_API_TOKEN \ --max-body-bytes 1048576 \ --rate-limit-window-ms 60000 \ --rate-limit-max 60 ``` ## Durable execution and identity - Bound model turns, tool calls, retries, tokens, wall-clock duration, command timeouts, and concurrency. - Propagate cancellation through sessions, models, tools, sandboxes, workflows, and deployment adapters. Never convert cancellation into an unbounded retry. - Keep Temporal workflow code deterministic; put model calls, network I/O, clocks, and other nondeterministic effects in activities. - Use stable idempotency keys for retryable external operations. - Isolate persistent-agent configuration, state, and credentials by tenant and addressed identity. - Keep terminal, exhausted, cancelled, retryable, and permanent failures distinguishable. Temporal credentials remain runtime-only. Durable configuration serializes the environment-variable reference, not the secret value. ## Build and supply-chain integrity - Generate SBOMs for package and image builds. - Emit provenance and attestations. - Sign provenance with a protected key or keyless workload identity. - Verify provenance and attestation before deployment. - Pin reviewed action and provider generations. - Scan packed packages and images for secret patterns and incompatible licenses. ```sh pnpm check:release pnpm check:supply-chain fh verify-attestation BUILD_DIRECTORY_OR_ATTESTATION fh verify-provenance BUILD_DIRECTORY_OR_PROVENANCE ``` ## Snapshots, stores, and audit evidence Local and Docker snapshots include a manifest with per-file byte counts and SHA-256 hashes; restore verifies the manifest before replacing workspace contents. Apply retention and deletion policies to snapshots, session stores, submissions, attachments, and artifacts. ```ts import { pruneSnapshots } from '@fabric-harness/sdk'; await pruneSnapshots(snapshotRoot, { keep: 10 }); await pruneSnapshots(snapshotRoot, { olderThanMs: 7 * 24 * 60 * 60 * 1000 }); ``` Keep durable stores enabled for production. Retain enough active history to meet audit needs before compaction, and correlate actor/tenant identity, approval records, effects, artifacts, costs, lineage, and terminal state. Test tenant deletion and disaster recovery rather than assuming store availability implies recoverability. ## Production review checklist - Authentication, tenant binding, webhook signatures, body limits, and distributed rate limiting are verified. - Secrets remain references until a trusted runtime boundary and are absent from logs, model context, durable state, and build output. - Definition policy is the security floor; tools, commands, mounts, and connectors use least privilege. - Custom HTTP clients cannot bypass egress controls because an external network boundary is active. - Untrusted execution uses a verified container or microVM boundary, not `local`. - Cancellation, timeout, retry, idempotency, cleanup, and crash recovery tests pass. - SBOM, provenance, signatures, vulnerability checks, and license review pass. - Audit retention, tenant deletion, backup, restore, and incident procedures have named owners. --- # Session Stores Canonical: https://harness.techfabric.com/docs/reference/session-stores Unified memory, SQLite, Postgres, Redis, MySQL, MongoDB, and libSQL/Turso persistence. For new Node applications, configure a complete persistence bundle rather than a session store in isolation. A bundle keeps session history, durable submissions, conversation offsets, attachments, run events, cost totals, health, and deletion on one backend: ```ts title=".fabricharness/config.ts" import { sqlitePersistence } from '@fabric-harness/node'; export default { persistence: sqlitePersistence({ path: '.fabricharness/fabric-harness.sqlite', }), }; ``` Use `memoryPersistence()` for ephemeral tests, `sqlitePersistence()` for a durable single process, and `postgresPersistence()` or `redisPersistence()` for high-throughput multiple replicas. `mysqlPersistence()`, `mongodbPersistence()`, and `libsqlPersistence()` provide the same complete contract through version-fenced snapshots for moderate operational state. Third-party backends can verify the same behavior with `definePersistenceBundleContractTests` from `@fabric-harness/sdk/testing/contracts`. ### Session-store configuration: one canonical idiom When you only need to pick the **session store** (no submission/stream/attachment stores), use the declarative `store` form — it needs no import: ```ts title=".fabricharness/config.ts" export default { store: { backend: 'memory' }, // ephemeral: nothing persists across runs // store: { backend: 'file' }, // durable local default // store: { backend: 'sqlite' }, // durable SQL }; ``` `persistence: memoryPersistence()` still works as a deprecated alias for the session-store case and prints a one-time deprecation warning pointing at `store: { backend: 'memory' }`; both forms work through at least the next major. Keep the `persistence` bundle form when you need the full bundle (submissions, streams, attachments) — or a backend the declarative form does not cover — as shown above. The session store is where Fabric persists session entries, events, tasks, approvals, checkpoints, and artifact metadata. The default is a file store. The full notes live in [`docs/session-stores.md`](/docs/reference/source-access). First-party stores implement `SessionStore.appendEntries()` for one atomic, ordered entry batch. The optional `expectedLeafId` is a compare-and-swap fence: a stale writer receives `false`, an exact replay is a successful no-op, and reuse of an entry id with different content fails. Harness uses this boundary to settle interrupted tool calls, task ends, and recovery advisories together, so a process crash cannot expose a partially repaired session. Third-party stores that implement the method should provide the same semantics. ## Backends | Backend | Where it stores | When to use | | --- | --- | --- | | **Memory** | nowhere (process memory) | Ephemeral runs and tests; `fh sessions` stays empty after the process exits. | | **File** (default) | `.fabricharness/sessions//` | Local development, CI smoke tests, single-host services. | | **SQLite** | `.fabricharness/fabric-harness.sqlite` (configurable) | Single-host services that want SQL queries and `BEGIN IMMEDIATE` atomic batches. | | **Postgres** | external Postgres | Multi-host services, Temporal worker fleets, production. | | **Redis / Valkey** | external Redis-compatible cluster | Multi-host services needing low-latency leases, offsets, retention TTLs, and atomic budgets. | | **MySQL** | versioned snapshot rows in MySQL 8 | Existing MySQL estates with moderate agent-state write volume. | | **MongoDB** | versioned snapshot documents | Existing Mongo deployments; standalone or replica set. | | **libSQL / Turso** | local file or remote versioned snapshot rows | Lightweight local/serverless deployments with moderate state. | ## Configuration `.fabricharness/config.ts`: ```ts export default { store: { backend: 'sqlite', path: '.fabricharness/sessions.sqlite', }, }; ``` ```ts export default { store: { backend: 'postgres', databaseUrlEnv: 'DATABASE_URL', }, }; ``` ## What gets stored For each session: - session header (id, created, updated, agent), - ordered entries (prompts, assistant turns, tool calls, shell commands, task events, approvals, compactions, checkpoints), - the event stream, - artifact metadata + content (or external blob URLs), - task records, - approval records. ## Examples - [`examples/with-config`](/docs/reference/source-access) — central config including SQLite session storage. - [`examples/with-postgres-store`](/docs/reference/source-access) — Postgres-backed session/artifact storage. - [`examples/database-persistence`](/docs/reference/source-access) — select libSQL/Turso, MySQL, or MongoDB from one config. --- # Source and example access Canonical: https://harness.techfabric.com/docs/reference/source-access How to use TechFabric Harness when the source repository is restricted and how to request repository access. The TechFabric Harness source repository is currently restricted. A GitHub `404` while signed out does not mean that the npm packages or this documentation are unavailable; it means your GitHub account does not have repository access. You can install and use the published packages without cloning the framework repository: ```sh npx --yes @fabric-harness/cli@latest init my-agents cd my-agents npm install npx fh doctor --getting-started --tools --model mock/test-model ``` The public site includes the complete [security hardening guide](/docs/reference/security-hardening), [license and attribution](/docs/reference/license), API inventory, deployment guidance, and copyable examples needed for normal product evaluation. Repository examples, contribution workflows, commit history, and internal release evidence require authorized access. [Contact TechFabric](https://techfabric.com/contact) to request access and include your GitHub username, organization, and the TechFabric Harness use case you are evaluating. Do not rely on a `git clone` command from an old guide unless TechFabric has confirmed access for your GitHub account. --- # Streaming protocol Canonical: https://harness.techfabric.com/docs/reference/streaming-protocol The HTTP wire protocol for delivering messages to an agent conversation and reading it back by offset, over JSON or SSE. Every persistent agent conversation is an append-only, offset-addressed record stream. Delivery and reading are separate operations: a `POST` durably admits a message and returns immediately, and the reply arrives in the conversation, which you read from an offset. `@fabric-harness/client` and `@fabric-harness/react` wrap this surface, and most applications should use them. Read this page when you are writing a client in another language, debugging a transport, or building your own UI layer. ## Routes Relative to a persistent agent instance at `/agents/:name/:instanceId`: | Route | Purpose | | --- | --- | | `POST /agents/:name/:instanceId` | Deliver one message. Returns `202` on durable admission. | | `GET /agents/:name/:instanceId/conversation` | Offset-based catch-up read (JSON). | | `GET /agents/:name/:instanceId/stream` | Catch-up plus live tail (SSE). | | `GET /agents/:name/:instanceId/submissions/:submissionId` | One submission's status. | | `POST /agents/:name/:instanceId/abort` | Abort in-flight and queued work. | `conversation` and `stream` both accept `session` (default `default`) and `offset`. `conversation` also accepts `limit`. ## Delivering a message ```http POST /agents/support/ticket-8472 Content-Type: application/json { "message": { "kind": "user", "body": "Summarize the open issues on my case." } } ``` `message` accepts a full `DeliveredMessage` as above, or a bare string as shorthand for `{ "kind": "user", "body": "..." }`. The body also accepts `session` (default `default`), `initialData` for instance creation, and `uid` to pin a generation. The response is `202` as soon as the message is durably admitted — before the model runs: ```json { "submissionId": "sub_01HZX...", "streamUrl": "/agents/support/ticket-8472/conversation?session=default&offset=42", "conversationUrl": "/agents/support/ticket-8472/conversation?session=default&offset=42", "updatesUrl": "/agents/support/ticket-8472/stream?session=default&offset=42", "offset": "42" } ``` `offset` is the stream position *before* this delivery, so reading from it returns this message and everything the agent produces in response — with no race against the agent starting. `uid` is present when the instance has a resolved generation. There is no "wait for the reply" mode on this route in the durable path; read the outcome from the conversation, or poll the submission. ## Reading by offset ```http GET /agents/support/ticket-8472/conversation?offset=42&limit=100 ``` ```json { "incarnation": "inc_01HZ...", "batches": [{ "offset": "42", "records": [] }], "nextOffset": "57", "upToDate": true } ``` Pass `nextOffset` as the next request's `offset` to continue. `upToDate` is `true` when the read reached the tail. A conversation that does not exist yet returns `incarnation: null` with an empty `batches` array rather than a 404, so a reader can start before the first message lands. Offsets are opaque strings. Compare them for equality, never order them numerically or arithmetically. ### Incarnation `incarnation` identifies the stream's producer generation. If it changes between reads, the stream was rebuilt and offsets from the previous incarnation are meaningless — discard projected state and re-read from `"0"`. ## Live tail over SSE ```http GET /agents/support/ticket-8472/stream?offset=42 Accept: text/event-stream ``` The server replays from `offset`, then tails. Every frame is a JSON object in `data:`; `: keepalive` comments are sent periodically and carry no data. | Frame `type` | Payload | Meaning | | --- | --- | --- | | `stream_checkpoint` | `incarnation`, `offset` | Producer generation. A change means re-read from `"0"`. | | `conversation` | `offset`, `records` | Durable records. `offset` is the next offset to resume from. | | `delta` | `eventId`, `kind` (`text` \| `reasoning`), `delta`, `submissionId?`, `turnId?` | Token-level text or reasoning fragment. | | `toolcall_delta` | `eventId`, `toolCallId`, `toolName`, `argumentTextDelta`, `submissionId?`, `turnId?` | Streaming tool-call arguments. | **Only `conversation` frames are durable.** `delta` and `toolcall_delta` are presentation-only: they let a UI render tokens as they arrive, are not replayed on reconnect, and are always superseded by the `conversation` records covering the same turn. A client that ignores them loses nothing but interactivity; a client that persists them will double-count. Reconnect by re-requesting `stream` with the last `offset` you received in a `conversation` frame. `@fabric-harness/client` reconnects after 90 seconds of transport silence by default (`idleTimeoutMs`), and falls back to JSON polling when SSE is unavailable (`live: 'auto' | 'sse' | 'poll'`). ## Records Each record in a `records` array is a `ConversationStreamRecord`: ```ts type ConversationStreamRecord = | { kind: 'entry'; entry: SessionEntry } | { kind: 'truncated'; rewoundTo: string; newLeafId: string; reason: string }; ``` A `truncated` record means the conversation path branched — a replay, a checkpoint restore, or a fork. Drop every projected record after `rewoundTo` and continue from the records that follow. Ignoring `truncated` leaves a client showing messages that are no longer on the active path. ## Projecting records for display Raw entries are the canonical log, not a render-ready view. `projectConversationRecords` from `@fabric-harness/sdk/conversation` reduces a record sequence into a stable UI protocol: ```ts import { projectConversationRecords } from '@fabric-harness/sdk/conversation'; const { messages, settlements } = projectConversationRecords(records); ``` A `ConversationMessage` carries `id`, `role`, `purpose`, `display`, optional `submissionId`/`turnId`/`metadata`, and an ordered `parts` array: | Part `type` | Shape | | --- | --- | | `text` | `text`, `state: 'streaming' \| 'done'` | | `reasoning` | `text`, `state: 'streaming' \| 'done'` | | `file` | `mediaType`, optional `id`, `size`, `filename` | | `dynamic-tool` | `toolName`, `toolCallId`, and a state-specific payload (`input-streaming`, `input-available`, `output-available`, `output-error`) | | `data-${name}` | `data` — agent-authored structured parts written with `useDataWriter()` | Honor `display`: `hidden` messages are not for users, and `diagnostic` ones belong behind a debug affordance. `purpose` distinguishes a user turn from a dispatched signal or an advisory injection. `settlements` reports terminal submission outcomes — `completed`, `failed`, or `aborted`, with `error` and `answeredBySubmissionId` where they apply. A submission that joined a busy conversation is answered by another submission's assistant turn, which `answeredBySubmissionId` names. ## Implementation checklist For a client in another language: 1. `POST` the message; keep `submissionId` and `offset` from the `202`. 2. Read from that `offset` — SSE if you want live tokens, JSON polling otherwise. 3. Treat offsets as opaque; resume from `nextOffset` or a `conversation` frame's `offset`. 4. Re-read from `"0"` whenever `incarnation` changes. 5. Apply `truncated` records by discarding everything after `rewoundTo`. 6. Render from `delta` frames if you want streaming, but persist only `conversation` records. 7. Stop when a settlement for your `submissionId` appears, or when the submission status is terminal. ## See also - [Events](/docs/reference/events) — the session entry types that appear inside records. - [Agent behavior](/docs/reference/agent-behavior) — built-in tool semantics reflected in tool parts. - [React](/docs/building/react) — the hook layer built on this protocol. --- # Telemetry Canonical: https://harness.techfabric.com/docs/reference/telemetry The events and metrics TechFabric Harness emits, and the OpenTelemetry hooks that carry them into your own tracing. TechFabric Harness emits structured events for every meaningful step in an agent run. The full notes live in [`docs/telemetry.md`](/docs/reference/source-access). ## What a correlated run looks like The run identifier ties model attempts, tool effects, policy decisions, schema validation, duration, usage, and cost together. Exporters may render this differently, but they should preserve the same parent-child and failure-classification evidence. ## Event types ``` agent_start text_delta prompt_start prompt_end tool_start tool_end command_start command_end task_start task_end approval_requested approval_granted approval_denied approval_expired checkpoint_created checkpoint_restored compaction mount metric result_retry result error ``` ## Transports - **SSE** — `GET /agents/:name/:id/stream` replays legacy session events; add `?offset=...` to tail the persistent conversation stream as offset-addressed records. Finite jobs expose run events at `GET /runs/:runId/events?offset=...`. - **OpenTelemetry** — `openTelemetryExporter` adapts Fabric's `TelemetrySpan` shape to any `@opentelemetry/api` Tracer (App Insights, Jaeger, Honeycomb, generic OTLP). Pass `conventions: 'foundry'` to emit `gen_ai.*` span names matching Azure AI Foundry / OpenTelemetry Generative AI semantic conventions. - **Langfuse** — `langfuseExporter` for direct trace export (peer-deps `langfuse`). - **Azure Monitor / App Insights** — `applicationInsightsExporter` from `@fabric-harness/azure/app-insights` (peer-deps `applicationinsights`). - **Console** — `consoleTelemetryExporter` for local debugging. ```ts import { openTelemetryExporter, langfuseExporter, eventToTelemetrySpan } from '@fabric-harness/sdk'; import { Langfuse } from 'langfuse'; const langfuse = new Langfuse({ publicKey, secretKey, baseUrl }); const exporter = langfuseExporter({ client: langfuse, attributes: { service: 'support-agent' } }); const session = await fabric.session(undefined, { onEvent: async (event) => { const span = eventToTelemetrySpan(event); if (span) await exporter.export(span); }, }); ``` ## Metrics from the CLI ```sh fh metrics [--json] ``` Aggregates: - token usage (input + output + total) and `costUsd` if the provider reports it, - tool calls (with per-tool breakdown for the top 5), - shell commands and durations, - artifacts, - mounts (count, total bytes, total files, top sources by bytes), - model attempts. ## Per-event hooks Subscribe to events at agent or session scope via the `onEvent` callback. Wire any of the exporters above (or a custom one implementing `TelemetryExporter`) into the callback to forward spans. ## Hierarchical OpenTelemetry observer `openTelemetryExporter` emits one flat span per duration-bearing event. For a **nested trace** — a single parent span per operation, with `turn`, `tool`, and `shell` spans inside — use the observer instead: ```ts import { trace } from '@opentelemetry/api'; import { createOpenTelemetryObserver } from '@fabric-harness/sdk/otel-observer'; const observe = createOpenTelemetryObserver({ tracer: trace.getTracer('fabric-harness'), conventions: 'fabric', // or 'foundry' for gen_ai.* span names + attributes }); const agent = await init({ onEvent: observe }); ``` It lives on the `@fabric-harness/sdk/otel-observer` subpath (not the main entry) because building parent spans needs `@opentelemetry/api` at runtime, while the main SDK keeps it an optional peer dependency. The tree is inferred from event start/end ordering; a `task()` sub-session traces separately with a wrapping `task` span, and an `error` event closes open spans with `ERROR` status. --- # Triggers and Public Route Gating Canonical: https://harness.techfabric.com/docs/reference/triggers How finite jobs and persistent agents are exposed once deployed, and what gates a public route before a request reaches one. Triggers are definition metadata that tell generated servers which entrypoints may be exposed in production. Put triggers inside `defineAgent({...})` or return them from `createAgent(...)`. ## Declaring triggers ```ts import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent({ name: 'webhook-triage', triggers: { webhook: true, }, async run({ input }) { return input; }, }); ``` ## Default behavior - **Finite job:** `webhook: true` enables `POST /jobs/:name` in production. - **Persistent agent:** `webhook: true` enables `POST /agents/:name/:id` in production. - Without it, the definition remains available to local/dev and CLI flows, but production public invocation returns `403 Forbidden`. ## Public route gating For Node-derived deployments, gate public routes with: - `--auth-token-env ` (CLI / env) requiring a bearer token. - `--max-body-bytes` to cap body size. - `--rate-limit-window-ms` + `--rate-limit-max` for per-IP rate limits. For Cloudflare, apply route-level rules around `/jobs/` and `/agents//` in addition to the Worker bearer token. ## Schedule triggers The Node server runs finite `schedule` triggers with `cron-parser`: ```ts export default defineAgent({ name: 'daily-report', triggers: { schedule: '0 9 * * 1-5' }, async run({ input }) { /* ... */ }, }); ``` Persistent-agent configs reject `triggers.schedule`: a cron expression alone cannot identify the instance, named session, or message to deliver. Put the schedule on a bounded finite job and dispatch explicitly: ```ts import { defineAgent, dispatch } from '@fabric-harness/sdk'; export default defineAgent({ name: 'daily-assistant-wakeup', triggers: { schedule: '0 9 * * 1-5' }, async run({ input }) { return dispatch({ agent: 'assistant', id: 'daily-ops', message: 'Review the morning operations queue.', dispatchId: `daily-assistant:${input.scheduledAt}`, tenantId: 'system:daily-operations', actor: { agentId: { id: 'daily-scheduler', type: 'service' } }, }); }, }); ``` This keeps the persistent identity and input explicit while the finite wrapper retains the normal bounded scheduling, lease, idempotency, and run-inspection behavior. On Cloudflare, a persistent agent instance can also own its wake-up times directly. The generated Worker exposes per-instance schedules (`GET`/`POST /agents/:name/:id/schedules`, `DELETE .../schedules/:scheduleId`) backed by Durable Object alarms, and each fire is admitted as a durable submission whose delivered message is a signal with `type: "schedule"` — visible to the agent through `useDelivery()` and to custom loop runtimes as `PromptRunInput.delivery`. See [Per-instance schedules](/docs/deployment/cloudflare#per-instance-schedules-durable-object-alarms). Finite-job scheduling stays on `triggers.schedule`; the Cloudflare build maps those expressions to Worker Cron Triggers (`triggers.crons` in `wrangler.jsonc`) as described in [Cloudflare Cron Triggers](#cloudflare-cron-triggers) below. Configure timezone and payload resolution when embedding the server: ```ts await startDevServer({ scheduler: { timezone: 'America/Phoenix', payload: (jobName, expression, scheduledAt) => ({ scheduledAt: scheduledAt.toISOString() }), catchUp: 'run-once', }, }); ``` Set `FABRIC_HARNESS_SCHEDULER_ENABLED=0` to disable it. The scheduler calculates each next cron boundary before execution, skips overlapping runs of the same job, emits normal session events, and stops its timers during graceful shutdown. `catchUp: "skip"` is the default. With a lease store that supports durable cursors, `catchUp: "run-once"` executes only the most recent occurrence missed during downtime. A first start establishes the cursor and does not replay historical cron time. Public `dispatch()` accepts `dispatchId`, `tenantId`, and `actor`, so scheduled persistent-agent delivery can be both idempotent and explicitly owned. ### Multiple Node replicas Use the Postgres lease store so every cron occurrence and active job has one owner across replicas: ```ts import { Pool } from 'pg'; import { postgresSchedulerLeaseStore, startDevServer } from '@fabric-harness/node'; const pool = new Pool({ connectionString: process.env.DATABASE_URL }); await startDevServer({ scheduler: { leaseStore: postgresSchedulerLeaseStore(pool), leaseMs: 60_000, }, }); ``` The active lease renews while the job runs. An occurrence claim remains long enough to prevent a late or restarted replica from replaying the same cron tick. `memorySchedulerLeaseStore()` is the single-process default and is useful for tests, not multi-replica coordination. Generated Databricks Apps bind scheduled work to the App principal's stable system tenant. Lakebase-backed Apps also wire the Postgres lease/cursor store and use `run-once` catch-up automatically. Without Lakebase, scheduling is process-local, uses `skip`, and should remain single-replica. Each claimed Node occurrence is admitted as a durable finite run. It receives a run receipt, can be inspected through `/runs/:runId`, and deduplicates across replicas using the schedule expression and scheduled timestamp. If an occurrence is more than Node's maximum timer delay away, the scheduler re-arms the same occurrence at each timer boundary; it does not execute the job early. Scheduled Databricks App runs belong to the App principal's tenant. A signed-in user's approval discovery route therefore cannot see a request raised inside that run. For human-gated schedules, persist a proposal for a later user-owned interaction or use a trusted decision bridge that retains the exact session/request receipt and resolves it through the stored approval boundary. The [Buzz bridge](/docs/ecosystem/channels/buzz) supplies the transport correlation primitives; the application still owns identity, membership, expiry, authorization, and compare-and-swap checks. ### Cloudflare Cron Triggers `fh build --target cloudflare` discovers every schedule expression, writes it to `wrangler.jsonc` under `triggers.crons`, and emits a Worker `scheduled()` handler. Each occurrence gets a deterministic run ID and executes through the same finite-job function as `POST /jobs/:name`. Inspect it with `GET /runs/:runId` and read offset events from `GET /runs/:runId/events?offset=0`. Cloudflare serializes duplicate deliveries for that run ID through its Durable Object and returns the existing run instead of executing twice. Cron expressions use the target runtime's timezone rules: Node accepts an explicit IANA timezone; Cloudflare Cron Triggers run in UTC. During DST changes, `cron-parser` advances missing wall-clock times to the next valid instant and executes a repeated wall-clock occurrence once. --- # Validation status Canonical: https://harness.techfabric.com/docs/reference/validation-status Current contract, provider, deployment, certification, and environment-specific evidence across TechFabric Harness features. TechFabric Harness separates implementation, deterministic contract coverage, credentialed provider smokes, deployment conformance, and retained certification. A green workflow is not live evidence for an optional provider when its credentialed steps were skipped. ## How to read the statuses | Status | Meaning | | --- | --- | | **Contract verified** | Public types, exports, runtime behavior, packaging, and deterministic tests passed. It does not establish a managed provider account. | | **Provider verified** | The current provider or service-backed contract ran with the required runtime rather than a structural mock. | | **Deployment conformance** | A built artifact passed the shared black-box lifecycle against the named runtime. | | **Live certified** | A retained record binds the exact package and environment to required checks and limitations. | | **Unconfigured** | The integration exists, but the latest protected credentialed suite did not execute. | | **Not established** | Available evidence is insufficient for the stated claim. It does not invalidate a narrower passing record. | | **Target validation required** | Typed support exists, but the customer's identity, region, network, SKU, and deployment must be proven. | ## Environment validation boundary Pin an explicit package set and enable only capabilities with matching evidence or a completed customer-environment smoke. Define the acting principal, tenant isolation, model, sandbox, durable stores, allowed tools, approval audience, cost bounds, recovery objective, and support owner before admitting users. For shared Databricks Apps, repeat two-user isolation, OBO expiry/refresh, allow-and-deny Unity Catalog access, App restart, cascade deletion, and cleanup in the target workspace. For every other managed runtime, run the provider command from [Live tests](/docs/reference/live-tests) and retain the result with the deployed artifact. ## Related evidence - [Release and documentation status](/docs/reference/release-status) - [Live test commands](/docs/reference/live-tests) - [Production readiness checklist](/docs/reference/production-readiness) - [Databricks certification](/docs/databricks/live-certification) - [Machine-readable validation status](/evidence/live/current.json) --- # Vite integration Canonical: https://harness.techfabric.com/docs/reference/vite-integration Compose Vite 8 with Harness development and portable build targets without replacing fh dev or fh build. `@fabric-harness/vite` is an optional composition layer. It does not scan for implicit agent functions or replace Harness's explicit `defineAgent()` / `createAgent()` identities. The same workspace discovery and target registry continue to power `fh dev`, `fh build`, and Vite. ## Install ```sh pnpm add -D @fabric-harness/vite vite ``` ```ts title="vite.config.ts" import { defineConfig } from 'vite'; import { fabricHarness } from '@fabric-harness/vite'; export default defineConfig({ plugins: [fabricHarness({ target: 'node' })], }); ``` During `vite dev`, Harness HTTP, SSE, and WebSocket route prefixes are proxied through the Vite server. The backing Harness server binds an ephemeral loopback port and is drained when Vite closes. Shell-exported environment values retain precedence; use Vite's normal environment loading for the front-end and Harness's documented runtime secret resolvers for privileged credentials. During `vite build`, the plugin invokes the same portable build registry as: ```sh fh build --target node ``` The Harness artifact remains under `.fabricharness/build//`; Vite owns its own output. Set `standalone: true` for a headless workspace with no HTML or application entry: ```ts fabricHarness({ target: 'node', standalone: true }) ``` ## Cloudflare Compose the official Cloudflare plugin as a sibling and keep Harness first: ```ts title="vite.config.ts" import { cloudflare } from '@cloudflare/vite-plugin'; import { defineConfig } from 'vite'; import { fabricHarness, fabricHarnessWorkerConfig, } from '@fabric-harness/vite'; export default defineConfig({ plugins: [ fabricHarness({ target: 'cloudflare', standalone: true }), cloudflare({ config: fabricHarnessWorkerConfig() }), ], }); ``` The customizer contributes only the generated Worker entry and `nodejs_compat`. Authored Wrangler bindings, Durable Object migrations, deployment names, environments, and observability settings pass through unchanged. Calling the customizer before `fabricHarness()`, reversing plugin order, or using a non-Cloudflare Harness target fails with an actionable configuration error. ## Choosing a path | Need | Command | | --- | --- | | One-shot, no transport | `fh run ` | | Harness-only development | `fh dev` | | Existing Vite application | `vite dev` with `fabricHarness()` | | Portable deployment artifact | `fh build --target ` or the equivalent Vite composition | Harness keeps `fh dev` and `fh build` because Vite is not available on every supported deployment or authoring surface. The integration is optional for local projects and never makes Vite a core SDK dependency. --- # Use Cases Canonical: https://harness.techfabric.com/docs/use-cases Ten TechFabric Harness agents you can build today, from issue triage and PR review to migrations, bug repro and incident runbooks. import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; Each use case below shows two equivalent forms: - **Minimal** — `defineAgent({...})` from `@fabric-harness/sdk`. Headless defaults pre-injected (stateless runtime, virtual sandbox, pi-agent-core, auto-compaction). - **Complete** — same `defineAgent({...})` from the same `@fabric-harness/sdk` import — but with typed `input`/`output` schemas, capability `policy`, artifacts, custom stores, providers, telemetry. *No import path change required.* > For **Temporal-backed durable agents**, **compliance/audit workloads**, or any case where you want zero implicit behavior, import from `@fabric-harness/sdk/strict` instead — same call shape, no headless defaults injected. ## How to test these locally Each agent below has a runnable scaffold and default fixture in the restricted [`examples/` source tree](/docs/reference/source-access). Without repository access, create a public starter and adapt the complete definition shown on this page: ```sh npx --yes @fabric-harness/cli@latest init my-agents cd my-agents && npm install npx fh run JOB_NAME --mock ``` For a live provider run in your own project: ```sh npm install @fabric-harness/sdk @fabric-harness/cli fabric-harness run JOB_NAME --payload '...' ``` ## Connecting to external knowledge bases | Source | Pattern | Notes | |---|---|---| | Local Markdown / MDX | `localDirectorySource('./kb')` | Eager mount; agent uses `grep`/`read` | | Fumadocs content tree | `fumadocsSource('./apps/docs/content/docs')` | Strips frontmatter | | Mintlify (local) | `mintlifySource('./mint-docs')` | Includes `docs.json` | | Mintlify (hosted MCP) | `connectMcpServer('mintlify', { url: '...mcp', transport: 'streamable-http' })` | Default transport is streamable-http | | Cloudflare R2 | `r2FilesystemSource(env.KB)` | From `@fabric-harness/sdk/cloudflare` | | S3 / Azure Blob | `s3FilesystemSource(...)` / `azureBlobFilesystemSource(...)` | From `@fabric-harness/connectors` | | Arbitrary HTTP | `httpFilesystemSource([{ url, path }])` | Fetch + cache as files | Mount any of these with `withFilesystemSources('virtual', [{ mountAt, source }])` and the agent gets `read` / `grep` / `glob` over them — no embeddings, no retrieval pipeline. --- ## 1. Issue Triage Read a GitHub issue, classify severity, suggest labels, draft a reply. ```ts import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ issueNumber: number; title: string; body: string }>({ name: 'triage', triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init()).session(); return await session.prompt( `Triage issue #${input.issueNumber}: "${input.title}". Return JSON { severity, labels[], suggestedComment }.\n\n${input.body}`, ); }, }); ``` ```ts import { defineAgent, schema } from '@fabric-harness/sdk'; const triageResult = schema.object({ severity: schema.enum(['low', 'medium', 'high', 'critical']), labels: schema.array(schema.string()), suggestedComment: schema.string(), }); export default defineAgent({ name: 'triage', input: schema.object({ issueNumber: schema.number(), title: schema.string(), body: schema.string() }), output: triageResult, triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init({ policy: { commandPolicy: { allow: ['gh issue view*'], requireApproval: ['gh issue comment*'] } }, })).session(); return await session.prompt(`Triage this issue and suggest labels and a reply.\n\n${JSON.stringify(input)}`, { result: triageResult, }); }, }); ``` **Run it:** `pnpm --filter @fabric-harness/example-issue-triage-ci run:triage` · [source](/docs/reference/source-access) --- ## 2. PR Reviewer Review a pull request diff for security / performance / readability and produce structured findings. ```ts import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ prNumber: number; diff: string }>({ name: 'pr-review', triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init()).session(); return await session.prompt( `Review PR #${input.prNumber}. Return JSON array { file, line?, severity, category, message, suggestion? }.\n\n${input.diff}`, ); }, }); ``` ```ts import { defineAgent, schema, shellQuote } from '@fabric-harness/sdk'; const finding = schema.object({ file: schema.string(), line: schema.number().optional(), severity: schema.enum(['info', 'low', 'medium', 'high']), category: schema.enum(['bug', 'security', 'performance', 'tests', 'readability']), message: schema.string(), }); const reviewResult = schema.object({ findings: schema.array(finding) }); const repositorySlug = (value: string) => { if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(value)) throw new Error(`Invalid repository slug: ${value}`); return value; }; export default defineAgent({ name: 'pr-review', input: schema.object({ prNumber: schema.number(), repository: schema.string() }), output: reviewResult, policy: { commandPolicy: { allow: ['gh pr diff*'] }, maxCommandTimeoutMs: 30_000 }, run: async ({ init, input }) => { const session = await (await init({ sandbox: 'local' })).session(); const repository = shellQuote(repositorySlug(input.repository)); const diff = await session.shell(`gh pr diff ${input.prNumber} --repo ${repository}`); if (diff.exitCode !== 0) throw new Error(`gh pr diff failed: ${diff.stderr.trim()}`); return await session.prompt(`Review this pull request diff.\n\n${diff.stdout}`, { result: reviewResult, }); }, }); ``` **Run it:** [source](/docs/reference/source-access) --- ## 3. Changelog Writer Turn `git log` between two refs into a Keep-a-Changelog section. ```ts import { defineAgent, schema, shellQuote } from '@fabric-harness/sdk'; const gitRevision = (value: string) => { if (!/^[A-Za-z0-9][A-Za-z0-9._/~^{}-]{0,127}$/.test(value)) throw new Error(`Invalid Git revision: ${value}`); return value; }; export default defineAgent({ name: 'changelog', input: schema.object({ from: schema.string(), to: schema.string() }), output: schema.object({ changelog: schema.string() }), triggers: { webhook: true }, init: { sandbox: 'local' }, policy: { commandPolicy: { allow: ['git log*'] }, maxCommandTimeoutMs: 30_000 }, run: async ({ input, shell, prompt }) => { const range = shellQuote(`${gitRevision(input.from)}..${gitRevision(input.to)}`); const log = await shell(`git log --pretty=format:'%h %s' ${range}`); if (log.exitCode !== 0) throw new Error(`git log failed: ${log.stderr.trim()}`); return { changelog: await prompt( `Format these commits as a Keep-a-Changelog section. Group: Added/Changed/Fixed/Removed.\n\n${log.stdout}`, )}; }, }); ``` ```ts import { defineAgent, schema, shellQuote } from '@fabric-harness/sdk'; const changelog = schema.object({ added: schema.array(schema.string()), changed: schema.array(schema.string()), fixed: schema.array(schema.string()), removed: schema.array(schema.string()), }); const gitRevision = (value: string) => { if (!/^[A-Za-z0-9][A-Za-z0-9._/~^{}-]{0,127}$/.test(value)) throw new Error(`Invalid Git revision: ${value}`); return value; }; export default defineAgent({ name: 'changelog', input: schema.object({ from: schema.string(), to: schema.string() }), output: changelog, init: { sandbox: 'local' }, policy: { commandPolicy: { allow: ['git log*'] }, maxCommandTimeoutMs: 30_000 }, run: async ({ input, shell, prompt }) => { const range = shellQuote(`${gitRevision(input.from)}..${gitRevision(input.to)}`); const log = await shell(`git log --pretty=format:'%h %s' ${range}`); if (log.exitCode !== 0) throw new Error(`git log failed: ${log.stderr.trim()}`); return await prompt(`Group commits into added/changed/fixed/removed arrays.\n\n${log.stdout}`, { result: changelog, }); }, }); ``` **Run it:** `pnpm --filter @fabric-harness/example-changelog-writer run` · [source](/docs/reference/source-access) --- ## 4. Test Generator Generate a Vitest spec for a TypeScript source file. ```ts import { defineAgent } from '@fabric-harness/sdk'; import { readFile } from 'node:fs/promises'; export default defineAgent<{ file: string }>({ name: 'testgen', triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init()).session(); const source = await readFile(input.file, 'utf8'); return { spec: await session.prompt( `Write a thorough vitest spec for the source below. Cover happy/error/boundary paths.\n\n${source}`, )}; }, }); ``` ```ts import { defineAgent, schema } from '@fabric-harness/sdk'; import { readFile } from 'node:fs/promises'; const generatedTest = schema.object({ specPath: schema.string(), spec: schema.string() }); export default defineAgent({ name: 'testgen', input: schema.object({ file: schema.string(), framework: schema.enum(['vitest', 'jest']).optional() }), output: generatedTest, run: async ({ init, input }) => { const session = await (await init()).session(); const source = await readFile(input.file, 'utf8'); return await session.prompt( `Write a ${input.framework ?? 'vitest'} spec. Return JSON { specPath, spec }.\n\n${source}`, { result: generatedTest }, ); }, }); ``` **Run it:** `pnpm --filter @fabric-harness/example-test-generator run` · [source](/docs/reference/source-access) --- ## 5. Dependency Auditor Run `npm/pnpm audit` and prioritize the findings. ```ts import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ manager?: 'npm' | 'pnpm' }>({ name: 'audit', triggers: { schedule: '0 9 * * *' }, run: async ({ init, input }) => { const session = await (await init({ sandbox: 'local', policy: { commandPolicy: { allow: ['npm audit --json', 'pnpm audit --json'] }, maxCommandTimeoutMs: 60_000, }, })).session(); const cmd = input.manager === 'pnpm' ? 'pnpm audit --json' : 'npm audit --json'; const result = await session.shell(cmd); if (result.exitCode > 1) throw new Error(`Dependency audit failed: ${result.stderr.trim()}`); return { summary: await session.prompt( `Summarize this audit JSON. List Critical/High first with package, version, recommended upgrade.\n\n${result.stdout.slice(0, 80_000)}`, )}; }, }); ``` ```ts import { defineAgent, schema } from '@fabric-harness/sdk'; const finding = schema.object({ package: schema.string(), severity: schema.enum(['low', 'moderate', 'high', 'critical']), recommendedVersion: schema.string().optional(), }); const auditResult = schema.object({ findings: schema.array(finding) }); export default defineAgent({ name: 'audit', input: schema.object({ manager: schema.enum(['npm', 'pnpm']).optional() }), output: auditResult, triggers: { schedule: '0 9 * * *' }, policy: { commandPolicy: { allow: ['npm audit --json', 'pnpm audit --json'] }, maxCommandTimeoutMs: 60_000, }, run: async ({ init, input }) => { const session = await (await init({ sandbox: 'local' })).session(); const cmd = input.manager === 'pnpm' ? 'pnpm audit --json' : 'npm audit --json'; const result = await session.shell(cmd); if (result.exitCode > 1) throw new Error(`Dependency audit failed: ${result.stderr.trim()}`); return await session.prompt(`Extract findings from audit JSON.\n\n${result.stdout.slice(0, 80_000)}`, { result: auditResult, }); }, }); ``` **Run it:** `pnpm --filter @fabric-harness/example-dependency-auditor run` · [source](/docs/reference/source-access) --- ## 6. Schema Migration Author Draft a forward + rollback SQL migration for a described change. Mutating apply commands are gated behind approval in the complete entrypoint example. ```ts import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ description: string; dialect?: string }>({ name: 'migrate', triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init()).session(); return await session.prompt( `Draft a ${input.dialect ?? 'postgres'} migration: "${input.description}". Return JSON { filename, upSql, downSql }.`, ); }, }); ``` ```ts import { defineAgent, schema } from '@fabric-harness/sdk'; import type { CapabilityPolicy } from '@fabric-harness/sdk'; const migrationResult = schema.object({ filename: schema.string(), upSql: schema.string(), downSql: schema.string(), }); const policy: CapabilityPolicy = { commandPolicy: { allow: ['ls migrations*', 'cat migrations/*'], requireApproval: ['psql*', 'pnpm prisma migrate*'], deny: ['rm -rf*'], }, approvals: { requiredApprovals: 1, defaultTimeoutMs: 300_000, risk: 'high' }, }; export default defineAgent({ name: 'migrate', input: schema.object({ description: schema.string(), dialect: schema.enum(['postgres', 'mysql']).optional() }), output: migrationResult, run: async ({ init, input }) => { const session = await (await init({ sandbox: 'local', policy })).session(); const existing = await session.shell('ls migrations 2>/dev/null || true'); return await session.prompt( `Draft a ${input.dialect ?? 'postgres'} migration: "${input.description}". Existing:\n${existing.stdout}`, { result: migrationResult }, ); }, }); ``` **Run it:** `pnpm --filter @fabric-harness/example-schema-migration run` · [source](/docs/reference/source-access) --- ## 7. API Docs Generator Generate MDX docs pages for HTTP routes, matching the tone of an existing Fumadocs site. ```ts import { defineAgent, fumadocsSource, withFilesystemSources, localDirectorySource } from '@fabric-harness/sdk'; export default defineAgent<{ sourceDir: string; docsRoot?: string }>({ name: 'apidocs', triggers: { webhook: true }, run: async ({ init, input }) => { const sandbox = withFilesystemSources('virtual', [ { mountAt: '/workspace/api', source: localDirectorySource(input.sourceDir) }, ...(input.docsRoot ? [{ mountAt: '/workspace/kb', source: fumadocsSource(input.docsRoot) }] : []), ]); const session = await (await init({ sandbox })).session(); return { mdx: await session.prompt( 'Read /workspace/api with the read tool. Match tone of /workspace/kb. Return JSON { ".mdx": "" }.', )}; }, }); ``` ```ts import { defineAgent, fumadocsSource, localDirectorySource, schema, withFilesystemSources } from '@fabric-harness/sdk'; const generatedDocs = schema.object({ pages: schema.record(schema.string()) }); export default defineAgent({ name: 'apidocs', input: schema.object({ sourceDir: schema.string(), docsRoot: schema.string().optional() }), output: generatedDocs, run: async ({ init, input }) => { const sandbox = withFilesystemSources('virtual', [ { mountAt: '/workspace/api', source: localDirectorySource(input.sourceDir) }, ...(input.docsRoot ? [{ mountAt: '/workspace/kb', source: fumadocsSource(input.docsRoot) }] : []), ]); const session = await (await init({ sandbox })).session(); return await session.prompt('Generate MDX page per route. Return { pages: { slug: content } }.', { result: generatedDocs, }); }, }); ``` **Run it:** `pnpm --filter @fabric-harness/example-api-docs-generator run` · [source](/docs/reference/source-access) --- ## 8. Bug Reproducer Convert a free-form bug report into a minimal failing test. ```ts import { defineAgent } from '@fabric-harness/sdk'; export default defineAgent<{ issueBody: string; framework?: string }>({ name: 'repro', triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init()).session(); return { repro: await session.prompt( `Produce a minimal failing ${input.framework ?? 'vitest'} test for this report:\n\n${input.issueBody}`, )}; }, }); ``` ```ts import { defineAgent, schema } from '@fabric-harness/sdk'; const reproduction = schema.object({ testCode: schema.string(), runCommand: schema.string() }); export default defineAgent({ name: 'repro', input: schema.object({ issueBody: schema.string(), framework: schema.enum(['vitest', 'jest']).optional() }), output: reproduction, run: async ({ init, input }) => { const session = await (await init()).session(); return await session.prompt( `Produce a minimal failing ${input.framework ?? 'vitest'} test. Return JSON { testCode, runCommand }.\n\n${input.issueBody}`, { result: reproduction }, ); }, }); ``` **Run it:** `pnpm --filter @fabric-harness/example-bug-reproducer run` · [source](/docs/reference/source-access) --- ## 9. Release Notes Drafter Customer-facing release notes from merged PRs between two tags. ```ts import { defineAgent, shellQuote } from '@fabric-harness/sdk'; const gitRevision = (value: string) => { if (!/^[A-Za-z0-9][A-Za-z0-9._/~^{}-]{0,127}$/.test(value)) throw new Error(`Invalid Git revision: ${value}`); return value; }; export default defineAgent<{ tag: string; previous: string }>({ name: 'release-notes', triggers: { webhook: true }, run: async ({ init, input }) => { const session = await (await init({ sandbox: 'local', policy: { commandPolicy: { allow: ['git log*', 'gh pr list*'] }, maxCommandTimeoutMs: 30_000, }, })).session(); const previous = shellQuote(gitRevision(input.previous)); const sinceResult = await session.shell(`git log -1 --format=%aI ${previous}`); if (sinceResult.exitCode !== 0) throw new Error(`git log failed: ${sinceResult.stderr.trim()}`); const search = shellQuote(`merged:>=${sinceResult.stdout.trim()}`); const prs = await session.shell(`gh pr list --state merged --search ${search} --json number,title,labels --limit 200`); if (prs.exitCode !== 0) throw new Error(`gh pr list failed: ${prs.stderr.trim()}`); return { notes: await session.prompt( `Write release notes for ${input.tag}. Group: Highlights/New/Improved/Fixed.\n\n${prs.stdout}`, )}; }, }); ``` ```ts import { defineAgent, schema, shellQuote } from '@fabric-harness/sdk'; const releaseNotes = schema.object({ highlights: schema.array(schema.string()), new: schema.array(schema.string()), improved: schema.array(schema.string()), fixed: schema.array(schema.string()), }); const gitRevision = (value: string) => { if (!/^[A-Za-z0-9][A-Za-z0-9._/~^{}-]{0,127}$/.test(value)) throw new Error(`Invalid Git revision: ${value}`); return value; }; export default defineAgent({ name: 'release-notes', input: schema.object({ tag: schema.string(), previous: schema.string() }), output: releaseNotes, policy: { commandPolicy: { allow: ['git log*', 'gh pr list*'] }, maxCommandTimeoutMs: 30_000, }, run: async ({ init, input }) => { const session = await (await init({ sandbox: 'local' })).session(); const previous = shellQuote(gitRevision(input.previous)); const sinceResult = await session.shell(`git log -1 --format=%aI ${previous}`); if (sinceResult.exitCode !== 0) throw new Error(`git log failed: ${sinceResult.stderr.trim()}`); const search = shellQuote(`merged:>=${sinceResult.stdout.trim()}`); const prs = await session.shell(`gh pr list --state merged --search ${search} --json number,title,labels --limit 200`); if (prs.exitCode !== 0) throw new Error(`gh pr list failed: ${prs.stderr.trim()}`); return await session.prompt(`Write release notes for ${input.tag}.\n\n${prs.stdout}`, { result: releaseNotes, }); }, }); ``` **Run it:** `pnpm --filter @fabric-harness/example-release-notes run` · [source](/docs/reference/source-access) --- ## 10. Incident Runbook Assistant Match an alert to a mounted runbook and walk through diagnostic steps. Read-only — never executes. ```ts import { defineAgent, fumadocsSource, withFilesystemSources } from '@fabric-harness/sdk'; export default defineAgent<{ alert: string; runbookRoot?: string }>({ name: 'runbook', triggers: { webhook: true }, run: async ({ init, input }) => { const sandbox = withFilesystemSources('virtual', [ { mountAt: '/workspace/runbooks', source: fumadocsSource(input.runbookRoot ?? './runbooks') }, ]); const session = await (await init({ sandbox })).session(); return { plan: await session.prompt( `Alert: "${input.alert}". Grep /workspace/runbooks, read the best match, return root causes + diagnostic commands. Do NOT execute.`, )}; }, }); ``` ```ts import { defineAgent, fumadocsSource, schema, withFilesystemSources } from '@fabric-harness/sdk'; const runbookPlan = schema.object({ matchedRunbook: schema.string(), likelyCauses: schema.array(schema.string()), diagnosticCommands: schema.array(schema.string()), }); export default defineAgent({ name: 'runbook', input: schema.object({ alert: schema.string(), runbookRoot: schema.string().optional() }), output: runbookPlan, run: async ({ init, input }) => { const sandbox = withFilesystemSources('virtual', [ { mountAt: '/workspace/runbooks', source: fumadocsSource(input.runbookRoot ?? './runbooks') }, ]); const session = await (await init({ sandbox })).session(); return await session.prompt(`Alert: "${input.alert}". Match a runbook and return structured causes + commands.`, { result: runbookPlan, }); }, }); ``` **Run it:** `pnpm --filter @fabric-harness/example-incident-runbook run` · [source](/docs/reference/source-access) --- ## How they compose These ten aren't isolated. Real workflows combine them: ```mermaid graph LR A[GitHub webhook] --> B[#1 Triage] B -->|severity high| C[#8 Bug Reproducer] C --> D[Failing test in PR] D --> E[#2 PR Reviewer] E -->|approved| F[Merge] F --> G[#3 Changelog] G --> H[Release tag] H --> I[#9 Release Notes] H --> J[#5 Dep Audit] ``` Adjacent stages share the same TechFabric Harness primitives — one agent's `output` schema feeds the next agent's `input` schema, and the policy stays consistent across the pipeline. ## Picking an entrypoint | Choose the minimal entrypoint when | Choose the complete entrypoint when | |---|---| | Prototyping, internal tools, edge/serverless deployment | Mutations need approval, you want typed I/O at the boundary | | Inputs are loose JSON | Inputs come from a webhook with a versioned schema | | One agent, one model | Skills, custom roles, custom session stores, telemetry | | Cloudflare Workers, Vercel Edge, Lambda | Temporal worker, Foundry Hosted, Docker fleet | You can mix: an agent using the minimal entrypoint can `init({ policy })` to opt into capability gating without leaving the smaller import graph. Durability still comes from runtime settings, not the import path.