FabricFabricHarness
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

fh build --target node

Output:

.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

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

curl http://localhost:8080/jobs/ask \
  -H 'content-type: application/json' \
  -d '{"question":"What is durable execution?"}'

The response includes { result, runId, agentPath }.

Invoke a persistent agent

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

MethodRoutePurpose
GET/healthLiveness probe.
GET/readyReadiness and workspace root.
GET/admin/agentsList finite jobs and persistent agents with kind.
POST/jobs/:nameInvoke a finite job.
POST/agents/:name/:idAdmit persistent input; 202 by default.
POST/agents/:name/:id/dispatchEnqueue asynchronous persistent input.
GET/agents/:name/:id/conversationRead conversation batches by offset.
GET/agents/:name/:id/stream?offset=...Catch up and tail with SSE.
GET/agents/:name/:id/submissions/:submissionIdRead settlement status.
POST/agents/:name/:id/abortRequest durable abort.
GET/sessionsList persisted sessions.
GET/builds/:target/manifestRead a build manifest under the workspace build directory.

Environment

VariablePurpose
PORTListen port; default 3000.
DATABRICKS_APP_PORTTakes precedence over PORT in a generated App artifact.
FABRIC_HARNESS_HOSTListen address; default 0.0.0.0.
FABRIC_HARNESS_API_TOKENBearer token for HTTP and WebSocket access; required for protected routes in production unless a custom authorizer is installed.
FABRIC_HARNESS_MAX_BODY_BYTESJSON/body limit; default 1 MiB.
FABRIC_HARNESS_RATE_LIMIT_MAXPer-process request limit; 0 disables it.
FABRIC_HARNESS_RATE_LIMIT_WINDOW_MSRate-limit window; default 60 seconds.
FABRIC_HARNESS_TENANT_REQUIRED=1Require 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.

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.

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. For the full job/agent walkthrough, see Build and run artifacts.