Agents / Fundamentals
OAuth
Genesis supports “subscription auth” via OAuth for providers that offer it (notably OpenAI Codex (ChatGPT OAuth)). For Anthropic, the practical split is now:
- Anthropic API key: normal Anthropic API billing
- Anthropic Claude CLI / subscription auth inside Genesis: Anthropic staff told us this usage is allowed again
OpenAI Codex OAuth is explicitly supported for use in external tools like Genesis. This page explains:
For Anthropic in production, API key auth is the safer recommended path.
- how the OAuth token exchange works (PKCE)
- where tokens are stored (and why)
- how to handle multiple accounts (profiles + per-session overrides)
Genesis also supports provider plugins that ship their own OAuth or API‑key flows. Run them via:
genesis models auth login --provider <id>
The token sink (why it exists)
OAuth providers commonly mint a new refresh token during login/refresh flows. Some providers (or OAuth clients) can invalidate older refresh tokens when a new one is issued for the same user/app.
Practical symptom:
- you log in via Genesis and via Claude Code / Codex CLI → one of them randomly gets “logged out” later
To reduce that, Genesis treats auth-profiles.json as a token sink:
- the runtime reads credentials from one place
- we can keep multiple profiles and route them deterministically
- external CLI reuse is provider-specific: Codex CLI can bootstrap an empty
openai-codex:defaultprofile, but once Genesis has a local OAuth profile, the local refresh token is canonical; other integrations can remain externally managed and re-read their CLI auth store
Storage (where tokens live)
Secrets are stored per-agent:
- Auth profiles (OAuth + API keys + optional value-level refs):
~/.genesis/agents/<agentId>/agent/auth-profiles.json - Legacy compatibility file:
~/.genesis/agents/<agentId>/agent/auth.json(staticapi_keyentries are scrubbed when discovered)
Legacy import-only file (still supported, but not the main store):
~/.genesis/credentials/oauth.json(imported intoauth-profiles.jsonon first use)
All of the above also respect $GENESIS_STATE_DIR (state dir override). Full reference: /gateway/configuration
For static secret refs and runtime snapshot activation behavior, see Secrets Management.
Anthropic legacy token compatibility
Anthropic's public Claude Code docs say direct Claude Code use stays within
Claude subscription limits, and Anthropic staff told us Genesis-style Claude
CLI usage is allowed again. Genesis therefore treats Claude CLI reuse and
claude -p usage as sanctioned for this integration unless Anthropic
publishes a new policy.
For Anthropic's current direct-Claude-Code plan docs, see Using Claude Code with your Pro or Max plan and Using Claude Code with your Team or Enterprise plan.
If you want other subscription-style options in Genesis, see OpenAI Codex, Qwen Cloud Coding Plan, MiniMax Coding Plan, and Z.AI / GLM Coding Plan.
Genesis also exposes Anthropic setup-token as a supported token-auth path, but it now prefers Claude CLI reuse and claude -p when available.
Anthropic Claude CLI migration
Genesis supports Anthropic Claude CLI reuse again. If you already have a local Claude login on the host, onboarding/configure can reuse it directly.
OAuth exchange (how login works)
Genesis’s interactive login flows are implemented in @earendil-works/pi-ai and wired into the wizards/commands.
Anthropic setup-token
Flow shape:
- start Anthropic setup-token or paste-token from Genesis
- Genesis stores the resulting Anthropic credential in an auth profile
- model selection stays on
anthropic/... - existing Anthropic auth profiles remain available for rollback/order control
OpenAI Codex (ChatGPT OAuth)
OpenAI Codex OAuth is explicitly supported for use outside the Codex CLI, including Genesis workflows.
Flow shape (PKCE):
- generate PKCE verifier/challenge + random
state - open
https://auth.openai.com/oauth/authorize?... - try to capture callback on
http://127.0.0.1:1455/auth/callback - if callback can’t bind (or you’re remote/headless), paste the redirect URL/code
- exchange at
https://auth.openai.com/oauth/token - extract
accountIdfrom the access token and store{ access, refresh, expires, accountId }
Wizard path is genesis onboard → auth choice openai-codex.
Refresh + expiry
Profiles store an expires timestamp.
At runtime:
- if
expiresis in the future → use the stored access token - if expired → refresh (under a file lock) and overwrite the stored credentials
- exception: some external CLI credentials stay externally managed; Genesis
re-reads those CLI auth stores instead of spending copied refresh tokens.
Codex CLI bootstrap is intentionally narrower: it seeds an empty
openai-codex:defaultprofile, then Genesis-owned refreshes keep the local profile canonical.
The refresh flow is automatic; you generally don't need to manage tokens manually.
Multiple accounts (profiles) + routing
Two patterns:
1) Preferred: separate agents
If you want “personal” and “work” to never interact, use isolated agents (separate sessions + credentials + workspace):
genesis agents add work
genesis agents add personal
Then configure auth per-agent (wizard) and route chats to the right agent.
2) Advanced: multiple profiles in one agent
auth-profiles.json supports multiple profile IDs for the same provider.
Pick which profile is used:
- globally via config ordering (
auth.order) - per-session via
/model ...@<profileId> - via
priority(see Rotation order)
Each profile can carry a human-readable displayName and a numeric priority
that controls the rotation order. Both fields can be set on either the
secret-side credential or the config-side auth.profiles.<id> entry; secret
side wins when both are set.
Example (per-profile name and priority via the secret side):
// auth-profiles.json
{
profiles: {
"anthropic:work": {
type: "oauth",
provider: "anthropic",
access: "...",
refresh: "...",
expires: 0,
displayName: "Work",
priority: 100,
},
"anthropic:personal": {
type: "oauth",
provider: "anthropic",
access: "...",
refresh: "...",
expires: 0,
displayName: "Personal",
},
},
}
Example (config side only — useful for shaping rotation from genesis.json without rewriting secrets):
// genesis.json
{
auth: {
profiles: {
"anthropic:work": {
provider: "anthropic",
mode: "oauth",
displayName: "Work",
priority: 100,
},
"anthropic:personal": { provider: "anthropic", mode: "oauth", displayName: "Personal" },
},
},
}
Add or edit via CLI:
# New profile with name + priority (paste-token / setup-token / login all accept these)
genesis models auth paste-token --provider anthropic --profile-id anthropic:work --name "Work" --priority 100 --expires-in 365d
# Rename / set priority / remove after the fact
genesis models auth rename --profile-id anthropic:work --name "Work"
genesis models auth set-priority --profile-id anthropic:work --priority 100
genesis models auth remove --profile-id anthropic:work
Example (session override):
/model Opus@anthropic:work
How to see what profile IDs exist:
genesis channels list --json(showsauth[])
Related docs:
- Model failover (rotation + cooldown rules)
- Slash commands (command surface)
Related
- Authentication — model provider auth overview
- Secrets — credential storage and SecretRef
- Configuration Reference — auth config keys