agentsmd

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Sep 21, 2026 License: MIT Imports: 6 Imported by: 1

README

agentsmd

The AGENTS.md convention for Go agents: the instruction files that apply at a path, found from its directory up to a root, one per directory, nearest last, and rendered into the text a product puts in its instructions. The nearest file is the last one written and wins. The module imports the standard library alone.

res, err := agentsmd.Chain(cwd, agentsmd.Options{
	Names:  []string{"AGENTS.override.md", "AGENTS.md"},
	Root:   repoRoot,
	Extra:  []string{filepath.Join(home, ".dex", "AGENTS.md")},
	Budget: 32 << 10,
})
if err != nil {
	return err
}
for _, o := range res.Omitted {
	log.Printf("%s (%d bytes): %s", o.Path, o.Size, o.Reason) // shadowed or over budget
}
cfg.Instructions = agentsmd.Render(res.Files)

Chain returns Extra first, then walks from the path's directory to Root, takes in each directory the first of Names that exists, and returns those files farthest first and nearest last, so that later text refines earlier text. Extra comes first because a file outside the tree, such as the user's own in their home directory, is the farthest of the lot: Codex reads ~/.codex/AGENTS.md before the repository's files for that reason, and the repository's nearest file still has the last word. Budget caps the total and is spent in that same order: the first file that would exceed it ends the chain, nothing is cut short, and running out is not an error. Every file found and left out, shadowed by a preferred name or over budget, is in Result.Omitted with its size and its path, so a product can tell the user and a session can record what the model was not given as well as what it was.

Render wraps the files as pi renders <project_context>: one <project_instructions path="..."> per file, in order. The result is one instructions part, identified by agentsmd.PartID: a product that records what the model was given in parts rather than as one string hands it the whole rendering under that id, and names a file it considered and left out by that file's Omitted.Path.

The package is about a repository checkout on the local file system. It does not expand imports inside files, know any file name specially, or fetch anything; a product with a remote checkout hands its files to Render itself.

Development

make check    # gofmt, tidy, vet, deps, staticcheck, govulncheck, race tests

The fixture tree is testdata/tree; the golden render is testdata/golden/render.txt, regenerated with go test . -update.

Documentation

Overview

Package agentsmd finds and renders the instruction files of the AGENTS.md convention: the files that apply at a path are the ones in its directory and every ancestor, one per directory, and the nearest takes precedence.

Chain collects them farthest first and nearest last, so that when a product includes every file, later text refines earlier text, and says which files it found and left out, so a product can record or show exactly what the model was given and what it was not. Explicit paths, such as the user's own file outside the tree, come before the chain, since the nearest file is the one that wins. Render wraps the files the way pi renders project context, one project_instructions element per file inside project_context. The package imports the standard library alone.

Index

Constants

View Source
const DefaultMaxBytes = 1 << 20

DefaultMaxBytes is the size above which a file is an error.

View Source
const PartID = "agentsmd"

PartID is the stable identifier of the one instructions part Render produces, for a product that records what the model was given as parts rather than as one string. The text of the part changes whenever the working directory moves or a file is edited; the identifier does not, so a reader can tell that this part moved and the others did not. A file considered and left out is named by its own Omitted.Path.

Variables

View Source
var DefaultNames = []string{"AGENTS.md"}

DefaultNames is the file name Chain looks for when Options.Names is empty.

View Source
var ErrTooLarge = errors.New("agentsmd: file exceeds size limit")

ErrTooLarge is wrapped in the error of a file over MaxBytes.

Functions

func Render

func Render(files []File) string

Render wraps the files as pi does: one project_instructions element per file, with its path as the attribute, inside project_context, in order, so the nearest file is last and refines the rest. No files render as the empty string.

The result is one instructions part, whose identifier is PartID: a product that hands its instructions to a session in parts hands it this whole string under that id, not one part per file.

Types

type File

type File struct {
	// Path is absolute.
	Path string
	// Content is the file's bytes as a string.
	Content string
}

File is one instruction file, read verbatim.

type Omitted

type Omitted struct {
	// Path is absolute, and is the omitted file's stable key.
	Path string
	// Size is the file's size in bytes.
	Size int64
	// Reason says why the file is not in [Result.Files].
	Reason Reason
	// By is the path of the file that took this one's place, for
	// [Shadowed]; "" otherwise.
	By string
}

Omitted is one file Chain found and left out. A product recording what the model was given as parts, beside the part Render produces, names an omitted file by its Path, which is the stable key for the file across runs.

type Options

type Options struct {
	// Names are the file names looked for in each directory, in order
	// of preference: the first one found is that directory's file and
	// the rest are not read, so a product can let AGENTS.override.md
	// shadow AGENTS.md, or CLAUDE.md stand in where AGENTS.md is
	// absent, as Codex reads them. Empty means [DefaultNames].
	Names []string
	// Root is the directory the walk stops after. Empty means the
	// file system root. A path outside Root is an error.
	Root string
	// Extra are explicit paths included before the chain, in order,
	// such as the user's own file in their home directory, which the
	// repository's files then refine. Missing ones are skipped.
	//
	// They come first because the convention is that the nearest file
	// wins, and a file that is not in the tree at all is the farthest
	// of the lot: Codex reads ~/.codex/AGENTS.md first for that
	// reason. They are also the first charge on Budget, as they are
	// there.
	Extra []string
	// MaxBytes bounds one file; zero means [DefaultMaxBytes]. A larger
	// file is an error, because a truncated instruction file would
	// silently change what the model is told.
	MaxBytes int64
	// Budget bounds the total bytes of every file returned. The first
	// file that would take the total over it, and every file after
	// it, is left out and reported in [Result.Omitted], and Chain
	// returns what fits without error, so a large file deep in a tree
	// degrades the prompt rather than failing the run. No file is cut
	// short. Zero means no budget.
	Budget int64
}

Options configure Chain.

type Reason

type Reason int

Reason is why Chain left a file out.

const (
	// OverBudget: the file, or one before it, would have taken the
	// total over Options.Budget, and the chain ends at the first such
	// file.
	OverBudget Reason = iota
	// Shadowed: an earlier name in Options.Names exists in the same
	// directory and stands for it.
	Shadowed
)

func (Reason) String

func (r Reason) String() string

String returns "over budget" or "shadowed".

type Result

type Result struct {
	// Files are the instruction files to include: Options.Extra first,
	// then the chain farthest first and nearest last, so the nearest
	// file is the last text the model reads and wins.
	Files []File
	// Omitted are the files Chain found and did not include, in the
	// order it met them.
	Omitted []Omitted
}

Result is what Chain found: the files that apply, in order, and the files it saw and left out, so a product can record or show exactly what the model was given and what it was not.

func Chain

func Chain(path string, opts Options) (Result, error)

Chain returns the instruction files that apply at path: opts.Extra in order, then, in path's directory and each of its ancestors up to opts.Root, the first file of opts.Names that exists, farthest first and nearest last, within opts.Budget. A file found and not included, because a preferred name shadows it or the budget is spent, is in Result.Omitted; only a file that would be included is read, and only such a file over opts.MaxBytes is an error. path may be a directory, an existing file, or a file about to be created, whose directory is then the start.

Jump to

Keyboard shortcuts

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