Skip to content

Installation ​

There are three ways to install Ship of Tools. GitHub Releases ship prebuilt artifacts for Linux x86_64, Windows x86_64 and macOS aarch64, so the default path is from release artifacts.

  • Agent-driven — start a Claude Code or Codex session on the target machine and tell it:

    text
    Install Ship of Tools: fetch https://raw.githubusercontent.com/kalidke/ship-of-tools/main/docs/INSTALL-AGENT.md and follow it.

    The agent checks the machine, confirms the release assets match the platform, falls back to the source path when they do not, and checks that the result answers before it reports success. The runbook it follows is docs/INSTALL-AGENT.md in this repo.

  • From release artifacts — prebuilt binaries via the install.sh installer. No Rust toolchain is needed.

  • From source — clone, build the Rust workspace, instantiate the Julia environments. This is the path for developing Ship of Tools; Per-machine setup adds the config and launcher checklist.

From release artifacts (Linux/macOS) ​

scripts/install.sh downloads a GitHub Release, verifies its checksums, and sets everything up under ~/.local/share/sot by default:

bash
curl -fsSL https://raw.githubusercontent.com/kalidke/ship-of-tools/main/scripts/install.sh | bash -s -- --local

The script fetched from main only resolves the latest release and runs that release's own install.sh, so what gets installed is always a tagged release.

With no role flag and an interactive terminal, the installer asks which role this machine should play. In curl | bash or other non-interactive runs, pass the role explicitly:

FlagRole
--localall-in-one: frontend and backend on this machine
--backend <ssh-alias>frontend here, backend on a remote host over SSH; the flag names where the backend lives
--be-onlyheadless backend only (servers)

Plus --version vX.Y.Z to pin a release (default: latest), --prefix <dir> to relocate the install, --no-service on backend roles when something else supervises sotd, --hub <ssh-alias> to copy the hub's ~/.config/sot/hosts.toml to this machine first (for a machine that does not share the hub's home directory), and --force-role-change (see the next section).

If ~/.config/sot/hosts.toml already names this host, that entry decides which parts are installed and enabled here, and a role flag on the command line is ignored.

A home directory shared by several Linux hosts shows them all the same sotd.service and the same boot start. The installer pins the unit with sotd topology pin: a drop-in, sotd.service.d/topology.conf, under which systemd starts it only on the hosts hosts.toml declares daemon or frontend, so on a shared home that file must list every host. With no hosts.toml the pin names the host that ran the install, and only that host starts the daemon. The pin compares the kernel hostname, so a host that SOT_SELF_HOST renames is not matched. An install or update rewrites the pin from hosts.toml (an update with no hosts.toml leaves it as the install wrote it), and so do the hub's daemon at each start and sotd topology apply there; a host whose entry changed reads it at its next boot or systemctl --user daemon-reload. The unit has no [Install] section: a drop-in, default.target.d/sotd.conf (Wants=sotd.service), starts it at boot, and the pin above picks the hosts. So systemctl --user enable and disable change no file for sotd.service, on any host, and a hand-typed one on one host cannot turn boot start off for the others. Stop the daemon on a host now with systemctl --user stop sotd.service. What it does at the next boot is what the pin and hosts.toml decide: to move it, change hosts.toml (or, with none, run sotd topology pin --dir ~/.config/systemd/user --claim on the host that should run it). On a home no other host shares, turn boot start off with rm -f ~/.config/systemd/user/default.target.d/sotd.conf; write that file again ([Unit] and Wants=sotd.service) to turn it back on. One rule governs both ways to update, running the installer again and the background update: a run that finds no sotd.service wires boot start, and a run over a unit moves an old enable link onto the drop-in or keeps the drop-in, and with neither writes nothing, so boot start you turned off stays off; an install.sh run says in a line before its verdict whether boot start is on, and when off, the command that turns it on. An install that runs no daemon on this host only stops this host's, and moves an old link onto the drop-in, unless the pin names this host alone: then it also removes the drop-in. The relay sockets and tunnels keep their rule: never disable them by hand.

The install itself is shared the same way: one ~/.local/share/sot and one install.json serve every host that runs sotd. Run the installer on one of those hosts. On a host hosts.toml leaves out or lists with neither key, the installer refuses to write over an install already there, whatever role its flags ask for; on a host that does run sotd, it refuses --no-service over an install whose record names the systemd unit. Either refusal comes before it writes anything under ~/.local/share/sot or ~/.local/bin. The remedy for the first is to declare the host in hosts.toml (frontend for a machine that runs a window) and re-run; a machine with a home of its own is declared in the hub's hosts.toml and re-runs with --hub <hub alias>, which fetches it. The remedy for the second is to drop --no-service. --force-role-change overrides either refusal, for a machine whose own role changed.

Every machine that runs a window also runs its own private local daemon, so an entry with frontend = true alone installs one as --local does. daemon = true means other machines dial that daemon through the hub; the installer never adds this machine to anyone's dial list. The one exception is --backend <ssh-alias>, an explicit choice of a remote backend, which installs no local daemon.

The checkout under the prefix is part of the installed product: a git clone --filter=blob:none of the selected tag, so history is available but only that tag's files are downloaded. The runtime resources and the in-app manual resolve from it. For roles that run a backend on this machine (--local and --be-only), the installer instantiates the Julia environments inside the checkout (julia/kernel, julia/repl, julia/pluto). --backend <ssh-alias> is a frontend-only install and uses Julia locally only to install the agent skills; install the remote machine as a backend role. Julia runs the installer's comm step on every role, which is why it is needed here too; the skills it installs load only in a session Ship of Tools starts on this machine.

Connection behaviour is role-specific:

  • --local runs frontend and backend on one machine over the backend user's per-user socket. There is no SSH-to-localhost requirement.

  • --backend <ssh-alias> writes a launcher that passes --dial <host>=ssh:<host> to the frontend, which reaches the remote user's per-user backend socket by spawning its own ssh child — no forward.

  • --be-only installs the headless backend and, unless --no-service, runs it as the systemd --user unit sotd.service.

Re-running on a machine that already has an install ​

A re-run is an upgrade. The installer refuses to overwrite files that belong to another install: the sotd.service unit, the sot-launch wrapper, the desktop entry and the macOS app. If one of these already exists under a different prefix (a source checkout, another --prefix, an earlier trial install), the installer stops before writing anything and names the file and its owner. --force-role-change overrides that. A file whose owner cannot be determined (an unrecognized sot-launch shape) is refused with no override; move it aside and re-run.

What the installer changes ​

Everything below is written under your home directory, with one exception: on Linux backend roles the installer runs loginctl enable-linger for your user, a systemd setting kept outside your home (it continues without it if that call is refused). Nothing needs root. The default prefix is ~/.local/share/sot (--prefix moves it). There is no uninstall script; Uninstall lists the commands to remove each item by hand.

Roles: all is every install; backend is --local and --be-only; frontend is --local and --backend.

PathWhat
~/.local/share/sot/bin/all · sot (frontend), sotd (backend daemon), sot-capsule (session supervisor), sot-apply (update applier)
~/.local/share/sot/repo/all · the release checkout, one directory per version under repo/versions/ (the current and previous one are kept); repo/current links to the installed one
~/.local/share/sot/julia/currentall · a link to the same checkout
~/.local/share/sot/updates/all · staging area for downloaded updates
~/.local/share/sot/install.jsonall · install manifest: prefix, version, and which parts (daemon, frontend) were installed
~/.config/sot/settings.tomlall · a one-line stub, written only if missing
~/.config/sot/hosts.tomlall · written only with --hub, as a copy fetched from the hub; otherwise only read
~/.juliaup/all · Julia 1.12, installed with the juliaup installer, only if no Julia 1.12 or newer is on PATH (an existing juliaup gets the 1.12 channel added instead)
the first depot in DEPOT_PATH (usually ~/.julia)backend · packages for the kernel, REPL and Pluto environments
~/.config/systemd/user/sotd.servicebackend, Linux, unless --no-service · the backend service, started (its boot start is the drop-in below); loginctl enable-linger is also run so it survives logout. The service sources ~/.bashrc before it starts sotd, so the backend and its sessions inherit your shell profile's exports.
~/.config/systemd/user/default.target.d/sotd.confbackend, Linux, unless --no-service · the boot drop-in (Wants=sotd.service) that starts the backend service at boot; written on a fresh install and kept or moved from an old enable link on a later one
~/.local/bin/sot-launchfrontend · the launcher wrapper
~/.local/share/applications/ship-of-tools.desktopfrontend, Linux · the desktop entry
~/.local/share/icons/hicolor/frontend, Linux · the icon, 256x256/apps/ship-of-tools.png
~/Applications/Ship of Tools.appfrontend, macOS · app bundle

The installer then runs ShipTools.update_comm() from the checkout, which installs the agent integration:

PathWhat
~/.sot-comm/the session messaging scripts (bin/) and their runtime state
~/.local/bin/ccb (Claude Code launcher), ccx (Codex launcher), sot-fe, show-result, sot-gh-auth
~/.claude/skills/the four onboarding skills, which you run before any row exists: sot-install, sot-setup, sot-statusline-setup, sot-gh-auth (each named account reaches the folder by the daemon's link)
~/.sot-comm/claude-layer/the other Claude Code skills (under .claude/skills/): julia-repl, show-result, sot-comm, sot-session-start, sot-status, sitrep, worktree, project-log, reauth. A session Ship of Tools starts (a row or ccb) adds this folder to itself and carries the work-state hooks in its own launch settings; a plain claude loads none of it
~/.claude/settings.json, ~/.claude-auth/<name>/settings.jsontwo hook entries, merged in without removing yours: Stop (the end-of-turn mail check) and PreToolUse on Bash (the subagent mail guard), each calling a script under ~/.sot-comm/bin. The work-state hooks an earlier release merged in are removed, but only a command that is exactly one that release wrote; every other hook, a compound command of yours included, stays. A link is followed and its target written once; an account folder with no settings.json is skipped
~/.codex/skills/the Codex skills sot-comm and sot-session-start
~/.codex/AGENTS.mdthe repo's AGENTS.md, installed when none is there and replaced only while the installed file holds "Codex sessions in Ship of Tools"; any other file there is left alone and a warning says to merge by hand
~/.agents/plugins/sot-comm/, ~/.agents/plugins/marketplace.jsonthe Codex work-state hook plugin; written whether or not Codex is installed, and registered with codex plugin add sot-comm@sot-local when it is

~/.claude and ~/.codex follow CLAUDE_CONFIG_DIR and CODEX_HOME when those are set; ~/.sot-comm follows SOT_COMM_HOME. The other paths do not move: ~/.local/bin, ~/.agents/plugins, ~/.claude-auth and everything in the first table are always written in your home directory. The install ends by naming every Claude settings file it could not bring up to date, with the reason (a file made read-only, one that could not be read or parsed). Setting those three variables is therefore not an isolated try-out; for that, install under a separate user account or in a virtual machine.

Apart from the four onboarding skills, the Claude skills and the work-state hooks exist only in a session Ship of Tools starts: a row, or ccb. That session adds ~/.sot-comm/claude-layer to itself (--add-dir) and carries the hooks in its own launch settings, so a claude you start yourself in a terminal loads none of them, and neither your skills folder nor your settings.json holds a skill or a work-state hook. An install removes the skills an earlier release put in a Claude skills folder (~/.claude, $CLAUDE_CONFIG_DIR, each ~/.claude-auth/<name>) only where the folder is byte for byte a version this repository shipped, and says so about any other folder of the same name, which stays; a skills folder that is a link is never touched. The two mail hooks remain in your settings and do nothing in a session that has not joined the Ship of Tools session registry; SOT_COMM_HOOKS=off turns the Claude Code hooks off entirely.

Nothing the installer writes for Claude lands in a folder of yours any more, so no skill of yours is overwritten. The Codex skills are still written into ~/.codex/skills: a skill directory there with the same name as one of them is overwritten, each shipped file replacing the file of the same name and any other file in that directory deleted, with no backup.

The installer itself edits no shell profile. If no Julia 1.12 or newer is found and juliaup is not installed, it runs the juliaup installer, which adds its PATH block to your shell startup files; juliaup self uninstall removes it.

How agent sessions are launched ​

Sessions you create in the window start their agent with these permission settings:

  • Claude Code: claude --permission-mode auto.

  • Codex: codex --dangerously-bypass-approvals-and-sandbox --dangerously-bypass-hook-trust, through the ccx launcher, which also marks the session's directory as trusted in ~/.codex/config.toml.

Claude Code's auto mode is not a bypass. It runs without routine permission prompts, but a separate classifier model reviews each action before it runs and blocks anything that goes beyond your request, targets infrastructure it does not recognise, or looks driven by hostile content; your own ask rules still prompt. See Claude Code's permission modes. Codex has no equivalent reviewed mode here: its flags turn approvals and the sandbox off.

These flags are fixed: no setting or environment variable changes them. The Claude Code flags are built into the daemon, and the Codex flags are in the ccx script, which every update overwrites. Ship of Tools adds no permission layer of its own on top. A claude or codex you start yourself, outside Ship of Tools, uses whatever flags you give it. See Agent sessions.

Uninstall ​

There is no uninstall script. To remove an install made with the default prefix, stop the service and delete what the installer wrote. On a home several hosts share these steps delete the shared install, so they uninstall every host:

bash
systemctl --user stop sotd.service
rm -rf ~/.config/systemd/user/sotd.service ~/.config/systemd/user/sotd.service.d \
      ~/.config/systemd/user/default.target.d/sotd.conf ~/.config/systemd/user/default.target.wants/sotd.service
systemctl --user daemon-reload
loginctl disable-linger "$USER"   # skip if something else needs linger
rm -rf ~/.local/share/sot ~/.config/sot ~/.sot-comm
rm -f ~/.local/bin/sot-launch ~/.local/bin/ccb ~/.local/bin/ccx ~/.local/bin/sot-fe \
      ~/.local/bin/show-result ~/.local/bin/sot-gh-auth
rm -f ~/.local/share/applications/ship-of-tools.desktop \
      ~/.local/share/icons/hicolor/256x256/apps/ship-of-tools.png
rm -rf ~/.codex/skills/{sot-comm,sot-session-start}
rm -rf ~/.agents/plugins/sot-comm

These commands use the default locations. If CLAUDE_CONFIG_DIR, CODEX_HOME or SOT_COMM_HOME is set, use those directories instead of ~/.claude, ~/.codex and ~/.sot-comm. Deleting ~/.config/sot also deletes your hosts.toml and any settings you edited; keep a copy if you want them.

Then, by hand:

  • if an earlier release was installed here and this one never was, remove the skills it put in ~/.claude/skills (the names in the table above);

  • remove the hook entries that call ~/.sot-comm/bin/comm-*.sh from ~/.claude/settings.json (even when CLAUDE_CONFIG_DIR is set), from $CLAUDE_CONFIG_DIR/settings.json when it is set, and from each ~/.claude-auth/<name>/settings.json; where one of these is a link, edit the file it points to, once;

  • if Codex is installed, remove the sot-comm@sot-local plugin (it is listed by codex plugin list);

  • remove the sot-local entry from ~/.agents/plugins/marketplace.json, or delete the file if nothing else is listed in it;

  • remove the [projects."<dir>"] blocks with trust_level = "trusted" that ccx appended to ~/.codex/config.toml, one per directory a Codex session ran in;

  • delete ~/.codex/AGENTS.md if the installer created it;

  • on macOS, delete ~/Applications/Ship of Tools.app;

  • ~/.juliaup and the Julia depot are ordinary Julia installs; keep them or remove them with juliaup (juliaup self uninstall also removes the PATH block it added to your shell startup files).

Sessions also keep runtime state under ~/.local/state (or $XDG_STATE_HOME); see Sessions and persistence.

Updating ​

Re-running the install command is also the updater. The built-in update check, pinning a version, and rolling back are in Updating and rollback.

  • A run that names a version or archive pins the install and turns automatic updates off. Run the installer again with no version or archive to remove the pin and follow the channel again.

  • Restart every open Ship of Tools window after an update, on every computer that shows one.

  • A computer declared as a frontend also runs its own local daemon; this is expected even when it shows rows on other computers. An explicit --backend <alias> install is the exception and runs no local daemon.

  • sotd is installed in $PREFIX/bin: ~/.local/share/sot/bin by default on Linux and macOS, or %LOCALAPPDATA%\sot\bin on Windows (where it is sotd.exe).

Requirements ​

Platforms ​

  • Linux x86_64: all roles.

  • Windows: frontend only, against a Linux backend.

  • macOS (Apple Silicon): experimental; the tested use is a frontend against a Linux backend (--backend) — the other roles install but agent sessions on a Mac backend are not supported yet. No agent session has run end to end on a Mac; the only rows a test starts there are the pane-timing job's plain shells; the successor and controlled-outcome cases are not built for macOS (the tests that a session outlives a restart of its daemon, and that the daemon's own ends, a close, an update restart or a stop signal, end its processes as designed).

  • linux-x86_64 or macos-aarch64 release artifacts (a windows-x86_64 zip also ships for the Windows frontend path below).

  • git, curl, tar and jq. The comm scripts read and write JSON with jq, so the installer stops without it and names the command that installs it (sudo apt-get install jq, or brew install jq on macOS).

  • A coding agent (Claude Code or Codex), installed and logged in on every machine that runs sessions. The installer does not install one.

  • Julia 1.12 or newer. The installer installs it with juliaup when missing; an existing juliaup only gets the 1.12 channel added, not made the default. The daemon runs the julia that SOT_JULIA_BIN names, else juliaup's default channel, else the one on PATH; the comm refresh runs the julia on PATH. When the julia on PATH is older than 1.12 the install stops there, before any step runs on it; when only the daemon's is older, or either cannot be asked, it ends ONE STEP LEFT. Either line names the version and the command: juliaup default 1.12 (after juliaup add 1.12 when that channel is not installed), or installing a newer Julia.

  • node/npm, optional, on the backend machine: typeset math in markdown previews renders in a long-lived node process, whose dependencies the installer fetches with npm ci. Without it the installer warns and continues, and math renders as raw LaTeX. To add math later, install node and re-run the installer (or npm ci in <checkout>/rust/backend/sidecars/mathjax).

  • poppler-utils (pdftoppm, pdfinfo) and ffmpeg, optional, on the backend machine: PDF pages and video poster frames in previews. The installer does not check for them; without them the preview shows a note naming the missing tool.

  • Frontend roles need glibc 2.35 or newer (Ubuntu 22.04 or newer) and a desktop session (X11 or Wayland): the frontend is a native window. It renders with wgpu through Vulkan on Linux, Metal on macOS and DirectX 12 or Vulkan on Windows, so a Linux frontend needs a working Vulkan driver. The backend binary is static musl and runs on any distribution; --be-only has no glibc floor.

  • --backend <ssh-alias> needs key-based SSH to the remote backend host.

  • No GitHub authentication: the repo is public and releases download from fixed URLs.

  • A home directory on NFS (or another remote filesystem) needs a systemd drop-in pointing the daemon's state root at local disk before sessions will start; see A session will not start on a shared home.

On Windows the installer is scripts/install.ps1 (Windows PowerShell 5.1; it needs git and curl.exe on PATH), and no Rust toolchain is needed: it downloads and verifies the release's sot-<ver>-windows-x86_64.zip, puts sot.exe, sotd.exe and sot-capsule.exe in %LOCALAPPDATA%\sot\bin, lays out repo\base, repo\versions\v<ver> and the repo\current junction, installs the comm layer, and creates the desktop shortcut (and re-syncs any taskbar pin) that runs repo\current\scripts\launch-sot.ps1. On a fresh box fetch the installer of the latest stable release and run it with -Hub (the hub's ssh alias) and no version; to update, run it again from the installed checkout with no options. -Version names a release instead and pins the install, so its automatic updates stay off until a run that names no version (while the latest stable release has no install.ps1, naming a pre-release is the way in). It ends with one PASS, ONE STEP LEFT or FAIL line. Do not point a shortcut at bare sot.exe, which skips the launcher's update and relaunch handling. The launcher also declares the home folder as the trusted folder prefix in %LOCALAPPDATA%\sot\config\settings.toml (a [trust] table, written once and never rewritten), so a session the daemon starts there does not stop at the agent's folder-trust dialog. The step-by-step walkthrough is INSTALL-AGENT.md §2b (written for a coding agent, equally followable by hand). A Windows box's comm scripts need jq on PATH too (winget install jqlang.jq): the installer's last line names that command when it is missing.

On macOS aarch64 the bash installer works, but there is no launchd service; local roles start sotd on demand. See Platforms for what is and is not supported on a Mac.

From source ​

Ship of Tools is a Rust and Julia project: the frontend and backend are Rust binaries, the kernel and plugins are Julia. Installing from source means building the Rust workspace once and instantiating a handful of Julia environments. Machine-specific config and launchers are covered by Per-machine setup; run that page's checklist by hand or let the /sot-setup Claude Code skill drive it.

Prerequisites ​

ToolVersionWhy
Rust toolchaincurrent stablefrontend, backend, protocol crates
Julia1.12 or newerkernel, ConceptExplorerCore, plugins
gitanyclone the repo

Install Rust with rustup and Julia with juliaup.

Clone ​

bash
git clone https://github.com/kalidke/ship-of-tools
cd ship-of-tools

Enroll the publish guard ​

From the clone root, before building or publishing, run in Bash (Git Bash on Windows):

bash
bash scripts/setup-publish-guard.sh "$PWD"

This installs a thin hooks/pre-push shim and publish-guard/installed-hash record under the clone's common Git folder. Every linked worktree uses the shim and its own checked-out scripts/hooks/pre-push; a missing implementation refuses the push. Other default hooks remain active. The development gate, release and pack entries also enroll their checkout. Direct Cargo commands do not perform setup, and a never-enrolled raw clone can push without this protection. Landing B adds automatic enrollment for release installs (validation pending). A fresh or repair run enrolls its installed base clone and a recognized caller clone, once per physical common Git directory, after the install gates. Run from inside the source clone to identify it: invoking its installer by absolute path from elsewhere does not identify that clone. An unrelated caller is named and kept. The installer reports the clones it considered and discovers no others.

The person maintaining policy provisions a private publish-list.txt outside every repository: in $XDG_CONFIG_HOME/sot (or $HOME/.config/sot) on Linux/macOS, or %LOCALAPPDATA%\sot\config on Windows. Shared homes share the same file. Save it as valid UTF-8 without BOM or NUL (CR, LF and TAB allowed). UTF-16 in either byte order, a UTF-8 BOM, NUL and invalid UTF-8 refuse at readiness and push, including errors in comments. Non-ASCII UTF-8 comment text is allowed. The file contains literal denied strings, one per line; blank lines and lines beginning # are ignored, and !literal span erases that exact span before matching. Entries match as whole words, bounded by any character that is not a letter or digit (ASCII [A-Za-z0-9]), or by the start or end of the text. This applies to every entry, including dotted names: paths, host labels, @, hyphens and punctuation supply boundaries; longer words do not. Matching folds ASCII letters only; a non-ASCII entry matches identical UTF-8 bytes, without Unicode case folding or normalization. Agents never print or copy the live list. The installer records that platform location without creating or changing the file. Its single final verdict is ONE STEP LEFT while policy needs provisioning or a preserved hook choice needs migration; a setup/Git-write or final-state failure is FAIL. A Windows update left armed uses verified staged setup if available; otherwise the verdict names enrollment as pending after apply and a repeated install. An armed update is never reported as applied. Once provisioned, record its absolute location in a clone enrolled manually and check readiness:

bash
bash scripts/setup-publish-guard.sh "$PWD" --list /absolute/external/publish-list.txt --require-ready

Use the actual native absolute config path on Windows. Setup does not create a permissive list. A missing, invalid or inside-repository sot.publishList refuses even a deletion-only push; only the common clone's local setting counts. The guard scans complete selected commit snapshots (including binary blobs, paths and identities), exact tag objects and destination branch/tag names. New refs can conservatively recheck previously published history. Missing local objects refuse without fetching.

If setup reports an existing core.hooksPath, it leaves that configuration and its hooks alone and names the clone. The owner inspects the other hooks, preserves those still wanted, then runs the clone-local migration command setup prints (git -C <checkout> config --local --unset-all core.hooksPath) and checks for remaining global/worktree overrides before repeating setup. An occupied default pre-push slot is also preserved: the owner may explicitly place that hook at <common>/hooks/pre-push.local before enrollment. The guard runs this optional local hook only after its scan succeeds, preserving its veto. It never moves a foreign hook on the owner's behalf.

This protection covers ordinary Git pushes after enrollment. --no-verify, removed/disabled hooks, overriding hook configuration, and gh text such as PR, issue and release bodies remain outside it. Keep the private policy deliberately when removing or reinstalling config folders; deleting the config folder deletes the list too.

Build the Rust workspace ​

The Rust workspace lives under rust/ and has six members: protocol (shared line-protocol types), backend (the daemon), frontend (the native window), updater, log and vt100 (a terminal-emulator fork). One command builds all of them:

bash
cargo build --release --manifest-path rust/Cargo.toml

This produces the binaries the launcher runs:

BinaryPathRole
sotrust/target/release/native window, chrome, previews
sotdrust/target/release/project state, supervision, agent sessions
sot-capsulerust/target/release/sotd's capsule-runtime pair, one per session

The first release build compiles the full rendering stack (winit, wgpu, cosmic-text, glyphon, resvg) and takes a while; later builds are incremental.

Instantiate the Julia environments ​

The repo is a set of nested Julia environments. The umbrella environment at the repo root pins project-level dependencies such as CairoMakie:

bash
julia --project=. -e 'using Pkg; Pkg.instantiate()'

Then the core library, kernel, REPL shim, and Pluto sidecar:

bash
julia --project=core            -e 'using Pkg; Pkg.instantiate()'
julia --project=julia/kernel    -e 'using Pkg; Pkg.instantiate()'
julia --project=julia/repl      -e 'using Pkg; Pkg.instantiate()'
julia --project=julia/pluto     -e 'using Pkg; Pkg.instantiate()'

core/ is ConceptExplorerCore, the abstract types and dispatch contract that make up the extension ABI. The standard plugins live under julia/plugins/*; instantiate any plugin environment you intend to load the same way, e.g.:

bash
julia --project=julia/plugins/julia-source -e 'using Pkg; Pkg.instantiate()'

Verify the build ​

bash
ls rust/target/release/sot rust/target/release/sotd rust/target/release/sot-capsule
julia --project=core -e 'using ConceptExplorerCore; println("core OK")'

Next steps ​

  • Quickstart — launch and start a first agent session.

  • Going remote — a backend on a server, the window on your laptop.

  • Per-machine setup — the source-checkout checklist: toolchains, config files, comm skills, and a launcher.

An agentic development environment for Julia. Released under the AGPL-3.0-or-later, with a commercial license on request.