artifact

package
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package artifact persists the full AI response for each PM task as a human-readable Markdown file with YAML frontmatter under .cloop/tasks/. It also stores shell verification scripts and their results.

Index

Constants

MaxReadBytes is the cap applied to every read of a task artifact. It is the shared constant described in boundedread; see there for why artifacts need one despite not being attacker-controlled.

View Source
const SandboxRunFile = ".cloop/sandbox-run.json"

SandboxRunFile is where the current run's environment record lives, relative to the project directory.

Variables

This section is empty.

Functions

func HeadTruncationNotice

func HeadTruncationNotice(total int64) string

HeadTruncationNotice is the marker to append to a head-biased read that hit the cap. It goes at the bottom, where the content stops.

func HumanBytes

func HumanBytes(n int64) string

HumanBytes renders a byte count for a human reading a log line or a prompt. Exported so callers that impose their own, tighter budget on top of the read cap can describe it in the same units.

func LiveArtifactDir

func LiveArtifactDir(workDir string) string

LiveArtifactDir returns the directory where live streaming artifacts are written.

func LiveArtifactPath

func LiveArtifactPath(workDir string, taskID int) string

LiveArtifactPath returns the canonical path for the live streaming output file for the given task ID. The file is written incrementally during execution.

func OpenLiveArtifact

func OpenLiveArtifact(workDir string, taskID int) (*os.File, error)

OpenLiveArtifact creates (or truncates) the live streaming output file for a task and returns the open file handle. The caller is responsible for closing it. Errors are non-fatal; the caller should treat nil as "no live artifact".

func ReadArtifactHead

func ReadArtifactHead(workDir, artifactPath string) (data []byte, truncated bool, total int64, err error)

ReadArtifactHead reads at most MaxReadBytes from the start of a task artifact. Prefer ReadArtifactTail unless the caller genuinely wants the beginning — a browsable detail pane that renders the first N lines, for instance, where the reader scrolls from the top.

func ReadArtifactTail

func ReadArtifactTail(workDir, artifactPath string) (data []byte, truncated bool, total int64, err error)

ReadArtifactTail reads at most MaxReadBytes from the end of a task artifact.

This is the right default for anything that wants to know how a task turned out — context injection into the next task, evaluation, summarization — because an agent's conclusion, its completion signal and any failure it hit are all at the end of its transcript. total is the artifact's full size on disk, so callers can say how much they did not read.

func ReadLiveArtifactTail

func ReadLiveArtifactTail(workDir string, taskID int) (data []byte, truncated bool, total int64, err error)

ReadLiveArtifactTail reads at most MaxReadBytes from the end of a task's live streaming output file.

Live artifacts are the riskiest of the lot: they are the log of a task that is running right now, so they are the ones actually growing while something reads them. Always tail-biased — a live log is read to find out where the task has got to, which is by definition its last line.

func ReadTaskOutput

func ReadTaskOutput(workDir string, task *pm.Task) string

ReadTaskOutput reads the AI output for a completed task. If task.ArtifactPath is set and readable, it returns the artifact body with YAML frontmatter stripped. Falls back to task.Result if the file is missing. Returns empty string when neither source is available.

The read is bounded at MaxReadBytes and biased to the tail, because every caller of this function wants the outcome: chained task input, acceptance checks, post-task evaluation, replay comparison and the task detail panel. When the cap is hit the returned string opens with TailTruncationNotice so no consumer mistakes the surviving tail for the whole transcript.

func TailTruncationNotice

func TailTruncationNotice(total int64) string

TailTruncationNotice is the marker to prepend to a tail-biased read that hit the cap. It goes at the top because that is where the omission is: the reader is about to see the end of a much longer log.

Truncation must always be stated. A summarizer that silently receives 16 MiB of a 2 GB log reports confidently on a fraction of the work; one that is told the log was cut can qualify what it says.

func WriteExecArtifact

func WriteExecArtifact(workDir string, task *pm.Task, cmdArgs []string, exitCode int, elapsed time.Duration, output string) (string, error)

WriteExecArtifact persists the output of a 'cloop task exec' run under .cloop/tasks/<id>-<slug>-exec-<ts>.md. Returns the relative path (relative to workDir) of the artifact file.

func WriteSandboxRun

func WriteSandboxRun(workDir string, rec SandboxRecord) (string, error)

WriteSandboxRun persists the record for the run that is about to start.

It is called by the control plane, from outside the sandbox, with the project directory the workload will see. Returns the path written.

func WriteTaskArtifact

func WriteTaskArtifact(workDir string, task *pm.Task, fullOutput string) (string, error)

WriteTaskArtifact writes the full AI response for a completed task to .cloop/tasks/<id>-<slug>.md with YAML frontmatter. Returns the relative path (relative to workDir) of the artifact file.

func WriteVerificationArtifact

func WriteVerificationArtifact(workDir string, task *pm.Task, script, scriptOutput string, passed bool) (string, error)

WriteVerificationArtifact persists a shell verification script and its execution result under .cloop/tasks/<id>-<slug>-verify.md. Returns the relative path (relative to workDir) of the artifact file.

Types

type SandboxRecord

type SandboxRecord struct {
	// ExecutorID and ExecutorKind identify where it ran.
	ExecutorID   string `json:"executor_id,omitempty"`
	ExecutorKind string `json:"executor_kind,omitempty"`
	// SpecHash is the .cloop/sandbox.yaml content hash, or empty when the
	// project has no spec and ran on the executor's defaults.
	SpecHash string `json:"spec_sha256,omitempty"`
	// RequestedImage is the reference the spec asked for, before resolution.
	RequestedImage string `json:"requested_image,omitempty"`
	// PinnedImage is the reference the workload actually ran from —
	// digest-pinned where the driver could resolve one.
	PinnedImage string `json:"pinned_image,omitempty"`
	// SetupHash identifies the setup: commands baked into a derived image,
	// empty when the spec has none.
	SetupHash string `json:"setup_sha256,omitempty"`
	// Warnings are the clamps applied while parsing the spec.
	Warnings []string `json:"warnings,omitempty"`
	// StartedAt is when the workload began.
	StartedAt time.Time `json:"started_at,omitempty"`
}

SandboxRecord is the provenance of one run's execution environment.

func LoadSandboxRun

func LoadSandboxRun(workDir string) (SandboxRecord, bool)

LoadSandboxRun reads the record for the current run, if there is one.

Every failure returns ok=false rather than an error. A missing, truncated or malformed record must never be the reason a completed task's output is not persisted — the stamp is provenance, and losing provenance is strictly better than losing the work it describes.

func ParseSandboxFrontmatter

func ParseSandboxFrontmatter(s string) (SandboxRecord, bool)

ParseSandboxFrontmatter extracts the sandbox stamp from a task artifact's leading YAML frontmatter block.

It is deliberately a hand-rolled scan of `key: value` lines rather than a YAML decode. The block is written by frontmatter above one line at a time, the keys are a closed set, and a partial read that lands mid-block must yield the keys it did see rather than a parse error for the truncated last line — which is what a real YAML parser would give.

func ReadTaskSandbox

func ReadTaskSandbox(workDir string, task *pm.Task) (SandboxRecord, bool)

ReadTaskSandbox recovers the sandbox a past task actually ran in.

Why this exists alongside LoadSandboxRun

They read the same record from two different places, and only one of them is durable. LoadSandboxRun reads .cloop/sandbox-run.json, which the control plane overwrites before every run — it answers "what am I running in right now", and by the time anyone asks about task 42 it describes some later task. The per-task copy stamped into the artifact's frontmatter is the one that survives, so it is the one a reproduction has to read.

Returns ok=false for a task with no artifact, no frontmatter, or no sandbox stamp — the ordinary case for a run that predates the stamp or executed on the host. A caller must treat that as "unknown", never as "unsandboxed".

func (SandboxRecord) IsZero

func (r SandboxRecord) IsZero() bool

IsZero reports whether the record carries nothing worth stamping.

func (SandboxRecord) Pinned

func (r SandboxRecord) Pinned() bool

Pinned reports whether the recorded image is immutable — whether re-running this record would provably get the same filesystem.

The test is for "@sha256:" rather than for any digest-shaped substring: a tag may legitimately contain hex, and calling a tag pinned is the one error here that would matter, because it is the claim someone relies on when they say a result reproduces.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL