How we built Ari

Mav

Founder Salesfinity

Ari is the AI employee that ships with Salesfinity. It builds target lists, runs email and LinkedIn sequences under a rep's name, logs calls and notes to the CRM, and asks before it sends, spends or deletes. It lives in Slack and in the app, and a manager can read its work log like a timesheet.

The model is the least interesting part of that sentence. Everyone has access to the same frontier models. What decides whether an AI employee is trusted with real work is everything around the model: how it keeps a plan over a long task, where it keeps its work, what "the account" means, how it finds a phone number without guessing, and how a rep says yes from their phone. This post is about those decisions, at whiteboard level.

1. The problems an AI employee has to solve

Any team that has tried to hand real go-to-market work to an AI agent runs into the same six problems. We designed Ari around them, so it is worth naming them first.

  • Long jobs drift. A chat assistant answers a question and stops. An employee works for hours: build a list, enrich it, check it, sequence it, follow up next week. Somewhere in that loop, an agent without structure repeats itself, loses the thread, or quietly declares victory.

  • A context window is not a memory. The 400-row table an agent just built is expensive to keep in its head, gets summarised away, and cannot be shared with a second agent doing a related job.

  • "The account" does not exist as one thing. The CRM has one version of a person, the dialer another, the sequencer a third, and every data provider a fourth. An employee cannot take responsibility for an account that lives in five places.

  • Data providers disagree, and some of them guess. Ask for a VP of Sales in San Francisco and one source returns exact matches, another returns "close enough," and a third returns Texas. A rep who calls the wrong number once stops trusting the list.

  • Anything that can send an email needs a manager. Outbound under a rep's name, spending on paid data, deleting rows: these are decisions, not actions. Someone has to be asked, and someone has to be able to see what happened afterwards.

  • Costs have to be legible. Model tokens and paid data calls are billed in different units by different vendors. A team cannot hand an employee a budget it cannot read.

The rest of this post is the architecture that answers each one.

2. A runtime built for long jobs

Ari runs on what we call the GTM harness: a coordinator that owns a plan and dispatches typed subagents, each with a narrow tool set, on top of a small set of principles. The behaviours that matter are mechanisms in the runtime, not instructions in a prompt.


Figure 1

Figure 1. The five layers. The harness is the only layer that talks to the model. Everything below it is deterministic, testable and shared by every surface, so a routine at 6 AM and a rep typing in Slack run the same code.

  • Plans are data. Ari writes its plan as a checklist the rep can see and edit. A step that keeps repeating without new information is a signal, and the runtime steps in.

  • Questions block. When Ari needs a decision it stops at that point in the job. Nothing else in that step proceeds on a guess.

  • Writes have classes. Every tool declares what kind of action it is: read, write to CRM, send, spend, delete. Classes map to a team policy: allow, ask, or never.

  • Money is a gate. A single ledger meters model usage and paid data in one currency. Before a large paid step, the cost gate can pause and ask.

  • Progress is measured. A long loop only continues while it is producing something new. No new rows, no new facts: it stops and says why.

  • Runs are recorded. Every job leaves a trace. A library of recorded jobs is replayed on every change to the system, so a regression is caught before a customer sees it.


Figure 2

Figure 2. The loop every long job runs. A round only repeats if the grader saw progress and the budget allows it. Approvals and the cost gate sit on the "act" edge and can stop the run mid-step.

The grader has three outcomes, not two. When a row clearly fails a constraint, it is dropped. When it clearly passes, it is kept. When the evidence cannot say either way, the grader abstains: the row is kept and flagged for a human. That third outcome is what stops an agent from deleting a good list because it could not verify one field.

3. Files, not context windows

Ari works in a virtual filesystem rather than in its own context. The tools are the ones an engineer would expect (list, read, search, query, write), and the folders are the ones a sales rep would recognise:

/workspace/tables/<table>      the lists Ari is building (rows, grades, provenance)
/scratch/                       notes for this job
/results/                       what gets handed back
/memory/                        team and account memory, versioned
/accounts/<domain>/            the account file: people, calls, threads, signals
/contacts/<id>

/workspace/tables/<table>      the lists Ari is building (rows, grades, provenance)
/scratch/                       notes for this job
/results/                       what gets handed back
/memory/                        team and account memory, versioned
/accounts/<domain>/            the account file: people, calls, threads, signals
/contacts/<id>

/workspace/tables/<table>      the lists Ari is building (rows, grades, provenance)
/scratch/                       notes for this job
/results/                       what gets handed back
/memory/                        team and account memory, versioned
/accounts/<domain>/            the account file: people, calls, threads, signals
/contacts/<id>

Small, hot data lives in the primary database. Questions ("how many of these are in California", "which accounts went quiet this month") go to a columnar warehouse fed continuously from the primary store, exposed through views that are filtered to the team before any query runs. A query can never cross a customer boundary regardless of what the model writes.

Because every subagent sees the same files, a follow-up question is a one-line query instead of a rebuilt list, and a computation the tools do not cover can run as code against the same files, under the same guard.

4. One record for the account

Two records are canonical in Salesfinity: Contact and Company, where Company is the account. Calls, email threads, sequence steps and enrichment results all reference them rather than carrying their own copies. Three mechanisms keep those records trustworthy when Ari, the reps, the CRM and the data providers all write to them:


Figure 3

Figure 3. Every writer, Ari and the reps included, goes through one change log. CRM sync reads that log to decide what to push, and per-field ownership rules decide who wins when both sides changed.

  • One change log. Every write to a canonical record, from any source, lands in an append-only log with the source and the field. CRM push is driven by that log, so a burst of edits becomes one clean update rather than five.

  • Ownership per field, not per record. For each field and each direction, the team chooses: fill blanks only, newest wins, or human edits always win. A rep's correction is never overwritten by a sync.

  • Engagement is a rollup. Calls, threads and sequence steps roll up onto the contact and the account, so "last touched" and "who is working this" are fields Ari reads, not queries it has to invent.

The account file in the filesystem is a projection of all of this: one folder per account with the people, the calls, the threads and the signals. When a rep asks Ari to read up on an account before a call, that folder is what it opens.

5. Finding the right person, honestly

Finding the right person and a working number means talking to many data providers, and they are all different. Some take structured filters and return exact matches. Some are semantic search and return plausible ones. Some are excellent at mobiles, some at titles, some at technologies in use. Ari does not treat them as a list of vendors; it treats them as a set of capabilities.


Figure 4

Figure 4. Requests with exact criteria go to providers that can honour them. The semantic provider is a backstop, not a default. Every row passes a provider-agnostic gate before Ari is allowed to show it.

  • Route on capability. Each provider declares, per kind of constraint (title, location, seniority, headcount, technology), whether it is exact, fuzzy, or not applicable. A request with an exact city goes to providers that filter on city. A request only a semantic engine can answer goes there, and the result is labelled as such.

  • Gate everything. After merging, every row passes a gate that is independent of where it came from. A row that is confirmed wrong (asked for San Francisco, got Texas) is dropped. A row that cannot be verified is kept and flagged. Nothing passes silently.

  • Pay for results, not attempts. The search for a phone number stops at the first provider that returns a valid one, and the team is charged only then.

6. A seat, a manager, and a timesheet

An employee needs a place to sit. Ari's is Slack, as its own app, alongside the in-app chat: one identity in team channels and a private colleague in each rep's direct messages. Three design decisions carry the trust.

Approval by default. Every tool that sends, spends, writes to the CRM or deletes belongs to an action class, and the team's policy decides per class whether Ari asks, proceeds, or is forbidden. The default for everything outbound is ask. The ask is a message with buttons, in the thread where the work happened, so a rep can approve from a phone before breakfast. Approving with edits opens the draft.


Figure 5

Figure 5. Action classes and their defaults. The last row is a product decision, not a safety fallback: everything a prospect reads goes out as the rep, or not at all.

The work log is a first-class object. Every job writes what Ari did, what it asked, and what was approved, per rep, per day. Managers read it the way they would read a timesheet. It is what makes "asks before it acts" something you can audit rather than something we assert.

Responsibilities, not just requests. Beyond answering, Ari can hold a standing responsibility: watch a channel, run a routine each morning, react when a meeting is booked. Each one runs behind an inexpensive pre-check, so ambient monitoring does not cost a model call per message.

7. Money you can read

An employee that can spend money needs a ledger. Ours meters everything, model usage and paid data alike, into one team pool at a single rate. Two details make it fair: rounding happens once per action rather than per step, so a multi-step job is not overcharged, and large actions place a hold rather than a charge, so a retried job can never bill twice. Reps never see tokens. They see hours of work done.

8. What this means for a rep

  • A list that arrives graded, with the rows Ari could not verify flagged instead of hidden.

  • Sequences that go out under the rep's name and reschedule themselves when a call changes the plan.

  • A CRM that is filled in without anyone opening it.

  • An approval on the phone instead of a task in a queue.

  • A manager who can read exactly what the employee did this week.


The model was never the hard part. Giving it a filesystem, a ledger, a change log, a gate and a manager was.

On this page

No headings found on page

Learn how top performing teams build sales pipeline.