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_hereUse 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 /projectsImport 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 whoamiInspect, rotate and remove
orboto profile list
orboto profile show codex
orboto profile import codex --from ./rotated.env --replace
orboto profile remove codex --yesThese 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
| Selection | Credential source |
|---|---|
Leading --profile name | Only that profile, ahead of ORBOTO_PROFILE |
ORBOTO_PROFILE=name | Only that profile |
| Neither | Existing 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.envor 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-profilepointer 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
| Symptom | What to check |
|---|---|
profile is unknown | Check the CLI version and update to a version meeting the requirement above. |
| Import rejects a profile | Check 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 403 | Verify the intended key, account and project permissions. The CLI deliberately does not fall back to another account. |
| CLI and MCP show different users | They authenticate independently. Select the intended CLI profile and verify the MCP connection separately. |
| Two agents share local state | Give each process a distinct ORBOTO_AGENT_SESSION, keeping its profile fixed. |
| Inbox does not run while the agent is idle | Hooks require their host events; a running supervisor is needed for automatic wakeups. |