A terminal coding agent is a model calling tools in a loop. It is powerful, and it has one limit: close the laptop and the process stops. An always-on agent removes that limit. It runs on a server, owns its own computer, remembers what you worked on, wakes up when something happens, and knows when to stay quiet. This guide explains how to build one, using the architecture described in a lecture by Lee, an engineer at SpaceX who works on this category of product. The talk calls these agents "bots" and notes that parts of what it describes are still in progress. We have kept to what the lecture says, flagged our own additions, and written the steps so they apply to any stack.
Two notes on scope. The lecture transcript we worked from ends partway through its discussion of message queues and priorities, so we cover what was said up to that point. And the code in this guide is our own illustrative sketch, not SpaceX code.
What you need before you start
- A working agent loop: a model that calls tools until it finishes. If you do not have one, build that first.
- A server environment you control, with a database for state.
- A place for the agent to run commands safely, such as a container or virtual machine.
- Patience for small steps. Each building block below is useful alone.
TL;DR: the architecture in one table
| Building block | Job | If you skip it |
|---|---|---|
| Server-side agent loop | Runs the model-and-tools loop and saves state | Agent dies with the client |
| Persistent state | Conversation logs, memory, routines in a database | Agent forgets after restart |
| Wake triggers and router | Start the agent from Slack, email, schedule or a call | Agent only reacts to your prompts |
| Notify heuristic | Decide whether to message the user | Agent spams you or goes silent |
| Sandbox computer | Files, shell, browser, desktop | Agent cannot act beyond text and APIs |
| Memory in files | Profile, work log, notes the agent can search | No continuity across days |
| Skills and routines | Reusable procedures and scheduled prompts | You re-teach everything |
| Subagents and compaction | Fresh working memory for long work | Context fills up and quality drops |
| Durable workflows | Retry without replaying finished steps | Crashes cause duplicate side effects |
| Priorities and batching | User steering beats background work | Agent ignores you mid-task |
Step 1: move the loop to a server
The lecture's core move is to take the simple loop and run it on a server instead of a laptop. It lists concrete reasons for a "thin client, thick server" design:
- Fast updates. Pushing a change to agent code should not require an app store release. A server deploy is much quicker.
- Heavy work. Tasks such as transcription or image generation are often faster on server hardware.
- Scaling. The industry already knows how to scale servers under variable traffic.
- Independence from the sandbox. This is the most important one. If the agent loop lived inside the virtual machine, you could not shut down or rebuild the machine without also stopping the agent.
The example given: you need to apply a critical operating-system patch to the sandbox. If the loop and state live on the server, you rebuild the machine and the agent keeps its conversation, memory and routines. Save everything on the server so the machine can always be recreated.
How to do it. Put the loop behind a service with a queue of incoming events. When an event arrives, load the agent's state from the database, run turns until it finishes or yields, and write the state back.
Step 2: make state persistent
An agent that can sleep needs somewhere to keep itself. The lecture lists what gets persisted: conversation logs, memories, routines and other state, written to a database or storage when the agent shuts down. When it wakes, the server loads that state and continues.
Sleeping matters for cost. There are not enough computers to keep one running for every user at all times, and idle servers waste money. The lecture describes the lifecycle: the server and the agent's computer start asleep, a message or trigger boots the state, the agent starts the computer only if it needs a browser or desktop, and both go back to sleep when done.
Step 3: add wake triggers and a router
An always-on agent is not only prompted by you. The lecture gives these wake sources:
- A direct message from you.
- A Slack message or an email.
- A phone call or meeting where the bot is present. The lecture notes that bots joining meetings to take notes for people who could not attend is increasingly common at SpaceX.
- A routine or background task that finishes after hours or days and needs to report.
A router sits between these triggers and the agent. It removes duplicates and puts events into the right conversation. The lecture also describes a heuristic step: decide whether this event is worth interrupting the user for. Its analogy is a coworker who tells you about every bit of progress, which would be annoying. A daily status update may be enough for some tasks.
Illustrative sketch (our code). This minimal router dedupes events, gives user steering priority over background work, and batches events that arrive close together into one turn:
import time, hashlib
from dataclasses import dataclass, field
@dataclass
class Event:
source: str # "user", "slack", "email", "routine"
text: str
priority: int = 1 # 0 = user steering, 1 = everything else
ts: float = field(default_factory=time.time)
class Router:
def __init__(self):
self.seen = set()
self.queue = []
def key(self, e):
return hashlib.sha256(f"{e.source}:{e.text}".encode()).hexdigest()
def submit(self, e):
k = self.key(e)
if k in self.seen: # dedupe retries and repeated triggers
return False
self.seen.add(k)
self.queue.append(e)
self.queue.sort(key=lambda x: (x.priority, x.ts))
return True
def next_turn(self, batch_window=2.0):
if not self.queue:
return []
first = self.queue[0]
batch = [e for e in self.queue
if e.priority == first.priority and e.ts - first.ts <= batch_window]
for e in batch:
self.queue.remove(e)
return batch
def should_notify(update, last_notified_at, min_gap=3600):
return update.get("important") or time.time() - last_notified_at > min_gap
We ran this sketch: a duplicate Slack event is dropped, a user message jumps ahead of background work, and a routine update that is not important is held back inside the minimum gap. A real router would also key on thread or conversation, persist its seen set, and use a smarter importance signal.
Step 4: give the agent its own computer
The lecture describes a Linux machine in the cloud with its own files, a browser and possibly desktop apps. It runs as a Firecracker virtual machine, chosen because it is easy to snapshot the machine's state, shut it down and start it again. You can connect to the machine for a live view and even take control. Running commands there is safer than running them on a personal laptop, since the environment is locked down.
Two details are worth copying:
- Virtual desktops. If you run many bots and each needs a browser, give each its own screen on shared infrastructure.
- Computer use. Because the agent can click around a screen like a person, any website or software without an API or MCP server can be driven through the screen. The lecture presents this as a way to use such products headlessly and autonomously.
How to do it. Start with a container if a full VM is too much. Add snapshot and restore early, because it makes the sleep-and-wake lifecycle cheap. Treat the machine as disposable and rebuildable from server-side state.
Step 5: store memory in files
The lecture's memory design is simple on purpose. Information lives in files that the model can search with ordinary Linux tools:
- A user profile that is included in every prompt, for example a preference for lowercase, text-message style replies.
- A working log that records what was done each day, like a colleague's daily notes. Ask "what did I do last week?" and the agent can search the log.
- Notes and artifacts saved on the machine.
Files work because models are good at running shell commands to grep and read them. They are also easy for you to inspect and edit. If you want a deeper treatment of the file conventions, see our guides to CLAUDE.md, SKILL.md and MCP and agent skills.
Step 6: add skills and routines
Two more kinds of reusable memory turn a one-off helper into a colleague.
- Skills encode how to do a specific task in a markdown file, including the process and the things that make it succeed or fail. The lecture notes a growing ecosystem of skills written by companies and developers, for tasks such as sending a good email or building a good API.
- Routines are prompts that run on a schedule, similar to cron jobs.
The lecture also says you can show the bot how to do some work and it will turn that into a skill, memory or routine it reuses later. It describes a plugin system in which a tool is added by installing a plugin that bundles skills or servers and routines. For when to use a skill versus a hook versus a plain prompt, see skills vs hooks vs prompts.
Step 7: handle long work with subagents and compaction
The lecture credits several model improvements for making this category possible: following instructions reliably over long periods, handing work to subagents, calling tools without the hallucination problems of earlier years, using powerful tools like a full computer, relying on files for memory, and learning skills from demonstration.
For length, two techniques matter:
- Compaction. With the right compression, models can run for hours or days without getting confused.
- Subagents. The main agent's working memory eventually fills. A subagent gets a fresh working memory, does token-heavy or tool-heavy work, and reports back. The lecture describes this as effectively unlimited context.
How to do it. Summarize old turns into the log when a threshold is reached, keep the profile and recent turns verbatim, and delegate expensive exploration to a subagent that returns a short report.
Step 8: use durable workflows, not a plain job queue
This is the most technical point in the lecture and the one that most affects reliability. Suppose a task has steps one, two and three, and an infrastructure problem hits at step three.
- With a job queue, a retry replays steps one and two. If those steps sent an email or charged a card, you now have duplicates.
- With a durable workflow, completed steps are recorded, so a retry resumes at step three.
The lecture says this is largely a solved problem in distributed systems, and that the team uses the open-source tool Temporal instead of rebuilding it. You still run the infrastructure, but you avoid writing a hard piece from scratch.
How to do it. Wrap each side-effecting tool call as a recorded step, give each a stable idempotency key, and let the engine handle retries and timeouts.
Step 9: set message priorities and batching
When a new message arrives, not all messages are equal. According to the lecture:
- A message from you to your own bot takes priority over everything else, including a running task. If you say "change the date for this event," the loop should stop and handle it.
- Messages from group chats, Slack threads and background routines go to the back of the queue.
- If several messages arrive in quick succession, batch them into one turn. The exact heuristic is up to you.
The lecture also covers steering: interrupting with a follow-up while the agent is working, such as asking it to check a thread and then adding that a related job should happen on Thursday. Newer models handle that kind of rambling better than earlier ones, the lecture says, so design the harness to accept mid-task input and not reject it.
For client sync, the lecture sketches a send, acknowledge, run and subscribe pattern: the client sees its message acknowledged immediately, the server runs the turn and saves it, and clients subscribed to updates fetch the latest state when notified, with deduplication so retries do not show duplicate messages.
Step 10: add safety checks you can live with
The lecture argues that watching every shell command creates fatigue, and that a separate model reviewing each command can do better than a tired human, as many companies are doing under names such as auto-review. It says that in blind comparisons the model often does the better job. Treat that as one speaker's claim and test it on your own commands before you rely on it. A good setup combines the reviewer with a locked-down sandbox, scoped credentials and logs you can audit.
Putting it together: a build order
| Order | Build | Done when |
|---|---|---|
| 1 | Server-side loop with state in a database | A restart resumes the conversation |
| 2 | Memory files and a profile | The agent recalls last week from its log |
| 3 | One schedule trigger (routine) | It runs a prompt without you |
| 4 | Router with dedupe and a notify rule | Duplicates drop and updates are rate-limited |
| 5 | Sandbox container with snapshot and sleep | You can pause and resume the machine |
| 6 | Durable workflow for side effects | A forced crash does not repeat an email |
| 7 | Skills and a second trigger such as Slack | New tasks reuse saved procedures |
| 8 | Subagents, compaction and command review | Multi-day tasks stay coherent |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Agent messages too often | Every event notifies | Add an importance check and a minimum gap |
| Agent never reports back | Notify rule too strict | Always notify on finished deliverables and blocking questions |
| Duplicate emails after a crash | Retry replays steps | Use durable workflows and idempotency keys |
| Agent forgets between days | State not persisted | Save logs, profile and routines on every shutdown |
| Quality drops late in a long task | Context is full | Compact and delegate to subagents |
| Machine patch kills the agent | Loop lives in the VM | Keep the loop and state on the server |
| User message ignored mid-task | No priority lane | Let direct messages interrupt background work |
What this does not cover
The lecture is one engineer's account of one team's design, with some parts described as in progress. It does not give benchmarks, and we have not reproduced its claims. It does not detail security, cost control or multi-user permissions, and it should not be read as a complete production blueprint. Treat it as a map of the problem. For real products built along these lines, see our coverage of SpaceXAI's Grok Bot, how one engineer runs a bot org, OpenAI Codex persistent mode and Cursor's persistent agents.
Related reading
- SpaceXAI Grok Bot: persistent agents that log into your tools
- Inside SpaceXAI's Grok Bot engineering org
- OpenAI Codex persistent mode and always-on agents
- OpenAI Dots and always-on agents
- Cursor persistent agents
- Agent skills: the complete guide
- Hermes Agent on a remote VPS
This guide is based on a lecture by Lee, an engineer at SpaceX, as transcribed to us. The transcript ends partway through its discussion of priorities. Code samples are our own illustrations. Product details may change.
