Workflows

Build a Fabric Harness agent

Scaffold, authorize, test, and deploy a finite Fabric Harness agent that operates GTM Brain through the governed MCP gateway.

Fabric Harness agents and Hermes use the same external-agent boundary. A Harness agent does not import GTM Brain stores, Temporal workflows, or Fabric Platform Host. It connects to one tenant registration through GTM Brain's MCP endpoint, discovers only that registration's current tools, and submits every business change to the same governed actions used by the product UI.

Rendering diagram...

The UI, Hermes, and a Harness agent therefore share action semantics, not blanket privileges. Tenant administrators decide which actions, campaigns, skills, budgets, and expiration belong to each registration. A catalog response or admitted request does not preserve stale authority: GTM Brain checks the current registration and resource scope again at the final Platform Host boundary.

Choose an agent shape

Use one of these supported patterns:

PatternBest forDeployment
External finite Harness agentA separately owned research, operations, or campaign agentLocal Node, container, or Databricks App
Built-in GTM agentA versioned agent shipped and certified with GTM BrainDetached Databricks App artifact

Both use Fabric Harness finite-agent contracts. The external pattern below is the fastest way to add a new agent without changing or redeploying GTM Brain.

1. Create the GTM registration

An organization administrator opens Team & agents → Agents and:

  1. creates or enables the external-agent registration;
  2. selects proposal and execution actions;
  3. sets exact campaign or skill scope;
  4. sets expiration, model, token, cost, and concurrency limits;
  5. leaves prospect-visible effects approval-gated unless the tenant has deliberately delegated them;
  6. generates the registration credential and stores the reveal-once value in a secret manager.

The credential is bound to exactly one registration. Rotating it increments that registration's credential generation and invalidates admitted work that has not yet passed final authorization.

For a production tenant, complete all human administrator profiles and select Enforce profiles before enabling an external agent. Observe mode is a bootstrap aid, not the production target.

2. Scaffold a Harness workspace

Use the public Harness CLI:

npx @fabric-harness/cli init gtm-operator --template minimal --store postgres
cd gtm-operator
npm install

Use memory only for disposable local development. Use PostgreSQL or Lakebase when submissions and finite runs must survive process replacement.

Add the registration values to .env.local or the deployment secret manager:

GTM_ORIGIN=https://gtm.fabric.pro
GTM_ORGANIZATION_ID=<organization-id>
GTM_AGENT_KEY=<registration-bound-key>
FABRIC_MODEL=<provider/model>

Never put the key in a prompt, tool argument, source file, Harness session artifact, or deployment manifest.

3. Define the finite agent

Create .fabricharness/jobs/gtm-operator.ts:

import { connectMcpServer, defineAgent, schema } from "@fabric-harness/sdk/strict";

export default defineAgent({
	name: "gtm-operator",
	description: "Researches an account and proposes only tenant-authorized GTM actions.",
	input: schema.object({
		requestId: schema.string().describe("Stable logical request ID"),
		instruction: schema.string(),
		accountDomain: schema.string().optional(),
	}),
	output: schema.string(),
	model: process.env.FABRIC_MODEL!,
	triggers: { manual: true, webhook: true },
	run: async ({ init, input }) => {
		const origin = process.env.GTM_ORIGIN!;
		const organizationId = process.env.GTM_ORGANIZATION_ID!;
		const registrationKey = process.env.GTM_AGENT_KEY!;

		const gtm = await connectMcpServer("fabric-gtm", {
			url: `${origin}/api/agents/gtm/${organizationId}/mcp`,
			headers: {
				"x-gtm-agent-key": registrationKey,
			},
			// allowTools filters the remote MCP names before Harness adds its
			// mcp__<server>__ prefix.
			allowTools: ["get_catalog", "gtm__*", "action__gtm__*"],
		});

		try {
			const runtime = await init({
				runtime: "inline",
				sandbox: "empty",
				tools: gtm.tools,
				compaction: { enabled: false },
			});
			const session = await runtime.session();

			return await session.prompt(`
        Request ID: ${input.requestId}
        Account: ${input.accountDomain ?? "not specified"}

        ${input.instruction}

        Call mcp__fabric-gtm__get_catalog before taking action. Use
        ${input.requestId} as the stable idempotency-key prefix. Do not retry
        authorization denials. Treat waiting_for_approval as a valid parked
        result, not a failure.
      `);
		} finally {
			await gtm.close();
		}
	},
});

The strict entry point makes runtime choices explicit. The loop remains finite under Harness runtime limits, while GTM Brain independently enforces tenant budgets, grants, current campaign/resource scope, action policy, approvals, adapter recovery, and idempotency.

Do not wrap GTM mutations in a second local policy engine. A Harness tool may propose or request a GTM action, but GTM Brain's Platform Host remains the authoritative mutation boundary.

4. Inspect and test

First validate discovery, schemas, and termination without calling a model:

fh agents
fh describe gtm-operator
fh run gtm-operator \
  --requestId local-gtm-001 \
  --instruction "List the actions available to this registration." \
  --mock

Then use the real gateway with a read-only registration:

fh run gtm-operator \
  --requestId account-review-20260728-acme \
  --accountDomain acme.example \
  --instruction "Read the account context and summarize the strongest evidence."

Before granting mutation authority, certify:

  • unknown or ungranted actions fail closed;
  • campaign/resource scope is enforced for direct and indirect identifiers;
  • the same request ID and payload converge on one operation;
  • the same request ID with different parameters conflicts;
  • approval-gated work parks and exposes operation status;
  • credential rotation invalidates stale admitted work;
  • cancellation and retry limits terminate cleanly;
  • agent-created events and runs appear only in the authorized tenant and registration projections.

5. Deploy as a Databricks App

Harness owns the deployable agent artifact:

fh deploy --target databricks-app

The Harness deployment driver builds the Databricks App artifact, validates its bundle resources, uploads it, and starts it through databricks apps deploy. For an explicit build-and-inspect flow, run fh build --target databricks-app, enter the generated dist/databricks-app directory, and follow its generated deployment README. Do not use databricks bundle run for the App artifact.

The generated directory contains app.yaml, databricks.yml, the bundled Harness server, immutable job definitions, and a deployment manifest. Treat that directory as the deployment unit. Bind GTM_ORIGIN, GTM_ORGANIZATION_ID, and GTM_AGENT_KEY through Databricks App resources or secrets; do not commit their values.

The Databricks App identity may invoke models and the GTM ingress, but it does not receive GTM Lakebase, Temporal, provider, or Platform Host credentials.

6. Operate it from GTM Brain

The administrator and operator experience remains in GTM Brain:

  • Team & agents manages status, grants, scope, credential generation, budgets, and kill switches. The detailed controls live under Advanced: access & autonomy.
  • Agents shows finite runs, model/runtime identity, usage, action evidence, and retained attestations.
  • Up next and Approvals show work that requires a person or a separately authorized agent.
  • Accounts, Signals, Artifacts, and Activity expose resulting projections and provenance.
  • The external operation-status tools let the Harness agent reconcile started, parked, failed, and completed work without scraping the UI.

Humans and agents can call the same action, but GTM Brain records their different actor identities and applies their different authority. Approval, publication, campaign activation, and sending are available to an agent only when the tenant explicitly grants the corresponding execution capability and all current policy requirements pass.

Built-in GTM agents

To ship an agent with GTM Brain itself, add it to the repository's agents Harness workspace, publish an immutable agent version, certify its source/runtime digest and evaluations, and build:

pnpm agents:build:databricks-app

The output at agents/.fabricharness/build/databricks-app/ is a detached Databricks App artifact. Installing a built-in definition never silently enables it for a tenant. An administrator must still create or bind a tenant registration, grant authority, set budgets, and enable it.

See Agents, Team & agents: advanced access and autonomy, and External agent gateway for the complete runtime, API, and recovery contracts.

On this page