Operator Dossier · Engine Log

DHURANDHAR

“Dhurandhar” — one who bears the burden; an expert, relied on to carry the operation through. This is the field log — the real campaign that proved the engine out, what it's built from, and where it plugs into the rest of the stack.

SCOPE: one real campaign, standing up email_only outreach STATUS: armed, review-gated
🔒 Operator access

This page is gated

Field log for the engine's first real campaign, its architecture, and integration roadmap. If you're meant to have this, you already have the passphrase.

How the engine actually got exercised for the first time, what it's built from underneath, and the open questions in folding it into Pitch and Volt AI.

01

The campaign that proved it out

Everything on this page is grounded in one real run: standing up an email-only outreach campaign for a set of manually-sourced leads, end to end, on this engine.

Two fields on the campaign that don't exist in the upstream project were added specifically for this: email_only, which is checked first, unconditionally, in every LinkedIn-touching scheduler function — verified to return early even with no session at all, before any LinkedIn code path can run — and direct_pitch, which swaps out the default discovery-question opener style for a direct, outcome-first one.

Leads didn't come from LinkedIn discover; email_only blocks that path by design. They came from public pages and a research list already compiled by hand, each resolved to an email at one of three honestly-labelled confidence tiers: verified (a published institutional address, sent straight to the ready-to-email state), pattern-guessed (a confirmed company email format applied to a specific person — stored, but deliberately held back from sending unverified), and not found — recorded as a dead end rather than papered over.

what the review gate actually caught

Before any of the drafted openers reached a real inbox, each was previewed — composed, not sent. The local model invented a client relationship that doesn't exist, naming a real company that is in fact a named competitor in this project's own proposal, not a client. A second draft claimed no upfront cost against a proposal with a real setup fee. Every one of 4 test drafts had a fabrication, an overclaim, or a formatting break. All send-ready emails in this campaign were hand-written afterward and checked line by line against the source material instead — which is the concrete argument for keeping first-send review on by default, not a hypothetical one.

Arming a campaign is one line, scoped to that campaign only — LinkedIn connect stays off globally either way:

campaign.coordination_enabled = True
campaign.save(update_fields=["coordination_enabled"])

Every draft this produces still needs its own opener_reviewed flag set by a human before the send queue will pick it up — the same hand-check the incident above already argues for, just made structural instead of optional.

02

Architecture

Five apps, each owning one slice of the funnel. The LinkedIn app is fully wired and live-capable in this codebase — it's the email_only flag that keeps it dormant for an email-only campaign, not an absence of code.

core

Campaign config, the task scheduler, the daemon loop, prompt templates, the LLM agent layer.

crm

The funnel's data model — who a lead is, what state their deal is in, and why.

emails

SMTP send, IMAP reply-read, mailbox provisioning, email-finder integration.

linkedin

Browser session, People Search, connect/check_pending — live-capable, blocked per-campaign by email_only.

chat

The per-deal message thread — what the follow-up agent reads to decide what happens next.

FlagScopeWhat it does
coordination_enabledper-campaignMaster switch — off means fully dormant, on runs discover/email/follow-up for that campaign only
LINKEDIN_CONNECT_ENABLEDglobalConnect/check_pending only ever plan when this is true, for every armed campaign — meant to stay off
email_onlyper-campaignHard-blocks discover/connect regardless of the global flag
direct_pitchper-campaignSwaps the default discovery-question opener for a direct, outcome-first one
03

Process flow

The deal's state machine — and the one branch that stays permanently closed for an email-only campaign.

QUALIFIED email_only blocks READY_TO_CONNECT email resolved READY_TO_EMAIL send EMAILED IMAP reply, agent decides COMPLETED FAILED
Every deal in an email-only campaign travels the lower path only. The dashed branch to READY_TO_CONNECT is real, reachable code in this same codebase for other campaigns — email_only is what keeps it permanently unreachable here, checked before any session or LinkedIn code ever runs.
LinkedIn discover (blocked) Manual seed (CSV / web) QUALIFY verified (institutional) pattern-guessed not found — dead end DRAFT HUMAN REVIEW — every draft gated by coordination_enabled SEND (SMTP via Mailbox) REPLY (IMAP + agent) follow-up loop
The human-review gate isn't part of the shipped pipeline code — it's the operating discipline the incident in Part 01 argues for directly: reviewing real drafts caught a fabricated claim, an incorrect fee claim, and a formatting break that the campaign brief alone didn't prevent.

In words: a lead is sourced → qualified → an email is resolved across the three confidence tiers above → a draft is composed → held for review → sent, gated by the campaign's activate switch → and any reply is read over IMAP and fed back to the follow-up agent, which keeps the thread moving or marks it done.

04

Folding into Pitch

Pitch's existing shape: an import, then Pitch Studio's research and prep, ahead of a human working The Floor. The question is where a qualify → email-find → draft → send engine like this one actually hooks in.

Excel / CSV import Pitch Studio research, brief, prep The Floor (human) new fork — same import, parallel lane qualify → email-find → draft → review → send → reply-track Inbox
One insertion point: the same imported list forks after import into Pitch Studio, unchanged, and this engine, new. Neither lane blocks the other — a lead can get a research brief for a human call and an automated, outcome-framed opener, independently.

Pitch is Electron + Next.js + TypeScript. This engine is Django + Python. That mismatch is the real decision, not a detail — three ways to bridge it:

Option A

Separate backend, Pitch calls it

  • The engine keeps running as its own service; Pitch calls a small internal API after import
  • No rewrite — the qualifier, mailbox pacing, and reply loop keep working as-is
Tradeoff: two runtimes to keep running on the operator's machine.
Option Bclosest fit

Port the pipeline logic into Pitch's own stack

  • Re-implement qualify/find/draft/send/reply-read inside Pitch's existing process
  • One runtime; the state machine and both safety flags port directly, losing nothing conceptually
Tradeoff: real rewrite effort for the qualifier specifically.
Option C

Keep them separate, sync via export

  • Pitch exports its list; the engine imports it as a seed — exactly how the campaign above was seeded
  • Zero integration work, good first step to validate demand
Tradeoff: no state syncs back — Pitch never learns a lead replied unless someone re-imports.

Is the human-review gate a permanent feature, or a today-only workaround?

Today's answer is forced by the local model's reliability, per the Part 01 incident. A stronger model narrows what needs review; it doesn't obviously remove the gate for claims tied to a real commercial proposal.

05

Folding into Volt AI

Volt AI is a different shape of product — a desktop AI coworker with a knowledge graph, a built-in email client, background agents, and self-updating notes. It already has a working pattern for exactly this kind of integration.

Background agents

Run on events or a schedule; connect to tools, browse, write code.

Live Notes

A note that keeps itself current against an objective plus a trigger.

Brain

A knowledge graph indexing email, meetings, and conversations.

Email client

Sorts and auto-drafts replies using work context — a native surface.

The groundwork already exists: existing tool domains in that codebase each export typed, agent-callable tools with a per-tool review-permission gate. A new domain for this engine, in the same shape, is the idiomatic way in — not a new integration mechanism.

Background agent generic tool-name recall rejected — hallucinated in testing Agent or Live Note typed tool domain same shape as existing domains dhurandhar (local) API or CLI call chosen — proven shape, no new mechanism
Not a hypothetical choice — that codebase's own comments name the reason generic tool-name recall was dropped: a smaller model hallucinated the wrong tool name in live testing, the same class of failure the Part 01 incident hit independently.

Every existing tool domain there calls a hosted backend over HTTPS. This engine isn't that yet — it's a local app with a local database, not a running network service. A new domain needs either a small local HTTP surface bound to localhost, or a direct process call reusing the same inline commands already used to inspect and seed a campaign.

A concrete Live Note, pointed at a campaign instead of a clock:

---
live:
  objective: |
    Track the outreach campaign: how many deals are
    Ready to Email, how many Emailed, and summarize any new
    replies since the last check. Flag anything the send-tool
    left waiting on review.
  active: true
  triggers:
    cronExpr: "0 8 * * *"   # every morning at 8am
---
# Campaign status

Should the send tool default to holding for review?

Given the Part 01 incident, yes by default — the same human-review discipline, enforced natively in the host's own tool-permission system instead of as a separate manual step.

Does the outreach mailbox become that product's own email surface, or stay separate?

Open. Merging them gives one inbox and one thread history; keeping them separate keeps this engine's pacing and review gate simpler to reason about in isolation.