Documentation
¶
Overview ¶
Package tools: grep is a pure-Go recursive search over the workspace — no dependency on an external ripgrep/grep binary being installed, in keeping with Kram's "never crash / always works" goal. It costs some performance on very large trees versus a real ripgrep, which is an accepted v0 trade-off.
Package tools: LSP tools give the model real semantic navigation (diagnostics, go-to-definition, find-references) on top of the grep/glob/read_file tools, which find text but don't understand structure. Backed by internal/lsp, which lazily starts one language server per language the first time it's needed and reuses that connection afterward.
Package tools is the daemon's tool registry: the concrete capabilities (file I/O, search, shell) the agent loop can call, each scoped to a session's workspace directory so a tool call can never read or write outside the project it was invoked for.
Index ¶
- Constants
- func OrderToolNames(visible []string, order []string) []string
- func StartedBackgroundProcessID(result string) string
- func UnknownToolOrderNames(order []string, known map[string]bool) []string
- func ValidateToolOrder(order []string) error
- func WithApprover(ctx context.Context, a Approver) context.Context
- func WithAsker(ctx context.Context, a Asker) context.Context
- func WithDepth(ctx context.Context, depth int) context.Context
- type ApprovalDecision
- type Approver
- type Asker
- type BackgroundProcessInfo
- type BackgroundProcessOutput
- type Delegator
- type MetadataProvider
- type Registry
- func (r *Registry) AllTools() []ToolInfo
- func (r *Registry) BackgroundProcessOutput(id string, cursor *int64) (BackgroundProcessOutput, bool)
- func (r *Registry) BackgroundProcesses() []BackgroundProcessInfo
- func (r *Registry) Definitions() []openai.Tool
- func (r *Registry) Execute(ctx context.Context, name string, args json.RawMessage) (string, error)
- func (r *Registry) RegisterMCP(m *mcp.Manager)
- func (r *Registry) ReplaceDisabled(names []string)
- func (r *Registry) SetDelegator(d Delegator)
- func (r *Registry) Skills() []Skill
- func (r *Registry) StopBackgroundProcesses()
- func (r *Registry) StopLSPServers()
- func (r *Registry) ToolMetadata(name string) ToolMetadata
- func (r *Registry) VisibleTools() []Tool
- type Skill
- type TodoItem
- type Tool
- type ToolInfo
- type ToolMetadata
Constants ¶
const ToolOrderRest = "<unlisted-tools>"
ToolOrderRest is the reserved marker in a configured tool order naming where every tool NOT explicitly listed gets inserted, alphabetically — the same position and ordering the generated Tools overview already uses when no order is configured at all. A configured order must contain this marker exactly once; there is no implicit "everything else goes last" behavior, so a deployment can't accidentally bury unlisted tools without saying so.
Variables ¶
This section is empty.
Functions ¶
func OrderToolNames ¶ added in v0.3.0
OrderToolNames arranges visible (already alphabetically sorted by the caller — see Registry.VisibleTools) according to order: names listed explicitly appear in that order, and every other visible name is inserted, still alphabetical, at the ToolOrderRest position. order == nil returns visible unchanged — today's plain alphabetical behavior, byte-for-byte. A listed name that isn't currently visible (disabled, or hidden by permission policy for this assembly) is simply absent from the result, the same as it would be from an unordered overview — this function only arranges what VisibleTools() already decided to show, never adds to it.
func StartedBackgroundProcessID ¶ added in v0.2.8
StartedBackgroundProcessID extracts the ID from run_background's own stable success result. Keeping this parser next to the producer lets the agent add click metadata without teaching the TUI to scrape human-facing text.
func UnknownToolOrderNames ¶ added in v0.3.0
UnknownToolOrderNames returns every name in order (other than the rest marker) that isn't present in known — the "typo in config" case ValidateToolOrder alone can't catch, since it has no registry to check against. Called once at Registry construction against the full registered-tool universe (every tool that exists, not just the ones currently visible — a name valid at startup but disabled or denied for one particular assembly must not become a startup error just because this workspace's policy currently hides it).
func ValidateToolOrder ¶ added in v0.3.0
ValidateToolOrder checks a configured order's shape — no duplicate entries, exactly one ToolOrderRest marker — without needing a live Registry. It deliberately does NOT check that listed names correspond to real registered tools: only the registry that will actually render with this order knows its full tool universe, so that check happens separately, once, when a Registry using this order is constructed (see Registry's own tool-order validation) — failing there instead of here is what makes an unregistered name fail loudly instead of just vanishing from the overview.
func WithApprover ¶
WithApprover attaches the approver for the current turn to ctx — called by agent.runLoop before executing tools, mirroring WithAsker.
func WithAsker ¶
WithAsker attaches the asker for the current turn to ctx — called by agent.runLoop before executing tools, mirroring WithDepth.
Types ¶
type ApprovalDecision ¶
type ApprovalDecision string
ApprovalDecision is the user's answer to a policy-gated tool call.
const ( ApprovalOnce ApprovalDecision = "once" ApprovalAlways ApprovalDecision = "always" ApprovalDeny ApprovalDecision = "deny" )
type Approver ¶
type Approver interface {
Approve(ctx context.Context, toolName, subject string) (ApprovalDecision, error)
}
Approver asks the user to sign off on a tool call the permission policy marked Ask — implemented by agent.Service, injected per-turn via context, same pattern ask.go's Asker uses. Deliberately a separate interface from Asker: ask_question means "I don't have enough information to proceed"; an approval means "I know exactly what I want to do, but policy requires sign-off first." Conflating the two would make a policy-driven pause look to the model (and the user) like the agent being unsure, which it isn't.
type Asker ¶
type Asker interface {
Ask(ctx context.Context, question string, options []string) (string, error)
}
Asker pauses the current turn to get a real answer from the user — implemented by agent.Service, injected per-call via context (the same pattern depth.go uses) rather than through Registry, since unlike delegation this needs the *current turn's* live event channel and session ID, not just a fixed dependency wired in once at startup.
type BackgroundProcessInfo ¶ added in v0.2.8
type BackgroundProcessInfo struct {
ID string `json:"id"`
Command string `json:"command"`
PID int `json:"pid"`
Running bool `json:"running"`
ExitCode int `json:"exit_code"`
ExitError string `json:"exit_error,omitempty"`
StartedAt time.Time `json:"started_at"`
EndedAt *time.Time `json:"ended_at,omitempty"`
OutputBytes int64 `json:"output_bytes"`
RetainedBytes int `json:"retained_bytes"`
Truncated bool `json:"truncated"`
}
BackgroundProcessInfo is the read-only, structured view of one process owned by this daemon. It intentionally contains no os.Process or command handle: callers can observe lifecycle and output without acquiring a second way to mutate process state outside the permission-gated tools.
type BackgroundProcessOutput ¶ added in v0.2.8
type BackgroundProcessOutput struct {
ID string `json:"id"`
Output string `json:"output"`
Cursor int64 `json:"cursor"`
Reset bool `json:"reset"`
Running bool `json:"running"`
ExitCode int `json:"exit_code"`
ExitError string `json:"exit_error,omitempty"`
Truncated bool `json:"truncated"`
}
BackgroundProcessOutput is one cursor-based read of captured stdout and stderr. Cursor is an absolute byte position in this process's output stream. Reset tells a client to replace, rather than append to, its local copy.
type Delegator ¶
type Delegator interface {
RunTask(ctx context.Context, goal, taskContext, model string, depth int) (string, error)
}
Delegator runs one subtask to completion in a fresh, isolated child session and returns its final answer. Implemented by agent.Service; declared here (not imported from the agent package) because agent already depends on Registry for its own tool calls — agent importing tools importing agent would be a cycle. Registry.SetDelegator wires the concrete implementation in after both are constructed.
type MetadataProvider ¶ added in v0.2.2
type MetadataProvider interface {
ToolMetadata() ToolMetadata
}
MetadataProvider is implemented by a Tool that wants a hand-curated prompt summary instead of the automatic Description()-derived one.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds every tool available to the agent loop for one workspace.
func NewRegistry ¶
NewRegistry builds the default tool set scoped to workspace — every file and shell tool refuses to operate outside this directory. st, if non-nil, backs the memory_write/memory_search tools (cross-session memory, scoped to this workspace plus store.GlobalScope) and session_search (deterministic full-text search over real conversation history, a distinct concern from curated memory — see internal/daemon/store/search.go); passing nil omits those tools entirely rather than registering ones that would always fail. disabled names every tool (or skill — they share one namespace) turned off via the CLI's tools/skills screen; nil or empty means everything's on. Taking a plain map here rather than importing internal/toolsettings keeps this package from depending on the settings-storage format — daemon.go loads the store and passes its Disabled() map in.
func (*Registry) AllTools ¶
AllTools returns every registered tool (including disabled ones), name order, for the settings screen — Definitions() deliberately can't be reused here since it already filters disabled tools out.
func (*Registry) BackgroundProcessOutput ¶ added in v0.2.8
func (r *Registry) BackgroundProcessOutput(id string, cursor *int64) (BackgroundProcessOutput, bool)
BackgroundProcessOutput returns an incremental output snapshot for id.
func (*Registry) BackgroundProcesses ¶ added in v0.2.8
func (r *Registry) BackgroundProcesses() []BackgroundProcessInfo
BackgroundProcesses exposes read-only process metadata to the daemon's local control surface. Mutation remains confined to process_kill and daemon shutdown, preserving the permission boundary around destructive actions.
func (*Registry) Definitions ¶
Definitions returns every visible tool's definition (see VisibleTools) in the gateway's wire format, ready to attach to a ChatCompletionRequest.
func (*Registry) Execute ¶
Execute runs a named tool, or returns an error result (not a Go error) if the name is unknown, disabled, or blocked by permission policy — the agent loop feeds this text straight back to the model as the tool's result either way, so the model can see and recover from a bad or unavailable tool name itself. The disabled check here is defense in depth: Definitions() already keeps a disabled tool out of what's offered, but a model can still try to call a tool name it saw in an earlier turn before it was disabled.
Every tool call — built-in, custom (manifest), and MCP-backed alike — funnels through this one method, which is what makes them all subject to the same permission policy without each tool implementation needing to know policy exists.
func (*Registry) RegisterMCP ¶
RegisterMCP adds every tool from every connected MCP server to the registry, plus four generic tools covering resources and prompts (mcp_resource_list/read, mcp_prompt_list/get) — those aren't per-server-per-item like tools are (a server can expose an unbounded, changing set of resources), so they're cross-cutting tools that take a server name as an argument rather than one registered tool per item. Called after NewRegistry because connecting to servers is I/O that can block or fail, and the registry has to exist (and the daemon has to be able to start) either way.
func (*Registry) ReplaceDisabled ¶ added in v0.2.5
ReplaceDisabled updates the effective tool/skill profile without restarting the daemon. The CLI persists the same desired set first, then sends it here; subsequent model calls and executions immediately observe the new profile.
func (*Registry) SetDelegator ¶
SetDelegator wires the concrete subagent runner into the registry's delegate_task tool, after both the registry and the agent.Service that implements Delegator exist — daemon.go calls this once during startup. Until it's called, delegate_task exists (the model can see it in tool definitions) but reports itself unavailable rather than being hidden, which would otherwise require rebuilding the registry after the agent service is constructed.
func (*Registry) Skills ¶
Skills lists every discovered skill (project + global), disabled state included — same purpose as AllTools but for skills, which aren't registered as one fixed Tool each the way built-ins are.
func (*Registry) StopBackgroundProcesses ¶
func (r *Registry) StopBackgroundProcesses()
StopBackgroundProcesses kills every process started by run_background — called on daemon shutdown so a background dev server doesn't outlive the daemon that started it as an orphan.
func (*Registry) StopLSPServers ¶
func (r *Registry) StopLSPServers()
StopLSPServers shuts down every language server this registry's LSP tools started, if any — called on daemon shutdown for the same reason as StopBackgroundProcesses: a language server is a subprocess Kram started, so it's Kram's job to make sure it doesn't outlive the daemon as an orphan. A workspace that never called an lsp_* tool never started any server, so this is a no-op in the common case.
func (*Registry) ToolMetadata ¶ added in v0.2.2
func (r *Registry) ToolMetadata(name string) ToolMetadata
ToolMetadata looks up name's hand-curated metadata, or derives a fallback from its Description() (first sentence only, to stay short — several Description()s run 3-5 sentences, appropriate for the wire schema but too long for a one-line prompt overview) if it doesn't implement MetadataProvider, isn't registered, or has an empty Summary. Never returns a value with an empty Summary for a registered tool — every tool gets *some* usable line.
func (*Registry) VisibleTools ¶ added in v0.2.3
VisibleTools returns every tool the model can actually be offered right now, name order — the single source of truth Definitions() (the wire schema) and internal/daemon/agent's compileToolsOverview (the prompt's generated Tools section) both derive from, so a tool can never be announced in the prompt without also being callable, or the reverse. Before this existed, compileToolsOverview built its list from AllTools instead, which only excludes disabled tools — a tool the permission policy denies unconditionally (e.g. a Strict preset's "delete_file: deny *") stayed disabled=false and so got announced in the prompt with no matching function in the wire schema. Filters the same two things Definitions() always has: a disabled tool, and one the permission policy denies unconditionally (see permission.Evaluator.FullyDenied) — a capability the model can never successfully use shouldn't cost tokens in the schema or occupy a line in the overview. A tool denied only for *some* patterns stays visible, since it's still sometimes usable and the policy is enforced at call time either way.
type Skill ¶
type Skill struct {
Name string `json:"name"`
Description string `json:"description"`
Path string `json:"path"` // SKILL.md path, for error messages / the toggle UI
Scope string `json:"scope"` // "project" or "global"
Disabled bool `json:"disabled"` // set by Registry.Skills(), not discoverSkills itself
Body string `json:"-"` // everything after the frontmatter
}
Skill is one discovered skill: a folder containing a SKILL.md with a small frontmatter block (name, description) followed by the actual instructions as markdown. This is the same shape opencode's Agent Skills, Hermes Agent's agentskills.io-based skills, and OpenClaude's DiscoverSkillsTool all converge on — a lightweight open convention, not something Kram invented.
type TodoItem ¶
type TodoItem struct {
Content string `json:"content"`
Status string `json:"status"` // "pending", "in_progress", "completed"
}
TodoItem is one entry in the project's task list.
type Tool ¶
type Tool interface {
Name() string
Description() string
// Schema is the JSON Schema (as a raw object) describing the tool's
// arguments, passed straight through to the gateway/provider.
Schema() json.RawMessage
// Execute runs the tool and returns its result as text — every tool's
// output is text, even for structured data (JSON-encoded as a string),
// since that's what every provider's tool-result message expects.
Execute(ctx context.Context, args json.RawMessage) (string, error)
}
Tool is one callable capability the agent loop can offer the model.
type ToolInfo ¶
ToolInfo is one entry in the registry's full listing (AllTools) — every tool that exists, regardless of enabled state, for the CLI's tools/skills toggle screen.
type ToolMetadata ¶ added in v0.2.2
type ToolMetadata struct {
Summary string
// PreferOver names another tool this one should be reached for
// instead of, when relevant — e.g. run_background over bash for a
// dev server. Empty when there's no such competing default.
PreferOver string
}
ToolMetadata is a short, prompt-facing summary of a tool — distinct from and shorter than its Description() (which stays in full in the wire schema, for once the model has already selected the tool as a candidate and needs the complete picture). A tool with no hand-curated ToolMetadata still gets one via Registry.ToolMetadata's fallback — that's the point: a tool can't vanish from a generated overview just because nobody wrote a Summary for it yet, which is exactly the bug that motivated this (21 of 38 registered tools were never mentioned in the hand-maintained prompt prose — see DECISIONS.md).
Source Files
¶
- approval.go
- artifact_read.go
- ask.go
- background.go
- bash.go
- customtools.go
- delegate.go
- delete_file.go
- depth.go
- edit_file.go
- git.go
- glob.go
- grep.go
- ignore.go
- list_dir.go
- lsp.go
- mcp.go
- memory.go
- move_file.go
- outputfilter.go
- read_file.go
- session_search.go
- skillinstall.go
- skills.go
- snapshot.go
- spill.go
- todo.go
- toolmetadata.go
- toolorder.go
- tools.go
- web_fetch.go
- write_file.go