---
title: "Two CC accounts on one machine | CommitCycle"
description: "One laptop, two CC accounts — a client's board and your own. Which identity answers is decided by the repository, not by whichever you signed into last."
url: https://commitcycle.com/docs/operations/accounts/
language: en
---

# Two accounts on one machine

> One laptop, two CC accounts — a client's board and your own. Which identity answers is decided by the repository, not by whichever you signed into last.

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.

## Sign in more than once

```bash
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.

## Which identity this repository uses

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:

```plaintext
$ 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_.

## The order of precedence

Four things can supply the credential. The narrowest wins:

| Source                                    | What it is                                                                                                                                  |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `CC_API_URL=… CC_TOKEN=… cycle <command>` | One command, one credential, nothing stored. The token is used only for a board the environment names: without `CC_API_URL`, it is not sent |
| `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

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:

```plaintext
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_API_URL=… CC_TOKEN=… cycle <command>
                                 one command, one credential, nothing stored — the token
                                 only goes to an address the environment names too
```

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.

An identity stored before the CLI began recording organizations has **unknown** memberships — which is not the same as _none_. Those are tried rather than ruled out, and `cycle accounts` labels them as such. Every machine that upgrades keeps working, and the board still gets to answer.

## Signing out

```bash
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:

```plaintext
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`](https://commitcycle.com/docs/operations/accounts/#undoing-a-pairing) is what undoes those.

## Sessions you are not holding

**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.

This is the surface for the laptop you no longer have, and for a `cycle logout` that could not reach the board. It is the answer to a session you cannot produce the token for.

## Undoing a pairing

```bash
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.

## If it is also two pieces of work at once

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](https://commitcycle.com/docs/operations/parallel-sessions/).

## What to read next

- [Two sessions at once](https://commitcycle.com/docs/operations/parallel-sessions/) — one worktree per session, and the incident that made it a rule
- [Install](https://commitcycle.com/docs/start/install/) — the plugin, the CLI, and which one enforces
- [Grants](https://commitcycle.com/docs/concepts/grants/) — what a grant opens, and why it expires
