← Back to tools

Open source · MIT

View on GitHub ↗

Outbound Campaign Crew — claim-traceable cold email sequences in CrewAI

CrewAI planner→copywriter→critic crew that turns an Account Research Agent brief into a 3-touch sequence where every factual claim is traceable, in code, to a line of research evidence — and refuses to write at all if the account scored out of ICP. The governance pattern from the LangGraph trilogy, ported to a second framework.

~$0.15

per 3-touch sequence

MIT

open source license

CrewAI Flows task guardrails Python Pydantic Anthropic

The problem

AI-written cold email is the most commoditized demo in GTM — and the least trusted. The failure mode is always the same: the model states things about the prospect that nothing in the research supports, repeats itself across touches, and nobody can audit which claim came from where. Teams that piloted agentic outbound describe the output the same way: noisy, and impossible to audit.

The fix isn’t a better prompt. It’s the same fix as everywhere else in this portfolio: the LLM never gets to decide whether the rules apply.

This repo is also a deliberate second-framework proof. The pre-outbound trilogy is LangGraph; this is CrewAI. If a governance pattern only works in one orchestration framework, it’s a framework habit, not an architecture. Porting it is the test.

What it does

One run takes an Account Research Agent summary.json and produces a 3-touch sequence (opener → bump → breakup) — or a refusal:

  1. Load — every piece of ARA evidence and every pitch hook gets an ID (E1..En, H1..Hn). These are the only facts the crew may state.
  2. Input gate (code, $0) — if the account scored below the ICP threshold, the Flow refuses before a single LLM call. The campaign crew does not write outbound to accounts the research layer disqualified.
  3. Planner allocates claims to touches — which claim earns the opener, what the bump adds that’s new, how the breakup closes. A guardrail rejects unknown IDs, claim reuse across touches, over-allocation.
  4. Copywriter writes the sequence citing claim_refs per email. A guardrail rejects refs outside the touch’s allocation, blown word budgets, banned phrases, stray merge fields.
  5. Critic judges what code can’t: faithfulness (a ref that resolves but is misrepresented), touch-job adherence (a bump that just rewords the opener), spam smell. A failing verdict triggers exactly one revision — the cap lives in Flow code, not in a prompt.
  6. Output gate (code) — independently re-verifies every ref before rendering. The output ships with the campaign plan table, per-email claim refs, the critic scorecard, and the full numbered source-claim list — its own audit trail.

Two live, unedited runs are checked into the repo: a full sequence for a strong-fit account and the gate refusing an out-of-ICP one.

Same pattern, different primitives

The design rule across all five repos in this stack: structural constraints are enforced by code; the model only gets autonomy inside them. What changes per framework is only where the code hooks in:

Governance mechanismLangGraph (trilogy)CrewAI (this tool)
Hard constraint on LLM outputclamp inside a nodeTask guardrail — validates, rejects, re-prompts
Routing on a deterministic conditionconditional edge@router in a Flow
Refuse bad input before spending tokensearly node short-circuitFlow input gate (no LLM call)
Critic-and-retry with a hard capcritic node + max_iterations in graph statecritic task + revision crew, cap in Flow code
Final integrity checkcompiler node re-validationFlow output gate — re-verifies independently of guardrails

Architectural decisions worth defending

1. The planner doesn’t generate angles — it allocates them. ARA’s pitch_hooks already are angles; a strategist agent rephrasing them would be theater. The planner’s real job is sequencing strategy: assign claim IDs to touches under code-enforced rules (each claim in at most one touch — which is what makes “the bump never repeats the opener” verifiable instead of aspirational).

2. Clamps between agents, not just at the output boundary. The plan-validation guardrail sits between agent 1 and agent 2 — a clamp placement none of the LangGraph repos has. The copywriter never sees an invalid plan.

3. The eval greps for governance violations, not copy charm. “Is this good cold email?” is unfalsifiable; a mushy LLM-judged quality score would be the first weak eval in the portfolio. Instead: 4 goldens, 10 deterministic checks — refusal behavior, ref resolution, cross-touch reuse, budgets, the revision cap — re-verified from disk artifacts, trusting neither the guardrails nor the crew. The refusal golden costs $0 and tests the system on what it declines to generate.

4. File contract in, not subprocess composition. Meeting Prep Agent already demonstrates live subprocess composition of siblings; repeating it here would buy nothing. OCC consumes ARA artifacts by file path — and composes with ARA at the policy level instead: the research layer’s verdict gates the outbound layer’s behavior.

5. CrewAI’s idioms, not LangGraph’s habits. Clamps are native task guardrails, deterministic structure is a native Flow, models route through CrewAI’s LLM provider layer. Rebuilding LangGraph in CrewAI syntax would prove the ability to fight a framework — the opposite of the point.

Watched by the discipline layer

OCC runs as eval-watch’s fourth sibling — the first non-LangGraph one — on the same monthly cron, regression gate, and public STATUS.md as the trilogy. The adapter contract (subprocess-runnable eval, non-zero exit on failure) turned out to be framework-agnostic by construction. Its drift dimension: revisions_used — a rising median means the copywriter is failing critique more often.

The stack

RepoAnswersFramework
Account Research AgentWho fitsLangGraph
Signal MonitorWhen to actLangGraph
Meeting Prep AgentWhat to sayLangGraph
Outbound Campaign Crew (this tool)What to sendCrewAI
eval-watchHow do you know they’re right?— (discipline layer)

Same thesis, seventh instance: disqualifier clamp (ARA) → length compliance (blog autopilot) → three clamps (SM) → concurrency clamp (SM runtime) → four clamps + sequential composition (MPA) → eval discipline in CI (eval-watch) → Flow gates + task guardrails, same rules in CrewAI primitives (here). Across surfaces — and now across frameworks.

Use it

MIT licensed. Bring an Anthropic API key and an ARA summary.json (or use the checked-in fixtures):

git clone https://github.com/aehirota/outbound-campaign-crew
cd outbound-campaign-crew
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env   # ANTHROPIC_API_KEY

python run.py evals/fixtures/brightlane.example.summary.json   # generate (~$0.15)
python run.py evals/fixtures/anthropic.com.summary.json        # watch the gate refuse ($0)
python evals/eval_runner.py --skip-llm                         # governance eval, free path

Sender identity, gate threshold, word budgets, and the banned-phrase list all live in config.yaml.

Let's talk

Let's build your revenue system

I'm available for GTM engineering and RevOps projects. Tell me where revenue is leaking and I'll tell you what I'd build.