Connect an outside agent
Connect any outside agent and approve exactly what it may do.
Connect Cursor, Grok Bot, Hermes, or another compatible agent without sharing database credentials, workspace identifiers, or hand-written configuration. GTM Brain prepares one private message containing everything the agent needs. The agent asks for access, and a workspace administrator reviews the request before anything turns on.
Connect an agent
The shortest human path is now visible in the main sidebar:
- Select Connect an agent, then select the single Connect an agent action to begin.
- Name the agent and choose the work it should help with. Write and review copy is the safe default and does not require a campaign.
- Select Create connection request. Keep the page open while GTM finishes; the button stays disabled and the ready state appears automatically.
- Select Copy instructions for your agent. This copies the pairing code and the complete setup request together—do not copy or construct JSON yourself.
- Paste the copied instructions into a private chat with the agent. The agent submits its request and stops for approval.
- Return to Approvals, review what it can and cannot do, and approve or decline it.
- Store the reveal-once key in the agent client's secure settings when prompted; never paste that key
into chat. Then use the try-it prompt returned by
get_catalog, such as Show the current operational summary. GTM only suggests work the approved catalog actually exposes.
If the page is refreshed while GTM is preparing the request, it offers Continue the same request for five minutes. Continuing replays the same governed command; it does not mint a second invite. Team & agents → Approvals shows only requests waiting for review and connection history, not the setup form.
Campaign selection is collapsed by default. Open it only when you want to limit access to a specific campaign or when the chosen role can run campaign work. Active campaigns appear first; draft campaigns stay behind Show draft campaigns so old test drafts and duplicate names do not bury the normal path. Each campaign includes its status, version, and a short ID suffix so similarly named campaigns remain distinguishable.
Agent operations under Workspace is for the built-in GTM specialists and runtime evidence. It is not where an outside agent is connected.
External runtimes can self-enroll without receiving an administrator session, a Fabric database
credential, or an infrastructure service principal. An organization administrator creates a short-lived,
single-use pairing credential through POST /gtm/external-agents/invites. Current workers reveal an
unambiguous GTM-XXXX-XXXX code once. During a rolling upgrade, an older worker may reveal an opaque,
case-sensitive gtminv_… credential instead; agents must copy either form exactly as supplied. Only
its environment- and purpose-separated HMAC attestation enters durable state; the credential is never
placed in a URL.
“Single use” means one external runtime can redeem the token in one successful enrollment request. The
code is consumed by that request and expires after 24 hours when unused. From GTM Brain → Connect an
agent, Copy instructions for your agent creates a ready-to-paste handoff for Cursor, Hermes,
Grok Bot, or another compatible runtime. Agents can also begin from the machine-readable
SKILL.md. The pairing code authorizes one request only; the separate
registration key returned after human approval and claim authorizes the ongoing MCP connection until an
administrator revokes or rotates it. Before creating the handoff, the administrator must enter a
recognizable runtime name, such as Hermes production. Campaign scope is optional for read and draft-only
work and required for execution authority. The name is preserved in review, registration, and audit surfaces so
operators can identify the caller. The copied handoff includes the pairing code, current external-agent
version, desired outcome, optional campaign scope, and a complete bounded request. The human never has
to find or type a tenant ID, invite UUID, campaign UUID, or JSON. The administrator can narrow every
requested capability during review.
The product setup flow asks for two required choices before the handoff is created:
- Give the agent a recognizable name that will appear in review, agent, and audit views.
- Choose a plain-language outcome. Write and review copy is the recommended default. Running a campaign is broader and requires an explicit campaign.
Campaign scope is an optional advanced choice for writing and review. Research or operational work may require a campaign, depending on the exact actions requested. The human configures these choices before GTM creates the single-use request, so the reveal-once handoff is never stranded above a long form.
After the agent submits the handoff, the enrollment card shows four stages: Access requested, Administrator approved, Waiting for agent, and Connected. Approval begins with a short summary of the campaign and capability counts. Review advanced permissions exposes the individual governed actions when an administrator needs to narrow the request. No role bypasses the action mutation pipeline, campaign scope, tenant checks, or the human gates that apply to prospect-visible or destructive work.
Campaign-workspace capabilities ship to the UI and reviewed external-agent catalog together. An authorized runtime can read the same campaign, ICP, knowledge, cohort, artifact, and readiness context; create or revise working copies; and request the next governed action within its approved scope. Every durable change records the named runtime, exact campaign and version, action, correlation, and result. The runtime never receives provider credentials or direct database access.
A paused Instantly campaign is not a harmless draft: activating it can make email prospect-visible. Outside agents may prepare the campaign and request activation, but they cannot perform provider activation or live promotion themselves. Those transitions remain bound to the exact reviewed manifest and natural-person authorization at the final delivery boundary.
The selector shows current active campaigns first. Draft campaigns appear only after the administrator opens Show draft campaigns. Historical versions, system campaigns, paused campaigns, and retired campaigns are not delegation choices. Existing registrations do not silently inherit a new campaign: the runtime must request a new reviewed grant that includes the new campaign, preserving the administrator approval boundary.
The external runtime generates and retains separate 256-bit random claim and status secrets, then submits:
{
"commandId": "<stable-submit-command-id>",
"enrollmentRequestId": "<stable-request-id>",
"pairingCode": "GTM-7K4Q-9H2M",
"claimSecret": "<caller-generated-base64url-encoded-32-random-bytes>",
"statusSecret": "<different-caller-generated-base64url-encoded-32-random-bytes>",
"runtimeKind": "generic-mcp",
"displayName": "Grok Bot production",
"requestedRegistration": {
"registrationId": "grok-production",
"agentDefinitionId": "external-signal-researcher",
"agentVersionId": "<currently-certified-version>",
"autonomy": "bounded",
"campaignIds": ["<initial-dry-run-campaign-id>"],
"grant": {
"grantId": "<grant-id>",
"readTools": [
"gtm.read_account_context",
"gtm.read_operational_state",
"gtm.search_workspace_knowledge"
],
"proposalActions": ["<selected reviewed proposal actions>"],
"executionActions": ["<selected reviewed execution actions>"],
"campaignIds": ["<initial-dry-run-campaign-id>"],
"skillIds": [],
"expiresAt": "<short-lived-ISO-8601-expiry>"
}
}
}Submit this document to POST https://app.gtm.fabric.pro/api/gtm/external-agents/enroll.
Enrollment, status, and claim use the application host; the authenticated agent gateway uses
https://gtm.fabric.pro. The enrollment call returns the resolved organization ID,
a non-secret request receipt, and status guidance. The public boundary resolves and consumes the exact
pairing code, hashes the claim and status
secrets before durable invocation creation, and calls
gtm.submit_external_agent_enrollment as a narrowly bound system actor. Reusing the invite for another
request fails. Poll POST /gtm/external-agents/enrollments/status with the receipt and status secret;
unknown, expired, throttled, and invalid requests deliberately return the same generic failure.
The public boundary maintains independent tenant, token-hash, and network-source rate windows. The
production reverse proxy must remove client-supplied forwarding headers and set the authoritative
X-Forwarded-For or X-Real-IP value before the request reaches GTM Brain.
External callers use the certified public gtm.ingest_signal action. The compact
gtm.ingest_signal_v2 action is reserved for the repository-owned composite ingestion workflow because
it consumes a private staged-evidence binding; it is never granted directly to an external runtime.
gtm.search_workspace_knowledge is a distinct, tenant-wide read grant. It is not implied by account
context or campaign scope. When granted and AI Search is enabled, MCP exposes
gtm__search_workspace_knowledge. GTM Brain performs the Databricks query under its own App identity,
then rejects stale, draft, archived, personal, deleted, unknown, or cross-tenant candidates against
the current Lakebase projection. Hermes receives bounded text and citation bindings—not a Databricks
credential, raw index client, or ability to write the index.
Each tenant registration ID can have only one enrollment record. PostgreSQL enforces that binding, so two otherwise-valid invites racing to provision the same registration cannot create competing registrations or credential generations. A rejected or revoked identity is retained as audit evidence; use a new registration ID for a replacement enrollment.
An administrator reviews the immutable request through GET /gtm/external-agents/enrollments,
optionally checks a concrete action with POST /gtm/external-agents/access/preview, and approves or
rejects it through POST /gtm/external-agents/enrollments/decide. The administrator may narrow the
requested authority but cannot add an unrequested capability; the decision persists both immutable
envelope hashes and the subset proof. Approval commits a deterministic operator-dispatch intent in the
same transaction, so a crash after approval cannot strand the request.
Approval does not create a parallel registration path. The versioned provisioning operator verifies
the exact completed human-decision invocation, creates the registration suspended, prepares one
encrypted reveal envelope, invokes gtm.configure_tenant_agent, then gtm.set_integration_secret, then
gtm.complete_external_agent_provisioning. Every step has a stable logical business-command identity;
each Temporal run receives a distinct HMAC-bound one-use admission, actor, and private staging identity.
The completion action binds both canonical invocation IDs to the exact credential generation. Temporal
history contains only tenant, dispatch, workflow/run, invocation, and opaque staged-command IDs. An
activity retry reuses the same admission. A governed Temporal reset gets a new run-bound admission while
Platform Host idempotently recovers the original business invocation; neither path invents another
registration, credential generation, or secret. The activity verifies the claimed workflow and run
against Temporal's execution context before it stages a command.
The runtime presents its original claim secret to the POST /gtm/external-agents/claim endpoint at
https://app.gtm.fabric.pro/api/gtm/external-agents/claim. A successful claim
atomically consumes the encrypted envelope, records claimed_pending_activation, and creates the
activation dispatch. It returns the registration-bound gateway key and credential version only during a
five-minute exact-command recovery window. A different command or a retry after that window cannot
recover the plaintext and requires administrator rotation. Store the returned key immediately in the
runtime's secret manager. The response also returns gatewayUrl, the absolute authenticated HTTP base,
and gatewayPath, its path component. Prefer gatewayUrl and append only a documented endpoint such as
/catalog, /invoke, or /mcp. The activation operator revalidates the enrollment fence and only then enables
the exact registration through gtm.configure_tenant_agent.
During this short activation window, the gateway returns HTTP 503 with
code: "agent_activation_pending", retryable: true, and Retry-After: 5. Retry with the same key;
do not send the operator back through approval. The MCP adapter carries the same delay in
error.data.retryAfterSeconds while returning JSON-RPC over HTTP 200. This transient response is bounded;
if it becomes the non-retryable agent_paused, ask the administrator to review the failed or paused
connection.
Invite revocation, enrollment revocation, registration disablement, credential removal, claim-ready expiry, and bounded retention are also governed actions. Revocation increments a monotonic fence before the offboarding operator suspends the registration and revokes the exact credential generation. A racing provisioning or activation workflow cannot restore authority afterward. Enrollment rows use tenant-composite relational constraints in PostgreSQL migration 50; raw invite tokens, claim/status secrets, and gateway keys are absent from Platform parameters, events, audit payloads, Temporal history, and ordinary reads.
Offboarding is valid from pending_review and every approved lifecycle state, including a provisioning
attempt that failed before creating its reveal envelope or installing a credential. A pre-approval
revocation records the fence and terminal audit evidence without inventing a decision, registration, or
credential invocation. Terminal records preserve whichever registration and credential invocation
bindings actually exist; they do not invent missing completion evidence. The operator reads canonical
registration state before staging suspension: it skips the
registration action when installation never completed, and an exact existing registration may only
move to disabled even if its historical grant is no longer accepted for new enablement. This lets the
monotonic revocation fence converge after a partial failure or contract change while
claim_ready, claimed_pending_activation, and active continue to require the full provisioning
attestation.
Manual administration and rotation
The invite-driven enrollment above is the normal installation path. It creates the certified External account operator registration and its first registration-bound gateway credential through canonical governed actions. The registration is not a locally runnable Harness agent—it is the identity and capability boundary for an out-of-process runtime such as Hermes.
After enrollment, an administrator can use Team & agents to narrow or disable the registration and Settings → Integrations → Agent gateway to rotate its credential. Rotation invalidates only that registration's previous credential. The key embeds an opaque registration binding; the caller cannot select another registration through query parameters, headers, or request bodies. Manual registration and credential controls are retained for recovery and rotation, not as an alternate ungoverned installation path.
Store the key in the calling platform's secret manager, never in source control or model context.
Connect any AI harness through MCP
GTM Brain exposes one remote Streamable HTTP MCP server. Agent identity, campaign scope, action grants, approval rules, audit, and revocation live in GTM Brain rather than in a client-specific connector. The same connection works with Grok Bot, Claude, Hermes, Kimi, a CLI, or another standards-compatible MCP client.
Prefer the client's native bearer-token field:
MCP URL: https://gtm.fabric.pro/api/agents/gtm/<organization-id>/mcp
Authentication: Bearer token
Token: <reveal-once registration key>GTM accepts Authorization: Bearer <registration key> and, for compatibility with existing clients,
x-gtm-agent-key: <registration key>. These are two transports for the same tenant-bound credential;
they do not create different authority. A connection is working only after get_catalog returns the
tools allowed by the current grant. “Added” or “secret saved” in a client does not prove authentication.
Most MCP clients load servers when a session starts. Restart the client or open a new private session after saving the server. Do not rotate a key just to retry setup; rotation is for loss or exposure.
Connect Grok Bot through MCP
Grok Bot runs in a persistent environment and can connect to remote MCP servers. See xAI's
Grok Bot overview and
apps and MCP guidance. Create the invite in
Connect an agent, approve the request in Approvals, then finish the one-time setup shown by GTM
Brain. Put the reveal-once registration key in the secret-variable field for the
approved team MCP/plugin configuration; never paste it into chat, instructions, source control, or a
routine. Saving the value in a generic bot secret card is not sufficient unless that same MCP/plugin
configuration binds the variable to the request header. Do not enter the literal ${GTM_AGENT_KEY}
unless Cursor's team MCP/plugin configuration explicitly supports variable interpolation. Prefer its
secure bearer-token control when available.
Configure this Streamable HTTP server in the Cursor team MCP/plugin settings used by Grok Bot. A team administrator may also need to allowlist the URL and enable the plugin. Grok Bot inherits that team configuration; a chat prompt cannot install or authenticate the connector by itself.
name: fabric_gtm
url: https://gtm.fabric.pro/api/agents/gtm/<organization-id>/mcp
headers:
x-gtm-agent-key: ${GTM_AGENT_KEY}The GTM registration must also be enabled. A paused or suspended registration deliberately returns no tools even when the key is correct. Enable the registration in Team & agents → Agents before reconnecting. Do not rotate the key or force a reconnect merely to fix a paused registration.
Routine reconnects reuse the installed key. Replace it only when it was lost or exposed. Replacing a key invalidates the old value immediately, so update the MCP/plugin variable before reconnecting.
Give the bot these operating instructions:
Use the fabric_gtm MCP server for all GTM Brain work. Call get_catalog at the start of each
session and treat it as the only available authority. Work only inside the campaigns returned by
the catalog. Use stable idempotency keys for every mutation. Source leads and propose campaign
work through catalog-advertised governed actions. Never bypass approvals, retry a failed_unknown
delivery, or attempt a direct send. GTM Brain does not yet expose appointment booking; create a
reviewable task or proposal when a prospect requests a meeting. Stop on authorization, scope, or
policy errors and ask an administrator to review them.Grok Bot's shared workspace is an operational convenience, not a GTM tenant boundary. Use a distinct GTM registration for each bot/team authority profile and rotate or revoke that registration from GTM Brain. Bot users who share the Grok workspace can use its configured credentials, so grant only the minimum campaigns and actions they collectively need.
Connect Hermes through MCP
Hermes does not install @fabricorg/platform-host and does not receive Lakebase, Temporal, model,
email-provider, or Databricks credentials. GTM Brain already runs Platform Host 0.7.0; Hermes connects
to the registration-bound MCP gateway that sits in front of it. The GTM registration is Hermes'
application account and the only identity that grants tenant actions or resource scope.
The production GTM Brain ingress is https://gtm.fabric.pro. Its narrow Cloudflare proxy forwards the
registration-bound GTM key to the Cloudflare application without adding another caller identity.
platform.fabric.pro documents the Fabric Platform framework; it is not the GTM Brain MCP endpoint.
GTM Brain derives the tenant, actor, and current action/resource authority from the GTM registration.
Do not create or give a cloud-provider or database credential to Hermes.
Hermes' standard installation includes MCP support. If MCP extras were intentionally omitted, install them using the Hermes MCP guide:
cd ~/.hermes/hermes-agent
uv pip install -e ".[mcp]"Put the generated registration key in ~/.hermes/.env:
GTM_AGENT_KEY=<registration-bound-key>Then add the remote server to ~/.hermes/config.yaml:
mcp_servers:
fabric_gtm:
url: "https://gtm.fabric.pro/api/agents/gtm/<organization-id>/mcp"
headers:
x-gtm-agent-key: "${GTM_AGENT_KEY}"
ssl_verify: true
skip_preflight: true
supports_parallel_tool_calls: false
timeout: 120
connect_timeout: 30
tools:
resources: false
prompts: falseSelf-hosted installations replace the production origin with their own GTM Brain application origin and expose the same authenticated gateway. The registration key is the only caller credential and must remain in secret storage; it is never a prompt, tool parameter, or action parameter.
skip_preflight is required because this stateless endpoint accepts authenticated JSON-RPC over POST
and does not expose an unauthenticated GET/HEAD probe. Keep TLS verification enabled. The key remains
in Hermes' environment file and is substituted into the header when the MCP session connects.
Tenant autonomy controls
The tenant access-and-autonomy policy is evaluated again at the final Platform Host boundary; a catalog
response or successful HTTP admission is not lasting authority. Administrators can pause all agent
execution or disable external-agent access without rotating every registration. In enforce mode,
external execution grants must expire and registrations with execution actions must carry the exact
campaign or skill scope required by those actions.
These controls, the reveal-once agent key, and their immutable audit events are available under Team & agents. See Team & agents: advanced access and autonomy for the rollout and recovery procedure.
Hermes should treat a response with retryable: false as a permanent access decision. Show its plain-
language message and setupUrl, then stop retrying until an administrator changes the connection.
Stable codes include agent_paused, workspace_agents_paused, outside_agents_disabled,
access_expired, expiry_required, agent_version_unavailable, and campaign_access_needed.
Read and action denials use information_access_not_approved, work_not_available,
work_not_approved, or campaign_not_approved with the same recovery shape.
The same fields are returned in JSON-RPC error data when discovery is temporarily unavailable.
Other governed tool denials remain normal MCP tool results with isError: true and their recovery
details in content[0].text.
Verify the connection, then reload an existing session or start a new one:
hermes mcp test fabric_gtm
# In an existing Hermes chat:
# /reload-mcpAsk Hermes to call get_catalog first. The other tool names are derived from the live,
registration-filtered catalog:
- read resources use names such as
gtm__read_account_context; - mutations use
action__<action-id>with dots replaced by double underscores, such asaction__gtm__upsert_task; - every mutation tool requires
{ idempotencyKey, params }.
Do not hard-code a broader tool list from another tenant or registration. A grant change becomes visible on the next MCP discovery/reload, and final execution authorization independently revalidates the current registration, expiry, action, campaign, and resource scope.
The certified gateway contract is gtm-external-agent-catalog-v14 /
gtm-external-gateway-v14. Reinstall or rebind the External campaign operator if its displayed runtime
version is older. The version's implementation digest certifies the catalog, action allowlist,
registration credential binding, caller-issued idempotency contract, opaque Temporal admission payload,
execution-time authorization, current resource scope, proposal-only tenant skill execution, and the
source-controlled external action-contract manifest. Every authenticated catalog response includes the
manifest schema version and digest. Catalog presence is descriptive and never grants authority.
Every externally callable action also has a committed fingerprint covering its normalized Platform
input schema, namespace/version, authority class, resource scope, idempotency/retry classification,
event phase, emitted events, and declared adapters. pnpm --filter @repo/gtm external-actions:certify prints a candidate with the exact source SHA, dirty-tree state, and
per-action diff. It does not certify its own output. CI compares the current definitions with the
source-controlled certified map; a new, removed, or changed action is quarantined from both catalog and
admission until an independently approved, clean-SHA recertification lands. Admission persists the exact
action fingerprint separately from the catalog release digest, and final execution checks that binding.
For non-Hermes runtimes, use the same endpoint with an MCP 2025-03-26 Streamable HTTP client, or use the REST catalog and invocation endpoints below. In either case, the external runtime installs no Platform database or mutation library.
Roll out enrollment safely
Enrollment is fail-closed by default. Production currently enables certification mode for explicitly allowlisted organizations:
GTM_EXTERNAL_AGENT_ENROLLMENT_MODE=certification
GTM_EXTERNAL_AGENT_ENROLLMENT_CERTIFICATION_TENANTS=<comma-separated-organization-ids>For dark certification, set GTM_EXTERNAL_AGENT_ENROLLMENT_MODE=certification and provide a
comma-separated GTM_EXTERNAL_AGENT_ENROLLMENT_CERTIFICATION_TENANTS allowlist. Use all only after
migration 50 PostgreSQL certification, the provisioning/activation/offboarding canaries, independent
contract review, and the exact-SHA release gates pass. This gate controls enrollment ingress; it does
not enable live delivery or autonomous prospect-visible actions.
Production also requires:
GTM_DEPLOYMENT_ENVIRONMENT=production
GTM_EXTERNAL_AGENT_TOKEN_PEPPER=<at-least-32-byte-secret>
GTM_EXTERNAL_AGENT_OPERATOR_ADMISSION_KEY=<at-least-32-byte-secret>
GTM_ENROLLMENT_ENVELOPE_ACTIVE_KEY_ID=<current-key-id>
GTM_ENROLLMENT_ENVELOPE_KEYS={"<current-key-id>":"<at-least-32-byte-secret>"}Keep prior envelope key IDs in GTM_ENROLLMENT_ENVELOPE_KEYS until every envelope encrypted with them
has expired and retention deletion has been verified. Rotate by adding the new key, deploying the key
map, then changing the active key ID. If the token pepper, operator-admission key, or active/historical
envelope key is unavailable, enrollment and recovery fail closed.
Certify a disposable Hermes enrollment
Before a production rollout, run the finite clean-state certification against the dark deployment. It
creates one disposable invite and registration, invokes only gtm.upsert_note, rotates the credential,
proves the old key fails, revokes the enrollment, proves the rotated key fails, and emits a privacy-safe
report. It never enables delivery or invokes a prospect-visible action.
Set these values through the release secret manager, not a committed environment file:
GTM_HERMES_CERT_BASE_URL=https://<exact-deployed-application-host> \
GTM_HERMES_CERT_ORGANIZATION_ID=<certification-organization-id> \
GTM_HERMES_CERT_ADMIN_COOKIE='<short-lived-admin-session-cookie>' \
GTM_HERMES_CERTIFICATION_ID=<stable-release-certification-id> \
GTM_HERMES_CERTIFIED_AGENT_VERSION_ID=<exact-v10-agent-version-id> \
GTM_HERMES_CERT_SCHEMA_FINGERPRINT=sha256:0e66df018fc0bd6d03ce027b468cdbea2c9fb8daa143402692d7196cf7216efe \
GTM_HERMES_CERT_SOURCE_REVISION=<exact-deployed-commit-sha> \
GTM_HERMES_CERT_EVIDENCE_PATH=reports/hermes-enrollment-certification.json \
pnpm hermes:certify-enrollmentCertification IDs use only letters, digits, dots, underscores, and hyphens because the script derives all durable command and request IDs from that value. The schema fingerprint above is the canonical migration-50 structure fingerprint emitted by the release gate; replace it only when a later rehearsed migration changes the certified production schema.
The report contains only hashed tenant, registration, enrollment, and invocation identities plus the source revision, schema fingerprint, manifest digest, catalog version, counts, denial results, and cleanup status. Invite tokens, claim secrets, gateway keys, the session cookie, note body, and raw tenant identifiers are excluded. The same scenario runs under the Fabric Experiments BDD evidence formatter in the worker test suite.
Human and AI operating boundary
Grok Bot, Hermes, and other enabled, registration-bound agents can operate production GTM capabilities that appear in their current catalog: research, account context, governed signal ingestion, notes/tasks, tenant skills, artifact proposals, and explicitly delegated campaign operations. Humans use the same canonical actions from the application. Neither path receives Lakebase, Temporal, Platform Host, delivery-provider, or Databricks credentials.
The internal gtm.send_approved_outreach_v2 action is never an external MCP tool. A live campaign pass
may eventually reach it only through the durable operator workflow after current registration scope,
campaign admission, policy, and the exact draft decision all pass. During a governed live launch,
natural-person approval is enforced again inside that action, so an agent-authored approval cannot
produce the prospect-visible send even if the agent has an outreach.approver grant. The agent may still
reject the draft or operate dry runs. See
Governed campaign launch.
Appointment booking is not exposed to external agents yet. Until a governed booking action lands, an agent may record the reply and create a reviewable task or proposal, but it must not call a calendar provider directly or claim that a meeting is booked.
Discover actions
curl \
-H "x-gtm-agent-key: $GTM_AGENT_KEY" \
"https://<app-host>/api/agents/gtm/<organization-id>/catalog"The catalog is generated from the canonical Platform action registry, intersected with GTM's explicitly reviewed external-capability allowlist, and filtered to the authenticated registration's current read, proposal, and execution grants. A newly registered action is unavailable externally until maintainers classify its effect, retry, scope, authorization, and recovery semantics. Catalog presence is descriptive; the same registration and grant are revalidated again at the final Host mutation boundary.
Read an account workspace
Use the registration-bound key to load the projection shown in the account half-sheet:
curl \
-H "x-gtm-agent-key: $GTM_AGENT_KEY" \
"https://<app-host>/api/agents/gtm/<organization-id>/accounts/<domain>/context"The response is gtm-account-context-v1. It includes company identity, eligible contact summary,
qualification and evidence, delivery attempts, account-bound tasks and team notes, campaign/artifact
references, proactive suggestions, and privacy-safe AssetEvent metadata. It omits private notes, raw event
payloads, secrets, and full staged commands. This resource is read-only; agents use /invoke for changes.
Invoke an action
Use a stable idempotency key for every logical request. If the caller loses the HTTP response and retries, GTM Brain reuses the same Temporal workflow instead of executing the mutation twice.
{
"contractVersion": 2,
"actionId": "gtm.ingest_signal",
"idempotencyKey": "research-20260711-northstar",
"params": {
"companyName": "Northstar AI",
"identifierClaims": [
{
"namespace": "domain",
"value": "northstar.ai",
"verification": {
"method": "provider_api",
"verifiedAt": "2026-07-11T18:30:00.000Z",
"sourceHash": "sha256:<64-lowercase-hex>"
}
}
],
"evidence": {
"evidenceId": "evidence-research-20260711-northstar",
"schemaVersion": "gtm-signal-schema-v2",
"evidencePolicyVersion": "gtm-evidence-policy-v1",
"provider": "public-web",
"origin": "provider_api",
"sourceNamespace": "research.public",
"sourceId": "research-20260711-northstar",
"sourceUrl": "https://example.com/source",
"retrievedAt": "2026-07-11T18:30:00.000Z",
"verification": { "method": "provider_api", "status": "unverified_public" },
"quote": "Opened a new data platform leadership role",
"contentHash": "sha256:<64-lowercase-hex>",
"sensitivity": "public",
"retention": "operational_180d",
"retentionPolicyVersion": "gtm-retention-policy-v1",
"entityId": "incoming-northstar",
"factFingerprint": "new data platform leadership role",
"subtype": "data_platform_leadership_hiring",
"collectorActorId": "hermes-researcher"
},
"signal": {
"signalId": "signal-research-20260711-northstar",
"sourceNamespace": "research.public",
"sourceId": "research-20260711-northstar",
"bucket": "company",
"subtype": "data_platform_leadership_hiring",
"summary": "Opened a new data platform leadership role",
"occurredAt": "2026-07-11T18:30:00.000Z",
"confidence": 0.8,
"schemaVersion": 2,
"contractVersion": 2,
"signalSchemaVersion": "gtm-signal-schema-v2",
"signalPolicyVersion": "signal-policy-v2"
}
}
}curl -X POST \
-H "content-type: application/json" \
-H "x-gtm-agent-key: $GTM_AGENT_KEY" \
-H "x-idempotency-key: research-20260711-northstar" \
"https://<app-host>/api/agents/gtm/<organization-id>/invoke" \
--data @payload.jsonThe registration-bound credential selects an enabled, tenant-owned principal. The server derives actor
identity from it; callers cannot provide or impersonate a registration, evaluator, or actor ID. The response includes both
the Temporal workflowId and governed actionInvocationId, which appear in the audit trail.
The idempotency key is mandatory. Same key plus the same canonical request converges on one result; the same key with changed evidence fails with conflict. GTM derives the opaque staging ID, so full evidence does not enter Temporal history. Consumed private staging is retained for a bounded recovery window, so an exact same-key replay after completion returns the original workflow and action invocation without leasing the consumed row, issuing new authority, or producing another event.
Treat waiting_for_approval, pending, and running as durable non-terminal states. Preserve the
returned actionInvocationId, poll the scoped operation-status resource, and do not change parameters or
mint a new idempotency key merely because a transport response was lost. completed,
blocked_by_policy, validation_failed, and failed are terminal for that exact invocation; ambiguous
provider outcomes are resolved through the advertised governed reconciliation action, never by directly
repeating a send.
Run an active tenant skill
A tenant skill is reviewed configuration for the compiled finite Tenant skill runner. It is not uploaded code and cannot create authority. Before Hermes can request one:
- In Workspace → Operations → Agent operations, install the built-ins, configure the Tenant skill runner, and enable its unscoped tenant registration.
- Promote the exact skill version to
active. It must have typedgtm-skill-io-v1input and output, at least two fixtures, active hash-bound knowledge dependencies, a fail-closed finite runtime policy, and reviewed allowed action IDs. - Configure the External campaign operator with the execution action
gtm.request_skill_run, the exact allowedskillIds, and an expiration time. - Rotate or generate the registration-bound gateway key, reconnect Hermes, and call
get_catalog.
The refreshed MCP catalog exposes action__gtm__request_skill_run only when the current registration has
that action and at least one exact skill scope. Invoke it with a caller-stable idempotency key:
{
"idempotencyKey": "hermes-account-summary-acme-v1",
"params": {
"skillId": "account-summary",
"skillVersion": 3,
"input": {
"accountDomain": "acme.example",
"objective": "Summarize current buying signals"
}
}
}The initial result returns skillRunId, workflowId, and requestActionInvocationId. Preserve all
three. Poll gtm__get_operation_status with the request invocation ID for governed admission evidence.
After the run succeeds, call gtm__get_skill_run_output:
{
"skillRunId": "skill-run-<opaque-id>"
}The output resource returns the skill's schema-validated output, outputHash, requiresApproval, and
zero or more proposedActions. A proposal is inert data: the skill runner has no Platform mutation
tools, shell commands, or network access, and never executes it. Hermes must deliberately invoke a
catalog-advertised action with a new stable idempotency key. That separate request rechecks the external
registration, expiry, exact campaign/resource scope, policy, schema, approval, durable invocation,
adapter, event, and recovery contracts.
The gateway binds admission to the requesting registration and exact active skill version, input hash, knowledge hashes, runtime budget, approval mode, and risk tier. The worker revalidates those bindings before model execution. Retiring the skill, knowledge, runner registration, external registration, or skill grant causes pending work to fail closed. A crash after immutable output staging resumes without a second model call; replay cannot duplicate an output or business mutation.
Skill input and private output are retained in tenant-isolated Lakebase staging for 30 days, while the
long-lived audit event and AgentRun keep only IDs, hashes, usage, policy outcome, and references. Do not
put passwords, access tokens, API keys, connection strings, or other secrets in skill input. Common
credential-shaped fields are rejected before invocation creation; store secrets in tenant-sealed storage
and pass only an approved opaque reference.
Propose an account task or note
Notes and tasks use the same /invoke endpoint and mandatory idempotency contract:
{
"contractVersion": 2,
"actionId": "gtm.upsert_task",
"idempotencyKey": "task-jpmorgan-review-trigger-v1",
"params": {
"taskId": "review-jpmorgan-trigger",
"title": "Review the current Databricks hiring trigger",
"description": "Confirm the role and source before proposing outreach.",
"priority": "high",
"subjectType": "GtmCompany",
"subjectId": "<company-id>"
}
}The server forces agent-created tasks to source=assistant and rejects caller-supplied command IDs,
timestamps, actors, or other durable metadata. For both notes and tasks, the trusted gateway derives
the stable command binding from the caller's idempotency key and supplies the canonical action's
required timestamp before private staging. The mutation is dispatched through Temporal, run through
Fabric Platform policy and state transition checks, and projected from its AssetEvent. Agents do not
write Lakebase directly.
Approval behavior
The V14 catalog separates proposal authority from privileged execution. An administrator may delegate any reviewed GTM product action while narrowing the final grant:
gtm.set_campaign_lifecycle;gtm.request_campaign_pass;gtm.decide_artifact_revision;gtm.publish_artifact;gtm.decide_draft_v2;gtm.apply_record_import_batchandgtm.reverse_record_import_batch;gtm.request_record_export;gtm.request_skill_runfor exact active skill IDs.
The caller never supplies an actor, command timestamp, or authorization proof. GTM derives the registered agent principal, validates current campaign or skill scope and grant expiry, derives the idempotent command ID, and mints a short-lived proof bound to that exact command. Canonical actions verify the proof inside Fabric Platform.
Record movement is intentionally privileged. An enabled grant may authorize exact hash-bound import
batches with record.operator, while export requests require the distinct record.exporter capability.
Full row bodies use the same Lakebase staging path as other private content and do not enter Temporal
history. Agents receive no direct database or connector-write capability.
gtm.decide_draft_v2 is a composite gateway command, not a raw send action. It stores private reviewer
content in bounded tenant staging, invokes canonical gtm.record_draft_decision_v2, and signals only the
exact server-verified parked workflow. It can approve only an existing exact V2 draft that belongs to a
delegated campaign. Approval resumes the normal V2 delivery path; suppression, cooldown, inbox ramp,
daily cap, proof, contact eligibility, and at-most-once delivery still run. There is no raw arbitrary-send
action.
For example, an authorized agent activates an already reviewed campaign version with the same endpoint:
{
"contractVersion": 2,
"actionId": "gtm.set_campaign_lifecycle",
"idempotencyKey": "activate-databricks-v5",
"params": {
"campaignId": "databricks-enterprise-first-touch",
"version": 5,
"status": "active"
}
}Supplying commandId, occurredAt, actorId, or authorization is rejected. Those values are
server-owned so the calling model cannot widen or impersonate its grant.
{
"workflowId": "gtm-command-org-...",
"status": "waiting_for_approval",
"hitlRoute": "needs-approval"
}The external caller should surface that status rather than changing parameters and retrying. A human or a separately delegated agent principal can resolve the exact pending revision or draft.
Security model
- key lookup is organization-scoped;
- every credential is hash-only at rest and bound to exactly one registration;
- missing, wrong, or disabled keys return unauthorized;
- every invocation uses
actorType=agent; - every mutation is a tenant-scoped Temporal workflow;
- enabled tenant registrations and exact grants determine the canonical agent principal;
- current registration status, expiry, action scope, and exact campaign or skill scope are revalidated immediately before mutation and prospect-visible adapters;
- campaign-scoped operational reads are re-evaluated against the current grant; ownership of an older invocation does not preserve visibility after its campaign is removed;
- an event that references a missing durable Platform invocation is withheld rather than inferred to be visible; direct event, account-activity, and synthetic imported-account projections all fail closed;
- agent runs and agent-authored events are visible only to the registration that produced them, even when two registrations share a campaign;
- account context is projected to the current campaign scope, so an account participating in multiple campaigns cannot reveal another campaign's drafts, artifacts, tasks, or activity;
- rotating a registration credential increments its generation and invalidates admitted work that has not already committed an exact idempotent invocation;
- privileged grants have exact campaign or skill resource scopes and expire;
- short-lived proofs are bound to the derived principal, capability, tenant, and command;
- authorization proofs never enter new Temporal histories; workflows carry only the opaque, verified admission invocation ID;
- artifact authors cannot evaluate or approve their own revisions;
- mandatory idempotency keys collapse caller retries onto one workflow execution;
- schemas validate action parameters;
- normal policies, state transitions, and audit events apply;
- catalog responses never expose organization credentials.
Integration patterns
Use the gateway when:
- a Databricks-hosted research agent discovers a new account signal;
- an Azure AI Foundry, Fabric Harness, or Hermes agent reads an account and proposes a governed Signal V2 record, note, or task;
- Hermes requests an exact active tenant skill through the compiled finite runner, reads its private typed result, and treats any returned action proposal as inert until separately invoked;
- a bounded autonomous operator activates an approved campaign, launches its exact immutable version, reviews artifacts, publishes approved revisions, or resolves parked V2 drafts;
- an MCP host needs a stable GTM tool boundary;
- an external orchestration system needs an audited account-operations boundary.
The UI and external gateway are peers over the governed operating loop. Both execute through Temporal and the same Fabric Platform action runtime, emit AssetEvents, and appear in the tenant audit surfaces.
MCP and operational monitoring
The same registration-bound credential can use the stateless MCP endpoint:
POST /api/agents/gtm/<organizationId>/mcptools/list returns only that registration's catalog. Read tools cover account context, an operational
summary, cursor-based recent events, pending approvals, failed or stalled operations, and exact operation
status. Mutation tools delegate to /invoke; the MCP adapter owns no policy, retry, or persistence logic.
The endpoint implements MCP protocol version 2025-03-26 over authenticated JSON-RPC POST requests.
Operational reads use bounded keyset pages and a request-scoped authorization projection. They never
load the full event or invocation ledger into one request, and campaign/registration visibility is
still evaluated for every returned record. Recent-event and operation responses may include
scanLimited: true when the privacy-safe scan budget is exhausted before the requested result count.
Continue from the returned cursor where one is provided; do not widen the registration scope to work
around a sparse result page.
If Lakebase cannot provide a connection within the bounded acquisition window, the gateway returns
HTTP 503 with code: "datastore_capacity_unavailable", retryable: true, and Retry-After: 5.
Agents should retry the identical read after that delay with bounded exponential backoff. A 503 does
not grant permission to bypass the gateway, query Lakebase directly, or change a mutation's
idempotency key. Server logs contain only the tenant, operation name, and aggregate pool counts—never
credentials, event payloads, or staged command bodies.
An administrator can also configure a public HTTPS operational webhook for one registration. GTM stores
the HMAC secret in tenant-sealed storage and begins after configuration, so it does not replay historical
events unexpectedly. The scheduled Temporal dispatcher reconciles committed AssetEvents into
gtm.deliver_operational_webhook action invocations. Its Platform adapter sends privacy-safe metadata,
an event ID, and a read URL—never the source payload—with:
Idempotency-Key: <stable delivery id>
X-GTM-Event-Id: <event id>
X-GTM-Timestamp: <ISO timestamp>
X-GTM-Signature: sha256=<HMAC_SHA256(secret, timestamp + "." + raw body)>Receivers must deduplicate by event ID. A failed delivery remains a failed/retryable action invocation; it never changes the underlying domain mutation.
Activation checklist
Commercial experiment lifecycle, activation, assignment, and treatment-consumption actions remain
internal/operator-only and are absent from Hermes' catalog. Hermes installation is unchanged: use
the registration-bound GTM MCP credential described above, never a Databricks service principal.
Even when a commercial experiment is running, GTM resolves the account assignment and exact
campaign artifact server-side; Hermes cannot supply a variant or treatment binding.
When an internally approved commercial draft is actually delivered, GTM—not Hermes—atomically records
the delivery attempt, touch, and Fabric Experiments exposure. Hermes receives no direct exposure-write
capability and cannot repair an ambiguous provider outcome.
Outcome attribution repair is also human-only: gtm.correct_outcome_v2 is not advertised to external
agents, and Hermes cannot choose or replace an experiment touch. Expired exposure evidence is removed
only by GTM's internal governed retention action; Hermes receives neither that action nor raw
retention tombstones.
Before enabling Hermes for live campaign execution:
- Confirm the release commit passed the required
Governed mutation certificationstatus. - Keep Hermes on its external GTM registration; built-in managed-MLflow certification does not require and must not grant Hermes a Databricks service principal.
- Confirm
get_catalogreturnsgtm-external-agent-catalog-v14and an action-contract manifest digest. - Confirm the installed External campaign operator reports runtime
gtm-external-gateway-v14. - Begin with a single campaign ID, a short grant expiration, and dry-run campaign mode.
- Reuse one caller-issued idempotency key for every retry of the same logical command.
- Verify a completed dry-run operation appears in the scoped operational summary and audit trail.
- Remove the campaign from the grant and verify its operation status becomes unavailable.
- Restore the scoped grant, enable the exact immutable live campaign version, and monitor the first
provider delivery, touch attestation, capacity reservation, and
GtmOutreachSentevent.
Do not enable live execution if the catalog/runtime version is stale, the registration is tenant-wide
without an explicit administrative decision, or an operation reports failed_unknown or ambiguous.
Resolve an ambiguous provider outcome through the governed reconciliation action before attempting more
delivery. A registration cannot invoke the operator-only model-resolution action, and it cannot observe
another registration's operations merely because both registrations share a campaign.
Next: Agents, Governance, and Integrations.