spec

package
v1.114.0 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package spec captures the specification a coding session was built from.

The agent is the resolver. Chainloop fetches nothing: the session-start hook hands the agent a directory, and the agent writes the text of whatever the task names — a ticket, a design document, a prompt — into it, one file per source. Pre-push folds those files into the session evidence and deletes them. That is why there are no connectors, no credentials and no fetch failures anywhere in this package.

The files live in the working tree rather than under .git because that is the only place an agent can reliably write: writes under .git prompt or are dropped, and in a git worktree the git directory sits outside the session's working directory entirely. A .gitignore holding "*" inside the directory makes it ignore itself and its contents, so nothing reaches a commit and the repository's own .gitignore is left alone.

Index

Constants

View Source
const (

	// MaxEntries bounds the evidence document against an agent that writes a
	// file per turn. The oldest entries are the ones kept, since what the
	// session started from is the last thing worth dropping.
	MaxEntries = 10
)

Variables

This section is empty.

Functions

func Dir

func Dir(repoRoot string) string

Dir returns the directory holding every session's captured specs.

func EnsureDir

func EnsureDir(repoRoot string) error

EnsureDir creates the spec tree and, if it is absent, the .gitignore that hides it. An existing .gitignore is never rewritten: it is in the user's working tree and may have been adjusted deliberately.

Only the shared parent is created, never the per-session directory. The agent's file-writing tool creates missing parents itself, and creating the session directory here would leave an empty one behind for every session that captures nothing — which is most of them. What must exist up front is the .gitignore, or the first spec written shows up in git status.

func Exists

func Exists(repoRoot, sessionID string) bool

Exists reports whether anything has been captured for a session.

Deliberately cheap: the session-start hook calls it on every start to decide whether to repeat its instruction, so it reads a directory listing and never the files themselves.

func Remove

func Remove(repoRoot, sessionID string) error

Remove drops a session's captured specs, once they are somewhere durable. A session that captured nothing is not an error.

func RemoveDir

func RemoveDir(repoRoot string) error

RemoveDir drops the whole spec tree, and then the .chainloop directory itself when nothing else is left in it. os.Remove fails with ENOTEMPTY otherwise, which is exactly the no-op wanted when that directory holds anything that is not ours.

It starts by checking that .chainloop is a directory at all, which is not redundant: .chainloop is also the basename the CLI gives its .yaml/.yml config, and a plain file carrying the bare name is both something os.Remove would happily delete and something os.RemoveAll would fail a whole cleanup over, since a path below it is then not a directory.

func SessionDir

func SessionDir(repoRoot, sessionID string) string

SessionDir returns the directory a single session's specs are written to.

The session ID is agent-supplied, so it goes through the same sanitisation the trace state store applies: an ID carrying separators names a directory inside Dir rather than escaping to anywhere else in the working tree.

Types

type Capture

type Capture struct {
	// FileName is the base name the agent gave the file. It names the material
	// the text is stored as.
	FileName string
	// Kind is one of the aicodingsession.SpecKind* constants.
	Kind string
	// URI is where the text came from, empty for a spec stated in the session.
	URI string
	// CapturedAt is the file's modification time, RFC3339.
	CapturedAt string
	// Raw is the file as the agent wrote it, header included. It is what
	// gets redacted before anything from the file is stored.
	Raw []byte
	// Verbatim reports a file that is stored exactly as it is on disk: an
	// image, or any file that is not text. The agent copied it into the
	// folder, so it has no header and nothing in it is rewritten.
	Verbatim bool
}

Capture is one spec document as read from the session folder: what the agent wrote, decided on and cleaned up, but not yet stored anywhere.

func Parse

func Parse(doc []byte, capturedAt time.Time) *Capture

Parse converts one spec document into a capture. It never fails.

A spec is the best record we have of what a session was asked to build, and the file is written by a model from a free-text instruction: it will sometimes be malformed. Every degradation below records something rather than nothing, because losing the spec — or failing the push that carries it — is a far worse outcome than recording it imperfectly.

  • No frontmatter, or an unterminated block: the whole document is content, with kind "text" and no URI.
  • Frontmatter that is not valid YAML: the body after the block is content, again with kind "text" and no URI.
  • A kind outside the vocabulary: normalised to "text".

It returns nil when nothing is left once the body is trimmed. That is the common shape of a session with nothing to capture: the agent was told to write nothing at all, and a stray empty file means the same thing.

func ReadAll

func ReadAll(repoRoot, sessionID string) ([]Capture, []string, error)

ReadAll returns the specs captured for a session, oldest first, along with a warning for each file it could not read and for the entries dropped for exceeding MaxEntries.

A session that captured nothing — by far the common case — yields no entries and no error. Individual files that carry nothing are skipped rather than recorded as empty entries. A file that cannot be read costs that file only: the others are still returned. The error is kept for a folder that cannot be read at all.

Jump to

Keyboard shortcuts

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