Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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, go for Desire Path, cargo for 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/bin is 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.toml and .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_64macOS arm64macOS x86_64Linux arm64
caboodlereleasereleasereleasebuild with cargo install --git
quipureleasereleasereleaserelease
camayocsource archivesource archivesource archivesource archive
bobbinreleasereleasereleaserelease
yupanareleasereleasereleasebuild with cargo
desire-pathbuilt with Gobuilt with Gobuilt with Gobuilt 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.