Status: v0.1.0 (initial implementation)
Audience: contributors, integrators writing manifests/tooling around orbito
Companion docs: README.md for user-facing quickstart
orbito is a command-line tool for managing workspaces made of many git
repositories, described by a single manifest file. It exists to do the
job of Google's repo and
Fuchsia's jiri — clone/sync dozens
or hundreds of repositories into a coherent local tree, driven by version
control rather than manual scripting — but as a single static Rust binary
with a manifest format designed to be read and diffed by humans.
Projects that span many repositories (an OS distribution, an SDK with
vendored dependencies, a monorepo-that-isn't) need a way to answer: what
repos make up this product, at what revisions, and how do I get a working
checkout of all of them? repo and jiri both solve this with an XML
manifest and a sync tool. orbito solves the same problem with:
- a TOML manifest (structured, comments, no XML tooling required),
- a single native binary (no Python interpreter, no Go runtime bootstrap),
- parallel sync using OS threads,
- a small, auditable command surface (7 subcommands, no plugin system).
- Code-review integration (
repo upload/ Gerrit push). ThereviewURL is parsed and surfaced (§4.2) but no upload command exists yet. - Manifest snapshotting/freezing to exact commits (
repo manifest -r). - A merge/rebase-across-projects workflow beyond what
forallgives for free by shelling out. - Non-git version control (Mercurial, Perforce, etc.) — git only.
- A plugin/extension system. New behavior means new Rust code.
These are explicitly deferred, not rejected; see §9 (Roadmap).
- Shell out to git, don't reimplement it.
orbitohas zero VCS logic of its own — every git operation is a call to the systemgitbinary (§6). This means credential helpers, SSH config,.gitconfig, corporate proxy setups, and git version quirks all behave exactly as the user already expects them to, for free. - The manifest is the source of truth, and it's just data. No
Turing-complete manifest language, no templating, no conditionals.
TOML in, a flat list of resolved
Projectstructs out. This keeps manifests diffable and reviewable in a PR the same wayCargo.lockorpackage.jsonare. - Fail loud, fail specific. Every fallible operation carries
anyhow::Contextnaming what was being attempted (which project, which file, which URL) so a sync failure across 200 projects doesn't require re-running with-vto find out which one broke. - No dependency you can't explain in one sentence.
clapfor CLI parsing,serde/tomlfor the manifest,anyhow/thiserrorfor errors,coloredfor output,walkdirfor filesystem walks. HTTP fetch shells out tocurl(§6.4) rather than pulling in a TLS stack, for the same reason git operations shell out togit. - Portable by construction. Linux release binaries link against musl (no glibc-version coupling); Windows binaries are native MSVC. Every release target builds on hardware matching its own architecture (§8) rather than cross-compiling, trading a little CI complexity for binaries nobody has to second-guess.
src/
├── main.rs entry point: parse CLI, dispatch, print top-level errors
├── cli.rs clap Parser/Subcommand definitions (the CLI surface, §5)
├── manifest.rs manifest data model + TOML parsing + import resolution (§4)
├── workspace.rs .orbito/ directory layout, config load/save, discovery (§7)
├── git.rs thin wrapper around the system `git` binary (§6.1–6.3)
├── http.rs thin wrapper around `curl`, for URL-based imports (§6.4)
└── commands/
├── mod.rs re-exports
├── init.rs `orbito init`
├── sync.rs `orbito sync` (parallel clone/fetch/checkout)
├── status.rs `orbito status`
├── list.rs `orbito list`
├── forall.rs `orbito forall`
├── branch.rs `orbito branch`
└── manifest_cmd.rs `orbito manifest`
┌─────────────────┐
│ manifest repo │ (a git repo, cloned into
│ (git, remote) │ .orbito/manifest-repo/)
└────────┬─────────┘
│ contains manifest.toml (+ maybe [[import]]s)
▼
┌─────────────────┐
│ Manifest::load │ recursive: follows [[import]]
│ (manifest.rs) │ entries, local + URL-based (§4.3)
└────────┬─────────┘
│ produces
▼
┌─────────────────┐
│ Vec<Project> │ flat, deduplicated by local path,
│ (fully resolved) │ sorted — the one true in-memory
└────────┬─────────┘ representation every command reads
│
┌──────────────┼──────────────┬───────────────┬─────────────┐
▼ ▼ ▼ ▼ ▼
sync status list forall branch
(clone/fetch/ (git status (print table (run shell (git checkout
checkout, -j per project) or TOML) cmd per -b per
parallel) project) project)
Every command re-runs Manifest::load from scratch — there is no cached,
serialized "resolved manifest" on disk. This is a deliberate simplicity
trade-off (§10.2): resolution is cheap (local file reads + a handful of
git/curl calls for imports) relative to the sync operations that follow
it, so caching would add state-invalidation complexity for negligible
speedup.
All fallible internal APIs return anyhow::Result<T>. Context is attached
at each layer boundary via .with_context(|| ...) so error chains read
top-down as a breadcrumb trail, e.g.:
error: resolving manifest at .orbito/manifest-repo/manifest.toml
Caused by:
0: importing manifest from https://raw.githubusercontent.com/org/x/main/extra.toml
1: fetching manifest from https://raw.githubusercontent.com/org/x/main/extra.toml
2: curl failed fetching '...' (exit 22):
curl: (22) The requested URL returned error: 404
main.rs is the single place that formats a top-level error ({:#} for
the full chain) and sets the process exit code; no other module calls
std::process::exit.
A manifest is a UTF-8 TOML document. orbito does not require a specific
filename (the workspace config records which file to read, default
manifest.toml) or that it live at the repo root — -m in orbito init
takes any path within the manifest repo.
Manifest := RemoteTable* DefaultTable? ProjectTable* ImportTable*
[[remote]] (RemoteTable, 0 or more)
name : string required, unique among remotes in this file
fetch : string required, base URL; project name is joined onto it
review : string optional, Gerrit-style code-review URL (§10.1)
[default] (DefaultTable, 0 or 1)
remote : string optional, fallback for project.remote
revision : string optional, fallback for project.revision
(if entirely absent, revision falls back to "main")
[[project]] (ProjectTable, 0 or more)
name : string required; also the path segment joined onto
remote.fetch to form the clone URL
path : string optional, local checkout path; defaults to `name`
remote : string optional, must name a [[remote]]; falls back to
default.remote; error if neither is set
revision : string optional; falls back to default.revision, then "main"
hooks : array<string> optional, default []; shell commands run once,
immediately after first clone (§4.5)
pinned : bool optional, default false; if true, `sync` never
moves this project off its current HEAD (§4.6)
[[import]] (ImportTable, 0 or more)
manifest : string optional (see resolution table below)
url : string optional (see resolution table below)
revision : string optional, default "main"; only meaningful
when url is a git repo (i.e. manifest is also set)
At least one of import.manifest / import.url must be set; an import
with neither is a parse-time error (bail! in resolve_import).
[[import]] has three forms, distinguished by which of manifest/url
are present:
manifest |
url |
Meaning |
|---|---|---|
| set | absent | Local/relative import. Resolved relative to the importing manifest: if that manifest came from disk, join as a filesystem path; if it came from a URL, join as a URL path segment (http::join, §6.4). |
| set | set | Git-hosted import. url is a git remote; orbito clones it (or fetches+checks out revision if already cloned) into .orbito/imports/<slug>/, then reads manifest as a path inside that checkout. Enables nested imports within that repo, resolved relative to it. |
| absent | set | Direct file import. url points straight at a manifest file, fetched over HTTP(S) via curl and parsed as-is — no git, no local cache. Re-fetched on every orbito sync / orbito manifest / etc. |
Import resolution is implemented as a Source enum internal to
manifest.rs:
enum Source {
File(PathBuf), // a manifest file that exists on disk
Url(String), // a manifest file fetched over HTTP(S)
}Manifest::load_into recurses on Source, so an HTTP-fetched manifest can
itself declare further imports (of any of the three forms above) and they
resolve correctly relative to where that manifest came from, not where
the top-level manifest started. There is no depth limit; a cyclic import
graph will recurse until the process runs out of stack (see §9, "known
limitations" — cycle detection is not yet implemented).
Cache directory naming (git-hosted imports only): the clone directory
name is slug(url), computed as: keep [a-zA-Z0-9._-], replace everything
else with _, truncate to 60 characters, then append -<16 hex digit hash>
(std::hash::DefaultHasher over the full URL) so two URLs that sanitize to
the same prefix never collide.
Every [[project]] across the top-level manifest and all its imports is
resolved independently (name/path/remote/revision/hooks/pinned, with
defaults applied per-file — a project's default.revision comes from
its own manifest file, not the top-level one) and inserted into a
HashMap<PathBuf, Project> keyed by local checkout path. This means:
- Two projects that resolve to the same
pathare not both kept — the later one (in file-then-import-order, depth-first) silently overwrites the earlier one. This mirrors how imports are meant to be used ("override a vendored project's revision") but means naming collisions fail silently rather than erroring. See §9. - The final
Manifest.projectslist is sorted by path, so command output (orbito list,orbito status, ...) is stable and deterministic regardless of import order.
project.hooks is a list of shell command strings (sh -c "<hook>"), run
once, immediately after that project's first clone, in the project's
own directory, in list order. Hooks do not re-run on subsequent
orbito sync calls for an already-cloned project. A failing hook
(non-zero exit) aborts that project's sync with an error; it does not roll
back the clone.
⚠️ Hooks execute arbitrary shell commands from the manifest with no sandboxing. See §10.3 (Security considerations) — a manifest is as trusted as aMakefileyou'd run, not as trusted as data.
project.pinned = true means orbito sync will clone it once (if not
present) but will never fetch/checkout/move it thereafter — it's the
escape hatch for "I have local changes here and don't want them clobbered"
or "this dependency is intentionally frozen." orbito status still reports
its dirty/clean state normally; only sync's mutation is suppressed.
[[remote]]
name = "origin"
fetch = "https://github.com/my-org"
review = "https://gerrit.my-org.com"
[default]
remote = "origin"
revision = "main"
[[project]]
name = "platform/core"
path = "core"
[[project]]
name = "platform/tools/build"
path = "tools/build"
revision = "release/stable"
hooks = ["./tools/build/bootstrap.sh"]
[[project]]
name = "vendor/thirdparty-lib"
path = "third_party/lib"
pinned = true
[[import]]
url = "https://github.com/my-org/other-manifests"
manifest = "extra.toml"
revision = "main"Resolves (assuming extra.toml is empty) to:
| name | path | remote_url | revision | pinned |
|---|---|---|---|---|
platform/core |
core |
https://github.com/my-org/platform/core |
main |
false |
platform/tools/build |
tools/build |
https://github.com/my-org/platform/tools/build |
release/stable |
false |
vendor/thirdparty-lib |
third_party/lib |
https://github.com/my-org/vendor/thirdparty-lib |
main |
true |
All commands except init require a workspace: they call
Workspace::discover(), which walks up from the current directory looking
for .orbito/, the same way git looks for .git. Every command that
resolves the manifest passes Workspace::imports_cache_dir(&ws.root)
(.orbito/imports/) as the import cache.
Clones <manifest-url> (git) into .orbito/manifest-repo/, checking out
<branch> (default main). Writes .orbito/config.toml:
manifest_url = "<manifest-url>"
manifest_file = "<file>" # default "manifest.toml"
branch = "<branch>" # default "main"Idempotent: if .orbito/manifest-repo/ already exists, init skips the
clone (prints a note) but still (re)writes the config — this lets you
re-point manifest_file/branch without re-cloning. Does not run
sync; that's a separate, explicit step.
git fetch+ checkout the manifest repo to its tracked branch (always; not parallelized, there's only one).- Unless
--manifest-only: resolve the manifest (§4), then sync every project,<n>at a time (default 4; see §5.1 for the concurrency model).
Per-project outcome (clone / update / pinned-skip / error) is printed as
it completes, not in project-list order — interleaving across workers is
expected and each line is self-contained (project name always included).
A per-project failure is reported and does not stop other workers'
projects (sync is best-effort across the whole set); the process still
exits non-zero if any project failed... (implementation note: currently
sync_projects prints ✗ lines but does not propagate a non-zero exit
code for individual project failures — see §9, this is a known gap
relative to forall, which does propagate.)
sync_projects statically partitions the project list round-robin across
jobs OS threads (std::thread::scope), not a work-stealing pool:
project[i] goes to worker[i % jobs]. Each worker processes its slice
strictly sequentially and sends (name, Result<String>) back over an
mpsc::channel; the main thread drains the channel and prints as results
arrive. This means:
- Total wall time is bounded by the slowest worker's total, not the
slowest single project — an unlucky round-robin split (e.g. one
worker getting all the large repos) is possible with very uneven
project sizes and small
jobscounts. - Output ordering is nondeterministic (arrival order), which is intentional — it reflects real progress rather than manifest order.
For each resolved project: not-checked-out / not-a-git-repo / clean /
dirty, plus current branch name (git rev-parse --abbrev-ref HEAD) and,
if dirty, a count of changed paths (git status --short line count).
Purely read-only — makes no git calls that mutate state. Prints a trailing
note if any project is dirty.
Default: an aligned table (NAME, REMOTE, REVISION) sized to the
longest project name, plus a trailing count. --toml: re-emits each
project as a standalone [[project]] block (name/path/remote/revision) —
useful for piping into other tools, though note this is a simplified
re-serialization (no remote/import structure, no hooks/pinned/review),
not a round-trippable manifest.
Runs sh -c "<command>" in every currently checked-out project
directory (silently skips projects whose path doesn't exist yet — run
sync first), sequentially, in resolved-manifest order. Exposes
ORBITO_PROJECT_NAME and ORBITO_PROJECT_PATH as environment variables to
the command. Without -p/--keep-going, stops at the first failing
project (non-zero exit) and returns an error immediately; with -p, runs
every project regardless and reports the total failure count at the end,
still exiting non-zero if any failed.
For every currently checked-out project: git checkout -b <name>. Prints
✓/✗ per project and continues past individual failures (e.g. branch
already exists in one project). Like sync (§5, exit-code note), branch
always returns success at the process level regardless of how many
per-project checkouts failed — the ✗ lines are the only failure signal.
This is the same gap noted in §9, not an intentional difference from
sync; forall is currently the only command that reflects per-project
failure in its own exit code.
Prints the fully-resolved manifest (post-import, post-default-resolution)
as a sequence of [[project]] blocks with name, path, remote_url
(the fully joined clone URL, not just the remote name), remote_review
(only if the remote declared one), revision, and pinned. This is the
"what will sync actually do" view — the closest thing to repo manifest
or jiri resolve — useful for debugging import resolution and reviewing
what a manifest change will actually check out before running it.
orbito has two "escape hatches" to the outside world, both implemented
as thin wrappers that shell out rather than link a library, on the
philosophy that CLI-tool behavior should match what's already installed
and configured on the machine.
git::run(dir: Option<&Path>, args: &[&str]) -> Result<GitOutput> spawns
git <args> with current_dir set if given, captures stdout/stderr, and
turns a non-zero exit into an anyhow error embedding stderr (or stdout
if stderr was empty). Every other function in the module is a thin,
named wrapper over run:
| Function | git invocation |
|---|---|
is_repo(dir) |
(no git call) — checks dir/.git exists |
clone(url, dest, revision) |
git clone --origin origin --branch <revision> <url> <dest> |
fetch(dir, remote) |
git fetch <remote> --prune --tags |
checkout_revision(dir, remote, rev) |
tries git rev-parse --verify <remote>/<rev>; if that resolves, git checkout -B <rev> <remote>/<rev> (branch case); else git checkout --detach <rev> (tag/commit case) |
current_branch(dir) |
git rev-parse --abbrev-ref HEAD |
head_commit(dir) |
git rev-parse --short HEAD |
status_short(dir) |
git status --short |
create_branch(dir, name) |
git checkout -b <name> |
clone_or_update(url, dest, rev) |
is_repo ? fetch + checkout_revision : clone |
checkout_revision's branch-vs-tag/commit branching means: if <remote>/<revision>
exists as a remote-tracking ref, orbito treats revision as a branch
and creates/resets a local branch of that name tracking it (so
git log, git push etc. behave normally for a developer working in that
checkout). Otherwise it's treated as a tag or raw commit SHA and
checked out detached. There is no manifest-level way to force one
interpretation over the other — it's inferred from what's fetchable.
clone always names the remote origin and always passes --branch. This
means tags and raw commit SHAs cannot be the initial clone revision —
git clone --branch <tag-or-sha> fails for arbitrary non-branch refs on
many git versions/hosts. A manifest that pins a fresh (never-before-cloned)
project to a tag or SHA will fail on first sync. This is a known gap; see
§9.
http::get(url) -> Result<String> shells out to curl -fsSL <url> and
returns stdout as a UTF-8 string, erroring (with stderr embedded) on
non-2xx/network failure. http::join(base_url, relative) does naive
"drop everything after the last / in base_url, append relative"
resolution (or returns relative unchanged if it's already absolute) —
deliberately not a full RFC 3986 URL resolver, since manifest import paths
are simple filenames/subpaths in practice, not ..-laden relative
references.
<workspace root>/
├── .orbito/
│ ├── config.toml manifest_url, manifest_file, branch
│ ├── manifest-repo/ full git checkout of the manifest repo
│ │ └── <manifest_file> (e.g. manifest.toml)
│ └── imports/ cache for git-hosted [[import]] entries
│ └── <slug(url)>-<hash>/ one clone per distinct imported repo URL
├── <project.path>/ one directory per resolved project
│ └── ... (a normal git checkout, origin = project's remote)
└── ...
Workspace::discover() walks up from cwd looking for .orbito/
(analogous to git's .git walk), so any command can be run from within a
project subdirectory, not just the workspace root.
On every push/PR to main: cargo build --locked + cargo test --locked
on ubuntu-latest and windows-latest (required checks). A separate
fmt/clippy job runs cargo fmt --all -- --check and
cargo clippy --all-targets --all-features -- -D warnings with
continue-on-error: true — informational, not blocking, on the theory
that lint failures shouldn't gate a PR the same way a broken build does,
but should still be visible.
Triggered by a tag push matching v*.*.* or manual workflow_dispatch.
Builds four portable, self-contained archives, each on a GitHub-hosted
runner matching its own target architecture — no Docker, no
cross-compilation toolchain:
| Target | Runner | Toolchain |
|---|---|---|
x86_64-pc-windows-msvc |
windows-latest |
native MSVC |
aarch64-pc-windows-msvc |
windows-11-arm |
native MSVC |
x86_64-unknown-linux-musl |
ubuntu-latest |
musl-tools (apt) |
aarch64-unknown-linux-musl |
ubuntu-24.04-arm |
musl-tools (apt) |
Each archive (orbito-<version>-<platform>.zip/.tar.gz) bundles the
binary, README.md, LICENSE-MIT, LICENSE-APACHE, and
examples/manifest.toml, plus a .sha256 checksum file. A final release
job downloads all four artifact sets, concatenates the checksums into
SHA256SUMS.txt, and publishes everything to a GitHub Release via
softprops/action-gh-release with auto-generated release notes.
windows-11-arm and ubuntu-24.04-arm are GitHub's newer Arm-native
hosted runner labels; if unavailable on a given plan/repo visibility, the
fallback is cross-targeting aarch64-pc-windows-msvc from windows-latest
(works out of the box, MSVC ships ARM64 libs) and building
aarch64-unknown-linux-musl via the Docker-based
cross tool from ubuntu-latest.
These are things the current implementation does not handle, called out explicitly rather than left implicit:
- No import-cycle detection. A manifest that (transitively) imports itself will recurse until stack overflow, not a clean error.
- Silent path collisions. Two projects resolving to the same local
path(whether within one manifest or across an import) silently overwrite rather than erroring — see §4.4. - Tags/commits can't be a first-clone revision —
clone()always passes--branch <revision>, which only works for actual branches on first clone (see §6.3). Re-syncing an existing checkout to a tag/SHA works fine viacheckout_revision's fallback path. syncandbranch's per-project failures don't set a non-zero process exit. Both print✗per failing project but always returnOk(())at the command level.forall, by contrast, does propagate failures into its own exit code (immediately by default, or as a summarized count with--keep-going). Bringingsync/branchin line withforallhere is tracked as a v0.2 fix.- Hooks and
forallcommands run with no sandboxing and inherit the user's full shell environment and permissions — see §10.3. - No
--dry-runonsync.orbito manifestis the closest substitute (shows what would be synced) but doesn't diff against current on-disk state. - HTTP imports have no integrity pinning (no checksum/signature
field in the
[[import]] url = "..."form) — anyone who can serve that URL controls what gets merged into your manifest on every sync. See §10.3.
| Concept | repo (Google) |
jiri (Fuchsia) |
orbito |
|---|---|---|---|
| Manifest format | XML | XML | TOML |
| Manifest hosting | separate git repo (.repo/manifests.git) |
separate git repo | separate git repo (.orbito/manifest-repo/) |
| Multi-manifest composition | <include> |
imports | [[import]] — local, git-URL, or direct-HTTP-URL (§4.3) |
| Parallel sync | yes (-j) |
yes (-j) |
yes (-j, round-robin threads, §5.1) |
| Pinned/local projects | repo forall/manual |
[projects] ... exclude |
project.pinned |
| Per-project hooks | repo-hooks (separate mechanism) | manifest hooks element |
project.hooks, run once on first clone |
| Code review upload | repo upload (Gerrit) |
jiri upload |
not implemented — remote.review is parsed & surfaced only |
| Cross-project shell command | repo forall |
n/a | orbito forall |
| Cross-project branch | repo start |
n/a | orbito branch |
| Runtime dependency | Python | Go (compiled) | none (static Rust binary) |
- No cached/serialized resolved manifest (§3.2): simplicity over micro-optimized re-run speed. Revisit if import chains grow deep enough (many git-hosted imports) that resolution itself becomes slow.
- Round-robin static partitioning over work-stealing for
sync(§5.1): arayon/work-stealing pool would balance uneven project sizes better, at the cost of a dependency and more complex progress reporting. Deferred until real-world manifests show this mattering. - Shelling out to
git/curloverlibgit2/an HTTP crate: slower process-spawn overhead per operation, in exchange for zero behavioral drift from the user's actual installed tools (§2, principle 1) and a much smaller dependency tree to audit and compile.
orbito executes code and fetches remote content on behalf of a manifest
file that, in the general case, arrived from someone else's git repo.
Treat a manifest with the same trust level as a Makefile or justfile
you'd cd into and run, not as inert configuration data:
project.hooksandorbito forall/orbito branchall invokesh -c "<string from manifest or CLI>"with no sandboxing, seccomp, or restricted environment — full shell, full user permissions.[[import]] url = "..."(both the direct-HTTP and git-hosted forms) means a manifest can pull in further manifests — and therefore further projects, further hooks — from anywhere the author points it, including atsynctime on every run (direct-HTTP imports are re-fetched, not cached). There is currently no checksum/signature pinning on imports (§9) — integrity relies entirely on TLS + trusting the URL's owner.orbito init/orbito syncwill happily clone fromfile://URLs (used throughout this document's examples and the test suite) — fine for local testing, but notefile://manifest/import URLs on a shared machine mean "trust whatever's on disk," not just "trust the network."
Recommendation for consumers: review a manifest (and its import graph)
the same way you'd review a build script before running it, especially
before running sync for the first time against a manifest you didn't
author.
There is no automated test suite yet (cargo test currently runs zero
tests — src/main.rs's implicit unit test harness is empty). Verification
to date has been manual/integration-style against locally-created git
repos and a local HTTP server, covering:
init→sync→status→forall→branchend-to-end against multiple localfile://project repos.- Re-
synccorrectly fast-forwards an already-cloned project. - All three
[[import]]forms (local-relative, git-hosted URL, direct HTTP URL) in combination within one manifest, including a nested local-relative import inside a fetched manifest. remote.review→Project.remote_review→ printed byorbito manifestend-to-end.
This is tracked as a gap: §9-style edge cases (path collisions, tag/SHA first-clone, import cycles) do not have regression tests and are verified only by code inspection. Adding an integration-test harness that spins up throwaway local git repos (as the manual verification above did by hand) is the natural next step — see §12.
Roughly in order of "next":
- Fix
sync/branchexit-code inconsistency (§9) — propagate per-project failure into the process exit code, matchingforall. - Integration test harness (§11) — turn the manual verification
flows above into
#[test]s using throwaway local git repos. - Import cycle detection (§9) — track the in-progress
Sourcestack inload_intoand error clearly instead of stack-overflowing. - Fix tag/SHA first-clone (§6.3) —
clone()should attempt--branch <revision>and fall back toclone+checkout_revisionon failure, rather than assumingrevisionis always a branch. orbito manifest --freeze— emit a manifest with every project'srevisionrewritten to its exact current commit SHA, theorbitoanalogue ofrepo manifest -r— for reproducible "what exactly did CI build" snapshots.- Path-collision detection (§4.4) — error (or at least warn) instead
of silently overwriting when two resolved projects share a
path. orbito upload(§1.2, §10.1) — the Gerrit-style review-upload commandremote.reviewis already threaded through for.- Integrity pinning for URL-based imports (§10.3) — an optional
sha256 = "..."field on[[import]]to pin direct-HTTP imports, at minimum.
- Manifest — the TOML file describing remotes, defaults, projects, and imports (§4).
- Manifest repo — the git repository that hosts the manifest file;
cloned into
.orbito/manifest-repo/byorbito init. - Project — one entry in the resolved project list; corresponds to exactly one local git checkout under the workspace root.
- Remote — a named base URL (
[[remote]]) that project names are joined onto to form a clone URL. - Import — a directive (
[[import]]) that merges another manifest's projects into the current resolution (§4.3). - Workspace — the directory tree rooted at the
.orbito/you get fromorbito init; discovered by walking up fromcwd(§7). - Pinned project — a project
orbito syncwill clone but never subsequently move (§4.6).
| Path | Purpose |
|---|---|
Cargo.toml / Cargo.lock |
crate manifest; lockfile committed for reproducible builds |
src/*.rs |
implementation (§3.1) |
examples/manifest.toml |
a documented example manifest, also bundled into release archives |
README.md |
user-facing quickstart, command table, install/push instructions |
DESIGN.md |
this document |
LICENSE-MIT / LICENSE-APACHE |
dual license, matching Cargo.toml's license field |
.github/workflows/ci.yml |
build/test/lint on every push/PR (§8.1) |
.github/workflows/release.yml |
tag-triggered multi-platform release builds (§8.2) |