Toolmux
Website: toolmux.com
Toolmux connects services to your local agents and gives you the same tools as a normal CLI. Register Slack, Google, or a remote MCP server once, configure your agent once, then ask the agent to use those tools without copying tokens into prompts.
Toolmux is built around four ideas:
- One command surface for people, scripts, and agents.
- Local credential custody through the operating system credential store.
- Tool policy and
--read-onlychecks before tool credentials are loaded. - Workflows that turn repeatable prompts into commands.
Toolmux is early software. Today it is most useful for Slack, Google Drive, Google Docs, Google Sheets, remote MCP toolboxes, and local agent setup for Codex and Claude Code.
Supported Today
Use the CLI for the live list in your installed version:
toolmux --help
toolmux list
toolmux list --mcp
toolmux list --internal
toolmux workflow templates
toolmux list lists every built-in toolbox and includes a Type column so
you can distinguish remote MCP toolboxes from internal Toolmux toolboxes.
toolmux ls is a shortcut for the same command.
Remote MCP catalog entries are hosted endpoints that can be added and
authenticated through the server's own OAuth flow without creating your own
OAuth app first.
Built-in remote MCP entries currently include:
airtable asana atlassian cloudflare datadog
excalidraw figma gainsight github grafana
granola incident-io linear miro neon
notion pagerduty pagerduty-eu posthog pylon
sentry stripe supabase vercel zoom
zoominfo
Install
With Homebrew:
brew install --cask fiam/tap/toolmux
toolmux version
Release archives for macOS, Linux, and Windows are available from GitHub Releases. macOS release binaries are Developer ID-signed and notarized.
Quick Start
Start by seeing what Toolmux can connect:
toolmux list
toolmux list --mcp
Add Slack when you are ready to connect a real workspace:
toolmux add slack --auth broker
toolmux status slack
Configure your local agent to see Toolmux tools over MCP:
toolmux mcp configure
With no agent argument, Toolmux detects installed supported agents and opens an interactive selector. For scripts, name the agents explicitly:
toolmux mcp configure codex claude
Now ask your agent to use Toolmux, for example:
Use Slack through Toolmux to find the latest messages about the release plan.
Or run the built-in Slack recap workflow:
toolmux workflow init slack-recap --template slack-recap
toolmux workflow config set default-agent codex
toolmux workflow run slack-recap --input since=yesterday
If the Slack recap workflow has no delivery_channel input, it asks the agent
to send the recap to you by opening a Slack DM first and posting to that DM
channel.
Slack
Slack is a native Toolmux toolbox under the registered toolbox name, usually
toolmux slack. Native toolbox commands and MCP tools are shown when the
toolbox is registered in config. The registered name is also the credential
account identity, so multiple Slack workspaces can be added with distinct
names:
toolmux add slack --name slack-work --label "Work workspace" --auth broker
toolmux add slack --name slack-personal --label "Personal workspace" --auth broker
Common setup options:
# Hosted Toolmux broker. This is the simplest OAuth path.
toolmux add slack --auth broker
# Explicit token and cookie values from environment variables.
toolmux add slack --token-env SLACK_TOKEN --cookie-env SLACK_COOKIE
# Your own Slack OAuth app with a local loopback callback.
toolmux add slack \
--auth oauth \
--client-id "$SLACK_CLIENT_ID" \
--client-secret-env SLACK_CLIENT_SECRET
# Explicit browser-session setup for a workspace subdomain.
toolmux add slack --workspace acme
--workspace is the Slack workspace subdomain, such as acme from
https://acme.slack.com. Browser-session setup only runs when you explicitly
request it with --workspace or --from-browser.
Useful Slack commands:
toolmux slack auth-test
toolmux slack channels-list --channel-types public_channel,private_channel
toolmux slack users-conversations --limit 20
toolmux slack experimental-conversations-list --query build
toolmux slack conversations-history --channel-id C123456 --limit 50
toolmux slack conversations-search-messages --search-query "from:@alice roadmap"
toolmux slack conversations-open --user-id U123456
toolmux slack conversations-add-message --channel-id C123456 --text "Build is green" --dry-run
toolmux slack conversations-add-message --channel-id C123456 --text "Build is green"
toolmux auth whoami slack
toolmux status slack
toolmux remove slack
Supported native Slack CLI command names:
- Auth:
auth-test - Channels and history:
channels-list,conversations-history,conversations-replies,conversations-search-messages,conversations-unreads,conversations-mark,users-conversations,experimental-conversations-list - Messages and DMs:
conversations-open,conversations-add-message - Files, reactions, users:
attachment-get-data,reactions-add,reactions-remove,users-search - User groups:
usergroups-list,usergroups-me,usergroups-create,usergroups-update,usergroups-users-update
The human CLI uses kebab-case commands and flags. Existing snake_case command
and flag spellings remain accepted as compatibility aliases. Stable action IDs
and MCP tool names retain their provider/upstream spelling, such as
slack.auth_test.
In Enterprise/Grid workspaces, Slack may restrict workspace-wide
channels-list. Try users-conversations to list conversations the
authenticated user is a member of; this documented Slack API method can still
be restricted by workspace policy. experimental-conversations-list is a
read-only Slack web-session fallback for browser-session auth and is explicitly
prefixed as experimental because it uses an undocumented Slack web app endpoint.
Run toolmux slack --help for the command list and per-tool flags.
Google is a native Toolmux toolbox for Google Drive, Google Docs, and Google Sheets.
Google uses brokered OAuth through toolmuxd and stores one local Google OAuth
bundle per registered toolbox name in the OS credential store. The default and
only supported scope is the
non-sensitive drive.file scope, which lets Toolmux create files and access
files the user explicitly opens for the app. Docs and Sheets read/write
commands use the same per-file grant.
Native Google commands and MCP tools are shown when the toolbox is registered
in config. The registered name is also the credential account identity:
toolmux add google --name google-work --label "Work Google account"
toolmux add google --name google-personal --label "Personal Google account"
The commands below use the default google registration. For a named account,
replace that namespace with its registered name, such as google-work.
toolmux google docs get 1abc...
toolmux google docs find-structure 1abc... --kind heading
toolmux google docs export 1abc... --format markdown
toolmux google docs append 1abc... --text "Status update\n"
toolmux google docs replace-all-text 1abc... --text "old" --replace-text "new"
toolmux google docs style-ranges 1abc... --paragraph-style-type HEADING_2 \
--foreground-color "#336699"
toolmux google docs insert-table 1abc... --rows 3 --columns 2
toolmux google docs insert-image 1abc... --upload-file ./diagram.png \
--mime-type image/png --make-public
toolmux google docs insert-image 1abc... --content-base64 "$PNG_BASE64" \
--name diagram.png --mime-type image/png --make-public
toolmux google docs batch-update 1abc... --json @requests.json
toolmux google sheets create --title "Quarterly plan" --sheet Summary --sheet Data
toolmux google sheets get 1abc...
toolmux google sheets values get 1abc... --range 'Summary!A1:D20'
toolmux google sheets values update 1abc... --range 'Summary!A1:B2' \
--values-json '[["Status","Count"],["Open",12]]'
toolmux google sheets values update 1abc... --range 'Data!A1:D100' \
--file ./data.csv
toolmux google sheets values append 1abc... --range 'Data!A:D' \
--file ./new-rows.tsv --value-input-option USER_ENTERED
toolmux google sheets values clear 1abc... --range 'Data!A2:D100'
toolmux google sheets tabs add 1abc... --title Archive
toolmux google sheets rows insert 1abc... --sheet-id 0 --start 2 --count 3
toolmux google sheets format-range 1abc... --sheet-id 0 --range A1:D1 \
--bold --background-color '#336699'
toolmux google sheets batch-update 1abc... --json @sheet-requests.json
toolmux google drive selected add
toolmux google drive selected list
toolmux google drive files copy 1abc... --name "Working copy" \
--target-mime-type application/vnd.google-apps.document
toolmux google drive files upload ./diagram.png --mime-type image/png --make-public
toolmux google drive files upload --content-base64 "$DOCX_BASE64" \
--name report.docx \
--mime-type application/vnd.openxmlformats-officedocument.wordprocessingml.document \
--target-mime-type application/vnd.google-apps.document
toolmux google drive files update 1abc... --name "Renamed file"
toolmux google drive files update 1abc... ./report.docx \
--mime-type application/vnd.openxmlformats-officedocument.wordprocessingml.document \
--target-mime-type application/vnd.google-apps.document
toolmux google drive files trash 1abc...
toolmux google drive selected remove 1abc...
toolmux google drive pick
toolmux google drive available
toolmux google drive search --query "mimeType='application/vnd.google-apps.document'"
toolmux google drive get --file-id 1abc...
toolmux google drive comments list 1abc...
toolmux status google
For normal file access, start with toolmux google drive selected add. It opens
the brokered Google Picker flow, saves selected file IDs locally, and stores
the OAuth token. Run toolmux add google only when you want Drive API access
before selecting files.
Default scope:
https://www.googleapis.com/auth/drive.file
With drive.file, Drive search is limited to files created by Toolmux or files
the user explicitly opened/shared with the Toolmux Google app. Drive-wide
discovery requires broader Drive scopes that Toolmux does not request.
Google Docs body reads and edits have the same per-file boundary: select or
open the document for Toolmux first, then use toolmux google docs get,
find-structure, export, append, replace-all-text, style-ranges,
insert-table, insert-image, or batch-update with the document ID or Docs
URL. find-structure returns Google Docs UTF-16 indexes for targeted edits.
batch-update accepts a full Docs API batchUpdate object, a requests array, or
@path; use --required-revision-id when an edit should only apply to a known
revision.
Google Sheets creation, value reads/writes, and structural edits also use
drive.file. Toolmux can immediately edit spreadsheets it creates. Select an
existing spreadsheet first with:
toolmux google drive selected add \
--mime-type application/vnd.google-apps.spreadsheet
Sheets value updates accept a two-dimensional array through --values-json,
or a JSON, CSV, or TSV file through --file. Values are written as RAW by
default, so strings beginning with = remain strings; pass
--value-input-option USER_ENTERED when Google should interpret formulas,
dates, and locale-sensitive numbers. The dedicated command groups cover
values, tabs, rows, columns, cell formatting, merges, and protected ranges.
Use toolmux google sheets batch-update <spreadsheet-id> --json ... for Sheets
API operations outside that surface. Sheets write commands support --dry-run.
Supported native Sheets CLI command names:
- Spreadsheets:
create,get - Values:
values get,values update,values append,values clear,values batch-update - Tabs:
tabs add,tabs delete,tabs rename - Dimensions:
rows insert/delete,columns insert/delete - Structure and formatting:
format-range,merge-cells,unmerge-cells,protected-ranges add/delete,batch-update
toolmux google drive comments list reads Drive comments and inline replies
for an accessible file with the same selected/opened-file boundary. It returns
plain comment text, author display names, quoted file content, resolved/deleted
state, replies, and pagination.
toolmux google drive selected add and toolmux google drive pick create a
short-lived Picker session in toolmuxd, open Google Picker in the browser,
and poll the broker until Google returns selected file IDs.
toolmux google drive selected add saves the selected file IDs locally for later
reference, while toolmux google drive pick returns Picker output without
saving it. toolmux google drive files copy accepts a raw file ID or a
Docs/Drive URL and copies an accessible file into My Drive, defaulting the
destination parent to root. The --target-mime-type flag requests Google
Workspace conversion during copy, such as converting a DOCX to native Google
Docs with application/vnd.google-apps.document. toolmux google drive files upload uploads content with Drive files.create; pass either a local path or
--content-base64 for MCP callers that do not share the CLI filesystem. Use
--make-public only when the file must be readable by anyone with the link,
such as when using a Drive-hosted image with Docs insert-image. The files update command uses Drive files.update to rename an accessible file, change
its trash state, or replace content with --upload-file, --content-base64,
or a second positional path. The --target-mime-type flag also requests
conversion during upload or content-replacing update. The files trash command
is a convenience command that moves an accessible file to Drive trash. With
drive.file, shared source files must be selected through Picker before Toolmux
can copy or update them. Removing a saved file only removes it from Toolmux's
local list; users can revoke app grants from their Google account when they need
Google to forget that per-file app access.
Toolmux uses one Picker path: a short-lived brokered Google Picker session
through toolmuxd. The CLI does not expose a local Picker fallback or a Picker
API key.
MCP Toolboxes
Toolmux can import MCP servers, cache their tool definitions, and expose them in two places:
- CLI commands under the registered toolbox name.
- Proxied MCP tools from
toolmux mcp serve.
Add from the built-in catalog:
toolmux list
toolmux add notion --name notion-work --label "Work Notion"
toolmux add notion --name notion-personal --label "Personal Notion"
toolmux auth whoami notion-work
toolmux auth whoami notion-personal
toolmux status notion-work notion-personal
--name is the unique registered CLI namespace and credential slot; --label
is a local human-readable account or workspace label. Toolmux cannot enumerate
unregistered SaaS accounts from an OAuth provider. toolmux auth whoami <name>
calls a supported read-only provider identity tool, so it shows which account
is actually authorized without exposing token material. For Notion it uses the
hosted server's self-user probe. Register each account under a different
--name; each registration runs its own OAuth flow and stores separate auth.
If Notion is already registered under the default notion name, rename that
credential slot before adding another one:
toolmux rename notion notion-work --label "Work Notion"
toolmux add notion --name notion-personal --label "Personal Notion"
toolmux auth whoami notion-work
toolmux auth whoami notion-personal
toolmux list --output json keeps registered_names for compatibility and
also returns a registrations array containing each namespace, label, config
scope, and path.
Register a custom MCP endpoint:
toolmux add https://mcp.linear.app/mcp --name linear-work --no-sync
toolmux auth login linear-work
toolmux mcp sync linear-work
toolmux linear-work
Toolmux checks stored remote MCP OAuth expiry metadata before sync and tool calls. When refresh metadata is available, it refreshes locally expired tokens before contacting the remote server. You can also refresh stored auth manually:
toolmux auth refresh linear-work
toolmux auth refresh
Passing names refreshes only those toolboxes. With no names, Toolmux probes all
registered remote HTTP MCP toolboxes that have stored auth and refreshes OAuth
tokens as needed. If a stored OAuth token cannot be refreshed because it is
missing refresh metadata, toolmux auth refresh falls back to the OAuth login
flow for that toolbox. toolmux mcp sync <name>, remote toolbox commands, and
proxied MCP tool calls also retry once after an OAuth refresh when the remote
server returns 401.
Agents connected through toolmux mcp serve can call toolmux.auth_refresh to
perform the same non-interactive repair. toolmux doctor --fix also runs safe
non-interactive remote MCP auth refreshes and repairs missing or stale MCP tool
caches before reporting diagnostics.
Register a command-backed MCP server over stdio:
toolmux add -- npx -y @upstash/context7-mcp
toolmux add -- docker run -i --rm browser-tools-mcp
Toolmux infers stdio MCP commands when the input is not a URL, built-in
catalog entry, or native toolbox. Use --name to override the derived command
namespace, and use --stdio only when the first command word would otherwise
match a built-in catalog entry or native toolbox. The -- separator is needed
when command arguments use dash-prefixed flags, so those flags are passed to
the command instead of Toolmux.
The registered name becomes the CLI namespace. A server named linear-work
exposes kebab-case commands as toolmux linear-work <tool-name>. Toolmux strips
a redundant catalog prefix when it is unambiguous, so an upstream Notion tool
named notion-get-users appears as toolmux notion-work get-users. Raw
upstream spellings remain CLI aliases, while proxied MCP tool IDs remain stable,
for example notion-work.notion-get-users.
For repeated non-secret arguments, configure defaults:
toolmux mcp defaults set atlassian cloudId <cloud-id>
toolmux mcp defaults list atlassian
Show registered toolboxes and cached tools:
toolmux status
toolmux mcp list
toolmux mcp list -R
toolmux mcp show linear-work
toolmux rename linear-work linear-personal
Inspect schemas and call tools:
toolmux mcp list linear-work
toolmux mcp schema linear-work <tool>
toolmux linear-work <tool> --json '{"key":"value"}'
Use --json for tool inputs that cannot be represented as flags.
Agents
Toolmux serves MCP over stdio:
toolmux mcp serve
Most users should configure an agent instead of running mcp serve manually:
toolmux mcp configure
toolmux mcp configure codex
toolmux mcp configure claude --scope project
Supported agent names:
Configure additional agents through workflows.agents in
~/.toolmux/config.yaml or .toolmux/config.yaml, mapping a name to a command
and arguments.
For non-interactive setup and teardown:
toolmux mcp enable codex claude
toolmux mcp disable claude
Limit which tools an agent can see with MCP profiles:
toolmux mcp profile set readonly \
--tool 'grafana.*' \
--exclude-tool '*.send'
toolmux mcp profile default readonly
toolmux mcp configure codex --mcp-profile readonly --read-only
Workflows
Workflows are YAML files that render a Go text/template prompt and run a
local agent command.
Global workflows live in:
~/.toolmux/workflows
Project workflows live in:
.toolmux/workflows
List templates and create a workflow:
toolmux workflow templates
toolmux workflow init slack-recap --template slack-recap
Template names are loaded from this repository on GitHub. You can also use a GitHub template path or a direct YAML URL:
toolmux workflow init team-recap \
--template github:acme/workflows/slack-recap.yaml@main
toolmux workflow init custom \
--template https://example.com/workflow.yaml
Render a workflow before running it:
toolmux workflow render slack-recap --input since="yesterday 18:00"
Run with an explicit agent:
toolmux workflow run slack-recap \
--agent "codex --yolo" \
--input since="yesterday 18:00"
Set the default workflow agent:
toolmux workflow config set default-agent codex
In an interactive terminal, omit the value to select from detected agents:
toolmux workflow config set default-agent
Workflows can declare required toolboxes such as internal:slack,
catalog:linear, or a remote MCP URL. Missing requirements are added
automatically during workflow init and workflow run unless --no-setup is
passed.
If a workflow command or agent definition contains {{ .prompt }}, Toolmux
substitutes the rendered prompt there. Otherwise it appends the prompt as the
final argument.
Output
Human output is the default. In an interactive terminal, Toolmux can use tables, color, Markdown rendering, links, pagers, progress spinners, browser opens, and selectors.
Use structured output for scripts and agents:
toolmux --output json mcp list -R
toolmux --output yaml list
JSON and YAML output are stable and undecorated: no ANSI escapes, prompts, spinners, pagers, or browser side effects.
Common global flags:
--output table|json|yaml
--color auto|always|never
--pager auto|always|never
--profile <name>
--policy <path>
--read-only
--mcp-tool-call-timeout <duration>
MCP toolbox calls wait up to 60s of response inactivity by default. Use
--mcp-tool-call-timeout, for example --mcp-tool-call-timeout 2m, when a
proxied MCP tool needs more time to return a tools/call response.
Safety
Toolmux stores non-secret config in:
~/.toolmux/config.yaml
Project config lives in:
.toolmux/config.yaml
Registered toolbox definitions, MCP server details, and cached tool metadata
are non-secret config. Native and remote toolboxes are stored under the
top-level toolboxes key; the map key is the registered command namespace and
the credential account identity. An optional non-secret label describes the
human account or workspace. toolmux rename moves the registration, cached MCP
tools, and matching stored credential to the new namespace.
Provider tokens, OAuth tokens, refresh tokens, bearer tokens, auth codes,
client secrets, and Slack token-cookie credentials are stored only in the OS
credential store or transient process memory.
Inspect and create config files with:
toolmux config paths
toolmux config show
toolmux config init --global
toolmux config init --project
toolmux config edit --global
toolmux config show prints the merged effective config by default. Use
--global or --project to print only one config file.
Use --read-only to block tool calls with local or remote write effects before
tool credentials are read:
toolmux --read-only google drive available
toolmux --read-only slack conversations-add-message \
--channel-id C123456 \
--text "This will be blocked"
Use local policy files for project guardrails around tool execution:
toolmux policy init
toolmux policy catalog
toolmux policy check --command "google drive available"
Policy discovery order:
--policy <path>TOOLMUX_POLICY=<path>.toolmux/policy.yamlin the current directory or a parent directory- No policy file, which allows local usage by default
Policy files are local guardrails for projects and automation. They are not a security boundary against a user who controls the machine or working directory.
Self-Hosting
Toolmux uses the hosted OAuth broker at https://api.toolmux.com by default
for native provider flows that require confidential client secrets.
To self-host the broker, point the CLI at your own toolmuxd:
export TOOLMUX_TOOLMUXD_URL=https://auth.example.com
Google uses the broker by default. For self-hosting, create a Google web OAuth
client, enable the Drive, Docs, Sheets, and Picker APIs, configure the Google
variables on toolmuxd, and point the CLI at that broker with
TOOLMUX_TOOLMUXD_URL.
Self-hosting instructions are in docs/SELF_HOSTING.md.
Help
toolmux --help
toolmux <toolbox> --help
toolmux mcp --help
toolmux workflow --help
toolmux doctor
For developer setup, tests, architecture notes, and release workflow, see CONTRIBUTING.md.