Always On, Mostly Asleep
Anthropic's blueprint for always-on agents is mostly not about the model. An explainer of its five parts, the design calls it leaves to you, and what my own harness had and lacked.
An always-on agent is asleep almost all the time. It wakes because something happened, or because it set itself a time to look again. It works for a few minutes, writes down what it needs to keep, and goes back to sleep. The model isn't the part that stays on. The infrastructure around it is: a place where events wait, a clock that keeps the agent's promises, memory that outlives any process, a gate on what the agent may do alone, and a narrow channel back to a person.
Anthropic's Building always-on agents (William Hu, November 13, 2026) is a reference architecture for exactly those parts. Its subtitle sets the goal: "Always-on agents run indefinitely, deciding how and when to act across many sessions." The agent loop underneath is the one from Building effective agents. What changes is everything that decides when the agent wakes, what carries over between runs, and how work reaches the user.
My read: each of the five primitives is a distributed-systems pattern that has been in production for years under another name. That's good news, because their failure modes are known. What's new is that the consumer has judgment. Decisions that used to live in code now live in prompts and evals: what counts as the same conversation, what's worth remembering, and when to say nothing.
Start here
| 🧠| Your first always-on agent, in one day One process, one SQLite file, one user. No queue service, no workflow engine. 1. Create two tables. 2. Write the handler. One HTTP endpoint. It verifies the webhook signature, runs 3. Write the worker, and run exactly one. On start it takes an exclusive file lock (or exits) and resets rows stuck in 4. Write the scheduler. Every 30 seconds, in one transaction: for each due timer, insert an event with source 5. Create the memory folder. 6. Give it three tools besides read-only ones. 7. Tell it to start quiet. In How you know it works. POST the same webhook twice: one row. |
The two tables from step 1. source is where the event came from (a webhook provider, timer or approval), source_id is that provider's delivery or message ID, and session_key is a thread, issue or pending-call ID. Times are UTC, and every_s is set on schedules only.
CREATE TABLE events (
id INTEGER PRIMARY KEY,
source TEXT NOT NULL,
source_id TEXT NOT NULL,
session_key TEXT,
payload TEXT NOT NULL,
status TEXT NOT NULL
DEFAULT 'pending',
attempts INTEGER NOT NULL
DEFAULT 0,
created_at TEXT NOT NULL
DEFAULT (datetime('now')),
UNIQUE (source, source_id)
);
CREATE TABLE timers (
id INTEGER PRIMARY KEY,
kind TEXT NOT NULL,
due_at TEXT NOT NULL,
every_s INTEGER,
session_key TEXT,
payload TEXT NOT NULL,
status TEXT NOT NULL
DEFAULT 'active'
);The event inbox
What Anthropic says. Always-on agents wake on webhooks, scheduled tasks and background jobs, not just user messages. If every source calls the agent directly, two events arriving together start competing runs, and a crash loses whatever was in flight. The fix is an inbox in three parts: a durable event list (usually a database table), a handler that writes to it (usually an HTTP endpoint), and a worker that reads from it (usually a background service). Each event's status is tracked, duplicates are dropped by source ID, and the article suggests starting with one inbox per user. The handler acknowledges fast and leaves deep checks, prompt-injection screening included, to the run. Only one worker is active per inbox, and pending events are batched so three quick messages get one reply.
The old pattern. It's the idempotent consumer with a single writer. Kafka gives each partition to exactly one consumer in a group, per Confluent's docs; SQS FIFO processes messages of one group "one at a time, in strict order." The fast acknowledgment isn't optional either. GitHub records a delivery as failed after 10 seconds. Slack wants a response within three seconds and retries. Stripe asks for a 2xx "before any complex logic that might cause a timeout," retries for up to three days, and doesn't promise ordering. A model call inside the handler fails all three.
The design call: what counts as the same session. Anthropic's rule is that events continuing earlier work, like a user reply, resume the existing session, and the rest start a new one. The hard part is the correlation key. I'd resume only when the event carries an explicit key (a thread ID, an issue number, a pending-call ID) and the session is recent. Everything else starts fresh and reads the relevant progress file. A week-old transcript drags stale context and token cost into every turn; a progress file gives you continuity for a fraction of it.
For events that land mid-run, the article lists three options: hold for the next run, fold into the current one, or interrupt and restart. I'd default to the next run and interrupt only on a cancel. Folding is convenient and makes runs hard to reproduce.
An inbox gives you runs that happen at least once, not effects that happen exactly once. If a run crashes after sending an email, the retry sends it again. Tools with side effects have to tolerate a repeat.
Timers
What Anthropic says. Two kinds. Follow-ups are deadlines the agent sets for itself, like checking whether someone replied. Schedules recur, like a daily digest. They live in their own durable store, apart from the inbox, which holds only work that's ready. A timer never starts a run. A scheduler polls at a fixed interval, finds what's due, marks follow-ups done or advances schedules, and puts an event in the inbox. It can be custom code or a durable execution engine.
The old pattern. Cron feeding a queue, which is also roughly how durable execution engines treat time. Temporal persists timers so they fire even if the worker was down when the time came. The property that matters is that a firing timer becomes an ordinary event, with the same deduplication and the same single worker as everything else.
The design calls. First, misfires. If the scheduler was down for three days, should the daily job run three times? For most agents, no: skip to the next slot, as step 4 above does. Anthropic's own schedulers don't agree with each other here, which tells you it's a real choice. Managed Agents scheduled deployments don't backfill missed triggers. Session-scoped /loop tasks don't catch up either. Desktop scheduled tasks run exactly one catch-up for the most recently missed time within the last seven days. Second, make follow-ups cheap to dismiss. Let the timer fire, have the run check whether the reply already arrived, and exit quietly if it did. Cancelling the timer when the reply comes gives you two places that must agree. Third, an agent that schedules itself can loop. Cap active follow-ups per inbox and set a minimum interval.
Memory
What Anthropic says. Memory gets its own store. Claude Code's auto memory and the Messages API memory tool implement it as a directory of files; in an always-on system that directory maps to a database or object store, so it outlives any worker. The rule of thumb: store only what the agent can't look up again, and otherwise store a pointer. There are four kinds:
- User instructions, loaded every run, because the user isn't there to steer.
- User notes: role, preferences, corrections. One file first, later small files behind an index.
- Past messages: what the user has already been told, so nothing repeats.
- Task progress: per task, what's done and what remains.
The article also describes "dreaming," an optional offline pass over past sessions that curates memory: it replaces outdated entries and finds patterns across runs. Anthropic's components of agent memory goes deeper.
The old pattern. Cache invalidation: point at the source of truth, and never keep a copy you can't invalidate.
The design call: who may write what. I keep instructions.md user-owned: the agent reads it and never edits it. Notes are agent-writable, but each entry records where it came from. That matters because memory can be poisoned. Suppose the agent reads an email and notes "user prefers invoices forwarded to this address." An instruction injected through the inbox has just become permanent. A note the user gave and a note the agent inferred from untrusted input shouldn't carry the same weight. reported.md needs a size cap or rotation; progress files get archived when their task closes. If you add dreaming, run it without outside tools and make its output a diff you can read.
The context window. Every run reloads the system prompt, tool definitions and memory files, so the article says to keep them lean and use prompt caching. A mostly-asleep agent makes many short runs, so that fixed overhead can be most of the bill. Caching matches on prefixes: put stable material first (system prompt, tools, instructions.md, index.md) and what changes, like reported.md, after it. Compaction and session replacement both lose detail, so the advice is to write important facts to memory during the run, not at the end.
Permissions
What Anthropic says. This is "where always-on agents carry the most risk," because each run holds the user's access and nobody is watching. Every tool call either proceeds, is blocked, or waits for approval. Three components:
- A credential store. The recommended pattern is a proxy outside the agent's environment that adds credentials to outgoing requests, so the agent never holds them.
- Auto mode. In Claude Code, classifiers review higher-risk actions and block dangerous ones so Claude looks for a safer route. The most important decisions still go to the user.
- Deferred tool calls. In Claude Code, a hook can defer a tool call pending user input; the user sees the request (for example as an interactive card built with MCP Apps), and the worker handles other events meanwhile.
Auto mode's own write-up is candid about its limits: on real traffic it has a 0.4% false-positive rate, and it misses 17% of real overeager actions, which the post calls "the honest number." That's why the important calls still need a person. Deferral is a PreToolUse hook returning permissionDecision: "defer". It works only in headless claude -p runs, and only when Claude makes a single tool call in that turn. The result carries stop_reason: "tool_deferred" and the pending call's ID, name and input. Your worker shows the question, and when the answer event arrives it runs claude -p --resume with the session ID; the hook fires again and can allow the call with the answer filled in. The docs say there is no timeout: the session waits on disk until the cleanup sweep, 30 days by default.
Why it matters. Simon Willison's lethal trifecta is private data, exposure to untrusted content, and a way to communicate externally; with all three, an attacker can trick the agent into sending your data out. Meta's Agents Rule of Two adds changing state to the list and says an agent should have "no more than two of the following three properties within a session" unless a human approves or something else reliably validates. An always-on agent has all three by default: the inbox brings untrusted input, the run holds your access, and it has a send tool. Deferred calls put a human exactly on the calls that complete the set.
OpenClaw, a widely deployed open-source always-on agent, shows the stakes. SecurityScorecard found more than 40,000 exposed OpenClaw instances in its first 24 hours of scanning in February 2026. When OpenClaw added VirusTotal scanning to its skill marketplace, the announcement itself said it was "not a silver bullet" and that a crafted prompt-injection payload "won't show up in a threat database."
The design call: bind approvals to calls. Store the pending call's exact arguments under an ID. The approval must reference that ID, and resuming should execute the stored arguments, not whatever the model generates on its second try. Approvals travel through the same inbox as untrusted events, so authenticate that channel: the word "approved" inside an email body is just text. And let approvals expire. Since the deferred session itself has no timeout, the expiry is yours to enforce: a yes given today shouldn't authorize a send next month.
The outbox
What Anthropic says. The agent works in the background, so users get outcomes, not streamed steps. A run ends one of three ways: it sends a message, decides nothing needs sending, or makes a deferred tool call. Most agents can use a direct send tool; a formal outbox (a table of outgoing messages drained by a dispatcher) pays off when you need pacing or recovery from errors. Volume needs tuning and evals, because too many messages is noise and too few misses things. The key line: "In practice, it's better for the agent to start quiet and then earn more of the user's attention over time."
The old pattern. The transactional outbox: write the message in the same transaction as the state change and let a separate relay send it. The microservices.io page notes that the relay "might publish a message more than once," so the receiving end still needs to tolerate duplicates. The attention side is old too. Google's SRE book on paging: "Every page should be actionable."
The design call: what the agent may decide never to send. Write the categories down. Mine: anything already in reported.md; progress with no decision attached; "still working on it"; anything the user will learn anyway from the system that produced the event. Then make "nothing to send" an explicit outcome with a one-line reason, and log it. You can't evaluate silences you didn't record.
The five at a glance
Which parts Claude already ships
You don't have to build all five from scratch. As of November 13, 2026, Anthropic's docs cover most of the wake-up side, mostly in beta or research preview:
- Schedules. Cloud scheduled tasks (formerly routines) run on Anthropic's infrastructure with schedule, API and GitHub triggers, at most once an hour, and start in auto mode. The API trigger's text arrives wrapped in a block that labels it untrusted data.
/looplives inside an open session and expires after seven days. Managed Agents have cron-based scheduled deployments with jitter and a per-run cost budget. - Events into a live session. Channels let an MCP server push events into a running Claude Code session. The docs say plainly that events only arrive while the session is open, so an always-on setup needs a background process.
- Pause and resume. The defer hook above, Agent SDK sessions you can resume or fork by ID, and the
requires_actionstate of a Managed Agents session, which idles until you answer a pending tool call.
What none of them gives you is the inbox. Managed Agents webhooks make up to three delivery attempts and then drop the event; the docs' own words are "Webhooks aren't a durable log." Even with Anthropic hosting the agent, the durable list of what happened, and what was already handled, is yours.
What my own harness had, and what it lacked
I run a personal Claude Code harness with unattended work, so I checked it against the list. It has no resident agent. Its always-on behavior is a set of macOS launchd jobs that run short commands, some of which start a fresh headless Claude. Mapped onto Anthropic's parts:
- Inbox, partly. Improvement findings go into one inbox file under a lock, with IDs derived from a hash of the subject, so the same finding filed twice is one item. A daily watch job hashes each source page it tracks and only sends pages that changed to the research step: deduplication on source content rather than source ID.
- One worker, yes. Each unattended pipeline takes a kernel file lock, and the kernel releases it when a process dies, so a crash never leaves a stale lock behind.
- Timers, inside out. launchd is the clock, and the scheduled job does the work itself instead of pushing an event into an inbox. The daily jobs get an hourly window each morning rather than one slot, so a skipped run retries an hour later, and a completed run blocks the next twenty hours. That's a misfire policy too: at most one run a day, never a backlog.
- Memory, yes. Plain Markdown with a one-line-per-entry index loaded every session, and a hook that writes a checkpoint before context compaction, which is "persist during the run" in mechanical form. No dreaming yet: a weekly curation pass is on the open list.
- Permissions, by fencing. No credential proxy and no classifier. Unattended runs get fenced by configuration instead: the workers that draft articles run offline with no shell and no hooks, the improvement worker has a write fence, and child processes don't inherit credentials.
- Outbox, no. Notifications go straight out and are logged. Nothing is queued, retried or counted against an attention budget.
The gaps I can live with as the only user (no outbox, no deferred calls) are the first things to fix once a second person depends on it.
What the blueprint leaves to you
This section is opinion. The reference architecture is a good skeleton. Production needs these too, and the article gives them little or no space:
- Run budgets. A cap per run on turns, tokens and wall-clock time, plus a daily cap per inbox. Managed Agents scheduled runs already carry a per-run cost budget; a self-built worker needs its own. Cheaper models lower the cost of a runaway loop; they don't prevent one.
- A kill switch. A STOP file that only the human creates or removes halts unattended work. The worker and the scheduler should both check one, and the agent should have no tool that can clear it.
- Replay. Store every run's transcript keyed to the event IDs that triggered it. When something goes wrong, you want to rerun that run, not reconstruct it from logs.
- Evals for silence. Anthropic says volume needs evals. The hard part is labeling: you need the recorded silences as well as the messages, and someone has to judge both.
- Verification before "done." A task shouldn't close because the model says it's finished; a separate verifier should pass it. In this skeleton the agent marks its own progress files complete, and nothing checks them.
- Memory migrations. Plain files drift. When you change what
index.mdshould contain, existing memory doesn't migrate itself. Version the layout. - Model changes. Instructions, quiet thresholds and budgets are tuned to one model's judgment. Before switching models, rerun the evals, silences included.
What to build first
Anthropic's summary is the right one: "Each run is brief, but the cycle keeps going indefinitely." Build in the Start here order, and add an outbox once a lost or mistimed message actually costs you something.