HomeBlog › Background shells with ring buffers: fire long jobs, check in later
Blog

Background shells with ring buffers: fire long jobs, check in later

Jul 19, 20265 min readBy the Rysh team

Agents shouldn't sit and watch a build scroll by. Rysh gives them background shell sessions with 256KB ring buffers — start, work, check back.

Watch an AI agent run a twenty-minute integration suite in a normal terminal setup and you'll see the dumbest possible use of a language model: it starts the command… and waits. The whole conversation blocks on a spinner. Twenty minutes of the most capable text-processing system ever built doing absolutely nothing, because the tool call hasn't returned yet.

Humans don't work like that. You kick off the build, switch windows, write the next function, and glance at the build every so often. The glance is the skill.

Rysh gives agents the same skill, with two tools: bash_background and bash_session.

The shape of it

bash_background starts a command in a detached background session and returns immediately — with a session ID. The agent's conversation doesn't block. It has a handle, not a wait.

bash_session is everything you do with that handle, as one tool with three actions:

So an agent's transcript stops looking like "ran tests (20 minutes of silence)" and starts looking like an actual engineer's loop:

bash_background: go test -tags=integration ./...   → session bg_7f3a
edit: fix the codec registration in internal/msg/…
bash_session read bg_7f3a                          → still running, 41 tests passed so far
file_write: update CHANGELOG.md
bash_session read bg_7f3a                          → done: 2 failures in pane_group_test.go

The agent interleaves. It reads partial output mid-run and reacts to it. If the first failure shows up at minute three, it doesn't need minute twenty to start thinking.

Why a ring buffer

Here's the design decision worth talking about: each background session captures output into a 256KB ring buffer, managed by rysh's BackgroundSessionManager. When output exceeds 256KB, the oldest bytes fall off the front.

That sounds like a limitation. It's actually the correct data structure, for three reasons.

1. Long jobs produce unbounded output; memory is not unbounded. A verbose test suite or a chatty deploy script can emit hundreds of megabytes. Buffering all of it "just in case" is how background-job systems eat your RAM. A ring buffer makes the cost of any session constant, no matter how noisy the job is.

2. The tail is where the truth lives. For almost every long-running command, the diagnostic signal is at the end: the failure summary, the exit trace, the last error before the hang. The front of the log is boilerplate. A ring buffer is a bet that the most recent 256KB matters more than the first — and for shell output, that bet almost always pays.

3. Agents have context windows. This is the part that's specific to agentic terminals. Whatever the agent reads gets spent from a token budget. Handing an agent a 300MB log isn't thoroughness, it's a denial-of-service on its own context. A bounded buffer is a contract: reads are always cheap enough to actually do. Which means the agent checks in more often, which means it catches failures earlier. Bounded output makes agents more attentive, not less informed.

(Need the full log? That's what redirection is for — go test ./... 2>&1 | tee /tmp/full.log in the background session, and the agent can grep the file surgically. The ring buffer is the default, not a wall.)

The governance still applies

Background execution doesn't get a hall pass. The command an agent hands to bash_background goes through the same safe-by-default policy as foreground bash: read-only and idempotent commands run freely, while mutating, redirecting, or chained-unsafe commands need your approval before they start. You approve the launch; the session runs; every read after that is inspection, which is always free.

And because it's rysh, all of it is visible. The tool calls — the start, every check-in, the kill if it comes to that — appear in the pane like everything else the agent does. A background job is out of the way, not out of sight.

What this unlocks

Once agents can fire-and-check instead of fire-and-wait, a different working pattern shows up:

None of this is exotic. It's just how a competent engineer already uses a terminal — encoded as tools, so the agent can do it too, inside a governed workspace you can watch.

Rysh runs on Claude with your own API key, on your own machine — the background sessions, the buffers, the logs: all local, all yours.

Fire the job. Do the work. Glance when it matters.


Building with agents in your real dev loop? We're recruiting design partners with a direct line to the founders: rysh.ai/design-partner.

More in this series: The bash allowlist: safe-by-default shell execution for agents · Loop detection: stopping an agent from calling the same tool forever

Try Rysh

Every pane is a shell and an AI agent — install takes one command.

Get started free →