ai

package
v0.34.2 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: Apache-2.0 Imports: 27 Imported by: 1

Documentation

Overview

Package ai puts an assistant inside rig without being one: every turn runs the user's own opencode or Claude Code, with rig's MCP server as its tools, the project directory as its only workspace, and rig's guard rails between it and the environments.

Index

Constants

View Source
const (
	BackendOpencode = "opencode"
	BackendClaude   = "claude"
)
View Source
const (
	EnvLock      = "RIG_AI_ENV"
	EnvDir       = "RIG_AI_DIR"
	EnvSock      = "RIG_AI_SOCK"
	EnvProtected = "RIG_AI_PROTECTED"
	EnvKube      = "RIG_AI_KUBE"
	// EnvBareTools has the MCP server list its tools without the rig_ prefix (opencode adds the server's name)
	EnvBareTools = "RIG_MCP_BARE"
	// EnvAgent names the rig.yaml agent the server acts as; EnvTools and EnvApprove are its globs, comma-separated.
	EnvAgent   = "RIG_AI_AGENT"
	EnvTools   = "RIG_AI_TOOLS"
	EnvApprove = "RIG_AI_APPROVE"
)

What rig's MCP server reads to know it serves an assistant, and with which bounds.

View Source
const DefaultFreeModel = "opencode/big-pickle"
View Source
const EnvAudit = "RIG_AI_AUDIT"

EnvAudit is where rig's MCP server appends what the assistant ran (AuditEntry lines).

Variables

View Source
var DefaultDeny = []string{".env", ".env.*", "**/*.pem", "**/*.key", "**/id_rsa*", "**/id_ed25519*", "**/.git-credentials", "**/secrets/**"}

DefaultDeny keeps credentials out of reach in every project.

View Source
var ErrTurnFailed = errors.New("the assistant's turn failed")

ErrTurnFailed is a turn whose failure was already reported as an error event.

View Source
var Keys = []string{"backend", "provider", "model", "effort", "fast_model", "fast_url", "fast_api_key", "url", "api_key", "proxy", "autocomplete", "disabled", "redact"}

Keys are the settings `rig ai config key=value` takes, in the order it prints them.

View Source
var LocalProviders = map[string]string{"ollama": "http://localhost:11434/v1", "lmstudio": "http://localhost:1234/v1"}

LocalProviders are the providers that run on this machine, with their OpenAI-compatible endpoints.

View Source
var Providers = map[string]string{
	"own":       "the backend's own setup (your opencode config or Claude Code login)",
	"opencode":  "opencode's free models (opencode/big-pickle and the other -free ones)",
	"openai":    "any OpenAI-compatible endpoint: url, api_key, model",
	"9router":   "a 9router instance (OpenAI-compatible, default http://localhost:20128/v1)",
	"deepseek":  "DeepSeek's API: api_key (model deepseek-chat unless set)",
	"anthropic": "an Anthropic-compatible endpoint for Claude Code: url, api_key",
	"ollama":    "a local Ollama (default http://localhost:11434/v1): model, no key",
	"lmstudio":  "a local LM Studio server (default http://localhost:1234/v1): model, no key",
}

Providers an API key can be set for; "own" leaves the backend on its own login and models.

Functions

func AppendAudit added in v0.6.0

func AppendAudit(file string, e AuditEntry) error

AppendAudit adds e to file as one JSON line; the output is cut to its last 400 bytes.

func ChangeConfig

func ChangeConfig(key, value string) error

ChangeConfig sets one key in the saved setup, leaving RIG_AI_* overrides out of the file.

func CloseSession

func CloseSession(dataDir, id string) error

Close forgets a session: its transcript and its tool state.

func CompletePrompt

func CompletePrompt(hint, text string) string

CompletePrompt asks for the rest of what is being typed, nothing else.

func ConfigFile

func ConfigFile() (string, error)

func Connect added in v0.7.0

func Connect(f Found) error

Connect points the saved setup at a found backend as the user has it set up: its own login, config and model (opencode without a model gets its free ones). Other settings are kept.

func DeniedPath

func DeniedPath(rel string, extra []string) bool

DeniedPath tells whether rel, a slash path inside the project, is one of DefaultDeny or extra (globs: * within a name, ** across directories; a pattern without / matches a name at any depth).

func DescribePrompt

func DescribePrompt(hint, before, want string) string

func LastPrompt

func LastPrompt(dir string) string

LastPrompt is the user's latest message, which tools check "user_request" quotes against.

func Quoted

func Quoted(message, quote string) bool

Quoted reports whether quote is the user's own words from their message: verbatim (case and spacing aside) and long enough not to match by accident.

func SaveConfig

func SaveConfig(c Config) error

func SecretName added in v0.6.0

func SecretName(n string) bool

SecretName is whether a variable or field named n holds a secret, by its name.

func Serve

func Serve(path string, handle func(Request) Reply) (close func(), err error)

Serve answers requests on a unix socket until close is called; handle may block (a person deciding).

func SocketPath

func SocketPath() string

SocketPath is one per rig process: short, since unix socket paths are capped near 100 bytes.

func SplitNext added in v0.23.0

func SplitNext(text string) (rest, next string)

SplitNext takes the "NEXT: ..." line the system prompt asks answers to end with off text.

func SystemPrompt

func SystemPrompt(s Scope) string

SystemPrompt is what every chat turn runs under.

Types

type Agent added in v0.26.0

type Agent struct {
	Name           string
	Tools, Approve []string
}

Agent is a rig.yaml agent: it reads files but never edits or runs a shell, and reaches rig only through the tools its globs allow, as itself.

type AuditEntry added in v0.6.0

type AuditEntry struct {
	At      time.Time `json:"at"`
	Env     string    `json:"env"`
	Command string    `json:"command"`
	Risk    string    `json:"risk"`
	// Result is ok, failed, declined (by the user) or refused (by rig).
	Result string `json:"result"`
	By     string `json:"confirmed_by,omitempty"`
	Output string `json:"output,omitempty"`
}

AuditEntry is one action the assistant ran, or tried to, on an environment.

func ReadAudit added in v0.6.0

func ReadAudit(file string) ([]AuditEntry, error)

ReadAudit returns file's entries, oldest first; a missing file has none.

func (AuditEntry) String added in v0.6.0

func (e AuditEntry) String() string

type Config

type Config struct {
	Backend   string `json:"backend,omitempty"`
	Provider  string `json:"provider,omitempty"`
	Model     string `json:"model,omitempty"`
	FastModel string `json:"fast_model,omitempty"`
	// Effort is the reasoning level of chat turns: Claude Code's --effort, opencode's --variant.
	Effort string `json:"effort,omitempty"`
	// FastURL and FastAPIKey point completions at an OpenAI-compatible endpoint of their own,
	// one direct request instead of a backend run, whatever the chat goes through.
	FastURL    string `json:"fast_url,omitempty"`
	FastAPIKey string `json:"fast_api_key,omitempty"`
	URL        string `json:"url,omitempty"`
	APIKey     string `json:"api_key,omitempty"`
	Proxy      string `json:"proxy,omitempty"`
	// Autocomplete suggests the rest of a query while it is typed; off by default only when set false.
	Autocomplete *bool `json:"autocomplete,omitempty"`
	Disabled     bool  `json:"disabled,omitempty"`
	// Redact replaces secrets with <secret:NAME> in everything sent to the model; on unless set false.
	Redact *bool `json:"redact,omitempty"`
}

Config is the user's AI setup, kept in ~/.config/rig/ai.json (it may hold an API key: mode 0600).

func LoadConfig

func LoadConfig() (Config, error)

LoadConfig reads the saved setup; RIG_AI_* variables override it for one run.

func (Config) Get

func (c Config) Get(key string) string

Get is a setting's value for display, the API key masked.

func (Config) RedactOn added in v0.6.0

func (c Config) RedactOn() bool

RedactOn is whether secrets are redacted before text reaches the model (the default).

func (*Config) Set

func (c *Config) Set(key, value string) error

Set changes one setting by its key; an empty value clears it.

type Event

type Event struct {
	Kind string // text, tool, error
	Text string
}

type Found added in v0.7.0

type Found struct {
	Backend, Bin, Model string
	// Ready is whether it has a login or a model to run with; opencode always does (free models).
	Ready bool
}

Found is an AI tool installed on this machine, with the model its own config picks.

func Detect added in v0.7.0

func Detect() []Found

Detect lists the installed backends and what their own configs set.

func (Found) Describe added in v0.7.0

func (f Found) Describe() string

type LocalServer added in v0.6.0

type LocalServer struct {
	Provider, URL string
	Models        []string
}

LocalServer is a model server found running on this machine.

func DetectLocal added in v0.6.0

func DetectLocal(ctx context.Context) []LocalServer

DetectLocal finds the local model servers (LocalProviders) that answer, with the models they serve.

type Message

type Message struct {
	Role  string    `json:"role"` // user, assistant, tool, error
	Text  string    `json:"text"`
	At    time.Time `json:"at"`
	Tools []string  `json:"tools,omitempty"`
}

type Redactor added in v0.6.0

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

Redactor puts <secret:NAME> in place of secrets in text bound for a model: the values rig knows to be secret (Known), then whatever goxang/scrub's packs take for a credential (URL passwords, key=value pairs, JWTs, cloud tokens, bearer headers, private keys, card numbers, PINs). A nil Redactor redacts nothing.

func NewRedactor added in v0.6.0

func NewRedactor(known map[string]string) *Redactor

NewRedactor redacts the values of known (name → value) wherever they appear.

func (*Redactor) Redact added in v0.6.0

func (r *Redactor) Redact(s string) string

Redact is the one function every text bound for a model goes through.

type Reply

type Reply struct {
	OK   bool   `json:"ok"`
	Text string `json:"text,omitempty"`
	// NoOne is an "approve" nobody could be asked (no terminal): the user's quoted words decide.
	NoOne bool `json:"no_one,omitempty"`
}

Reply answers a Request. For an "approve", Text names who said yes, or why not.

func Call

func Call(path string, req Request, wait time.Duration) (Reply, error)

Call sends one request and waits for the reply, at most wait.

type Request

type Request struct {
	Op   string `json:"op"`
	Text string `json:"text,omitempty"`
	// Command is the exact action an "approve" is for, which "always allow" remembers.
	Command string            `json:"command,omitempty"`
	Action  string            `json:"action,omitempty"`
	Args    map[string]string `json:"args,omitempty"`
}

Request is what rig's MCP server asks the rig that started the assistant: a person's go-ahead (op "approve") or an action in the UI (op "ui").

type Risk

type Risk int
const (
	Read Risk = iota
	Change
	Danger
	Refused
)

func Classify

func Classify(argv []string) Risk

Classify rates a rig command line an assistant wants to run. Unknown commands count as changes, anything that runs arbitrary commands or reaches secrets as dangerous or refused.

func ClassifyQuery

func ClassifyQuery(q string) Risk

ClassifyQuery rates query text by its statements' leading words: SQL, a redis command, kubectl arguments, PromQL. UPDATE and DELETE without WHERE are dangerous.

func (Risk) String

func (r Risk) String() string

type Runner

type Runner struct {
	Setup Setup
	Scope Scope
	// Self is this rig binary, which the backend starts as its MCP server.
	Self string
	// Sock is the bridge for approvals and UI actions; empty when nothing can answer.
	Sock string
	Kube bool
	// Redactor takes the secrets out of every prompt; nil sends them as they are (redact=false).
	Redactor *Redactor
	// AuditFile is the JSONL file every action of the assistant is appended to.
	AuditFile string
	// Agent, when set, runs turns as that agent.
	Agent *Agent
	// contains filtered or unexported fields
}

Runner runs turns of one project and environment.

func (*Runner) Ask added in v0.6.0

func (r *Runner) Ask(ctx context.Context, prompt string) (string, error)

Ask puts one question to the chat model, without tools, and returns its whole answer.

func (*Runner) Complete

func (r *Runner) Complete(ctx context.Context, hint, text string) (string, error)

Complete returns what likely follows text, given hint about where it is typed. An API-key provider is asked directly (one request, fast); otherwise the backend runs once without tools.

func (*Runner) Describe

func (r *Runner) Describe(ctx context.Context, hint, before, want string, check func(context.Context, string) error) (string, error)

Describe writes the input asked for in words: before is what is typed ahead of the description (a query's start, or nothing), want the description; it returns the whole input, before included.

check, when not nil, tries the answer (compiles it, runs it where that is safe); an answer that fails goes back to the model with the error, up to three tries. After the last, the answer is returned with the error.

func (*Runner) Models

func (r *Runner) Models(ctx context.Context, fast bool) ([]string, error)

Models lists what "model" can be set to, or with fast "fast_model": the endpoint's own list when one is set, else the backend's.

func (*Runner) Turn

func (r *Runner) Turn(ctx context.Context, s *Session, typed, screen string, on func(Event)) error

Turn sends one message: typed is what the user wrote, screen what they were looking at.

type Scope

type Scope struct {
	Project   string
	Dir       string
	File      string
	Env       string
	Runtime   string
	Protected bool
	ReadOnly  bool
	Envs      []string
	// Deny are project paths the assistant must not read (rig.yaml ai.deny), on top of DefaultDeny.
	Deny []string
	// Extra is the project's own instructions (rig.yaml ai.instructions).
	Extra string
}

Scope is what a session is bound to: one project directory and one environment.

type Session

type Session struct {
	ID        string    `json:"id"`
	Backend   string    `json:"backend"`
	BackendID string    `json:"backend_id,omitempty"`
	Env       string    `json:"env"`
	Title     string    `json:"title"`
	Created   time.Time `json:"created"`
	Updated   time.Time `json:"updated"`
	Messages  []Message `json:"messages"`
	// Next is what the last answer suggests the user asks next
	Next string `json:"next,omitempty"`
	// contains filtered or unexported fields
}

Session is one conversation: rig keeps the transcript to show and resume it, the backend keeps its own (BackendID) so a resumed turn carries the whole context.

func ListSessions

func ListSessions(dataDir string) ([]*Session, error)

ListSessions are the project's conversations, newest first.

func LoadSession

func LoadSession(dataDir, id string) (*Session, error)

func NewSession

func NewSession(dataDir, backend, env string) *Session

func (*Session) Add

func (s *Session) Add(role, text string, tools ...string)

func (*Session) Dir

func (s *Session) Dir() string

Dir holds what the session's tools read: the last user message and the bridge address.

func (*Session) Save

func (s *Session) Save() error

func (*Session) Summary

func (s *Session) Summary() string

type Setup

type Setup struct {
	Config
	Bin string
	// Why says why AI is off, when Bin is empty.
	Why string
}

Setup is a Config resolved against this machine: which binary runs, with which model and endpoint.

func Resolve

func Resolve(c Config) Setup

Resolve picks the backend (the configured one, else opencode, else Claude Code) and fills the provider's defaults. A provider with its own key needs opencode, except anthropic, which is Claude Code's.

func (Setup) AutocompleteOn

func (s Setup) AutocompleteOn() bool

func (Setup) Describe

func (s Setup) Describe() string

Describe is one line about the setup, for headers and `rig ai config`.

func (Setup) Efforts

func (s Setup) Efforts() []string

Efforts are the levels Effort takes on this backend.

func (Setup) Enabled

func (s Setup) Enabled() bool

Directories

Path Synopsis
Package agents fires rig.yaml agents on their events and schedules.
Package agents fires rig.yaml agents on their events and schedules.
Package router gives an AI a small fixed set of meta-tools over the Engine (find, call, query, read, open, skill, docs, file, ui) instead of one tool per action, so forty plugins do not flood its context.
Package router gives an AI a small fixed set of meta-tools over the Engine (find, call, query, read, open, skill, docs, file, ui) instead of one tool per action, so forty plugins do not flood its context.

Jump to

Keyboard shortcuts

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