Skip to content

ctx login

ctx login authenticates this project against a Contexo server and writes the resulting token to .contexo/credentials.json.

Once per project, right after ctx init and before your first ctx push. Two things surprise people. First, credentials are per project root, not machine-wide: they live in the project’s .contexo/ directory next to the knowledge base, so signing in inside ~/work/acme-api does nothing for ~/work/acme-web. This is not gh auth login. Second, a repo invite key (ctxi_…) is not a login credential — ctx login rejects it on sight and tells you to use ctx join instead.

You do not need to run ctx remote set first. When no server is configured, login defaults to the hosted API at https://api.contexo.live and saves that into .contexo/config.json for you.

Terminal window
ctx login # browser flow — the default on a terminal
ctx login --no-browser # paste a token at a prompt instead
ctx login --token ctxp_… # non-interactive (CI, containers, remote shells)
ctx auth login [flags] # identical; ctx login is the alias
ctx auth status # what is this project signed in as?
FlagTypeDefaultDescription
--api-keystringDEPRECATED: legacy shared API key. Use --token instead
--browserboolfalseforce the browser flow even when stdin is not a terminal
--dashboardstringdashboard URL used by the browser flow (default: https://app.contexo.live)
--emailstringyour email (used as commit author)
--namestringyour display name (used as commit author)
--no-browserboolfalseskip the browser flow; paste the token interactively
--repostringrepo_id on the server
--serverstringserver URL (default: https://api.contexo.live)
--tokenstringpersonal access token (skips the browser flow if set)

--token wins over everything else: if it is set, no browser opens and no prompt appears. --api-key is only consulted when --token is empty, and it prints warning: --api-key is deprecated; use --token instead (PATs are minted from the dashboard's Settings page). to stderr before proceeding.

Whether the browser opens is decided as --browser || (not --no-browser and stdin is a terminal). So off a TTY with neither flag and no token you get an error rather than a hung prompt; --browser forces the flow anyway (useful over a display-forwarded session), and --no-browser falls back to the paste prompt, which itself requires a TTY.

--server and --dashboard are persisted into .contexo/config.json as server_url and dashboard_url. ctx login --dashboard is the only CLI surface that writes dashboard_urlctx remote has no equivalent subcommand.

--name and --email are stored locally and sent as the git commit author on every push. With a personal access token you can usually skip them: if the request arrives with an empty author the server fills it from your user record. With a legacy API key there is no user record, so commits land as unknown <unknown@contexo.local> unless you pass both flags.

FlagTypeDefaultDescription
--rootstringproject root directory (default: current directory)
Terminal window
ctx login

Prints the dashboard URL it is about to open, opens it, and blocks until the dashboard hands a token back. Nothing is written until the callback succeeds, so a cancelled sign-in leaves the project untouched. If your machine cannot open a browser the URL is still printed — paste it into any browser on the same machine, since the callback targets a loopback port that only exists there.

Non-interactive, with a token you already minted

Section titled “Non-interactive, with a token you already minted”
Terminal window
ctx login --token "$CONTEXO_TOKEN" --repo acme-api

Mint the ctxp_… token from the dashboard’s Settings page at app.contexo.live. Passing --repo skips the interactive repo picker, which is what you want in CI — without a repo id and without a TTY, login still succeeds but leaves repo_id unset and the first push fails.

Terminal window
ctx login --no-browser

Prompts with Token: and reads one line from stdin. The prompt requires a terminal; piping a token into this command does not work — use --token.

Self-hosted server with the legacy shared key

Section titled “Self-hosted server with the legacy shared key”
Terminal window
ctx login --server https://contexo.internal \
--api-key "$CONTEXO_API_KEY" \
--name "dev" --email "dev@example.com"

A server started with CONTEXO_API_KEY set accepts that one shared secret as a bearer token. It authenticates as a sentinel admin rather than a person, which is why the author flags matter here — and why anything needing a real identity (minting invite keys, joining a repo) is refused. See Self-hosting.

The browser flow is a loopback redirect, the same shape as gh auth login:

  1. The CLI opens a listener on a random port on 127.0.0.1.
  2. It opens <dashboard>/cli-login?port=…&state=…&hostname=… — the hostname is informational, so you can confirm on the dashboard that the request came from the machine you are sitting at.
  3. The dashboard signs you in, mints a personal access token, and redirects to http://127.0.0.1:<port>/callback with the token, the echoed state, and your name and email from the dashboard session.
  4. The CLI rejects the callback if state does not match the value it generated or if the token does not start with ctxp_, shows a success or failure page in the browser, and shuts the listener down.

The wait is capped at five minutes. The name and email from the callback only fill in --name/--email that you did not pass explicitly.

Once a token is in hand — from any of the four paths — login writes two files under .contexo/:

  • config.json (mode 0644): server_url, plus dashboard_url and repo_id when the corresponding flags were given.
  • credentials.json (mode 0600): the token, the resolved server URL, and your name and email.

Then, if repo_id is still unset and stdin is a terminal, it calls GET /v1/repos and shows a picker of the repos you belong to. Declining the picker or failing the call is not fatal — the token is already saved, and ctx remote set-repo can finish the job later.

A container command with no behaviour of its own. Running it prints help for the two subcommands below.

Terminal window
ctx auth [command]
Terminal window
ctx auth login [flags]

The canonical spelling. ctx login is built by the same constructor with only its name and one-line summary changed, so the two are the same code path with the same flags and the same behaviour — pick whichever reads better in your notes.

FlagTypeDefaultDescription
--api-keystringDEPRECATED: legacy shared API key. Use --token instead
--browserboolfalseforce the browser flow even when stdin is not a terminal
--dashboardstringdashboard URL used by the browser flow (default: https://app.contexo.live)
--emailstringyour email (used as commit author)
--namestringyour display name (used as commit author)
--no-browserboolfalseskip the browser flow; paste the token interactively
--repostringrepo_id on the server
--serverstringserver URL (default: https://api.contexo.live)
--tokenstringpersonal access token (skips the browser flow if set)
Terminal window
ctx auth status

Reads .contexo/credentials.json and reports what is stored, masking any token longer than eight characters to its first and last four. The trailing parenthesis is the token kind, inferred from its shape: personal access token for ctxp_…, session token for a JWT, legacy API key for anything else, and invite key (NOT for CLI use) if a ctxi_… key somehow got saved.

ctx auth status
Authenticated: yes
Server: https://contexo.example.com
User: dev <dev@example.com>
Token: capt...6789 (legacy API key)

ctx auth status takes no flags.

a token is required (--token, or run interactively for the browser flow) — you are not on a terminal (CI, a pipe, a redirected stdin) and passed no token. Pass --token, or --browser if you really can drive a browser from there.

that looks like a repo invite key (ctxi_…), not a CLI token. — you pasted the output of ctx invite mint. Run ctx join <key> instead.

browser login: state mismatch (possible CSRF) — please re-run — the callback carried a state the CLI did not issue, usually a stale /cli-login tab from an earlier attempt. Close the old tabs and re-run.

browser login: callback did not include a CLI personal access token — the dashboard reached the callback but sent no ctxp_… token. Check that --dashboard points at a real Contexo dashboard; fall back to --no-browser.

browser login: timed out after 5m0s — re-run, or use --no-browser to paste a token manually — the sign-in never completed.

You're not a member of any repos yet. — the post-login repo picker found zero repos. Your credentials are already saved; create or join a repo, then run ctx remote set-repo.

  • ctx join — redeem a ctxi_… invite key into a repo
  • ctx remote — change the server or repo after signing in
  • ctx init — create .contexo/ and wire your agent
  • Self-hosting — running your own server