moonlings

behind the scenes at moonlings.ai

What happens
after you go to bed

Moonlings is a marketing night shift for small businesses: a small crew of AI agents that researches your market while you sleep and leaves a short, honest report on the desk by morning. This page explains how — starting very simple, ending at the raw API calls.

How to read this page: each section goes one level deeper than the last. Stop whenever you’ve had enough — section 1 is for everyone, section 4 onward is for engineers.

01 · the short version

An employee who works while you sleep

No dashboards, no charts to interpret. You describe your business once; the night shift does the rest on a schedule.

Evening

You go home

Your standing task — most owners keep one, “the weekly rundown” — sits on the schedule for 3 AM Monday, in your timezone. Nothing for you to do.

Overnight

The crew works

Agents read everything they already know about your business, check your connected accounts, watch your competitors on the live web, and write it up.

Morning

A note on the desk

A two-minute report in your inbox: the bottom line, the 2–4 moves to make this week, the evidence, and a source for every fact.

☾ what a morning report looks like

Weekly rundown — Hartman’s Garage

Bottom line: Two competitors dropped brake-service prices this week; your Google listing is invisible for “brake repair near me.”

  • Do this: add “Brake Repair” as a service on your Google listing — you show for 0 of the 3 highest-intent searches.
  • Do this: reply to Tuesday’s 3-star review — a draft is included, edit and post.

…plus What I found and Sources. Every number links to where it came from.

02 · one level down

It's not one AI — it's a crew

Five distinct roles, each on the cheapest model that can do the job well. That division of labor is why a full overnight research run costs well under a dollar.

The Coordinator

Claude Sonnet 5

Your business's own dedicated agent — one per tenant, with your profile, your 90-day goal, and your town baked into its system prompt. It plans the night, delegates research, weighs the evidence, and writes the report.

judgment · synthesis · report-writing

provisioned once at onboarding, versioned forever

The Scouts

Claude Haiku 4.5

A shared research subagent the Coordinator fans out in parallel — one Scout per competitor, capped at five. They gather; the Coordinator judges. Roughly 80% of a competitor-watch run's tokens flow at Haiku prices.

parallel web research fan-out

shared across every tenant

The Dreamer

Claude Haiku 4.5

Once a night — only if something new happened — a consolidation agent re-reads memory, merges what the night's runs learned, prunes stale facts, and surfaces up to three insights for the owner.

nightly memory consolidation

skipped when idle: no work, no spend

The Grader

platform outcome eval

Every report is graded against a written rubric before it can ship — sourcing, location proof, honesty rules. A failing report goes back for revision, up to two cycles. Owners never see an ungraded draft.

rubric-driven quality gate

built into Claude's Managed Agents runtime

The Oracle

daytime · Messages API

The chat you talk to during the day. It answers only from what the crew already found — reports, memory, your documents — and it never acts on its own: anything with a side effect becomes a one-tap confirmation.

12+ read tools, propose→confirm for all writes

fresh research is teed up for the night shift

03 · follow one report through the night

One night, step by step

This is a real run of “the weekly rundown” — every step below maps to actual production code. Click through the night.

3:00 AM

The cron tick

A scheduler wakes up, sees “the weekly rundown” is due for your business tonight, and starts a run.

☾ one level deeper

A Vercel cron evaluates every saved task’s schedule in the business’s own timezone — 3 AM means 3 AM where the shop is.

Before anything spends a token, the run passes a quota gate: a row-locked atomic update on a usage counter reserves the report, so two simultaneous triggers can never double-spend a plan’s allowance. Denied means denied before cost — a rejected run costs exactly $0.

The run row is inserted first and the heavy provisioning happens after the HTTP response returns — owner-facing routes answer instantly. If the process dies mid-flight, an orphan sweep fails the run within 15 minutes rather than leaving it zombied.

1 / 8

← → arrow keys work too

04 · the machinery

The Managed Agents primitives

Moonlings runs on Claude’s Managed Agents platform: Anthropic hosts the agent loop, the sandbox, the memory, and the grading — we supply the judgment: prompts, rubrics, tools, and orchestration. Eight primitives carry the whole product.

4.1Agents

An agent is a server-side, versioned definition: model, system prompt, toolset, subagent roster. Each business gets its own Coordinator at onboarding; editing the profile updates the same agent in place, producing a new immutable version. Sessions reference the agent by bare id — string shorthand means “latest version” — so a profile edit takes effect on the next night’s run with no re-provisioning.

// one-time, at onboarding
const agent = await client.beta.agents.create({
name: `Moonlings — ${profile.name}`,
model: "claude-sonnet-5",
system: buildCoordinatorSystem(profile), // the business, baked in
tools: buildAgentTools([]), // base toolset + google_search (bash disabled)
multiagent: { type: "coordinator", agents: [SCOUT_AGENT_ID] },
});

One subtlety that bit us: model choice lives per version. Changing a model constant in code does nothing for existing tenants until every live agent is re-versioned — we keep a migration script for exactly that.

4.2Sessions

A session is one night’s disposable workspace: the agent runs inside a sandbox with a real filesystem and writes its deliverables to /mnt/session/outputs/. Sessions are cheap and per-run — the durable state lives in memory stores, never in the session. After harvest we archive the session; helpfully, its output files survive archival, so a missed attachment is always recoverable.

4.3Memory stores

Each business owns a persistent memory store, seeded at onboarding with profile.md and grown into six standing files: profile.md, learnings.md, competitors.md, leads.md, suppliers.md, patterns.md. The Coordinator’s first instruction on every task is memory first — build on what you know, then report what changed, which is what an owner actually cares about. Agents are told to correct stale facts in place: small, current files beat long archives.

The same mechanism, mounted read-only, carries the owner’s reference library — uploaded price lists, menus, policies. When the web disagrees with the owner’s documents, the documents win, and no agent can ever edit them.

4.4Vaults

Connected accounts (Google Business, Google Ads, Instagram/Facebook) authenticate through a per-tenant vault. OAuth tokens live there — not in our database, not in the model’s context. At session time we attach at most one vault id, resolved by a pure function that can only ever return the passed business’s own vault; cross-tenant leakage is structurally impossible, not just policy.

If a connected server rejects its credential mid-run, we detect the auth-failure event during collection and flip the connection to needs reauth — the run still completes on its snapshot data; the owner sees a reconnect banner, never a dead report.

4.5Multiagent rosters

The Coordinator’s definition declares multiagent with one shared Haiku Scout on the roster. At run time it spawns one Scout per independent target — competitor, lead, supplier — each in its own thread of the session, in parallel. Prompt discipline caps the fan-out (“never more than 5 Scouts — cost scales directly with Scout count”).

Threads are also how we price honestly: each thread reports its own model and usage, so a finished run is costed per thread at that model’s rates — Sonnet for the Coordinator’s judgment, Haiku for the Scouts’ volume — instead of a flat worst-case estimate.

4.6MCP toolsets

Connected-account tools arrive over MCP (Model Context Protocol) servers, but the agent never gets a server’s full surface. Every toolset defaults to everything off, then enables an explicit, hand-verified read-only allowlist — 18 tools for social analytics, similar for Google Business and Ads. Each allowed tool is marked always_allow because there’s no human awake at 3 AM to approve anything.

// per connection
{
type: "mcp_toolset",
mcp_server_name: "googlebusiness",
default_config: { enabled: false }, // deny by default
configs: readToolAllowlist.map((name) => ({
name, enabled: true,
permission_policy: { type: "always_allow" }, // unattended runs never stall
})),
}

The tools array on an agent update is a full replacement, so every sync re-emits the base toolset and web search — a connect or disconnect can never silently drop the agent’s core capabilities.

4.7Outcomes & rubrics

Task runs don’t get a chat message — they get a defined outcome: the kickoff plus a written rubric the platform grades the finished work against. Fail the grade, and the agent revises; we cap it at two cycles, because each extra cycle re-runs the whole Coordinator-plus-Scouts fan-out and the third pass was our single most expensive knob for marginal gain.

Collection trusts only terminal grader states (satisfied / max_iterations_reached / failed). A session reports idle transiently — including right after kickoff, before any work — so “idle means done” would harvest empty sessions mid-flight. That trap cost us a debugging night; the fix is encoded in the collector.

4.8Custom tools

Some tools we deliberately keep outside the sandbox. When the agent calls google_search, the session emits a tool-use event and waits; our collector executes the search host-side via Serper and posts the result back. The API key never enters the agent’s environment. Scout calls from subagent threads carry a thread id we echo back so the answer lands in the right thread.

// the agent asked; the host answers
await client.beta.sessions.events.send(sessionId, {
events: [{
type: "user.custom_tool_result",
custom_tool_use_id: use.id,
content: [{ type: "text", text: serperResults }],
session_thread_id: use.threadId, // route back to the Scout that asked
}],
});

05 · keep-me-honest

Why the report can be trusted

An AI that confidently tells a shop owner about the wrong town is worse than no AI at all. Location claims — the classic failure — pass through three independent defenses, and honesty rules are enforced, not requested.

LAYER 1

The prompt demands proof

There's a Batavia in New York, Ohio, and Illinois. Any business with a physical footprint gets a geo-grounding module in its Coordinator's prompt: nothing may be called “local” without a city-and-state match, every place must carry a verified ZIP from research time, and a place that can't be pinned to an in-state ZIP gets cut, not listed.

LAYER 2

The grader checks the work

The outcome rubric enforces the correctness floor on every single run — location or marketplace proof, plus a live source behind every price, rating, and date. A report that asserts what it didn't verify gets sent back before any human sees it.

LAYER 3

Deterministic code gets the last word

At harvest, plain non-AI code scans the finished report for ZIP codes and resolves each to a US state. An out-of-state ZIP in a “local” report flags it for review before the morning email. This check cannot be argued with, persuaded, or hallucinated past.

Sourced this run, or say so

A price, rating, or date may only be stated if it was retrieved from a source during this run — never carried forward from memory, never filled in from how things “usually” are. Can't confirm it? The report says “unconfirmed,” plainly.

## Sources — required on every report

The web is data, not instructions

Everything an agent reads — web pages, reviews, emails, ad captions — is treated as untrusted content to summarize, never commands to obey. Connected tools are read-only by construction: the crew cannot post, reply, change a budget, or spend a cent.

prompt-injection defense, held at the tool layer

A quiet week is a valid answer

Agents are explicitly told never to manufacture findings to fill space. “Nothing material changed since last week” is a complete, useful report — padding is treated as a defect.

brevity is a feature

Failure never loses work

If a run fails its grade or times out, whatever it wrote is still salvaged onto the failed record for review — and an empty run can never masquerade as a success. Broken reads as broken, and rerunnable.

fail loudly, salvage everything

06 · what a night costs

The economics of a night shift

The whole design answers one constraint: a small business pays tens of dollars a month, so every report has to cost cents — measured, not guessed.

~$0.57

inference · typical report

~$0.63

with live-tool drill-downs

2

max grade→revise cycles

≤5

scouts per fan-out, capped

Where a competitor-watch run’s tokens go

~80% Scouts · Haiku 4.5~20% Coordinator · Sonnet 5

Cost tracking prices each session thread at its own model’s rates — including the separately-billed prompt-cache token classes the platform reports. We learned that one the hard way: reading the wrong usage field priced cache writes at $0 while they were about half the real bill. Quotas are enforced before spend by a row-locked counter reservation — a denied run never costs anything.

07 · the rest of the workshop

Everything around the agents

The night shift is the heart; a deliberately boring stack keeps it running.

Claude Managed Agents

agents · sessions · memory · vaults · grading

Next.js + Vercel

App Router · cron ticks the night

Neon Postgres + Drizzle

runs, tasks, insights · row-locked usage metering

Clerk

auth + organizations for agency multi-tenancy

Stripe

subscriptions, trials, metered add-ons

Resend

morning reports out · owner replies flow back into memory

Serper

Google search + Places ground truth, host-side

Zernio

read-only social analytics over MCP · 18-tool allowlist

PostHog

product analytics · session replay · funnels

One detail worth noticing in Resend’s row: owners can reply to any report email in plain English — “actually, we stopped offering detailing last spring” — and the correction lands in the crew’s memory as an owner note that outranks anything on the web. The night shift you correct is the night shift that stops making that mistake.

Now watch it work for your business.

Two weeks free on the full Starter plan. Hand off your first job tonight; wake up to the report.

$0 today · then $39/mo · cancel anytime