Skip to main content
The CLI authenticates every API call with a bearer token. It resolves that token from one of five sources, in a fixed order, and persists browser-login credentials to a config file under ~/.ish.

Token resolution order

Every command resolves a token before it calls the API. The first source that produces a token wins. If none produce a token, the command fails with:
--token and --token-file are global flags, documented with the other globals on every generated command page. See ish session and any command’s global-flags table.

Token refresh

The saved OAuth session (source 4) holds an access_token, a refresh_token, and the oauth_client_id minted at login. When a command runs and the access token is expired or within five minutes of expiry, the CLI refreshes it against Supabase, saves the rotated pair back to ~/.ish/config.json, and continues. The refresh token rotates on each use, so a session persists with regular use without a re-login. Refresh outcomes:
  • Success. The command proceeds with the new access token.
  • Network failure during refresh. The command fails with Could not refresh session (network error). Check your connection or run "ish login". Tokens are left intact.
  • Permanent failure (Supabase 4xx, such as refresh_token_not_found or invalid_grant). The dead access_token, refresh_token, and legacy token fields are cleared from the config so the next run does not retry the doomed refresh. The command fails with Session expired. Run "ish login" to re-authenticate. Add --verbose to append the raw Supabase response.
A resolved token (sources 4 and 5) is verified against the API before use. If the API rejects it, the command fails with Saved token is invalid. Run "ish login" to re-authenticate. A dev or prod environment mismatch (a token minted by one Supabase project but presented to the other API) appends a hint explaining which side to change.
Auth failures exit with code 3 and carry error_code: "auth_failed" in JSON output. Branch on either to re-prompt for login. A billing or quota wall arrives as HTTP 403 but exits 1, not 3, so a login retry loop never triggers on a credit cap.

Commands

ish login

Open the browser, sign in, and save the resulting OAuth session to ~/.ish/config.json.
login always runs the full browser flow and re-authenticates. There is no “already logged in” short-circuit; that check is ish status. A routine token refresh does not go through login. Each login mints a fresh OAuth client.

ish logout

Remove saved credentials and clear the active context.
logout deletes access_token, refresh_token, the legacy token, and oauth_client_id, and it also clears the active workspace, study, ask, and chat-endpoint selections. Those selections are identity-scoped, so they are meaningless to the next account that signs in.

ish status

Show the active session: signed-in user, active workspace, study, ask, chat endpoint, installed skill, config home, and API URL. Aliased as ish whoami.
status is the first command to run when starting cold. It does not error when no token is present: it returns user: null with a hint instead of exiting, so it is safe to run pre-login. JSON output is safe to pipe. For the full command list and flags, see the generated reference: ish session.

Config file

Saved credentials and the active context live in a single JSON file.
  • Path. ~/.ish/config.json.
  • Permissions. The CLI creates the ~/.ish directory with mode 0700 and writes the config file with mode 0600. Writes are atomic (temp file plus rename).
  • A corrupted file is ignored. The CLI treats an unparsable config as empty rather than failing.
Fields the CLI reads and writes:
string
OAuth access token from the last ish login. Auto-refreshed when stale.
string
OAuth refresh token. Rotates on each refresh.
string
OAuth client id minted at login. Required to refresh the OAuth session.
string
Legacy single token pasted by hand. No refresh. Absent on OAuth setups.
string
Active workspace id, set by ish workspace use.
string
Active study id, set by ish study use.
string
Active ask id.
string
Active chatbot endpoint id, set by ish chat endpoint use.

ISH_HOME

By default the CLI stores everything under ~/.ish. Set ISH_HOME to relocate that root, the same way gh uses GH_CONFIG_DIR and aws uses AWS_CONFIG_FILE. When ISH_HOME is set, config.json, aliases.json, the downloaded binary, browsers, and simulation artifacts all live under it.
ish status prints the resolved home directory in its home field, so you can confirm which root is in effect.

Environment variables

string
Auth token (token-resolution source 3). Overridden by --token and --token-file.
string
Override the ~/.ish state root for config, aliases, and cached binaries.
string
Override the backend API base. Default https://api.ishlabs.io.
string
Override the web app URL used in the browser login flow. Default https://app.ishlabs.io.
string
Override the Supabase project URL used for login and token refresh. Set with ISH_SUPABASE_ANON_KEY.
string
Override the Supabase publishable key paired with ISH_SUPABASE_URL.
NO_COLOR is also honored: set it (or pass --no-color) to disable colored output.