Coding agents on Rebuno
A background coding agent might restart halfway through a task, wait hours for approval, or get review comments on its pull request days later. To continue the task, it needs its working files and the conversation so far.
Here's a design using Rebuno, following an agent asked to fix a bug. After making the edit and passing the tests, its worker runs out of memory and is killed. It resumes, gets approval to open a pull request, and handles a review comment in a later run.
The setup
- Clients start a run for each request from an issue or pull request, and post approval requests.
- The agent service runs the model and tool loop.
- The sandbox runs repository code and holds the working files.
- Rebuno dispatches executions, checks each call against policy, and records the results. It dispatches an execution again after an interruption or approval, and keeps each session's conversation and sandbox between runs.
The agent works with no one watching. Its worker can die halfway through a task, or it can run a command that was never reviewed. Clients start runs through Rebuno so a crashed run is dispatched again and each call is checked against policy before it runs. Every run for the same issue or pull request belongs to one session.
The workspace
The agent edits the code and runs the tests. They pass, and Rebuno records both results. Before the next model call, the worker runs out of memory and is killed. Rebuno dispatches the execution again, and the agent code starts from the beginning.
Recorded calls return their saved results. The edit reports success and the tests report a pass without either running again. If the new worker clones the repository again, the fix is missing and the agent can open a pull request without it.
The agent registers its sandbox as a resource so the new worker gets the files the first one edited. On first use, the resource's driver creates the sandbox and Rebuno records its binding, such as the sandbox ID. Later dispatches open the same sandbox from that binding.
The conversation
Each run completes with its conversation as session state. The next run in the session reads it back with previous():
from rebuno import Agent, Result, previous, resource async def process(task: str) -> Result: workspace = await resource("workspace", driver=SandboxDriver()) prior = await previous() or {} messages = [*prior.get("messages", []), {"role": "user", "content": task}] messages = await run_agent(workspace, messages) return Result( output={"summary": messages[-1]["content"]}, state={"messages": messages}, ) Agent("coder").run(process)
Rebuno saves the state when the execution completes. A worker killed partway through a run saves nothing, so the next attempt reads the same conversation as the first. Replaying the recorded model calls rebuilds the rest.
Approvals and follow-ups
Opening a pull request needs approval, so the run pauses. The client posts the request on the issue, and the sandbox can stop while it waits. Once a maintainer approves, Rebuno dispatches the execution again. The agent reopens the sandbox from its binding, replays its earlier calls, and opens the pull request.
Later, a reviewer requests another change. The client starts a new execution in the same session. It runs after the previous one finishes, reads the conversation it saved, and opens the same sandbox.
Summary
Rebuno records every model and tool call. It dispatches the execution again after the worker is killed or an approval comes back. The agent code replays the recorded results until it reaches new work. The sandbox can be stopped during the approval wait.
Replay doesn't change the files on disk. The sandbox is registered as a resource, so every attempt and every later run in the session opens the one with the fix. Each run saves its conversation as session state, and a follow-up reads it back. The agent service keeps nothing between runs.
To learn more about Rebuno, read the docs or visit the repository on GitHub.