tool

package
v0.2.0-alpha.8 Latest Latest
Warning

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

Go to latest
Published: Sep 6, 2026 License: Apache-2.0 Imports: 32 Imported by: 0

Documentation

Overview

Package tool provides concrete agent tools. Every runtime gets Read, Write, Edit, Glob, Grep, Bash, WebFetch, TodoWrite, NoteWrite, Skill, Task, and the MCP gateway tools; UploadArtifact, Worktree, GetIssue, ReportToIssue, MemoryRead, MemoryWrite, JobList, JobOutput, JobStop, and Monitor are registered only where the surface can serve them, as the constants below say.

Package tools provides concrete agent tools (e.g. read_file, write_file, webfetch, todowrite).

Package tools provides concrete agent tools (e.g. read_file, write_file, webfetch).

Index

Constants

View Source
const (
	ToolNameLoadMCPTools = "LoadMcpTools"
	ToolNameCallMCPTool  = "CallMcpTool"
)
View Source
const (
	ToolNameRead      = "Read"
	ToolNameWrite     = "Write"
	ToolNameEdit      = "Edit"
	ToolNameGlob      = "Glob"
	ToolNameGrep      = "Grep"
	ToolNameBash      = "Bash"
	ToolNameWebFetch  = "WebFetch"
	ToolNameTodoWrite = "TodoWrite"
	ToolNameNoteWrite = "NoteWrite"
	ToolNameSkill     = "Skill"
	ToolNameTask      = "Task"
	// ToolNameUploadArtifact is registered only where the surface has an
	// artifact service; a session with none does not offer it at all.
	ToolNameUploadArtifact = "UploadArtifact"
	// ToolNameWorktree is registered only where a session may move its own
	// workspace root — the CLI and TUI — and never inside subagents, which
	// share the parent's root for the length of their run.
	ToolNameWorktree = "Worktree"
	// The Issue tools are registered only where the run is working one Issue
	// and can reach it -- a worker run started from an Issue, or a logged-in
	// local session linked to one -- and never inside subagents, which report
	// to their parent rather than to a space's thread. Both are scoped to that
	// one Issue when they are built; neither takes an issue id. See
	// docs/design/issue-agent-access.md.
	ToolNameGetIssue      = "GetIssue"
	ToolNameReportToIssue = "ReportToIssue"
	// The memory tools are registered only on a local primary run whose session
	// belongs to a Project and whose user has not turned memory off. A subagent
	// gets neither, and no index either: it is the highest-volume run in a
	// session, so it would pay the resident cost most often, and a parent that
	// needs it to know something can say so in the delegated task. They are
	// named for the operation rather than the scope, matching NoteWrite and
	// TodoWrite; a second scope would be an argument, not a second pair of
	// tools. See docs/design/local-project-memory.md §9.3 and §9.4.
	ToolNameMemoryRead  = agent.ToolNameMemoryRead
	ToolNameMemoryWrite = agent.ToolNameMemoryWrite
	// The Job tools and Monitor are registered only where local background
	// jobs are enabled (TUI and Desktop), and never inside subagents.
	ToolNameJobList   = "JobList"
	ToolNameJobOutput = "JobOutput"
	ToolNameJobStop   = "JobStop"
	ToolNameMonitor   = "Monitor"
)

Tool name constants — single source of truth for every tool's Name(). Use camelCase for LLM-facing names.

View Source
const (
	GeneralSubAgentPrompt = `` /* 234-byte string literal not displayed */

	ExploreSubAgentPrompt = `` /* 242-byte string literal not displayed */

	ShellSubAgentPrompt = `` /* 194-byte string literal not displayed */
)

Built-in sub-agent system prompts.

View Source
const (
	StatusPending    = agent.TodoPending
	StatusInProgress = agent.TodoInProgress
	StatusCompleted  = agent.TodoCompleted
)

Valid todo statuses. The values live in internal/core/agent, which owns durable session state; these names stay for the tool's own schema and messages.

View Source
const DefaultLimit = 1000

DefaultLimit is the default number of lines returned when limit is not specified.

View Source
const (
	// MaxContentRunes is the maximum runes of fetched content before truncation.
	MaxContentRunes = 200_000
)

Variables

This section is empty.

Functions

func GatewayTools

func GatewayTools(reg *mcp.Registry) []llm.Tool

GatewayTools returns LoadMcpTools and CallMcpTool bound to reg.

func LoadAgentDefs

func LoadAgentDefs(dir string) ([]subagent.Def, error)

LoadAgentDefs reads all files from dir, parses each as an agent definition, and returns the valid definitions sorted alphabetically by Name. If dir does not exist, returns (nil, nil) — not an error. Individual files that fail to parse are skipped with a log warning.

func LoadAgentDefsFromPaths

func LoadAgentDefsFromPaths(dirs []string) ([]subagent.Def, error)

LoadAgentDefsFromPaths loads agent definitions from multiple directories in priority order. Directories are scanned in order; if two directories contain a definition with the same Name, the first one wins (project-level overrides global-level). Missing directories are gracefully skipped. This is the unlabelled form, for a caller with no layering to express.

Types

type AgentDefResolution

type AgentDefResolution struct {
	Defs     []subagent.Def
	Shadowed []plugin.Shadowed
	Findings []plugin.Finding
}

AgentDefResolution is what scanning every source produced: the definitions that load, what a higher layer shadowed, and the collisions that stopped a name from loading at all.

func ResolveAgentDefs

func ResolveAgentDefs(sources []plugin.Source) (AgentDefResolution, error)

ResolveAgentDefs scans priority-ordered sources and reduces them to one definition per name. Sources come from internal/config: workspace, then global, then each plugin in name order.

type AgentTypeConfig

type AgentTypeConfig struct {
	Tools         []llm.Tool // tools available to this agent type
	SystemPrompt  string     // system prompt for the sub-agent
	Description   string     // LLM-readable description of this agent type
	Model         string     // model name to use; "" = runner default
	MaxIterations int        // iteration cap; 0 = defaultSubAgentMaxIter (50)
}

AgentTypeConfig holds the configuration for one agent type (built-in or user-defined).

type AgentTypeToolsAt

type AgentTypeToolsAt func(agentType string, ws util.Workspace) []llm.Tool

AgentTypeToolsAt rebuilds one agent type's tool set against a workspace root. Everything except the root is the set the parent would have used.

type ArtifactPublisher

type ArtifactPublisher interface {
	PublishArtifact(ctx context.Context, in ArtifactUpload) (PublishedArtifact, error)
}

ArtifactPublisher hands one local file to the artifact service.

A port rather than the capability itself: this package must not know whether the file reaches a server over a person's session or over a run token, and must not grow a dependency on the service to find out. A surface that has no implementation does not register the tool — see docs/design/unified-artifacts.md section 7.1.

type ArtifactUpload

type ArtifactUpload struct {
	// Path is the resolved absolute path of a regular, readable file.
	Path string
	// Filename is the name the artifact carries, already reduced to one element.
	Filename string
	Title    string
	// Share asks the server to also create a public link and return it, so an
	// agent can hand a person one link that opens and renders.
	Share bool
}

ArtifactUpload is one file an agent chose to publish.

type Bash

type Bash struct {
	// contains filtered or unexported fields
}

Bash runs a shell command in the workspace (one command per call).

func NewBash

func NewBash(ws util.Workspace) *Bash

NewBash creates a Bash tool that runs commands under the given workspace.

func (*Bash) Access

func (b *Bash) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer.

func (*Bash) CheckArgs

func (b *Bash) CheckArgs(args map[string]any) llm.ToolAction

CheckArgs implements llm.ArgChecker.

Decision order (each step short-circuits):

  1. Catastrophic patterns (rm -rf /, raw dd, mkfs on device) — always Deny.
  2. Risky patterns (curl, npm, sudo, …) — Ask, unless auto-allow applies.

Auto-allow demotes Ask → Allow when:

  • the sandbox is enabled,
  • its mode is auto_allow (config.auto_allow_bash_if_sandboxed),
  • the command would actually be sandboxed (not in excluded_commands),
  • the caller did not pass dangerously_disable_sandbox=true.

Matches Claude Code's documented behavior in /sandboxing: catastrophic destructive commands still prompt even in auto-allow mode; everything else is contained by the OS sandbox boundary.

func (*Bash) DefaultAction

func (b *Bash) DefaultAction() llm.ToolAction

DefaultAction overrides the action derived from Access, leaving CheckArgs above as the only authority on shell commands.

The derived tier is a fallback for tools with no judgement of their own. Bash has one, and a sharper one: catastrophic denies, risky asks, the rest runs. Letting the category default apply on top would prompt for every `ls` and `git status`, which is how a permission prompt becomes something people switch off. See docs/design/tool-permissions.md §6.

func (*Bash) Description

func (b *Bash) Description() string

Description returns a short description so the LLM knows when to use this tool.

func (*Bash) Execute

func (b *Bash) Execute(ctx context.Context, args map[string]any) (string, error)

Execute runs the command in b.root with the given timeout, captures combined stdout+stderr, and returns the result (truncated if needed). On success (exit 0) returns output and nil error. On non-zero exit or timeout returns a clear message and nil error so the LLM receives a readable result. Returns error only for argument validation (missing or empty command).

func (*Bash) Name

func (b *Bash) Name() string

func (*Bash) Parameters

func (b *Bash) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

func (*Bash) WithJobs

func (b *Bash) WithJobs(m *job.Manager) *Bash

WithJobs returns a copy of b that can detach commands to the given job manager. Nil leaves background execution unavailable.

func (*Bash) WithSandbox

func (b *Bash) WithSandbox(v agent.SandboxView) *Bash

WithSandbox returns a copy of b that wraps spawned commands through the given SandboxView. Pass agent.NoopSandbox{} (or nil) to disable. Returning a copy keeps Bash safe to share across goroutines.

type BuiltinSubAgentDef

type BuiltinSubAgentDef struct {
	Name         string
	ToolNames    []string // nil ⇒ all base tools
	SystemPrompt string
	Description  string
}

BuiltinSubAgentDef describes a built-in sub-agent type declaratively. ToolNames lists tool names resolved at runtime; nil means all base tools.

func BuiltinSubAgentDefs

func BuiltinSubAgentDefs() []BuiltinSubAgentDef

BuiltinSubAgentDefs returns the built-in sub-agent types in display order. The returned definitions can be changed without altering later runtimes.

type EditFile

type EditFile struct {
	// contains filtered or unexported fields
}

EditFile performs exact string replacements in a file under a workspace root.

func NewEditFile

func NewEditFile(ws util.Workspace) *EditFile

NewEditFile creates an EditFile tool that edits files under the given workspace root.

func (*EditFile) Access

func (e *EditFile) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer.

func (*EditFile) CheckArgs

func (e *EditFile) CheckArgs(args map[string]any) llm.ToolAction

CheckArgs implements llm.ArgChecker. Editing a sensitive file (credentials, private keys) triggers Ask so the user can confirm intent in interactive sessions.

func (*EditFile) Description

func (e *EditFile) Description() string

Description returns a short description so the LLM knows when to use this tool.

func (*EditFile) Execute

func (e *EditFile) Execute(ctx context.Context, args map[string]any) (string, error)

Execute performs string replacement(s) in the file at args["file_path"]. Reads the file, validates old_string uniqueness when replace_all=false, performs replacement(s), and writes back.

func (*EditFile) Name

func (e *EditFile) Name() string

func (*EditFile) Parameters

func (e *EditFile) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

type GetIssue

type GetIssue struct {
	// contains filtered or unexported fields
}

GetIssue reads the issue this run is working.

func NewGetIssue

func NewGetIssue(client IssueClient) *GetIssue

func (*GetIssue) Access

func (t *GetIssue) Access(_ map[string]any) llm.Access

func (*GetIssue) Description

func (t *GetIssue) Description() string

func (*GetIssue) Execute

func (t *GetIssue) Execute(ctx context.Context, _ map[string]any) (string, error)

func (*GetIssue) Name

func (t *GetIssue) Name() string

func (*GetIssue) Parameters

func (t *GetIssue) Parameters() any

type Glob

type Glob struct {
	// contains filtered or unexported fields
}

Glob lists files matching a glob pattern under a workspace root. Symlinks: doublestar.Glob with WithFilesOnly does not follow symlinks to directories; symlinks to files are included as matches.

func NewGlob

func NewGlob(ws util.Workspace) *Glob

NewGlob creates a Glob tool that searches for files under the given workspace root.

func (*Glob) Access

func (g *Glob) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer.

func (*Glob) Description

func (g *Glob) Description() string

Description returns a short description so the LLM knows when to use this tool.

func (*Glob) Execute

func (g *Glob) Execute(ctx context.Context, args map[string]any) (string, error)

Execute lists files under the search directory that match the pattern, sorted by modification time (newest first). Returns one absolute path per line, or "No files matched the pattern.", or an error for validation/system failures.

func (*Glob) Name

func (g *Glob) Name() string

func (*Glob) Parameters

func (g *Glob) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

type Grep

type Grep struct {
	// contains filtered or unexported fields
}

Grep searches file contents by regex pattern under a workspace root.

func NewGrep

func NewGrep(ws util.Workspace) *Grep

NewGrep creates a Grep tool that searches file contents under the given workspace root.

func (*Grep) Access

func (g *Grep) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer.

func (*Grep) CheckArgs

func (g *Grep) CheckArgs(args map[string]any) llm.ToolAction

CheckArgs implements llm.ArgChecker. Grepping inside a sensitive file (credentials, private keys) triggers Ask so the user can confirm intent in interactive sessions.

func (*Grep) Description

func (g *Grep) Description() string

Description returns a short description so the LLM knows when to use this tool.

func (*Grep) Execute

func (g *Grep) Execute(ctx context.Context, args map[string]any) (string, error)

Execute searches file contents under the tool's root for the given regex pattern. Returns formatted results based on output_mode, or "No matches found.", or an error.

func (*Grep) Name

func (g *Grep) Name() string

func (*Grep) Parameters

func (g *Grep) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

type IssueChild

type IssueChild struct {
	Title  string
	Status string
}

IssueChild is one sub-issue, as title and status. Not the child's own description: a parent's agent needs to know what was split out, not to read the whole subtree into its context.

type IssueClient

type IssueClient interface {
	Issue(ctx context.Context) (IssueSnapshot, error)
	Report(ctx context.Context, in IssueReport) error
}

IssueClient reads and reports on the one Issue a run is working.

A port rather than the capability itself: this package must not learn whether the call reaches a server over a run token, a person's session, or an in-process service, and must not grow a dependency on the issue service to find out. A surface with no implementation does not register the tools -- see docs/design/issue-agent-access.md section 8.

There is no issue identifier in either method. The scope is fixed when the client is constructed, so the model cannot address a second issue; that is a decision, not an omission, and section 5.3 says why.

type IssueComment

type IssueComment struct {
	AuthorKind string
	Body       string
	CreatedAt  time.Time
}

IssueComment is one statement on the thread. AuthorKind is carried because a model that cannot tell a spacemate's comment from its own principal's instruction has no basis for treating them differently.

type IssueReport

type IssueReport struct {
	Body string
	// ArtifactIDs names artifacts the run already published. Naming, not
	// attaching: the artifact exists under its own identity, and repeating an
	// object-store path in a comment would create a second, weaker reference.
	ArtifactIDs []string
}

IssueReport is one statement an agent makes about the work it did.

type IssueSnapshot

type IssueSnapshot struct {
	Title        string
	Description  string
	Status       string
	AssigneeKind string
	Children     []IssueChild
	Comments     []IssueComment
	// OmittedComments is how many older comments the window left out, so the
	// agent can say the thread is longer than what it read instead of assuming
	// it saw all of it.
	OmittedComments int
}

IssueSnapshot is the bounded view of the one Issue a run is working.

type JobList

type JobList struct {
	// contains filtered or unexported fields
}

JobList lists this runtime's background jobs.

func NewJobList

func NewJobList(m *job.Manager) *JobList

func (*JobList) Access

func (j *JobList) Access(_ map[string]any) llm.Access

func (*JobList) Description

func (j *JobList) Description() string

func (*JobList) Execute

func (j *JobList) Execute(_ context.Context, _ map[string]any) (string, error)

func (*JobList) Name

func (j *JobList) Name() string

func (*JobList) Parameters

func (j *JobList) Parameters() any

type JobOutput

type JobOutput struct {
	// contains filtered or unexported fields
}

JobOutput reports one job's status and incremental output.

func NewJobOutput

func NewJobOutput(m *job.Manager) *JobOutput

func (*JobOutput) Access

func (j *JobOutput) Access(_ map[string]any) llm.Access

func (*JobOutput) Description

func (j *JobOutput) Description() string

func (*JobOutput) Execute

func (j *JobOutput) Execute(_ context.Context, args map[string]any) (string, error)

func (*JobOutput) Name

func (j *JobOutput) Name() string

func (*JobOutput) Parameters

func (j *JobOutput) Parameters() any

type JobStop

type JobStop struct {
	// contains filtered or unexported fields
}

JobStop stops one background job.

func NewJobStop

func NewJobStop(m *job.Manager) *JobStop

func (*JobStop) Access

func (j *JobStop) Access(_ map[string]any) llm.Access

Access declares write: stopping changes state. DefaultAction keeps it prompt-free — it only ever terminates jobs this runtime itself started, which the user can equally do from the activity view.

func (*JobStop) DefaultAction

func (j *JobStop) DefaultAction() llm.ToolAction

func (*JobStop) Description

func (j *JobStop) Description() string

func (*JobStop) Execute

func (j *JobStop) Execute(_ context.Context, args map[string]any) (string, error)

func (*JobStop) Name

func (j *JobStop) Name() string

func (*JobStop) Parameters

func (j *JobStop) Parameters() any

type MemoryRead

type MemoryRead struct{}

MemoryRead returns the bodies behind index lines.

func NewMemoryRead

func NewMemoryRead() *MemoryRead

NewMemoryRead creates a MemoryRead tool.

func (*MemoryRead) Access

func (t *MemoryRead) Access(_ map[string]any) llm.Access

Access implements llm.AccessDeclarer. Reading changes nothing the user owns.

func (*MemoryRead) DefaultAction

func (t *MemoryRead) DefaultAction() llm.ToolAction

DefaultAction implements llm.PolicyProvider. The content is the agent's own recall, kept under BUILDMAX_HOME, and a prompt to read it would arrive on every run for no decision the user could usefully make.

func (*MemoryRead) Description

func (t *MemoryRead) Description() string

func (*MemoryRead) Execute

func (t *MemoryRead) Execute(ctx context.Context, args map[string]any) (string, error)

Execute returns the requested bodies.

func (*MemoryRead) Name

func (t *MemoryRead) Name() string

func (*MemoryRead) Parameters

func (t *MemoryRead) Parameters() any

type MemoryWrite

type MemoryWrite struct{}

MemoryWrite creates or replaces exactly one memory.

Unlike a note, this outlives the session. That is the whole value and the whole risk: a missed memory costs convenience, while a false or sensitive one misleads every future run in the project.

func NewMemoryWrite

func NewMemoryWrite() *MemoryWrite

NewMemoryWrite creates a MemoryWrite tool.

func (*MemoryWrite) Access

func (t *MemoryWrite) Access(_ map[string]any) llm.Access

Access implements llm.AccessDeclarer. Declaring it a write is what keeps two calls in one batch from racing each other into the store's lock.

func (*MemoryWrite) DefaultAction

func (t *MemoryWrite) DefaultAction() llm.ToolAction

DefaultAction implements llm.PolicyProvider.

What this writes is the agent's own recall, kept under BUILDMAX_HOME and never in the user's repository, so a prompt on every call would be noise. The user's controls are the ones that matter and they are outside the model: the memories are theirs to read, edit, delete, or switch off for a run.

func (*MemoryWrite) Description

func (t *MemoryWrite) Description() string

Description is the behavioural contract. Without the "do not keep" half, the store fills with restated code and task narration, and every future session in the project pays for both.

func (*MemoryWrite) Execute

func (t *MemoryWrite) Execute(ctx context.Context, args map[string]any) (string, error)

Execute writes or deletes one memory.

func (*MemoryWrite) Name

func (t *MemoryWrite) Name() string

func (*MemoryWrite) Parameters

func (t *MemoryWrite) Parameters() any

type Monitor

type Monitor struct {
	// contains filtered or unexported fields
}

Monitor starts an event watcher: a command expected to stay quiet until something worth delivering happens, whose stdout lines become bounded events. It is a specialized command job, not a second scheduler, and it reuses Bash's argument risk, permission, sandbox, and environment rules — watching is not a way around them.

func NewMonitor

func NewMonitor(ws util.Workspace) *Monitor

NewMonitor creates a Monitor for the given workspace.

func (*Monitor) Access

func (m *Monitor) Access(_ map[string]any) llm.Access

Access declares write: a monitor spawns a process.

func (*Monitor) CheckArgs

func (m *Monitor) CheckArgs(args map[string]any) llm.ToolAction

CheckArgs applies Bash's command risk classification to the watched command: catastrophic denies, risky asks, the rest runs.

func (*Monitor) DefaultAction

func (m *Monitor) DefaultAction() llm.ToolAction

DefaultAction defers to CheckArgs, the same authority Bash uses.

func (*Monitor) Description

func (m *Monitor) Description() string

func (*Monitor) Execute

func (m *Monitor) Execute(ctx context.Context, args map[string]any) (string, error)

func (*Monitor) Name

func (m *Monitor) Name() string

func (*Monitor) Parameters

func (m *Monitor) Parameters() any

func (*Monitor) WithJobs

func (m *Monitor) WithJobs(j *job.Manager) *Monitor

WithJobs returns a copy that can start monitor jobs. Nil leaves the tool non-functional; surfaces without jobs do not register it at all.

func (*Monitor) WithSandbox

func (m *Monitor) WithSandbox(v agent.SandboxView) *Monitor

WithSandbox returns a copy whose command resolution wraps through the given SandboxView, exactly as Bash does.

type NoteWrite

type NoteWrite struct{}

NoteWrite records durable session notes. Unlike a tool result, a note is not a message: it survives history compaction and is re-rendered on every model call, so it is where the agent keeps what the conversation cannot be trusted to hold.

The store is reached through the context rather than held on the tool, because the tool registry is cached per model and shared across sessions.

func NewNoteWrite

func NewNoteWrite() *NoteWrite

NewNoteWrite creates a NoteWrite tool.

func (*NoteWrite) Access

func (t *NoteWrite) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer. Session notes have no lock, so this is a write and cannot run concurrently with a sibling call.

func (*NoteWrite) DefaultAction

func (t *NoteWrite) DefaultAction() llm.ToolAction

DefaultAction implements llm.PolicyProvider, overriding the action the permission layer would otherwise derive from Access.

What this writes is the agent's own scratch state, not anything the user owns. Asking a user to approve the agent taking a note would be noise, and the noise would arrive on every run. The write classification above is still the honest one — it is what keeps this tool out of a parallel batch. See docs/design/tool-permissions.md §5.2.

func (*NoteWrite) Description

func (t *NoteWrite) Description() string

Description tells the LLM what belongs in a note. The behavioural contract matters more than the name here: without a stated rule the list fills with narration and duplicated context.

func (*NoteWrite) Execute

func (t *NoteWrite) Execute(ctx context.Context, args map[string]any) (string, error)

Execute replaces the session's notes with the given list.

func (*NoteWrite) Name

func (t *NoteWrite) Name() string

func (*NoteWrite) Parameters

func (t *NoteWrite) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

type PublishedArtifact

type PublishedArtifact struct {
	ArtifactID string
	Filename   string
	SizeBytes  int64
	// URL is where an authorized person opens it. Empty when the surface knows
	// the id but not the address to render it at.
	URL string
	// ShareURL is a public link anyone can open, set only when Share was asked
	// for and the server created one. ShareDownloadURL is its raw-download form.
	ShareURL         string
	ShareDownloadURL string
	// ShareError explains why a requested link could not be made. The artifact
	// still published; only the link is missing.
	ShareError string
}

PublishedArtifact is what the artifact service made of it.

type ReadFile

type ReadFile struct {
	// contains filtered or unexported fields
}

ReadFile reads a local file under a workspace root.

func NewReadFile

func NewReadFile(ws util.Workspace) *ReadFile

NewReadFile creates a ReadFile tool that reads files under the given workspace root.

func (*ReadFile) Access

func (r *ReadFile) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer.

func (*ReadFile) CheckArgs

func (r *ReadFile) CheckArgs(args map[string]any) llm.ToolAction

CheckArgs implements llm.ArgChecker. Reading a sensitive file (credentials, private keys) triggers Ask so the user can confirm intent in interactive sessions.

func (*ReadFile) Description

func (r *ReadFile) Description() string

Description returns a short description so the LLM knows when to use this tool.

func (*ReadFile) Execute

func (r *ReadFile) Execute(ctx context.Context, args map[string]any) (string, error)

Execute reads the file at args["file_path"] if it is under the tool's root. File contents are returned as UTF-8 text; invalid UTF-8 in the file is passed through as-is.

func (*ReadFile) Name

func (r *ReadFile) Name() string

func (*ReadFile) Parameters

func (r *ReadFile) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

type ReportToIssue

type ReportToIssue struct {
	// contains filtered or unexported fields
}

ReportToIssue posts one comment on the issue this run is working.

func NewReportToIssue

func NewReportToIssue(client IssueClient) *ReportToIssue

func (*ReportToIssue) Access

func (t *ReportToIssue) Access(_ map[string]any) llm.Access

func (*ReportToIssue) Description

func (t *ReportToIssue) Description() string

func (*ReportToIssue) Execute

func (t *ReportToIssue) Execute(ctx context.Context, args map[string]any) (string, error)

func (*ReportToIssue) Name

func (t *ReportToIssue) Name() string

func (*ReportToIssue) Parameters

func (t *ReportToIssue) Parameters() any

type SkillEntry

type SkillEntry struct {
	Name        string // skill identifier (directory name)
	Description string // short description extracted from SKILL.md
	Path        string // absolute path to the SKILL.md file
	// Origin is the layer this skill was found in. Status surfaces it so a
	// plugin's contribution is visible, and so is anything that shadowed it.
	Origin plugin.Origin
}

SkillEntry holds metadata for one discovered skill.

func DiscoverSkillEntries

func DiscoverSkillEntries(searchPaths []string) []SkillEntry

DiscoverSkillEntries scans search paths for subdirectories containing SKILL.md. First-path-wins on name conflicts. Returns skills sorted alphabetically by name. This is the unlabelled form, for a caller with no layering to express.

type SkillResolution

type SkillResolution struct {
	Entries  []SkillEntry
	Shadowed []plugin.Shadowed
	Findings []plugin.Finding
}

SkillResolution is what scanning every source produced: the skills that load, the definitions a higher layer shadowed, and the collisions that stopped a name from loading at all.

func ResolveSkills

func ResolveSkills(sources []plugin.Source) SkillResolution

ResolveSkills scans priority-ordered sources and reduces them to one skill per name. Sources come from internal/config: workspace, then global, then each plugin in name order.

type SkillTool

type SkillTool struct {
	// contains filtered or unexported fields
}

SkillTool is an agent tool that discovers and invokes skills from disk. It implements agent.Tool.

func NewSkill

func NewSkill(searchPaths []string) *SkillTool

NewSkill creates a SkillTool that discovers skills from the given search paths. Each search path is scanned one level deep for subdirectories containing a SKILL.md file. Missing directories are silently skipped. If multiple search paths contain a skill with the same name, the first one found wins (search paths are priority-ordered).

func NewSkillFromEntries

func NewSkillFromEntries(entries []SkillEntry) *SkillTool

NewSkillFromEntries creates a SkillTool from pre-discovered skill entries. The provided entries are copied so callers can treat the returned tool as immutable.

func (*SkillTool) Access

func (s *SkillTool) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer.

func (*SkillTool) Description

func (s *SkillTool) Description() string

Description returns a static preamble followed by a dynamic listing of discovered skills.

func (*SkillTool) Execute

func (s *SkillTool) Execute(ctx context.Context, args map[string]any) (string, error)

Execute looks up the requested skill, reads its SKILL.md file, and returns the content. If args is provided, it is prepended as context.

func (*SkillTool) Name

func (s *SkillTool) Name() string

func (*SkillTool) Parameters

func (s *SkillTool) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

type SubAgentRunOpts

type SubAgentRunOpts struct {
	Tools        []llm.Tool
	SystemPrompt string
	Description  string
	MaxIter      int    // 0 = defaultSubAgentMaxIter
	Model        string // "" = use runner default client
}

SubAgentRunOpts configures one sub-agent invocation.

type SubAgentRunner

type SubAgentRunner interface {
	RunSubAgent(ctx context.Context, opts SubAgentRunOpts, prompt string) (reply string, err error)
}

SubAgentRunner runs a sub-agent with the given options and prompt. It is implemented by agentapp and injected when building the Task tool so that tools do not depend on a concrete runner; tests can inject a mock.

func NewDefaultSubAgentRunner

func NewDefaultSubAgentRunner(llmClient llm.LLMClient, policy coreagent.ToolPolicy, modelResolver func(string) (llm.LLMClient, error), opts ...SubAgentRunnerOption) (SubAgentRunner, error)

NewDefaultSubAgentRunner returns a SubAgentRunner backed by the given LLM client. policy is inherited from the parent agent run (nil = AllowAll). modelResolver looks up an LLM client by model name for agent types that specify a model; nil means always use client regardless of the model field.

type SubAgentRunnerOption

type SubAgentRunnerOption func(*defaultSubAgentRunner)

SubAgentRunnerOption configures a SubAgentRunner.

func WithSubAgentHooks

func WithSubAgentHooks(h coreagent.HookRunner) SubAgentRunnerOption

WithSubAgentHooks attaches a parent hook runner so subagent runs honor the same PreToolUse / PostToolUse / lifecycle hooks as the parent agent. Nil disables hooks.

func WithSubAgentMaxParallelTools

func WithSubAgentMaxParallelTools(n int) SubAgentRunnerOption

WithSubAgentMaxParallelTools gives sub-agent runs the same tool-scheduling limit as the parent. Without it a sub-agent runs every call sequentially, which loses the setting exactly where it pays best: an exploration agent batches reads and searches for a living.

func WithSubAgentSessionFactory

func WithSubAgentSessionFactory(f SubAgentSessionFactory) SubAgentRunnerOption

WithSubAgentSessionFactory supplies the private session each subagent run gets. Without it, subagent history is in-memory and discarded on return.

func WithSubAgentTraceFactory

func WithSubAgentTraceFactory(factory SubAgentTraceFactory) SubAgentRunnerOption

WithSubAgentTraceFactory attaches durable trace creation at the assembly layer. A nil factory leaves subagent execution unchanged.

type SubAgentSession

type SubAgentSession interface {
	coreagent.NotesHistory
	coreagent.CompactionHistory
	ID() string
	Close() error
}

SubAgentSession is one subagent's own conversation: everything the loop needs to read and commit history, plus the identity and close it needs to be a durable session rather than a scratch buffer.

It is an interface here for the same reason SubAgentTrace is: this package sits below infra, so it says what it needs and lets agentapp supply the durable implementation.

type SubAgentSessionFactory

type SubAgentSessionFactory func(ctx context.Context, opts SubAgentRunOpts) (SubAgentSession, error)

SubAgentSessionFactory creates the private session for one subagent run.

§9 of the local session storage plan gives every subagent its own hidden bundle: it must never write into the parent's journal or durable state, and the parent's Task result stays the model-facing return path. A nil factory falls back to an in-memory session, which is what a test or an embedder with no store gets.

type SubAgentTrace

type SubAgentTrace interface {
	Record(coreagent.Event)
	Close() error
}

SubAgentTrace receives the event stream for one subagent run. It is kept as a small interface so this package stays below infra: agentapp supplies the durable trace implementation without making the tool layer know where or how traces are stored.

type SubAgentTraceFactory

type SubAgentTraceFactory func(ctx context.Context, sessionID string, opts SubAgentRunOpts) SubAgentTrace

SubAgentTraceFactory opens a trace for a subagent run. sessionID is the session the trace is filed under — the parent's, so a subagent's diagnostics stay reachable from a session a person can still find. Returning nil disables only this trace; the subagent must still run.

type TaskTool

type TaskTool struct {
	// contains filtered or unexported fields
}

TaskTool is an agent tool that spawns sub-agents to handle complex subtasks. It implements llm.Tool.

func NewTask

func NewTask(runner SubAgentRunner, agentTypes map[string]AgentTypeConfig) (*TaskTool, error)

NewTask creates a TaskTool with the given sub-agent runner and agent type configurations. runner must not be nil; agentTypes must have at least one entry.

func (*TaskTool) Access

func (t *TaskTool) Access(args map[string]any) llm.Access

Access implements llm.AccessDeclarer. A sub-agent writes whatever its tools write, so the answer is the requested type's tool set rather than the Task tool itself: a type restricted to read-only tools runs a nested loop that cannot write, and may overlap its neighbours.

Everything else is a write — an unknown type, a background run (which mutates the job manager and outlives the call), and a nil-args capability listing, which is asking about the tool and not about a call.

func (*TaskTool) Description

func (t *TaskTool) Description() string

Description returns a dynamically built description listing all available agent types.

func (*TaskTool) Execute

func (t *TaskTool) Execute(ctx context.Context, args map[string]any) (string, error)

Execute spawns a sub-agent of the requested type, runs the prompt, and returns the reply.

func (*TaskTool) Name

func (t *TaskTool) Name() string

func (*TaskTool) Parameters

func (t *TaskTool) Parameters() any

Parameters returns the OpenAI-style JSON schema with a dynamic enum for subagent_type.

func (*TaskTool) WithJobs

func (t *TaskTool) WithJobs(m *job.Manager, workspace util.Workspace) *TaskTool

WithJobs returns a copy of t that can detach subagents to the given job manager. Nil leaves background execution unavailable.

func (*TaskTool) WithWorktrees

func (t *TaskTool) WithWorktrees(m *worktree.Manager, toolsAt AgentTypeToolsAt) *TaskTool

WithWorktrees returns a copy of t that can give a delegate its own worktree.

Offered, never imposed: nothing forces one worktree per subagent, and the model decides per delegation whether the isolation is worth a tree the user will have to clean up by hand. See docs/design/workspace-root-and-worktrees.md D7.

type TodoWrite

type TodoWrite struct{}

TodoWrite records the task list the LLM uses to trace progress.

The list is durable session state, not a message: it survives history compaction and is re-rendered on every model call. It is stored through the context, because the tool registry is cached per model and shared across sessions. A run with no store — a subagent, for instance — still gets a formatted list back, and is told the list was not kept.

func NewTodoWrite

func NewTodoWrite() *TodoWrite

NewTodoWrite creates a TodoWrite tool.

func (*TodoWrite) Access

func (t *TodoWrite) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer. Session task list has no lock, so this is a write and cannot run concurrently with a sibling call.

func (*TodoWrite) DefaultAction

func (t *TodoWrite) DefaultAction() llm.ToolAction

DefaultAction implements llm.PolicyProvider, overriding the action the permission layer would otherwise derive from Access.

What this writes is the agent's own scratch state, not anything the user owns. Asking a user to approve the agent taking a note would be noise, and the noise would arrive on every run. The write classification above is still the honest one — it is what keeps this tool out of a parallel batch. See docs/design/tool-permissions.md §5.2.

func (*TodoWrite) Description

func (t *TodoWrite) Description() string

Description returns a short description so the LLM knows when to use this tool.

func (*TodoWrite) Execute

func (t *TodoWrite) Execute(ctx context.Context, args map[string]any) (string, error)

Execute parses and validates todos from args, stores them on the session when the run keeps durable state, and returns a formatted list for the LLM.

func (*TodoWrite) Name

func (t *TodoWrite) Name() string

func (*TodoWrite) Parameters

func (t *TodoWrite) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

type UploadArtifact

type UploadArtifact struct {
	// contains filtered or unexported fields
}

UploadArtifact publishes one file the agent names as a durable artifact.

func NewUploadArtifact

func NewUploadArtifact(ws util.Workspace, publisher ArtifactPublisher) *UploadArtifact

NewUploadArtifact creates the tool. It is only ever constructed where a publisher exists; see agentapp's tool assembly.

func (*UploadArtifact) Description

func (t *UploadArtifact) Description() string

Description states the choosing rule, not just the mechanics.

Without it the tool is used as a save button and the space's artifact list fills with intermediate files. What the model has to understand is that this publishes, once, the file a person is meant to receive.

func (*UploadArtifact) Execute

func (t *UploadArtifact) Execute(ctx context.Context, args map[string]any) (string, error)

Execute validates the file, publishes it, and reports the reference.

func (*UploadArtifact) Name

func (t *UploadArtifact) Name() string

func (*UploadArtifact) Parameters

func (t *UploadArtifact) Parameters() any

type WebFetch

type WebFetch struct {
	// contains filtered or unexported fields
}

WebFetch is a tool that fetches a URL, converts HTML to markdown, optionally processes content with the LLM using a prompt, and returns the result. It implements the llm.Tool interface.

func NewWebFetch

func NewWebFetch(llmClient llm.LLMClient, cacheTTL time.Duration) *WebFetch

NewWebFetch creates a WebFetch tool with the given LLM client and cache TTL. llmClient may be nil: fetching without a "prompt" argument still works; if "prompt" is set, Execute returns an error until a non-nil client is provided.

func (*WebFetch) Access

func (w *WebFetch) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer. The only thing it writes is its own response cache, which cacheMu guards.

func (*WebFetch) Description

func (w *WebFetch) Description() string

Description returns a short description so the LLM knows when to use this tool.

func (*WebFetch) Execute

func (w *WebFetch) Execute(ctx context.Context, args map[string]any) (string, error)

Execute fetches the URL, converts HTML to markdown, optionally calls the LLM with content+prompt, and returns the result.

func (*WebFetch) Name

func (w *WebFetch) Name() string

func (*WebFetch) Parameters

func (w *WebFetch) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

func (*WebFetch) WithSandbox

func (w *WebFetch) WithSandbox(v agent.SandboxView) *WebFetch

WithSandbox installs v as the host filter on w and returns w. Mutates in place because WebFetch holds shared cache state behind a mutex — copying would split the cache. Pass agent.NoopSandbox{} (or nil) to disable enforcement.

type Worktree

type Worktree struct {
	// contains filtered or unexported fields
}

Worktree creates, enters, leaves, lists, and removes Git worktrees, moving the session's workspace root as it goes.

Every other tool then follows: the point of the tool is that after entering, nothing needs a path prefix or a different call. See docs/design/workspace-root-and-worktrees.md.

func NewWorktree

func NewWorktree(m *worktree.Manager) *Worktree

NewWorktree creates the tool over a worktree manager. Nil leaves the tool off the surface entirely rather than present and always failing.

func (*Worktree) Access

func (w *Worktree) Access(args map[string]any) llm.Access

Access reports what each action does to the workspace, so the permission tier is derived from the action rather than from the tool.

Creating and entering are ordinary writes: a new directory on a new branch interrupts nobody, and that autonomy is the point. Removing can destroy the only copy of work, so it asks — see CheckArgs and docs/design/workspace-root-and-worktrees.md D4.

func (*Worktree) CheckArgs

func (w *Worktree) CheckArgs(args map[string]any) llm.ToolAction

CheckArgs makes removal ask while the rest runs.

func (*Worktree) Description

func (w *Worktree) Description() string

func (*Worktree) Execute

func (w *Worktree) Execute(ctx context.Context, args map[string]any) (string, error)

func (*Worktree) Name

func (w *Worktree) Name() string

func (*Worktree) Parameters

func (w *Worktree) Parameters() any

type WriteFile

type WriteFile struct {
	// contains filtered or unexported fields
}

WriteFile writes content to a local file under a workspace root.

func NewWriteFile

func NewWriteFile(ws util.Workspace) *WriteFile

NewWriteFile creates a WriteFile tool that writes files under the given workspace root.

func (*WriteFile) Access

func (w *WriteFile) Access(_ map[string]any) llm.Access

Name returns the tool name for the LLM. Access implements llm.AccessDeclarer.

func (*WriteFile) CheckArgs

func (w *WriteFile) CheckArgs(args map[string]any) llm.ToolAction

CheckArgs implements llm.ArgChecker. Writing to a sensitive file (credentials, private keys) triggers Ask so the user can confirm intent in interactive sessions.

func (*WriteFile) Description

func (w *WriteFile) Description() string

Description returns a short description so the LLM knows when to use this tool.

func (*WriteFile) Execute

func (w *WriteFile) Execute(ctx context.Context, args map[string]any) (string, error)

Execute writes args["content"] to the file at args["file_path"] if the path is under the tool's root. Creates parent directories if needed; overwrites if the file exists. Returns a short success message or error.

func (*WriteFile) Name

func (w *WriteFile) Name() string

func (*WriteFile) Parameters

func (w *WriteFile) Parameters() any

Parameters returns the OpenAI-style JSON schema for the tool arguments.

Jump to

Keyboard shortcuts

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