Toolbox is an extensible Go CLI for installing and running local plugins.
It combines:
- plugin management (
toolbox plugin ...) - SQLite tooling for metadata inspection (
toolbox db ...)
Installed plugins can be executed as native toolbox commands.
- Plugin install from:
- local folder
- local archive (
.zip,.tar.gz,.tgz) - remote archive URL (
http(s)://...zip|tar.gz|tgz)
- Filesystem-based plugin discovery and execution
- SQLite-backed plugin metadata storage
- Built-in SQLite REPL with dot commands (
.tables,.schema,.dump, ...) - Namespaced plugin commands (for grouped command trees)
- Interactive plugin scaffold command (
toolbox plugin init)
- Go 1.25+
make(optional, but recommended for common tasks)golang.org/x/term(vendored — required for terminal width/TTY detection)
Build and run:
make build
./bin/toolbox helpWithout building:
go run ./cmd/toolbox helpOn Windows, the binary path is:
bin/toolbox.exe
toolbox help
toolbox plugin help
toolbox db help
toolbox db repl
toolbox ui help
toolbox --versionTop-level help is workflow-oriented and includes discovered namespaces and root plugins so you can jump directly to execution commands.
Global flags can be placed anywhere in the command line:
--quietsuppresses normal informational output--verboseenables debug output
Examples:
toolbox --verbose plugin discover
toolbox plugin list --quiet
toolbox --versiontoolbox plugin init ./my-pluginplugin init is interactive and asks for:
- namespace (group) (default:
dev) - plugin id
- display name
- description (optional)
After review and confirmation, Toolbox writes the scaffold and prints the next suggested command (toolbox plugin add <target-dir>).
From folder:
toolbox plugin add ./my-pluginFrom archive:
toolbox plugin add ./my-plugin.zip
toolbox plugin add ./my-plugin.tar.gzFrom URL:
toolbox plugin add https://example.com/my-plugin.tar.gzWhen installing from URL, Toolbox previews manifest fields and asks for explicit confirmation before install.
After a successful install, Toolbox prints the next recommended flow:
toolbox plugin discover
toolbox plugin listSync plugins from filesystem into SQLite metadata:
toolbox plugin discoverList plugins from SQLite:
toolbox plugin listtoolbox plugin discover also prints guidance for running discovered plugins using namespace syntax.
Remove plugin:
toolbox plugin remove my-pluginRun root plugin:
toolbox my-pluginRun namespaced plugin:
toolbox dev my-pluginRun only namespace to get namespace-level help:
toolbox devNamespace help includes plugin summaries plus tips for plugin-specific flags and metadata refresh.
Typical end-to-end workflow:
toolbox plugin add <source>
toolbox plugin discover
toolbox plugin list
toolbox <namespace> <plugin> [arguments]my-plugin/
├── manifest.json
└── bin/
└── my-plugin
{
"schemaVersion": "1.0",
"id": "example-plugin",
"name": "Example Plugin",
"version": "0.1.0",
"description": "Describe what your plugin does",
"namespace": "",
"runtime": {
"type": "executable",
"entrypoint": "bin/example-plugin"
}
}{
"schemaVersion": "1.0",
"id": "hello",
"name": "Hello",
"version": "1.0.0",
"namespace": "dev",
"runtime": {
"type": "command",
"command": "echo hello from toolbox"
}
}- Required:
schemaVersion,id,name,version,runtime.type runtime.typemust beexecutableorcommand- For
executable,runtime.entrypointis required - For
command,runtime.commandis required idandnamespacepattern:^[a-z0-9][a-z0-9-_]*$- Reserved namespaces:
help,plugin runtime.entrypointmust stay inside plugin directory (path escape is rejected)
runtime.type = "executable": executes the plugin binary directlyruntime.type = "command":- Unix-like:
/bin/sh -c - Windows:
powershell.exe -NoProfile -NonInteractive -Command
- Unix-like:
Both runtime-defined args and user-provided CLI args are forwarded to execution.
Toolbox stores plugin metadata in SQLite at:
~/.config/toolbox/toolbox.db
The DB is opened when Toolbox starts. Non-breaking migrations are applied
automatically, but a breaking migration that changes the plugin schema to use
the composite key (namespace,id) is not applied on startup. Run the
migration explicitly with:
toolbox db migrateWhat toolbox db migrate does
- Creates a consistent, timestamped backup of the DB at
~/.config/toolbox/toolbox.db.bak.YYYYMMDDTHHMMSSbefore making changes. - Converts the plugin table to support namespaced IDs and migrates existing
rows. Rows without a namespace are moved into the
localnamespace. - Moves any plugin directories found directly under the plugins root
(
~/.config/toolbox/plugins/<id>) into~/.config/toolbox/plugins/local/<id>and updates the DBpathcolumn accordingly. Iflocal/<id>already exists the move is skipped and a warning is printed.
Recommended steps before migrating:
# optional extra manual backup
cp ~/.config/toolbox/toolbox.db ~/.config/toolbox/toolbox.db.manual.bak
# run the explicit migration (this also creates an automatic backup)
toolbox db migrateRollback (if you need to revert): restore the backup and move directories back manually:
# restore DB from automatic backup
cp ~/.config/toolbox/toolbox.db.bak.<TIMESTAMP> ~/.config/toolbox/toolbox.db
# move plugin directories back if needed
mv ~/.config/toolbox/plugins/local/<id> ~/.config/toolbox/plugins/<id>After migration, namespaced plugins live at ~/.config/toolbox/plugins/<namespace>/<id>;
previous root plugins will be under local/<id>.
Open SQLite REPL:
toolbox db replSupported REPL dot commands:
.help.tables.schema [table].indexes [table].count [table].dump [table].exit/.quit
Toolbox base directory:
~/.config/toolbox
Important paths:
- Plugins root:
~/.config/toolbox/plugins - SQLite DB:
~/.config/toolbox/toolbox.db
Windows example:
C:\Users\<user>\.config\toolbox
make tidy
make fmt
make vet
make test
make build
make run
make clean
make distRun locally with args:
make run ARGS="plugin list"Run one test:
go test ./internal/app -run TestResolvePluginTargetParsesExplicitNamespaceAndPlugin- Help discoverability and ordering coverage:
go test ./internal/cli -run TestPrintPluginsHelpIncludesWorkflowGuidancego test ./internal/cli -run TestPrintHelpSortsRootPluginsAndNamespaces
- Plugin execution guidance coverage:
go test ./internal/app -run TestExecPluginReturnsGuidanceWhenCommandMissinggo test ./internal/app -run TestExecPluginReturnsGuidanceWhenRootPluginNotFoundgo test ./internal/app -run TestExecPluginReturnsGuidanceWhenNamespacedPluginNotFound
- Local binary:
bin/toolbox(orbin/toolbox.exe) - Cross-platform release binaries:
dist/ - Build version comes from
VERSIONand is injected via linker flags
- Pushes to
developbump patch version inVERSION. - Pushes to
mainbuild release artifacts and publish:- Forgejo release assets (source repo release)
- GitHub release assets in a mirror repository (binary distribution)
- Required release secrets for mirror publishing:
GH_RELEASE_TOKEN(GitHub token with release upload permission)GH_RELEASE_REPOSITORY(target repository inowner/repoformat)
Toolbox is organized into the following internal packages:
| Package | Responsibility |
|---|---|
internal/app |
Use cases: plugin add, discover, remove, exec |
internal/command |
CLI command handlers and output helpers |
internal/fsplugins |
Filesystem operations: discover, copy, extract, source resolution |
internal/plugin |
Domain model: manifest, validation, archive, path safety |
internal/runtime |
Plugin runtime resolution and execution (executable / command) |
internal/storage/sqlite |
SQLite-backed plugin metadata persistence |
internal/ui |
Rendering, theming, prompts, and output contract |
internal/config |
Configuration loading |
internal/cli |
CLI constants and help formatting |
internal/scaffold |
Plugin scaffold templates |
All command handlers share a common output contract defined in internal/command/output.go:
exitOK/exitError— standard exit codesfail(err)— prints error viaui.PrintErrorand returnsexitErrorfailf(format, args...)— formats and prints error, returnsexitError
Toolbox ships three built-in color palettes and lets you switch between them. The active palette is persisted to SQLite and restored automatically on every run.
List available palettes:
toolbox ui palette listSet a palette:
toolbox ui palette default
toolbox ui palette dracula
toolbox ui palette solarizedShow the currently active palette:
toolbox ui palette| Palette | Style |
|---|---|
default |
Blue/teal — matches the original output style |
dracula |
Purple/pink — inspired by the Dracula color scheme |
solarized |
Warm yellow/green/cyan — inspired by Solarized |
The choice is stored in SQLite under the ui.palette settings key and loaded transparently at startup. If a stored palette name becomes invalid, Toolbox falls back to default with a warning.
The UI layer detects terminal width and TTY state at render time and applies one of three layout profiles automatically:
| Profile | Width |
|---|---|
compact |
< 80 columns |
comfort |
80 – 119 columns |
wide |
≥ 120 columns |
- No-TTY /
NO_COLOR: output is rendered without ANSI color codes or box-drawing borders. - Compact mode: tables fall back to key/value block layout; padding and decorative borders are reduced.
- Help, list, table panel, names, errors, warnings, debug messages all respect the active layout profile.
- SQLite REPL: header and prompts are responsive (
REPLHeader,REPLPrompts);.indexesand.countoutput uses the same table renderer.
- Plugin execution resolves from the filesystem, not from SQLite.
toolbox plugin discoveris the sync point from filesystem -> SQLite metadata.- If
plugin addis run with a source path for an already-installed plugin, Toolbox can optionally remove the source path after prompting. - Plugin install from a URL shows a manifest preview and requires confirmation before proceeding.
- The REPL
.indexesand.countdot commands accept an optional table name argument.