Installing and removing Tambo
Tambo is the renamed Caboodle installer. For the transition release, both
tambo and caboodle are available. Existing caboodle-plan.toml and
.caboodle state paths remain compatible; no install-state move is required.
The canonical archive is tambo-vVERSION-TARGET.tar.gz; a compatibility archive
named caboodle-vVERSION-TARGET.tar.gz carries the same two commands for legacy
self-update clients. Both have filename-bound SHA-256 checksum files.
The planned managed Linux and macOS cutover uses apt and Homebrew to update
both commands as a package after the first official Tambo release. The Homebrew
formula rename will migrate caboodle to tambo; the Linux transitional
caboodle package will depend on tambo. The checksummed release
installer remains the standalone fallback. A standalone self-update of a
dual-command installation verifies and updates both commands together, restoring
both prior files and state if either installed read-back fails.
Caboodle publishes a release only when a vVERSION tag exactly matches the
version in Cargo.toml. Each supported archive has a sibling .sha256 file;
the installer verifies that checksum before replacing the binary.
Caboodle’s built-in HTTPS asset downloads make at most three attempts. Server errors (HTTP 5xx) and transient resolution, connection, timeout, partial-transfer, send/receive or HTTP/2 stream errors are retried after one and then two seconds. Each attempt has a 10-second connection timeout and a 120-second transfer limit. Retry logs identify the URL, attempt, curl status, HTTP status and delay; recovery logs name the successful attempt. Failed attempts use disposable files. HTTP 4xx (including missing assets), certificate and local file errors fail immediately. Checksum verification happens after downloading and is never retried or bypassed. This policy covers downloads made by the Caboodle binary, not the bootstrap shell installer above it or external package managers.
Homebrew member updates
For a Mac plan with stack formulas, tambo update refreshes Homebrew metadata
once before checking members. An unpinned formula follows the tap’s current
stable version, even when the installed version is already ahead of Tambo’s
embedded minimum release. A newer installed version is never downgraded.
brew pin scbrown/tap/bobbin holds that formula; the updater reports the hold
and never unpins it. Use brew unpin scbrown/tap/bobbin when you intend to resume
stable updates.
A failed metadata refresh, unreadable channel, failed upgrade, or version
read-back mismatch is an error. After an upgrade, the formula receipt must reach
stable and agree with the executable, and functional verification must pass.
The release fallback still requires the embedded reviewed minimum when no stack
formula is available. check-updates continues to report drift from those
embedded release pins; it does not refresh package metadata.
Release install
Run the checksummed release installer in one line:
curl -fsSL https://raw.githubusercontent.com/scbrown/caboodle/main/scripts/install.sh | bash
Pin a release by setting the version on the receiving shell:
curl -fsSL https://raw.githubusercontent.com/scbrown/caboodle/main/scripts/install.sh | CABOODLE_VERSION=vX.Y.Z bash
The script still verifies the release archive’s SHA256 checksum before replacing
the binary. Read the installer source
when inspecting the bootstrap. After installation, caboodle --version reads
back the installed release.
The compatibility repository URL remains the bootstrap default through the
rename. The installer prefers a tambo- archive with both commands. Only an
HTTP 404 selects the historical caboodle- archive, which may contain just
caboodle; pinned releases such as v0.2.23 therefore remain installable.
Checksum, server and transport failures stop installation without trying an
alternative archive.
Supported release targets are Linux x86_64, macOS x86_64, and macOS arm64.
The default destination is ${CARGO_HOME:-$HOME/.cargo}/bin/caboodle; override
it with CABOODLE_INSTALL_DIR when that directory is managed elsewhere.
caboodle --version prints the release version and the commit it was built
from, for example caboodle 0.2.3 (1a2b3c4d5e6f). Two builds of one release
can then be told apart. The installer warns when a different caboodle comes
earlier on PATH than the one it just installed, and caboodle doctor warns when
PATH runs a different build from the one you invoked. Remove the stale copy or
reorder PATH.
Source install
A Rust toolchain can install the reviewed revision directly:
cargo install --git https://github.com/scbrown/caboodle \
--rev <reviewed-commit-sha> --locked
caboodle --version
Preflight
caboodle doctor reports what would stop an install on this host and changes
nothing. With a plan in the current directory it checks that plan; without one
it checks every tool in the everything profile. It exits nonzero when any line
is a FAIL:
- the install directory (
$CARGO_HOME/bin, default~/.cargo/bin) is not on PATH, so installed tools could not be read back; - a command an install or verification step shells out to is missing (
curl,tar,git,bash,python3,sha256sum,gofor Desire Path,cargofor the lancedb Quipu flavor); - a selected tool is not installed and has no reviewed release for this platform (for example, Yupana on Linux arm64), with the source build to run instead.
It warns, without failing, when a tool differs from the reviewed version, when
several copies of a tool are on PATH (the first one runs), and when a Quipu
server is already live at QUIPU_SERVER. Camayoc verification uses its own
temporary server and never loads the ontology into that existing server.
First proof and resume
The interview writes a plan and changes nothing else. Read the complete file before applying it:
caboodle init --guided
less caboodle-plan.toml
caboodle install
caboodle verify-questions
If input or an install is interrupted, rerun the same command. Interview
answers resume from .caboodle/interview.toml; install state resumes from
.caboodle/state.json. A green result means version read-back and functional
reader-path checks passed, not merely that an installer exited zero.
If a tool cannot install or pass version read-back, apply and install
continue attempting the remaining tools, save each success, and exit nonzero
with all tool failures. Any saved proof for a failed tool is cleared. Stack
configuration, model provisioning, crew setup, share imports and functional
verification wait until every selected tool applies successfully. Fix the
reported gaps, then rerun the same command; already-current tools are reused.
State-write and evidence-queue failures still stop immediately.
Two plan-level choices extend what the box installs, both documented with
their proofs in Profiles: --quipu-flavor lancedb builds the
reviewed Quipu revision with the lancedb feature compiled in (proven by the
server’s GET /version per-feature compile map), and
--embedding-model <spec.toml> provisions checksum-pinned embedding-model
artifacts (a mismatched download is deleted and fails the step; verify
re-hashes the artifacts on disk).
Registering MCP servers
Caboodle owns binary installation, version convergence, and functional proof. Shantytown owns harness registration: it projects the MCP/skill manifest from Quipu into the workspaces named by the rig’s crew cards. Installing binaries alone does not register servers.
After a green install, on a configured Shantytown rig:
caboodle project-settings --root /path/to/.shanty
# Optional: select one crew member or read identities directly from Quipu.
caboodle project-settings --root /path/to/.shanty --agent ada --registry quipu
This delegates to st --root /path/to/.shanty ops provision --json. It reads the
rig’s existing crew, even when the installation plan has no crew profile, and
requires the configured Quipu tooling manifest (SHANTY_TOOLING_MANIFEST).
Server names, transports, and secret references come from that manifest; Caboodle
does not maintain another server list. A rig whose manifest names yupana, bobbin,
forgejo, and homelab registers all four. A missing crew reports
“no crew on this rig yet - run st fleet init / st agent new first”. Missing
manifest, credentials, or failed read-back refuses registration. This needs a
Shantytown version exposing st ops provision; upgrade st if it rejects the command.
No agents are launched or restarted. Existing sessions need their next normal
start to load the new registration.
--policy-only retains the old plan-based policy-summary export to
caboodle-settings/ (--plan and --output customize it). Those summaries do
not register MCP servers. Normal registration does not read the install plan.
For a standalone harness, or until the adapter is available, register explicitly. For Claude Code, substitute your deployment’s reviewed HTTP MCP endpoints:
claude mcp add bobbin -- "$(command -v bobbin)" serve "$PWD"
claude mcp add yupana -- "$(command -v yupana)" serve
claude mcp add --transport http forgejo https://forgejo-mcp.example.com/mcp
claude mcp add --transport http homelab https://homelab-mcp.example.com/mcp
claude mcp list
Homelab MCP exposes the quipu_* tools; it is a separately operated proxy, not
installed by Caboodle. Use your deployment’s authentication procedure without
putting credentials in the plan. Bobbin’s knowledge tools are not a replacement
for Homelab’s Quipu tools. HTTP endpoints above are placeholders, not public
services. For Codex, use the rig adapter to emit its harness-specific settings.
Claude Code cloud environments
scripts/setup-environment.sh is the version-controlled copy of the setup
script for a Claude Code cloud environment. Paste its body into the Setup
script field (claude.ai/code → the cloud icon above the message box →
Add/edit environment) — the field takes a script, not a path, and it runs
before the repo is available, which is why the file exists to be pasted from
rather than executed.
It bootstraps quipu (checksummed prebuilt quipu and quipu-server release
binaries), caboodle itself (prebuilt release binary via scripts/install.sh),
the shared tooling the stack’s quality gates need (just, bd,
pre-commit, mdbook, mdbook-mermaid, cffi), and stages the stack
knowledge packs into ~/.caboodle/packs/, verified with
quipu pack --verify — a pack that fails verification is deleted rather
than trusted. It deliberately does not build the rest of the corpus:
that is caboodle’s own job, and a session that needs the full stack runs
caboodle install against a reviewed plan so every tool is proved rather
than assumed.
Set CABOODLE_ALLOW_SOURCE_FALLBACK=1 only when the Quipu release artifact is
unavailable and the environment has enough time and memory for a Rust build.
The normal setup path never compiles Quipu from source.
Owned Quipu installs provide qp as a relative link to quipu. Both command
names execute the same CLI; quipu remains supported. Apply repairs a missing
alias on a current pair without reinstalling or downgrading that pair. Existing
conflicting qp files in the destination or on PATH cause refusal. Verification
checks the link, executable identity and matching version output without creating
files. --skip-install requires the alias to be present already.
An externally owned Quipu must provide its own command alias; Caboodle verifies
it but does not create it. A paired release update retains the alias across a
CLI replacement or rollback because the link follows the canonical quipu path.
Hosts that only ever run update-self (such as a scheduled installer consumer)
never run apply, so update-self also heals the alias. After a verified swap it
runs the newly installed binary once to repair the owned directory
($CARGO_HOME/bin, default ~/.cargo/bin). That pass creates a missing qp, or
re-points a qp symlink with the wrong or a dangling target. A regular file or
directory named qp is foreign: it is reported and left in place. A failed
repair is reported but never fails the update. Because the old binary performs
the swap, the first release carrying this behaviour repairs on the update after
it.
Stack knowledge packs
packs/ carries quipu knowledge packs for working with the stack:
stack-map/pendant/— what each tool is, where it lives, and how the pieces relate.stack-operations/pendant/— how each repo builds, tests, and proves itself, and the git discipline that binds them.
A pendant is the artifact once called a qpack (named for the khipu’s pendant
cords, each a self-contained record hanging from the primary cord). The old
Each directory contains manifest.json, manifest.ttl, canonical export.nt
and shapes.ttl. SQLite databases are scratch build inputs, not repository
artifacts. The former .pendant.db and .qpack.db paths remain symlinks to
these directories, so directory-based imports can retain their old paths.
They are directory aliases, not binary SQLite packs. Use quipu import,
not quipu unpack or quipu pack --verify, for these new artifacts. Previously
published binary packs retain their original binary consumer commands.
Alias removal is separate from this conversion and is not scheduled before
the release after the announced 0.14 deprecation.
quipu import packs/stack-map/pendant --db scratch.db
quipu import packs/stack-operations/pendant --db scratch.db
Import verifies the bundle’s hashes and stages or quarantines its graph; it
does not promote it automatically. These shares intentionally contain no
domain shapes or stored queries. An empty receiver quarantines stack-map
because https://caboodle.dev/ns#StackComponent is outside its local vocabulary.
Configure reviewed receiver shapes for that class before expecting admission.
Hash integrity alone is not vocabulary, shape or producer certification.
The Turtle sources in packs/src/ remain the review surface.
scripts/build-stack-packs.sh rebuilds and verifies both bundles before
replacing output; a failed build or native verification preserves existing
bundles. Rebuild by hand when sources change: creation time and source identity
can change manifests without changing the semantic graph. Python 3 and Quipu
with text-share support are required. PACKS_OUTPUT_DIR selects an isolated
output root for experiments; python3 scripts/test-stack-pendants.py exercises
native integrity, quarantine, tamper refusal and failure preservation.
Shipping a pack from a repository
Each repository can publish its graph beside its release binaries as a Quipu
share. A .pendant.tar.gz release asset is a deterministic archive of the same
text bundle, not a SQLite database:
quipu share --graph https://example.org/knowledge/repository/example \
--db .bobbin/quipu/quipu.db --out repository-share
tar --sort=name --mtime=@0 --owner=0 --group=0 --numeric-owner \
-czf repository.pendant.tar.gz -C repository-share .
Publish the archive as an immutable release asset. A clone points Quipu at the asset; Quipu fetches bounded bytes, verifies the manifest and payload, and opens a fresh in-memory store without a local download step:
quipu import \
https://github.com/scbrown/quipu/releases/download/quipu-ai-v0.11.1/quipu-quipu-ai-v0.11.1-repository.qpack.tar.gz
Releases still publish the asset as *-repository.qpack.tar.gz (checked on
quipu-ai-v0.11.1). The pendant rename has not shipped yet; when it does, the
asset becomes *-repository.pendant.tar.gz.
For a modified graph, quipu share --since <parent-share> --out <delta-dir>
writes a parent-bound SPARQL 1.1 Update delta. Import rejects a wrong parent,
changed update bytes, unrestricted operations, or a mismatched result digest.
Bobbin’s .bbpack index remains a separate binary release artifact.
Uninstall
Remove only the Caboodle binary and optional local Caboodle state. Installed corpus tools are intentionally left in place because they may be shared with other workflows:
rm "${CARGO_HOME:-$HOME/.cargo}/bin/caboodle"
# Optional, from the directory where Caboodle was run:
rm -r .caboodle
Reviewed-pin drift
caboodle check-updates proposes an update only when the installed version is
older than the reviewed pin. A newer version is reported as ahead of the pin;
an unparseable or same-version identity mismatch is reported as version drift.
These reports remain nonzero because the installation differs from the review.
caboodle update refuses a reviewed-pin downgrade before replacing the tool.
There is no --allow-downgrade escape: a deliberate rollback requires a separately
reviewed installation, rather than a normal stack update.
Replacing a cargo-installed Bobbin
If apply refuses to replace an existing Bobbin executable, it preserves your
installation. To switch a regular-file Cargo install to the reviewed release,
first stop any automatic updates and choose a backup that does not already exist.
The following works on macOS and Linux and uses $CARGO_HOME/bin when configured.
It creates a hard-link backup beside the executable, retaining its bytes and
permissions, before removing the original directory entry. It refuses symlinks,
directories, and an existing backup (including a dangling symlink). It does not
change Cargo’s install metadata or uninstall the crate.
python3 - <<'PYTHON'
import os
from pathlib import Path
import stat
binary = Path(os.environ.get("CARGO_HOME", str(Path.home() / ".cargo"))) / "bin/bobbin"
backup = binary.with_name("bobbin.before-tambo")
if not stat.S_ISREG(binary.lstat().st_mode):
raise SystemExit(f"Expected a regular file; preserved {binary}")
os.link(binary, backup, follow_symlinks=False) # fails if backup already exists
binary.unlink()
print(f"Saved {backup}; rerun apply with your existing plan and state")
PYTHON
caboodle apply --plan caboodle-plan.toml --state .caboodle/state.json
caboodle verify --plan caboodle-plan.toml --state .caboodle/state.json
Keep bobbin.before-tambo until verification succeeds. If either command fails,
stop and inspect the failure. To restore, remove only the managed Bobbin symlink
created by this attempt, if present, then run the following. It refuses an
occupied destination and leaves the backup in place:
python3 - <<'PYTHON'
import os
from pathlib import Path
import stat
binary = Path(os.environ.get("CARGO_HOME", str(Path.home() / ".cargo"))) / "bin/bobbin"
backup = binary.with_name("bobbin.before-tambo")
if not stat.S_ISREG(backup.lstat().st_mode):
raise SystemExit(f"Expected a regular backup; preserved {backup}")
os.link(backup, binary, follow_symlinks=False) # never overwrites a destination
print(f"Restored {binary}; backup retained at {backup}")
PYTHON
This procedure deliberately replaces the selected Bobbin version with the plan’s
reviewed release. Compare bobbin --version with the planned version first; keep
a newer Cargo install if you do not intend to switch. Do not use cargo uninstall
after switching: Cargo still records its previous install and may remove the new
entry. For a symlink or a package-manager-owned executable, use its owner’s repair
procedure instead of the regular-file steps above.
Opt-in published binary updates
After the initial install and plan review, track published stable releases for a selected binary without waiting for this Caboodle build’s reviewed pins to change:
caboodle update-release --tool bobbin --check
caboodle update-release --tool bobbin
caboodle update-release --tool yupana
caboodle update-release --tool desire-path
This path currently supports Linux x86_64. The tool must already be installed on
PATH and selected in the retained plan. --plan and --state select the existing
files; the command never starts a new interview or changes the selected profile.
Each invocation changes one tool, not the whole stack. Quipu server/CLI source
convergence, Camayoc source bundles, and crew runtime updates retain their own
contracts and are not silently included.
The updater resolves GitHub’s latest published stable release, requires the named binary archive and checksum asset, checks the downloaded SHA256 and executable’s version, then atomically replaces the PATH entry. Symlink targets are not written through. It retains the previous bytes, runs the existing adapter’s functional verification, and only then records the new version as verified. Failed proof restores the backup. An interrupted update leaves a journal; the next invocation restores its previous artifact before doing anything else, including during a hold.
A numerically newer installed version is preserved. Equal versions with different
binary bytes are ambiguous (for example a source build ahead of its release) and
are refused. Unreadable versions, missing assets and wrong checksums are errors,
never evidence of a current install. The older reviewed-pin update path also
refuses to replace a newer installed binary or an ambiguous equal-version build.
For initial or missing installations, use apply first.
Create ~/.caboodle/hold to defer new release lookup and installation, or set
CABOODLE_HOLD_FILE to a shared host hold path. The updater uses an OS-held lock
beside the state file to serialize release updates; backups are retained under
release-backups/<binary>/<sha256> in the same directory. A host scheduler must
bound total runtime and retain stdout/stderr. This command does not itself install
a timer or claim that another host or a long-running process has updated.
caboodle update-self applies the same release, checksum, downgrade, backup and
interruption-recovery controls to Caboodle itself. Its post-install contract
requires the new binary’s version and update-release --help to answer correctly.
Self-update supports Linux x86_64, macOS x86_64, and macOS arm64, selecting the
matching published archive and its .sha256 asset. Other platforms refuse before
release lookup. The extracted executable is written as a new file rather than
restoring archive metadata, so archive extended attributes are not installed.
Event consumers can select an exact stable release with update-self --tag v0.2.14.
To bind the download to evidence obtained before installation, also supply
--archive-sha256 and --binary-sha256. Both values must be lowercase SHA256
digests; both flags require the exact tag and each other. CABOODLE compares the
archive before extraction and the executable before running it or replacing the
installed copy. A mismatch leaves the previous installer and state intact.
Use update-self --check to inspect metadata; it does not download artifacts or
prove either supplied hash. Bootstrap from a published release
before scheduling this command; a same-version source build with different bytes
is deliberately refused rather than silently overwritten. It replaces the copy
PATH runs; when you invoke a different copy by its full path, it says that copy
was not changed.
Installed files
- Binaries in
~/.cargo/bin(or$CARGO_HOME/bin). Keep that directory on your PATH, ahead of any other directory that holds an older copy of the same tool (~/.local/binis the usual one). The shell runs the first copy it finds. - Unpacked releases under
~/.local/share/caboodle/. - One setting,
[quipu.owl] reactive_materialize = true, merged into~/.config/bobbin/config.toml. Other settings in that file are kept. - In the directory you ran it from:
caboodle-plan.tomland.caboodle/(interview, state, queued install records).
Every verification check uses a throwaway directory, camayoc’s included. The camayoc
check starts its own quipu-server on a free localhost port with a temporary store,
loads camayoc’s vocabulary and one marker node into it, and stops it afterwards. It
never touches the server at QUIPU_SERVER. To set camayoc up against your real quipu
server, run the bundle’s bootstrap yourself as a separate step:
QUIPU_SERVER=<your server> bash ~/.local/share/caboodle/camayoc/<revision>/scripts/bootstrap.sh.
To remove caboodle, delete ~/.cargo/bin/caboodle and the .caboodle/
directory. Installed tools stay, because other workflows may use them. The
install guide covers release pins, source
installs, and updates.
Platform prerequisites
Platforms. Linux x86_64 needs no Rust toolchain: each tool comes from a
checksummed release or source archive, and Go builds desire-path. On other
platforms, availability depends on the tool as shown below; caboodle doctor
prints the exact source-build command where no reviewed release exists.
| Linux x86_64 | macOS arm64 | macOS x86_64 | Linux arm64 | |
|---|---|---|---|---|
| caboodle | release | release | release | build with cargo install --git |
| quipu | release | release | release | release |
| camayoc | source archive | source archive | source archive | source archive |
| bobbin | release | release | release | release |
| yupana | release | release | release | build with cargo |
| desire-path | built with Go | built with Go | built with Go | built with Go |
Commands on PATH. curl, tar, git, bash, python3, and sha256sum
(brew install coreutils supplies sha256sum on macOS). Yupana verifies its
three pinned v0.12.7 archives in-process and needs only curl and tar for installation. The everything
profile also needs Go 1.22+. Rust is only needed for the source builds above.
Accounts and servers. None. Nothing talks to a private network, and no
token is needed to install. A token (QUIPU_AUTH_TOKEN) matters only when you
send install records to a remote quipu with flush-episodes.
Seeds successful-update rollback
rollback-seeds restores only the prior Seeds artifact retained by the last
successful update-release --tool seeds. It requires the same selected plan,
state file, executable path and exact current/prior SHA256 values:
caboodle rollback-seeds --plan crew.toml --state state.json \
--current-sha256 <installed-sha256> --prior-sha256 <retained-prior-sha256>
The successful update records a Seeds receipt bound to the plan, state bytes, paths, versions and both artifact hashes. Missing receipts, changed state, wrong hashes, corrupt backups, symlinks, held updates and lock contention refuse before replacing Seeds. A hold is any directory entry, including a dangling symlink. Unknown hold-path configuration or metadata errors block execution; only a definitely absent entry permits it. Other tools retain their state. A successful rollback runs the existing isolated functional verifier and consumes the receipt. A failed rollback verifier restores the current artifact and retains the state. An interrupted rollback uses normal release journal recovery, restoring the current artifact and invalidating only Seeds verification; it must earn fresh proof before a later operation. This is not a general downgrade override.
Legacy updates without this receipt do not qualify. A private implementation or test does not authorize publication or adoption; follow the applicable review and deployment contract before using it on an installed tool.
Maintainers can verify an embedded Rust release member before publishing a pin:
caboodle verify-member seeds
This stages the archive pinned by that Caboodle checkout, checks its digest,
identity and version, and runs the manifest’s functional steps in temporary
roots. It does not install a managed program. The caboodle-verify CI job runs
this command against the PR checkout; Seeds pin automation requires that exact
check to complete successfully, alongside the rest of CI.