Orbit uses a project root + .repos/ + workspace directory model to manage multi-repo workspaces.
project-root/
.repos/
.orbit ← Global index
.backend.md ← Per-repo memo
backend/ ← Primary repo
frontend/
task-01/
.orbit ← Workspace metadata (goal, created, status)
backend/ ← Worktree
frontend/
task-02/
.orbit
backend/
Where:
.repos/stores the primary copy and metadata for each repotask-01/,task-02/are workspaces, isolated by task<workspace>/<repo>is the actual development directory, corresponding to a Git worktree
You can run directly:
./orbit.sh <command>The following assumes orbit as the command name. For global installation:
./install.sh --zshIf you use bash, change to --bash. Every install refreshes plugin content — the marketplace snapshot is updated and the plugin reinstalled from it, so re-running the installer is how you pull the latest. To repair a broken plugin state or switch where a plugin's marketplace points (for example from a local checkout to the public git repo), add --force: it removes the plugin and marketplace first, then re-adds from the current source — e.g. ORBIT_SOURCE=orbcli/orbit ./install.sh --codex --force. (If the source is unreachable, --force skips the reset and keeps the existing install instead.) The marketplace snapshot and plugin caches are per-user global state and the agent CLIs take no locks on them — avoid running install.sh in parallel (e.g. CI plus a local run). To uninstall: ./install.sh --uninstall --all, or pick individual targets (--cli, --claude, --codex, …) — ./install.sh --help lists them.
This section only matters when installing over the network (piped curl | bash, or a remote ORBIT_SOURCE); running ./install.sh from a local checkout touches no network at all.
Every network operation install.sh performs (the orbit.sh download, a URL-source clone, the OpenCode file downloads, the agent CLIs' marketplace/plugin installs) is retried through transient failures and never fails silently — the final attempt prints the real underlying error.
| knob | default | meaning |
|---|---|---|
ORBIT_RETRY |
3 |
attempts per network operation before giving up |
ORBIT_RETRY_DELAY_SECONDS |
5 |
seconds between attempts |
ORBIT_TIMEOUT_SECONDS |
60 |
per-attempt cap — a hung connection is killed and retried |
Source chain. Sources resolve by priority: ORBIT_SOURCES > ORBIT_SOURCE > this local checkout > the default orbcli/orbit.
-
ORBIT_SOURCEStakes a space-separated chain; each retry rotates to the next entry, spreading attempts across route and time (intermittent blocks rarely sit on every host+protocol combo at once). A one-entry chain never rotates, so plain install.sh stays single-source and stable. -
try.shsuppliesorbcli/orbit→ HTTPS clone → SSH clone for zero-setup demo runs. -
ORBIT_SOURCEalso picks the clone protocol for the plugin marketplace: theowner/reposhorthand leaves that choice to the agent CLI (some expand it to SSH, which fails without an SSH key), while an explicit URL is used as-is. On a machine without SSH keys, pass the HTTPS URL:ORBIT_SOURCE=https://github.com/orbcli/orbit.git ./install.sh --claude
Marketplace failures. A marketplace add/update that fails through every retry is not immediately fatal: install.sh prints the CLI's real error plus a warning naming it as the root cause, then lets the plugin install decide — an existing local snapshot still installs offline; a missing marketplace fails the install with the CLI's own clear error.
Escape hatch. When all retries fail, the remaining issue is network reachability: get the repo onto the machine yourself (proxy / mirror / another network) and run ./install.sh from the checkout — a local path source needs no network.
External config-management tools (provider switchers, dotfile syncers) commonly snapshot the whole config file and restore it later — anything written after the snapshot was taken is silently rolled back. Orbit's plugin registration lives in these same files, so a restore unregisters the plugin; the on-disk content (marketplace snapshot, plugin cache) is never touched.
Recovery. Re-run the installer — every install re-registers and refreshes in one pass.
Prevention. Add Orbit's registration entries to your tool's stored config, so restores bring them back. Snapshots are usually kept per profile/provider — update each one. (Adding them only to the live config file is not enough: the next restore drops them again.) What each host needs:
Codex — ~/.codex/config.toml must contain:
[marketplaces.orbcli]
source_type = "git"
source = "https://github.com/orbcli/orbit.git"
[plugins."codex-orbit@orbcli"]
enabled = true(Codex maintains the last_updated and last_revision bookkeeping itself.)
Claude — ~/.claude/settings.json must contain:
"enabledPlugins": {
"claude-orbit@orbcli": true
}(Claude's marketplace registration lives in a separate file, ~/.claude/plugins/ — only this entry can be rolled back.)
OpenCode (npm install only) — the plugin array in opencode.json must contain:
"plugin": [
"opencode-orbit"
](The install.sh path drops the plugin file into ~/.config/opencode/plugins/ — no config entry, nothing to roll back.)
No separate init command is needed — the first clone or new automatically initializes the project root.
orbit clone <url>
orbit clone <url> --push <fork-url>
orbit clone <url> --name <identity>
orbit clone <url> --branch <branch>Common examples:
orbit clone git@github.com:org/backend.git
orbit clone git@github.com:org/backend.git --push git@github.com:me/backend.git
orbit clone git@github.com:kubernetes/kubernetes.git--push sets the fork push URL (git push pushes to fork, git fetch pulls from upstream).
--name overrides the default repo identity (defaults to URL basename), used when basename is unsuitable as a directory name.
--branch specifies the default branch at clone time (passed to git clone --branch), used when only a specific branch is needed.
View repos already in the pool:
orbit reposOutput format:
NAME ADDED MEMO BRIEF
backend * ok Go REST API, sqlc-generated DB layer
frontend ok React SPA, consumes backend API
my-svc none -
ADDED marks repos already in the current workspace; MEMO is the card state
(ok / stale N / none). Add --urls for the remote URL column.
View detailed memo of a specific repo:
orbit info backendorbit info is purely local (never fetches) and detects two layers of staleness against last-fetched refs — refreshed by orbit sync / orbit prune, or your own fetch/pull:
- Pool behind upstream: stderr shows
N new commits on origin/main, runorbit syncto synchronize - Memo behind pool HEAD: stderr shows
memo is N commits behind HEAD, consider updating memo
orbit sync backend # fast-forward to upstream latest
orbit sync backend --force # force align (when local has diverged)
orbit sync backend --branch release-1.30 # switch tracking branch
orbit sync # sync all pool repos (at project root)Scope is inferred from CWD: project root → all repos; workspace → repos in that workspace; worktree → that single repo. You can also specify repo names explicitly.
sync fast-forwards the pool repo (.repos/<repo>) only — it never moves a worktree you've already checked out. When run from inside a workspace whose worktree tracks the branch just advanced, sync emits a stderr note that the worktree is now behind; bring it up to date with native git if you want. Don't re-run orbit sync expecting the worktree to move.
orbit new "Modify API definition and update frontend calls"
orbit new "Debug release-1.29 performance issue" --name perf-debug
orbit new "Refactor auth module" --exec "claude"
echo "Modify API definition" | orbit new # Read goal from stdin (pipe-friendly)
orbit new # Open editor to input goal (similar to git commit)Behavior:
- Creates a workspace directory (defaults to
task-01,task-02...) - Writes
.orbitfile recording goal and creation time - If
agent.recommendis configured, recommends a launch command; otherwise just promptscd <workspace>
After orbit new creates a workspace:
--exec "cmd": immediately starts the agent in the new workspace- No
--execbutagent.recommendis configured: recommends launch command in next steps (does not auto-execute) - Neither: just prompts
cd <workspace>
It's recommended to configure agent.recommend after project initialization, so each orbit new recommends the correct launch command:
orbit config agent.recommend 'claude "orbit start"'After configuration, orbit new "goal" outputs:
created workspace: task-01
goal: goal
cd task-01 && claude "orbit start"
Godspeed.
Copy and run the recommended command to launch the agent. The agent triggers orbit skill startup detection through the initial prompt, reads context, and starts working. With the Claude Code or Qoder plugin installed, the orbit start phrase is optional — the session hook detects the workspace either way; keep it for skill-only setups, where it is the trigger.
Common configuration examples:
# Claude Code
orbit config agent.recommend 'claude "orbit start"'
# Qoder
orbit config agent.recommend 'qoder "orbit start"'
# Custom launch
orbit config agent.recommend 'claude --model sonnet "orbit start"'Execute within a workspace:
cd task-01/
orbit add backend
orbit add frontendSpecify a particular tag or branch as starting point:
orbit add backend --ref v2.1.0
orbit add backend --ref release-1.29Notes:
- Workspace is auto-inferred from CWD (no need to pass explicitly)
- Defaults to creating worktree using the repo's default remote branch
--ref <tag/branch>specifies the checkout starting point (tag or remote branch)- The created local branch is
ws/<workspace>/<default-branch>(e.g.,ws/task-01/main) - This is the local starting point; the agent branches off from here
Create a new tracking branch from current HEAD:
orbit switch -c feat-api-refactor
# → Creates ws/task-01/feat-api-refactor
# → Sets upstream → origin/feat-api-refactor (local only, no push)
# → Remote branch is only created on first git pushSwitch to an existing remote branch:
orbit switch hotfix-123
# → fetch origin/hotfix-123
# → Creates ws/task-01/hotfix-123 tracking itWhen executing from workspace root, specify the repo:
cd task-01/
orbit switch backend feat-api-refactor
orbit switch -c frontend new-featureIn scoped mode, git push automatically pushes to the correct remote branch (without prefix):
git push
# → ws/task-01/feat-api-refactor pushes to origin/feat-api-refactorAfter orbit add, use all native git commands; orbit does not participate in branch management:
cd task-01/backend/
git checkout -b feature/api-refactor
# work, commit
git push origin feature/api-refactorTracking display: the pool's fetch config carries the full wildcard map (+refs/heads/*:refs/remotes/origin/*), so once a branch has upstream config, git status / @{upstream} resolve and a push materializes the tracking ref on the spot — no registration, no waiting for an orbit touchpoint. The upstream config itself is wired by orbit switch -c, by git push -u, or by hand.
Fetch habits are a cost question, never a correctness one: orbit's own commands always fetch named branches only, and your git fetch origin <branch> does the same — the pool's object pull stays at what you actually track. A bare git fetch or git pull is just as correct; it simply pulls every branch's objects too (on a huge repo that's a one-time GB-scale step; fetch.prune keeps the refs self-cleaning afterward).
orbit status # Current workspace (inferred from CWD)
orbit status task-01 # Specify when at project rootView/set workspace goal:
orbit context goal # Read
orbit goal "new goal" # Set/update
echo "new goal" | orbit goal # Set from stdin (pipe-friendly)
orbit goal # Modify interactively (editor on a TTY) — never a read
orbit goal --clear # Delete goalWrite a per-repo memo (common agent operation):
cat <<'EOF' | orbit memo backend
# backend
Go REST API, sqlc-generated DB layer.
## When to add (roles)
- Owns the HTTP API and business logic — add for any endpoint or service change.
## How to use
- `cmd/server/main.go` — server startup + route mounting; start here to trace a request.
- `internal/service/` — business logic; the entry point for behavior changes.
EOFAuto-generate a scaffold memo template (for quick initialization):
orbit memo backend --scaffold--scaffold outputs a static scaffold template to stdout (doesn't write to file or update index), listing the recommended section structure with TODO placeholders. Agents use this as a starting point to write the real memo after exploring the repo.
Refresh the index (infrequent maintenance):
orbit memo # Refresh all repo indexes
orbit memo backend --refresh # Refresh single repo indexThree optional keys tune the memo card; set them with orbit config <key> <value> (unset → default):
orbit config memo.minLines 4 # soft floor: below this a memo counts as thin/missing (default 4)
orbit config memo.maxLines 16 # hard ceiling: curate instead of appending past it; also caps the
# README fallback in `orbit info` (default 16)
orbit config explore.paths ".:1" # cold-start exploration scope for the first `orbit add` of a repo:
# a comma-delimited list of <path>:<depth> entries (default ".:1")memo.minLines/memo.maxLines are surfaced as card budget: <min>–<max> lines at the curation checkpoints (jot overflow and orbit done). explore.paths is a one-time cold-start knob only — once the first exploration writes the card, the jot → incremental-memo pipeline maintains it. Orbit attaches no meaning to what lives at those paths (a pre-generated code-doc works just as well).
A config key orbit depends on is managed state: converged at every touchpoint under the default mode, with three-mode escape hatches. Three optional keys select the mode, each taking always (default) / once / never:
orbit config git.fetchAllBranches always # always: keep remote.origin.fetch at exactly the wildcard map
# (+refs/heads/*:refs/remotes/origin/*), converging
# anything else at the next touchpoint (default)
# once: write the map once at clone, then the layout is yours
# never: never write it (pools stay single-branch)
orbit config git.fetchPrune always # same three modes, for fetch.prune=true (default always)
orbit config git.pushUpstreamByDefault always # same three modes, for push.default=upstream (default always)Under the default always, a pool whose config deviates — an older orbit's per-branch entries, a hand-edit, an emptied config — is converged at the next orbit sync / orbit info / session start / orbit prune, with a stderr note at the moment it happens. Set the keys to once when your team keeps its own refspec layout (e.g. a feat/* scoped map) or its own push.default: new pools still get the working baseline at birth, and orbit never corrects it afterward.
During work, record repo knowledge for later memo aggregation:
cd task-01/backend/
orbit jot "entry point is cmd/main.go" # Record a discovery (repo inferred from CWD)
orbit jot backend "role: owns the public /auth API" # Explicit repo name
orbit jot backend --pop # Pop all entries (outputs + clears)Jot is a lightweight queue — push discoveries as you find them, pop and merge into memo at natural breakpoints. Per repo, when entries pass half of jot.bufferSize (default 4) a building note counts them; past the buffer an overflow warning suggests aggregation.
When orbit add pulls in a repo whose memo is thin or missing, it prints a one-shot stderr naming the explore.paths scope — explore and write a memo before done. The same state resurfaces automatically via per-repo status (bare orbit context, the session-start block) and at orbit done.
Mark workspace as done:
orbit done # Mark done (no PR also OK)
orbit done --pr https://github.com/org/backend/pull/42 # Mark done and record PR
orbit done --pr https://github.com/org/frontend/pull/43 # Can append multiple PRsRunning orbit done --pr <url> again on an already-done workspace appends the PR (done-at updates to current time).
orbit done prints non-blocking per-repo stderr warnings before completing: leftover jots (pop + merge), a thin memo with no capture (explore + write), or an over-budget card (curate once). It still marks the workspace done — the warnings just flag knowledge that would be lost on the next prune.
Reclaim completed workspaces:
orbit prune # Clean all status=done
orbit prune --older 30d # Only clean those done more than 30 days ago
orbit prune task-01 # Clean a specific workspace
orbit prune --dry-run # Preview
orbit prune --force # Skip validation (accept the loss)Note: non-force
pruneis all-or-nothing per workspace: it either reclaims the workspace completely — directory, worktrees, branches, config — or touches nothing at all. Any blocker (uncommitted changes, a foreign repo, unmerged jots, a damaged worktree, an unmerged branch) holds the whole workspace, with every reason reported at once. Resolve what the report names and re-run — or accept the loss with--force. A workspace staying around is the design working, not prune failing: the report is what drives the cleanup. Use--dry-runfirst to preview.
prunemust be run from the project root — it refuses the invocation when any process in the invoking shell's ancestry is rooted inside a workspace (detected via process ancestry, not CWD, socd-ing out first does not bypass it). If only your own CWD is inside a workspace and the ancestry check can run and comes back clean, it replays the exact command to run from the root.If the workspace recorded PR URLs (
orbit done --pr), prune checks them withghautomatically — per branch, never wholesale — and falls back to git's own merged check with one warning whenghis unavailable. A merged PR only clears the branch it actually covers, and only when no unpushed local commits would be lost. Squash and rebase merges need neitherghnor a recorded PR: a branch whose content is already in the default branch is proven by tree comparison (git merge-tree) and deleted like any merged branch.Beyond workspace directories,
prunealso reclaims residue left by force-deleted workspace directories (an agent'srm -rf, a crash): scoped branches whose workspace is already gone are cleaned per branch (merged deleted, unmerged reported), and untraceable raw branches (no remote copy, no workspace) are reported with review/delete commands for you to dispose of by hand. A run with kept content ends in a closing block: one confirm-useless caveat, then the force-delete suggestions (orbit prune <ws> --forcefor scoped, nativebranch -Dfor raw). Interruption is safe at any point — directory removal goes through an atomic rename into.prune-trash/, so the next run simply resumes; the only case non-force will refuse to resume is a worktree half-removed by a failed deletion (it reads as uncommitted work — review, then--force).Two things worth knowing before you reach for
--force. Deletion lines name the commit they removed (deleted branch (force): <branch> (was abc1234)) — that SHA is the recovery handle:git branch <name> abc1234recreates the ref while the objects survive. Prune deletes refs, never objects; unreachable objects live untilgit gccollects them (gc.pruneExpire, two weeks by default — the deleted branch's own reflog goes with it, so don't count on the longer reflog window). Discarding uncommitted work is the one step with no recovery path at all, so--forcesays so before it acts. And prune does not protect everything:.gitignored files, hand-written notes at the workspace top level, and commits left on a detached HEAD have no guard — seedocs/spec-lifecycle.md→ Out of Scope.
--forcedoes not overridedone. A workspace is reclaimable only once you have marked it done, and no flag substitutes for that — it is the one thing only you can decide. If a workspace's.orbitfile was lost, prune stops mentioning it entirely; runorbit doneinside it again to restore the marker.
ORBIT_ROOT=<project-root> # Explicitly specify project rootThe scoped-mode branch prefix is project config — orbit config branch.prefix <prefix> (default ws). It is baked into every branch orbit creates and is what prune matches on to find them again, so it has to stay stable across sessions. Changing it is refused while any branch still carries the current prefix (moving it would orphan those branches). See docs/spec-worktree.md → The Prefix.
Codex runs with a filesystem sandbox that restricts writes to the workspace
root and a few system directories. Orbit manages its pool repos under
.repos/ outside the workspace root, so commands that write into the pool
(orbit add, orbit memo, orbit sync, orbit done, git operations in
worktrees, etc.) are blocked by the sandbox and require escalation.
The sandbox is a security boundary. Keep .repos/ outside the writable roots
so the agent never sees it as an accessible path. When an orbit command or git
operation fails with a sandbox permission error, retry with
sandbox_permissions: "require_escalated" and include a prefix_rule so the
user can persist the approval:
| Prefix rule | Covers |
|---|---|
["orbit"] |
All orbit subcommands |
["git", "checkout"] |
Branch creation in worktrees |
["git", "switch"] |
Branch switch/create in worktrees (incl. orbit switch fallback) |
["git", "commit"] |
Commits in worktrees |
["git", "add"] |
Staging changes in worktrees |
["git", "push"] |
Pushing worktree branches |
Suggest persisting these rules on first use. Subsequent sessions reuse the
stored approvals without additional prompts. Note the scope: a git prefix
rule like ["git", "commit"] approves that subcommand in any path, not
only orbit worktrees. That is intended here — worktree writes land in the pool
outside the workspace — but the user should approve it knowing the breadth.
This is a convenience workaround, not the primary path. The recommended flow above (escalate on demand, persist the prefix rules once) already makes subsequent sessions frictionless. Reach for this only if you dislike being reminded of the escalation steps each session.
Copy the block below into an AGENTS.md at the orbit project root (the
directory that holds .repos/). Codex auto-loads it on startup, so the agent
knows the escalation steps from its first message — no per-session reminder.
# Orbit workspace
## Sandbox escalation for orbit commands
Orbit commands (add, memo, sync, done, etc.) and git operations inside orbit
worktrees write git metadata under `.repos/` — the pool repo infrastructure
outside the workspace sandbox. These writes are blocked by the sandbox.
**Do NOT add `.repos/` to `writable_roots`.** The agent must not see `.repos/`
as a writable path in its system prompt — that would expose the directory and
risk the agent working directly in the pool instead of through orbit worktrees.
When an orbit command or git operation in an orbit worktree fails with a sandbox
permission error, retry with `sandbox_permissions: "require_escalated"` and
include a `prefix_rule` so the user can persist the approval:
- `["orbit"]` — all orbit subcommands
- `["git", "checkout"]` — branch creation in worktrees
- `["git", "switch"]` — branch switch/create in worktrees (incl. `orbit switch` fallback)
- `["git", "commit"]` — commits in worktrees
- `["git", "add"]` — staging changes in worktrees
- `["git", "push"]` — pushing worktree branches
Suggest persisting these rules on first use so subsequent sessions are frictionless.You can skip per-command escalation by adding .repos/ to the sandbox
writable roots, but this is not recommended:
-
One-off:
codex --add-dir /path/to/pool/.repos start -
Persistent: add to
~/.codex/config.toml:[projects."/path/to/workspace"] trust_level = "trusted" writable_roots = ["/path/to/pool/.repos"]
Why not: writable_roots are injected into the agent's system prompt. The
agent then knows .repos/ exists and is writable, which risks it working
directly in the pool instead of through orbit worktrees — undermining orbit's
isolation guarantees. Use only if you understand and accept this tradeoff.
Some commands support --json for script/agent parsing:
orbit status --json # Workspace status
orbit repos --json # Repos list (includes memoBehind field)
orbit info backend --json # Repo details
orbit done --json # Mark done and output JSON
orbit context --json # Cruise block (per-repo status, no memos)
orbit context path # Single key query (workspace/path/goal/state)
orbit jot backend --pop --json # Pop jot entries as JSONorbit repos --json includes a "memoBehind": N field per record, indicating how many commits behind the current HEAD the memo was written at (0 = up to date).
orbit context is the model-facing context command — its stdout is a readable markdown block:
orbit context --startup # Session-start block: cold start → pool roster; populated → memos + per-repo status
orbit context # Cruise block: durables + conditional per-repo status (no memos)
orbit context path # Single key: workspace directory absolute path
orbit context workspace # Single key: workspace name
orbit context goal # Single key: workspace goal
orbit context state # Single key: active / done--startup is what the session hooks inject (agent plugins wrap it in <orbit-context> tags); it doubles as workspace detection — it fails fast outside a workspace. The bare form is the cruise block — the in-session recovery view for compaction/resume: cheap durables plus one status line per repo that has pending jots, is behind upstream, or has a thin/over-budget memo. Full memos are pulled on demand via orbit info <repo>.
Workspace scope best practice: keep workspaces task-scoped (small — on the order of 1~6 worktrees). The startup block injects every worktree's memo, which stays cheap only at that scale. A workspace holding dozens of repos is a scope signal, not something to cap with truncation: split it (create a new task-scoped workspace and orbit prune the old one).
Must be executed within a workspace (workspace inferred from CWD).
Check whether the current environment meets orbit's runtime requirements:
orbit doctorChecks:
- git version (≥ 2.20; bootstrapping the first commit of an empty repo needs ≥ 2.42, since
orbit addusesgit worktree add --orphan) - bash version (≥ 3.2)
- Optional tools (jq, gh)
- Process-ancestry facility (
/procon Linux,lsofon macOS) — prune's initiation guard is best-effort and needs one of them; without either it warns, the guard is inactive, and a misplaced cwd gets no cd replay - Project structure (
.repos/existence, repo count, workspace count)
orbit doctor can be executed from anywhere; being inside an orbit project is not required. It also prints the orbit runtime version, which you can query on its own with orbit version (aliases: --version, -v).
orbit has built-in completion script generation:
orbit completion zsh # Output zsh completion script
orbit completion bash # Output bash completion scriptinstall.sh --zsh / --bash automatically calls the above commands, writing completion to the shell's search path. Open a new shell to use orbit <Tab>.
For manual installation (without depending on install.sh):
# zsh (place in a directory within fpath)
orbit completion zsh > /path/to/fpath/_orbit
# bash (place in bash-completion search path)
orbit completion bash > /path/to/bash-completion/completions/orbitAn orbit session runs read-only and idempotent subcommands (context / repos / info / status, plus workspace-writes like add / memo / jot) constantly, so per-command confirmation prompts add up. Those framework-verified tiers can run without a prompt; destructive or externally-visible commands (prune clone config) always keep prompting. Workflow-timing commands (done new) are deliberately outside the framework's list — orbit takes no position on when they should run; allowlist them in your own agent settings if you want them prompt-less.
Plugin users — nothing to do: all four plugins ship an auto-approve hook that approves exactly the framework-verified subcommands and fails safe. The hook needs jq on PATH; without it the hook stays inert and you keep the native prompts. The dependency goes away in a future release. Skill-only / other agents: add a static allowlist to your agent settings.
The exact command tiers, the ready-to-paste allowlist snippet, and the rationale for each tier all live in skills/CONSTRAINTS.md.
Auto-approve cuts confirmation friction; it is not a security boundary — the hook can only allow, never deny. Non-matching commands fall back to the agent's native permission flow, which orbit neither controls nor sees.
# Repo management
orbit clone <url> [--push <fork-url>] [--name <identity>] [--branch <branch>]
orbit repos
orbit info <repo>
orbit memo [<repo>] [--refresh|--scaffold]
orbit sync [repo...] [--force] [--branch <branch>] # --force / --branch: project root only
# Workspace lifecycle
orbit new "<goal>" [--name <name>] [--no-goal] [--exec "<cmd>"]
orbit add <repo> [--ref <tag/branch>] [-s|--silent]
orbit switch [repo] <name>
orbit switch -c [repo] <name>
orbit jot [<repo>] ["<text>"]
orbit jot [<repo>] --pop [--json]
orbit done [--pr <url>...] [--json]
# Cross-workspace cleanup (from project root only)
orbit prune [workspace] [--older <dur>] [--dry-run] [--force]
# Status and context
orbit status [workspace]
orbit goal ["text" / --clear]
orbit context [<key>] [--startup|--prime|--reignite] [--json] # key: workspace, path, goal, state; bare = cruise block; --startup = session-start block
# Configuration
orbit config [<key> [<value> | --unset]]
# Diagnostics
orbit doctor
orbit version
# Completion
orbit completion <zsh|bash>