An open-source AI Operating System should keep a sales agent's queue small
Every demo of an AI sales agent sells you the reply. It lands in seconds, in a voice close to your team's, and the only decision left is whether to press send
Every demo of an AI sales agent sells you the reply. It lands in seconds, in a voice close to your team's, and the only decision left is whether to press send. A reply is worth one conversation. The record the agent writes on the way past is what the team still reads in March. Kortix is open source, and it is where that agent runs.
A sales team gets its value from that record, because it is what the next rep and the next tool read when they decide who to call. The follow-up we run on Kortix treats the write as the output: research onto the lead record, a draft ready to send, and a short queue of decisions for a person in the morning.
The write outlives the reply
A wrong write costs you the pipeline behind it. Move a stage to Qualified and the forecast and the commission conversation change with it. Set a score from a note that misread the company and the account lands in the wrong sequence. Create a task against the wrong owner and the follow-up never happens, while the dashboard shows the task exists.
The write is the thing to design, because it outlives the session and often the person who would have typed it. Research that reaches the record is usable by everyone who opens the lead afterwards; research that stays in a chat transcript dies with it.
A sweep every 15 minutes, a person at the end
Every 15 minutes a scheduled trigger sweeps our HubSpot pipeline for new leads, and each firing spawns a fresh session in its own sandbox, with scoped access to the record, the web, our email and the calendar (the full flow). One isolated sandbox per session, so nothing from this morning's sweep sits in the one handling this afternoon's.
The agent researches the company, writes a research note onto the record, drafts the follow-up against our playbook, and proposes a call slot from real availability. Then it stops and waits for a person. A sweep that turns up five leads runs as one session with five independent units inside it, so a research failure on one never touches the other four. Sessions keep no state between sweeps. The note on the HubSpot record is the memory.
The policy fits in one file
kortix_version: 2
default_agent: sales-follow-up
connectors:
- slug: hubspot
name: HubSpot
provider: composio
app: hubspot
policies:
- match: "get_*"
action: always_run
- match: "search_*"
action: always_run
- match: "write_*"
action: require_approval
- match: "update_*"
action: require_approval
- match: "delete_*"
action: block
- slug: gmail
name: Gmail
provider: composio
app: gmail
policies:
- match: "draft_*"
action: always_run
- match: "get_*"
action: always_run
- match: "send_*"
action: require_approval
- slug: google_calendar
name: Google Calendar
provider: composio
app: googlecalendar
policies:
- match: "list_*"
action: always_run
- match: "get_*"
action: always_run
- match: "create_*"
action: require_approval
policy:
default_mode: risk
policies:
- match: "gmail.send_email"
action: always_run
conditions:
- arg: to
match: "*@your-company.example"
- match: "*.send_*"
action: require_approval
- match: "*.delete_*"
action: block
agents:
sales-follow-up:
file: agents/sales-follow-up.md
connectors: [hubspot, gmail, google_calendar]
secrets: none
skills: [sales-follow-up-playbook]
kortix_permissions: none
The sales-follow-up agent is granted all three connectors, and the HubSpot connector runs get_* and search_*, holds write_* and update_*, and blocks delete_*, so the agent cannot delete a record. Gmail runs draft_* and get_* and holds send_*; calendar reads run and create_* waits. default_mode: risk catches whatever those rules miss: reads run, writes and destructive calls wait.
Project-wide rules run before connector rules, and the first match in that list wins, so the exception sits at the top. gmail.send_email to your own domain runs; every other send falls to *.send_* and waits. List the wildcard first and the exception never fires. That conditioned rule is what keeps the queue short: internal notice moves without a decision, and anything a customer reads gets a person.
Approval gates you set. Off until you set them. Here the file sets them, in the same repository as the agent's persona and skills, so a change the agent proposes arrives as a diff somebody reviews. A project manager can change a connector rule in the dashboard too, and that applies at once. Every action is recorded. Reading, exporting and streaming the audit log depend on the plan. How the three actions resolve, and where the credential sits, is in how to give an agent tool access without handing over a key.
Four calls on one lead
Northwind fills in the form on Tuesday morning. The next sweep picks it up and makes four calls on that lead.
Reading the HubSpot record runs. It is a get_*, and nothing leaves the building. Writing the research note back is a write_*, so it is held. The follow-up goes to the lead rather than your own domain, so the conditioned rule does not match it and *.send_* holds it. The calendar slot for the account owner is a create_* on the calendar connector, so it waits too. A held call returns 202 with status: pending_approval and an approval_url, and that page shows the redacted arguments the provider will receive (connectors). Nothing ran. An approval covers that exact request, so changing the recipient on a draft needs a second decision.
A queue nobody works gets switched off
Ask on every call and the queue stops being a queue. One sweep of five leads makes a dozen decisions before lunch, most about a note nobody would read anyway. A person approves the first three carefully, then clicks through the rest like a cookie banner. By the end of the month the gate is off, or default_mode is back to allow_all, and the pipeline is worse for looking supervised.
Two rules keep the queue small. Reads run, which default_mode: risk already gives you, so research costs nobody a decision. And each lead contributes one write worth a person's attention: the send. This manifest holds every write, so one lead can arrive as three rows. The first change worth making is to let the research note and the proposed slot run, and leave the send where it is, because a person can correct a note later and the email is what a customer reads.
That tuning has a limit: there is no session-wide approval, so the note write needs an Allow rule of its own or it returns to the queue every time.
What a person does in the morning
The queue is worked in Review, or from the card in Slack or Teams. A project manager or the person who started the session decides a held call. Anyone else who opens it sees the request and who can resolve it, without the buttons.
Approve and the call runs exactly as shown, then the session resumes. An identical call that repeats within 15 minutes runs once, so a resumed turn does not send a second email. Deny and the session continues without it, with an optional message back to the agent.
The denial is the useful one, because it is the only training signal the playbook gets. A message saying the draft led with pricing on a company that has not seen the product is worth more than a hundred approvals, provided it lands in the skill that writes the follow-ups, or the memory the next session loads. A denial that says no and nothing else teaches the next sweep nothing, and the same draft comes back tomorrow.
Ignore a call and it expires. Twenty-four hours by default, or the expiry the project sets, and the session does not resume. The agent asks again with a new call, which makes an unworked queue a slower version of sending.
Where this stops
The sweep sees new leads. The records already in your pipeline when the trigger went live are a separate job, and an agent on that backlog is a decision about data quality, not follow-up speed.
Some accounts should never open with an agent. An enterprise deal that arrives through a warm intro, or a customer's expansion, is a relationship before it is a lead. The agent can research those. It should not write first.
And a team that wants outbound run for it, with no configuration to own and no queue to work, should buy a managed AI SDR. That product is priced for the outcome; a person who never wanted policy files should not be handed one. Kortix runs the agent; the queue is the work the team keeps. Free is $0 with 500 credits per month, on your own provider keys or your ChatGPT subscription. Credits start at $50 a month. Enterprise is custom, with SAML SSO and SCIM, audit logs, and cloud, VPC or on-prem deployment (pricing, checked October 2026).
Time one morning of the queue on your own leads. Ask for that queue in the next demo, and ask what the agent writes back.
If you want the failure modes behind the gate, how to build reliable AI agent workflows covers them.
More from the blog
An installed skill is a dependency. Open source is how you pin it.
A skill copied from another repository is a dependency nobody versioned. Open-source Kortix pins each skill to a hash and a grant in a repo you own.
An AI agent for HR has to read the policy library your team wrote
HR agents in the big suites answer from their own product's data, while an open-source agent reads your policy library and drafts the reply.