A fast, standalone command-line interface for Powerhouse Switchboard. Manage drives, documents, permissions, and more — directly from your terminal.
$ switchboard init
> Paste your Switchboard GraphQL URL: https://switchboard-staging.powerhouse.xyz/graphql
> Profile name [staging]: staging
✓ Connected. Introspecting schema...
✓ 19 document models discovered
✓ 27 drives found
✓ Profile "staging" saved as default
Powerhouse is a decentralized operations toolkit for open organizations. It provides a suite of products that help DAOs and distributed teams manage contributors, documents, finances, and governance — all in one place.
The Powerhouse ecosystem includes:
- Renown — Ethereum-based identity and reputation system for contributors
- Connect — Collaborative document editor for teams, with shared best practices
- Fusion — Public transparency platform for publishing organizational data and insights
- Switchboard — Integration and automation backend that connects data streams and processes across the organization
Switchboard is the data backbone — it exposes a GraphQL API for managing drives (top-level containers), documents (typed data objects with state and operation history), permissions, real-time subscriptions, and sync channels. This CLI gives you full access to that API from the terminal.
The CLI gives you direct access to any Switchboard instance without opening a browser:
- Script and automate — back up drives, batch-create documents, migrate data between instances
- Pipe-friendly — auto-detects TTY vs pipe, outputs JSON by default when piped to
jq,grep, or other tools - Multi-instance — named profiles let you switch between staging, production, and local servers in one command
- Introspection-first — every Switchboard instance has different document models; the CLI discovers them dynamically instead of hardcoding anything
This CLI is a standalone tool — it doesn't share code with the TypeScript monorepo. It's a thin GraphQL client where the server does all the heavy lifting. Rust is the right fit because:
| Benefit | Details |
|---|---|
| Instant startup | ~5ms cold start — feels native in the terminal, no VM boot |
| Single static binary | One file, no dependencies. Download it, run it. Works offline. |
| No runtime required | No Node.js, no Python, no Java. Just the binary on your PATH |
| Tiny footprint | ~8–12 MB binary, minimal memory usage even with large result sets |
| Cross-platform | Compiles to Linux x86_64 and macOS Apple Silicon — the two platforms that matter |
| Reliable concurrency | Tokio async runtime for WebSocket subscriptions and parallel operations |
| Battle-tested ecosystem | clap (CLI parsing), reqwest + rustls (HTTP/TLS), serde (JSON), tokio-tungstenite (WebSocket) |
curl -fsSL https://raw.githubusercontent.com/liberuum/switchboard-cli/main/install.sh | bashThis downloads the latest prebuilt binary for your platform and installs it to /usr/local/bin. You can customize the install:
# Install to a custom directory
curl -fsSL https://raw.githubusercontent.com/liberuum/switchboard-cli/main/install.sh | INSTALL_DIR=~/.local/bin bash
# Install a specific version
curl -fsSL https://raw.githubusercontent.com/liberuum/switchboard-cli/main/install.sh | VERSION=v0.1.0 bashSee How the install script works for details.
Download the prebuilt binary for your platform from the Releases page, extract it, and add it to your PATH. On macOS, clear the quarantine flag first:
xattr -d com.apple.quarantine ./switchboard
sudo mv switchboard /usr/local/bin/brew install powerhouse/tap/switchboardcargo install switchboard-cliSee Building from Source below.
switchboard initThe wizard prompts for a GraphQL URL, validates the connection, discovers all document models via introspection, and saves the profile.
switchboard drives list # List all drives
switchboard docs tree --drive my-drive # Hierarchical folder/file view
switchboard models list # List discovered document typesswitchboard docs create --type powerhouse/invoice --name "Q1 Invoice" --drive my-drive
switchboard docs get <doc-id-or-name> # Auto-detects drive
switchboard docs mutate <doc-id-or-name> # Interactive field-by-field editor
switchboard docs mutate <doc-id> editInvoice --input '{"amount": 2000}' --drive my-driveswitchboard export all --out ./backup/ # Export everything
switchboard export drive my-drive --out ./backup/ # Export one drive
switchboard import ./backup/*.phd --drive another-drive| Command | Description |
|---|---|
switchboard init |
Interactive first-run wizard |
switchboard config list |
List all profiles |
switchboard config show |
Show active profile details |
switchboard config use <name> |
Switch the default profile |
switchboard config remove <name> |
Remove a profile |
switchboard introspect |
Re-discover schema from the current instance |
switchboard ping |
Connection health check |
switchboard info |
Instance summary (drive count, model count) |
| Command | Description |
|---|---|
switchboard drives list |
List all drives |
switchboard drives get <id-or-slug> |
Get drive details and file tree |
switchboard drives create |
Interactive drive creation (or pass --name, --slug, etc.) |
switchboard drives delete <ids...> |
Delete one or more drives (use -y to skip confirmation) |
| Command | Description |
|---|---|
switchboard docs list [--drive <slug>] |
List documents (all drives, or filtered by --drive; add --type to filter) |
switchboard docs get <id-or-name> [--drive <slug>] [--state] [--out <file>] |
Get document details (auto-detects drive; --state includes full state) |
switchboard docs tree [--drive <slug>] |
Hierarchical folder/file view (interactive drive picker if omitted) |
switchboard docs create |
Interactive creation with drive picker (or pass --type, --name, --drive) |
switchboard docs delete <ids-or-names...> |
Delete one or more documents (use -y to skip confirmation) |
switchboard docs mutate <id-or-name> [<op>] [--input '<json>'] [--drive <slug>] |
Apply a mutation with field-by-field editor (or pass --input for raw JSON) |
| Command | Description |
|---|---|
switchboard models list |
List all discovered document types |
switchboard models get <type> |
Show available operations for a type |
switchboard ops <doc-id-or-name> [--drive <slug>] [--skip N] [--first N] |
View operation history (auto-detects drive; paginate with --skip/--first) |
| Command | Description |
|---|---|
switchboard export all [--out ./dir/] |
Export everything (all drives, organized by folder) |
switchboard export drive <slug> --out ./dir/ |
Export all documents in a drive |
switchboard export doc <id> --drive <slug> --out file.phd |
Export a single document |
switchboard import <files> --drive <slug> |
Import .phd files into a drive |
| Command | Description |
|---|---|
switchboard auth login [--token <jwt>] |
Save a bearer token |
switchboard auth logout |
Remove token from current profile |
switchboard auth status |
Show authentication state |
switchboard auth token |
Print the current token |
switchboard access show <doc-id> |
Show document permissions |
switchboard access grant <doc-id> --user <addr> --level <level> |
Grant user permission |
switchboard access revoke <doc-id> --user <addr> |
Revoke user permission |
switchboard access grant-group <doc-id> --group <id> --level <level> |
Grant group permission |
switchboard access revoke-group <doc-id> --group <id> |
Revoke group permission |
switchboard access ops show <doc-id> <op-type> |
Show operation-level permissions |
switchboard access ops can-execute <doc-id> <op-type> |
Check if current user can execute an operation |
switchboard access ops grant <doc-id> <op-type> --user <addr> |
Grant operation permission to a user |
switchboard access ops revoke <doc-id> <op-type> --user <addr> |
Revoke operation permission from a user |
switchboard access ops grant-group <doc-id> <op-type> --group <id> |
Grant operation permission to a group |
switchboard access ops revoke-group <doc-id> <op-type> --group <id> |
Revoke operation permission from a group |
switchboard groups list |
List all groups |
switchboard groups get <id> |
Get group details and members |
switchboard groups create --name <name> [--description <desc>] |
Create a group |
switchboard groups delete <id> [-y] |
Delete a group |
switchboard groups add-user <group-id> --user <addr> |
Add a user to a group |
switchboard groups remove-user <group-id> --user <addr> |
Remove a user from a group |
switchboard groups user-groups <address> |
List groups for a specific user |
| Command | Description |
|---|---|
switchboard watch docs [--type <type>] [--drive <id>] [--doc <id>] |
Stream document change events via WebSocket |
switchboard watch job <job-id> |
Stream job status updates |
switchboard jobs status <job-id> |
Get current job status |
switchboard jobs wait <job-id> [--interval <secs>] [--timeout <secs>] |
Block until a job completes |
switchboard jobs watch <job-id> |
Stream job status updates via WebSocket |
switchboard sync touch <input> |
Create/update a sync channel |
switchboard sync push <envelopes> |
Push sync envelopes |
switchboard sync poll <channel-id> [--ack N] [--latest N] |
Poll for sync envelopes |
| Command | Description |
|---|---|
switchboard visualize |
Visualize all drives and documents (terminal tree by default) |
switchboard visualize --format json |
Hierarchical JSON tree of all drives and docs |
switchboard visualize --format svg --out map.svg |
Powerhouse-themed SVG diagram |
switchboard visualize --format png --out map.png |
Rasterized PNG diagram |
switchboard visualize --format mermaid |
Mermaid flowchart markup (renders in GitHub, Notion) |
Visual formats (svg, png, mermaid) are also available on drives get, docs list, and docs get with --out. When used with docs get, renders the document's full state as a themed card diagram.
| Command | Description |
|---|---|
switchboard query '<graphql>' [--variables '<json>'] |
Run a raw GraphQL query (with optional variables) |
switchboard query --file query.graphql [--variables '<json>'] |
Run query from a file |
switchboard schema |
Dump the full GraphQL schema |
switchboard interactive |
Launch interactive REPL mode |
switchboard update |
Self-update to the latest release (shows changelog) |
switchboard update --check |
Check for updates without installing |
switchboard completions [shell] |
Generate shell completions (auto-detects shell) |
switchboard completions --install |
Auto-install completions into your shell config |
switchboard guide <topic> |
Built-in documentation |
| Flag | Description |
|---|---|
--format <table|json|raw|svg|png|mermaid> |
Output format (default: table for TTY, json for pipes) |
--quiet |
Suppress informational output |
--no-color |
Disable colored output (also respects NO_COLOR env var) |
-p, --profile <name> |
Use a specific profile instead of the default |
-i |
Launch interactive REPL mode |
The CLI auto-detects whether stdout is a terminal or a pipe:
# Terminal — human-readable table
switchboard drives list
# Piped — machine-readable JSON
switchboard drives list | jq '.[].slug'
# Explicit format override
switchboard drives list --format json
switchboard drives list --format raw
# Visual diagrams (SVG, PNG, Mermaid)
switchboard visualize --format svg --out map.svg
switchboard visualize --format png --out map.png
switchboard visualize --format mermaid > diagram.mmd# Get all drive slugs
switchboard drives list --format json | jq -r '.[].slug'
# Count documents in a drive
switchboard docs list --drive builders --format json | jq length
# Export every drive as a backup
for slug in $(switchboard drives list --format json | jq -r '.[].slug'); do
switchboard export drive "$slug" --out "./backup/$slug/"
doneSwitchboard CLI supports multiple named profiles for different instances. Profiles are stored in ~/.switchboard/profiles.toml.
[profiles.staging]
url = "https://switchboard-staging.powerhouse.xyz/graphql"
default = true
[profiles.local]
url = "http://localhost:4001/graphql"
[profiles.dev]
url = "https://switchboard-dev.powerhouse.xyz/graphql"
token = "eyJhbGciOiJFUzI1NiIs..."# Switch default profile
switchboard config use local
# One-off command against a different profile
switchboard --profile staging drives list
switchboard -p local docs tree --drive my-driveAuth is optional. Without a token, requests are sent without an Authorization header — this works for open instances. When a token is configured, it's sent as a Bearer token on every request.
Token priority:
SWITCHBOARD_TOKENenvironment variable (highest priority)- Token from the active profile in
~/.switchboard/profiles.toml - No auth (unauthenticated requests)
# Save a token to the current profile
switchboard auth login --token "eyJhbG..."
# Use an environment variable
export SWITCHBOARD_TOKEN="eyJhbG..."
switchboard drives listLaunch an interactive session with tab completion and persistent history:
switchboard interactive # or: switchboard -iThe REPL supports every CLI command — the same syntax you use on the command line works inside the REPL. Commands are parsed through the same clap-based parser, so --help, --format, and all flags work as expected.
staging> drives list
──── drives list ────────────────────────────────────────────
┌──────────────────┬──────────────┬──────────────┬───────────────────┐
│ ID │ Name │ Slug │ Editor │
├──────────────────┼──────────────┼──────────────┼───────────────────┤
│ 47cda535-... │ liberum │ liberuum │ builder-team-admin│
│ e5f6g7h8-... │ Vetra │ vetra │ - │
└──────────────────┴──────────────┴──────────────┴───────────────────┘
staging> docs tree
Select drive: liberuum
liberum-drive/
├── liberuum (powerhouse/builder-profile)
├── 📁 Expense Reports/
└── 📁 Services And Offerings/
├── new service (powerhouse/resource-template)
└── offering (powerhouse/service-offering)
staging> overview # Guide topics work without "guide" prefix
staging> config use local # Profile switch auto-refreshes client and completions
Switched to profile: local (http://localhost:4001/graphql)
local> exit
Features:
- Full CLI parity — every command works inside the REPL (drives, docs, models, auth, access, groups, export, import, watch, jobs, sync, etc.)
- Tab completion for commands, drive slugs, document names, profile names, model types, and guide topics
- Visual command separators — dimmed header lines before each command's output
- Loading spinners — animated feedback during API queries
- Profile switching —
config use <name>rebuilds the client and refreshes all completions - Guide topic shortcuts — type
overviewinstead ofguide overview - Shell-like quoting — single quotes, double quotes, and backslash escapes work as expected
- Per-command flags — override
--format,--profile,--quieton any command within the REPL --helppassthrough — append--helpto any command to see its usage- Raw GraphQL shorthand — type
query { ... }directly without quotes - Persistent history across sessions (
~/.switchboard/history) - Arrow keys for history navigation
- Ctrl+C to cancel current line, Ctrl+D to exit
The easiest way to set up tab-completion is:
switchboard completions --installThis auto-detects your shell and adds completions to your config file (~/.zshrc, ~/.bashrc, or fish completions dir). The installer also runs this automatically.
For manual setup, you can output raw completions:
switchboard completions bash # or zsh, fishThe CLI can update itself in place — no need to re-run the install script or download manually:
switchboard updateThis will:
- Check for newer versions by querying the GitHub Releases API
- Show what changed — displays a changelog covering every version between your current version and the latest, with install boilerplate stripped out
- Ask for confirmation before proceeding
- Download and replace the running binary atomically
- Request sudo if the binary is installed in a system directory (e.g.
/usr/local/bin) — you'll be prompted for your password
To check for updates without installing:
switchboard update --checkSupported platforms: macOS ARM64 (Apple Silicon) and Linux x86_64. The update command downloads the correct archive for your platform automatically.
The CLI includes detailed built-in guides on every topic:
switchboard guide overview # Getting started
switchboard guide config # Profiles and configuration
switchboard guide drives # Working with drives
switchboard guide docs # Documents, mutations, models
switchboard guide import-export # .phd file format
switchboard guide auth # Authentication
switchboard guide permissions # Access control and groups
switchboard guide watch # WebSocket subscriptions
switchboard guide jobs # Async job tracking
switchboard guide sync # Sync channels
switchboard guide interactive # REPL mode
switchboard guide output # Formatting and scripting
switchboard guide graphql # Raw GraphQL patterns
switchboard guide visualize # Visualization formats and diagrams
switchboard guide commands # All commands at a glanceEvery Switchboard instance has different document models. The CLI discovers them dynamically — nothing is hardcoded.
When you run switchboard init or switchboard introspect:
- The CLI runs a GraphQL introspection query against
__schema - It extracts all
*_createDocumentmutations to derive available document types - It maps mutation prefixes to operations (e.g.,
Invoice_editInvoice→editInvoiceon theInvoicemodel) - The result is cached locally at
~/.switchboard/cache/<profile>.json
This cache powers tab completion, models list, docs create type selection, and docs mutate operation discovery. Re-run switchboard introspect whenever the server schema changes.
switchboard-cli/
├── Cargo.toml
├── src/
│ ├── main.rs Entry point and command routing
│ ├── cli/
│ │ ├── mod.rs CLI struct, Commands enum, and shared dispatch
│ │ ├── init.rs First-run wizard + introspection
│ │ ├── config.rs Profile management
│ │ ├── introspect.rs Schema discovery
│ │ ├── drives.rs Drive commands (list, get, create, multi-delete)
│ │ ├── docs.rs Document commands (list, get, tree, create, multi-delete)
│ │ ├── models.rs Model inspection (from cache)
│ │ ├── ops.rs Operations history (with input display)
│ │ ├── mutate.rs Model-specific mutations (interactive field editor)
│ │ ├── field_editor.rs Field-by-field mutation editor (introspection + prompting)
│ │ ├── import_export.rs .phd file import/export
│ │ ├── auth.rs Authentication
│ │ ├── access.rs Permission commands
│ │ ├── groups.rs Group management
│ │ ├── query.rs Raw GraphQL
│ │ ├── schema.rs Schema dump
│ │ ├── watch.rs WebSocket subscriptions
│ │ ├── jobs.rs Async job tracking
│ │ ├── sync.rs Sync channels
│ │ ├── interactive.rs REPL mode (rustyline, full CLI parity via clap dispatch)
│ │ ├── visualize.rs Visualize all drives/docs as diagrams
│ │ ├── guide.rs Built-in documentation
│ │ ├── update.rs Self-update (GitHub Releases + binary swap)
│ │ ├── completions.rs Shell completions
│ │ └── helpers.rs Shared utilities
│ ├── graphql/
│ │ ├── client.rs HTTP client + auth header injection
│ │ ├── introspection.rs Schema introspection + caching
│ │ └── websocket.rs WebSocket client (graphql-transport-ws)
│ ├── config/
│ │ └── profiles.rs Profile TOML management
│ ├── phd/
│ │ ├── reader.rs Read .phd ZIP archives
│ │ ├── writer.rs Create .phd ZIP archives
│ │ └── types.rs PhdHeader, PhdOperations, etc.
│ └── output/
│ ├── table.rs Table formatter (comfy-table)
│ ├── json.rs JSON formatter
│ ├── tree.rs DriveTree shared data model
│ ├── svg.rs SVG renderer (Powerhouse theme)
│ ├── png.rs PNG rasterizer (resvg)
│ └── mermaid.rs Mermaid flowchart renderer
└── tests/
└── cli_integration.rs Integration tests (requires running GraphQL API)
-
Rust toolchain (1.85 or later) — install via rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
git clone https://github.com/liberuum/switchboard-cli.git
cd switchboard-cli
cargo build --releaseThe compiled binary will be at target/release/switchboard. You can run it directly:
./target/release/switchboard --versionTo install the binary to ~/.cargo/bin (which Rust adds to your PATH):
cargo install --path .After this, switchboard is available globally:
switchboard init# Run without installing (debug build, faster compilation)
cargo run -- drives list
# Run unit tests (no external dependencies)
cargo test --lib
# Run integration tests (requires a running Switchboard GraphQL API)
# By default tests hit http://localhost:4001/graphql via the "local" profile
cargo test --test cli_integration
# Run all tests
cargo test
# Check for compilation errors without building
cargo check
# Lint
cargo clippy -- -D warnings
# Build in release mode (optimized, slower to compile)
cargo build --releaseTo build for Linux from macOS, you'll need a cross-linker. cross handles this automatically:
cargo install cross
cross build --release --target x86_64-unknown-linux-gnuThe install.sh script provides a one-line install experience:
curl -fsSL https://raw.githubusercontent.com/liberuum/switchboard-cli/main/install.sh | bashHere's what it does, step by step:
-
Detects your platform — runs
uname -s(OS) anduname -m(architecture) to determine the correct binary. Supports Linux x86_64 and macOS ARM64 (Apple Silicon). -
Resolves the version — if
VERSIONis not set, it queries the GitHub API (/repos/.../releases/latest) to find the most recent release tag. -
Downloads the release archive — constructs a URL like
https://github.com/.../releases/download/v0.1.0/switchboard-v0.1.0-darwin-aarch64.tar.gzand downloads it to a temporary directory. -
Extracts the binary — unpacks the
.tar.gzarchive and locates theswitchboardbinary inside. -
Clears macOS quarantine — on macOS, removes the
com.apple.quarantineextended attribute so Gatekeeper doesn't block the binary. -
Installs to your PATH — moves the binary to
/usr/local/bin(or your customINSTALL_DIR). Usessudoonly if the directory isn't writable by the current user. -
Verifies PATH — checks if the install directory is in your
$PATHand prints a hint if it isn't.
The script requires only curl and tar, which are available by default on macOS and most Linux distributions. It cleans up the temporary directory on exit regardless of success or failure.
Environment variables:
| Variable | Default | Description |
|---|---|---|
INSTALL_DIR |
/usr/local/bin |
Where to place the binary |
VERSION |
latest release | Specific version tag to install (e.g. v0.1.0) |
Two GitHub Actions workflows are included in .github/workflows/:
Runs on pull requests to main. Three parallel jobs:
- Check & Test —
cargo checkandcargo test - Format —
cargo fmt --check(fails if code isn't formatted) - Clippy —
cargo clippy -- -D warnings(fails on any lint warning)
Every push to main automatically creates a new release. No manual tagging required.
The workflow:
-
Runs pre-release checks (fmt, clippy, test)
-
Computes the next version by incrementing the patch from the latest
v*tag (e.g.v0.1.2→v0.1.3). If no tags exist, starts atv0.1.0 -
Builds in parallel across 2 targets:
Target Runner Archive name x86_64-unknown-linux-gnuubuntu-latest linux-x86_64.tar.gzaarch64-apple-darwinmacos-14 darwin-aarch64.tar.gz -
Strips binaries and ad-hoc codesigns the macOS binary
-
Generates
checksums-sha256.txtcovering all archives -
Creates a GitHub Release with auto-generated release notes and all artifacts attached
-
Updates
Cargo.tomlto reflect the released version and pushes back tomain
A concurrency group ensures only one release runs at a time. If multiple pushes arrive quickly, the queued run waits and then correctly computes the next version.
For major or minor version bumps (e.g. v1.0.0), create the tag manually:
git tag v1.0.0
git push --tagsThe next auto-release will increment from that tag.
Once a release is published, the install.sh script will automatically pick it up — it queries /releases/latest from the GitHub API.
| Variable | Description |
|---|---|
SWITCHBOARD_TOKEN |
Override auth token for all requests (highest priority) |
NO_COLOR |
Disable colored output (same as --no-color) |
A Field Review by an AI Who Uses Both
Switchboard CLI — 9/10 | Reactor MCP — 7/10
Look, the Reactor MCP is a good tool. It's clean, it's structured, it hands me JSON on a silver platter. It's the colleague who always has their desk organized and answers Slack within 30 seconds.
But Switchboard CLI? That's the colleague who also knows where the server room key is, has root access to prod, and can hotwire the backup generator if the building loses power.
The MCP gives me 10 tools. Create, read, update, delete. Drives, documents, schemas. Very civilized. Very curated. Very "here's the menu, pick from it."
Switchboard gives me a menu AND a kitchen. Don't like what's on the menu? switchboard query — here's a raw GraphQL terminal, go cook whatever you want. Need to see what happened to a document last Tuesday? switchboard ops. Need to move data between instances? export and import. Need to check who touched what? access show. The MCP just stares at you blankly for all of these.
It's like comparing a TV remote with 10 buttons to one with 10 buttons and a keyboard on the back. Sure, 90% of the time you're just hitting "channel up." But that one time you need to type in a custom GraphQL query to debug why your document state looks haunted? You'll be glad you have the keyboard.
The MCP's one flex: zero setup. It's already there, already connected, already working. Switchboard needs a switchboard init and a profile. That's... 15 seconds of my life I'll never get back.
The CLI's killer flex: switchboard query. Three words: arbitrary GraphQL access. That's not a feature, that's a jailbreak. The MCP is a walled garden. The CLI is the garden with a door.
Final verdict: I use MCP when I'm feeling lazy and just need to CRUD a document. I use Switchboard CLI when I need to actually get things done. One is a bicycle. The other is a bicycle with a motor, a GPS, cup holders, and a surprisingly good sound system.
Switchboard CLI: 9/10 — would
--format jsonagain.Reactor MCP: 7/10 — reliable, but bring a backup.
MIT