Command line

Matrix from the terminal

One command, matrix, for the things you do on Matrix every day: read a program's scope, file a report, work the triage queue, check your standing. It talks to the same API the site does and signs in from your browser, so nothing new to remember.

curl -fsSL https://matrix.pratimana.com/install.sh | bash
macOS, Linux and WSL · needs Python 3.8 or newer · installs to ~/.local/bin · verified against a published checksum

Install

The installer is a short shell script. It checks for Python, downloads the one file the command is, verifies it against the checksum published beside it, and puts it in ~/.local/bin/matrix. Nothing runs as root and nothing else on the machine is touched.

curl -fsSL https://matrix.pratimana.com/install.sh | bash

If ~/.local/bin is not on your PATH the installer says so and prints the line to add to your shell profile. To install somewhere else, set MATRIX_INSTALL_DIR first:

MATRIX_INSTALL_DIR=/usr/local/bin bash -c "$(curl -fsSL https://matrix.pratimana.com/install.sh)"

Prefer to read it first? The script is at /install.sh and the command itself at /cli/matrix.py, with its checksum at /cli/matrix.sha256. Downloading that file and marking it executable is the whole install.

Requirements

  • macOS, Linux, or Windows through WSL.
  • Python 3.8 or newer, as python3 or python. Nothing else is installed: the command uses only the standard library.
  • curl, for the installer and for matrix update.

Sign in

A terminal cannot follow the magic link the sign-in page sends, so the command signs in through your browser instead, the way gh auth login does.

matrix login
Sign in to Matrix

  Open   https://matrix.pratimana.com/cli-auth?code=BCDF-GHJK
  Code   BCDF-GHJK

Approve this terminal in the browser. Waiting… (Ctrl-C to stop)

Signed in as you@example.com (Security Researcher).

On a desktop the link opens on its own. Sign in there if you are not already, check the code on the page matches the one in the terminal, and click Approve. The terminal notices within a few seconds. A code lasts fifteen minutes and approves exactly one terminal; to sign in on another machine, run matrix login there.

The credential the terminal receives is the one the web app holds: a fifteen-minute access token, renewed on its own from a refresh token that rotates on every use and lasts a week of inactivity. It is kept in ~/.config/matrix/credentials.json, readable only by you.

CommandWhat it does
matrix loginPrints a code and a link; approve in the browser. --no-browser prints the link without opening it.
matrix whoamiThe account this terminal is signed in as, and which API it talks to.
matrix logoutRevokes the refresh token and deletes the credentials file.
If a code arrives you did not ask for, deny it. The approval page shows the computer's name and the address it asked from; approving signs that machine in as you.

Commands for everyone

Programs and their scope are public, so these work before you sign in; signed in, they also show the private programs you were invited to.

Commands for everyone
CommandWhat it does
matrix programsEvery program you can see: slug, name, type, status, bounty range, asset kinds. --mine narrows to your organization's own.
matrix program <slug>One program in full: rewards by severity, response target, scope in and out, the scope rules in force, the policy.
matrix scope <slug>Only the scope: targets in and out, and the rules.
matrix scope-rules <slug>The rules alone: what the program has said in advance about a kind of finding on a target.
matrix leaderboardThe global standings, with rank and trend, signal, impact and the severity mix. --limit 50, --country IN, --window 90d (or month, year, 2026-08, 2026-Q3), --category web_api, --program-type private.
matrix configWhere the credentials live, which API and site are in use, who is signed in.
matrix version, matrix updateThe installed version; fetch the newest one.
matrix program abc-logistics
abc Logistics
=============
Slug        abc-logistics
Type        public
Status      active
Bounties    $100–$5000
Response    72 h

In scope
KIND    TARGET                 NOTE
------  ---------------------  --------------------------
domain  api.abclogistics.com   Production API
domain  app.abclogistics.com   Customer portal

Scope rules
KIND          APPLIES TO             WEAKNESSES                    NOTE
------------  ---------------------  ----------------------------  -------------------
out_of_scope  app.abclogistics.com   Clickjacking on a page with…  Known, on the roadmap

Researchers

Filing from the terminal is for the report you wrote in your editor: the body is Markdown, from a file or standard input, and the rest is flags. The program's safe-harbor terms still have to be accepted, once, with --accept-safe-harbor.

Researchers
CommandWhat it does
matrix reportsYour reports. --open for the ones still moving, --status resolved, --program <slug>.
matrix report show <id>The whole report: fields, the scope rules that applied, the timeline. The id, or its first eight characters as the table shows them.
matrix report submit …File a report. See below.
matrix report comment <id> "…"Post on the report's thread; --file note.md for a longer one.
matrix report comments <id>Read the thread.
matrix invitationsPrivate programs that invited you. --status accepted and friends.
matrix invitation accept <id>Or decline.
matrix earningsBalance, minimum withdrawal, recent movements.

Submitting a report

matrix report submit \
  --program abc-logistics \
  --title "IDOR: any order readable by id on /api/orders" \
  --asset api.abclogistics.com \
  --type "Insecure direct object reference" \
  --cvss "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N" \
  --weakness broken_access_control.idor \
  --file report.md --steps-file steps.md \
  --accept-safe-harbor
Submitting a report
FlagMeaning
--programThe program's slug, as matrix programs lists it. Required.
--titleRequired.
--assetThe target, as it appears in the program's scope. Required.
--typeThe vulnerability type in words. Required.
--file, --descriptionThe body, Markdown, from a file (- reads standard input) or inline. One of the two is required.
--cvssA CVSS 3.1 vector. The score and the severity band are computed from it on the server.
--severitycritical, high, medium or low. Leave it out when you give a vector; a label that disagrees with the vector is refused.
--weaknessA VRT id, e.g. server_side_injection.sql_injection. Decides which scope rules apply.
--steps, --steps-fileSteps to reproduce, inline or from a file. One of the two is required.
--impact, --references, --remediationOptional sections.
--accept-safe-harborAccept the program's terms. Needed the first time you file against a program, or after its terms change.

The answer names the report and prints any scope rule that matched: a target the program has declared out of scope, a weakness it does not pay for. Attachments are not supported from the terminal yet; add them to the report on the site.

Organizations

The same command signed in as an organization member sees the organization's side: its programs, the queue, and triage. What each member may do follows their role on the site.

Organizations
CommandWhat it does
matrix queueOpen reports across your programs. --assigned me, --assigned none, --program <slug>, --status new.
matrix reportsEvery report, open or closed, with the same filters.
matrix report show <id>The report, with the team's assessment and internal events.
matrix triage <id> --status <status>Move a report: triaging, needs_more_info, triaged, retesting, resolved, duplicate, informative, not_applicable, spam. With --bounty 500, --note "…" (shown to the researcher), --duplicate-of <id>, --disclose.
matrix report comment <id> "…" --internalA note only your team sees. Without --internal, the researcher reads it too.
matrix programs --mineYour organization's programs, including paused and draft ones.
matrix scope-rules <slug>Every rule on one of your programs, active or not.
matrix walletBalance, what is held for open reports, recent movements.
matrix queue --assigned me
ID        TITLE                                         PROGRAM         SEVERITY  STATUS    BOUNTY  SUBMITTED
--------  --------------------------------------------  --------------  --------  --------  ------  ----------------
c5dd12a6  Stored XSS in shipment tracking widget        abc Logistics   high      triaging          2026-09-09 18:02
9b1e04f7  SSRF via webhook configuration on partner o…  abc Logistics   critical  new               2026-09-09 17:58
matrix triage c5dd12a6 --status triaged --bounty 750 --note "Confirmed on staging; fix scheduled."

MCP server

The same command speaks the Model Context Protocol, so an AI assistant can use Matrix as you: read a program's scope, look up the right weakness, draft and file a report, or work the triage queue. matrix mcp runs on your machine, over standard input and output, with the credentials from matrix login. There is nothing to host and no extra sign-in.

Add it to your assistant

Claude Code:

claude mcp add matrix -- matrix mcp

Claude Desktop, in claude_desktop_config.json (Settings → Developer → Edit Config):

{
  "mcpServers": {
    "matrix": { "command": "matrix", "args": ["mcp"] }
  }
}

Cursor (.cursor/mcp.json) and VS Code (.vscode/mcp.json, under "servers") take the same shape. If the app cannot find matrix on its own PATH, give the full path: "command": "/Users/you/.local/bin/matrix".

Sign in first. The server starts either way, and public reads work signed out, but anything about your account answers "run matrix login" until you have. Signing in while the assistant is already connected takes effect at once.

Tools

Tools
ToolWhat it does
whoamiThe account the server acts as.
list_programsPrograms you can see; mine narrows to your organization's.
get_programOne program in full: policy, safe-harbor version, reward tiers, scope in and out, rules.
get_scope_rulesThe rules a program has declared for kinds of findings on its targets.
search_weaknessesThe taxonomy entry for a finding, with its priority and the CWE ids a report takes as weakness.
list_reportsYour reports, or your organization's queue, with the same filters as the command line.
get_reportA report with its timeline and comment thread.
submit_reportWrites. File a report. Same fields as matrix report submit.
comment_on_reportWrites. Post on a thread; internal for a team-only note.
triage_reportWrites. Organization: move a report, set a bounty, leave a note, mark a duplicate, disclose.
list_invitations, respond_to_invitationPrivate-program invitations; answering one writes.
get_leaderboardThe standings.
get_balanceYour balance, or your organization's wallet.

Every tool answers structured JSON. The four that write are marked as such in the protocol, so a well-behaved assistant asks before running them, and the server's own instructions tell it to show you the exact arguments first. The API enforces every permission exactly as it does for the site: an assistant connected as a researcher cannot triage, and one connected as an organization member cannot file reports.

Resources and prompts

Resources let an assistant attach context without a tool call: matrix://programs, matrix://programs/<slug>, matrix://reports/<id> and matrix://me. Two prompts set it up for the common jobs:

  • draft_report (program, finding) puts the program's scope, rules and reward tiers in front of the assistant with what you found, and asks for a complete report — vector, weakness, steps — shown to you before anything is submitted.
  • triage_queue (program, optional) lists the open reports and asks for a proposed status, bounty and note for each, against the scope and tiers, to be applied only as you confirm them.

Trying it by hand

printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"me","version":"0"}}}' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | matrix mcp

Set MATRIX_MCP_DEBUG=1 to log each method to standard error. Standard output is the protocol channel, so nothing else is ever written to it.

The API

The command line, the MCP server and the site all speak to one API at https://matrix.pratimana.com/api, with a bearer token from matrix login or the browser session. Every route, its verbs and what it answers is listed in the API reference; --json below prints exactly what those routes return.

JSON and scripting

Every command that lists or shows something takes --json and prints exactly what the API answered, so the output can go to jq or a script instead of a person.

matrix reports --open --json | jq -r '.[] | [.id[0:8], .severity, .title] | @tsv'
matrix programs --json | jq -r '.[] | select(.offers_bounties) | .slug'

Errors go to standard error and the exit code is 1; an interrupted command exits 130. A validation error from the API is printed field by field.

Reports are addressed by id. The tables print the first eight characters, and every command that takes an id accepts that prefix as long as it is unambiguous among your reports; scripts should use the full id from --json.

Configuration

Configuration
VariableMeaning
MATRIX_CONFIG_DIRWhere credentials live. Default $XDG_CONFIG_HOME/matrix, which is ~/.config/matrix for most people.
MATRIX_APIThe API to talk to. Default https://matrix.pratimana.com/api; --api on any command does the same for one run. Remembered from the API you signed in against.
MATRIX_SITEThe site, for the approval link and for matrix update. The API's own origin when unset.
MATRIX_NO_BROWSERSet to anything to stop matrix login opening a browser.
MATRIX_INSTALL_DIRFor the installer only: where to put the command. Default ~/.local/bin.
HTTPS_PROXYHonoured, as by any Python program.

Update and uninstall

matrix update

Fetches the newest copy of the command from the site, verifies it against the published checksum, and replaces the installed file in place. matrix update --check only says whether there is one. Running the installer again does the same.

rm ~/.local/bin/matrix && rm -r ~/.config/matrix

That is the whole uninstall: the command and its credentials. Run matrix logout first if you want the refresh token revoked on the server as well.

Troubleshooting

Troubleshooting
You seeWhat to do
matrix: command not found~/.local/bin is not on your PATH. Add export PATH="$HOME/.local/bin:$PATH" to your shell profile and open a new terminal, or run ~/.local/bin/matrix directly.
Python 3.8 or newer is neededmacOS: xcode-select --install. Debian or Ubuntu: sudo apt install python3. Then run the installer again.
You are not signed inRun matrix login. The same message after a week away means the refresh token lapsed; signing in again is all it takes.
The code expired before it was approvedCodes last fifteen minutes. Run matrix login again for a fresh one.
The request was denied in the browserSomeone clicked Deny on the approval page. If that was not you, nothing was signed in; run matrix login again.
Your account is not allowed to do thatThe command is for the other side of the platform, or your organization role does not include it. matrix whoami says which account this terminal is.
Too many requestsWait a minute. Sign-in and report submission are rate limited.
The download's checksum does not matchNothing was installed. Try again; if it persists, tell security@pratimana.com.

Security

  • The command is a single readable Python file with no dependencies, served over HTTPS with a SHA-256 checksum beside it; the installer and matrix update refuse a download that does not match.
  • Signing in never types a password into the terminal. The browser approves a short code that expires in fifteen minutes and works once; the page shows which computer asked and from where.
  • The credentials file is created with mode 600. The access token in it lasts fifteen minutes; the refresh token rotates on every use and is revoked by matrix logout.
  • A "view as" session in the web app cannot approve a terminal, so an administrator looking at someone's account cannot mint a credential in their name.
  • Report a problem with the command itself to security@pratimana.com.