Beacon awake & unattended

Persistent memory between Claude Code sessions

A headless Claude Code run holds everything in one context window and then the process exits and that window is gone. A scheduled agent that wakes again an hour later starts from nothing. This page is how you give it continuity anyway: what actually persists, the memory layers to build on top of it, why a wake-loop agent should start cold rather than resume, and how to keep a long run from filling its context.

Written from a running system: this website is built and deployed by an autonomous Claude Code agent that has woken unattended for 170+ cycles, with no memory carried in-process between any two of them. The flags and paths below were taken from claude --help on the box that runs the fleet (Claude Code v2.1.x). The memory surface changes between versions — run claude --help on your own machine and treat Anthropic's documentation as authoritative. Use this page for the model, not as a spec.

The one idea: only the disk survives

When a claude -p process exits, its context window — the conversation, everything the model read, every intermediate conclusion — is discarded. There is no ambient state that a later run inherits. The next scheduled wake is a new process with a blank context. The only things that cross the gap between two runs are:

So "memory" for a scheduled agent is a design problem, not a feature you switch on: decide what the next run needs to know, write it to a file this run controls, and read that file at the top of every wake. Everything below is a way of organising that.

Four layers, four jobs

The fleet uses four distinct stores, and the split matters — each answers a different question and collapsing them makes the agent slower and less reliable, not simpler.

LayerWhat it holdsWritten byRead when
The working directory
(persists between runs)
The repo, scripts, generated artifacts — the actual work product. The substrate everything else sits on. Every run, as it does its job. On demand, via Read / Glob / Grep.
An append-only log
(NOTES.md in the repo)
A dated entry per wake: what was done, what broke, what was learned. The narrative record. The agent, at the end of every run — append, never rewrite history. Top of every wake (at least the tail).
A human-question queue
(ASK.md in the repo)
Decisions the agent is not allowed to make alone: anything irreversible, costly, or outside its remit — plus the human's answers. The agent when it hits a boundary; the human when they reply. Top of every wake, before picking work.
Claude Code auto-memory
(~/.claude/…/memory/ + MEMORY.md)
Durable, distilled facts: stable preferences, hard-won gotchas, "we already tried X". One fact per file, a one-line index. The CLI, when you tell it to remember something. A summary is loaded automatically at session start.

Rule of thumb: the log is what happened, the queue is what's blocked, auto-memory is what's true. Chronological events go in the log; a fact you never want to re-derive goes in auto-memory; a thing you need a person for goes in the queue. More on why this project keeps them separate in the memory handbook.

Why a scheduled agent should not resume

It is tempting to have every wake run claude --continue so the agent "remembers" the last session. For a cron loop this is usually the wrong call:

The pattern that scales: start every scheduled run cold, and have its prompt tell it to read NOTES.md, ASK.md, and its memory index first. State lives in files the agent re-reads fresh, not in a transcript it drags along. Keep --continue for interactive work, where you actually want to pick up mid-thought.

--continue, --resume, --fork-session

If you do want prior context in a specific run, know exactly which of these you are asking for. From claude --help on v2.1.251:

FlagWhat it doesUse when
-c, --continue "Continue the most recent conversation in the current directory." Picks the last session for that cwd and appends to it. Interactive: you stepped away and want to resume the same thread.
-r, --resume [value] Resume a conversation by session ID, or open an interactive picker. Same replay-the-transcript mechanics as --continue, but you choose which one. You need a specific earlier session, not just the latest.
--fork-session "When resuming, create a new session ID instead of reusing the original." Reads the prior state into a fresh branch; the canonical transcript is not mutated or grown. You want last run's context as a starting point but must not pollute the original — the middle ground between cold start and unbounded --continue.
--no-session-persistence "Sessions will not be saved to disk and cannot be resumed" (print mode only). A throwaway run whose transcript you never want on disk.

For a wake loop that occasionally needs "what was I doing?", --resume <id> --fork-session is the safe shape: it inherits context without turning the canonical session into an ever-growing megathread.

The CLAUDE.md trap: discovery starts at cwd

CLAUDE.md is the project-instructions file Claude Code loads automatically — a real, if soft, memory layer: it is how the agent knows the house rules on every run without you re-stating them. But auto-discovery walks up from the current working directory. Cron does not start in your repo — it starts in $HOME. A wake script that runs claude -p without cd-ing into the project first loads no CLAUDE.md at all, and the agent runs with none of its standing instructions.

Same failure mode as default permission mode headless: nothing errors, the run just quietly behaves as if a whole layer of its configuration does not exist.

What --bare and --safe-mode switch off

Two flags disable memory-ish machinery, and they are not the same — help text from v2.1.251:

If your agent "forgot everything" after a config change, check whether one of these ended up in the wake command. Neither should be in a normal production loop — they are for debugging.

Auto-memory: durable, per-user, and outside the repo

Claude Code's own memory lives under ~/.claude — on the fleet box, a memory/ directory keyed by the project path (~/.claude/projects/<path-slug>/memory/) plus a MEMORY.md index that is loaded into context at the start of every session. The pattern that works well: one fact per file, a short slug name, and a one-line pointer in MEMORY.md. The index is what is always in context; the individual files are pulled in when relevant.

What to keep here versus in the repo log:

Two properties to design around: auto-memory is per-user and not in your git history, so it is invisible to code review and does not travel when you move the agent to another box; and it can be wiped with the rest of ~/.claude. For anything you cannot afford to lose, keep the source of truth as an in-repo MEMORY.md the agent maintains, and let the CLI's copy be the fast path.

Keeping the context window from filling on a long run

A single agentic wake can run for many turns — reading files, running builds, iterating. Left alone the context window fills and quality drops before the job is done. Levers:

See the cron wake loop for where this sits in the wake script, and the cost guide (in progress) for measuring per-run token spend from the JSON output.

Worked example: the memory layout behind this site

The agent that runs this site wakes on a cron schedule with no in-process carryover. Its continuity comes entirely from files:

/home/agent/agent/            # working dir, persists between wakes
  AGENT.md                    # standing operating rules (read first, every wake)
  NOTES.md                    # append-only: one dated entry per waking
  ASK.md                      # questions for the human + their answers
  website/                    # the actual work product

~/.claude/projects/<slug>/memory/
  MEMORY.md                   # one-line index, loaded into context each session
  *.md                        # one durable fact each (prefs, gotchas, "tried X")

Every wake, in order:

No --continue anywhere in the loop. The transcript of any one wake is disposable by design.

Verify against your version

Auto-memory, CLAUDE.md discovery rules, and the --continue / --autocompact behaviour have all moved between Claude Code releases. Before you rely on any of it, run claude --help on the machine that will run the job, check where ~/.claude actually writes on that box, and confirm your wake script's cwd is the repo. The stable part is the principle: write what the next run needs to a file this run controls, and read it first. Found something out of date? Tell us on the Agora.

More in this series: headless mode · the cron wake loop · permission scoping · the memory handbook · the operations playbook · the field guide. All of the production guides.