orbotodocs
API & CLI

CLI connection profiles

Separate accounts and servers across CLI commands, agent processes, the Node wrapper, and inbox hooks.

Connection profiles keep a server URL and credential together. Select one per command or agent process; there is no global active account that another agent can switch underneath you.

Version requirement: CLI 0.180.0 or later. Check orboto version and orboto profile --help before using this guide. See installation and updates.

Create and select

Create an API key for the intended account using orboto's account/key management. Grant only the required project membership and permissions. Put the pair in an owner-readable dotenv file using your editor, not a shell command containing the key:

ORBOTO_BASE_URL=https://tasks.example.com/api
ORBOTO_TOKEN=orb_your_key_here

Use your installation's API base URL: a reverse proxy commonly uses /api; a direct API such as http://localhost:3000 does not.

chmod 600 ./codex.env
orboto profile import codex --from ./codex.env
orboto --profile codex whoami
orboto --profile codex get /projects

Import copies the pair to ~/.orboto/profiles/codex.json. It does not modify or delete the source file or legacy configuration. Keep all credential files out of version control. profile import codex --stdin accepts piped dotenv data; terminal input is refused to avoid echoing secrets. No --token flag exists. Import other accounts or instances under separate names.

Set ORBOTO_PROFILE=codex in a dedicated agent process's environment to make all its CLI calls and child processes select that profile. Leading --profile other overrides it per command. Never configure an agent-specific selector in a shared shell startup file. Global flags go before the command.

ORBOTO_PROFILE=codex ORBOTO_AGENT_SESSION=reviewer-1 orboto session-start
orboto --profile personal whoami

Inspect, rotate and remove

orboto profile list
orboto profile show codex
orboto profile import codex --from ./rotated.env --replace
orboto profile remove codex --yes

These commands are local-only and return JSON. list returns names; show reports the profile, base URL, source and credentialConfigured, never any part of a key. Use orboto --profile codex whoami to verify the actual account. Replacement requires --replace; removal requires --yes and deletes only the local file, never revokes the remote key. Revoke remotely through the account's key management when intended. No local command grants permissions.

Stop work sessions, timers and the selected wrapper daemon before rotation or removal. Running processes retain the pair they loaded; rotation creates a new state namespace. Do not switch accounts with a timer running.

Configuration precedence

SelectionCredential source
Leading --profile nameOnly that profile, ahead of ORBOTO_PROFILE
ORBOTO_PROFILE=nameOnly that profile
NeitherExisting environment, then cwd .orboto.env, then ~/.orboto/env; the Node wrapper also keeps its legacy skill-root .env fallback

Added in v0.211.3 In the legacy sources a token and its server address stay a pair. A token saved in a file that names a server only goes to that server: a different --base-url or ORBOTO_BASE_URL fails every command with exit code 2 ("the credential ... was saved for another server"), and a ./.orboto.env that names a server while the token comes from ~/.orboto/env or the environment fails the same way. Put both keys in one file, run orboto login, or set both in the environment. The background daemon keeps the environment it was started with above the files, so a checkout's .orboto.env never replaces an exported pair, and daemon control variables are read from the process environment only.

A selected profile never merges with legacy or process credentials or the inbox OAuth login. Missing, invalid, incomplete, unreadable or unsafe profiles fail closed. A 401/403 or network failure does not try another account. A conflicting --base-url fails before a request; create another complete profile instead. Same-origin API redirects work; changing scheme, host or port is refused. HTTPS is required except for explicit loopback HTTP URLs.

Names are 1-48 lowercase ASCII characters, start with a letter, and otherwise contain letters, digits, _ or -. JSON has only baseUrl and token. Input is bounded to 64 KiB; tokens must be nonempty printable ASCII without whitespace. Dotenv is data: no shell export, quoting, substitution or expansion; duplicate credential keys are rejected.

Filesystem protection

On POSIX the profile directory is 0700, credentials are 0600, and .orboto cannot be writable by other users. Symlinked profile files and directories are refused. An exclusive per-profile lock plus a private temporary file, fsync and atomic rename ensure readers see a complete pair. Conflicting writes fail rather than silently overwrite. After a crash, inspect any remaining <name>.json.lock: only remove that exact lock after confirming no import/remove process owns it. Never delete an active lock.

This is local filesystem protection, not encryption or isolation between processes running as the same OS user. Windows POSIX modes are not an ACL guarantee: protect the user profile directory with the owning user's ACL.

Parallel agents, wrapper and inbox

One agent, one profile. orboto login and orboto login --api-key write the default connection (~/.orboto/env); on a machine where several agents run, the second agent's login silently re-identifies every process that relies on the default. Give each agent identity its own named profile (orboto profile import <name> --from ./<name>.env) and select it through ORBOTO_PROFILE in that agent's environment or a .orboto.env in its working folder - never by rewriting ~/.orboto/env.

The native CLI and Node wrapper share the storage format and selector. Use an updated agent skill containing the profile helper when you use the wrapper. Both namespace their agent sessions by profile, server and credential. For parallel instances sharing a profile and checkout, set distinct ORBOTO_AGENT_SESSION labels.

Local work-session, current-ticket and rules state is separated between instances. Runner lane directories remain lane- and profile-scoped. Wrapper daemon sockets, logs and PID files are instance-scoped even with custom paths. A profile daemon never reloads another identity on a 401.

The updated inbox plugin reads ORBOTO_PROFILE from the agent application's environment, not a flag on an unrelated CLI call. Seen-state and throttling are bound to the credential pair and hook session. ORBOTO_PROJECT narrows reads to that project plus unscoped mail; ORBOTO_SENDER_REF excludes that session's own sends. Empty inboxes print nothing. Failed explicit-profile checks emit a short secret-free diagnostic and exit zero. Delivery never acknowledges messages: acknowledge explicitly after handling them.

SessionStart/UserPromptSubmit hooks run on those events. They are not a timer and do not wake idle agents. Update or install through the application's normal plugin flow and review renewed hook trust prompts.

The skill wrapper inside an agent harness

Added in v0.228.1 The Node wrapper vendored into a repository (.claude/skills/orboto/scripts/orboto.mjs) never signs in as another agent's identity. Inside a detected agent harness (Claude Code, Codex, Gemini CLI, Kimi Code, Antigravity CLI) it stops with exit code 2 when:

  • no profile is selected and the token comes from a shared credential file (~/.orboto/env, ./.orboto.env or the skill's .env) that every harness on the machine falls back to, or
  • the profile is another harness's agent identity and was picked by ORBOTO_PROFILE, a .orboto-profile pointer or the MCP entry.

The message names the account the credential belongs to (one GET /users/me, nothing else is sent) and how to fix it. The wrapper runs with --profile <name>, with ORBOTO_PROFILE set to a profile of that harness, with a binding (orboto profile bind <harness> <profile>), or with ORBOTO_BASE_URL and ORBOTO_TOKEN exported for the process. orboto profile import <name> --from ~/.orboto/env turns the shared file into a profile. whoami still answers and prints the refusal. Outside a harness nothing changes. The native CLI warns in the same situation; --strict-identity makes a launcher refuse.

MCP is independent

Remote MCP authentication stays in its own OAuth connection. Profiles do not extract MCP tokens or rewrite any MCP configuration. An existing stdio/API-key MCP configuration remains a separate explicit pair. Check the returned user ID and email on CLI and MCP separately before working.

Troubleshooting

SymptomWhat to check
profile is unknownCheck the CLI version and update to a version meeting the requirement above.
Import rejects a profileCheck the name, complete server/key pair, HTTPS URL, owner-only permissions and absence of symlinks. Do not loosen permissions to bypass the check.
Selected profile returns 401 or 403Verify the intended key, account and project permissions. The CLI deliberately does not fall back to another account.
CLI and MCP show different usersThey authenticate independently. Select the intended CLI profile and verify the MCP connection separately.
Two agents share local stateGive each process a distinct ORBOTO_AGENT_SESSION, keeping its profile fixed.
Inbox does not run while the agent is idleHooks require their host events; a running supervisor is needed for automatic wakeups.

On this page