
Harish Deivanayagam
•8 days ago
GTM teams are moving their logic into tools that an agent can edit. The open question is what that logic is stored as.
Clay stores a workflow in Clay. n8n stores a graph of nodes. Both are real products, and both are awkward for a model. The model has to learn a private format, click-equivalent APIs, and a pile of settings that only exist inside that vendor. Code does not have that tax. Models already write TypeScript. A file can be read, diffed, copied onto the next client, and executed somewhere that is not a laptop.
That is the case for code as the source of truth. The workflow you can open is the workflow that ran.
A GTM workflow has two artifacts that matter.
The first is the definition: which sources to read, which rows to keep, who to enrich, where to send the result, and what "new" means compared with yesterday. The second is the evidence: this run started, these calls happened, this payload left.
If the definition lives in a canvas, the truth is whatever the canvas saved, plus whatever somebody changed in the UI at 6pm. If the definition is a TypeScript file, the truth is the file. The run log is the evidence. When a client asks why a lead was enrolled, you open the file and the log. You do not reconstruct a table from memory.
Monial takes that literally. A workflow is one TypeScript file. Monial injects it into run(input) and executes it in a remote sandbox. input is the webhook payload, or an empty object on a cron run. The value you return is checked against the workflow's output schema. Lists remember rows between runs, so a monitor can suppress what it already sent.
GTME Pulse's 2026 stack benchmark puts AI coding tools in the majority of GTM engineer setups. The people building GTM systems are already in Claude Code, Cursor, and similar editors. Those editors are good at files. They are worse at being a careful user of someone else's workflow UI.
A Clay workflow or an n8n scenario can be driven by an API, and both ecosystems are adding agent hooks. The model is still targeting a format it sees less often than TypeScript, inside a product whose columns, nodes, and credentials are easy to get slightly wrong. A slightly wrong TypeScript file fails in a way you can read. A slightly wrong table fails as a blank column three steps later.
Code also travels. An agency can keep a hiring monitor as a file, duplicate it, change the title list and the Slack channel, and ship it for the next client. The runtime stays put. You are not exporting a scenario and hoping the credentials remap.
Cargo and Deepline made the same bet: GTM logic should be TypeScript an agent can write. The disagreement is scope. Cargo wants the whole motion in a repo (context, plays, territories, evals) and deploys that repo. Deepline wants Plays across a wide provider catalog, with a database between runs. Monial wants the execution file: one-off jobs and monitors, with a fixed toolkit already in scope.
The sandbox is the other half of "code as truth." The file is not a script on someone's machine with their API keys in the environment. It has no filesystem and no ambient network. It can call four namespaces, and those calls are what show up in the run:
scrappers.* for social, jobs, news, and pages. The underlying access (Apollo, Apify, Bright Data) is managed.enrichments.getEmail and enrichments.getPhone for a waterfall through FullEnrich.integrations.* for HubSpot, Slack, Instantly, HeyReach, Smartlead, and ad audiences on LinkedIn, Google, and Meta.ai.generateOutput to extract or classify from data the scrapers actually returned.Lists and webhooks.push are there too. Lists are how a monitor stays honest across days. Webhooks are how a row reaches a tool Monial does not integrate directly.
A hiring monitor is a short file, not a platform tour:
const LIST_ID = "your-list-id"
const jobs = await scrappers.getJobsFromLinkedInSearch(
"head of revops",
"7d",
"United States",
25,
)
const list = await lists.get(LIST_ID)
const data = list.data && typeof list.data === "object" ? list.data : {}
const seen = new Set((data.companies ?? []).map((row) => row.name))
const fresh = jobs.filter((job) => job.company?.name && !seen.has(job.company.name))
await integrations.slack.send(
fresh.map((job) => `${job.company?.name}: ${job.title}`).join("\n") || "No new RevOps roles.",
)
await lists.update(LIST_ID, {
companies: [
...(data.companies ?? []),
...fresh.map((job) => ({ name: job.company?.name, title: job.title, url: job.url })),
],
})
return { added: fresh.length }
The shape will follow the scraper result type you look up before writing the file. The point is the size. The whole motion is visible.
Code is a bad system of record for a rep's day. A seller should not review a pull request to learn which accounts are warm. Clearcue and WhiteWhale are built for that reading experience: ranked accounts, sourced research, a draft, an alert. If the deliverable is a morning brief, a signal product is the truth, and a workflow is plumbing behind it.
Code is also a bad fit when the editor is a person who will only work on a canvas. Clay and n8n are better daily drivers for that operator. A model can still help them. The file they trust is the one on screen in the product, and forcing TypeScript on them creates a workflow nobody on the team will touch after the freelancer leaves.
Code does not protect you from a bad spec. An agent will faithfully build the wrong ICP. Monial's answer is a small file a human can read, an in-product agent that drafts it, and a person on chat when the draft misses. It is not a claim that generated TypeScript is correct.
And code-as-truth fails when the code can do anything. A Claude Code session with a hundred MCPs and a shell is powerful, and it is a laptop workflow: keys, rate limits, and a process that dies when the lid closes. The truth Monial wants is narrower. The file runs in a sandbox, on a schedule, after the session ends.
Put the decision in the file: the query, the filter, the enrichment, the destination, the definition of new. Leave the systems of record where they are. The CRM stays HubSpot. The send stays Instantly, HeyReach, or Smartlead. The ad account stays the ad account.
Then the TypeScript is the GTM workflow, in the same way a migration is the schema change. You can show it to a client. You can run it tomorrow without rebuilding the graph. You can ask an agent to change one condition and read the diff before it goes live.