Skip to content

Two accounts on one machine

One laptop often holds more than one CC identity: a client’s organization and your own, two products under one company, a work address and a side project. All of them can be signed in at once, and the repository decides which one answers — not whichever you signed into most recently.

Terminal window
cycle login

Run it again with a different address. Both are kept, side by side.

Sessions live in ~/.commitcycle/session.json at mode 600 — outside any repository, because a credential that can be committed eventually is. Each entry is keyed by board and address, so two identities on the same board host are two entries, not one overwriting the other.

A repository names its organization in .zones/board.json, and the identity that answers is the one that is a member of it. cycle accounts shows both halves of that:

$ cycle accounts
→ you@acme.com https://dash.commitcycle.com (acme)
you@side-project.dev https://dash.commitcycle.com (side-project)
This repository reports to acme/checkout. It uses you@acme.com.
Stored in /Users/you/.commitcycle/session.json.

The arrow answers the question that matters in a terminal — which of me is about to be used here — rather than the one that is easy to answer, am I signed in.

Four things can supply the credential. The narrowest wins:

Source What it is
CC_TOKEN=… cycle <command> One command, one credential, nothing stored
token in .zones/board.json Committed, so it belongs to the repository
cycle pair This machine joined to one repository on one board
cycle login Your identity across a whole board

A pairing beats a session on purpose: it is scoped to a single repository, which makes it the narrower of the two, and a paired laptop is the ordinary case for a CLI while a session is what a browser holds.

What it refuses, and why the refusal is the feature

Section titled “What it refuses, and why the refusal is the feature”

If this machine holds identities for the board and none of them belongs to the organization the repository names, the command stops before it touches the network:

Signed in here as you@side-project.dev — and acme is not an organization
that identity belongs to.
Every call would come back 404, which reads exactly like "no grant" and is not.
Three ways on, narrowest first:
cycle pair join this machine to acme/checkout …
cycle login as an address that is a member of acme …
CC_TOKEN=… cycle <command> one command, one credential, nothing stored

That refusal exists because of what happened without it. The session file used to be keyed by board URL alone, so signing into a second account evicted the first. Both organizations lived on the same board host, which made the eviction invisible: every call went out as the wrong address and came back 404 — the same status a healthy board returns for no grant. So the CLI reported that a task had no grant while the console, signed in as the other address, showed one sitting right there.

A day went into that before anyone suspected the account rather than the gate. A 404 that could mean two things is not a diagnosis, and the fix is not a better error message downstream — it is refusing to send a credential that provably cannot work.

Terminal window
cycle logout you@example.com # end one identity for this board
cycle logout # end all of them for this board

It ends the session at the board first, and only then removes it from ~/.commitcycle. The order is the whole point: the stored token is the credential the board is told with, so deleting it first would leave the session alive for the rest of its 30 days with nothing anywhere able to stop it.

If the board cannot be reached, the local copy is still removed — a machine you are handing over needs it gone — and the command says so and exits non-zero:

Forgot 1 identity for https://dash.commitcycle.com on this machine.
The board was NOT told, so that session is still valid there:
you@acme.com — connect ECONNREFUSED
End it from the console: Settings → Your sessions, and revoke the row for this machine.
A session lasts 30 days, and nothing on this laptop can stop it now.

Pairings are separate and are left alone — cycle unpair is what undoes those.

Settings → Your sessions in the console lists every place this account is signed in — this browser, another browser, any terminal that ran cycle login — with when it started, when it was last used and when it expires. Ending one there stops it immediately: whatever was using it is signed out on its next request.

The list belongs to the person, not to a board: nobody else can see it, and switching boards in the sidebar does not change it. Nothing in it can be used to sign in with — a row is named by a short id derived from the credential, never by the credential.

The session you are reading it in has no End button. That one is ended by Sign out, which also clears this browser’s cookie.

Terminal window
cycle unpair

Run it in the repository whose pairing you want to end. It revokes the key at the board and then deletes it from ~/.commitcycle/machines.json, in that order and for the same reason cycle logout uses that order.

A machine key has no expiry, by design — like an SSH key it lives until it is revoked, and what makes that safe is that it is listed and revocable. Pairing again does not undo a pairing: cycle pair mints a second key and leaves the first one open.

It leaves .zones/board.json alone. That file is committed and names which board this repository reports to; it is not a credential, and deleting it would take the board away from everyone who clones the repository.

If the board cannot be reached, the command says so, keeps the key and exits non-zero. That is deliberately different from cycle logout: a session expires in 30 days, a machine key never does, and the key on this disk is the only credential that can revoke it — deleting it would leave the pairing open with nothing able to close it. Run cycle unpair again when the board answers, or revoke the row from the console’s Settings → Connect a machine table, which works from anywhere.

Accounts and sessions are independent questions. The identity answers who; the branch answers which task. Holding two accounts does nothing to make two agents safe in one directory — a single working directory has one branch, so it has one task, no matter how many identities you hold.

If the two accounts are also two pieces of work running side by side, give each one its own working directory: Two sessions at once.

  • Two sessions at once — one worktree per session, and the incident that made it a rule
  • Install — the plugin, the CLI, and which one enforces
  • Grants — what a grant opens, and why it expires