miadi-orchestration-kit

miadi (apt packages)

sudo apt install miadi sets up a Miadi host. miadi is the umbrella package: each part of a host is its own package and joins it as a dependency. On a new system, add the repository first:

curl -fsSL https://apt.sanctuaireagentique.com/sanctuaire-agentique.gpg \
  | sudo tee /usr/share/keyrings/sanctuaire-agentique.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/sanctuaire-agentique.gpg] https://apt.sanctuaireagentique.com stable main" \
  | sudo tee /etc/apt/sources.list.d/sanctuaire-agentique.list
sudo apt update && sudo apt install miadi

miadi brings miadi-tide, whose tide runtime needs Python 3.11 or newer with venv. Ubuntu 24.04 has it. On 22.04, add the deadsnakes PPA before installing (see miadi-tide).

package gives the host since
miadi its dependencies (through 0.1.x it held the settings itself) 0.1.0
miadi-config the MIADI_* settings and the miadi-config command 0.2.0
miadi-tmux /usr/bin/tmux 3.7c built from the upstream release, replacing the distribution’s tmux (3.2a on 22.04): one tmux version on a host, since a client cannot attach to a server of another version 3.7c-1
miadi-terminal a client’s clickable miadi-chronicle:, miadi-ceremony:, miadi-circle: and miadi-foundation: (0.2.2) references, and bare circle ids (0.1.4): desktop, Terminator, tmux 0.1.0
miadi-tide the review loop (tan, plannotator-tui) and the tide runtime (tide, its daemon) 0.1.0
miadi-perms group read and write on the shared session capture (MIADI_SESSIONDATA_ROOT), every 4 hours, so one user’s agent hooks can write where another user’s session created files 0.1.0
miadi-node Node.js 24 LTS at /usr/lib/miadi-node, private to the two below: nothing on PATH, no npm 24.21.0-1
miadi-chronicle-client the chronicle’s commands and MCP servers from pinned npm releases: inquiry-weave, inquiry-weave-mcp, passages, mkepisode, miadi-voice-mcp, medicine-wheel-mcp 0.1.0
miadi-chronicle-server the chronicle’s host services: miadi-capture-service (a per-user unit, not started), miadi-episode-capture, miadi-transcription, miadi-hooks, miadi-hooks-interpret, plan-insight-register (miadi depends on it since 0.4.0) 0.1.0
miadi-music music on the host, for an album or an episode’s score: brings the three below and the miadi-music command 0.1.0
miadi-music-render ABC to MIDI, audio and the engraved page: abcmidi, abcm2ps, fluidsynth with the FluidR3 soundfont, ffmpeg 0.1.0
miadi-music-measure NumPy, SciPy and Pillow, pinned, in their own venv, built from one of the three below 0.1.0
miadi-music-wheels-cp310, -cp311, -cp312 the wheels for that venv, one package per Python (Ubuntu 22.04, Debian 12, Ubuntu 24.04); apt installs the one matching python3 0.1.0
miadi-music-video score videos for an episode: ImageMagick and ffmpeg beside the two above (recommended by miadi-music) 0.1.0

Each package is a directory here holding its DEBIAN/control and the files it installs. The packages are MIT-licensed (LICENSE, as in jgwill/Miadi), and build.sh writes each one’s /usr/share/doc/<package>/copyright from it.

miadi-config

file holds on upgrade
/etc/miadi/miadi.env this host’s values, plain KEY=VALUE conffile: an edited copy is kept
/usr/share/miadi/env.sh the defaults and how each value is built replaced
/usr/share/miadi/settings every known setting and what it does replaced
/etc/profile.d/miadi.sh loads env.sh into bash login shells conffile
/usr/bin/miadi-config the command below replaced

A value in the environment wins over miadi.env, which wins over the defaults. env.sh prints nothing and loads under set -u. Sourced a second time in the same shell, as binscripts load.sh does after ~/.env, it rebuilds the values it filled in the first time from the new inputs and keeps any value changed in between. Because miadi.env is plain KEY=VALUE, systemd EnvironmentFile= and docker compose env_file read it too. It holds no secrets: a user’s tokens stay in that user’s ~/.env, a service’s in its own env file.

miadi-config                              # every setting, its value, and its source: env, miadi.env, default, unset
miadi-config get MIADI_DATA_DIR           # one resolved value, for scripts
sudo miadi-config set MIADI_SRC /a/src/Miadi
sudo miadi-config unset MIADI_SRC
miadi-config check                        # what this host is missing
miadi-config settings                     # what each setting does

miadi.env stays the same file from 0.1.x on. A host that edited it keeps its edits through the upgrade without a prompt.

Termux cannot install Ubuntu packages. There, set MIADI_ETC and source miadi-config/usr/share/miadi/env.sh from this checkout.

miadi-terminal

For a machine that reads chronicle references, not one that serves them. A click turns miadi-chronicle:126 into <front>/api/chronicle/open?uri=… and the Miadi server redirects to the room, so nothing is resolved here. A ceremony or circle reference opens its page the same way: miadi-circle:<id>, miadi-ceremony:<id>, or the bare wheel id circle:1790787727155:2slscw (jgwill/Miadi rispecs/miadi-chronicle-dsl/SPEC.md §9).

sudo apt install miadi-terminal
miadi-terminal front https://<your Miadi>   # when MIADI_URL_BASE is not already it
miadi-terminal enable                       # per user; or: enable desktop terminator tmux
miadi-terminal status
integration a click is file
desktop an OSC 8 link or a page link carrying miadi-chronicle:, miadi-ceremony:, miadi-circle: or miadi-foundation: /usr/share/applications/miadi-chronicle-open.desktop
terminator Ctrl+click a bare reference /usr/share/miadi-terminal/terminator/, linked into Terminator’s plugin directory
tmux click, or tap on Termux, a bare reference in a pane /usr/share/miadi-terminal/tmux/miadi-chronicle.conf
restore (0.2.0, by name only) tmux starts at boot, restores its sessions, and tide brings the agents back /usr/share/miadi-terminal/session-continuity/, /usr/lib/systemd/user/tmux-server.service, tmux-save.timer

The package installs system-wide; its maintainer scripts write nothing into a home directory. enable, run by the user, changes that user’s Terminator enabled_plugins, adds one line to their tmux config, and sets the scheme default in ~/.config/mimeapps.list. Each config it changes keeps a .bak-miadi-terminal copy of how it was before the first change. The plugin and wrapper an earlier inquiry-weave terminal install left are moved to ~/.local/share/miadi-terminal/legacy/; its environment drop-in stays, since the session may read its values. status names each key that drop-in still sets over /etc/miadi/miadi.env, with both values, and says nothing when it overrides none. The front is MIADI_CHRONICLE_OPEN_URL, else MIADI_URL_BASE. A Termux build of the same tree is made by build.sh (termux/README.md). Contract: jgwill/Miadi rispecs/miadi-chronicle-dsl/SPEC-TERMINAL.md §3.

miadi-tide

The terminal half of Miadi’s review loop and the tide runtime, as one amd64 package. It is built from sources pinned in other repositories and is neither an npm nor a PyPI release (jgwill/miadi-orchestration-kit#55).

installed what it is client or server
/usr/bin/tan <target> review the last reply of the agent in a tmux pane, deliver on submit client
/usr/bin/plannotator-tmux-review the loop itself; the script and its pane-write guard sit in /usr/lib/miadi-tide/ client
/usr/bin/plannotator-tui the annotator, built from miadisabelle/mia-plannotator-tui at jgwill/Miadi’s runtime/plannotator-tui pin client
/usr/bin/tide the tide CLI, from the runtime venv client
/usr/share/miadi-tide/node/@miadi/{tide,tide-contract} the Node client, as pnpm pack would publish it client
/usr/lib/systemd/user/tide-runtime.service tide daemon --interval 60, the context daemon the cockpit reads through $MIADI_HOME/daemon.sock server
/usr/lib/systemd/user/tide-store-prune.{service,timer} keeps the daemon’s snapshot store to 7 days server
/usr/share/miadi-tide/SOURCE the repository and commit each part was built from  

The tide runtime (ironsilk) runs in its own venv, /usr/lib/miadi-tide/tide-runtime, which postinst builds from the wheels in the package with --no-index. Its dependencies are pinned in prep/miadi-tide.constraints.txt, and it reads nothing from system site-packages or a user’s conda. It needs a Python 3.11 or newer with venv. That is python3-venv on Ubuntu 24.04. On 22.04, add the deadsnakes PPA first so apt can install python3.12-venv:

sudo add-apt-repository -y ppa:deadsnakes/ppa && sudo apt update
sudo apt install miadi-tide

The daemon observes one user’s tmux, so it is a user unit that each user turns on. Its name is the one ironsilk’s tide service install writes, so a user’s own ~/.config/systemd/user/tide-runtime.service replaces it instead of running beside it:

systemctl --user enable --now tide-runtime.service tide-store-prune.timer

build.sh runs prep/miadi-tide.sh to add what git does not keep: the binary (rustup’s cargo), the wheels (pip), and the packed Node sources (pnpm). It reads MIADI_SRC (default /a/src/Miadi), GAIA_SRC (/a/src/gaia, for the review script) and PANE_WRITE_GUARD_SRC, and caches builds under MIADI_DEB_CACHE (~/.cache/miadi-deb).

miadi-perms

Several users’ agent sessions write into one capture directory, MIADI_SESSIONDATA_ROOT (/src/_sessiondata by default). A file one user creates there is often not writable by the others. miadi-perms.timer, a system timer enabled at install, runs miadi-perms as root at 00:00, 04:00, 08:00, 12:00, 16:00 and 20:00, and at the next boot when a run was missed. It gives the group read and write on every file there that lacks it, and leaves the others untouched.

systemctl list-timers miadi-perms.timer        # when it runs next
sudo miadi-perms                               # run it now; or: sudo miadi-perms <dir>...
journalctl -u miadi-perms.service              # how many entries each run changed
sudo systemctl disable --now miadi-perms.timer # stop it; an upgrade keeps it off

It replaces the sudo chmod -R g+rw /workspace/repos/ /src/_sessiondata that jgwill/Miadi’s .github-hooks/push ran on every push until 2026-10-08: that walked 3 million files per push, and push bursts started several at once.

miadi-node, miadi-chronicle-client, miadi-chronicle-server

The chronicle’s commands are npm packages from jgwill/Miadi packages/*. These three packages put them on a machine without npm, npx or a Node of its own (jgwill/miadi-orchestration-kit#77). They split as a client and a server half around one private runtime:

package half for
miadi-node runtime Node.js 24 LTS from nodejs.org, sha256-checked, at /usr/lib/miadi-node/bin/node. Nothing on PATH, so a system or nvm node is left alone
miadi-chronicle-client client any machine an agent or a person works from: reads, relates and writes the chronicle through the Miadi API
miadi-chronicle-server server the host where sessions run and takes are recorded; miadi (the host) depends on it and recommends the client
sudo apt install miadi-chronicle-client          # a client: brings miadi-node
inquiry-weave --help
systemctl --user enable --now miadi-capture-service   # on a host, per user

Each half installs its pinned npm releases (prep/<half>.packages) under /usr/lib/<half> with the npm of the same Node it runs on, and gets a /usr/bin wrapper for every command those packages declare. Install scripts are not run; no package in either list has a native module. SOURCE in /usr/share/<half>/ lists the pins and the resolved tree. The MCP servers are pinned at the versions the miadi-chronicle-episode-kit plugin runs with npx, so an MCP config can call /usr/bin/miadi-voice-mcp instead, with no npm cache and no network at session start. A user’s own npm install, earlier on PATH, still wins.

To move a pin: change prep/<half>.packages, bump the half’s Version:, build, test, publish. A Node release is a new miadi-node Version (24.21.0-1 names v24.21.0); the halves accept any 24.x.

miadi-music

Music on a Miadi host, installed beside the platform. The parts are split by what a host makes, so an album workstation and a host scoring episodes each install only what they use:

package an album an episode’s score
miadi-music-render yes yes
miadi-music-measure yes yes
miadi-music-video no yes
sudo apt install miadi miadi-music                          # the platform, and music with score video
sudo apt install --no-install-recommends miadi-music        # an album host: render and measure only
miadi-music check                                           # every tool each part needs, and its package
miadi-music python script.py                                # run under the measuring Python

miadi-music-measure follows miadi-tide: its postinst builds /usr/lib/miadi-music/venv with --no-index from the wheels in /usr/share/miadi-music/wheels/cp<NN>/, and checks that NumPy and SciPy import together without a warning. A NumPy that pip put in /usr/local cannot pair with the distribution’s SciPy there. The pins are in prep/miadi-music-measure.constraints.txt.

The wheels for all three Pythons came to about 175 MB, over the repository’s 100 MB limit for a .deb. They are three packages instead, about 55 MB each, built by prep/miadi-music-wheels.sh. Each miadi-music-wheels-cp<NN> depends on the python3 of its version, and miadi-music-measure depends on any one of them, so apt installs only the set the host can use. A wheels package installed, upgraded or replaced triggers miadi-music-measure (DEBIAN/triggers), which rebuilds the venv: after a release upgrade changes python3, apt swaps the wheels package and the venv follows.

miadi-music itself carries the watch tools (rsync, ssh, jq, curl, file) and /usr/bin/miadi-music. MIADI_MUSIC_SOUNDFONT (else JAMAI_SOUNDFONT) and MIADI_MUSIC_PYTHON override its defaults. The atelier-jerry plugin (jgwill/miadi-orchestration-kit#44) tries the venv first for its measurements.

Build, test, install

bash build.sh                               # -> dist/<package>_<version>_<arch>.deb for each package
bash build.sh miadi-tide                    # one package
bash test-install.sh dist/*_<version>_*.deb     # clean ubuntu:22.04 container
IMAGE=ubuntu:24.04 bash test-install.sh dist/miadi-tide_<version>_amd64.deb
python3 tests/tmux-click.py miadi-terminal/usr/share/miadi-terminal/tmux/miadi-chronicle.conf miadi-terminal/usr/bin/miadi-chronicle-open
bash tests/session-continuity-sync.sh   # restore's copies against jgwill/gaia's installer
sudo apt install ./dist/*_<version>_all.deb

The host-level check is runtime/miadi-host in miadisabelle/workspace. It installs through apt with the published repository beside the kit’s build, covers the upgrade from the published version, and opens a shell in a clean host (shell.sh).

Publishing to apt.sanctuaireagentique.com uses scripts/apt-publish.sh from miadisabelle/mia-parallel-code, which needs the repository’s signing key and APT_PUBLISH_TOKEN. It takes one .deb per run. Bump Version: in each DEBIAN/control, build, and publish the dependencies before miadi, so the index never lists a miadi whose dependency is missing:

publish=/workspace/repos/miadisabelle/mia-parallel-code/scripts/apt-publish.sh
bash "$publish" dist/miadi-config_<version>_all.deb
bash "$publish" dist/miadi-perms_<version>_all.deb    # after miadi-config, before the miadi that depends on it
bash "$publish" dist/miadi-node_<version>_amd64.deb   # before the two halves that run on it
bash "$publish" dist/miadi-chronicle-client_<version>_all.deb
bash "$publish" dist/miadi-chronicle-server_<version>_all.deb   # before the miadi that depends on it
bash "$publish" dist/miadi_<version>_all.deb
bash "$publish" dist/miadi-terminal_<version>_all.deb   # after the miadi-config it depends on
bash "$publish" dist/miadi-tide_<version>_amd64.deb     # before the miadi that depends on it
bash "$publish" dist/miadi-music-render_<version>_all.deb
for w in dist/miadi-music-wheels-cp3*_<version>_amd64.deb; do bash "$publish" "$w"; done
bash "$publish" dist/miadi-music-measure_<version>_all.deb   # after the wheels it depends on
bash "$publish" dist/miadi-music-video_<version>_all.deb   # after the two it depends on
bash "$publish" dist/miadi-music_<version>_all.deb         # last

The repository publishes amd64 only, so the Termux build in dist/termux/ is installed from the file. It is a Cloudflare Worker over R2, and an uploaded .deb must stay under 100 MB: split a package that grows past it, as the music wheels are split by Python.

The Miadi umbrella packages (packages/miadi/js, packages/miadi/py in jgwill/Miadi) can join here later.