Wednesday 9 / 09 / 2026

タイラーRetourner

Striker

Most "AI SDR" tools stop at the door: find leads, run a sequence, book a meeting, hand it to a human. That's the easy half.

The hard half starts after the meeting: follow-up, quotes, objections, and the seller who swore he'd call back on Tuesday. Striker is built for that half, because prospecting is just the door, not the product.

The layer

Take the funnel a sales manager already knows (prospecting through close) and put one layer on top:

  • who acts at each stage, agent or human
  • what happens when the human doesn't execute
  • meeting agreements, meeting quality, executive evaluation, sentiment

Strip that layer away and you've got a CRM. The product is the layer.

Three planes, one rule

The dashboard calls the server directly. No BFF in between.

server: Bun + Elysia + Better Auth. Multi-tenant HTTP, webhooks, orchestration, sends, jobs. It's the only thing that touches the database.

agents: Mastra. Drafts only: conversation, first touch, persona. No auth, no DB, no send. Imported in-process by default (it can run as its own process when a deployment needs it).

core: pure engines. Scoring, send gates, playbooks, pricing. No IO, so it's the part that's actually testable.

The rule: only the server writes to the database. It sounds simple until an inference framework asks for a repo and you say no, keeping the damage of a bad prompt down to a draft nobody sent.

The rest of the stack: Bun workspaces with Moon, not Turborepo or Nx. Postgres as truth, Redis for cache and queues, Drizzle for schema and repos, Zod contracts shared across the wire. The dashboard is a Vite SPA speaking Eden Treaty straight to the server, with no BFF to keep in sync with the backend.

The accent

The agent sells in Chile, so it speaks Chilean Spanish. The voice was fine until someone interrupted it: after an interruption it came back neutral, which mid-call sounds like a different person taking the phone.

How do you fix that? Not with a better prompt. Three places asked for that voice: the note, the audition and the call. We changed the sentence that sets the accent, but the same instruction also said which voice to use after an interruption, and that part still said neutral Spanish. So we were telling the voice to keep its accent, but drop it whenever someone cut in. Now that accent line lives in one place and all three read it from there. A profile sets what the voice speaks and what the transcriber expects, which also stopped a noisy Chilean "sí, dale" getting filed as Portuguese. Interruptions stopped changing who was talking.

Most of the interesting bugs look like that: not "the model is wrong", but two parts of the system given contradictory instructions.

Silence is a step

A campaign that keeps sending while the prospect is halfway through a reply is worse than one that never sends at all.

So waiting isn't a gap between steps. It's a step with its own state. An inbound email stops the clock, and a human task blocks the next move until someone closes it. The runtime keeps a ledger of turns, not a list of phrases to fire.

Tools work the same way: the agent binds eight named packs instead of loose flags, capped at twelve at a time. There's no master switch to turn them all on, on purpose, because an override switch would produce actions the ledger couldn't explain.

What I would keep

Contracts before prompts: every bug where the model seemed to behave weirdly turned out to be conflicting instructions across different parts of the system.

One writer to the database. Everything else drafts.

Domain rules stay pure, far away from anything that talks to an LLM.