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
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
python3orpython. Nothing else is installed: the command uses only the standard library. curl, for the installer and formatrix 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.
| Command | What it does |
|---|---|
matrix login | Prints a code and a link; approve in the browser. --no-browser prints the link without opening it. |
matrix whoami | The account this terminal is signed in as, and which API it talks to. |
matrix logout | Revokes the refresh token and deletes the credentials file. |
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.
| Command | What it does |
|---|---|
matrix programs | Every 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 leaderboard | The 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 config | Where the credentials live, which API and site are in use, who is signed in. |
matrix version, matrix update | The 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.
| Command | What it does |
|---|---|
matrix reports | Your 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 invitations | Private programs that invited you. --status accepted and friends. |
matrix invitation accept <id> | Or decline. |
matrix earnings | Balance, 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
| Flag | Meaning |
|---|---|
--program | The program's slug, as matrix programs lists it. Required. |
--title | Required. |
--asset | The target, as it appears in the program's scope. Required. |
--type | The vulnerability type in words. Required. |
--file, --description | The body, Markdown, from a file (- reads standard input) or inline. One of the two is required. |
--cvss | A CVSS 3.1 vector. The score and the severity band are computed from it on the server. |
--severity | critical, high, medium or low. Leave it out when you give a vector; a label that disagrees with the vector is refused. |
--weakness | A VRT id, e.g. server_side_injection.sql_injection. Decides which scope rules apply. |
--steps, --steps-file | Steps to reproduce, inline or from a file. One of the two is required. |
--impact, --references, --remediation | Optional sections. |
--accept-safe-harbor | Accept 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.
| Command | What it does |
|---|---|
matrix queue | Open reports across your programs. --assigned me, --assigned none, --program <slug>, --status new. |
matrix reports | Every 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> "…" --internal | A note only your team sees. Without --internal, the researcher reads it too. |
matrix programs --mine | Your organization's programs, including paused and draft ones. |
matrix scope-rules <slug> | Every rule on one of your programs, active or not. |
matrix wallet | Balance, 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".
matrix login" until you have. Signing in while the assistant is already connected takes effect at once.Tools
| Tool | What it does |
|---|---|
whoami | The account the server acts as. |
list_programs | Programs you can see; mine narrows to your organization's. |
get_program | One program in full: policy, safe-harbor version, reward tiers, scope in and out, rules. |
get_scope_rules | The rules a program has declared for kinds of findings on its targets. |
search_weaknesses | The taxonomy entry for a finding, with its priority and the CWE ids a report takes as weakness. |
list_reports | Your reports, or your organization's queue, with the same filters as the command line. |
get_report | A report with its timeline and comment thread. |
submit_report | Writes. File a report. Same fields as matrix report submit. |
comment_on_report | Writes. Post on a thread; internal for a team-only note. |
triage_report | Writes. Organization: move a report, set a bounty, leave a note, mark a duplicate, disclose. |
list_invitations, respond_to_invitation | Private-program invitations; answering one writes. |
get_leaderboard | The standings. |
get_balance | Your 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
| Variable | Meaning |
|---|---|
MATRIX_CONFIG_DIR | Where credentials live. Default $XDG_CONFIG_HOME/matrix, which is ~/.config/matrix for most people. |
MATRIX_API | The 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_SITE | The site, for the approval link and for matrix update. The API's own origin when unset. |
MATRIX_NO_BROWSER | Set to anything to stop matrix login opening a browser. |
MATRIX_INSTALL_DIR | For the installer only: where to put the command. Default ~/.local/bin. |
HTTPS_PROXY | Honoured, 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
| You see | What 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 needed | macOS: xcode-select --install. Debian or Ubuntu: sudo apt install python3. Then run the installer again. |
| You are not signed in | Run 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 approved | Codes last fifteen minutes. Run matrix login again for a fresh one. |
| The request was denied in the browser | Someone 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 that | The 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 requests | Wait a minute. Sign-in and report submission are rate limited. |
| The download's checksum does not match | Nothing 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 updaterefuse 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 bymatrix 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.