Neural Inverse Govern (powered by Keystone) is your organisation's account and policy service. The CLI signs in to it the same way the Editor and the Agents app do: the same endpoints, the same device list, the same signed policy format and the same operating-system credential store. Settings and commands keep the name keystone.
Signing in is optional unless your organisation requires it. When you are signed in, the CLI can:
- register this device with your organisation;
- fetch your organisation's signed policy: settings it locks, the models you may use, an organisation model gateway, and organisation skills, agent profiles, slash commands and permission rules (see Known gaps);
- use your organisation's context: retrieval, Team memory, agent instruction files and the team work registry (Organisation context);
- keep working offline for a grace period, and lock agent features after that.
Sign in
neuralinverse login # opens your browser and prints the URL too (SSH, headless)
neuralinverse login --no-browser # only print the URL
neuralinverse login --device # a code to enter on any other device
neuralinverse login --browser # insist on the browser flow where none is detected
neuralinverse login --base-url https://keystone.example.com # another Govern address, for this sign-in
--device and --browser cannot be used together. In a session, use /login.
In a browser
The CLI uses the OAuth 2.0 authorization code grant with PKCE (S256). It listens once on http://127.0.0.1:<random port>/callback (never localhost), opens your browser, checks the state value, shows a "Signed in, you can close this tab" page, and gives up after 10 minutes. A callback with another state is refused without ending your attempt.
Over SSH, open the printed URL in a browser on the machine that runs the CLI, or forward the port, because the browser returns to that machine's loopback address.
With a device code
In an SSH session, and on Linux with no display server, neuralinverse login uses the device authorization grant (RFC 8628) by itself. It prints the sign-in page of your Govern server and a code; you enter the code on any device with a browser, choose the account and approve, and the CLI waits for the approval. The page must be on the Govern server's own domain; anything else is refused before a code is shown. Enter a code only if you started the sign-in yourself.
Check who you are
| Command | Shows |
|---|---|
neuralinverse whoami [--json] | Account, device and policy state |
neuralinverse account show [--json] (/account) | Your account as the Editor and the Agents app show it |
neuralinverse policy (/policy) | Organisation, policy version, issue and expiry dates, signing key, state and locked settings |
neuralinverse policy refresh (/policy refresh) | Fetch the policy now |
neuralinverse doctor | Includes a Keystone section |
When you are signed in, the welcome header shows signed in as <email> · <org>.
account show prints your name and email; the Account (name and alias) and the 12-digit Account ID, shown in groups of four (1234-5678-9012); the Account Region (<display name> · <region id>); the server, the CLI's client id, when you signed in and where the session is kept; the policy state and version; the connection state; and links to the console's Profile, Security and Sessions pages. The account details come from GET <api_url>/api/v1/account/resolve/<org_id> and are shown only when the answer names a 12-digit Account ID of exactly your token's organisation; otherwise it shows Account details unavailable (<code>). The organisation UUID and your user id are not printed.
--json prints one object with the schema neuralinverse.account/v2 (account.id, account.name, account.alias, or account.available: false with reason; region.id, region.name). It never contains a token. Exit codes: 0 signed in, 1 signed out or the session has ended, 2 usage error.
One sign-in is one account. To use another account, sign out and sign in again.
Sign out
neuralinverse logout
logout (/logout) reports the device inactive, revokes the refresh token (RFC 7009) and deletes the local tokens, the cached policy and the organisation content. If Govern cannot be reached, the refresh token is kept aside in the credential store and revoked at the next start.
The CLI follows the Build apps' shared account link (~/.neural-inverse-shared/neural-inverse-account/link-<quality>.json, no secrets): signing out of the Editor or the Agents app signs the CLI out at its next start, and the CLI's login and logout are recorded there so the apps follow it. Set NEURALINVERSE_SHARED_DATA_DIR or NEURALINVERSE_IDE_QUALITY (default stable) when the Editor uses a different folder or build quality.
Where Govern is
The only address built into the CLI is the address of the service Neural Inverse hosts, the same one the Editor and the Agents app ship with. For a self-hosted deployment, set keystone.baseUrl in your user settings or in your organisation's managed settings. A project's settings cannot set it. login --base-url <url> uses another address for one sign-in, unless managed settings fix it.
From the base URL the CLI discovers the rest:
GET <baseUrl>/.well-known/keystone-regionnames the region, the issuer and the API origin.GET <issuer>/.well-known/openid-configurationmust name the same issuer, and says whether authorization responses carryiss(RFC 9207).
Discovery is refused, with the reason, when an answer is not https, redirects, is not strict JSON of the expected shape, or names a host outside the base URL's domain. A sign-in always discovers afresh. The last result is kept in <config>/keystone/region.json only so that a start without a network knows which issuer a stored sign-in belongs to; no credential is sent to an address read from that file. Every request declares X-Keystone-Client: neuralinverse-cli/<version>.
When the issuer advertises iss, the authorization response must carry exactly one iss equal to the discovered issuer. A different iss is treated as a mix-up attempt: the sign-in ends and the code is not exchanged.
The settings keystone.issuer and keystone.apiUrl and the --issuer flag are retired. An issuer set on its own is used as the base URL, and doctor says so. --issuer is refused with a message pointing to --base-url.
The CLI's client id
Each Build app signs in with its own public OAuth client: neuralinverse-editor, neuralinverse-agents and neuralinverse-cli. Sessions, device-list entries and audit records therefore say which app they belong to. Govern registers neuralinverse-cli for the authorization code, device code and refresh grants, with loopback redirects on any port, no secret, and PKCE S256 required.
The CLI reads its client id only from managed settings, never from user settings, project settings or the environment (NEURALINVERSE_KEYSTONE_CLIENT_ID is retired). A Govern server older than the per-app clients answers invalid_client; the CLI then stops with a message telling the administrator to upgrade Govern or set keystone.clientId in the managed settings. It never tries another client id by itself.
Where tokens are kept
Tokens go to the operating system's credential store, using the same module and service name (Neural Inverse Models) as the Editor:
| OS | Store |
|---|---|
| macOS | Keychain (security; the secret is passed on standard input) |
| Linux | Secret Service through secret-tool (GNOME Keyring, KWallet) |
| Windows | DPAPI for the current user (PowerShell), in an owner-only folder under ~/.neural-inverse-shared/neural-inverse-models/credentials |
The CLI's entries are cli:neural_inverse_auth_token, cli:neural_inverse_refresh_token and cli:neural_inverse_pending_revocation. The CLI holds its own session, with its own refresh token and device entry.
When no credential store works, for example on a Linux server without a Secret Service, tokens are kept in memory for the running process only, and the CLI says so. Tokens are never written to settings.json or any plain file. ~/.neuralinverse/keystone/session.json holds only non-secret facts: issuer, client id, email, organisation and sign-in time.
Session refresh
The access token is refreshed 60 seconds before it expires and after any 401, and the request is retried once. Refresh tokens rotate, and the new pair is stored at once. If Govern refuses the refresh, the CLI does not sign you out; requests report Keystone session expired, run neuralinverse login.
The device list
At sign-in, and hourly while a session runs, the CLI registers the device with POST <api>/api/v1/account/devices. It sends machineId (a SHA-256 of the operating system's machine id, salted with the issuer; the raw id never leaves the machine), deviceName (Neural Inverse CLI on <OS>), version, os (macOS, Windows, Linux), lastActive and isActive.
Only a 403 whose error is device_blocked, device_revoked or device_limit_exceeded signs the CLI out; over the device limit, the session is also revoked. The CLI shows why. Any other failure is logged and does not interrupt the session.
The organisation policy
The CLI fetches your organisation's Ed25519-signed policy at start, at sign-in and hourly, from GET <api>/api/v1/policy/bundle with If-None-Match. A bundle is rejected as a whole when its signature does not verify with a pinned key, it has expired, it names another organisation, or its version is older than one already accepted. What a bundle contains and does is described in Enterprise deployment.
Offline use
The last verified bundle is cached in ~/.neuralinverse/managed/keystone-policy.json and verified again every time it is loaded; editing it removes it. When Govern cannot be reached, the cached bundle stays in force until offlineGraceHours after its last successful refresh, or until it expires. After that the policy is locked: the CLI starts and /login, /policy refresh, /doctor and /help work, but model calls and tools are refused with an explanation until a refresh succeeds. The cached restrictions stay applied while locked.
If keys are pinned or sign-in is required, and the policy request fails with no valid cached policy, the policy is locked too (fail closed). An answer of 404 (or 204) means the organisation has no policy: the cache is cleared and nothing is restricted.
Changes between online, cached and locked are written to the audit log as keystone_policy events.
What is sent to Govern
- To the authorization server: the OAuth parameters (no client secret).
- To the device list: the fields listed above.
- To the policy endpoint: the bearer token and the cached ETag.
- To the organisation model gateway: model requests, with your access token, and
X-Keystone-Context-Request-Idwhen the prompt carries organisation context. - To the Context Platform: the normalised repository address of the working folder, each chat prompt's text for retrieval (unless turned off), and what the
contextcommands and the team work tools send. See Organisation context.
Your code goes only to the model provider you use.
Inside the Editor's agent host
When the CLI runs inside a governing host such as the Editor's shared agent host, the host supplies the session. login and logout then report that sign-in is managed by the host.
Known gaps
- The policy route. The current Govern server does not serve
GET /api/v1/policy/bundle. When the server answers404, the CLI records that the organisation has no policy and runs unrestricted by one, even when policy keys are pinned (the fail-closed rule applies only when the request fails in another way). Organisation settings,models.allowed, the organisation model gateway (providerkeystone),personalModelsand organisation skills, agents, commands and rules do not reach the CLI through sign-in until the route exists. Use managed settings or the remote policy to enforce settings today. - Governance bundles. The policy bundle does not yet carry the organisation governance bundles that decide tool calls and supply checks rule packs; those come from managed settings, the shared governance folder or the repository. See Permissions and modes.
- Help text.
neuralinverse --helpstill listslogin [--issuer URL]. The flag is retired: use--base-url.
Administrator settings
The keystone block of the managed settings file:
{
"keystone": {
"baseUrl": "https://keystone.example.com", // self-hosted or air-gapped Govern; the rest is discovered
"clientId": "ni_...", // only for a Govern server older than the per-app clients
"policyKeys": { // Ed25519 keys that may sign the organisation policy, by key id
"ks-2026": "MCowBQYDK2VwAyEA...",
"ks-2027": "MCowBQYDK2VwAyEA..."
},
"requireSignIn": true // refuse model calls and tools until the person signs in
}
}
policyKeys and requireSignIn are read only from managed settings (the managed file or the remote policy). Managed settings lock the whole keystone block. Pin the next key before rotating to it; any pinned key may sign. keystone.policy: false turns the organisation policy off; lock it in managed settings if people must not turn it off.
Register the loopback redirect http://127.0.0.1/callback (any port) for the client. Govern's own first-party client registration already does this for neuralinverse-cli.
See also Enterprise deployment and Neural Inverse Govern.