Reference
Scripts reference
Every executable under Scripts/, with its arguments, environment, output,
and exit behavior, and the tama hooks commands those scripts run. Two of them
ship inside the app bundle and run on operator machines (emergency_disable_hooks
and the sealed release with its own bin/tama); the rest are maintainer tools
that run only in a checkout. The sealed CLI itself is documented in cli; the
integrity model these commands implement is concepts/seal.
#Bundled on operator machines
#tama hooks install-release
The transactional installer, a subcommand of the tama program the sealed
release carries in bin/tama. The desktop runs
Tama.app/Contents/Resources/hooks-release/bin/tama hooks install-release to
install session controllers; tama hooks release calls the same installer
in-process for the release Stado placed under ~/.stado/share/tama. Wire format:
one JSON result object on stdout on success; on any failure, one line on stderr —
Tama hook release installation failed: <reason> — and exit 1.
tama hooks install-release --release <dir> --home <dir>
[--emergency-manifest <file>] [--session-control-only]
| Argument | Meaning |
|---|---|
--release (required) | The sealed release root to install; must contain release.json with schema ai.wisent.tama.hook-release.v1 |
--home (required) | The target home directory; every managed write resolves against it |
--emergency-manifest | The emergency-backup/manifest.json written by a global disable; restores every entrypoint it names |
--session-control-only | Install hook sources and provider session controllers, and rewrite each global Git dispatcher already Tama's for this release, without connecting other Git dispatchers or restoring entrypoints |
Without --session-control-only, --emergency-manifest is required: the
refusal is Full hook installation requires an emergency manifest. The full
gate order and write set are in hook-releases; every
refusal sentence is in the runbook. Environment: TAMA_OMP
overrides the omp executable used to register the OMP adapter.
The success object has keys installed (the new installed.json content),
previous, managedSourceFiles, restoredEntrypoints, and
sessionControlOnly.
#emergency_disable_hooks
The global kill switch, bundled at
Tama.app/Contents/Resources/emergency_disable_hooks. No positional
arguments; everything is environment:
| Variable | Default | Effect |
|---|---|---|
TAMA_EMERGENCY_ACTION | disable | disable or enable; anything else prints Unsupported Tama emergency action: <value> and exits 2 |
TAMA_HOME | $HOME | Target home |
TAMA_SKIP_SESSION_RESTART | 0 | 1 skips the supervised-session pause/resume |
TAMA_HOOK_RELEASE_ROOT | bundled hooks-release (falls back to .build/Tama.app/... in a checkout) | Release root |
TAMA_HOOK_INSTALLER | the release's own bin/tama (run as tama hooks install-release) | Installer override |
TAMA_SESSION_SUPERVISOR | $TAMA_HOOK_RELEASE_ROOT/shared-hooks/agent-session-supervisor.py | Supervisor override; if missing (and sessions are not skipped) the script prints Tama session supervisor is missing: <path> and exits 66 |
Disable ends with Disabled hooks. Supervised agent sessions will resume without an editor restart.; a repeat prints Tama hooks are already disabled. and exits 0. Enable ends with Enabled approved hook release <first-12-of-id>. Supervised agent sessions will resume without an editor restart.; enable without a manifest fails with Tama has no emergency backup manifest to restore.. The step-by-step behavior is in
enforcement-control and
concepts/emergency-disable.
#Read-only integrity report
#tama hooks integrity
tama hooks integrity [--release <release-root>] [--home <dir>]
The two seal gates the installer enforces, reported instead of enforced; it
writes nothing. --release prints release root:, recorded releaseId:,
actual tree digest:, sealed at:, source revision:, source dirty:,
then result: intact or result: DRIFTED followed by
written after the seal: and one path per file modified after
release.json was written. When no file is newer, it prints
no file is newer than the seal -- the drift is a permission change, a deletion, or a file whose timestamp was preserved on copy.
A missing manifest is refused with no release manifest at <path>.
--home (the default, with $HOME, when no --release is given)
digests every tree under Library/Application Support/Tama/hooks-runtime/releases/
against its directory name and prints intact or DRIFTED and the path,
with <- current on the live one; with no releases directory it prints
nothing installed under <runtime>. Exit 0 when every tree is intact,
1 when one drifted, 2 when refused. Runnable wrappers live in
../examples/integrity/.
#Build and release (maintainer-only)
#build-app.sh
Builds, signs, and installs the app bundle from a checkout: Swift release
build, the two system-policy binaries and the Network Extension, the sealed
Rust tama program (built with cargo from the hook
source tree's rust/ workspace), the catalog snapshot
(export-catalog.mjs), the staged hook release sealed by
tama hooks seal, and tama-build.json. No arguments; the environment
variables (TAMA_HOOK_ROOT, TAMA_RELEASE_VERSION, TAMA_BUILD_CHANNEL,
WISENT_CODESIGN_IDENTITY, provisioning profiles, TAMA_NODE,
TAMA_CARGO, TAMA_INSTALL_APP_PATH, TAMA_INSTALL_AFTER_BUILD,
WISENT_RESTART_AFTER_BUILD, …) are tabled in
operations. It requires Node.js 20+, a
resolvable codesigning identity, and a Git checkout for both the desktop and
hook source trees. Output ends with Built <path> and, unless
TAMA_INSTALL_AFTER_BUILD=no, Installed <path>.
#tama hooks seal
tama hooks seal [--source-root <checkout>] <release-root>
tama hooks digest <artifact-or-release>
seal restates the release registry's checkout with $HOME
(TAMA_DEPLOY_CHECKOUT names it explicitly in a fleet build), packages external
hook sources into external-hooks/ with an external-sources.json mapping
(schema ai.wisent.tama.external-hook-sources.v1, refusing when an external source
is missing: External hook source is missing: <path>), computes the tree
digest, and writes release.json with the digest as releaseId; prints the
id. When TAMA_HOOK_SOURCE_REVISION or TAMA_HOOK_SOURCE_DIRTY is set, a
source tree whose identity differs is refused with
Hook source expectation <name> differs at <root>. digest prints the
tree digest of a release directory, or the SHA-256 of one file (used for artifact
.digest sidecars); a missing path exits with artifact not found: <path>.
The digest definition is in concepts/seal.
#export-catalog.mjs
export-catalog.mjs <tama-root> <output-path>
Renders the desktop's catalog snapshot by running the Rust CLI
(tama list --root <tama-root> --json; override the binary with
TAMA_CLI) and filling the fields the CLI leaves out (generatedAt →
Unknown, category → Uncategorized, status → unknown).
Missing arguments throw usage: export-catalog.mjs <tama-root> <output-path>.
#tama hooks stage and tama hooks source-identity
tama hooks stage --source-root <tree> --release-root <prepared-release> --cargo <cargo>
[--codesign-identity <id>] [--codesign-timestamp <flag>]
tama hooks source-identity --source-root <tree> [--shell]
stage builds, from the source tree, every native program the prepared
release's registry runs plus the one tama program, places them in
bin/ (signing each when an identity is given), and writes
native-hook-binaries.json with the source identity they were built from; a
staged hook file that differs from its source is refused with
Staged hook source differs from <path>; restage the release.
source-identity prints that identity — commit, whether the tree held
uncommitted work, and a fingerprint of every source input — or, with
--shell, <revision> <dirty> for a build script. A fleet build
names its commit in WISENT_SOURCE_COMMIT instead of a .git directory.
What to do with a staged tree afterwards is
hook-releases.
#package-release.sh
No arguments. Packages the immutable release candidate for the exact signed
v<SemVer> tag at HEAD (TAMA_RELEASE_TAG disambiguates). It refuses,
each with its own printed sentence, on: a missing Package.resolved,
multiple release tags at HEAD, a tag that is not v<SemVer>, invalid
SemVer, a dirty desktop or hook checkout, a tag that does not resolve to
HEAD, a missing or still-Unreleased CHANGELOG.md section, missing
signing/provisioning/notary variables, dirty build provenance, mismatched
component versions, and any pre-existing artifact output (Refusing to overwrite immutable release output: <path>). It then builds with
--timestamp signing, notarizes and staples, and writes
Tama-<version>-macOS-<arch>.zip plus .digest and .provenance.json
(schema ai.wisent.tama.release-provenance) under
.build/releases/<version>/. Channels: a pre-release version packages as
preview, otherwise stable. Details: releases.
#publish-release.sh
No arguments; same tag resolution as packaging (Publication requires the exact signed v<SemVer> release tag at HEAD.). Verifies the packaged
artifact, digest, provenance, and qualification sidecars for that version and
publishes them to the immutable GitHub release; a pre-release version
publishes as a GitHub prerelease and never becomes latest. The publication
contract is in releases.
#import-brand-icon.sh
import-brand-icon.sh PRODUCT OUTPUT.icns
Fetches the canonical app icon from the asset resolver named by
WISENT_GROUND_TRUTH_API (unset: WISENT_GROUND_TRUTH_API must point to the canonical asset resolver., exit 64), renders the iconset with sips, and
writes the .icns. Requires curl, sips, iconutil (missing tool: exit
69).
#Restarting the app after a build
Tama Desktop carries no restart script of its own. stado product install tama --surface desktop
restarts the bundle it places when the app runs and leaves a stopped app stopped;
stado product restart --if-running Tama.app restarts a bundle placed any other way,
refusing with a sentence that names the bundle, its Info.plist or the LaunchServices answer it
could not use. build-app.sh restarts nothing itself.