Documentation
¶
Overview ¶
Package task is what the host and the VM agree on for a task that runs unattended: the files the host gives it and the results it gives back.
The host boots the VM with a blank state disk and the task share, and opens a session without a terminal. The results come as a tar archive on standard output, and standard error says what the task is doing. The host must read both, or the task stops on a full window. The exit code is 0 when the task went through to its end and 1 when a step failed. An archive without ResultFile is a failure too.
Everything that comes back was made by git and Claude Code running as the user of the VM, who may be hostile. Result is what the VM claims, and its texts are free text. The host checks the bundle against the commit it sent before it fetches anything, limits how much it reads, and cleans every text before it shows it. The VM stops Claude Code after Settings.TimeoutSeconds and still sends what it did, but the host needs a limit of its own for a VM that hangs. The host checks the settings with Check before it boots the VM.
Index ¶
Constants ¶
const ( MaxTranscriptBytes = 256 << 20 MaxLogBytes = 1 << 20 MaxChangesBytes = 1 << 30 MaxResultBytes = 1 << 20 )
The sizes the results may have. The VM cuts the transcript and the log at theirs and refuses changes above theirs, the host refuses anything larger.
const ( // SettingsFile holds the Settings as JSON. SettingsFile = "task.json" // PromptFile is what the task is to do, in words for Claude Code. PromptFile = "prompt.md" // InputBundle is a git bundle with the commit the task starts from as // HEAD. InputBundle = "input.bundle" )
The files of the task share, which the host fills and the VM mounts read-only.
const ( // TranscriptFile is what Claude Code printed, as stream-json. TranscriptFile = "transcript.jsonl" // LogFile is what Claude Code printed to standard error. LogFile = "claude.log" // ChangesFile is a git bundle of Branch from Result.Base on. It is // missing when the task made no changes. ChangesFile = "changes.bundle" // ResultFile holds the Result as JSON. It comes last. ResultFile = "result.json" )
The results, the files of the tar archive the VM sends back. All but ResultFile may be missing when the task failed before it made them.
const Branch = "refs/heads/aibox/task"
Branch is the branch the task works on and ChangesFile carries.
Variables ¶
var ( // ErrBadResults is an archive of results the host does not take. ErrBadResults = errors.New("the VM sent results aibox does not take") // ErrBadBundle is a bundle of changes the host does not take. ErrBadBundle = errors.New("the bundle of changes is not one aibox takes") )
var ErrBadSettings = errors.New("bad settings of the task")
ErrBadSettings is a task.json the VM does not run.
Functions ¶
func CleanLine ¶
CleanLine is CleanText on one line: the lines of the text are joined with " | ", so that text from the VM cannot pass for a line of aibox.
func CleanText ¶
CleanText makes text from the VM safe to show on a terminal: a CRLF becomes a newline, a tab a space, other control and format characters become ?, and so do bytes that are no UTF-8.
func Indent ¶
Indent is CleanText with every line indented, for text from the VM that has lines of its own.
Types ¶
type Bundle ¶
Bundle is the header of a git bundle: the commits it needs and the refs it carries, by name.
func ReadBundle ¶
ReadBundle reads the header of a git bundle without git, so that the host knows what it holds before git looks at it.
type Log ¶ added in v1.3.0
type Log struct {
// contains filtered or unexported fields
}
Log writes the lines of a task to one writer, each after the time and a label with the ID of the task, so that the lines of tasks that share a log can be told apart. The text from the VM goes through a writer of its own label, and the VM cannot leave the label out, so a line from it cannot pass for a line of aibox.
func NewLog ¶ added in v1.3.0
NewLog returns a Log that writes to w, with the ID id and the time now gives.
type LogWriter ¶ added in v1.3.0
type LogWriter struct {
// contains filtered or unexported fields
}
LogWriter is a writer of a Log. It cleans each line with CleanText and takes a CRLF for a newline. Close writes what is left of the last line, and a write after Close goes out at once, so that none is lost.
type Result ¶
type Result struct {
// Base is the commit the task started from, Head the commit Branch
// points at in the end. They are equal when the task made no changes.
Base string `json:"base,omitempty"`
Head string `json:"head,omitempty"`
// ClaudeExitCode is missing when Claude Code did not run.
ClaudeExitCode *int `json:"claudeExitCode,omitempty"`
// ClaudeResult is the last line Claude Code printed when it is a JSON
// object, normally the result event with the cost and why it stopped.
// It is here even when TranscriptFile was cut off. The task can print
// a line of its own after it, so it is only good to show.
ClaudeResult json.RawMessage `json:"claudeResult,omitempty"`
// TimedOut is true when Claude Code was stopped after
// Settings.TimeoutSeconds.
TimedOut bool `json:"timedOut,omitempty"`
// Leftovers is true when aibox committed changes the task had left
// uncommitted. Files git ignores are not part of it.
Leftovers bool `json:"leftovers,omitempty"`
// Truncated names the results that were cut off at their size limit.
Truncated []string `json:"truncated,omitempty"`
// Warnings are failures the task went on after, such as leftovers it
// could not commit.
Warnings []string `json:"warnings,omitempty"`
// Error is the failure that stopped the task, if any.
Error string `json:"error,omitempty"`
}
Result is what the VM tells the host about the task.
type Settings ¶
type Settings struct {
Model string `json:"model,omitempty"`
MaxTurns int `json:"maxTurns,omitempty"`
MaxBudgetUSD float64 `json:"maxBudgetUSD,omitempty"`
TimeoutSeconds int `json:"timeoutSeconds,omitempty"`
GitName string `json:"gitName,omitempty"`
GitEmail string `json:"gitEmail,omitempty"`
}
Settings are how Claude Code runs the task. A zero value leaves the default of Claude Code, or has no limit. GitName and GitEmail are who the commits of the task are by, aibox when they are empty.