Documentation · updated

Learn Axon, one request at a time.

Axon is a local-first desktop API client for HTTP, GraphQL, gRPC, WebSocket, Socket.IO, SOAP, SSE, MQTT and MCP. These guides cover every part of it — from your first request to running collections in CI and syncing with your team without a cloud account.

All guides

GETTING STARTEDInstall AxonAxon is a native desktop app for macOS, Windows and Linux.GETTING STARTEDGetting startedFind your way around the window, send your first request, and see where your data lives.GETTING STARTEDRequestsThe request tab is where you'll spend most of your time.GETTING STARTEDCollectionsA collection is a tree of folders and requests.GETTING STARTEDVariablesA variable lets you write a request once and point it at staging, then production, without editing it.PROTOCOLSProtocolsEverything that isn't a plain HTTP call lives in the Protocols rail.WORKSPACEScripting & testsScripts are how a request stops being a single call and starts being part of a workflow — grabbing a token, seeding an id, asserting the response is actually correct.WORKSPACERunner & CLIRun a whole collection at once — in the app for a quick pass, or from the CLI so CI can gate on it.WORKSPACEServicesThe Services rail bundles the workspace surfaces that run in the background: mock servers, monitors and webhook receivers.WORKSPACEAI assistantAxon has a chat-style assistant that can read the request you are on and propose concrete edits to it.TEAMTeam syncAxon syncs a workspace live between teammates' machines over your LAN — or over a VPN address for people who are not on it.TEAMWork with GitIf your API suite belongs next to your code, link a folder and let Axon keep it there as YAML.REFERENCEWorkspaces & settingsA workspace is a separate space: its own collections, environments, history and team.REFERENCEKeyboard shortcutsThe default keyboard map, and how to rebind any command.

Getting started

Install Axon

Axon is a native desktop app for macOS, Windows and Linux. There is no account to create and nothing to sign in to — download it, open it, and send a request.

Download

Every release is published on GitHub with an installer for each platform: a .dmg for macOS, an .msi or .exe for Windows, and .deb, .rpm or .AppImage packages for Linux.

Get the latest one from github.com/faithdevss/axon/releases/latest.

First launch

On first launch Axon creates a local workspace and a cryptographic identity for this device. Both stay on your machine. If you are moving from another API client, press ⌘O (Ctrl+O) to import your collections — see Collections.

Updates

Releases are signed. When Axon starts it asks GitHub whether a newer signed release exists and installs it. Turn this off in Settings → Update; you can still check by hand from the same page.

Build from source

You need Rust (stable, 1.94+), Node.js 22+ and pnpm 10, plus the platform toolchain: Xcode Command Line Tools on macOS, webkit2gtk-4.1, libsoup-3.0 and librsvg2 on Linux, and WebView2 with the MSVC build tools on Windows.

pnpm --dir frontend install
cd frontend
./node_modules/.bin/tauri build

The installers land in target/release/bundle/<platform>/.

Getting started

Getting started

Welcome to Axon. It's an API client that runs natively on your machine and keeps everything offline.

If you've used Postman or Insomnia, you already know the shape of this: you write a request, you send it, you read the response. Axon adds scripting, tests, a collection runner, mock servers, monitors, an AI assistant, and live team sync over your LAN — and it speaks a lot more than REST: GraphQL, WebSocket, Socket.IO, gRPC, SOAP, SSE, MQTT and MCP.

One thing to settle up front, because it changes how you use everything else: there is no account and no server. Your collections, environments, history and secrets live on your own disk — a local SQLite database, with secrets in your OS keyring. Nothing you work on is uploaded. You never sign in.

Finding your way around the window

Five regions, and you'll use all of them within your first hour.

  • Left rail — the narrow strip of icons. Each one swaps the sidebar beside it: Collections, Environments, Protocols, Services, History. Click the icon you're already on to collapse the pane and win back some width.
  • Center — the tab strip and whatever tab is active. Tabs aren't only requests; the runner, settings, docs and other full-page surfaces all open as tabs too.
  • Right sidebar — companion panels for the AI assistant and the variable editor. Open them from the top bar.
  • Top bar — environment switcher, Team sheet, and the AI and Variables toggles.
  • Footer — Globals, Tools, and the terminal drawer where live protocol traffic streams.

Your first request

Let's send something real. This takes about thirty seconds.

  1. Press ⌘K (Ctrl+K) to open the command palette — or just click + on the tab strip for a blank tab.
  2. Pick a method from the dropdown and type a URL. Try https://httpbin.org/get if you don't have one handy.
  3. Press ⌘Enter to send. Watch the Send button: while the request is in flight it turns into a red Cancel, so a hung request is always escapable.
  4. The response docks underneath. Drag its top edge to give it more room.
  5. Press ⌘S to save the request into a collection.

That last step is the one worth building a habit around. An unsaved request isn't lost — the History rail keeps every response you've ever sent — but a saved one can be run, shared, exported and monitored.

Anywhere you can type a value, you can type {{a_variable}} instead. Axon highlights the names it recognises as you type. More on that in Variables.

Where to go next

You don't need to read these in order. Follow whichever one matches the thing you're trying to do.

  • Collections — organize, import, export and share requests.
  • Requests — the anatomy of a request tab: params, auth, headers, body, settings.
  • Variables — environments, globals, the vault, and which one wins when two disagree.
  • Protocols — everything that isn't plain HTTP.
  • Scripting & tests — pm.* scripts that run before and after each request.
  • Runner & CLI — run a whole collection, in the app or in CI.
  • Services — mock servers, monitors, webhook receivers, search.
  • AI assistant — the in-app agent and how it proposes changes.
  • Team sync — pair devices over the LAN and sync live.
  • Workspaces & settings — themes, proxies, certificates, backups.
  • Keyboard shortcuts — the full default map.

Where your data actually lives

Worth knowing before you trust it with anything important.

Axon keeps one SQLite database in your OS user-data directory, holding every workspace (each row is tagged with its workspace), plus whatever YAML/JSON exports you write elsewhere. Secrets go to the OS keyring.

Your requests only go where you send them. Apart from that, Axon makes exactly two kinds of network call on its own:

  • Update check — on launch it asks GitHub for a newer signed release and installs it. Turn this off in Settings → Update; you can still check by hand there.
  • Licence check — only if you have activated a paid licence: it is revalidated with the store about once a day. A free install never contacts the store.

Team sync is the one feature that moves your data between machines, and even then it goes directly between paired devices on your network — never through a third party.

Getting started

Requests

The request tab is where you'll spend most of your time. It has an address bar on top, seven sub-tabs beneath it, and the response docked below.

Look for the small dot on a sub-tab — that means it has content. It's how you tell at a glance that a request carries a body or three headers without clicking through all seven tabs to check.

Address bar

Pick a method, type a URL, hit Send (⌘Enter).

The URL accepts {{variables}} and highlights the names it recognises as you type. If a name stays unhighlighted, it isn't defined in any scope yet — that visual cue catches typos before you send.

The caret beside Send offers Copy as cURL. Save (⌘S) writes back to the collection; Share copies the axon://request/{id} deep link.

Docs

Markdown notes for this request, with a view/edit toggle.

These aren't just for you. Export → Markdown / HTML docs turns them into published API documentation, so a sentence written here becomes a sentence in the docs your team reads later.

Params

Query parameters and path variables as an enable/disable checklist.

The useful part: editing a param rewrites the URL, and editing the URL rewrites the params. They stay in sync, so you can work in whichever one is more convenient. Unchecking a row keeps it in the list but leaves it out of the wire request — which beats deleting a param you'll want back in five minutes.

Authorization

  • Inherit auth from parent — the default, and usually the right answer. Uses whatever the parent folder or collection defines.
  • No Auth
  • API Key — in header or query.
  • Basic
  • Bearer Token
  • JWT (HS\*) — signs an HMAC JWT from a secret and claims.
  • Digest
  • AWS SigV4
  • OAuth 2.0 — token, refresh token, expiry.

Every field takes {{variables}}. Please use that: put the secret in the vault and reference it here, rather than typing a live token into a request that might get exported or synced.

Headers

Your manual headers sit on top. Below them is a read-only auto-generated headers preview showing what Axon adds on your behalf — content type, content length, host, accept-encoding, auth, cookies.

Expand that preview when a signature mismatch has you stuck. It's exactly what goes out on the wire, which makes it the fastest way to spot the header you assumed was there and isn't.

Body

  • none
  • form-data — text and file fields.
  • x-www-form-urlencoded
  • raw — Text, JSON, JavaScript, HTML or XML, in a Monaco editor with syntax highlighting.
  • binary — a file path streamed as the body.
  • GraphQL — a query editor plus a JSON variables editor.

Scripts

Pre-request and post-response JavaScript. Covered properly in Scripting & tests.

Settings

Per-request overrides: TLS verification, redirect following, and the other knobs in the Postman-equivalent settings view.

Reading the response

The response panel docks under the request — drag its top edge to resize. Its header carries status, elapsed time and size, and it has these tabs:

  • Body — pick a rendering: JSON, XML, HTML, YAML, JavaScript, Markdown, Raw, Hex, or Base64. Hex and Base64 exist so a binary payload is still inspectable instead of a wall of nonsense.
  • Cookies — cookies this response set, with a count badge.
  • Headers — response headers, with a count badge.
  • Request — exactly what was sent, after interpolation and auto-headers. When a request misbehaves, start here: it shows what actually left, not what you meant.
  • Tests — pass/fail rows from the post-response script.

Cookies

The Cookies link at the right of the sub-tab row opens the cookie jar: cookies grouped by domain, with add, clear-one and clear-domain.

Axon sends matching cookies automatically on later requests to that domain, so a login request followed by an authenticated one just works.

History

The History rail keeps every response you've sent, saved or not. Click an entry to load it back into a tab.

This is the safety net for "I sent the right thing an hour ago and now I can't reproduce it."

Getting started

Collections

A collection is a tree of folders and requests. It's the unit Axon runs, exports, syncs and shares — so once a request lives in a collection, every other feature in the app can reach it.

If you're just poking at an API, you don't need one. The moment you want to run a suite, hand it to a teammate, or commit it next to your code, you do.

Building the tree

Open the Collections rail on the left.

  • New collection — the + button at the top of the sidebar.
  • Add a request — hover a collection row and click the + that appears, or use ⋯ → Add request.
  • Add a folder — ⋯ → Add folder nests a sub-collection.
  • Reorder — drag rows around the tree.

Every row has a ⋯ menu carrying Run, Copy link, Duplicate, Export, Rename and Delete.

Deleting a collection makes you type its name first, because there is no undo. That prompt is the only safety net, so read it rather than clicking through it.

The collection page

Click a collection's name and it opens as a tab with five sub-tabs. This page is where you set things once instead of on every request inside it.

  • Overview — description and notes.
  • Authorization — auth for every request set to inherit. Configure it here and your fifty requests stop each carrying their own copy of the same bearer token.
  • Scripts — pre-request and post-response scripts wrapping every request in the collection.
  • Variables — collection-scope variables, which outrank environment and global scope.
  • Runs — history of runner executions for this collection.

Finding things

The filter box at the top of the Collections sidebar does double duty.

Typed text filters the tree, and at the same time those terms are scored against a full-text index — BM25 over request names, URLs, bodies, tags and collection names. When there are hits, the ranked list replaces the tree and your matched terms are highlighted in place. Click any hit to open that request. Clear the box to get the tree back.

So you can search for a header value you half-remember, not just a request name.

Importing what you already have

File → Import… (⌘O) opens the import modal. It reads:

  • Postman Collection v2.1
  • OpenAPI 3.x / Swagger 2
  • HAR 1.2
  • Insomnia v4 export
  • Bruno (.bru)

cURL is handled separately — paste a command into the cURL import dialog and it becomes a request with method, URL, headers and body already filled in. This is the fastest way to move something out of your browser's network tab and into Axon.

One honest caveat about Postman: scripts do not always translate one-to-one. Rather than let them fail silently, run axon convert postman. It rewrites a v2.1 collection so its scripts run under Axon, comments out any call with no equivalent, and writes a per-request diagnostics report telling you exactly what it couldn't carry over. See Runner & CLI.

Exporting

From a collection's ⋯ menu:

  • Export → JSON or YAML — the full collection, round-trip safe. YAML is the git-friendly one; commit it beside your code and your API suite gets reviewed like everything else.
  • Export → Markdown or HTML docs — readable API documentation generated from your requests and their Docs tabs.

That second option is why filling in a request's Docs tab pays off later — it's the source those published docs are built from.

Sharing one request

Share on the request panel copies a deep link shaped like axon://request/{id}. A teammate on the same synced workspace pastes it and lands directly on that request.

Getting started

Variables

A variable lets you write a request once and point it at staging, then production, without editing it. Reference one anywhere — URL, params, headers, body, auth fields — with {{name}}.

Axon highlights names it can resolve as you type, so an unhighlighted {{name}} is your early warning that you spelled it wrong.

Syntax

  • {{key}} — simple lookup.
  • {{ key }} — surrounding whitespace is fine.
  • {{key:default}} — falls back to the literal default when key isn't defined anywhere.
  • \{{key}} — escaped, sent literally as {{key}}. Useful when the API itself expects braces.

Which scope wins

Four scopes hold variables, and the same name can live in several. Highest tier wins:

  1. Runtime — set by a script (pm.variables.set) or by the runner during a run.
  2. Collection — the collection's Variables tab. Nested sub-collections all feed this tier, and a closer collection masks a farther ancestor.
  3. Environment — whichever environment is currently active.
  4. Global — always in scope, whatever the environment.

The practical read: a script can always override an environment, and an environment can always override a global. If a value isn't what you expect, something above it is shadowing it — check runtime first and work down.

Environments

An environment is a named bag of variables you swap as a set — one for local, one for staging, one for prod.

Open the Environments rail to manage them. + New environment creates one, the radio control on each row activates it, and each row supports inline rename, edit-variables and delete. The Environment button in the top bar is the quick picker for the same thing.

Press ⌘/ to float the variable editor over whatever request you're on. It's the fastest way to check or nudge a value without navigating away and losing your place.

Globals

The footer Globals button opens a full-page editor locked to global scope.

Use it for the things that are true no matter which environment is active: a base host, a shared account id, a build tag.

Vault — for secrets

The vault holds secrets encrypted at rest behind a passphrase. It's where tokens and API keys belong.

  • First use — you set a passphrase, which derives the encryption key.
  • Locked — enter the passphrase to unlock for the session.
  • Unlocked — a key/value list with add and delete, plus a Lock button.

Why bother instead of an ordinary variable? Because a vault reference keeps the secret out of the exported YAML. You can commit a collection to a shared repo, and the token stays on your disk.

The passphrase never leaves the frontend except as a one-shot argument. The derived key stays in memory in the backend process and is never written to disk.

Dynamic variables

Built-in generators for throwaway data, Postman-compatible, written {{$name}} or {{$name(args)}}.

Each occurrence resolves independently — two {{$randomUUID}} in one request give you two different UUIDs, which is usually what you want.

{{$randomUUID}}          {{$randomInt(1,100)}}
{{$randomString(20)}}    {{$timestamp}}
{{$randomEmail}}         {{$randomFullName}}
{{$randomIp}}            {{$futureDate(30)}}

Identity, contact, address and internet values come out realistic (en locale) rather than as random noise, so a seeded test account reads like a real one. Numbers, dates and tokens honour the ranges you pass.

One ordering detail worth knowing: dynamic variables resolve after your own. So defining a variable named $timestamp shadows the built-in — occasionally handy, occasionally baffling if you did it by accident.

Reading and writing from scripts

pm.environment.set("token", res.json().access_token);
pm.globals.get("base_url");
pm.collectionVariables.set("run_id", pm.variables.get("$randomUUID"));
pm.variables.get("token"); // merged view, highest precedence wins

The rule to remember: pm.variables reads the merged view across all scopes, while the scope-named accessors (pm.environment, pm.globals, pm.collectionVariables) read and write one specific tier.

So read through pm.variables when you just want the value, and write through a named scope when you care where it lands. More in Scripting & tests.

Protocols

Protocols

Everything that isn't a plain HTTP call lives in the Protocols rail.

The pattern is the same whichever one you pick: click +, choose a kind, and you get a saved connection — a row you can reopen later, not a throwaway session. Click a saved row to open it as a tab. For the connection-oriented protocols, live traffic streams into the footer terminal drawer while you work.

REST / HTTP

The default request tab. Covered in Requests.

GraphQL

Two ways in: set the body type to GraphQL on any request, or create a saved GraphQL connection.

  • Point at an endpoint and Axon runs the standard introspection query, then uses the returned schema for field autocomplete on types and root operations. You get completion for the API you're actually talking to, without configuring anything.
  • Queries and mutations post a well-formed {query, variables, operationName} body.
  • Subscriptions run over graphql-transport-ws and stream results into the tab.

WebSocket

Open a connection, send text or binary frames, and watch inbound frames land in the log. Ping is there for keepalive checks.

Reconnect uses exponential backoff with jitter and a capped attempt count — so pointing Axon at a flaky server doesn't leave it spinning forever.

Socket.IO

Event-oriented rather than frame-oriented. You emit a named event with a payload and subscribe to the events you care about, instead of pushing raw frames.

Server-Sent Events (SSE)

Connect to an SSE endpoint and stream events as they arrive, with event name, id and data broken out per message.

gRPC

Normally gRPC means a codegen step before you can call anything. Not here — Axon works in two layers:

  • Introspection — load a .proto file, or use server reflection, to build a catalog of services, methods, messages and fields. The sidebar lists every callable method.
  • Invocation — pick service.method, supply JSON input, and Axon encodes it dynamically against the proto, then decodes the response back to JSON.

Unary and streaming calls both work, over plaintext or TLS. You write JSON and read JSON; the protobuf part stays out of your way.

SOAP

  • Builds a SOAP 1.1 or 1.2 envelope around your body payload, with the right Content-Type and SOAPAction.
  • Parsing a WSDL populates a sidebar of <service> / <port> / <binding> / <operation> entries, so you call operations by name instead of hand-writing envelopes.
  • A <soap:Fault> response is parsed and shown as a fault, rather than dumped as raw XML for you to squint at.

Not there yet: full XSD validation and dynamic schema binding.

MQTT

MQTT 3.1.1. Connect form on the left, publish editor and live message log on the right.

Two modes, and picking the right one matters:

  • Publish once — connect, publish, disconnect. Stateless, and you get the ack back. Use it to fire a single message.
  • Session — a long-lived subscriber. Subscribe to topics and inbound publishes stream into the log until you disconnect. Use it to watch a topic.

MCP (Model Context Protocol)

Connects to a local MCP server over stdio JSON-RPC.

  • Configure the command, args and env for the server process.
  • Probe runs initialize and lists the server's tools, resources and prompts — so you can see what it offers before calling anything.
  • Pick a tool, fill its arguments in the generated editor, and Call. The JSON response renders in the viewer.

Axon owns that child process for the life of the connection, which means closing the tab terminates the server. No orphaned processes left behind.

The terminal drawer

The footer terminal drawer carries every live stream: sends, inbound messages, errors and script logs, colour-coded by level.

When a socket drops or a subscription produces nothing, open this first. It's almost always faster than reasoning about what should have happened.

Workspace

Scripting & tests

Scripts are how a request stops being a single call and starts being part of a workflow — grabbing a token, seeding an id, asserting the response is actually correct.

Every request has a Scripts tab with two editors: a pre-request script that runs before the call goes out, and a post-response script that runs after it comes back. Collections have the same pair on their Scripts tab, wrapping every request inside them.

Scripts run in a sandboxed JavaScript engine (Boa) inside Axon. No Node, no filesystem, and no network access except through pm.sendRequest. The API is a documented subset of Postman's pm.*, so most existing Postman scripts port over directly.

New to this? The Snippets picker beside the editor inserts working examples for every supported call, grouped the way Postman groups them. It's a faster way in than reading this page top to bottom.

Reading the request and response

pm.request.url;      // string
pm.request.method;   // "GET", "POST", …
pm.request.headers;  // array of [name, value]

pm.response.code;    // 200
pm.response.status;  // "OK"
pm.response.headers;
pm.response.json();  // parsed body
pm.response.text();  // raw body

Both are read-only views — assigning to them does nothing.

Changing the outgoing request

This only works from a pre-request script, for the obvious reason that afterwards the request has already gone.

pm.setUrl("https://api.example.com/v2/users");
pm.setMethod("POST");
pm.setBody(JSON.stringify({ name: "axon" }));
pm.setHeaders([["X-Trace", "1"]]);
pm.request.headers.add({ key: "X-Run", value: "42" });

Variables

pm.variables.get("token");           // merged view, highest precedence wins
pm.variables.set("token", "abc");    // runtime scope
pm.environment.set("host", "stage.example.com");
pm.globals.get("base_url");
pm.collectionVariables.set("run_id", "42");

Each scope object supports get, set and unset. Note that pm.variables.set writes to runtime scope, which outranks everything else — handy, but it means a value you set in a script will shadow the environment for the rest of the run. See Variables for the full precedence chain.

Tests

pm.test(name, fn) records one pass/fail row. Assertions throw when they fail, which fails that test — but the other tests keep running, so one broken assertion doesn't hide the rest of your results.

pm.test("status is 200", () => {
  pm.response.to.have.status(200);
});

pm.test("returns the right user", () => {
  const body = pm.response.json();
  pm.expect(body).to.have.property("name", "axon");
  pm.expect(body.roles).to.have.lengthOf(3);
  pm.expect(body.email).to.match(/@example\.com$/);
});

pm.test("not a 404", () => {
  pm.response.to.not.have.status(404);
});

Results land in the response panel's Tests tab, and in the runner's report when the request runs as part of a collection.

Assertion vocabulary

pm.expect(value) returns a chai-style chain.

These words are chainable no-ops that exist purely so assertions read like English: to, be, is, has, have, with, that, and, of, at, same, does, but, still. Add not to invert whatever follows.

Boolean terminals: ok, true, false, null, undefined, empty.

Method terminals:

  • equal / equals / eq — strict equality.
  • eql / eqls — deep equality. This is the one you want for objects and arrays.
  • status(n) — response status code.
  • include / includes / contain / contains — substring or member.
  • property(key) or property(key, value).
  • match(regex).
  • above / greaterThan / gt, below / lessThan / lt, least / gte, most / lte.
  • lengthOf(n).
  • a(type) / an(type) — type check.
  • oneOf([...]).
  • header(name) — response header presence.

Chaining requests

pm.sendRequest fires an extra HTTP call from inside a script and hands the result to a callback. The classic use is fetching a token before the real request goes out.

pm.sendRequest(
  {
    url: "https://auth.example.com/token",
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ key: pm.globals.get("api_key") }),
  },
  (err, res) => {
    if (err) return;
    pm.environment.set("token", res.json().access_token);
  },
);

It's callback-style, not promise-style — so do your follow-up work inside the callback, as above.

Logging

console.log(...) output is captured and shown in the footer terminal drawer, tagged as script log lines. That drawer is your debugger here.

Collection scripts in the runner

The CLI accepts --pre-script and --post-script. These run once before the first iteration and once after the last — not per request.

The post-collection script sees the run summary through pm.response.json(), which is the hook for pushing results somewhere at the end of a CI run.

Schema validation

Writing an assertion per field gets old fast. Axon can validate a response body against a JSON Schema instead, so contract drift fails the run without you enumerating every property by hand.

Workspace

Runner & CLI

Run a whole collection at once — in the app for a quick pass, or from the CLI so CI can gate on it.

The collection runner

Open it with ⌘⇧R, from File → New Runner Tab, or from a collection's ⋯ → Run.

The runner is a full page split in two. The left column is the run sequence: one row per request, with a checkbox, a folder breadcrumb, a method badge and the request name. Drag rows to reorder, uncheck rows to skip them. The right column is the configuration.

Functional runs

Two ways to drive a functional run:

  • Run manually — configure and run it here and now.
  • Automate runs via CLI — the panel generates the exact axon run command for this collection, ready to paste into a CI job.

Run configuration:

  • Iterations — how many times to run the sequence.
  • Delay — milliseconds to wait between requests.
  • Stop run if an error occurs — bail on the first failure instead of finishing the sequence.

Performance runs

Switch the right column to Performance to drive the same collection as a load test, in the app or via the CLI. You pick a load profile, a number of virtual users, and a test duration.

Reading the results

Results stream into a table as the run proceeds, one row per request per iteration: iteration number, method, request name, status, duration, test results and any error. A collection's Runs tab keeps the history of past runs.

The CLI

The axon command (built from the axon-cli crate) is the headless runner. It shares the request engine and script sandbox with the app, so a run in CI behaves exactly like a run in the window.

axon run <collection.json|yaml> [options]
axon run --collection-id <uuid> [--workspace-db <path>] [options]

Point it either at an exported collection file or at a stored collection by UUID. A stored collection is read from --workspace-db, else --db / AXON_DB, else this app's own database, and runs with its folder scripts, inherited auth and the workspace's active environment, the same as the in-app Runner.

Options:

  • -e, --env <file> — environment file: a JSON or YAML object of key/value pairs.
  • -d, --data <file> — data file: CSV or a JSON array of objects. One iteration per row.
  • -o, --out <file> — report path. The format follows the extension: .xml for JUnit, plus .html, .md, .sarif and .json.
  • --bail — stop on the first failure.
  • --iterations <n> — iteration count when no data file is supplied. Default 1.
  • --retry <n> — per-request retries on failure. Default 0.
  • --delay <ms> — delay between requests. Default 0.
  • --parallel <n> — parallel requests within one iteration. Default 1.
  • --iteration-concurrency <n> — iterations to run at once. Default 1, which preserves dispatch order; raise it for load tests.
  • --pre-script <file> — runs once before any iteration; can seed variables every request then sees.
  • --post-script <file> — runs once after the last iteration, with the run summary exposed as pm.response.json().
  • --db <path> — workspace database. Also settable via the AXON_DB environment variable. Defaults to the user data directory.

Other commands:

  • axon version — version and build info.
  • axon convert postman <file> [--out <file>] [--report <file>] — rewrite a Postman v2.1 collection so its scripts run under Axon. Calls with no Axon equivalent are commented out and reported in a per-request diagnostics file.

CI example

axon run ./collections/api.yaml \
  -e ./env/staging.json \
  -d ./fixtures/users.csv \
  --bail \
  -o ./reports/api.xml

JUnit XML drops straight into most CI test reporters; SARIF is there for code-scanning dashboards.

Workspace

Services

The Services rail bundles the workspace surfaces that run in the background: mock servers, monitors and webhook receivers. All three sections are always open, each with its own Create button.

Mock servers

A local HTTP server that answers with responses you define — useful for building a client before the real API exists, or for reproducing an error your backend will not produce on demand.

A mock is defined by a spec:

  • bind — the address and port to listen on. Use port 0 to auto-assign.
  • label — the name shown in the panel and on the log tab.
  • routes — matched in declaration order; the first matching (method, path) wins. Path matching is exact by default, and a trailing * makes the rest of the path a wildcard.
  • auth — optional token endpoints backing the stateful layer below.
  • resources — optional stateful CRUD collections.
  • api_key — when set, every request must carry a matching x-api-key header or it is refused with 401 before any route is considered.
  • delay_ms — artificial latency on every response. Per-route delay_ms still applies; the longer of the two wins rather than stacking.
  • allow_external — whether anything outside localhost may reach it.

Each route carries a method, path, status, headers, body and an optional delay_ms for simulating a slow endpoint. A route can hold several named examples; which one is served is chosen at request time by a header or query selector, and example bodies can interpolate values out of the incoming request. That is the mechanism for error injection — add a 500 example behind a selector and flip your client into it without restarting anything.

The page

Mock servers opens as a full page (command palette, or Create in the Services rail), with room for the form and, once a server runs, the server itself.

The form is one card, and the JSON spec at the bottom of it is the thing Create actually submits — the fields above are an overlay on that JSON:

  • Blueprint — which kind of API to start. Picking one rewrites the spec editor:

    BlueprintWhat it serves
    CRUD + auth APIThe full demo surface: register / login / me plus /api/posts and /api/todos. The only one that can seed a collection.
    Public read-only catalogOne open resource with seeded records, search and filtering, no tokens.
    Error injectionGET /api/flaky?case=500|429|422|401 answers with that failure; no case is a 200.
    Slow / timing outEvery response waits 1.5s and /api/hang waits 15s — for spinners and client timeouts.
    Long paginated list23 orders at 5 per page, for ?page=, ?limit=, ?sort= and ?status=.
    Request echoPOST /api/echo returns your body; GET /api/whoami returns your headers.
  • Environment — where the server's URL is saved as mockUrl, so requests can point at {{mockUrl}}. Pick an existing environment, ask for a new one, or leave it at No environment and nothing is written.
  • Network delay — applied to every response. A blueprint's own delay comes selected.
  • Create a collection for this server — off by default; tick it to save a collection that exercises every endpoint. Only the CRUD + auth blueprint has one; it is disabled for the others, whose paths the seeder doesn't know.
  • Make mock server private — generates an x-api-key, shown once the server starts and copyable from the card. It is never persisted, so it dies with the session.
  • Spec — the raw JSON, exactly as axon_mock::MockServerSpec deserializes it. Edit it for anything the blueprints don't cover — extra routes, more resources, a different auth base path — and Reset puts the blueprint back.

One mock server runs at a time. While it does, the form is replaced by the server's card: status, URL with a copy button, the collection and environment the create wrote, the x-api-key for a private one, and Logs / Stop. Stop it and the form comes back.

Request logs

Logs on a running server opens that server's request log as its own tab in the bottom terminal drawer — one line per request with method, path, status and the matched route or example. It keeps streaming while you work, and the tab closes on its own. It lives there rather than on the page so it stays visible once you switch tabs to go send something at the mock.

The server keeps its last 50 requests. Watching starts from the present rather than replaying that buffer, and the terminal says so when requests roll off it faster than it polls.

Stateful CRUD and authentication

Static routes answer with a canned body — enough for one stubbed endpoint, not enough to exercise a client against something that behaves like a real API. A spec can also declare auth and resources, which are backed by an in-memory store that lives as long as the server does.

auth mounts, under base_path (default /auth):

MethodPathBehaviour
POST/registerCreates an account. 409 if the username is taken, 422 if a field is missing, 403 when allow_register is false.
POST/loginReturns access_token, token_type, expires_in. 401 on bad credentials — the same body whether the username or the password was wrong.
GET/meThe token's user.
POST/refreshIssues a new token and revokes the presented one.
POST/logoutRevokes the token, 204.
GET/usersAll accounts, hashes never included.

Seed accounts with users: [{ "username": …, "password": …, "role": … }], and set token_ttl_secs (0 never expires). Passwords are salted-hashed per server so demo credentials do not sit in cleartext, but this is a test double — never put a real secret in a spec.

Each entry in resources serves a full CRUD surface over its path:

MethodPathBehaviour
GET{path}{ items, total, limit, offset }. Accepts limit, offset, q (substring search over search_fields, or every string field), sort, order=asc|desc, and exact field=value filters.
POST{path}201 with a Location header. The id is server-assigned; one you send is ignored.
GET{path}/{id}One record, or 404.
PUT{path}/{id}Full replace. id, created_at and created_by survive.
PATCH{path}/{id}Shallow merge; a null value drops the field.
DELETE{path}/{id}204, or 404 if it was already gone.

Per resource: auth is "none", "write" (default — public reads, authenticated writes) or "all"; required_fields drives a 422 with a fields map; seed pre-loads records; owner_scoped hides each record from every account but its creator, reads included.

A static route always wins over the stateful layer for the exact (method, path) it declares, so you can override one endpoint of an otherwise-live resource — pin a 500 on GET /api/posts while create and delete keep working.

The demo collection

Ticking Create a collection for this server saves a collection wired to that server's port: a folder each for auth, a public-read posts resource and an owner-scoped todos one, nineteen requests including the deliberate 401 and 422 cases. baseUrl is a collection variable, and the login request's test script stores the token into token, so the rest of the collection sends authenticated without any copy-paste. Send 2. Login first.

Marking it private also writes the key into the collection as the secret variable apiKey and adds an x-api-key: {{apiKey}} header to every request, so the collection still works end to end.

Monitors

A monitor runs a saved request or collection on a schedule and alerts when the result drifts.

Each monitor has:

  • name — taken from the target it watches; there is no separate field.
  • schedule — a fixed interval in seconds, or a cron expression.
  • target — a request or a collection, optionally pinned to a specific environment.
  • send options — follow redirects, verify SSL, timeout.
  • retention — how many days of results to keep.
  • alert rules — any of: status is not the expected code, latency over a threshold in milliseconds, body missing an expected string, or any test failed.
  • enabled — pause without deleting.

Each run records status, duration, body, failed test count and any triggered alerts. Recent runs are listed under the monitor so you can see the pattern rather than only the last failure.

Monitors opens as a full page (command palette, or Create in the Services rail), built like the mock server page: the form while nothing is configured, then one card for the monitor itself — schedule, target, environment and alert rules, with Pause / Resume, Refresh runs and Delete. One monitor at a time; delete it and the form comes back.

Webhook receivers

An inbound webhook capture. Start a receiver bound to a local port, point an external service at its URL, and every request it receives is captured with method, path, headers and body. The list polls while the page is open.

This is how you inspect what a third party actually sends you — Stripe, GitHub, a payment provider — instead of reading their docs and guessing.

Webhook receivers opens as a full page, in the same shape as the other two. The form asks for the bind address, a label and the status code to reply with; a bind other than 127.0.0.1 also needs Expose on the network, since the receiver has no auth. Once it listens the form is replaced by the receiver's card — its URL with a copy button, Clear captures and Stop — and every capture below it, click one for headers and body. One receiver at a time: you point a service at exactly one URL.

Axon keeps an in-memory tantivy index over your requests and collections, rebuilt on startup from the workspace database. It scores over request name, URL, body text, tags and collection name using BM25.

Type in the Collections sidebar filter box to use it: matching hits replace the tree, ranked by score, with the matched terms highlighted in place and the collection name shown as a breadcrumb. Clear the box to get the tree back.

Workspace

AI assistant

Axon has a chat-style assistant that can read the request you are on and propose concrete edits to it. Open it with the AI button in the top bar — it docks into the right sidebar.

No API key

Axon never stores API keys. The default backend drives an AI CLI that is already installed on your machine (the Claude Code CLI) as a subprocess, so it uses whatever you are already authenticated with. Ollama is supported for fully local models, and a direct Anthropic HTTP backend exists for callers that want to supply their own connection.

Available providers and models are detected at startup. Settings → AI shows what was found and lets you set your default; the panel's own model picker overrides it per conversation.

The panel

  • Header — the conversation title, a new chat button and a history button.
  • Composer — the prompt box, a model picker popover (an Auto option that lets the CLI pick its default model, a Thinking toggle for extended thinking, and a quick model list; all three are remembered), a shortcut into AI settings, and the send button.

Your provider and model choice persists across reloads. Conversation history lives in memory for the lifetime of the tab — it is not written to disk.

Tool calls

The assistant does not answer only in prose. It can propose changes, which appear as one reviewable list under its reply. A single Apply runs the whole list in order, and nothing changes until you press it; Reject drops it.

The complete set of actions it can propose:

  • create_collection — a collection, or a folder inside one (by id or name).
  • create_request — a new request with name, method, URL and target collection.
  • set_url, set_method
  • set_headers — replacing or merging the current set.
  • set_body — any body kind except binary: JSON, XML, text, HTML, JavaScript, URL-encoded, form-data (text fields) and GraphQL. set_body_json is the JSON shorthand.
  • set_auth — No Auth, Inherit, Basic, Bearer or API Key. Axon does the Basic encoding itself.
  • set_variable — an environment (the active one), collection or global variable, applied right away. Tokens and keys can be marked secret.
  • set_pre_request_script, set_test_script — e.g. a test script that saves a token from the response with pm.environment.set.
  • run_command — runs one Axon command: anything in the command palette, plus send and save the current request. It can carry the answers to the dialogs the command opens (a name, a yes/no, a choice); without them the dialog waits for you. Unused answers are dropped right away, so they never fill a dialog you open later.
  • update_request — changes any saved request by id (name, method, URL, params, headers, body, auth, scripts, docs), open or not.
  • move_request, move_collection (a collection or folder under another one, or to the top level), rename_collection
  • delete_request, delete_collection — shown with a red warning; a collection delete must name its target.
  • set_collection_auth, set_collection_scripts — auth and scripts on a collection or folder, inherited by its requests.
  • create_environment — with its variables, optionally activated.
  • read_request, read_collection — look at saved settings. These only read, so they run without Apply.
  • create_connection, update_connection, delete_connection, read_connection — WebSocket, Socket.IO, MQTT, SSE, gRPC, SOAP, MCP and GraphQL connections. Each kind has a fixed list of settings the assistant may set. MCP is HTTP-only: the assistant can never set a STDIO command line, because that would run a program on your machine.
  • run_connection — opens the connection's tab and presses its main button (Connect, Send, Invoke, Subscribe). Not for STDIO MCP; the output shows in that tab.
  • start_mock, stop_mock, read_mock — a local mock server from fixed routes and in-memory CRUD resources. Its URL comes back to the assistant and can be saved as {{mockUrl}} in an environment; read_mock shows the requests it answered.
  • create_monitor, update_monitor, delete_monitor, read_monitor — run a request or collection on a schedule (every minute or slower, or cron) with alerts; pause, change, remove, and read the last runs.

The assistant sees your whole workspace tree (collections, folders, and each request's name, method and URL), your protocol connections, running mock servers and monitors, the active environment, and the conversation so far.

Working in steps

The assistant can work through a task over several steps. When a step reads something, sends a request, or fails, the results (the read data, the response status, body and test results, or the error) go back to it, and it proposes the next step: fix the test, retry, read before editing. Steps that only read carry on by themselves; every step that changes something still waits for Apply. The results each step sent back are listed, collapsed, in the chat.

A task stops when the assistant says it is done, after 8 steps (say "continue" to keep going), or when you press Stop.

Steps in one reply build on each other: "make a Users collection with a login request using basic auth, then send it" creates the collection, puts the request in it, sets its auth on the new request, and sends that one.

The assistant also knows the random values ({{$randomUUID}}, {{$randomEmail}}, {{$randomInt(1,100)}} and the rest) and uses them for sample data.

That list is the whole surface, and it is deliberately closed. There is no shell tool, no file tool, no arbitrary network tool; run_command only reaches Axon's own commands. Even a model that is confused, or a response crafted by a hostile API you are testing, cannot make the assistant do anything outside those in-app actions.

What it is good at

  • Generate tests — hand it a response and ask for assertions; it writes the pm.test block.
  • Explain a response — a plain-language read of a status code, error envelope or unfamiliar payload.
  • cURL to request — paste a cURL command and get a filled-in request.
  • JSON to schema — turn a sample payload into a JSON Schema you can validate against.
  • Fix a request — describe what should have happened and let it adjust the URL, headers, body or scripts.

Privacy

The prompt, and whatever request or response context you attach, go to the provider you selected. With Ollama or a local CLI that stays on your machine; with a hosted model it does not. Nothing is sent implicitly — the assistant only sees what a message includes.

Team

Team sync

Axon syncs a workspace live between teammates' machines over your LAN — or over a VPN address for people who are not on it. There is no server, no account, and no third party in the middle. Open it with the Team button (the radio icon) in the top bar; the sheet slides in from the right edge.

How it works

Each device keeps its SQLite database as the source of truth for what you see. A team workspace is additionally mirrored into a CRDT document (automerge), and it is that document peers exchange over a TLS WebSocket. Merges are conflict-free — two people editing different fields of the same request both land, with no manual resolution prompt.

The topology is a full mesh: every active member connects to every other. That is fine at team scale and means there is no leader to elect and no host whose absence stops everyone else.

Discovery on the LAN is mDNS (_axon._tcp).

Hosting a team

  1. Click Host. Nearby devices running Axon can now discover you.
  2. When a teammate joins, you both see a Confirm pairing code prompt with a short code derived from the handshake transcript. Read it aloud to each other. If it matches on both screens, click They match; otherwise They differ — cancel.
  3. Click Sync to start exchanging edits live.

The pairing code is what makes this safe on a network you do not fully trust. It defeats a man-in-the-middle and stops random devices on the same Wi-Fi from joining. If the codes differ, something is wrong — cancel.

Joining a team

Click Start discovery to list nearby hosts, then Join next to the one you want. Confirm the pairing code as above.

Remote members

mDNS cannot cross a WAN, so someone off the LAN will never appear in discovery. Use the Join a remote host field with an address instead — TLS pinning and pairing are address-agnostic, so everything else works the same.

Reachability has to come from a VPN overlay. Do not port-forward the pairing port to the public internet.

Members, keys and revocation

The members list shows each person's role and status.

  • Rotate key issues a new team encryption key. Remaining members must re-pair to receive it.
  • The shield icon revokes a member, cutting them out of future syncs.

Auth secrets travel inside the synced document encrypted with a shared 32-byte team key (ChaCha20-Poly1305, per-field nonce), decrypted locally by each member.

One thing to be clear about: revoking a member cannot un-share data that already reached their disk. Rotating the key only protects future secrets. If someone leaves under bad circumstances, rotate the key and rotate the credentials themselves upstream.

Backing up your identity

Each device has its own cryptographic identity, stored only on that machine. There is no server-side account to fall back on — lose it and you re-pair from scratch.

  • Back up identity (cloud-download icon) in the Team panel saves a passphrase-protected backup file. Do this before wiping a machine or switching computers.
  • Restore identity (cloud-upload icon) on the new device brings the same identity back. Restoring overwrites whatever identity is currently on that device, so use it before you have paired anything, or right after a fresh install.

Team

Work with Git

If your API suite belongs next to your code, link a folder and let Axon keep it there as YAML.

Linking a folder

Open Work with Git from the left rail and pick a working directory — usually the root of a git repository. Axon mirrors the workspace's collections and environments into <folder>/axon/ as YAML files.

  • Every file keeps a stable id, so a rename or an edit shows up as a small diff instead of a delete and an add.
  • Axon only deletes files it wrote itself. It tracks them in a manifest, so files you added to the folder by hand are never touched.
  • Secrets are never written to these files. Vault entries and secret variables stay on your device.

Commit, pull and push

Once linked, the pane shows the folder, its branch, how far you are ahead of or behind the remote, and the synced files that changed — each marked as added, modified, renamed, deleted or untracked.

Commit, Pull and Push run through the git installed on your system, so your existing credentials, SSH keys and hooks apply. Pulling brings teammates' changes back into Axon.

This is the asynchronous alternative to Team sync: changes are reviewed in pull requests instead of streaming live between machines.

Reference

Workspaces & settings

Workspaces

A workspace is a separate space: its own collections, environments, history and team. (They all live in Axon's one local database, kept apart by workspace.) Use one per client, per product, or to keep a personal scratch space away from work.

Open the Workspaces page from the Home menu. It lists every workspace with name, type, access, whether it is active, and when it was created, and supports create, activate, rename and delete. Switching workspaces swaps everything the window shows.

The Workspace switcher in the header is the quick picker for the same thing.

Settings

Settings open as a full page with a section rail on the left.

General

  • Request timeout — seconds; 0 never times out.
  • Follow redirects — auto-follow 3xx Location headers, up to 10 hops.
  • SSL certificate verification — validate the peer's TLS chain against the system trust store. Turning this off is the right call against a staging box with a self-signed cert, and the wrong call everywhere else.
  • Always ask when closing unsaved tabs
  • Always open sidebar item in new tab
  • Two-pane view — show the response beside the request instead of below it.
  • Show icons with tab names — the method badge on request tabs and the protocol badge on protocol tabs.
  • Variable autocomplete — suggest variable names after you type {{ in the URL bar.
  • Editor behaviour: font and font size, auto close brackets, auto close quotes, indentation type (space or tab) and indentation count.

Themes

Light, Dark or System, plus seven named themes — Nebula, Abyss, Solar, Carbon, Ember, Verdigris and Rose. Alongside them: font family (a preset or your own), font size, and a font scale of Compact / Default / Comfortable.

Shortcuts

Every command with its current chord. Click a row and press a new combination to rebind it; conflicting chords are flagged. Only changed bindings are stored, so defaults keep tracking the app. Reset appears on rows you have changed, and there is a reset-all.

AI

Which AI CLIs and local models were detected on this machine, and which model the Ask AI tab uses by default. See AI assistant.

Data

Backup & restore. Backup writes the whole workspace out to a file; restore reads one back in. Take a backup before an upgrade, before a risky import, or before wiping a machine.

Proxy

A proxy URL for outgoing requests. HTTP, HTTPS and SOCKS5 are supported. The TLS material the same section carries:

  • Custom CA bundle (PEM) — trust an internal CA without disabling verification entirely. Prefer this over turning SSL verification off.
  • Client certificate (PEM) and client key (PEM) — for mutual TLS.

Update

Check for updates on launch (on by default) looks for a newer signed release on GitHub when Axon starts and installs it. Turn it off and Axon makes no update requests; Check for updates checks once, and offers Install and restart when there is a newer version.

About

Version, UI build, and architecture — the same details as the Developer Info page, which also carries license and repository information.

Plans & licensing

Axon → Plans… opens the plans page. Purchases happen in your system browser; the app carries no payment code. A license key unlocks the corresponding features in place.

Reference

Keyboard shortcuts

Mod is ⌘ on macOS and Ctrl elsewhere.

Rebindable commands

These live in the command registry and can be reassigned in Settings → Shortcuts.

General

  • Mod+K — Command palette
  • Mod+Alt+P — Ask AI

Request

  • Mod+Enter — Send request
  • Mod+S — Save request
  • Mod+/ — Edit variables (floating editor)
  • Mod+Shift+R — Open runner (owned by the menu's New Runner Tab, so it isn't rebindable)

Edit

  • Mod+C — Copy (context-aware)

Mod+C yields to the browser's native copy when any text is selected (in a field or in rendered text such as a response body) or focus is inside a Monaco editor. Otherwise it copies whatever the focused pane advertises — a response body, a header table, a hit row.

Protocol tabs (WebSocket, gRPC, MQTT, …) use the same Send and Save chords while focus is inside the tab.

App menu

Accelerators from the native menu bar. They're handled by the menu itself, so they can't be rebound and no command can take them:

  • Mod+N — New…
  • Mod+T — New Tab
  • Mod+Shift+R — New Runner Tab
  • Mod+Shift+N — New Window
  • Mod+O — Import…
  • Mod+W — Close Tab
  • Mod+Shift+W — Close Window
  • Mod+Alt+W — Force Close Tab
  • Mod+R — Reload (View menu)

Close Tab asks before discarding unsaved edits (unless you turned that off in Settings → General). Force Close Tab skips the prompt.

Rebinding

Open Settings → Shortcuts, click a row, and press the combination you want. A chord already claimed by another command is moved to the new one (and flagged); a chord the app menu owns is refused. Only bindings you change are stored — everything else follows the app's defaults, so upgrades never leave you with a stale map. Rows you have changed grow a Reset, and there is a reset-all at the bottom.