The statejar command
statejar login signs a terminal in to your account the way gh auth login does. You approve a code in the browser once, and a one-year developer key is stored on the machine, where the Python SDK and the StateJar plugins find it. Your password never passes through the terminal.
What it does
statejar loginasks StateJar for a pairing and prints (and opens) the approval page,statejar.com/devicewith a code. You sign in there as usual, two-factor included, check the device's name and the code, and approve. The terminal, which has been waiting, receives a developer key and stores it. The key lives a year, carries the device's name as its label, and reaches the memory API only: it cannot issue keys, read provider keys or change the account.statejar whoamisays which account the key belongs to, with its last four characters, when it expires and which API it is for.statejar logoutforgets the key on this machine. Revoke it on the API keys page to stop it working anywhere.
The stored key is used by the Python SDK (StateJar() with no key), and for recall and capture by the StateJar plugins for Claude Code, Codex, OpenCode, OpenClaw and Hermes Agent when their own key setting is empty. The key never appears in the browser, and the command prints only its last four characters.
Install
pip install statejar
statejar login
statejar whoami
The command comes with the Python package. PyPI serves version 0.6.0 (checked on 27 Oct 2026), which has login, whoami and logout. The memory commands (init, add, search, list, forget, export and status) come with version 0.7.0, which is not on PyPI yet. Until then, the Python SDK and the MCP server cover the same ground.
Set it up
| Option | What it does |
|---|---|
--no-browser | Prints the link without opening a browser: for SSH sessions, containers and CI. |
--device-name | The name the approval page shows, and the key's label. The default is this machine's host name. |
--base-url | The API to sign in to. The default is STATEJAR_BASE_URL, then https://api.statejar.com/api/v1. |
The code is valid for ten minutes; the command checks for your answer every few seconds. Where the key goes:
- The system keychain when the optional
keyringpackage is installed (pip install "statejar[keyring]") and the system has a keychain. - Otherwise a file only you can read (mode 0600):
~/.config/statejar/credentials.json, or%APPDATA%\statejar\credentials.jsonon Windows.STATEJAR_CONFIG_DIRputs it in another folder.
STATEJAR_API_KEY, when it is set, wins over the stored key, for the SDK and for whoami.
Check it works
statejar whoamiprints your address, the key's last four characters, its expiry and the API.- The API keys page lists the key with the label
statejar login:and the device's name.
A run against a local StateJar server: statejar login prints the link and waits, the code is approved on the site, and whoami names the account:
statejar login prints the approval link with its code and waits. The code is approved on the site (the next recording), the terminal stores a key and prints its last four characters, and statejar whoami names the account. Recorded 27 Oct 2026 against a local StateJar server; the output is real, with pauses over 3 s cut to 3 s. Full sizeThe recording (.cast)
statejar login printed: the code and the device's name shown, Approve pressed, and the new key's last four characters and expiry. Recorded 27 Oct 2026 in Chromium, on this site built from the same code, against a local StateJar server: every frame is a screenshot of the real page; waits for the server are shortened. Full sizeRemember and recall from the terminal
From version 0.7.0, which is not on PyPI yet, the command also reads and writes your memory:
| Command | What it does |
|---|---|
statejar add "My budget is ₹3,500." | Stores the facts in a message and prints each one with the new handle. |
statejar search "What is my budget?" | Prints only the facts the question needs, the handle and the audit id of the disclosure. |
statejar list | Every fact of the scope's current version. |
statejar forget budget | Removes a fact from the current state, as a new version; history keeps it. |
statejar export --out memory.json | Every version of the scope with its handle, as JSON; without --out it prints it. The file is written with mode 0600. |
statejar status | The account, the key, the API and the scope's newest version. |
statejar init | Signs in when no key is found and saves a default scope. |
--scope picks the scope (the default is STATEJAR_SCOPE, then the one init saved, then default). The run below used 0.7.0 built from StateJar's own repository, against a local server:
statejar add stores Meera's facts and prints each one with the new handle, statejar search prints only what the question needs with the handle and the audit id of the disclosure, and statejar list prints the scope's facts. Recorded 27 Oct 2026 against a local StateJar server; the output is real, with pauses over 3 s cut to 3 s. Full sizeThe recording (.cast)What it sends
- To StateJar: the device's name when a pairing starts, then the pairing's own secret every few seconds until you decide.
whoamisends the stored key to ask whose it is. - Never your password: you sign in on the approval page, in your browser.
- The key: issued when you approve, held encrypted on the server until the terminal collects it, once, then removed from the pairing.
- On your machine: the key, with the API it is for, your address, its last four characters and its expiry, in the keychain or the file above. Nothing else.
Troubleshooting
- "the code expired before it was approved": codes are valid for ten minutes. Run
statejar loginagain. - "the sign-in was denied in the browser": someone pressed Deny on the approval page. Run
statejar loginagain if that was a mistake. - "this key was already collected": a pairing gives its key once. Run
statejar loginagain. - "Not signed in": nothing is stored and
STATEJAR_API_KEYis not set. Runstatejar login. - "The key … is not valid for" an API: the key was revoked or has expired, or it belongs to another server (staging and production keys differ). Run
statejar loginagain. statejar: command not found: the package is installed in a virtualenv that is not active, or its scripts folder is not on yourPATH.statejar addorstatejar searchis unknown: those commands come with version 0.7.0, which is not on PyPI yet. Use the Python SDK or the MCP server.
This page as Markdown: /docs/cli.md