ctx login
ctx login authenticates this project against a Contexo server and writes the
resulting token to .contexo/credentials.json.
When you’d reach for it
Section titled “When you’d reach for it”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.
Synopsis
Section titled “Synopsis”ctx login # browser flow — the default on a terminalctx login --no-browser # paste a token at a prompt insteadctx login --token ctxp_… # non-interactive (CI, containers, remote shells)ctx auth login [flags] # identical; ctx login is the aliasctx auth status # what is this project signed in as?| Flag | Type | Default | Description |
|---|---|---|---|
--api-key | string | DEPRECATED: legacy shared API key. Use --token instead | |
--browser | bool | false | force the browser flow even when stdin is not a terminal |
--dashboard | string | dashboard URL used by the browser flow (default: https://app.contexo.live) | |
--email | string | your email (used as commit author) | |
--name | string | your display name (used as commit author) | |
--no-browser | bool | false | skip the browser flow; paste the token interactively |
--repo | string | repo_id on the server | |
--server | string | server URL (default: https://api.contexo.live) | |
--token | string | personal 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_url — ctx 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.
| Flag | Type | Default | Description |
|---|---|---|---|
--root | string | project root directory (default: current directory) |
Examples
Section titled “Examples”Browser flow (the default)
Section titled “Browser flow (the default)”ctx loginPrints 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”ctx login --token "$CONTEXO_TOKEN" --repo acme-apiMint 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.
Paste a token by hand
Section titled “Paste a token by hand”ctx login --no-browserPrompts 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”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.
How it works
Section titled “How it works”The browser flow is a loopback redirect, the same shape as gh auth login:
- The CLI opens a listener on a random port on
127.0.0.1. - 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. - The dashboard signs you in, mints a personal access token, and redirects to
http://127.0.0.1:<port>/callbackwith the token, the echoedstate, and your name and email from the dashboard session. - The CLI rejects the callback if
statedoes not match the value it generated or if the token does not start withctxp_, 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, plusdashboard_urlandrepo_idwhen 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.
ctx auth
Section titled “ctx auth”A container command with no behaviour of its own. Running it prints help for the two subcommands below.
ctx auth [command]ctx auth login
Section titled “ctx auth login”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.
| Flag | Type | Default | Description |
|---|---|---|---|
--api-key | string | DEPRECATED: legacy shared API key. Use --token instead | |
--browser | bool | false | force the browser flow even when stdin is not a terminal |
--dashboard | string | dashboard URL used by the browser flow (default: https://app.contexo.live) | |
--email | string | your email (used as commit author) | |
--name | string | your display name (used as commit author) | |
--no-browser | bool | false | skip the browser flow; paste the token interactively |
--repo | string | repo_id on the server | |
--server | string | server URL (default: https://api.contexo.live) | |
--token | string | personal access token (skips the browser flow if set) |
ctx auth status
Section titled “ctx auth status”ctx auth statusReads .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.
Authenticated: yes
Server: https://contexo.example.com
User: dev <dev@example.com>
Token: capt...6789 (legacy API key)ctx auth status takes no flags.
Common errors
Section titled “Common errors”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.
See also
Section titled “See also”ctx join— redeem actxi_…invite key into a repoctx remote— change the server or repo after signing inctx init— create.contexo/and wire your agent- Self-hosting — running your own server
