Sessions and runs
A Session is a single run of work on a Task by one Drudger. A Drudger hosts at most one Session at a time. A Task can be worked on many times, so it can have many Sessions over its life. Only the last one is tracked.
Starting a Session
drg task run claims a Drudger, puts its workspace on the branch of the Task, starts the agent in its sandbox and waits for the first output of the agent. Then it returns, and the agent works on its own. --dry-run prints the prompt the agent would get and starts nothing.
A free Drudger can still have an agent of an earlier launch running in its sandbox. drg task run looks for one before it touches the workspace or the run directory, and refuses to launch when it finds one. The Task stays where it was. Run drg drudger nuke on the slot to kill that agent, then run the Task again. --dry-run warns about such an agent.
The agent has 60 seconds to write its first output. When it writes nothing in that time, or the launch fails after the agent started, drg task run sends SIGTERM to the agent, stops the sandbox and frees the Drudger. The Task stays todo. When the kill or the stop fails, the Drudger stays claimed and the error says the agent may still be running. Run drg drudger nuke on the slot then.
The prompt is the description of the Task wrapped in a template. A prompt file named in the config swaps in your own template.
The agent writes a Session id on its first event. The agent harness resumes a Session by that id, and DRUDGE records it on the Task.
The run directory
Every run writes its files to .drudge/runs/<task-id>/ in the project directory:
prompt.txt: the prompt the agent gotharness: the agent harness that launched the run.drg task runlog, close-out and the Session checks read the stream with it, so a change to the configured harness leaves old runs readable. A run with noharnessfile is read with the configured harness. Close-out and the Session checks fail on a harness DRUDGE cannot read the stream of, and so doesdrg task runbefore it claims a Drudgerrun-id: a UUID each new run gets. A reader that follows a run as it grows starts over when the ID changessetup.log: the output of the setup commands of the repositories, written when the project has anystream.jsonl: the event stream of the agent, one JSON event per linestderr.log: what the agent wrote to stderrexit: the exit code of the agent, written once it exitspull-requests/: the pull request descriptions close-out has not opened a pull request from yet
The sandbox mounts the runs directory, so the agent writes its stream where DRUDGE reads it. A new run of the same Task deletes the directory and starts it again with only the new prompt, harness and run ID. drg task rm deletes it with the Task.
drg task runlog prints the event stream and the stderr log. drg task show prints what the last run left on the Task.
How it is going
drg task status reads the run directory and says how the Session is going:
- working: the agent runs and keeps writing.
- needs babysitting: the agent runs and has written nothing for 5 minutes.
- fucked up: the agent stopped without finishing the work.
- got shit done: the agent finished the work it was given.
- never got going: the vendor turned the agent away.
Once the Session has ended, drg task status records the outcome on the Task: what the agent said last, how many turns it took, how long it worked and what it cost. Close-out runs at that point, and the Task ends up done, unmerged or fucked-up. See Tasks for what the statuses mean.
When the vendor turns the agent away
A vendor can refuse an agent before it does any work: a rate limit, an outage or an expired login. With the opencode harness, a provider opencode cannot reach, like a stopped local model server, refuses the agent too. A Session that the vendor turned away never got going. The agent was refused before it could work, so the Task is not at fault and goes back to todo. The Task records what the vendor said and which kind of refusal it was. The Drudger goes idle and records its agent as refused.
Fix whatever the vendor named, like logging in again for an expired login, and run the Task again.