permit

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
const ClassifierSystem = `` /* 2078-byte string literal not displayed */

ClassifierSystem is auto-mode's prompt: classify one shell command as exactly one word by whether it changes any state.

Variables

View Source
var ErrDenied = errors.New("denied by user")

ErrDenied marks a dialog answer that explicitly refused (Esc) rather than the session having no UI, so the barrier reports a real user denial. main.go maps tui.ErrCancelled onto it.

Functions

func DenyMatches

func DenyMatches(call agent.ToolCall, cmds []string) bool

DenyMatches reports whether call is named by a configured denied command: an exact tool name for any non-bash tool (MCP/extension/built-in), or, for bash, the trimmed command line matched as a token-boundary prefix, so "git" covers every git invocation and "git stash" its subcommands. A compound line is refused when any of its components matches, so wrapping in `cd ... &&` never escapes the gate. Unlike SafeMatches it may also name core writers; denying one is a legitimate safety gate.

func MCPClassifierSystem

func MCPClassifierSystem(name, description, params string) string

MCPClassifierSystem is auto+mcp's prompt: classify one tool call by whether it changes any state. name, description and params are embedded so an unfamiliar server can be judged by what it declares.

func NewCachedClassifier

func NewCachedClassifier(fn ClassifierFn) *cachedClassifier

NewCachedClassifier returns a session-scoped, LRU-caching classifier over fn.

func SafeMatches

func SafeMatches(call agent.ToolCall, cmds []string) bool

SafeMatches reports whether call is named by a configured safe command: an exact tool name for any non-bash tool (MCP/extension/built-in), or, for bash, the trimmed command line matched as a token-boundary prefix, so "git" covers every git invocation and "git status" its subcommands. A compound line matches only when every component is either a listed entry or verifiably read-only (mirroring allSegmentsReadOnly's all-or-nothing gate), so an appended write never rides in. write/edit can never be listed, so no config entry overrides a known writer.

Types

type Barrier

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

Barrier gates every tool call through static classification plus an optional approval dialog, holding the live mode and any open dialogs.

func NewBarrier

func NewBarrier(ro func(string) bool) *Barrier

NewBarrier builds a barrier with read-only metadata lookup ro. It starts in allow-read; set prompter/classifier before use.

func (*Barrier) Asker

func (b *Barrier) Asker() tools.Asker

Asker resolves a guard's ask into allow or deny. It consults session allows, opens an approval dialog, and in auto mode classifies bash concurrently.

func (*Barrier) Cycle

func (b *Barrier) Cycle() Mode

Cycle advances to the next mode in order and re-evaluates open dialogs.

func (*Barrier) Guard

func (b *Barrier) Guard() tools.Guard

Guard returns the static gate: user-initiated and allow-all always permit; rejections deny with guidance; block-all asks even for reads. Never blocks.

func (*Barrier) Mode

func (b *Barrier) Mode() Mode

Mode returns the current live mode.

func (*Barrier) SetClassifier

func (b *Barrier) SetClassifier(c Classifier)

SetClassifier installs the model classifier used in auto mode.

func (*Barrier) SetDeniedCommands

func (b *Barrier) SetDeniedCommands(cmds []string)

SetDeniedCommands installs config-declared denied commands: exact tool names or bash command lines that are always refused without prompting, in every mode (allow-all and user-initiated included). An empty list clears any prior set.

func (*Barrier) SetDryRun

func (b *Barrier) SetDryRun(fn func(agent.ToolCall) error)

SetDryRun installs a registry-backed dry-run check for doomed calls. nil means no tool can predict failure, so nothing is skipped.

func (*Barrier) SetMode

func (b *Barrier) SetMode(m Mode)

SetMode swaps the live mode and re-evaluates any open dialog under it: a call the new mode would allow outright is resolved as allow. Never rewrites config.

func (*Barrier) SetNoter

func (b *Barrier) SetNoter(n Noter)

SetNoter installs note injection for "allow with note".

func (*Barrier) SetNotice

func (b *Barrier) SetNotice(n func(string))

SetNotice installs a callback for transient status notices such as an auto-allowed classification. main.go wires it to ui.Notify; nil silences them.

func (*Barrier) SetPreview

func (b *Barrier) SetPreview(p func(agent.ToolCall) string)

SetPreview installs an optional per-call subject renderer (a write's content or an edit diff). It returns "" to fall back on the raw tool arguments.

func (*Barrier) SetPrompter

func (b *Barrier) SetPrompter(p Prompter)

SetPrompter installs the approval-dialog source; nil means headless.

func (*Barrier) SetSafeCommands

func (b *Barrier) SetSafeCommands(cmds []string)

SetSafeCommands installs config-declared safe commands: exact tool names or bash command lines that skip the approval prompt. write/edit can never be listed (they always prompt); an empty list clears any prior set.

type Class

type Class uint8

Class is a model classifier's verdict on one tool call.

const (
	ClassReadOnly Class = iota // verifiably read-only, safe to auto-allow
	ClassWrite                 // writes or otherwise unsafe; keep the dialog open
	ClassUnsure                // garbled or failed response; never cached
)

func NormalizeClass

func NormalizeClass(text string) Class

NormalizeClass maps a model's raw reply to a verdict: lowercase, drop every non-letter, then prefix-match so "read-only", `readonly.` and backticked answers all collapse cleanly. Anything else is ClassUnsure.

type Classifier

type Classifier interface {
	Classify(ctx context.Context, s Subject) Class
}

Classifier decides whether an unverifiable tool call is read-only. main.go supplies a fresh-context model adapter in auto/auto+mcp mode.

type ClassifierFn

type ClassifierFn func(ctx context.Context, s Subject) Class

ClassifierFn is one uncached classification; main.go supplies the model call.

type Dialog

type Dialog interface {
	Wait(ctx context.Context) (int, error)
	Resolve(index int)
	Close()
}

Dialog is an open approval dialog. Wait blocks for the answer, Resolve settles it from the caller (the mode-change path), Close abandons it; first wins.

type Mode

type Mode uint8

Mode is the permission gate's operating level.

const (
	ModeAllowAll  Mode = iota // no gate; every call runs
	ModeAllowRead             // verifiably read-only calls run, everything else prompts (default)
	ModeAuto                  // allow-read plus model classification of unverifiable shell commands
	ModeAutoMCP               // auto plus model classification of MCP/extension tool calls with their metadata
	ModeBlockAll              // nothing writes or reads without a prompt; ! lines exempt
)

func ParseMode

func ParseMode(s string) (Mode, bool)

ParseMode maps the config string to its Mode. The empty value means default.

func (Mode) Next

func (m Mode) Next() Mode

Next returns the following mode in cycle order.

func (Mode) Short

func (m Mode) Short() string

Short returns the status-segment label for a mode.

func (Mode) String

func (m Mode) String() string

String returns the config name for a mode.

type Noter

type Noter func(note string)

Noter injects a short user note into agent context at the next step boundary, used by "allow with note" and deny-with-reason so the model adapts without stopping the turn.

type Prompter

type Prompter interface {
	Open(prompt, subject string, options []string) (Dialog, error)
	Reason(ctx context.Context, label string) (string, bool)
}

Prompter opens approval dialogs and asks for free-text reasons. main.go supplies a tui-backed implementation; nil means headless (no UI available).

type Scan

type Scan struct {
	// Segments split on unquoted control operators; quoted regions collapse to "".
	Segments []string
	// Raw is the index-aligned verbatim counterpart of Segments (only sed reads it).
	Raw []string
	// HasSplitOp reports any &&, ||, |, ;, & or newline outside quotes.
	HasSplitOp bool
	// HasUnsafeOp reports any >, `, $( or <( outside quotes except discarding redirects.
	HasUnsafeOp bool
}

Scan is the result of one left-to-right pass over a shell command.

type Subject

type Subject struct {
	Name string // tool name; bashTool for shell calls
	Args string // bash command text, or elided JSON arguments for other tools
}

Subject is one call sent to the model classifier in auto/auto+mcp mode: a shell command, or any other (MCP/extension) tool named with its elided arguments.

func (Subject) IsShell

func (s Subject) IsShell() bool

IsShell reports whether the subject is a shell command rather than an MCP/extension call.

type Verdict

type Verdict uint8

Verdict is the static outcome of classifying one tool call.

const (
	VerdictAllow  Verdict = iota // verifiably read-only, runs without a prompt
	VerdictReject                // hard refusal with guidance; no dialog
	VerdictPrompt                // needs approval or model classification
)

func Classify

func Classify(call agent.ToolCall, ro func(string) bool) Verdict

Classify statically sorts a call into allow / reject / prompt using declared metadata and the shell analyser. Session allows, mode and the model classifier live above it; there is no name-prefix auto-approval.

Jump to

Keyboard shortcuts

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