+ Book
GTM Engineering

Revenue OS: A Fully Agentic Sales Pipeline You Own (2026)

Four acquisition channels, one CRM, an agent on every step. The rule, the nine stages, the ledger, and the order to build it in. Owned, no SaaS in the middle.

Revenue OS hero: four acquisition channels feeding one CRM through agents, in the anfloy editorial style.
On this page

A Revenue OS is the system underneath a sales motion: every channel a prospect can reach you through, one CRM, and an agent on every step between the two. We run ours across cold email, LinkedIn, website visitors and inbound. It was built in a weekend with Claude Code, it runs on tools we already paid for, and nothing in the middle is rented.

This is the exact structure, short enough to copy.

The rule that makes it work

A person enters the CRM only when a conversation started: a positive reply, a booked call, a form, a website visit that passed the ICP. Scraped lists, profile views and email opens stay in a ledger and, at most, become a Slack prompt.

Qualification happens after the first real exchange, usually the call, as a stage. Nobody has to pre-qualify to get in, and the CRM stays small enough to read every morning. The wider approach is the same one behind signal based selling: act on what people do, not on who is in a list.

Two more rules the code enforces. One service owns every CRM write, so there is one place to look when something breaks. And one open deal per person: a form fill, a booking and a reply in the same week are one opportunity, not three records.

Four channels, one agent each

Revenue OS architecture: four input channels feeding one hub of eight agents, Attio as the source of truth on the left, the Supabase ledger on the right, Slack and the company brain as outputs
The Revenue OS, drawn from the repo at build time.
  • Cold email. Instantly already scores every reply, so no model runs on this step. A positive reply becomes a person, a company and a deal at the Signal stage in Attio, with the campaign as the source and the reply text as a note. Instantly's own Slack app posts the reply; the agent threads the CRM link under it. When someone on our side answers from the inbox, the deal moves to Contacted and a follow-up is set three business days out.
  • LinkedIn. Every profile viewer, like and comment on the founder's posts gets pulled and qualified against one ICP file. Tier 1 and 2 land in Slack for a human to act on. Replies to LinkedIn outreach enter the CRM at Signal the same way email replies do. Nothing in the system sends on LinkedIn.
  • Website visitors. RB2B identifies visitors and posts them into a Slack channel. The agent reads the post, extracts name, title, company and pages, runs the same ICP rules, then asks Claude the one question that matters: does this company sell AI or GTM builds to other companies? If yes, it is a peer, not a buyer. Tier 1 and 2 become a Signal deal; the verdict is threaded under the post.
  • Inbound. A Cal.com booking moves the deal to Call Booked. Thirty minutes before the call, a brief lands in Slack: the deal, where they came from, their exact words, what to ask. A cancellation sets the next action to rebook.

The qualification logic is the same two-stage gate we use everywhere: free rules first (competitor keywords, individual-contributor titles, a seniority floor, a country allowlist), a model only on what survives. More on the scoring side in AI powered lead qualification.

The CRM, kept deliberately small

Nine stages and four custom fields. The stages are the filters: Signal, Contacted, Call Booked, Proposal Sent, Nurture, Unqualified, Closed Won, Closed Lost, and one Partnerships column for the people you can always go to.

The four fields: source (set once by the agent, never overwritten), source detail (campaign, post or page), next action, and next action date. Nothing on people or companies. Follow-up is arithmetic on two timestamps, not a stage, which is why Follow Up, Canceled and No Show are not stages anymore.

Automation may push a deal forward only as far as Call Booked. Everything after that is a human click.

The ledger, and why it stays cheap

Every contact, reply, visit and booking lands in Supabase as history. Identity is email OR LinkedIn URL, and when both keys turn up on different rows the two merge. A duplicate event is rejected by the database, not by code.

Supabase bills egress, not rows, so the design minimises reads. Nothing polls the ledger. Every read must name its columns and a limit, or the code refuses to run. Sends are not stored, so a 1,000-a-day campaign adds about 20 rows a day. At a 100k MRR pace the whole thing stays under 100 MB. This is the same discipline described in GTM infrastructure: a database is a ledger, not a job queue.

The Slack agent and the 7:05 digest

All CRM updates run from Slack. Type "followed up with Aram, next touch Friday" and the agent finds the deal, updates the stage, the next action and the date, and confirms in the thread. It has four tools over the CRM and cannot delete anything.

Every weekday at 7:05 one digest: overdue, due today, partners to check in with, open pipeline by stage. Nothing else pings outside money moments, a call booked or a closed won. That is the whole answer to "who do I follow up with".

The stack

Instantly, RB2B, Cal.com, Attio, Supabase, Railway, Slack, Claude Code. One service on Railway holds the eight agents. Two small model calls in the whole system: Sonnet for the competitor judgement and the meeting brief, Haiku to read the RB2B post. Zero model calls on the reply path.

How to build it

  • The CRM first. Rename the stages, add the four fields, move every deal that sat in an event-named stage to Contacted with a next action due today.
  • The hub. One service, config from the environment, every integration off until its variable is set. Deploy it empty before wiring anything in.
  • Cold email. Poller plus webhooks. Test with a synthetic reply, then deliver the same reply twice: one deal, one event.
  • The ledger. Apply the schema, then prove the merge and the duplicate rejection on the live database before the post claims it.
  • Slack, Cal.com, the website form, the visitor tool. Point each at the hub. Prove every auth check can fail with a wrong secret before trusting it.
  • Stop what the hub replaced. Ours included an old worker hitting the database 150 times every five seconds on stuck leads. That was the bill.

This is the shape of every GTM agent system we ship: the client owns the repo, the CRM and the data, and the agents run on their cloud.

Frequently asked questions

Why not put every sourced lead in the CRM?

Because the CRM stops being readable. A CRM holding thousands of scraped prospects cannot be read every morning by one founder. The ledger holds the pool; the CRM holds conversations.

Why Attio and not a custom CRM in Supabase?

Views, tasks, Gmail and calendar sync, mobile, and a second seat for an SDR already exist in Attio. Rebuilding them for one team is not the product. The custom part is the agents around it.

Where does the LLM actually run?

Three places, all narrow: the competitor call on website visitors and LinkedIn signals, the 90-word meeting brief, and the Slack command agent. Reply classification uses the sending tool's own score plus regex.

How long did it take?

One weekend for the hub, the CRM migration and the ledger, with eleven tests and every auth path proven to fail on a wrong secret. The LinkedIn signals engine existed before and was wired in.

If you want this built on your own stack and handed over, book a call. You get the repo, the CRM and the data.

About Dima Bilous

Founder of Anfloy, an embedded AI engineering team. Designs, builds, and operates AI for agencies, tech companies, info businesses, and service teams, from simple automation to agentic systems to complex AI products, all shipped into your repo and owned by you forever. Forward-deployed AI engineering, not an agency.

[ 099 ]The next move

Let's build
what your
company needs.

Drop your email. We'll send The Custom Agent Blueprint on what we'd build first for a company like yours, before you ever take a meeting.

↳ Or skip ahead · book a call