Help us shape the future of Go! Take the 2026 Go Developer Survey

host

package
v0.34.1 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: 51 Imported by: 0

Documentation

Overview

Package host finds, starts and supervises plugins, and connects them to the engine.

Index

Constants

View Source
const DefaultIndex = "https://raw.githubusercontent.com/goxang/rig-plugins/main/registry/index.json"
View Source
const DevStamp = "plugin-dev"

DevStamp, under .rig, names the plugin rig plugin dev just built; a running TUI reloads when it changes.

View Source
const LockFile = "rig.lock"
View Source
const ManifestFile = "rig-plugin.yaml"

Variables

View Source
var ErrUntrusted = errors.New("this project's plugins need workspace trust: run rig trust (or pass --yes, or set RIG_TRUST=project)")

ErrUntrusted stops a run nobody can answer the workspace trust question for.

View Source
var OfficialKey = "RWSO4FXV354ZdKG69JB39vUGx5l3XooSJoWp0c8T/bWN548qByjgecLr"

OfficialKey is the minisign public key goxang's artifacts are signed with.

View Source
var SandboxExe string

SandboxExe is the rig binary that runs `rig __sandbox`; empty starts plugins directly.

View Source
var Version = "dev"

Version is the rig version plugins see at initialize.

Functions

func CacheDir

func CacheDir() string

func ConfigDir

func ConfigDir() string

func GC

func GC() ([]string, error)

GC removes installed versions no known project locks.

func HostSupports

func HostSupports(c string) bool

HostSupports says whether this rig satisfies a manifest's rig: constraint; dev builds take anything.

func Keygen

func Keygen() (pub, secret string, err error)

Keygen makes a minisign key pair: the public key as minisign writes it, the secret as a base64 key id and ed25519 seed (not minisign's encrypted format), for Sign.

func LogFile

func LogFile(name string) string

func Platform

func Platform() string

func Sandbox

func Sandbox(args []string) error

Sandbox is `rig __sandbox [--ro dir] [--rw dir] [--port n] -- command...`: it confines itself, then becomes the command.

func Sandboxed

func Sandboxed() bool

Sandboxed says whether plugins run confined on this OS.

func Sign

func Sign(secret, file string, data []byte) (string, error)

Sign makes a prehashed minisign signature file of data, named file in its trusted comment.

func StateDir

func StateDir() string

func StoreDir

func StoreDir() string

func TraceFile

func TraceFile(name string) string

func Trust

func Trust(dir string) error

Trust records that dir's plugins may run.

func Trusted

func Trusted(dir string) bool

Trusted says whether project-local plugins and auto-install may run in dir.

Types

type ActionDecl

type ActionDecl struct {
	Help   string         `yaml:"help,omitempty"`
	Effect string         `yaml:"effect,omitempty"`
	Args   map[string]any `yaml:"args,omitempty"`
	Keys   []string       `yaml:"keys,omitempty"`
	On     []string       `yaml:"on,omitempty"`
	Plan   bool           `yaml:"plan,omitempty"`
	Run    Command        `yaml:"run,omitempty"`
}

type Artifact

type Artifact struct {
	URL    string `json:"url"`
	SHA256 string `json:"sha256"`
	// Sig is the minisign signature file's text.
	Sig string `json:"sig,omitempty"`
	// Files are gzipped files the archive leaves out because several plugins share them (rig-std),
	// by their path in the plugin; each is downloaded once.
	Files map[string]Artifact `json:"files,omitempty"`
}

type Command

type Command []string

Command is a program to run, as a list or a shell line.

func (*Command) UnmarshalYAML

func (c *Command) UnmarshalYAML(n *yaml.Node) error

type Detect

type Detect struct {
	GitRemote string   `yaml:"git_remote,omitempty"`
	Files     []string `yaml:"files,omitempty"`
}

type Host

type Host struct {
	Options
	Warnings []string
	// contains filtered or unexported fields
}

Host runs the project's plugins.

func New

func New(o Options, cfg map[string]*spec.Plugin) *Host

func (*Host) Close

func (h *Host) Close()

Close stops every plugin process.

func (*Host) Get

func (h *Host) Get(name string) *Plugin

func (*Host) Import

func (h *Host) Import(ctx context.Context, name string, files []string) (*protocol.ImportResult, error)

Import runs a plugin importer, returning its rig.yaml fragment.

func (*Host) Plugins

func (h *Host) Plugins() []*Plugin

func (*Host) Query

func (h *Host) Query(ctx context.Context, name string, args protocol.Args) (*protocol.Frame, error)

func (*Host) Run

func (h *Host) Run(ctx context.Context, name string, args protocol.Args, dryRun bool) (*protocol.RunResult, error)

Run runs or plans an action; progress goes to the job in ctx.

func (*Host) Skills

func (h *Host) Skills() []Skill

Skills are the skills of every plugin, from the skills: directories their manifests list.

func (*Host) Stream

func (h *Host) Stream(ctx context.Context, name string, args protocol.Args) (<-chan protocol.StreamBatch, error)

Stream opens a server plugin's stream; batches arrive until Done, an error, or ctx ends.

func (*Host) View

func (h *Host) View(ctx context.Context, name string, args protocol.Args) (*protocol.Node, error)

View asks a plugin for a view it renders itself (render), named <plugin>.<view>.

func (*Host) Widget

func (h *Host) Widget(ctx context.Context, name string, params protocol.WidgetRenderParams) ([]string, error)

Widget asks a plugin to draw one of its canvas widgets, named <plugin>.<widget>, into p.Size.

type ImporterDecl

type ImporterDecl struct {
	Help  string   `yaml:"help,omitempty"`
	Files []string `yaml:"files,omitempty"`
	Run   Command  `yaml:"run,omitempty"`
}

type Index

type Index struct {
	Plugins map[string]*IndexEntry `json:"plugins"`
}

func (*Index) Resolve

func (ix *Index) Resolve(roots map[string]string) (map[string]string, error)

Resolve picks a version for every plugin the roots need, by minimal version selection: each plugin gets the highest of the minimums asked of it, then the lowest published version of that major at or above it. The result is deterministic and needs no solver.

type IndexEntry

type IndexEntry struct {
	Description string `json:"description,omitempty"`
	Publisher   string `json:"publisher,omitempty"`
	Repo        string `json:"repo,omitempty"`
	// Key is the publisher's minisign public key; goxang's is built in.
	Key      string                   `json:"key,omitempty"`
	Detect   *Detect                  `json:"detect,omitempty"`
	Provides map[string]any           `json:"provides,omitempty"`
	Packs    []string                 `json:"packs,omitempty"`
	Versions map[string]*IndexVersion `json:"versions"`
}

func (*IndexEntry) Latest

func (e *IndexEntry) Latest() string

Latest is the highest published version, pre-releases only when nothing else exists.

type IndexVersion

type IndexVersion struct {
	Rig         string              `json:"rig,omitempty"`
	Requires    map[string]string   `json:"requires,omitempty"`
	Permissions Permissions         `json:"permissions"`
	Artifacts   map[string]Artifact `json:"artifacts"`
}

type Installer

type Installer struct {
	Dir      string
	Registry *Registry
	// Yes approves workspace trust and permissions without asking (--yes).
	Yes bool
	// Ask asks the person at the terminal; nil means nobody is there.
	Ask func(question string) bool
	Out io.Writer
	// contains filtered or unexported fields
}

Installer adds, upgrades and restores a project's plugins, pinned in rig.lock.

func (*Installer) Add

func (in *Installer) Add(ctx context.Context, srcs []string) error

Add installs plugins from their sources and pins them in rig.lock, with their packs' plugins.

func (*Installer) Ensure

func (in *Installer) Ensure(ctx context.Context) (changed bool, err error)

Ensure installs what rig.lock pins and this machine lacks, after workspace trust; changed says the project's plugins differ from before, so a loaded project is stale.

func (*Installer) Remove

func (in *Installer) Remove(names []string) error

Remove unpins plugins, and the plugins a removed pack brought that nothing else needs.

func (*Installer) Up

func (in *Installer) Up(ctx context.Context, names []string, major bool) error

Up moves plugins (all when names is empty) to their newest version of the same major, or the newest at all with major.

func (*Installer) Vendor

func (in *Installer) Vendor() ([]string, error)

Vendor copies the locked plugins into .rig/vendor so an offline machine installs from the repo.

type Lacking

type Lacking struct{ Bin, Fix string }

Lacking is a program a plugin needs that is not on PATH, and what to do about it.

type Lock

type Lock struct {
	Plugins map[string]*Locked `yaml:"plugins"`
}

func ReadLock

func ReadLock(dir string) (*Lock, error)

func (*Lock) Names

func (l *Lock) Names() []string

func (*Lock) Write

func (l *Lock) Write(dir string) error

type Locked

type Locked struct {
	Version string `yaml:"version"`
	// Source is registry, a git repo (host/owner/repo[/sub]@ref), a tarball URL or a local path.
	Source string `yaml:"source"`
	Commit string `yaml:"commit,omitempty"`
	// SHA256 is per os/arch, or "any" for a platform-independent artifact.
	SHA256 map[string]string `yaml:"sha256,omitempty"`
	// Files are the shared files' sha256, per os/arch and then by path in the plugin.
	Files map[string]map[string]string `yaml:"files,omitempty"`
	// Permissions is the hash of the permissions granted; a plugin asking for more needs approval again.
	Permissions string `yaml:"permissions"`
	// Pack names the pack that brought it in, if any.
	Pack string `yaml:"pack,omitempty"`
}

Locked pins one plugin: where it came from and what it was, so every machine gets the same bytes.

type Manifest

type Manifest struct {
	Name        string            `yaml:"name"`
	Version     string            `yaml:"version"`
	Rig         string            `yaml:"rig,omitempty"`
	Description string            `yaml:"description,omitempty"`
	Publisher   string            `yaml:"publisher,omitempty"`
	Requires    map[string]string `yaml:"requires,omitempty"`
	// Needs are programs on the machine the plugin's scripts run, each with how to install it
	// (needs: {jq: "apt install jq"}); permissions.exec ones are checked too.
	Needs       map[string]string `yaml:"needs,omitempty"`
	Implements  []string          `yaml:"implements,omitempty"`
	Detect      *Detect           `yaml:"detect,omitempty"`
	Server      *Server           `yaml:"server,omitempty"`
	MCP         *Server           `yaml:"mcp,omitempty"`
	Permissions Permissions       `yaml:"permissions,omitempty"`
	// Config is the JSON Schema of plugins.<name>: in rig.yaml, as properties.
	Config    map[string]map[string]any `yaml:"config,omitempty"`
	Types     map[string]yaml.Node      `yaml:"types,omitempty"`
	Schemes   []string                  `yaml:"schemes,omitempty"`
	Sources   map[string]SourceDecl     `yaml:"sources,omitempty"`
	Actions   map[string]ActionDecl     `yaml:"actions,omitempty"`
	Importers map[string]ImporterDecl   `yaml:"importers,omitempty"`
	Views     map[string]yaml.Node      `yaml:"views,omitempty"`
	Widgets   map[string]yaml.Node      `yaml:"widgets,omitempty"`
	On        map[string]yaml.Node      `yaml:"on,omitempty"`
	Events    []string                  `yaml:"events,omitempty"`
	Skills    []string                  `yaml:"skills,omitempty"`
	Search    bool                      `yaml:"search,omitempty"`
	Complete  []string                  `yaml:"complete,omitempty"`
	Doctor    bool                      `yaml:"doctor,omitempty"`
	Docs      string                    `yaml:"docs,omitempty"`
	// Build runs in the plugin's directory after a git or path install, such as go build -o bin/x .
	Build Command `yaml:"build,omitempty"`

	// Dir is where the manifest lives; Fragment the rig.yaml keys it contributes.
	Dir      string      `yaml:"-"`
	Fragment *config.Doc `yaml:"-"`
	Warnings []string    `yaml:"-"`
}

func Discover

func Discover(dir string, cfg map[string]*spec.Plugin) (ms []*Manifest, warnings []string)

Discover finds the project's plugins. A later scope replaces an earlier one of the same name: what rig.lock pins, then what the user's own lock pins (rig plugin add --user), then user plugins, then project plugins (under workspace trust), then plugins.<name>.path.

func LoadManifest

func LoadManifest(dir string) (*Manifest, error)

LoadManifest reads dir/rig-plugin.yaml. Unknown keys are warnings, so an older rig loads a newer plugin. Callers share the result and must not change it.

func ParseManifest

func ParseManifest(raw []byte, file string) (*Manifest, error)

func (*Manifest) Kind

func (m *Manifest) Kind() string

Kind says how the plugin runs.

func (*Manifest) Missing

func (m *Manifest) Missing(needsOnly bool) []Lacking

Missing lists the programs the plugin needs (needs:, and unless needsOnly permissions.exec) that are not on PATH.

func (*Manifest) MissingText

func (m *Manifest) MissingText(needsOnly bool) string

MissingText is Missing as one sentence, "" when nothing is missing.

func (*Manifest) Path

func (m *Manifest) Path(p string) string

Path resolves a manifest-relative path.

func (*Manifest) Relevant

func (m *Manifest) Relevant(dir string, cfg map[string]*spec.Plugin) bool

Relevant reports whether m belongs on dir's screens. Project plugins always do; a user-wide one does when rig.yaml configures it, its detect matches, or it has neither detect nor config.

func (*Manifest) ShowsTab

func (m *Manifest) ShowsTab(dir string, cfg map[string]*spec.Plugin) bool

ShowsTab reports whether m's tab views belong on dir's screens. A plugin only the user installed shows its tabs when rig.yaml configures it, or when its detect matches and the credentials it asks for are set: a tab that cannot load anything is noise in a fresh project.

type Options

type Options struct {
	// Dir is the project, File its rig.yaml; Env the environment calls run in.
	Dir  string
	File string
	Env  string
	// StateDir keeps host/state values, per plugin: the project's .rig/<env>.
	StateDir string
	// Engine serves host/query and host/run.
	Engine api.Engine
	Ask    func(context.Context, protocol.AskParams) (protocol.AskResult, error)
	AI     func(context.Context, protocol.AIParams) (string, error)
	// Secret looks up a declared secret; nil reads the process environment.
	Secret func(name string) (string, bool)
	Emit   func(protocol.Event)
	// Components are the project's components a plugin serves (type: <plugin>), by name; nil is none.
	Components func(plugin string) map[string]protocol.Args
	// Idle stops a plugin process after this long unused; zero is 10 minutes.
	Idle time.Duration
}

type Permissions

type Permissions struct {
	// Net lists hosts or URLs a plugin connects to; on Landlock ABI 4+ their ports are enforced.
	Net []string `yaml:"net,omitempty" json:"net,omitempty"`
	// Secrets are the names host/secret answers.
	Secrets []string `yaml:"secrets,omitempty" json:"secrets,omitempty"`
	// Exec lists programs the plugin runs (advisory; PATH stays).
	Exec []string `yaml:"exec,omitempty" json:"exec,omitempty"`
	// Uses are globs of other plugins' sources and actions it may call through the host.
	Uses []string `yaml:"uses,omitempty" json:"uses,omitempty"`
	// FS lists paths beyond the project, its own directory and temp it reads (ro:) or writes.
	FS []string `yaml:"fs,omitempty" json:"fs,omitempty"`
	// Env lists environment variables it gets besides PATH, HOME and LANG.
	Env []string `yaml:"env,omitempty" json:"env,omitempty"`
	// AI lets it call host/ai.
	AI bool `yaml:"ai,omitempty" json:"ai,omitempty"`
}

func (Permissions) Hash

func (p Permissions) Hash() string

Hash identifies a set of permissions, so an update that widens them asks again.

func (Permissions) String

func (p Permissions) String() string

type Plugin

type Plugin struct {
	*Manifest
	// Config is plugins.<name> from rig.yaml over the manifest's config defaults.
	Config map[string]any
	// contains filtered or unexported fields
}

Plugin is one discovered plugin and, once called, its process.

func (*Plugin) Provides

func (p *Plugin) Provides(ctx context.Context) *protocol.Provides

Provides is what the plugin offers: its manifest, plus what its process said at initialize (cached, so a lazy plugin need not start to be listed).

func (*Plugin) Running

func (p *Plugin) Running() (int, bool)

Running says whether its process is up, and its pid.

type Registry

type Registry struct {
	// Mirror replaces every download: <mirror>/index.json and <mirror>/<name>/<version>/<file>.
	Mirror string
	Client *http.Client
}

Registry reads the plugin index, from a mirror when one is set.

func UserRegistry

func UserRegistry() *Registry

UserRegistry is the registry the user config, or $RIG_REGISTRY, points at.

func (*Registry) Index

func (r *Registry) Index(ctx context.Context, refresh bool) (*Index, error)

Index is the cached index, refetched after an hour or when refresh is set.

type Server

type Server struct {
	Command Command           `yaml:"command"`
	Env     map[string]string `yaml:"env,omitempty"`
}

Server is how a plugin runs: a JSON-RPC process, or an MCP server under mcp:.

type Skill

type Skill struct {
	Name        string `yaml:"name"`
	Description string `yaml:"description"`
	Plugin      string `yaml:"-"`
	Body        string `yaml:"-"`
}

Skill is a SKILL.md: its front matter's name and description, always shown to the AI, and the body, loaded only when asked for.

func ParseSkill

func ParseSkill(raw, fallback string) Skill

ParseSkill reads a SKILL.md; fallback names it when its front matter does not.

type SourceDecl

type SourceDecl struct {
	Help   string         `yaml:"help,omitempty"`
	Args   map[string]any `yaml:"args,omitempty"`
	Cache  string         `yaml:"cache,omitempty"`
	Stream bool           `yaml:"stream,omitempty"`
	// Run makes it a script source; Format overrides output detection.
	Run    Command `yaml:"run,omitempty"`
	Format string  `yaml:"format,omitempty"`
}

Jump to

Keyboard shortcuts

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