CLI
Install the median command, sign in once, then set up and run your workspace from a terminal or a script.
npm install -g mediansh
median loginEvery command and flag is in the CLI reference.
Install
| Package manager | Install | Run without installing |
|---|---|---|
| npm | npm install -g mediansh | npx mediansh |
| pnpm | pnpm add -g mediansh | pnpm dlx mediansh |
| Bun | bun add -g mediansh | bunx mediansh |
The package is mediansh. It installs a prebuilt binary for your platform. The command is median. median --version prints the installed version.
Sign in
median loginSign in at https://median.sh/cli
Your code is ZFTT-B9CP
Any device with a browser works. Waiting for you to approve.Open the address
Use any device with a browser. The CLI opens one for you when it can, with the code filled in. Over SSH or in a container, open it on your own machine.
Sign in to Median
A new account signs up on this page.
Approve the code
Check that the code matches your terminal and click Allow. The terminal prints Signed in as <you>, working in <organization>.
| Fact | Value |
|---|---|
| Code | 8 characters, shown as XXXX-XXXX |
| Code lifetime | 15 minutes. After that, login fails with login_timed_out |
| Don't allow | Login fails with login_refused |
| Organization | The one you have open in the dashboard when you click Allow |
Pick the organization
| Command | Effect |
|---|---|
median login | Binds the session to the organization open in the dashboard |
median orgs use <slug> | Moves this session to another of your organizations. The dashboard stays where it is |
median orgs create <name> | Creates an organization, makes you its owner, and moves both this session and the dashboard into it |
median whoami | Prints the account, the bound organization and your role |
New accounts
A new account can approve the code before it belongs to any organization. Create one next:
median orgs create "Acme"Until then, only whoami, orgs list, orgs create, orgs use and logout work. Everything else fails with no_organization.
First setup
From a signed in session with no organization:
median orgs create "Acme"
median keys create --name production
median agent set --name "Acme Support" --personality "Friendly, brief."
median knowledge write --title "Refund policy" --file ./docs/refunds.md
median webhooks add https://acme.com/median/events
median tools endpoint add https://acme.com/api/median/tools
median tools test orderStatus --input '{"orderNumber":"ORD-1042"}'| Line | Result |
|---|---|
| 1 | The organization, with you as owner |
| 2 | Prints MEDIAN_KEY and the publishable widget key. They are shown once. Webhooks and tool endpoints need a key to exist |
| 3 | The agent's name and personality |
| 4 | A knowledge document from a markdown file |
| 5 | A webhook endpoint for every event |
| 6 | Connects your tool route and syncs its manifest |
| 7 | Calls the tool the way the agent would and prints the answer. It needs no conversation |
tools test runs a tool at any risk level with no approval, so a write tool performs a real write. Give it --conversation <id> to use a stored visitor from that thread instead of --as <user id>. The two cannot be combined.
Scripting
median conversations list --waiting --json | jq -r '.[].id'| Behavior | Detail |
|---|---|
--json | One JSON value on stdout. login prints the sign in lines before it |
| Always JSON | analytics charts and explore, billing limits, billing usage, call <method>, api |
| Refusals | code: message on stderr, for example forbidden: Only admins and owners can edit the agent. |
| Usage errors | Error: <message> on stderr, for a missing required flag or a value outside its choices |
| Unexpected errors | error: <message> on stderr |
| Exit code | 0 on success, 1 on any failure |
tools test | Exits 1 when the tool reports a failure, even though the API call succeeded |
| Paging | logs list and billing invoices end a partial page with more: --cursor .... With --json, read isDone and continueCursor |
| Code | Meaning |
|---|---|
not_signed_in | No session on this machine. Run median login |
session_expired | The session stopped refreshing and was cleared. Run median login |
no_organization | The session is not bound to an organization. Run median orgs create or median orgs use |
invalid_token | You are no longer in the bound organization. Run median orgs use <slug> or median login |
forbidden | Your role cannot do this. See roles |
rate_limited | Wait and retry. See rate limits |
unreachable | Login or a token refresh could not reach the API. Check your connection. Other commands print error: <message> when offline |
no_api | median login could not reach https://api.median.sh. Check your connection. Login never falls back to another address |
Links
Paste a page instead of finding its id:
median read https://median.sh/signal/q5776nawkbmazaj4qv4p26y3v98d83qc| Page | median read prints |
|---|---|
/signal/<id> | The signal, every report, and commits that claim to fix it |
/inbox/<id> | The conversation with every message |
/customers/<id> | The person, their learned facts and their conversations |
/knowledge/<id> | The document in full |
Only the path is read, so the host does not matter. Any other link fails with not_a_link.
A link also works in place of the id argument of conversations, customers, knowledge, signals, tools run and tasks adopt commands:
median signals status https://median.sh/signal/<id> planned
median conversations reply https://median.sh/inbox/<id> --body "On it."--conversation on tools approvals, tools test and logs list takes the bare id.
Sessions and config
| Fact | Value |
|---|---|
| Credentials file | ~/.median/credentials.json. On macOS and Linux only you can read it |
| Access token | 8 hours. Refreshed 60 seconds before it expires, and once after a 401 |
| Refresh | Each refresh replaces both tokens and retires the old pair |
| Session expiry | 30 days after the last refresh |
| Failed refresh | Deletes the credentials file and prints session_expired |
| API address | https://api.median.sh. Set another at login with --api <url> or MEDIAN_API_URL. It is stored in the credentials file |
median logout | Revokes the session on the server and deletes the credentials file |
The CLI signs in only through median login. It never reads MEDIAN_KEY.
Where sessions show
Each session appears in Settings → API under MCP as Median CLI, with who approved it and when it was last used. Admins and owners see this section and can Disconnect a session. Its next command fails with session_expired.
CI and other machines
Run median login on each machine. A copied credentials file stops working on one machine as soon as the other refreshes, because each refresh retires the old tokens. A credentials file stored as a CI secret fails the same way, after the first run that refreshes it.
| Where | Use |
|---|---|
| A laptop or a long lived server | median login once. The session lasts while it is used at least every 30 days |
| CI or a short lived container | The REST API with MEDIAN_KEY. See authentication |
What stays in the dashboard
These have no CLI command:
- Creating your account.
median loginsends you to sign up in the browser. - Connecting Slack, Discord, Linear, Notion and GitHub. Each connection is an install in the browser. After that,
median integrationsconfigures it. - Choosing Notion pages, adding a docs site and uploading files to the knowledge base.
- A public link on a single document. A repository's link is
median integrations repos published. - The organization's picture and the agent's picture.
- Editing a customer.
- Buying a plan, credits or add-ons.
median billingreads them. - The help site. See Site.
- Resending an invitation.
- Linking your Slack or Discord account. See Work from Slack and Discord.
- Disconnecting a CLI or MCP session. See Where sessions show.
- Leaving or deleting the organization.
Member role changes are not on this list. Use median members role <userId> <owner|admin|member>.