CLI reference
tama build
Writes and reads ~/.shared-hooks/build_restart_registry.json. A build
needs the agent's written whole-task completion statement and one unused entry;
the block-unregistered-build-or-restart
gate consumes that entry for one attempt. Restarts retain their ordinary open
entry. The CLI and Tama Desktop use the same registry operations.
#Record an intent
tama build record --kind build --target skarbiec \
--reason "Validate the committed identity checks in the shared build" \
--revision FULL_SHA \
--completed-task "The whole requested identity change is finished in code and documentation" [--minutes 60] [--json]
tama build record --kind restart --target brama-desktop-model-router \
--reason "the router holds a revoked credential and reads it once at start" \
--minutes 30
| Option | Meaning and refusal |
|---|---|
--kind | build or restart. Any other word is refused
by name. |
--target | The product for a build, the service or unit for a restart. A build
command that names no target of its own — stado release submit --source .,
cargo build — is registered against the repository it runs in, which is the directory name
the gate reports in its refusal. |
--reason | Required: what the entry is for, because it is read later by somebody who was not there. A missing or blank reason is refused. |
--revision | Required for --kind build, and it must be a full
forty-character source revision. A build that cannot say what it carries is not recorded. |
--completed-task | Required for a build: which whole task was finished
before building. Missing or blank text is refused before an intent is spent. It is an agent
declaration retained in completed_task, not independent proof; do not claim completion
while work remains. Restarts are unchanged. |
--minutes | How long the entry authorizes: one to the policy's
window_minutes, which is also the value when the option is absent. A longer window is
refused, so an entry nobody closes cannot become standing permission. |
--repository | Where a build's change is measured. Without it, the repository the command runs in; a directory in no repository is refused by name. |
--home | The home whose registry is written. Present so a test can drive the real command against a disposable registry instead of the operator's. |
--approval-session, --approval-quote | Optional, together, for builds only. The session identifies Tama's captured current user message; the quote must equal that whole message verbatim. Tama verifies explicit permission to exceed the daily count for this product or a batch containing it. Missing capture, a different quote, refusal, or an unavailable verifier does not authorize an exception. |
#The ration
Recording is not paperwork, it is an allowance. When Stado is available, the build count comes from
stado queue budget --json: the fleet's UTC-day budget. Otherwise Tama uses its local
rolling 24-hour ledger. Restarts always use the local ledger. A build is refused when the applicable
allowance is spent without a recorded user exception, or when its change is too small:
the policy allows 3 builds in any 24 hours and this machine has recorded 5
in that window (skarbiec, brama, tama, stado, oko). The local daily allowance
has a slot in 412 min if no further intents are recorded. Gather the work
into one build instead, or have the operator raise the limit with
`tama build policy --builds-per-day <n>` and DEVICE_HOOK_EDIT_APPROVED set
outside the agent session.
this build carries 2 changed lines against <revision>…, the revision the last
recorded build of skarbiec carried, and the policy calls a build serious at 30
lines. A build spends forty minutes of a builder the fleet has two of, so small
changes travel together: keep working and record the build once the change is
worth it.
The local count comes from ~/.shared-hooks/build_restart_ledger.json. Ordinary intents
are retained for thirty days; entries containing user approval are retained as audit evidence without
that expiry. An accepted build consumes its open entry before the tool runs, so another build
attempt requires a new completion statement and intent. close ends an authorization
without refunding it. Restarts are counted separately, ten in a rolling day.
The rolling-window forecast waits until enough entries have expired to put usage below the current limit, not merely until the oldest entry expires. This matters after a limit is lowered or approved exceptions have left usage above it. An entry at the exact boundary still counts. A zero limit has no timed reset. The forecast concerns the count only, assumes no further recorded intents, and is not a promise that change-size, source, resource or publication checks will pass.
The unregistered-build gate does not estimate usage from open authorizations: that would forget closed intents and disagree with the actual allowance. The recording command gives the authoritative refusal. Tama Desktop displays that same refusal from the shared backend.
#A user-approved exception
An exception changes neither the default limit nor the policy file. Record it before submitting the build. Replace the session, revision and message placeholders with the actual captured approval; an example in documentation is not user consent.
tama build record --kind build --target skarbiec --revision FULL_SHA \
--reason "Build the committed change after explicit permission from the user" \
--completed-task "The whole requested change is finished before this approved build" \
--approval-session SESSION_ID --approval-quote 'VERBATIM_USER_MESSAGE' --json
tama build approval --target skarbiec --revision FULL_SHA --json
tama build list --json
The message must explicitly authorize exceeding the daily build count for the named product or batch. A normal build request, a request to implement this mechanism, hypothetical consent, and an agent's assertion are not consent. Tama checks the message through Brama and refuses if it cannot obtain an accepting verdict. It rechecks that the captured message has not changed before writing.
The entry stores user_approval: the exact quote, session, message digest, capture time,
product, revision and verification verdict. The audit ledger is written before the open registry.
If the latter write fails, the error is returned and the auditable intent remains spent; it is not
silently granted or erased. The same captured message cannot authorize another intent for this
product. A batch approval may cover different products, each with its own recorded intent.
The exception bypasses only the daily count. The same-revision refusal, minimum change size,
expiry, source checks, resource admission and publication permissions remain in force. It cannot
authorize a restart. approval returns only a matching, unexpired entry also present in
the audit history; it refuses a missing entry, a different revision, or a closed authorization.
Stado's native build submission reads that entry when its fleet budget is exhausted and retains
the evidence with the charged run and platform in its canonical registry. One approval cannot charge
another run for the same product and platform. Raw queue submissions cannot claim this exception.
Read fleet charges and approval receipts with stado queue budget --json.
This flow requires both Tama's build approval command and Stado's approval consumer.
An older release reporting unknown action approval does not support the exception;
recording an ordinary intent is not evidence that consent was stored or consumed.
Availability: the approval flow and corrected rolling-window forecast are in source. Native release, real-fleet consumption and desktop visual qualification are still pending; this page is not evidence that the installed release supports them.
#Tama Desktop
Open Policy → Build registry. Enter the product, full revision, repository, reason and Completed whole task and result. For an exception, enable Use recorded user consent for a daily-limit exception and supply the session and verbatim current message. Record build records one permission; it does not start compilation. The screen displays the statement and backend refusal, current entries, local intent counts and retained approval history. Close removes an authorization but does not cancel an accepted job.
The screen runs the same operations as tama request builds,
tama request builds/record and tama request builds/close
(tama request). Recording uses kind,
target, reason, revision, completedTask,
optional repository and minutes, and paired
approvalSession/approvalQuote. Closing uses kind
and target. Unknown request fields are refused.
#Read the limits, and change them
tama build policy [--json]
tama build policy --builds-per-day 2 --restarts-per-day 6 \
--minimum-changed-lines 80 --window-minutes 45
Without options it prints the file and the sentence, for example 3 builds and 10 restarts in
any 24 hours; a build carries at least 30 changed lines; one recorded intent authorizes 60
minutes, with the numbers the file states. builds_per_day the file does not state is
the operator's own number, builds_per_day in numeric-provenance.json with his
words. The other three have no value in code: while the file does not state one, the command and every
intent are refused with <file> sets no <field>: the operator states it with `tama
build policy <option> <n>`, which needs DEVICE_HOOK_EDIT_APPROVED=1 set outside the agent
session. Tightening a limit needs nothing. Setting one the file did not state, or loosening one
— more builds a day, a smaller minimum change, a longer window — is refused unless
DEVICE_HOOK_EDIT_APPROVED=1 is set outside the agent session, because an agent that can
raise its own allowance has none. A policy or ledger that cannot be parsed refuses the build and names
the file, rather than counting the day as unspent.
#Read and close
tama build list [--json]
tama build close --kind build --target skarbiec [--json]
tama build close --kind build --target stado --not-started "Skarbiec request failed before any job existed"
list prints each entry with its kind, target, reason, revision and completed task.
An accepted build is shown as used and authorizes no second build; an expired entry authorizes
nothing. close removes one entry without refunding its allowance. JSON output
includes approval_history, including approvals whose entry was closed or replaced.
For builds, record, list and the Desktop Builds screen
report the fleet's count when stado queue budget answers — the fleet has N build
jobs left today, JSON fleet_remaining — because that count is the one that
admits a build. The local N of M intents in this 24 hours appears only when the fleet
cannot be asked, and for restarts.
A build whose submit was refused before any job existed built nothing. Close it with
--not-started <refusal>: the ledger keeps the row and still counts it against the
day's allowance, but the next build of that product is no longer measured against its revision, so
the same revision can be recorded again instead of being refused as carries no change at
all. --not-started without a refusal, or on a restart, is refused and closes nothing.
The JSON result carries not_started.revision and not_started.refusal.
#What waits for the next build, and what a failed build gives back
tama build pending --target oko --repository ~/Documents/CodingProjects/Wisent/oko [--json]
tama build fail --target oko --revision FULL_SHA --failure "cargo test: 2 failed" [--json]
Work ends at a commit and a push; the batched build runs later over everything that
accumulated. pending fetches the repository and prints the revision the last recorded
build of the product carried, the commits on origin/main since, how many lines they
change against the policy's minimum, whether a build is due, and the Oko tasks whose recorded
evidence names one of those commits (read with oko tasks carried --commit
<revision>…). JSON: last_built, tip, commits,
changed_lines, minimum_changed_lines, due, tasks.
fail is how a failed batched build reopens work. It takes the commits the build of
--revision carried — those after the revision the build before it carried — finds the
tasks whose evidence names them, and reopens each with oko tasks defect,
giving the batched build of <product> at <revision> failed: <failure> as the
reason. The build's ledger row records the failure and still counts against the day's allowance.
JSON: since, commits, reopened, and refused with
Oko's own answer for each task it would not reopen, for example a task whose session transcript is
not on this machine. Without --revision or --failure the command is refused
and reopens nothing; when Oko cannot be run or answers no JSON, the command fails and names the call.
#What the refusal looks like
BLOCKED: unregistered build: `stado release submit --source . --version 0.3.11` would
build skarbiec, but ~/.shared-hooks/build_restart_registry.json has no unused,
unexpired entry with a whole-task completion statement for it. A build consumes
its entry once. Record the completed task and intent, then run the command again:
tama build record --kind build --target skarbiec --reason "<what this
build is for>" --revision <source revision this build carries>
--completed-task "<which whole task is finished>"
#Package a matching desktop backend
In the Tama Desktop checkout, pin the pushed Tama commit before releasing the app:
bash Release/tama-source.sh pin --revision FULL_TAMA_COMMIT
bash Release/tama-source.sh verify
The producer updates Release/tama-revision and its immutable archive and checksum.
Both release lanes use that revision. Stado unpacks the verified archive with its recorded origin;
native packaging and sealing refuse changed, missing or additional source inputs rather than
treating the enclosing desktop checkout as the backend's revision.
The verification command checks the archive digest and recorded Git commit and prints the archive
path. That result proves source handling only, not a compiled or published desktop release.
Retained qualification evidence must name the exact revision and consumer it exercised.
#Publish the desktop's locked Swift dependencies
From the Tama Desktop checkout, publish the committed package resolution through Stado:
stado release catalog pin-input . --name swiftpm-cache --source . --revision HEAD --swiftpm --json
This resolves dependencies and publishes a checksummed archive; it does not compile or install
the app. Commit the updated .wisent-release.json with the release source.
The release recipe reads the expected digest from that manifest rather than a second checksum
in the script, then uses stado product swift restore to verify and restore the cache.
Subsequent dependency updates use the same publication command.
The updater is a locked Swift package inside this cache, so the release needs no
separate updater archive; its source is verified with the other
Package.resolved dependencies during restoration.
Stado refuses changed package declarations, missing or mismatched locked revisions, unsafe archive entries and invalid binary-artifact paths. It reports the failed dependency or path; neither a missing archive nor an invalid cache falls back to fetching during compilation. In Stado Desktop, Releases → Publish an immutable build input exposes the same operation with Export the Swift package's committed resolution. A publication receipt proves only the input was published, not that Tama built or passed qualification.
Source: rust/crates/tama-cli/src/builds/mod.rs.