Skip to content

Repository files navigation

Toolbox

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.

What you get

  • 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)

Requirements

  • Go 1.25+
  • make (optional, but recommended for common tasks)
  • golang.org/x/term (vendored — required for terminal width/TTY detection)

Quick start

Build and run:

make build
./bin/toolbox help

Without building:

go run ./cmd/toolbox help

On Windows, the binary path is:

bin/toolbox.exe

Command quick reference

toolbox help
toolbox plugin help
toolbox db help
toolbox db repl
toolbox ui help
toolbox --version

Top-level help is workflow-oriented and includes discovered namespaces and root plugins so you can jump directly to execution commands.

Global flags

Global flags can be placed anywhere in the command line:

  • --quiet suppresses normal informational output
  • --verbose enables debug output

Examples:

toolbox --verbose plugin discover
toolbox plugin list --quiet
toolbox --version

Plugin workflow

1. Scaffold a plugin

toolbox plugin init ./my-plugin

plugin 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>).

2. Install a plugin

From folder:

toolbox plugin add ./my-plugin

From archive:

toolbox plugin add ./my-plugin.zip
toolbox plugin add ./my-plugin.tar.gz

From URL:

toolbox plugin add https://example.com/my-plugin.tar.gz

When 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 list

3. Discover and list plugins

Sync plugins from filesystem into SQLite metadata:

toolbox plugin discover

List plugins from SQLite:

toolbox plugin list

toolbox plugin discover also prints guidance for running discovered plugins using namespace syntax.

4. Run and remove plugins

Remove plugin:

toolbox plugin remove my-plugin

Run root plugin:

toolbox my-plugin

Run namespaced plugin:

toolbox dev my-plugin

Run only namespace to get namespace-level help:

toolbox dev

Namespace 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]

Plugin authoring

Minimal layout (runtime.type = "executable")

my-plugin/
├── manifest.json
└── bin/
    └── my-plugin

Manifest example (executable)

{
  "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"
  }
}

Manifest example (command)

{
  "schemaVersion": "1.0",
  "id": "hello",
  "name": "Hello",
  "version": "1.0.0",
  "namespace": "dev",
  "runtime": {
    "type": "command",
    "command": "echo hello from toolbox"
  }
}

Manifest rules (enforced)

  • Required: schemaVersion, id, name, version, runtime.type
  • runtime.type must be executable or command
  • For executable, runtime.entrypoint is required
  • For command, runtime.command is required
  • id and namespace pattern: ^[a-z0-9][a-z0-9-_]*$
  • Reserved namespaces: help, plugin
  • runtime.entrypoint must stay inside plugin directory (path escape is rejected)

Runtime behavior

  • runtime.type = "executable": executes the plugin binary directly
  • runtime.type = "command":
    • Unix-like: /bin/sh -c
    • Windows: powershell.exe -NoProfile -NonInteractive -Command

Both runtime-defined args and user-provided CLI args are forwarded to execution.


Database and REPL

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 migrate

What toolbox db migrate does

  • Creates a consistent, timestamped backup of the DB at ~/.config/toolbox/toolbox.db.bak.YYYYMMDDTHHMMSS before making changes.
  • Converts the plugin table to support namespaced IDs and migrates existing rows. Rows without a namespace are moved into the local namespace.
  • Moves any plugin directories found directly under the plugins root (~/.config/toolbox/plugins/<id>) into ~/.config/toolbox/plugins/local/<id> and updates the DB path column accordingly. If local/<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 migrate

Rollback (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 repl

Supported REPL dot commands:

  • .help
  • .tables
  • .schema [table]
  • .indexes [table]
  • .count [table]
  • .dump [table]
  • .exit / .quit

Storage paths

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

Development

Common targets

make tidy
make fmt
make vet
make test
make build
make run
make clean
make dist

Run locally with args:

make run ARGS="plugin list"

Run one test:

go test ./internal/app -run TestResolvePluginTargetParsesExplicitNamespaceAndPlugin

Coverage notes (refactored UX)

  • Help discoverability and ordering coverage:
    • go test ./internal/cli -run TestPrintPluginsHelpIncludesWorkflowGuidance
    • go test ./internal/cli -run TestPrintHelpSortsRootPluginsAndNamespaces
  • Plugin execution guidance coverage:
    • go test ./internal/app -run TestExecPluginReturnsGuidanceWhenCommandMissing
    • go test ./internal/app -run TestExecPluginReturnsGuidanceWhenRootPluginNotFound
    • go test ./internal/app -run TestExecPluginReturnsGuidanceWhenNamespacedPluginNotFound

Build artifacts

  • Local binary: bin/toolbox (or bin/toolbox.exe)
  • Cross-platform release binaries: dist/
  • Build version comes from VERSION and is injected via linker flags

Release automation

  • Pushes to develop bump patch version in VERSION.
  • Pushes to main build 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 in owner/repo format)

Internal architecture

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

Output contract (internal/command)

All command handlers share a common output contract defined in internal/command/output.go:

  • exitOK / exitError — standard exit codes
  • fail(err) — prints error via ui.PrintError and returns exitError
  • failf(format, args...) — formats and prints error, returns exitError

Color palette

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 list

Set a palette:

toolbox ui palette default
toolbox ui palette dracula
toolbox ui palette solarized

Show 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.

Responsive UI (internal/ui)

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); .indexes and .count output uses the same table renderer.

Operational notes

  • Plugin execution resolves from the filesystem, not from SQLite.
  • toolbox plugin discover is the sync point from filesystem -> SQLite metadata.
  • If plugin add is 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 .indexes and .count dot commands accept an optional table name argument.

About

CLI for manage scripts, commands or executables

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages