Documentation
¶
Overview ¶
Package shell hosts shell-side tools: Bash, Ls, Grep, Tree.
Bash is synchronous shell execution; Ls/Tree are filesystem listing helpers (cheaper than a Bash round-trip when you just want to look at a directory); Grep is a regex search across files. Long-running process monitoring is intentionally elsewhere (the monitor package).
Index ¶
Constants ¶
This section is empty.
Variables ¶
var Grep tools.Tool = &GrepTool{}
Grep is the singleton GrepTool. Delegates to system grep via Bash.
var Tree tools.Tool = &TreeTool{}
Tree is the singleton TreeTool. Stateless.
Functions ¶
Types ¶
type BashTool ¶
type BashTool struct {
// contains filtered or unexported fields
}
BashTool runs `/bin/sh -c <command>` with cmd.Dir set to the workdir captured at construction. One BashTool instance per agent — the toolset factory in internal/toolset/builtins.go calls NewBashWithHost so each agent (including subagents spawned with isolation: "worktree") gets a tool that runs in its own directory. The bash process is fresh per call — shell env state does NOT persist between invocations.
When run_in_background=true and a DaemonHost is installed on the agent's ToolState, Execute returns immediately with a daemon id (prefix "b") and the command runs in a detached goroutine. Completion emits a terminal Lifecycle signal on the agent's DaemonState; the drain at the next iter start folds it into <system-reminder>.
func NewBash ¶
NewBash constructs a BashTool bound to workdir. An empty workdir means "use the process's current directory" (cmd.Dir = "" — exec defaults). Use this for tests / narrow callers; production tooling always passes the agent's workdir.
host may be nil — in that case run_in_background falls back to the "not supported" error path. Production callers pass a non-nil host so the detached path works.
func NewBashWithHost ¶
func NewBashWithHost(workdir string, host DaemonHost) *BashTool
NewBashWithHost is the production constructor used by the toolset builtins factory. The host supplies the DaemonState + RootCtx + AgentID the bash daemon needs; without it run_in_background is rejected with a clear message.
func (*BashTool) Description ¶
func (*BashTool) Schema ¶
func (t *BashTool) Schema() json.RawMessage
type Classification ¶
Classification is the structured result of Classify.
Matched is the rule entry that triggered the verdict — for ReadOnly it's the binary name; for Dangerous it's the prefix that matched. Surfaced in the approval UI so the user knows *why* a prompt is showing.
IsCommonFS is an orthogonal flag (NOT a Risk level) set when the binary is one of {mkdir, touch, mv, cp, rmdir, ln, chmod, chown}. The gate uses it to auto-allow these in accept_edits mode while leaving them as regular RiskMutate calls in default mode (which still asks).
func Classify ¶
func Classify(command string) Classification
Classify inspects a shell command string and returns a structured Risk assessment. The classifier:
- Splits on safe operators (`|`, `&&`) and recurses on each segment. The combined Risk is the max — a chain is only ReadOnly if every segment is ReadOnly, and is Dangerous if any segment is Dangerous.
- Blocks unsafe operators (`;`, `||`, `>`, `>>`, `<`) — they collapse the command to RiskUnknown so the gate asks.
- Strips leading `VAR=value` env assignments (POSIX prefix; not the same as `env VAR=value cmd`).
- Checks the first non-env token against the dangerous-prefix list.
- Checks the first token against the read-only allowlist.
Empty input is RiskUnknown — defensive.
type DaemonHost ¶
type DaemonHost interface {
DaemonState() *daemon.DaemonState
RootCtx() context.Context
AgentID() string
}
DaemonHost is the narrow surface BashTool needs to spawn a bash daemon. Satisfied by *toolset.ToolState in production: it exposes DaemonState() (the catalog daemons register into), RootCtx() (the agent-lifetime ctx daemon goroutines bind to so they outlive the LLM call), and AgentID() (copied into snapshots so the TUI can label rows by owner).
type GrepTool ¶
type GrepTool struct{}
func (*GrepTool) Description ¶
func (*GrepTool) Schema ¶
func (t *GrepTool) Schema() json.RawMessage
type Risk ¶
type Risk int
Risk classifies a shell command's safety from the gate's perspective.
The gate uses Risk to drive auto mode (RiskReadOnly → allow, RiskDangerous → ask with a hint, RiskMutate/RiskUnknown → ask without a hint). Default mode treats every risk level as "ask," so a misclassification can't bypass the user — at worst it shows a prompt that didn't need to appear.
Conservative bias: RiskUnknown is the catch-all. Anything we can't confidently rate as ReadOnly stays Unknown, which forces ask.