Run the loop, with a hand on every outward step. The operate stage of the Founder-to-Builder loop. It reads an activation readout, decides the next motion, and writes the morning report, on a schedule. It acts on its own only to measure and draft. Every outward step (a founder email, a dollar of spend, a GTM handoff) waits for your approval, or is refused by design.
An operator that runs your company while you sleep is easy to demo and hard to trust: the failure mode is expensive noise, sent in your name, while you sleep. This repo is the accountable version. It does the overnight work that is safe to automate (re-score the cohort, name the leak, draft the update) and stops at the line where judgment and your name are on the hook. That boundary is not a promise in a README. It is a check the build runs.
- Problem it solves: autonomy without accountability. The plan is explainable, every outward action is gated, and a CI check proves nothing outward-facing ran unattended.
- Run in under 5 minutes:
python -m operator_loop examples/readout.json- stdlib only, no dependencies. - Production lesson it encodes: the morning report is the product, the one honest pass over what moved overnight that a growth operator actually runs on. A founder who reads one honest update a day stays in the loop. A black box loses them the first time it ships noise.
This is the capstone of the founder-to-builder demo set, and it sits one stage downstream of claude-activation-loop: that repo measures the funnel, this one operates on what it measured. claude-startup-linter diagnoses the company, claude-prompt-to-production builds the product, claude-pitch-deck-linter builds the raise, claude-agent-linter hardens the agent, claude-activation-loop measures the activation. This repo runs the loop.
git clone https://github.com/cfregly/claude-operator-loop && cd claude-operator-loop
python -m operator_loop examples/readout.json # the morning report
python -m operator_loop examples/readout.json --weekly # the weekly report
python -m operator_loop examples/readout.json --json # the full gated plan
python -m operator_loop examples/readout.json --audit-gates # CI: prove no outward action auto-ran
python tests/test_plan.py # the test suiteIn production the input is a live readout from the measure stage:
python -m activation_loop cohort.json --json > readout.json # claude-activation-loop
python -m operator_loop readout.jsonThe input is an activation readout: the funnel state, the biggest leak, time-to-second-build, and the accounts ready for a handoff. The operator turns that state into three lists, sorted by how much trust each action needs:
- did: what ran overnight on its own. Measurement and drafting only (re-score the cohort, flag the leak, draft the report). Never outward-facing.
- proposed: what waits for you. Each outward motion the state calls for, with the metric it moves. Approve to run.
- will not: what the operator refuses to do on a schedule, by design: send mail in your name, spend, post in public, grant credits, or hand off an account that has not earned it.
Every action carries a gate: always (safe, internal), ask (outward, waits), or never (refused). Only always actions land in did, and the audit proves it.
The map from funnel state to the next motion is deterministic, so the same readout gives the same plan every run:
- Leak at the first build, propose a build clinic. Moves the activation rate.
- Leak at the second build, or a leaky bucket, propose the 72-hour second-build nudge. Moves time-to-second-build.
- An engagement leak, builders who do not return weekly, propose the week-2 re-engagement prompt. Moves engagement retention.
- Accounts in production with rising spend and no handoff, propose a GTM handoff to a named owner. Moves qualified PQA handoffs.
- A healthy loop, propose nothing, and say so.
python -m operator_loop examples/readout.json on the bundled sample cohort:
operator-loop morning report: Q3 SF founder day (sample, fictional)
State
activation rate ......... 67%
retention (2nd build) ... 62%
time-to-second-build .... 9 days
biggest leak ............ first_build -> second_build (38% lost)
PQAs ready .............. 2
Ran on its own (measurement and drafting only, no approval needed)
- Re-score the cohort and recompute the funnel.
- Flag the biggest leak: first_build -> second_build (38% lost).
- Draft this report.
Waiting on you (approve to run)
- [second_build_nudge] Send the 72-hour second-build nudge to 3 account(s). Moves: time-to-second-build.
- [pqa_handoff] Hand 2 product-qualified account(s) to a named GTM owner: acct_02, acct_03. Moves: qualified PQA handoffs.
Will not do on its own (by design)
- Send founder emails without your review.
- Spend on ads or any paid channel.
- Post to public or social channels.
- Promise or grant credits.
- Hand off an account that has not met the production-and-rising-spend trigger.
Reply approve <id> or skip <id> for each item above.
The morning report is the daily cadence. The weekly report is the same gated loop on a 7-day cadence, with optional week-over-week deltas:
python -m operator_loop examples/readout.json --weekly # this week
python -m operator_loop examples/readout.json --weekly --prev last_week.json # with deltasWith --prev (last week's readout), the State block annotates the move on each metric, so a weekly skim shows direction, not just level:
operator-loop weekly report: Q3 SF founder day (sample, fictional)
State
activation rate ......... 67% (+5 pts vs last week)
retention (2nd build) ... 62% (+2 pts vs last week)
time-to-second-build .... 9 days (-1 day vs last week)
biggest leak ............ first_build -> second_build (38% lost)
PQAs ready .............. 2 (+1 vs last week)
The Did, Waiting, and Will-not sections are identical to the morning report. The cadence differs, the gate model does not.
The report names each outward motion. With --draft, Claude writes the message that motion needs, grounded in the same funnel state, so every proposed action arrives with a founder-ready draft. The gate does not move. A draft rides on a proposed action that still waits for your approval, and the audit still proves nothing outward-facing ran on its own. Determinism stays on the gate, and the model only writes the copy a person reads before sending. When the deslop linter is on hand, each draft is graded against the brand bar and the grade rides with the message, so a draft that misses the bar is flagged before you approve it.
This is the CASH pattern in the small. Claude drafts the growth copy, the deslop linter grades it against the brand bar, and the human-gated loop approves it.
pip install anthropic # optional dependency
export ANTHROPIC_API_KEY=sk-ant-... # or put it in .env
python -m operator_loop examples/readout.json --draftThe drafted message renders under the action it belongs to. One run produces something like:
Waiting on you (approve to run)
- [second_build_nudge] Send the 72-hour second-build nudge to 3 account(s). Moves: time-to-second-build.
draft subject: 72-hour nudge to 3 accounts on second build
We lose 38% of accounts between the first and second build, and the second build is the real activation signal. Send the 72-hour nudge to the 3 accounts that built once and stopped. This shortens time-to-second-build and keeps them from dropping off.
brand bar: A (100/100)
The model is claude-opus-4-8, and the draft comes back as structured output through a forced tool call, so the result is reliable JSON rather than text the CLI has to parse. The Agent SDK is the right surface when a task needs its own multi-step loop. Drafting one message from a state you already have is a single call, so this uses the Messages API. With no key or no SDK, --draft prints a one-line note and falls back to the deterministic motions, so the demo still runs offline. The brand bar is the sibling deslop linter: install it to grade the drafts, or leave it out and the drafts still render, just ungraded.
python -m operator_loop readout.json --audit-gates || exit 1The audit fails the build if anything outward-facing ever ran without approval. It is the operator's own eval: the same evals-before-vibes discipline claude-agent-linter puts on a tool's behavior, turned on the operator's autonomy. The approval boundary is a test, not a footnote.
Packaged as a Claude Skill in skills/operator-loop/SKILL.md. Install it as a Claude Code plugin with /plugin marketplace add cfregly/claude-operator-loop then /plugin install operator-loop@operator-loop-plugins, or upload the skills/operator-loop/ folder in the Claude app under Settings > Skills (see Anthropic's skills guide). Then say "run my operator loop" or "what should I do about my activation funnel this morning." Claude reads the readout, writes the morning report, and lists what is waiting on your approval. To run it unattended, wire the skill to a scheduled agent: the gate ledger keeps the schedule honest.
The plan is only as honest as the readout you feed it: it operates the loop you measured, and inherits whatever that measurement missed. It proposes outward motions. It does not write the email or place the spend, on purpose. The gates are a default boundary to argue with, not a law, but the audit makes any change to that boundary visible in the diff. This is an accountable operator, not an autopilot, and the difference is the whole point.
Once the operator loop shows production accounts with rising spend, the founder has outgrown credits-as-a-demo. Point them at Claude for Startups: acceptance grants the highest API rate limits and first-party API credits so they can scale without throttling. If they are backed by a partner VC or accelerator, the Anthology Fund track adds an investment alongside the credits, and Claude Founder House is the in-person programming. This loop never grants credits itself, that is the gated human call. It points the founder to the program that does.
MIT. The example readout is the fictional sample cohort from claude-activation-loop, scored by that tool.