GTM OS Product Documentation
osGTM OS product documentation · v0.2.5

01 · What GTM OS is

An operating system for go-to-market that you host and agents run.

GTM OS is an open-source, self-hosted platform that holds your go-to-market data in one typed model, runs the GTM work through engines, and lets humans and AI agents operate all of it through one governed interface where every customer-facing action waits for a second person to approve it.

8 engines in the console 670+ operations 35 canon object types 31 definition kinds 41 first-party packages 10 blueprints

For GTM teams

Most GTM teams run on a stack of tools that each hold a slice of the customer and none of which agree. GTM OS replaces that with one system: your accounts, contacts, deals, signals and activity live in one place, and the work on top of them (finding intent, enriching records, scoring accounts, routing, sequencing, merging duplicates, running plays, SEO, paid ads) runs as engines you configure.

You describe your motion once (who your ICP is, which signals matter, how many emails a mailbox may send, who must never be contacted) and the engines follow it. Nothing reaches a customer, a CRM or an ad account until a person on your team approves it.

Under the hood

A small kernel holds the runtimes and the meta-model and contains no GTM business objects. Everything a company recognizes as GTM ships as packages on top (engines, ontology modules, connectors, screens, packs, blueprints). Every capability is an operation in one registry; REST, the TypeScript SDK, the gtm CLI and the MCP server are all generated from it and all call the same runOperation pipeline, so authorization and approvals cannot be bypassed.

Stack: Next.js console, NestJS API, Postgres with pgvector, Prisma, Better Auth, Cedar authorization, CEL expressions, a Postgres-native durable flow runtime, pnpm and Turborepo.

Who it is for

GTM engineers

The person who designs the scoring, routing, sequencing and data rules, usually working through Claude Code or Codex.

Revenue and marketing leaders

Owners and admins who approve sends, merges, budget changes and config before they go live.

Agencies

Teams that run GTM inside client orgs through delegations, with the client keeping approval rights.

The core idea

GTM OS is built so that an AI agent can do the work of a GTM engineer without being trusted blindly. The agent gets the same operations a human admin has. What it cannot do is approve its own work, widen its own authority, consent to OAuth in a browser, or switch off the safety switch. Those stay with people. In plain terms: the agent builds and proposes, a second human decides, and the kernel records who did what.

The README compares it to WordPress: a stable core you install on your own infrastructure, plus packages that deliver the work. You own the data and the deployment, and you can take your data out at any time with gtm org export.

How it is delivered

For GTM teams

What you get. A complete go-to-market workspace that runs on your own machine or cloud: a web console with your CRM (companies, contacts, deals), the engines that find, score, route and reach accounts, an approvals inbox, and a built-in agent workspace so Claude Code or Codex can set up and run the system with you. It is open source and self-hosted, so your pipeline data never sits in someone else's SaaS.

How you set it up. You do not configure it by hand. In an empty folder you open Claude Code and run gtm init, then /setup-gtmos. Claude installs GTM OS, creates your organization with an owner and a second approver, connects it to itself, and asks you only for the things a person has to provide:

  • your organization name and the two people's emails (the approver must be a different person);
  • one click on Connect Composio, after which the apps you already use (CRM, Gmail, Calendar, Slack, Search Console, Ahrefs) are discovered and linked;
  • the API keys you choose to add (an AI model, looot for data, an email sender), which you paste in the console;
  • the DNS records for your sending domain, if you will send email.

From setup to working system. Then the setup wizard in the console (Setup: nine steps on six screens) or /build-gtm-system with your agent: either one interviews you about your ICP, offer, markets, channels and goals, drafts each definition with the evidence behind it, and builds the engines. You review and approve. When you are happy, one card in Environments > Go live signs everything and promotes it to production with a single approval. Expect roughly an hour for a first setup, most of it answering questions and approving. A first-win checklist on Home shows eight milestones computed from what really happened in your workspace, and opt-in operator nudges tell owners and admins when something needs them.

Safe by default. A new install runs in live mode: anything not connected says so plainly and names the missing key, instead of showing invented numbers. Nothing is sent, merged or published without a person approving it, and the person who proposed a change (or whose agent did) can never approve it. Dry Mode, for the whole organization and for each engine, shows what would have happened first, and the claims gate checks every factual claim in outbound content against proof you approved. A separate demo mode with sample data exists only for walkthroughs; never use it with real prospects.

Who does what. A GTM lead owns the decisions and approvals; the agent (or a GTM engineer) does the building; an IT person is only needed if you host it on company servers. Day to day, the team works in the console: the Hot list, company pages, outreach approvals and the engine dashboards.

What it costs to run. The software itself has no license fee. You pay only for what you connect: the AI model you choose, looot data credits for enrichment and signals (with per-run spend caps), your Composio plan, and the machine it runs on.

Staying current. New versions arrive as an upgrade command. Upgrade the CLI first, then the instance: it takes a verified backup, rehearses the migration on a copy, and rolls back by swapping the images if anything fails. An upgrade never touches, removes or loses your data: every release only adds. Your configuration, data and approvals history carry over.

Under the hood

Four images, gtmos-api, gtmos-console, gtmos-worker and gtmos-mcp (0.2.5), plus pgvector/pgvector:pg16, wired by a generated docker-compose.yml. Default ports: console 3000, API 3001, MCP 3004, all bound to 127.0.0.1 (see below). The gtm CLI installs from npm (@gtmos/cli, 0.2.5); the images are public on GHCR (ghcr.io/ay-automate/gtmos-{api,worker,mcp,console}, tags 0.2.5 and stable, linked to github.com/ay-automate/gtmos-releases), so gtm setup pulls them. Locally built images can still be used with --version <tag> --no-pull.

npm i -g @gtmos/cli
mkdir my-gtm && cd my-gtm && claude
! gtm init                      # agent workspace + docs, even with no instance yet
/setup-gtmos                    # Claude runs gtm setup, the agent key, connections

# by hand instead:
gtm setup ./instance --org Acme --email you@x.com --approver-email ops@x.com --version 0.2.5
gtm doctor --strict             # what is live, unverified, missing

gtm init writes CLAUDE.md at the project root, AGENTS.md, .mcp.json (the key is read from GTMOS_AGENT_TOKEN, never written to a file), the skills and commands, and docs/gtmos/ (reference generated from the live registry, plus the guides). GTMOS_LIVE=true is written into a new .env; --demo writes the keyless demo floor. Upgrades: gtm upgrade --check, then gtm upgrade --channel stable --dry-run and --yes (see below).

Self-hosting and upgrading

For GTM teams

Closed by default. From 0.2.5 a self-hosted instance accepts connections from its own machine only. To let your team in from the network you put a reverse proxy with HTTPS in front (the safe choice, and a short job for whoever hosts the server), or you open the ports on purpose. If people used to reach an existing instance by its IP address, that stops until you pick one of the two. If you only use GTM OS on one machine, nothing changes.

Upgrades. Ask for the CLI update first, then check what is available, rehearse, and upgrade. Your data is backed up and verified before anything changes, and an upgrade only adds to your data. If a step fails, GTM OS puts the previous version back; your data is never restored over the live database.

Under the hood

Bind address. gtm up publishes the console, API and MCP ports on 127.0.0.1, like Postgres. The address is one .env variable, GTMOS_BIND_ADDRESS (127.0.0.1 by default; 0.0.0.0 for every interface, only behind a firewall; a private IP for a proxy on another host). Change it by editing .env and running gtm up again, or create the instance with gtm up --bind 0.0.0.0. gtm up rewrites docker-compose.yml on every run, so never edit the compose file to open ports; a --bind flag passed to an existing instance is ignored and reported because the existing .env wins. On an older instance, the first gtm up or gtm upgrade warns and backfills GTMOS_BIND_ADDRESS=127.0.0.1.

Reverse proxy. Point app., api. and optionally mcp. hosts at the server (one parent domain, so the session cookie is shared), open only 80 and 443, set PUBLIC_API_URL, PUBLIC_CONSOLE_URL and PUBLIC_MCP_URL in .env to the https origins, and proxy each host to 127.0.0.1:3001, :3000 and :3004. Caddy gets the certificates for you. Verify with curl https://api.acme.com/health and ss -tlnp | grep -E ':(3000|3001|3004|5432)\b': every line must show 127.0.0.1. A mismatch between the public URLs and the browser origin shows up as login loops or unstored cookies.

Upgrade path. npm i -g @gtmos/cli@latest first, because the CLI renders the compose file. Then gtm upgrade --check (read-only), gtm upgrade --channel stable --dry-run and gtm upgrade --channel stable --yes. A plain gtm upgrade never moves a pinned install; use --channel or --to <version>. Steps: fetch and verify the signed release list (no downgrade, no skipped required stop, additive-only, minimum CLI), preflight (one update at a time, free disk of twice the database plus 2 GB), pull and check image digests, refuse any non-additive migration (no override), stop the services, take and verify a backup, rehearse the migration on a restored copy and compare tables, columns, row counts and checksums, migrate inside the new image, start, verify, keep the newest five backups. Rollback is an image swap only. Restoring a backup is a manual last resort into a renamed database. Keep GTMOS_MASTER_KEY apart from backups: they do not contain it.

System email. Invitations, password reset, email verification and setup reminders go out through a transport you choose in .env: EMAIL_TRANSPORT (smtp, webhook or none; left empty it is inferred), with SMTP_HOST, SMTP_PORT (587), SMTP_SECURE, SMTP_USER, SMTP_PASS and EMAIL_FROM, or per-purpose webhook addresses (RESET_PASSWORD_WEBHOOK_URL, VERIFICATION_EMAIL_WEBHOOK_URL, INVITATION_EMAIL_WEBHOOK_URL, OPERATOR_NUDGE_WEBHOOK_URL). With none configured the instance still runs and the first owner can be created, but those mails are not sent: each skip is logged with the recipient and the kind of mail, and the link itself is never logged in production. gtm member add creates a verified teammate without email. The daily update and open-ask reminders use the organization's own Resend connection instead.

Operator settings. GTMOS_LIVE must be true or false in production or the api, worker and mcp images refuse to start (an upgrade writes false into an older .env). GTMOS_PLATFORM_CREDENTIAL_PROVIDERS lists the providers whose instance keys organizations may fall back to; setting it replaces the default list. After the CLI upgrade, gtm init --refresh takes the new skills and subagents.

02 · Architecture

Kernel, stdlib, apps, SDK, packages

The repo has four layers. The kernel is the stable core; stdlib is the first-party GTM content built on it; apps are the processes you run; the SDK is the public API that packages build against.

flowchart TB
  subgraph People["Humans and agents"]
    H["Console users"]
    AG["Claude Code, Codex, any MCP agent"]
    OP["Operator with the gtm CLI"]
  end
  subgraph Apps["apps"]
    CON["console (Next.js)"]
    API["api (REST, tRPC, OpenAPI)"]
    MCP["mcp (streamable HTTP)"]
    WK["worker (jobs, plays, agent loops)"]
  end
  subgraph Kernel["kernel"]
    REG["Operation registry and pipeline"]
    POL["Policy: Cedar, gate, Dry Mode"]
    DP["Data plane: observe, resolve, project"]
    BR["Broker and cost ledger"]
    MG["Model gateway"]
    FL["Flow runtime, plays, lanes"]
    CFG["Config store, environments"]
  end
  subgraph Stdlib["stdlib packages"]
    ENG["Engines"]
    ONT["Ontology modules"]
    CNX["Connectors"]
    SCR["Screens and packs"]
  end
  DB[("Postgres with RLS and pgvector")]
  H --> CON
  AG --> MCP
  OP --> API
  CON --> API
  API --> REG
  MCP --> REG
  WK --> REG
  REG --> POL
  REG --> DP
  REG --> BR
  REG --> MG
  REG --> FL
  REG --> CFG
  ENG --> REG
  CNX --> BR
  DP --> DB
  CFG --> DB
  

The kernel

The kernel lives in kernel/*. It imports nothing from stdlib, and packages never get a raw database connection: the only database access goes through kernel stores under row-level security. CI enforces these boundaries with dependency-cruiser.

PartIn plain wordsTechnically
operationsThe single list of everything the system can do.Operation registry and the unified pipeline: validate, org context, authz, guards, disposition, approval, execute, events and audit. Generates the SDK and OpenAPI.
runtimeThe approval queue and the record of what ran.Runs, actions, approvals, executions, receipts, the claim-due queue and fair scheduler.
policy, celWho may do what, and the rule language for criteria.Two layers: Cedar authorization ("can this principal do this at all") and an ordered decision table for disposition (allow, require approval, draft, deny). CEL (pinned @bufbuild/cel) for segment, persona, predicate and scoring conditions.
data-planeHow outside data becomes one clean record.Observe (append-only observations) → normalize → resolve (identity) → project, with survivorship, monitors, lineage and privacy.
brokerEvery paid call is priced and logged.capability.acquire resolves a definition.binding, quotes and holds spend on a double-entry cost ledger, runs the backend, settles at actual cost.
model-gatewayOne door for every LLM and embedding call.model.call resolves definition.model_policy (and definition.model_pin), meters on the same ledger, applies region and budget constraints.
flow, flow-play, lanesAutomations that survive restarts, and send limits per channel.Postgres-native step journaling with durable sleep; definition.play compiled to versioned flows; lanes enforce the pre-send gate, deliverability and compliance.
configSettings as reviewable, versioned files.Resource envelopes with per-kind JSON Schema, the config store, mixed-kind ChangeSets, environments and promotion.
ontologyThe shared data model.Catalog parser and validator, core pack, ontology ChangeSets and the extension layer for custom fields and objects.
auth, dbSign-in and tenant isolation.Better Auth, role mapping; Prisma schema and migrations, RLS with a NOBYPASSRLS app role.
indexing, memorySearch across records, and what agents remember.Hybrid retrieval (Postgres full-text plus pgvector) built by a background job; agent memory as a governed view over records, decisions and run history.
agent-runtimeAgents that run step by step and pause for approval.Durable perceive, decide, act, observe loop; decisions go through model.call, actions through operations.
channels, connectors, observabilityNotifications, outside systems, monitoring.Push delivery (Slack adapter); capability contracts and fixture adapters only (real adapters live in stdlib); OpenTelemetry traces, logs and metrics.

stdlib, apps and the SDK

stdlib

First-party packages: the engines (stdlib/qualification, outreach, performance-ads, search, identity-dq, enrichment, signals), ontology modules (gtm-base, gtm-pipeline, gtm-motion, gtm-intelligence always on; gtm-company, gtm-partner, gtm-ads, gtm-b2c, gtm-search optional), gtm-routing, gtm-plays, gtm-compliance, connectors, packs and the stdlib apps (Mission Control, Focus Queue, Account Workspace).

apps

api: NestJS, tRPC, OpenAPI; the only database writer besides the worker. worker: multi-org durable jobs, plays, agent loops, outbox relay. mcp: MCP server on the official SDK with the same authorization path as the API. console: the Next.js operator UI and CRM. cli: install, org lifecycle, plan and apply, packages, harness.

sdk

@gtmos/sdk is the typed client generated from the operation registry plus the define* kit (for example defineEngine, definePlay). Stdlib and third-party packages import only the SDK, never kernel internals.

Packages

Everything installable is a package with a manifest (gtmos.package.yaml), declared permissions and one of three execution tiers. Install, enable, upgrade and rollback are proposals a second human approves. Details below.

Packages and execution tiers

For GTM teams

Think of packages as apps for your GTM system. Most are configuration only (a blueprint, a set of scoring rules, a screen layout) and carry no code at all. Packages that do carry code must be signed by a publisher the instance trusts, and third-party code runs in a sandbox that cannot touch your session or other data.

Under the hood

TierRunsSignature
declarativeNo code (definitions, apps, blueprints)Optional; verified if present
trustedCode in-processRequired and verified
sandboxedCode in an isolated iframeRequired and verified

Ed25519 (or sigstore keyless) against the first-party key plus GTMOS_TRUSTED_PUBLISHER_KEYS. A trust ladder (community, verified, certified) grades versions; community runs only sandboxed and outside prod.

Package lifecycle operations: packages.install, packages.enable and packages.disable (per environment), packages.upgrade, packages.rollback, packages.uninstall, with packages.preview_upgrade as a read-only diff. The CLI mirrors them under gtm pkg, plus offline tooling to scaffold, validate, build (hash and SBOM) and sign.

The operation pipeline: an agent asks, a human decides

This is the path every call takes, whether it comes from the console, the CLI or an agent over MCP. A read runs straight through. A customer-facing effect stops at the gate and waits.

sequenceDiagram
  participant A as Agent
  participant M as MCP server
  participant K as runOperation
  participant G as Approval gate
  participant H as Second human
  A->>M: gtm_describe outreach.send_message
  A->>M: gtm_act outreach.send_message
  M->>K: validate, org context, authz, guards
  K->>G: disposition is require approval
  G-->>A: approval id, state proposed
  H->>G: runtime.approve_action
  H->>G: runtime.execute_approval
  G->>K: execute
  K->>K: outbox event and hash-chained audit row
  

The pipeline stages, in order: validate the input against the operation's schema, resolve the org context, authorize (Cedar plus scope checks), run guards and transforms, compute the disposition (gate policy, Dry Mode, autonomy caps, lane controls, binding mode), create an approval if one is needed, execute, then write the outbox event and the audit record in the same org transaction.

03 · Core concepts

The ideas you need before anything else

Operations and their classes

For GTM teams

Every action in GTM OS has a name, such as score.score_account or outreach.send_message. Reading data is free to run. Writing your own data is logged. Anything a customer, a CRM or an ad platform would see is only proposed until someone approves it.

Under the hood

671 operations: 294 Q, 255 D, 5 T, 30 E, 87 M. Q runs as GET /v1/operations/<name>?input=<json>; the rest as POST /v1/operations/<name>. Each descriptor declares its class, input and output schema, required scopes and whether it needs approval.

ClassMeaningExampleGate
QQuery: readquery.list_qualificationsNone
DData write inside GTM OSsignals.recordLogged; some agent writes become proposals
TStage transitionlane.activate, play.triggerPer operation
ECustomer-facing effectcrm.update_record, perf_ads.update_campaignAlways proposed; a different human approves and executes
MMeta: config, ontology, platformpolicy.set_dry_modeMany are human-only

Definitions

For GTM teams

A definition is one piece of your GTM playbook written down: an ICP segment, a persona, a scoring model, a sending lane, a play, a brand voice, a suppression rule. Engines read your definitions instead of hard-coded settings. Change the definition and the engine changes behavior, after review.

Under the hood

31 definition kinds plus 4 other config kinds (ontology.object, ontology.field, ontology.relationship, package.manifest). Each is a resource envelope (apiVersion, kind, metadata.key, spec) validated by a strict per-kind JSON Schema; unknown keys are rejected.

KindWhat it setsRead by
definition.segmentWhich records a motion works (CEL criteria)Plays, lists, Mission Control
definition.personaWho to target inside an accountScore, plays, Outreach
definition.scoring_modelWeighted rules and thresholds (keys default, icp_fit, signals)Score, Signals
definition.committee_modelRequired buying-committee rolesScore (ABM)
definition.laneA sending channel with caps, checks, budget and domainOutreach
definition.brand_voiceTone and vocabulary for generated copyOutreach drafting
definition.suppression_rule, definition.compliance_policyWho must never be contacted; regulatory rulesPre-send gate
definition.playTrigger, filter, steps, gate and guardrailsFlow runtime
definition.bindingWhich backend serves a capability, and the price capBroker
definition.source_mappingHow an app's list maps into the ontologySource sync
definition.identity_rule, definition.data_monitorMatching and survivorship; data-quality checksData plane, Identity & DQ
definition.metric, definition.stage_machine, definition.predicateKPIs as SQL aggregates; legal stage transitions; reusable CELApps, ontology, segments
definition.model_policy, definition.model_pinWhich model serves each task classModel gateway
definition.unit_economicsMargin, AOV, CAC targetsPerformance Ads
definition.agent, definition.skillAgent authority, skills and run boundsAgent runtime
definition.app, definition.brand_kitDeclarative screens; console theme tokensConsole
definition.customer_typeOne kind of customer in your own words (agency, reseller, mid-market SaaS), the criteria that match a company, and the journeys it followsJourney and territory routing, plays, search index, agent context
definition.deal_taxonomyYour deal types (pilot, demo, expansion) and the raw CRM values that mean each oneDeal type on records, dashboards, agent context
definition.enrichment_policyHow long an enriched value stays fresh, per field, and the monthly enrichment spend capEnrichment, the capability broker
definition.journeyA lifecycle a company, person or deal follows: ordered stages (open, won, lost) and the segments routed to itJourney engine, CRM and source mirrors, lead scoring
definition.moneyWhere revenue truth lives, the attribution window and the FX conventionCRM dashboard, metrics, the money operations, the Actions ledger
definition.reply_labelsThe labels a reply gets (interested, not now, objection, unsubscribe, bounce), how each is recognised, and what each one triggersReply ingest and classification, Conversations
definition.sequenceA sequence's ordered email or LinkedIn steps, waits, send windows, A/B variants and exitsOutreach cadence
definition.stage_mapWhat each value of one source's stage field means; an unmapped value is held for review, never defaultedCRM and source mirrors

Lifecycle: draft, propose, sign, promote

A definition cannot be published straight into prod. It is drafted in dev through a ChangeSet, proposed for signing, signed by a human who did not propose it, then promoted. Engines read only the signed version in the call's environment; with none, they fall back to their stdlib default. Editing a definition creates a new version that must be signed again. definition.data_monitor is the one sign-exempt kind.

config.propose_changeset      -> draft ChangeSet         (gtm plan / gtm apply --env dev)
config.validate_changeset     -> issues, nothing applied
config.apply                  -> approval; a different human approves -> published in dev
definition.propose_for_signing-> proposed                (gtm definition propose-for-signing)
definition.sign_many          -> signed, by a human, not the proposer   (gtm definition sign-all)
env.promote dev -> prod       -> ONE approval            (gtm promote --all dev prod)

Environments

For GTM teams

Every org has three spaces: dev to build, staging to check, prod where things run for real. Emails sent from dev or staging go to a sink and never reach anyone. The console shows a banner ("N definitions are in dev, not live") until you sign and promote.

Under the hood

prod is the default for MCP and REST calls that name no environment. MCP takes an environment argument or the x-gtmos-environment header; an unknown key is refused. env.promote plans every changed resource, proposes one approval and walks dev → staging → prod; backward is refused. config.promotion_status reports what is not live.

Approvals and four-eyes

The four-eyes rule. The person or agent who proposed an action cannot approve it, sign it or execute it. Neither can the human an agent acts for. An agent cannot approve anything at all. Only an owner or admin can approve. The proposer can still withdraw a proposal, and any approver can reject (veto) it.

For GTM teams

Every send, CRM write-back, record merge, page publish, ad budget change and config change that goes live lands in Approvals or Needs a human. A teammate reviews it, approves, then executes. If your org has only one admin, nothing can go live: add a second approver first.

Under the hood

An E-class call creates an ActionApproval in state proposed. States: proposed, approved, rejected, withdrawn, revoked, expired (after 7 days), executing, executed, failed. Ops: runtime.approve_action, runtime.reject_action, runtime.execute_approval, runtime.withdraw_action. At execution the gate re-checks that a valid, distinct human approver is stored. Actions auto-approved by a gate policy or a pre-approval envelope are exempt: the standing rule is their approver.

Dry Mode

Two layers of safety switch, both human only to change. The organization-wide switch (Settings > Safety, policy.set_dry_mode): while it is on, every E-class operation becomes a draft, logged, never executed, no approval created. D, T and M operations still run. Every console page shows a banner. Read it with policy.get_dry_mode. Each engine also has its own Dry or Live mode (policy.engine_modes.get and policy.engine_modes.set; Settings > Safety and the header of each engine page), covering outreach and sequences, meeting booking, performance ads, SEO & GEO publishing, lifecycle plays, routing notifications, CRM write-back, enrichment spend and merges. The effective mode is the stricter of the two. Going live is an owner or admin action, confirmed and audited, and policy.shadow_report shows each engine's accuracy from its dry runs.

Guardrails are enforced by the kernel for every engine and agent: emails a day, new accounts contacted a week, ad spend a day (above it a person approves), a send window in the recipient's timezone with quiet hours, and allowed channels (policy.guardrails.set). A hit holds the action instead of dropping it, raises an alert and runs it later. One rule has no setting: the first message to someone nobody has written to is never sent automatically.

Proof library and the claims gate

For GTM teams

Settings > Proof library holds your case studies, metrics, testimonials and logos, each with a permission (public, anonymized or internal only) and an optional expiry. Claims are taken from documents you upload and kept only when the quote is verbatim in the source. A second person activates each proof. Before anything goes out, every factual claim in it (a statistic, a result, a named customer, an outcome with no number) is checked against active proof. A claim with no proof blocks the action, or goes to an approver who must acknowledge it, depending on the policy you choose. A customer whose proof is not public can never be named.

Under the hood

The gate runs when an action is proposed and again right before it runs, so proof archived or expired in between fails the run. It covers outreach on every channel, sequence steps and batches, SEO publishes and undo, and meeting invites and cancellations. Verdicts: Backed, Close (at least half the wording matches, never treated as backed) and No proof. Modes: block (default, POLICY_DENIED blocked_unbacked_claim) or route to the approver, who acknowledges each claim in the claims panel (the proposer and the agent cannot). Ops: proof.create, proof.extract_from_document, proof.propose_activation, proof.list, proof.archive, policy.claims.*, voice.customer_language.*. Customer language mined from calls, replies and won deals is approved phrase by phrase.

Budgets and spend caps

CapSet whereWhen exceeded
Per-call data capLOOOT_MAX_COST_USD (default 0.05) and binding maxUnitCostUsdAPPROVAL_REQUIRED; waits for a human
Ledger budgetsMission runs, agents, plays (internal)BUDGET_EXCEEDED; acquire and model calls turn into proposals
Lane envelopeenvelopeBudgetEur over windowDaysSends stop until re-approval
Play guardrailsmaxBudgetUsd, maxActionsPerRunThe play stops
Model policymaxUsd per routePer route
Pre-approval envelopeenvelope.grant (human only)Scoped, time-bound auto-approval ends

Spend is visible in Operate > Cost (ledger.list). Price before running with capability.quote or enrichment.enrich_accounts {estimate: true}.

Provenance and lineage

Every value on a record knows where it came from: the winning observation, the others that competed, the survivorship rule, a confidence from 0 to 1, a band (VERIFIED, PROBABLE, POSSIBLE) and a status. A human edit is VERIFIED and automation never overwrites it. Read it with records.provenance and lineage.trace (MCP gtm_lineage_trace); the CRM record pages show a provenance panel.

Readiness and required connections

instance.readiness (CLI gtm doctor) lists every seam with a status: live, configured_unverified, failed, fixture or not_configured. Items are required while the engine that needs them is in use, otherwise informational. Applying a blueprint makes its declared connections required. The console shows the same list as Required connections on Integrations > Connections.

04 · Ontology and data

One model of your market

For GTM teams

The ontology is the shared vocabulary every engine uses: accounts, contacts, deals, signals, activities and more. Your CRM data, enrichment results, form fills and intent data all land on the same records. You can add your own fields (an account tier, a product line) and your own objects (partners, projects) without waiting for a release.

Under the hood

35 canon object types in the reserved gtm.* namespace (ontology 0.1.0-draft), interfaces Subject, Engageable, Touch, Monetary, and stage machines such as gtm.pipeline.deal_stage. Every object carries common fields (id, revision, timestamps, owner_principal_id, archived_at, a custom JSON bag). Live list: query.object_types.

Canon objects you will use most

ObjectKey fields
gtm.accountname, domain, relationship_status (prospect, customer, partner, former_customer, other), industry, employee_count, country_code
gtm.contactdisplay_name, primary_email, phone, linkedin_url, contactability (unknown, allowed, restricted, do_not_contact)
gtm.dealname, account_id, pipeline_id, stage_id, value, status (open, won, lost, cancelled)
gtm.signalkind, subject, observed_at, summary, verification_status
gtm.employment, gtm.deal_contactLinks contact to account, and contacts to a deal (the buying committee)
gtm.activity, gtm.task, gtm.meeting, gtm.messageTimeline and work items
gtm.campaign, gtm.campaign_memberSequences and their rosters
gtm.qualification, gtm.outcome, gtm.suppressionEngine outputs and lifecycle

Optional ontology modules add more when enabled: stdlib/gtm.partner (partners, tiers, partner deals, referrals, commissions), gtm.search (properties, pages, keywords, SERP positions), gtm.ads, gtm.b2c, gtm.company (products, price books, territories, quotas). Check packages.catalog before inventing an object a module already provides.

Custom fields and custom objects at runtime

For GTM teams

Add a field to companies, contacts or deals in Settings > Custom fields: text, number, date, checkbox, select, URL, email, phone or user. It appears on the record page at once. Show in tables and Allow filtering are saved with the field, but list columns and filters for custom fields arrive in a later release; until then records.list filters and your agent can already use the field. A new object type (say, "Partner") is designed in CRM > Model and goes live after a second person approves it.

Under the hood

Fields: field.create (no approval, owner/admin or their agent with engine.configure), plus field.update, field.archive, field.coverage, field.backfill. Objects: ontology.propose_changeset with create_object, add_field, add_relationship (keys custom.<slug>), ontology.validate_changeset, then ontology.publish_changeset (human only, approval). Canon fields can be extended, never redefined.

Identity resolution

Two layers keep one record per real company and person.

  1. Observation to entity (data plane). An account matches on domain (authoritative) and name (corroborating); a contact on primaryEmail and displayName. Matching runs deterministic, then blocking, then probabilistic; unsafe matches go to a human review (resolve.review.decide). A signed definition.identity_rule overrides the keys and survivorship (most_recent, highest_confidence, first_write_wins, longest_non_empty, source_priority).
  2. Record dedupe (the Merges engine). identity_dq.scan_duplicates follows the signed definition.identity_rule, then identity_dq.merge_records as an approval that lists each field conflict and the strategy that decides it, reversible with identity_dq.unmerge_records. A merge keeps survivor columns a person set by hand.

Automated writes onto an existing record must resolve to that record by domain, email or source id. A write that cannot resolve never creates a duplicate; source mappings report it as unresolved.

Mirror (binding) modes

ModeWhat happens to outside data
replicate (default)Full local copy, authoritative, metered
soft_mergeOverlay that never overwrites a human-set value
federateNo local row; read through
in_zoneNo row-level data leaves the customer's zone; aggregates only; fails closed
sheetLow-trust overlay; effects need explicit human confirmation

Set per object type with binding.set_mode or gtm connect <provider> --mode <mode>. CRM sync and source mappings respect it.

Vectors and search

search_records (MCP) fuses Postgres full-text rank with pgvector similarity over accounts, contacts, deals and activities. Embeddings come from OpenAI (text-embedding-3-small) or Gemini (gemini-embedding-001), whichever key the org has. Anthropic has no embedding model; without OpenAI or Gemini, results come back mode: "text_only". Indexing runs as a daily background sweep; search.index_status shows coverage and search.reindex_now runs it on demand.

The CRM

For GTM teams

The console includes a full CRM: Hot list, Companies, Contacts, Deals with managed pipelines and stage moves, Tasks, a timeline per record, saved and shared list views, CSV import, a Data quality page, AI chat, Sequences and Research. Around it sit pages for running the system: Signals (with a review queue and the verification gate), Conversations (replies with labels, calls, coverage), Studio (ask for a play or app, plays scored on impact and ease), Data health (completeness and parity per source), Adapters, and, under Operate, Open asks (the numbered ledger), Daily update and Actions (the ledger of what engines drafted or did, with undo and send batches you can pull back). It can be your system of record, or mirror the CRM you already use.

Under the hood

CRM screens live in apps/console under /org/<orgId>/. Writes: canon.edit / canon.edit_many for canon objects (an agent's call becomes a proposal), records.create for custom objects, canon.import (max 1000 rows per call; it manages its own transactions, so a large import is not cut off by the 30 second operation limit; a contact file with a company column links each contact by website, then name, and lists rows with no or several matches without creating accounts; members cannot commit it unless an owner allows it), deal.move_stage, deal.close, pipeline.create, view.create, task.create. Reporting currency and FX conversion for deals shipped in 0.2.1.

05 · The engines

What does the work

For engineers: how the engines work together and a page per engine with prompts and verification.

The console lists eight engines: Score, Outreach, Performance Ads, SEO & GEO, Enrichment, Merges, Plays and Routing. Every engine page opens on an overview with its mode (Dry or Live), KPIs, what it needs, approvals waiting, recent actions with undo, the definitions it uses and its plays. Around them sit signals, the research agent, CRM sync, source mappings, the search index and agent chat. Every engine runs on your signed definitions in the call's environment and falls back to a stdlib default. Build in this order: data first, then scoring, then routing and plays, then the outbound channels.

Signals and intent

stdlib/engine.signals 1.0.0

For GTM teams

Captures the reasons to reach out: funding, hiring, expansion, a pricing-page visit, a booked call, an intent-topic surge. Each signal gets a strength that fades over time, so last month's funding round counts less than this week's. Accounts above your thresholds become hot or warm.

Under the hood

Records typed gtm.signal rows (idempotent, 1 to 1000 per call), computes recency-weighted strength (default half-life 30 days, hot at 60, warm at 30) and surge reports. Intent comes from looot capabilities such as intent.topic_surge and intent.visitor_identification.

Key ops
signals.record, signals.ingest_intent, signals.score, signals.surge_report, signals.retract_signals, signals.undo_retraction
Definitions
definition.scoring_model key signals (a signalStrength block); definition.binding for intent.*
Jobs
Signal scans per play schedule; workflow flag signals.reaction (on by default) re-scores, routes unowned accounts, enrols on strong signals (≥ 50), alerts the owner (≥ 60)
Connections
looot; website tracking (tracking.site.create) for page visits; Cal.com and webform for inbound
Console
CRM > Signals: the feed of signals with their evidence, a Review queue to verify or dispute them, and the verification gate mode (owners and admins). CRM > Hot list shows the signals behind each score.
KPIs
Hot and warm accounts from the surge report

Enrichment

stdlib/engine.enrichment 1.0.0

For GTM teams

Fills in what is missing on companies and contacts: emails, phones, headcount, technographics. It fills empty fields and never overwrites what your team typed. Every value it writes carries when it was verified, how long it stays fresh and how confident it is, and stale ones are re-checked. A newer value replaces an existing one only through an approval, with undo. It always prices a batch first, and a monthly cap spends on your best accounts first.

Under the hood

A provider waterfall over capability.acquire: per-field try order, first satisfactory result stops the chain. Capabilities enrich.company, enrich.find_email, enrich.verify_email, enrich.find_phone, enrich.technographics, enrich.headcount, resolved by definition.binding with a price cap.

Key ops
enrichment.enrich_accounts, enrichment.enrich_contacts (default 25, max 500; estimate: true prices without running), enrichment.coverage_report
Definitions
definition.binding per capability (blueprints seed enrich.find_email on looot, max $0.05 per call)
Freshness
Each written value stamps verifiedAt, a freshness window and a confidence. enrichment.refresh_stale re-checks stale values the engine owns. A newer value replaces a record's value only through an approved proposal with undo. A monthly spend cap applies, with best accounts first. If a provider is down (unavailable, a timeout or a server error) the next provider in the binding runs. looot lookups use the workspace key, with the instance key only as a fallback.
Jobs
On demand; stale-value refresh; research-agent re-checks
Connections
looot (required)
Console
Engines > Enrichment (mode, fill rate, spend, bindings, freshness windows, newer values, runs); CRM > Companies and Contacts (enriched fields)
KPIs
Field coverage

Scoring and qualification (Hot list)

stdlib/engine.score 0.1.0 · stdlib/qualification

For GTM teams

Decides which accounts deserve attention now. It combines two views: fit (does this company match your ICP by region, size, industry) and intent (are they showing buying signals). Each verdict comes with the evidence behind it, and qualified accounts appear on the Hot list. Signals fade by family, intent is weighted by who it comes from, hard disqualifiers and negative reply or bounce behavior count, and committee coverage is visible. The engine learns from outcomes: it measures what happened after each verdict and proposes a better model for a second person to approve.

Under the hood

Rule-based scoring of gtm.signal against a versioned policy, producing gtm.qualification. Key default scores intent (default score.default.v1: qualified ≥ 60, review ≥ 30); key icp_fit matches the synthetic firmographic kind with CEL conditions over account fields. The stdlib icp_fit fallback is a pilot hypothesis: always sign your own.

Key ops
score.score_account, score.explain_qualification, score.rescan_organization, score.ingest_market_signals, query.list_qualifications
Definitions
definition.scoring_model (default, icp_fit), definition.committee_model (ABM), definition.segment, definition.persona
Learning
Scoring records an immutable snapshot of each verdict. score.learn measures outcomes (a confirmed positive reply, a meeting, an opportunity, a won deal), computes lift per criterion and proposes a new signed definition.scoring_model version. Reps flag a score with score.feedback. score.rescan_preview shows what a rescan would change before it runs: the fallback models changed in 0.2.5, so the first rescan re-scores accounts once, and it never hands off, routes or enrols anyone.
Jobs
Scheduled score.rescan_organization; hooks for signal scans and the qualified handoff
Connections
A model provider for explanations
Console
Engines > Score (/a/score) with a Learning section, CRM > Hot list
KPIs
Qualified coverage (Mission Control), hot-list size

Verify: score.score_account on a real account must report definition.scoring_model:default:vN (your model), not score.default.v1.

Routing, plays and workflow automation

kernel/flow-play · stdlib/gtm-routing · stdlib/gtm-plays

For GTM teams

When an account qualifies, someone has to own it and something has to happen. Out of the box, a qualified account gets an owner (round-robin over members, or a list you set), a follow-up task due in two days, and its contact enrolled in the right sequence. Customers, partners and former customers are skipped, and an open deal blocks enrolment. Routing has its own page with territories, team capacity (caps per type, weights, out-of-office, stickiness) and lead-to-account matching, where only an exact domain match attaches on its own. Plays let you add your own automations, and Engines > Plays > Results shows runs, outcomes, credited revenue and spend per play. Nine ship in the blueprints: speed to lead, meeting prep, meeting follow-up, stage-stuck nudge, closed-lost win-back, renewal runway, champion change, content refresh and enrich on create.

Under the hood

routing.assign sets the owner and records an auditable decision with its reason (no routing definition kind; capacity and weights are per-member settings, a queued cool-off is evaluated in SQL, and a full owner's records spread over the eligible pool). Workflow flags qualification.handoff and signals.reaction are toggled with flags.set. definition.play compiles to a versioned flow: triggers manual, event, schedule, metric, webhook, segment, mission_step; steps action, wait, branch; guardrails cap actions and budget per run.

Key ops
play.simulate (zero writes, always first), play.trigger, runs.list, runs.get, flow.cancel, routing.assign, flags.set
Definitions
definition.play, definition.segment
Shipped plays
signal_based_outbound, inbound_speed_to_lead, dormant_account_reactivation in stdlib/gtm-plays; blueprints add first-touch-outreach, daily-rescore, daily-seo-audit, the nine plays above and more. Results per play: plays.kpis
Console
Engines > Routing, Engines > Plays (with Results), Settings > Workflow automation (/workflow); Operate > Runs

Outreach

stdlib/engine.outreach 0.1.0

For GTM teams

Drafts, personalizes, sequences and sends email (and LinkedIn steps through Unipile). Every send is a proposal a teammate approves, and its factual claims are checked against your proof. Sends go out through a lane: a channel with a daily cap, a minimum gap between touches, a monthly budget, automatic pause on high bounce or complaint rates, and a checked sending domain. Your brand voice shapes the copy.

Under the hood

outreach.send_message is E-class and needs an active lane and a bound mailbox, otherwise lane_required or mailbox_required. Pre-send checks: suppression, consent, mailbox_health, daily_cap, template_integrity, declared_params, recent_touch, open_deal, reply_stop, plus Dry Mode, the engine mode, the claims gate, brand safety, quiet hours and the net-new rule, at propose time and again at execution. New mailboxes warm up from 20 per day, +20 per day, to 200.

Key ops
outreach.draft_message, outreach.draft_personalized_message, outreach.send_message, sequence.create, sequence.enroll (max 500), sequence.update, lane.activate, outreach.sending_mailboxes
Definitions
definition.lane, definition.brand_voice (default), definition.suppression_rule, definition.compliance_policy (seed with compliance.seed_policies)
Sequences
definition.sequence: ordered steps, waits in days or business days counted in the recipient's timezone, send windows, templates or briefs, weighted A/B variants, and exits on reply, unsubscribe, bounce, an optional meeting and a stage change. Three signal plays (funding, hiring, intent) enrol one person per signal into an approved sequence, with a daily cap. Personalization is tiered (1:1, 1:few, 1:many) and grounded in the proof library. Reply next actions are proposals, never automatic.
LinkedIn
Steps send through Unipile on the same approval path as email, with seat caps and an accept-wait step. High-risk use needs explicit acceptance, and live use needs a real Unipile account (not yet verified live in this release).
Deliverability
Gmail and Outlook delivery reports are applied as hard or soft bounces and never ingested as replies. outreach.bounce_undo is human only. outreach.learning_report powers "What's working" (a group needs at least 30 sends before its rates show).
Jobs
outreach.rescan_cadences, outreach.advance_cadence, Gmail and LinkedIn reply ingestion, mail and calendar auto-logging
Sending domain
lane.activate checks SPF, DKIM and DMARC for the lane's sendingDomain; prod refuses activation unless all three pass
Connections
Gmail or Microsoft 365 connected mailbox (preferred) or Resend; Unipile for LinkedIn; a model provider
Console
Engines > Outreach (/a/outreach), CRM > Sequences, Needs a human
KPIs
Reply rate, sends per lane against the daily cap, bounce and complaint rate

A sent email cannot be un-sent: outreach.undo_send_message only records a retraction.

Merges, identity and data quality

stdlib/engine.identity-dq 1.0.0

For GTM teams

Keeps the database clean: finds duplicate companies and contacts, normalizes formats, flags invalid records, fills missing company domains from work emails at no cost, and scores overall data quality. The duplicate scan follows your signed identity rule. Merges are proposals that list each field conflict and how it is decided, and they can be undone.

Under the hood

Deterministic, reversible normalization; zero-spend domain backfill; looot-backed firmographic enrichment through the broker. Thresholds live in the flag identity_dq.thresholds (defaults maxDupRate 0.05, minMeanQuality 0.5, maxStaleRate 0.8; daily scan).

Key ops
identity_dq.quality_report, identity_dq.scan_duplicates, identity_dq.normalize_records, identity_dq.backfill_domains, identity_dq.merge_records (E), identity_dq.unmerge_records
Definitions
definition.identity_rule, definition.data_monitor
Jobs
identity_dq.scan data monitors on the claim-due loop
Console
Engines > Merges (merges waiting for approval, recent merges with undo, identity rules, merge rules); CRM > Data quality; Operate > Monitors
KPIs
Fill rate, duplicate rate, staleness, mean quality score

SEO and GEO

stdlib/engine.search 0.1.0

For GTM teams

Tracks your important pages, audits technical SEO and readiness for AI search engines (GEO), recommends fixes, and records whole-site visibility from Search Console (and Ahrefs if you have it). It also groups demand into topic clusters and runs a content factory (briefs, drafts, a quality gate, lifecycle states) and publishes an approved draft to your CMS. A content change to your site is a proposal a teammate approves, and its claims are checked against your proof.

Under the hood

Audits gtm.content_asset pages and proposes content, meta and schema publishes. Google Search Console is required for orgs that use this engine, through a Google connected account or the Composio google_search_console toolkit, plus the property gsc/site_url. Without it, gtm doctor reports an error and blueprint SEO plays are held back.

Key ops
seo_geo.create_tracked_page, seo_geo.audit_page, seo_geo.scan_all_pages, seo_geo.run_visibility, seo_geo.get_visibility, seo_geo.get_recommendation, seo_geo.gsc_properties, seo_geo.publish_content_change (E)
Publishing
Webflow through Composio, WordPress.com as drafts only, or a signed webhook (also the route for self-hosted WordPress). The body published is read from the approved draft and bound to its hash. Refresh candidates and publishing KPIs are on the page. Publishing needs a live check with a real CMS account.
Definitions
definition.play (daily seo_geo.scan_all_pages), definition.metric (search KPIs)
Connections
Search Console (required), Ahrefs optional (Composio), GA4 optional, looot for keyword data
Console
Engines > SEO & GEO (/a/seo-geo) and the page workbench
KPIs
search_organic_traffic, search_avg_rank, search_geo_readiness, search_tracked_pages

Performance Ads

stdlib/engine.performance-ads 0.1.0

For GTM teams

Pulls spend and conversions from Google Ads and Meta Ads, compares them with the economics you set (margin, CAC target, order value), and recommends pacing. A nightly allocator proposes budget moves toward your target and never executes them. Any budget or status change is real money, so it is a proposal.

Under the hood

Reads performance into gtm.outcome, proposes changes on gtm.campaign through the gate. The economics gate reads definition.unit_economics key default (targetCac or targetRoas or maxPaybackMonths, with grossMargin); with no target set, behavior is as before. The allocator runs nightly at 02:00 UTC and only proposes, each move needs a different approver, and a budget increase is capped at 2x. The page shows MER, aMER, ACoS and CAC payback tiles and a table of platform numbers against real ones; real CAC and ROAS come from paid visits credited by utm_campaign and read as a dash with the reason when campaigns are untagged.

Key ops
perf_ads.sync_performance, perf_ads.scan_all_campaigns, perf_ads.get_pacing_recommendation, perf_ads.update_campaign (E), perf_ads.undo_campaign_change
Connections
Google Ads through the connected Google account (ads feature) and google_ads/customer_id; Meta through a meta_ads Connection
Console
Engines > Performance Ads (/a/perf-ads) and the campaign workbench
KPIs
perf_ads_spend_total, perf_ads_conversions_total, perf_ads_campaign_count

Research agent

kernel agent runtime

For GTM teams

Researches people and companies for you: identity, social profiles, company profile, meeting prep 24 hours before a call, and periodic re-checks. It proposes facts with the evidence attached. It also builds your own "who we are" workspace profile from your website.

Under the hood

Defaults: enabled, auto-applies verified facts, daily budget $5, re-checks at 14, 90 and 365 days. Uses looot capabilities (enrich.person, research.web_search, research.extract_page). Switching autoApplyVerified on stays a human decision. Writes must resolve onto the existing record by domain or email.

Key ops
research.request, research.queue, research.subject.get, research.fact.decide (human), research.settings.set, research.workspace_profile.refresh
Console
CRM > Research

CRM sync (CRM of record)

hosted by stdlib/engine.score · stdlib/connector.composio

For GTM teams

Keep using HubSpot, Salesforce, Pipedrive, Attio or Zoho. GTM OS mirrors its companies, contacts and deals every six hours (or on demand), scores and enriches them, and can write results back, such as an account tier, after approval.

Under the hood

Through Composio: crm.settings.set {crmOfRecord} (needs an ACTIVE Composio account), crm.sync (one job per org, 10,000 records per object cap), crm.sync_status. Records are keyed on custom.crm = {toolkit, object, recordId}. Write-back: crm.update_record (E), undo with crm.undo_update_record.

Console
Integrations > Connections > Composio, section "CRM of record", Sync now
After sync
Run identity_dq.quality_report and identity_dq.scan_duplicates

Source mappings (any app to the ontology)

source.* operations

For GTM teams

Any other app you connect (Typeform, Stripe, Intercom, Airtable, Notion, an internal tool) can feed records into GTM OS. You preview real rows from the app, map its fields to companies, contacts, signals or your own objects, and schedule it.

Under the hood

A signed definition.source_mapping: source {backend: composio | mcp, toolkit, listTool, args, pagination, itemsPath}, target {objectType}, idField, fields[{from, to, transform}], match, mode: mirror | append (signals must append), schedule, optional approval-gated writeBack. Only a signed version runs.

Key ops
source.list_tools, source.preview (no writes), source.targets, source.suggest_mapping, source.sync, source.sync_status, source.update_record (E)
Console
Composio card > a connected app > Map to ontology
Outcome counts
created, updated, unchanged, skipped, invalid, unresolved, truncated

Agent chat

chat.* operations

For GTM teams

An AI assistant inside the CRM. Ask about an account, log an activity, create a task, move a deal. Anything it would change is proposed, and a teammate other than the person who asked approves it.

Under the hood

chat.conversation.create, chat.message.send: a bounded tool loop through the model gateway (8 steps, 120 s). Write tools (activity.log, task.create, task.update, canon.edit, deal.move_stage, sequence.enroll) are only proposed. Needs a model provider. Console: CRM > AI chat (/chat).

06 · End-to-end flows

How the pieces move together

From signal to approved send

This is the default path with both workflow flags on (signals.reaction, qualification.handoff). No custom play is needed.

flowchart TD
  S["Signal recorded: funding, hiring, visit, form"] --> R["signals.reaction re-scores the account"]
  R --> Q{"Qualified by your scoring model?"}
  Q -- "no" --> W["Stays warm, watched by scans"]
  Q -- "yes" --> HO["qualification.handoff"]
  HO --> O["Owner assigned, round-robin or your list"]
  HO --> T["Follow-up task due in 2 days"]
  HO --> E["Contact enrolled in the lane-bound sequence"]
  E --> D["Message drafted in your brand voice"]
  D --> P["outreach.send_message proposed"]
  P --> C{"Pre-send checks pass, claims backed by proof?"}
  C -- "no" --> X["Blocked: suppression, cap, open deal, unbacked claim"]
  C -- "yes" --> A["Second human approves and executes"]
  A --> M["Sent from the lane mailbox, logged"]
  

For GTM teams

Your reps see qualified accounts on the Hot list with an owner and a task already set. Sends wait in Needs a human. Customers, partners and former customers are excluded by default, and an open deal stops enrolment.

Under the hood

Strong buying or intent signals (strength ≥ 50) enrol directly; ≥ 60 alerts the owner. Owner pool: members round-robin, or route.ownerIds in the flag. Both flags are edited with flags.set (keep the other keys). The lane's envelope, daily cap and DNS state apply at send time.

Connect an app with Composio and sync it into the ontology

flowchart LR
  A["Connect Composio: sign-in, ck_ or ak_ key"] --> B["composio.connect an app, human consent"]
  A --> SC["composio.sync_connections finds apps already connected"]
  SC --> C
  B --> C{"Is it your CRM?"}
  C -- "yes" --> D["crm.settings.set, then crm.sync every 6 hours"]
  C -- "no" --> E["source.preview and source.suggest_mapping"]
  E --> F["definition.source_mapping, signed by a human"]
  F --> G["source.sync on its schedule"]
  D --> H["gtm.account, gtm.contact, gtm.deal, gtm.signal"]
  G --> H
  H --> I["Identity resolution and dedupe review"]
  

Build and go live

flowchart LR
  A["Discovery interview"] --> B["blueprint.apply into dev"]
  B --> C["Customize definitions in dev"]
  C --> D["config.apply approved by a second human"]
  D --> E["definition.propose_for_signing"]
  E --> F["definition.sign_many by a human, not the proposer"]
  F --> G["env.promote dev to prod, one approval"]
  G --> H["lane.activate, SPF DKIM DMARC checked"]
  H --> I["go-live-check returns GO"]
  

In the console, Environments > Go live does the sign and promote in two clicks: "Review & sign all proposed (N)", then "Promote dev → prod". The /go-live-check command runs a read-only GO / NO-GO list: live mode, gtm doctor --strict, readiness, the Search Console requirement (if SEO is used), engines enabled, definitions signed in the target environment, a live check per engine, a second approver, Dry Mode off, and caps.

07 · Integrations

What GTM OS connects to, and why

The split that matters. looot is for buying third-party data. Composio is for your own apps and actions in them. Never use Composio to buy data, and never use looot to write into your CRM.

looot: third-party data

For GTM teams

The single source for outside data: company and people search, lookalikes, email and phone finding and verification, intent, news, jobs, web search, page extraction and SEO keyword data. Every call is priced, capped and recorded with its source.

Under the hood

Reached only through capabilities (capability.quote, capability.acquire) resolved by a definition.binding with backend: looot; there are no looot.* operations. Credential: instance LOOOT_TOKEN or a per-org looot Connection. Values carry provenance looot:<capability>:<runId>. Pin an endpoint with gtm capabilities discover.

Composio: your own apps and actions

For GTM teams

Composio connects GTM OS to the SaaS accounts you already use, from a catalog of 1,000+ toolkits: your CRM, Slack, Typeform, Stripe, Ahrefs, Search Console and more. Click Connect Composio, sign in, and apps you already connected in Composio are picked up automatically.

Under the hood

Three credential modes, one per org (the newest replaces the previous): Connect Composio (OAuth 2.1 + PKCE, tokens sealed and refreshed: composio.oauth_start → composio.oauth_callback), a ck_ Connect key, or an ak_ project key (composio.set_api_key, verified live). uak_ user keys are refused. Precedence: sign-in, then ck_, then ak_, then instance COMPOSIO_API_KEY. Auto-discovery: composio.sync_connections; status: composio.status.

Per-org MCP servers

Any streamable-HTTP MCP server can become a capability backend for one org, without a restart. mcp_servers.add stores the URL and auth header sealed, mcp_servers.test runs a live initialize and tools/list, and a human marks each tool read or write with mcp_servers.set_tool_effects. Bind it with definition.binding {backend: "mcp", opId: "mcp:<server>:<tool>"}. An undeclared tool is unusable; a write tool needs riskClass: "high_risk", broker.accept_high_risk and a second human's approval on every call.

Native connections

ConnectionUsed forHow
Google account (OAuth)Search Console, GA4, Google Ads, Gmail send and sync, CalendarSettings > Connected accounts; "Use for org" for the org default
Microsoft account (OAuth)Mail, send, calendarSettings > Connected accounts
Slack (OAuth)Alerts, channels, member matching; agents can postSettings > Slack
ResendEmail sending when no mailbox is connectedresend Connection or RESEND_API_KEY
UnipileLinkedIn reads and sends (high risk, needs your explicit acceptance, same approval path as email)Unipile card: API key + DSN
Webform, Cal.comInbound forms and bookings as signalsHMAC-verified webhooks
Website trackingPage views, sources, first and last touchtracking.site.create snippet, tracking.verify
Meta AdsAd performance and changesmeta_ads Connection

Mail and calendar sync every 10 minutes and auto-log activities with known contacts.

The Connections page

Integrations > Connections is a searchable grid of brand-logo tiles in 11 categories. Each tile shows whether it connects Native or Via Composio, with a choice where both exist, and a Needed strip lists what your chosen blueprint and engines still need. Press / to jump to the search box. Sort by relevance to your setup (the default), A to Z or connected first. Statuses are honest (live, stored but not verified, failed, not connected), and in demo mode a tile says it uses built-in sample responses, not your data. Instance keys are shared with an organization only for the providers in GTMOS_PLATFORM_CREDENTIAL_PROVIDERS. No native card exists yet for Instantly, lemlist, Smartlead, Gong, Mixpanel or Amplitude: use Composio.

Model providers

At least one of Anthropic, OpenAI, Gemini or OpenRouter (one key for many vendors, generate-only) must be live, as an org Connection or an instance key. Default models: claude-sonnet-5-5, gpt-4o, gemini-3.8-flash, overridable per provider with GTMOS_DEFAULT_MODEL_<PROVIDER>. Pin routes per task class (reasoning, drafting, classification, extraction, embedding) with definition.model_policy. Region-specific routing fails closed without a configured regional endpoint.

08 · Flexibility and customization

Change almost anything, through an agent, under review

For engineers: the GTM engineer guide has copy-paste prompt recipes for every kind of change, and governance explains who approves what.

GTM OS is designed so that you, through Claude Code, Codex or any MCP agent, can reshape the system to fit your motion. Engines, data model, data sources, integrations, starting templates, packages and screens are all configuration. The agent writes it; your team signs it; it goes live.

For GTM teams

You do not file a feature request to change how leads are scored or which accounts get a sequence. You tell the agent what you want ("weight hiring signals higher, and only DACH companies with 200 to 5,000 people"). It writes the definition in dev, shows you the diff, and a teammate signs it. The same goes for a new field, a new object, a new data source or a new automation.

Under the hood

Every customization point is an operation or a definition kind with a strict schema, so the agent never guesses a field (gtm_describe returns the exact JSON Schema). Config changes travel as ChangeSets, are validated before anything applies, and go through the same sign and promote path as anything else. Nothing is edited in the database directly.

What you can customize

Engines

Scoring models and thresholds (definition.scoring_model), buying committees, segments, personas, lanes (caps, checks, budget, domain), sequences, brand voice, suppression and compliance, unit economics, workflow flags (qualification.handoff, signals.reaction, identity_dq.thresholds) and routing owners.

Ontology

Custom fields on accounts, contacts and deals (field.create, immediate). Custom objects and relationships (ontology.propose_changeset, published after approval). Optional modules such as stdlib/gtm.partner. Pipelines and stages.

Data

Source mappings from any Composio app or MCP server into any canon or custom object, with transforms, match keys, schedule and optional gated write-back. Identity rules and survivorship. Mirror modes per object type. CSV import.

Integrations

Connect any Composio app; add your own MCP servers; bind any capability to looot, Composio, MCP or native backends with a price cap and fallbacks (definition.binding). Build Composio-powered automations as plays whose steps call operations, or as agents with triggers.

Blueprints

Start from the closest general blueprint (blueprint.apply), then change only what your motion needs. Blueprints are general templates: no customer-specific blueprint ships, and you should not create one.

Packages

Ship your standard setup as a declarative package of definitions and parameters (gtm pkg scaffold --tier declarative). Code goes in a signed trusted or sandboxed package. Example: examples/acme-cyber-outbound/.

Apps and screens

Declarative screens with definition.app (routes, audiences, pages composed from view types over operations), served at /org/<org>/a/<key>. Sandboxed code apps for custom UI. Console theme tokens via definition.brand_kit. Saved views and nav settings per org.

Agents and automations

Register agents with a signed definition.agent (scopes, skills, step, cost and deadline bounds), and fire them manually, on a schedule or on CRM events (agent.trigger.create). 16 organization agents in 6 packs install when you enable a pack, with the same governance, and packs and blueprints can ship triggers. CRM: inbound responder, meeting prep, follow-up, pipeline review, deal desk. Revenue: signal watch, routing steward, scoring steward, reply triage. Data: enrichment, data hygiene. Growth: SEO and GEO watch. Ops: onboarding guide, ops copilot (read only). Core: SDR, account research. They start on a schedule, an event (a form submitted, a meeting booked, a transcript ingested, a reply received, an account created, a verified funding, hiring or intent signal) or when you run them. Operations that spend inside themselves are never granted to an agent skill. Long jobs run as missions with one human approval moment.

Agent parity

An agent key with the Full GTM engineer preset (the Claude Code default), acting for an owner or admin, can do everything that person can do in the console through operations: records, fields, pipelines, definitions (proposed), research settings, CRM settings, workflow flags, connections and keys the user hands over, MCP servers, syncs, scans. Four things stay human and return FORBIDDEN:

Stays humanWhyExamples
Approve, reject, execute, sign, publishFour-eyesruntime.approve_action, runtime.execute_approval, definition.sign, ontology.publish_changeset, mission.approve, research.fact.decide
Widen its own authorityNo self-escalationagent.create_key, agent.revive, policy.set_gate_policy, envelope.grant, delegation.grant, mcp_servers.set_tool_effects
Give browser OAuth consentA person must clickcomposio.oauth_start, composio.connect, Google, Microsoft and Slack sign-ins (the agent gets the link)
Toggle Dry ModeSafety switchpolicy.set_dry_mode

Effective authority is the intersection of the key's scopes, the agent's scopes and the creating human's current role, re-checked on every call. Demote the human and the key shrinks. action.approve can never be granted to a key. Kill an agent everywhere with agent.kill.

The harness: gtm init

For GTM teams

Open an empty folder in Claude Code, run gtm init, then type /setup-gtmos. Claude installs or connects GTM OS, sets up the agent key, connections and second approver with you, then runs /build-gtm-system: an interview about your business, a blueprint recommendation, and an engine-by-engine build. It stops wherever a human must act. /go-live-check tells you GO or NO-GO.

Under the hood

gtm init (alias of gtm harness) scaffolds: CLAUDE.md and AGENTS.md; 11 builder subagents (lead gtm-architect) and 11 role subagents (gtm-operator, revops-analyst, deal-reviewer, sales-researcher, content-strategist, seo-refresher, customer-success-manager, competitive-analyst, ads-analyst, data-steward, eval-reviewer) written to .claude/agents, .agents/agents and .codex/agents; 13 slash commands; 107 skills from ay-automate/gtmos-skills (pinned to a release, checked against a sha-256 manifest, with a bundled offline copy); .mcp.json; a session-start hook; .claude/gtm-context.md generated from the live registry; memory seeds; and docs/gtmos/ with the 11 guides (including the setup wizard) and generated reference. Idempotent; gtm init --refresh takes new skills, subagents and docs and keeps your edits. It stamps the CLI version, skills release and operation list it generated from into .claude/gtmos-instance.json, and gtm doctor reports a stale harness with the fix.

The agent's tools over MCP: gtm_describe (always first), gtm_query, gtm_get, gtm_search, gtm_act, gtm_approvals, gtm_lineage, gtm_lineage_trace, search_records.

The ten blueprints

General templates, applied with blueprint.apply or gtm apply --from <id>. Each seeds a whole motion in one change set and makes its declared connections required. Every one except seo needs a model provider, looot and (where it sends) an email sender.

BlueprintMotionEnginesAlso required
b2b-saas-sales-ledEnterprise ICP, firmographic and intent scoring, human-run outbound lane (34 resources)CRM, enrichment, outreach, research, score, signalsCRM
enterprise-abmNamed accounts, buying committee, multithreaded lane, account journey (34)CRM, enrichment, outreach, research, score, signalsCRM
b2b-saas-plgProduct-qualified signals and a low-touch nurture lane (17)CRM, enrichment, outreach, scoreNone
devtoolsDeveloper-first adoption signals and a help-first lane (16)CRM, enrichment, outreach, scoreNone
agency-servicesDone-for-you services to small businesses, outside-in scoring (21)CRM, enrichment, outreach, research, scoreNone
b2b-marketplaceTwo-sided marketplace, supply acquisition lane (18)CRM, enrichment, outreach, research, scoreNone
dtc-b2cConsumer lifecycle email and ad pacing (14)Enrichment, outreach, performance ads, scoreAd platform (Google Ads or Meta Ads)
outboundGeneric outbound starter (19)CRM, enrichment, outreach, research, scoreNone
seoSEO and GEO starter (15); no email sender neededCRM, searchSearch Console
full-gtmEvery built engine on one foundation (49)CRM, enrichment, outreach, performance ads, research, score, search, signalsCRM, ad platform, Search Console

gtm blueprint list and gtm blueprint show <id> browse the catalog offline, gtm blueprint upstream --org <id> shows which blueprint an organization derives from, and gtm blueprint upgrade produces a reviewable diff and, with --yes, proposes it for approval. The user guide lists what each one sets up.

Customizable now, or needs a new release

ChangeConfig, todayNeeds a release
Scoring rules, thresholds, segments, personas, committeesYes
Lanes, sequences, brand voice, suppression, complianceYes
Plays, schedules, workflow flags, routing ownersYes
Custom fields, custom objects, relationships, pipelinesYes
New data source from any Composio app or MCP serverYes
Capability backends, price caps, model routingYes
Declarative screens, theme tokens, saved viewsYes
Agents, skills, triggersYes
Your own declarative, trusted or sandboxed packageYes, signed if it carries code
Redefining a canon gtm.* fieldOntology release
A new definition kind or operation classKernel release
A new first-party engine, native connector adapter or model providerStdlib release
Weakening four-eyes, agent limits or tenant isolationNot possible by design

09 · Security and governance

Who can see, do and approve what

For GTM teams

Each organization's data is walled off from every other organization at the database level. API keys and OAuth tokens are encrypted and never shown again after you save them. Every action, by a person or an agent, is written to a tamper-evident audit log with who proposed it, which agent did it, for whom, and who approved it.

Under the hood

Every tenant table is under Postgres row-level security and the app connects as a non-superuser NOBYPASSRLS role. Credentials are AES-256-GCM encrypted under a per-org data key (envelope encryption), rotatable with secret.rotate_org_key. The operation audit log is hash-chained per org with signed daily checkpoints.

Roles

RolePermissions
owner, adminrecord.read, record.write, engine.configure, connection.manage, action.approve
builder (delegated agency role)Everything except action.approve
memberrecord.read, record.write
servicerecord.write
Role profile (optional, on top of a role)Only narrows. A base role plus the operations the person never runs and the KPIs and actions of their Mission Control. Built in: Operator, Ops lead, Exec, Engineer; add your own (roles.upsert, roles.assign, human only). Agents act under the profile of the person they act for.

Controls at a glance

Sign-in

Better Auth sessions, Google and Microsoft sign-in, SSO (sso.*) and allow-listed sign-in (auth.allowlist.*), all human-only to configure.

Agent keys

gtm_ keys shown once, default expiry 90 days (1 to 365 or never), revocable; 15-minute exchanged tokens; kill switch agent.kill.

Signing

Definitions are signed by a human other than the proposer. Packages are Ed25519-signed. Container images are cosign-signed.

Sandboxing

Sandboxed code apps run in an opaque-origin iframe with a strict CSP, deny-by-default egress, and a bridge that only runs operations listed in the manifest.

Privacy

privacy.erase (right to erasure with a re-ingest guard), retention.set_policy per class, governed org.offboard.

Network exposure

The console, API and MCP ports bind to 127.0.0.1 by default (GTMOS_BIND_ADDRESS), so a reverse proxy with HTTPS is the only thing exposed. GTMOS_LIVE must be set explicitly in production.

System email

Invitations, password reset, verification and setup reminders need EMAIL_TRANSPORT and SMTP_* (or webhook addresses) in .env. Unset means those mails are not sent, and reset or verification links are never written to production logs.

Instance keys

An organization falls back to an instance key only for providers listed in GTMOS_PLATFORM_CREDENTIAL_PROVIDERS. CRM, ads-account, LinkedIn and Search Console credentials are not shared by default.

Claims and proof

Every factual claim in outbound content is checked against active, permissioned proof at propose time and again at execution. A customer is never named without public proof.

Record privacy

Records set to private or team are visible only to their owner, creator and the organization's owners and admins, across lists, search, counts and the dashboard. Members cannot commit CSV imports or bulk edits unless an owner allows it. Tasks are editable only by their creator, assignee or an owner or admin. Agent keys follow the person's current role.

Audit and lineage

audit.list (Settings > Audit log), runtime.get_approval with full attribution, lineage.trace per value. OpenTelemetry tracing across the pipeline.

10 · Glossary

Terms, GTM and technical

ABM gtm
Account-based marketing: selling to a named list of accounts and covering their buying committee.
ACV gtm
Annual contract value of a deal.
Buying committee gtm
The people who sign off a purchase. Modelled with definition.committee_model.
GEO gtm
Generative engine optimization: being cited by AI search engines.
GSC gtm
Google Search Console. Required for the SEO & GEO engine.
Hot list gtm
CRM view of qualified accounts with the signals behind each score.
ICP gtm
Ideal customer profile. Scored by the icp_fit model.
Intent surge gtm
A spike of research activity on topics you care about at an account.
Lane gtm
A sending channel with caps, checks, budget and a sending domain.
Persona gtm
A role you target inside an account, defined by title and seniority criteria.
Play gtm
An automation: a trigger, optional filter, steps and guardrails.
PLG, PQL gtm
Product-led growth; a product-qualified lead or account.
Segment gtm
A rule that selects which records a motion works.
Signal gtm
A dated reason to engage (funding, hiring, visit, booking), stored as gtm.signal.
SPF, DKIM, DMARC gtm
DNS records that prove a sending domain is yours; checked at lane activation.
Suppression gtm
People or companies who must never be contacted.
Binding tech
Config that says which backend serves a capability, at what price cap.
Capability tech
A named outside ability (for example enrich.find_email) acquired through the broker.
CEL, Cedar tech
Common Expression Language for criteria; Cedar for authorization policy.
ChangeSet tech
A batch of config or ontology changes validated and applied together.
Definition tech
A signed, versioned piece of config an engine reads at run time.
Dry Mode tech
A switch, for the organization and for each engine, that turns customer-facing effects into drafts. The stricter one applies.
Envelope tech
A scoped, time-bound pre-approval with a budget (for example a lane's send budget).
Fixture tech
Deterministic fake data served only in demo mode.
Claims gate tech
The check that each factual claim in outbound content is backed by active proof, at propose time and again before it runs.
First win tech
One of eight milestones computed from real events (onboarding.first_win), never from clicks.
Harness tech
The files gtm init writes in a project (skills, subagents, commands, MCP config, docs) so an agent can run GTM OS.
Four-eyes tech
The proposer, and the human an agent acts for, can never approve, sign or execute.
Ledger tech
Double-entry record of every quoted, held and settled cost.
MCP tech
Model Context Protocol: how Claude Code, Codex and other agents call GTM OS.
Mirror mode tech
How outside data materializes per object type (replicate, soft_merge, federate, in_zone, sheet).
Observation tech
An immutable raw fact from a source, before resolution and projection.
Outbox tech
Events written in the same transaction as the change, relayed by the worker.
Provenance tech
Per-value evidence: source, confidence, band and survivorship rule.
RLS tech
Postgres row-level security isolating each tenant's rows.

11 · What is not built yet

Honest limits in 0.2.5

These come from the release notes and the shipped guides. Plan around them rather than discovering them during a pilot.

AreaStatus
Create in CRMThere is no gated "create a record in the CRM" action. CRM writes stay update-only, and high-risk Composio writes need per-record approval.
Custom field display and filters"Show in tables" and "Allow filtering" are stored, but the Companies list has no such columns or filters yet. records.list filters do work.
Company context for AI stepsOnly brand voice, proof and customer phrases reach drafts. The rest of the company context does not yet.
Connectors without a native cardInstantly, lemlist, Smartlead, Gong, Mixpanel and Amplitude. Use Composio.
More enginesEight appear in the console. New engines (ABM, sales intelligence, lifecycle, reporting) are deferred, as are the ads creative loop, audience sync and offline conversions, routing SLAs and escalation, merge batches and learning from rulings, an enrichment catalog with job-change triggers, play holdouts and a larger play library, GEO gap fixes and a link graph, more vendor skill packs, engine-dependent agents and per-agent evaluation sets.
Signal scan qualityWeb search results are not yet checked as being about the account. Set up a news binding for better results, or switch the scan off with signals.scan set to enabled: false.
White-label for agenciesCustom branding or domain per client is not available. Delegations, agency.overview and agency-private packages exist; definition.brand_kit re-themes one app only.
Expansion and reorder motionNot a shipped motion. You can compose a customer segment plus a custom play; renewal runway ships as a play.
LineageDerived and metric lineage are stubbed (empty). Value lineage works.
RelationshipsCustom relationship cardinality is recorded, not enforced.
Gate policiesOne org-wide gate policy per org; per-operation-family policies are supported in storage, not routed yet.
Console rough edgesThe Records and Model pages still list ontology keys and type names. A few small icon buttons are under 28 px at phone width.
RolesNo viewer role.
Nudge emailSetup reminder emails to your own team need an email transport (SMTP or a webhook). Without one they stay in the console, and only for people who opted in.
CSV importUp to 1,000 rows and 10,000,000 characters of CSV text per call (the console chunks larger files). Members cannot commit unless an owner or admin allows it. A company that is not found is never created: the row is imported without a link. Look-alike rows are held for review.
Dry Mode scopeDry Mode turns customer-facing (E) operations into drafts. Data writes (D), stage transitions (T) and configuration (M) operations still run.
Strict signal gateNew workspaces start on Strict: third-party signals do not count or reach sellers until a person verifies them, so a first test can show an empty Hot list. First-party signals verify by default.
Ontology versionCanon ontology is 0.1.0-draft.

Integration maturity

IntegrationWhere it stands in 0.2.5
HubSpot, Google Ads, Meta Ads, Search Console, GA4, Resend, loootNative connectors with a live path (needs your credential) and a fixture path. Google Ads and Meta Ads can also be read through Composio, which is read-only.
SalesforceNative adapter is fixture-first (recorded Salesforce responses), not verified against a real organization. Use the Composio path.
LinkedIn Ads, TikTok AdsRead-only through Composio.
WebflowPublishing through Composio, tested with simulated responses.
WordPress.comDrafts only. Self-hosted WordPress goes through the signed webhook.
LinkedIn through UnipileHigh risk, off until an owner or admin accepts it, tested against recorded responses, not verified live.
Gmail, Google CalendarPolled; wire formats not yet verified against a live account.

Needs a live check with real accounts

The code is tested against contracts and a live database, but these need a real account. Treat them as unverified until you have checked them.

IntegrationWhat to check
UnipileA LinkedIn message, a connection request and the accept wait.
Webflow and WordPress.comCMS publishing through Composio, and self-hosted WordPress through the signed webhook.
GmailA real bounce report arriving in a connected mailbox.
ResendSend, bounce and complaint events.
SalesforceThe native adapter is not verified against a real organization. Connect Salesforce through Composio.

This page describes GTM OS release 0.2.5. Counts come from the generated reference shipped with the CLI (operations, definition kinds, canon object types, packages, blueprints); your instance may differ, and its live registry (gtm_describe) wins.