Documentation
¶
Overview ¶
Package toolbelt provisions developer tools onto a persistent volume, declaratively. A manifest (tools.json) records intent: which tools, at which versions, enabled or disabled. A compiled catalog carries install knowledge (sources, artifact templates, checksum locations, shims, dependencies). The Engine reconciles installed state against intent through a single-flight job queue: enabled-but-missing tools are installed, disabled-but-installed tools are uninstalled (their template kept), unmanaged files are never touched.
Data files (all under the consumer's persistent config volume):
<ConfigDir>/tools.json — the manifest: user intent. Toolbelt is
the only writer, but out-of-band hand
edits are supported by design (the file
is re-read on every operation).
<ConfigDir>/tools-state.json — engine-owned machine state (installed
version, owned bin names, last error).
<ToolsDir>/opt/<name>/<ver>/ — versioned install trees.
<ToolsDir>/bin — the single PATH dir: symlinks + shims.
The catalog (CatalogPath, compiled at image build by cmd/toolcatalog) is read-only environment data; a missing catalog degrades to manual and ecosystem sources only, and entries that need catalog knowledge fail their jobs with a named error.
Install sources: aqua-registry artifact definitions (with upstream checksum verification when the definition declares a source), npm, pip (via uv), cargo, go install, and a manual bash escape hatch. No external package-manager binary ships with the library; ecosystem backends are themselves installable tools (npm needs node, pip needs uv, ...), and the engine adopts those backend dependencies automatically.
Index ¶
- Constants
- Variables
- func VerifyCatalog(c *Catalog, require []string) []error
- type AddRequest
- type AquaChecksum
- type AquaFile
- type AquaOverride
- type AquaPackage
- type AquaVersionOverride
- type Catalog
- type CatalogEntry
- type Config
- type DependentsError
- type Engine
- func (e *Engine) Add(ctx context.Context, req *AddRequest) (*Job, error)
- func (e *Engine) CancelJob(id string) bool
- func (e *Engine) Close()
- func (e *Engine) EnsureInstalled(ctx context.Context, name string) error
- func (e *Engine) Install(name string) (*Job, error)
- func (e *Engine) Inventory() (*Inventory, error)
- func (e *Engine) Jobs() (active *Job, recent []*Job)
- func (e *Engine) Patch(name string, req PatchRequest) (*Job, error)
- func (e *Engine) Reconcile(mode ReconcileMode) (*Job, error)
- func (e *Engine) Remove(name string, force bool) (*Job, []string, error)
- func (e *Engine) Search(query string) []CatalogEntry
- func (e *Engine) Update(names ...string) (*Job, error)
- func (e *Engine) Wait(ctx context.Context, jobID string) (*Job, error)
- type InstallSpec
- type Inventory
- type Job
- type Manifest
- type PatchRequest
- type ReconcileMode
- type State
- type SystemTool
- type Tool
- type ToolInfo
- type ToolStatus
Constants ¶
const ( SourceAqua = "aqua" // aqua:owner/repo — evaluated aqua-registry definition SourceNpm = "npm" // npm:package SourcePip = "pip" // pip:package (installed via uv) SourceCargo = "cargo" // cargo:crate SourceGo = "go" // go:module/path SourceManual = "manual" // user-provided install command )
Source prefixes for Tool.Source. A source is "<kind>:<ref>" except SourceManual which stands alone.
const ( JobQueued = "queued" JobRunning = "running" JobDone = "done" JobFailed = "failed" JobCancelled = "cancelled" )
Job states.
const ( JobKindInstall = "install" JobKindUninstall = "uninstall" // Remove: footprint removed, entry deleted JobKindDisable = "disable" // Patch disabled:true: footprint removed, entry kept JobKindUpdate = "update" JobKindReconcile = "reconcile" // converge disk to intent (install missing + disable extras) )
Job kinds.
const ManifestVersion = 2
ManifestVersion is the manifest schema version this engine reads and writes. Files without it (the retired sectioned v1 shape) are backed up and replaced with the configured seed at engine start.
Variables ¶
var ( // ErrNotFound marks an operation on a tool the manifest doesn't have. ErrNotFound = errors.New("tool not found") // ErrHasDependents marks a refused remove/disable: enabled entries // still require the tool (directly or as an implied backend). ErrHasDependents = errors.New("tool has dependents") // ErrDisabled marks an install attempt on a disabled template. // Enabling is an explicit state change (Patch Disabled=false), never // a side effect of a retry. ErrDisabled = errors.New("tool is disabled") )
Sentinel errors. Compare with errors.Is; *DependentsError additionally carries the dependent names (errors.As).
Functions ¶
func VerifyCatalog ¶
VerifyCatalog checks that every required name resolves in the catalog to install knowledge the engine can act on, offline: a non-empty source; for aqua sources an embedded definition that parses its templates and claims linux support on both amd64 and arm64; for manual sources an install command. One error per failing name; nil means the catalog satisfies the requirement set. Consumers run this at image build (cmd/toolcatalog verify) over their seed + migration names so a registry drift fails the build instead of a boot job.
Types ¶
type AddRequest ¶
type AddRequest struct {
Shims map[string]string `json:"shims,omitempty"`
Name string `json:"name"`
Source string `json:"source,omitempty"` // optional when the catalog knows the name
Version string `json:"version,omitempty"` // optional: resolve latest
Description string `json:"description,omitempty"`
Origin string `json:"origin,omitempty"`
Install string `json:"install,omitempty"`
Uninstall string `json:"uninstall,omitempty"`
Probe string `json:"probe,omitempty"`
Requires []string `json:"requires,omitempty"`
Pin bool `json:"pin,omitempty"`
// Disabled adds the entry as a template: recorded, not installed,
// no job enqueued (Add then returns a nil Job).
Disabled bool `json:"disabled,omitempty"`
}
AddRequest is the Add call's body: intent for a new tool. Every field except Name is optional when the catalog knows the name.
type AquaChecksum ¶
type AquaChecksum struct {
Enabled *bool `json:"enabled,omitempty" yaml:"enabled"`
Type string `json:"type,omitempty" yaml:"type"` // github_release | http
Asset string `json:"asset,omitempty" yaml:"asset"`
URL string `json:"url,omitempty" yaml:"url"`
Algorithm string `json:"algorithm,omitempty" yaml:"algorithm"` // sha256 | sha512 | ...
}
AquaChecksum describes where the artifact's checksum lives.
type AquaFile ¶
type AquaFile struct {
Name string `json:"name" yaml:"name"`
Src string `json:"src,omitempty" yaml:"src"` // template; default = Name
}
AquaFile names one binary inside the extracted artifact.
type AquaOverride ¶
type AquaOverride struct {
Replacements map[string]string `json:"replacements,omitempty" yaml:"replacements"`
Checksum *AquaChecksum `json:"checksum,omitempty" yaml:"checksum"`
GOOS string `json:"goos,omitempty" yaml:"goos"`
GOArch string `json:"goarch,omitempty" yaml:"goarch"`
Asset string `json:"asset,omitempty" yaml:"asset"`
URL string `json:"url,omitempty" yaml:"url"`
Format string `json:"format,omitempty" yaml:"format"`
Files []AquaFile `json:"files,omitempty" yaml:"files"`
}
AquaOverride adjusts fields for a specific GOOS/GOARCH.
type AquaPackage ¶
type AquaPackage struct {
Replacements map[string]string `json:"replacements,omitempty" yaml:"replacements"`
Checksum *AquaChecksum `json:"checksum,omitempty" yaml:"checksum"`
VersionConstr string `json:"version_constraint,omitempty" yaml:"version_constraint"`
VersionSource string `json:"version_source,omitempty" yaml:"version_source"`
Asset string `json:"asset,omitempty" yaml:"asset"`
URL string `json:"url,omitempty" yaml:"url"`
Path string `json:"path,omitempty" yaml:"path"`
Format string `json:"format,omitempty" yaml:"format"`
RepoOwner string `json:"repo_owner,omitempty" yaml:"repo_owner"`
RepoName string `json:"repo_name,omitempty" yaml:"repo_name"`
VersionPrefix string `json:"version_prefix,omitempty" yaml:"version_prefix"`
Description string `json:"description,omitempty" yaml:"description"`
Type string `json:"type" yaml:"type"`
VersionFilter string `json:"version_filter,omitempty" yaml:"version_filter"`
VersionOverrides []AquaVersionOverride `json:"version_overrides,omitempty" yaml:"version_overrides"`
SupportedEnvs []string `json:"supported_envs,omitempty" yaml:"supported_envs"`
Overrides []AquaOverride `json:"overrides,omitempty" yaml:"overrides"`
Files []AquaFile `json:"files,omitempty" yaml:"files"`
NoAsset bool `json:"no_asset,omitempty" yaml:"no_asset"`
}
AquaPackage is the subset of an aqua-registry package definition the engine evaluates. Field names mirror the upstream YAML/JSON schema (https://aquaproj.github.io/docs/reference/registry-config), which the catalog compiler (cmd/toolcatalog) relies on to unmarshal registry files directly. Windows- and darwin-only concerns (rosetta2, windows_arm_emulation, complete_windows_ext) are intentionally absent: the engine resolves for linux only, and the evaluator resolves everything for linux/GOARCH.
func (*AquaPackage) CheckTemplates ¶
func (p *AquaPackage) CheckTemplates() error
CheckTemplates parses (without executing) every Go template the definition carries — asset, url, path, checksum asset/url, file srcs, across version overrides — so catalog verification can catch template syntax drift offline. Returns the first parse error.
func (*AquaPackage) ResolveSpec ¶
func (p *AquaPackage) ResolveSpec(version string) (*InstallSpec, error)
ResolveSpec evaluates the package definition for the given version on linux/GOARCH and returns the download plan. version is the upstream tag (with any version_prefix still attached).
func (*AquaPackage) SupportsLinux ¶
func (p *AquaPackage) SupportsLinux(goarch string) bool
SupportsLinux reports whether the definition claims support for linux/goarch at the root level (supported_envs; empty = everywhere). A static, offline check — no version rendering. Used by catalog verification.
type AquaVersionOverride ¶
type AquaVersionOverride struct {
Asset *string `json:"asset,omitempty" yaml:"asset"`
URL *string `json:"url,omitempty" yaml:"url"`
Format *string `json:"format,omitempty" yaml:"format"`
Replacements *map[string]string `json:"replacements,omitempty" yaml:"replacements"`
Checksum *AquaChecksum `json:"checksum,omitempty" yaml:"checksum"`
NoAsset *bool `json:"no_asset,omitempty" yaml:"no_asset"`
VersionPrefix *string `json:"version_prefix,omitempty" yaml:"version_prefix"`
VersionConstr string `json:"version_constraint,omitempty" yaml:"version_constraint"`
Files []AquaFile `json:"files,omitempty" yaml:"files"`
Overrides []AquaOverride `json:"overrides,omitempty" yaml:"overrides"`
SupportedEnvs []string `json:"supported_envs,omitempty" yaml:"supported_envs"`
}
AquaVersionOverride switches definition fields per version range. A nil pointer field means "inherit from the package root".
type Catalog ¶
type Catalog struct {
// Refs records the upstream registry refs this catalog was
// compiled from (informational).
Refs map[string]string `json:"refs,omitempty"`
Entries map[string]CatalogEntry `json:"entries"`
}
Catalog is the compiled tool-catalog.json document.
func (*Catalog) Featured ¶
func (c *Catalog) Featured() []CatalogEntry
Featured returns the curated starter set (empty-state content), sorted by name.
func (*Catalog) Lookup ¶
func (c *Catalog) Lookup(name string) (CatalogEntry, bool)
Lookup finds a catalog entry by name or alias.
func (*Catalog) Search ¶
func (c *Catalog) Search(query string) []CatalogEntry
Search ranks catalog entries against a query: exact name, name prefix, alias, name substring, then description substring. Empty query returns the featured set.
type CatalogEntry ¶
type CatalogEntry struct {
Shims map[string]string `json:"shims,omitempty"`
Aqua *AquaPackage `json:"aqua,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Source string `json:"source"`
// Version is the default pinned version for entries without an
// upstream version source (manual installs).
Version string `json:"version,omitempty"`
Install string `json:"install,omitempty"` // manual-source entries
Uninstall string `json:"uninstall,omitempty"` // manual-source entries
Probe string `json:"probe,omitempty"` // manual-source entries
Aliases []string `json:"aliases,omitempty"`
Requires []string `json:"requires,omitempty"`
Featured bool `json:"featured,omitempty"`
// Lsp marks language-server entries; drives the consumers'
// no-LSP-enabled warning and UI badges.
Lsp bool `json:"lsp,omitempty"`
}
CatalogEntry is one tool in the compiled catalog: the mise-registry name/description joined with the preferred install source and, for aqua sources, the embedded aqua package definition. Overlay entries (curated) may add requires/shims/manual install commands and the lsp marker.
type Config ¶
type Config struct {
// OnJobChanged, when non-nil, receives every job state transition
// (queued, running, done, failed, cancelled). Views carry no output
// tail; stream output via OnJobOutput or poll Jobs().
OnJobChanged func(*Job)
// OnJobOutput, when non-nil, receives coalesced batches of a running
// job's output lines (~150 ms cadence).
OnJobOutput func(jobID string, lines []string)
// Logger receives engine-level log lines. Nil means slog.Default().
Logger *slog.Logger
// Seed is the manifest written when no valid one exists (fresh
// volume, or a retired-format file that was just backed up). Nil
// seeds an empty manifest. See DefaultSeed.
Seed *Manifest
// ConfigDir holds tools.json + tools-state.json (the persistent
// config volume root).
ConfigDir string
// ToolsDir is the install tree root (bin/, opt/, npm/, python/).
ToolsDir string
// CatalogPath is the compiled catalog baked into the consumer's
// image (optional; missing = degraded search + named install errors
// for catalog-dependent entries).
CatalogPath string
// System names image-baked binaries surfaced read-only in
// Inventory's System group (informational; not managed).
System []string
}
Config wires an Engine. ConfigDir and ToolsDir are required.
type DependentsError ¶
type DependentsError struct {
Dependents []string
}
DependentsError is the ErrHasDependents shape that names the enabled entries blocking a remove/disable.
func (*DependentsError) Error ¶
func (e *DependentsError) Error() string
func (*DependentsError) Is ¶
func (e *DependentsError) Is(target error) bool
Is makes errors.Is(err, ErrHasDependents) match.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine is the tools subsystem: the single owner of the manifest and install tree, the job queue, and the catalog. Construct with New.
The manifest store's single-writer guarantee is an in-process lock: every other process (a CLI, an agent) must go through the consumer's server rather than linking toolbelt against the same data dirs.
func New ¶
New constructs and starts an Engine: initializes the manifest files (seeding when absent, backing up a retired-format file) and launches the job worker.
func (*Engine) Add ¶
Add records a new tool in the manifest and, unless the request marks it disabled, enqueues its install. Present-and-enabled is the default intent: adding means "have this installed".
func (*Engine) Close ¶
func (e *Engine) Close()
Close stops the job worker (cancelling any running job).
func (*Engine) EnsureInstalled ¶
EnsureInstalled synchronously guarantees a tool: present in the manifest (created from the catalog when missing), enabled, installed, and on PATH. This is the programmatic "a product action needs this binary now" path (a forge login installing gh, an MCP flow installing node); unlike Install it DOES enable a disabled template, because the user explicitly invoked the feature that needs the tool.
func (*Engine) Install ¶
Install re-enqueues an install for an existing, enabled tool (retry / install-missing). Installing a disabled template is refused with ErrDisabled: install is policy-neutral, enabling rides Patch.
func (*Engine) Inventory ¶
Inventory assembles the full read-side snapshot: every manifest entry joined with install state, the system group, and the active job.
func (*Engine) Patch ¶
func (e *Engine) Patch(name string, req PatchRequest) (*Job, error)
Patch merges fields into an existing tool and enqueues the follow-up job the transition needs: enable → install (when missing), disable → footprint uninstall (template kept), version change on an enabled tool → reinstall. Returns nil when no job is needed.
func (*Engine) Reconcile ¶
func (e *Engine) Reconcile(mode ReconcileMode) (*Job, error)
Reconcile enqueues the convergence job: install missing enabled entries, uninstall the engine-owned footprint of disabled ones. ReconcileFull additionally enqueues an update pass over unpinned entries. Returns (nil, nil) when the manifest is empty (nothing to converge). The returned job is the reconcile job; Wait on it to gate consumer readiness (session creation, UI states).
func (*Engine) Remove ¶
Remove uninstalls a tool and deletes its template. Without force, a tool that enabled entries require is refused and the dependents are returned. The removed manifest entries travel on the uninstall job so source-specific cleanup (npm/pip uninstalls, manual uninstall commands) still knows the sources after the manifest rows are gone.
func (*Engine) Search ¶
func (e *Engine) Search(query string) []CatalogEntry
Search queries the catalog (empty query = featured set), hiding entries already in the manifest.
type InstallSpec ¶
type InstallSpec struct {
URL string
Format string // tar.gz | tar.xz | tar.zst | zip | gz | xz | raw
ChecksumURL string // empty = no verification
ChecksumAlg string
Files []AquaFile
}
InstallSpec is the fully resolved plan for downloading one tool version on this machine: a URL, an archive format, the binaries to link, and an optional checksum source.
type Inventory ¶
type Inventory struct {
Job *Job `json:"job,omitempty"`
Tools []ToolInfo `json:"tools"`
System []SystemTool `json:"system"`
}
Inventory is the full read-side snapshot: every manifest entry joined with state, the system group, and the active job.
type Job ¶
type Job struct {
ID string `json:"id"`
Kind string `json:"kind"`
State string `json:"state"`
Error string `json:"error,omitempty"`
Names []string `json:"names,omitempty"`
// OutputTail carries the job's most recent output lines; populated
// by Jobs() snapshots only (live output streams via the
// Config.OnJobOutput callback).
OutputTail []string `json:"output_tail,omitempty"`
// Timestamps are Unix milliseconds.
CreatedAt int64 `json:"created_at"`
StartedAt int64 `json:"started_at,omitempty"`
EndedAt int64 `json:"ended_at,omitempty"`
}
Job is one queued/running/finished unit of engine work.
type Manifest ¶
type Manifest struct {
Tools map[string]Tool `json:"tools"`
// Comment is a single reserved documentation key preserved across
// engine rewrites (seed how-to text). Other unknown JSON keys are
// NOT preserved; the manifest is not a general round-tripping
// document.
Comment []string `json:"_comment,omitempty"`
Version int `json:"version"`
}
Manifest is the tools.json document (schema ManifestVersion).
func DefaultSeed ¶
func DefaultSeed() *Manifest
DefaultSeed returns the shared starter manifest: language-server templates for Go, TypeScript, and Python plus the GitHub CLI, all disabled. Nothing downloads until an entry is enabled; install knowledge (source, shims, dependencies, version) hydrates from the catalog at enable time. Returns a fresh copy on every call.
type PatchRequest ¶
type PatchRequest struct {
Version *string `json:"version,omitempty"`
Pin *bool `json:"pin,omitempty"`
Disabled *bool `json:"disabled,omitempty"`
Description *string `json:"description,omitempty"`
Requires *[]string `json:"requires,omitempty"`
Shims *map[string]string `json:"shims,omitempty"`
Install *string `json:"install,omitempty"`
Uninstall *string `json:"uninstall,omitempty"`
// Force permits disabling a tool that enabled entries require
// (mirrors Remove's force).
Force bool `json:"force,omitempty"`
}
PatchRequest edits an existing tool. Pointer fields distinguish "absent" from zero values. Disabled is the enable/disable toggle: false→true uninstalls the engine-owned footprint and keeps the template; true→false installs.
type ReconcileMode ¶
type ReconcileMode int
ReconcileMode selects how much a Reconcile job does.
const ( // ReconcileMissing converges intent without network: installs // missing enabled entries, uninstalls the engine-owned footprint of // disabled ones. Zero fetches when already converged. ReconcileMissing ReconcileMode = iota // ReconcileFull is ReconcileMissing plus an update pass over // unpinned entries (enqueued as a separate update job). ReconcileFull )
type State ¶
type State struct {
Tools map[string]ToolStatus `json:"tools"`
}
State is the tools-state.json document.
type SystemTool ¶
SystemTool is one image-baked binary surfaced read-only (Config.System).
type Tool ¶
type Tool struct {
// Shims maps extra bin names to command lines, written as wrapper
// scripts in the bin dir (e.g. typescript-language-server ->
// "tsc --lsp --stdio"). Shims are full command lines, not symlinks.
Shims map[string]string `json:"shims,omitempty"`
// Source locates the install definition: "aqua:cli/cli",
// "npm:pyright", "pip:x", "cargo:x", "go:golang.org/x/tools/gopls",
// or "manual". Empty = hydrate from the catalog.
Source string `json:"source,omitempty"`
// Version is the concrete upstream version, exactly as upstream
// tags it (may or may not carry a leading v). Never a range.
// Empty = resolve latest when the tool is actively installed.
Version string `json:"version,omitempty"`
// Description is display text (catalog-provided or user-written).
Description string `json:"description,omitempty"`
// Origin records provenance for linked entries, e.g. "mcp:<name>"
// for a tool created from an MCP add flow.
Origin string `json:"origin,omitempty"`
// Install is the shell command for Source == "manual". It runs via
// bash with VERSION, BIN, TOOLS, OPT and ARCH_* in the environment.
Install string `json:"install,omitempty"`
// Uninstall optionally overrides cleanup for Source == "manual".
Uninstall string `json:"uninstall,omitempty"`
// Probe is the bin name whose presence marks the tool installed
// (manual installs only; other sources derive it). Defaults to the
// tool name.
Probe string `json:"probe,omitempty"`
// Requires lists other manifest/catalog tool names that must be
// installed before (or alongside) this one, e.g. jdtls -> java.
// Backend-level needs (npm->node, pip->uv, cargo->rust, go->go)
// are implied and need not be listed.
Requires []string `json:"requires,omitempty"`
// Pin freezes the version: update runs skip this tool.
Pin bool `json:"pin,omitempty"`
// Disabled marks the entry a template: recorded intent whose
// install is explicitly bypassed. The reconciler uninstalls a
// disabled tool's engine-owned footprint and keeps the entry.
// Absent (false) means enabled — presence in the manifest is
// intent to have the tool installed.
Disabled bool `json:"disabled,omitempty"`
}
Tool is one manifest entry: the user's intent for a single tool. Every field except the map key (the tool name) is optional; empty Source/Version/Shims/Requires hydrate from the catalog when the tool is installed or updated.
type ToolInfo ¶
type ToolInfo struct {
Shims map[string]string `json:"shims,omitempty"`
Name string `json:"name"`
Source string `json:"source,omitempty"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
Origin string `json:"origin,omitempty"`
InstalledVersion string `json:"installed_version,omitempty"`
Latest string `json:"latest,omitempty"`
LastError string `json:"last_error,omitempty"`
Requires []string `json:"requires,omitempty"`
Pin bool `json:"pin,omitempty"`
Disabled bool `json:"disabled,omitempty"`
// Lsp marks a language-server entry (catalog knowledge); consumers
// use it for the no-LSP-enabled warning and UI badges.
Lsp bool `json:"lsp,omitempty"`
Installed bool `json:"installed"`
Installing bool `json:"installing"`
}
ToolInfo is one tool row in Inventory: the manifest entry joined with the engine's install state.
type ToolStatus ¶
type ToolStatus struct {
// UpdatedAt is when this status last changed.
UpdatedAt time.Time `json:"updated_at"`
// InstalledVersion is the version last installed successfully.
InstalledVersion string `json:"installed_version,omitempty"`
// LastError is the failure message of the most recent install
// attempt; cleared on success.
LastError string `json:"last_error,omitempty"`
// Bins are the names this tool owns in the bin dir (symlinks and
// shim wrappers), removed on uninstall.
Bins []string `json:"bins,omitempty"`
// PMBins are package-manager bin names discovered by diffing the
// pm's bin dir (npm/pip), symlinked into the bin dir.
PMBins []string `json:"pm_bins,omitempty"`
}
ToolStatus is the engine-owned per-tool machine state.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
toolcatalog
module
|
|
|
Package httpapi is the HTTP projection of a toolbelt Engine: a REST surface over the Engine's Go API, one route per method, JSON in and out.
|
Package httpapi is the HTTP projection of a toolbelt Engine: a REST surface over the Engine's Go API, one route per method, JSON in and out. |