@holocronlab/brt
v0.12.3
Published
brt — botruntime CLI. Full fork of @botpress/cli (MIT), rebranded and repointed at our cloudapi (botruntime.ru). Keeps the native build (codegen + esbuild bundle), local dev/serve, and the cloud deploy/login flow against our host.
Readme
brt — botruntime CLI
brt is a full fork of @botpress/cli
(MIT), rebranded and repointed at our self-hosted cloud
(https://botruntime.ru). It keeps the upstream toolchain intact — most
importantly the native build (codegen + esbuild bundle) — and targets our
cloudapi, which mirrors the Botpress admin API.
Toolchain: bun (the bin runs via #!/usr/bin/env bun).
Run it
# from this dir
bun src/cli.ts --help
bun src/cli.ts --version
# or install the `brt` bin onto PATH
bun link # then: brt --helpThe default host is https://botruntime.ru (src/consts.ts), overridable per
command with --apiUrl, or via env with the BRT_ prefix (e.g. BRT_API_URL,
BRT_BOTPRESS_HOME). Profiles live in $BRT_BOTPRESS_HOME/profiles.json
(default ~/.brt/profiles.json).
Commands
The full upstream command set is preserved:
login logout bots integrations interfaces plugins init generate(gen)
bundle build read serve deploy add(i/install) remove(rm) dev run lint chat
profiles link logs traces conversations workflows eval config secretbrt build runs the native pipeline — generate (typings codegen into
.botpress/) followed by bundle (esbuild → .botpress/dist/index.cjs). It is
not a bun build shortcut; it is the upstream Botpress build, repointed.
Smoke path
brt login # Personal Access Token + workspace, against our cloud
brt init # scaffold a bot / integration / plugin
brt build # native codegen + esbuild bundle -> .botpress/dist/index.cjs
brt deploy # build + publish to our cloud (PUT /v1/admin/bots/{id})For an integration project (with integration.definition.ts), brt build
produces a runnable .botpress/dist/index.cjs exporting { default, handler },
and brt deploy publishes the integration.
One-shot agent scripts
brt run executes a TypeScript file locally with the selected agent runtime
context. Unlike brt dev, it starts no worker, watcher, reverse tunnel or
callback receiver and exits with the script process code.
# Uses the attested development target previously prepared by brt dev
brt run scripts/reconcile.ts claimant-42
# Regenerate target-specific script artifacts before running
brt run scripts/reconcile.ts --force
# Uses the canonical agent.json production target
brt run scripts/audit.ts --prodDevelopment scripts receive config variables with the same precedence as the
brt dev worker: cloud values first, then the caller's local environment, then
immutable runtime identity variables. Public agent configuration is fetched
strictly; auth or network failure stops before user code runs. Stored
production secrets are never downloaded to a developer machine, so a
production script receives only explicitly supplied local environment values.
--local selects a development stack and is rejected with --prod.
Durable workflows
brt workflows starts and observes the persisted workflow engine; it does not
run a second workflow implementation inside the CLI.
# Idempotent creation. Input must be a bounded JSON object in a file.
brt workflows run collectDocuments --input-file ./input.json
# Return after durable creation instead of waiting in this terminal.
brt workflows run collectDocuments --input-file ./input.json --no-wait
# Reconcile an unknown create outcome by reusing the exact key.
brt workflows run collectDocuments --input-file ./input.json \
--idempotency-key 9d36a8e9-63f3-48e6-a355-e796175d31a2
# Cursor-paginated metadata history and one-run inspection.
brt workflows list --status listening --status paused --limit 20
brt workflows list --next-token 123 --json
brt workflows show wkflow_0123456789abcdef01234567 --steps
brt workflows wait wkflow_0123456789abcdef01234567 --timeout 300000
# The same operations against the attested target kept by brt dev.
brt workflows list --dev
brt workflows show wkflow_0123456789abcdef01234567 --dev --localCreation uses a per-run idempotency key and request fingerprint. If the network outcome is unknown, rerun the original command on the same target with the same input and printed key; a new key means an intentionally new workflow run.
--timeout bounds only how long this CLI invocation observes the workflow.
Reaching it exits with code 2 and never cancels the durable process.
--workflow-timeout is the separate, optional execution deadline persisted by
the workflow engine. A terminal failed, timed-out, or cancelled workflow exits
with code 1; completed and successfully created --no-wait runs exit with
code 0.
List/show/wait omit arbitrary input, output, tags, raw failure reasons, step
outputs and error text by default. --include-data explicitly includes only
workflow input/output/tags. --steps returns bounded metadata and safe error
diagnostics. A large swapped step state is not downloaded through the CLI; it
is reported as requiring the server-side bounded projection endpoint. Workflow
responses are capped at 2 MiB and list pages at 100 runs, so one tenant cannot
make a developer process consume unbounded memory.
Abort an interrupted staged deployment
brt deploy --adk leaves traffic safely fenced when old executions cannot
drain before the observation deadline. Reconcile the reported units and rerun
the identical deploy to resume it. If the staged version must instead be
abandoned before any schema mutation, terminally abort that exact deployment:
# Uses the production target from agent.json or bot.json.
brt bots deployments abort 00000000-0000-5000-8000-000000000001 --confirm
# Works without a project link when the exact numeric bot is supplied.
brt bots deployments abort 00000000-0000-5000-8000-000000000001 \
--bot-id 34 --confirm --jsonThe command first verifies that the deployment is still in the pre-schema
staged or fenced phase and asks for confirmation. It then reads the current
environment fence generation and sends one generation-CAS abort request. It
does not reuse the generation stored on the deployment: traffic may already
have been unfenced by an earlier recovery step, in which case the environment
is authoritatively one generation ahead.
Cloud preserves the active version, makes the staged version permanently
non-activatable, and leaves traffic unfenced. The command succeeds only for the
exact terminal pair failed / BOT_DEPLOYMENT_ABORTED; schema-mutated or
otherwise advanced deployments fail closed. Repeating the command after a lost
response is idempotent. --confirm is the non-interactive approval flag; no
public fence-generation override exists because that CAS value must be read
from Cloud immediately before mutation.
Upgrade an installed integration
brt integrations install <name@version> only creates a new connection. To
move one existing ADK agent installation to another published exact version,
use upgrade:
# Production target from agent.json; alias defaults to the integration name
brt integrations upgrade [email protected] --alias primary
brt deploy --adk
# Development target previously established by brt dev
brt integrations upgrade [email protected] --alias primary --dev
# Explicit rollback is the same atomic operation targeting the former version
brt integrations upgrade [email protected] --alias primaryThe command accepts only canonical exact SemVer refs. It lists the selected
bot's installations and resolves exactly one current installation by effective
alias. An explicit stored alias has priority. If the stored alias is empty, as
with a default install, the canonical integration name or its unqualified last
segment can select it. Missing and ambiguous matches fail before mutation. The
command rejects an already-current ref, then sends one atomic direct repoint
request. There is no separate preflight endpoint. Cloud validates catalog
trust, publication, stored config/secrets, and webhook authentication
compatibility inside the repoint transaction. Any non-2xx response leaves
local project files unchanged.
Cloud atomically repoints the existing installation: installation ID, alias,
webhook ID, status, and credentials are preserved, and no second installation
is created. The CLI never calls register automatically.
After repoint, the selected dev or production dependency snapshot is refreshed.
A running dev watcher picks up its dev snapshot; production always requires the
next brt deploy --adk. --wait is retained in the command surface but rejected
before target lookup or mutation: Cloud does not yet expose runtime-host
readiness. A local refresh error after a successful repoint exits non-zero while
stating that server-side repoint already completed and printing the symmetric
rollback command.
The repoint POST is non-idempotent. Only a Cloud 4xx is a definitive rejection.
If the connection drops, a successful response is malformed or inconsistent,
or any 5xx is returned, the CLI reports the outcome as unknown and leaves
local files unchanged. Inspect the installation's current ref first; only if the
target ref is active should you use the printed shell-safe rollback command. Do
not create or register a second installation during recovery.
Rebrand boundary (hard rule)
brt is rebranded only on our user-facing surface (CLI name brt, help/banner
text, default cloud host, ~/.brt home, BRT_ env prefix). It does not
rename what the runtime/SDK consume:
@botpress/*npm packages (@botpress/sdk,@botpress/client,@botpress/chat) — these are the SDK the integrations depend on.- the
.botpress/build/output dir andbp_modules/install dir the toolchain emits and resolves.
Renaming those would break codegen and bundle execution.
Cloud repoint
The only functional cloud-base config is src/consts.ts
(productionBotpressDomain + the default*Url constants), all pointed at
https://botruntime.ru. The cloud commands (login, deploy, bots,
integrations, …) use @botpress/client against that host; our cloudapi
mirrors the Botpress admin API, so a base-URL repoint is sufficient. Per-endpoint
contract parity is owned by api/ (the cloudapi server), not this CLI.
Install from npmjs
bun add -g @holocronlab/brt
brt login
brt init my-bot && cd my-bot && brt build && brt deployRequires bun >= 1.3.
Runtime logs
brt logs reads the selected bot through the workspace profile. Production
uses the canonical project link or a numeric --bot-id override. --dev
resolves the cached opaque runtime target, or an opaque --bot-id override,
and queries its attested numeric target bot. Passing an opaque runtime ID
without --dev remains a production-target error.
brt logs --follow
brt logs --conversation-id conv_123 --dev
brt logs --since 2026-07-17T18:00:00Z --dev --localRuntime traces
brt traces reads the selected profile's trace API. It returns the complete
stored span content, including attributes, platform payload, tool input/output
and runtime exceptions. Trace content is not redacted: the bot developer owns
the data sent by their bot and must delete traces when they are no longer needed.
Access remains scoped to the selected workspace and bot.
# Production target from agent.json (or bot.json for a classic project)
brt traces --conversation-id conv_123
brt traces conversation=conv_123 error since=1h
# Attested dev target created by brt dev; --local selects the local stack/profile
brt traces --conversation-id conv_123 --dev
brt traces --conversation-id conv_123 --dev --local
# Botpress-compatible tokens; workflow/action match rows, trace drills into a tree
brt traces conversation=conv_123 workflow=onboarding
brt traces conversation=conv_123 trace=0123456789abcdef0123456789abcdef
brt traces conversation=conv_123 trace=0123456789abcdef0123456789abcdef --verbose
# Extended typed API filters; --no-error selects effective non-error rows
brt traces --conversation-id conv_123 --status ok --source otlp --name autonomous.tool
brt traces --conversation-id conv_123 --no-error --action lookup-order
# Stable machine output and resumable cursor pagination
brt traces --conversation-id conv_123 --limit 100 --json
brt traces --conversation-id conv_123 --limit 100 --next-token 456 --jsonSupported compatibility tokens are error, conversation=<id>,
workflow=<name>, action=<name>, trace=<id>, since=<duration>,
until=<duration>, and limit=<n>. Relative durations such as 30s, 5m,
and 1h are converted once to absolute RFC3339 bounds. Equivalent named flags
are available, together with --status, --source, and --name. A conversation
is required unless workflow, action, or exact trace is provided; unscoped
workflow/action queries also require since. Use a returned traceId with
trace=<id> to fetch its full tree.
Accepted --source values are otlp, cognitive_v2, cognitive_action,
integration_action, and observation. Accepted --name values are the
canonical span names: request.incoming, handler.conversation,
handler.event, handler.trigger, handler.workflow, autonomous.execution,
autonomous.iteration, autonomous.tool, chat.sendMessage,
state.saveAllDirty, state.save, cognitive.request,
cognitive.generateText, cognitive.generateContent, integration.action,
and observation.
Human output prints tool input/output plus the exception code and message for
failed spans; --verbose also prints the stack and complete attributes/payload.
JSON output always includes the complete stored span content.
The cloud API deliberately does not provide unscoped listing or follow mode.
trigger remains unavailable until the server exposes a bounded typed trigger
name. include-llm is unnecessary and rejected: hosted output already contains
the attributes and payload stored by the platform.
Production requires canonical positive-decimal workspaceId and botId
coordinates matching the selected profile. Development requires an opaque,
stack-scoped runtime target previously established by brt dev; it never
silently falls back to production or to a default workspace. Authentication,
target, network, HTTP, and response-shape failures exit non-zero with no partial
trace output.
Privacy-safe conversations
brt conversations follows the current Botpress ADK CLI command shape with
separate list and show operations, but reads the selected cloud target
instead of a local SQLite trace store. Conversation tags and message content
are never printed. show builds a compact typed timeline; use brt traces for
the complete stored span.
# Production target from the canonical project link
brt conversations list
brt conversations list limit=5 since=1h
brt conversations show conv_123
brt conversations show conv_123 since=24h limit=50
brt conversations show conv_123 --until 2h --limit 100 --json
# Attested development target; --local only selects the linked stack
brt conversations list --dev
brt conversations show conv_123 --dev --local
# Stable machine output and resumable pagination
brt conversations list --limit 100 --json
brt conversations list --limit 100 --next-token 456 --json
brt conversations show conv_123 --limit 100 --json
brt conversations show conv_123 --limit 100 --next-token 456 --jsonlist accepts Botpress-compatible limit=<n> and since=<duration> tokens;
the equivalent named flags are also available. --next-token resumes from the
strict positive-decimal server cursor. JSON list output contains only id,
timestamps, channel, integration, and messageCount.
show reads at most 20 raw trace rows by default instead of draining the
complete conversation. It accepts since, until, and limit as either
key=value tokens or --since, --until, and --limit flags. limit is the
number of trace rows fetched before grouping, not the number of turns; its
range is 1–10000, matching brt traces. Values such as 30s, 5m, 1h, or
2d are look-back durations. Absolute RFC3339 timestamps are also accepted.
Both bounds are resolved once from one command-scoped clock instant, so
multi-page retrieval cannot move the window.
Limits up to the 1000-row backend page maximum issue one timeline request.
Larger explicit limits can issue sequential requests, but never read beyond the
total row limit. JSON show output adds traceCount, turnCount, nextToken,
and truncated while preserving schemaVersion: 1. Human output prints the
next token and a continuation command. Reuse the same absolute time bounds and
pass --next-token <cursor> to read the next, older window.
The timeline contains grouped trace IDs, timestamps, duration, typed status,
typed trigger, tool metadata, and bounded error kinds. It never includes
prompts, model responses, tool input/output, documents, message payloads,
conversation tags, or unfiltered trace attributes/payload. Use
brt traces conversation=<id> trace=<traceId> --verbose to inspect the full
bounded exception diagnostics for a failed turn.
conversations show intentionally has neither --follow nor --include-llm:
the hosted multi-tenant API is not the Botpress local developer store, and the
timeline remains metadata-only. Production and development use the same
filters and fail-loud profile-auth rules; only target resolution differs.
Client-side bounding avoids downloading the whole timeline, but does not make
the server project compact trace fields before transport. A compact hosted
conversation projection remains a separate Botforge backend optimization.
Hosted evals
brt eval follows the current Botpress ADK eval/run-history shape while using
the hosted runtime workflow and bounded cloud persistence. A bare
brt eval [name] and the explicit brt eval run [name] both start the deployed
builtin_eval_runner; runs lists or inspects persisted results.
# Sync local evals/manifest + private fixtures, then run the hosted workflow
brt eval run
brt eval greeting
brt eval run greeting --tag smoke --type regression
brt eval run --judge-model openai:gpt-4o
brt eval run --repeat 10 --max-concurrency 2 --min-pass-rate 0.9
# Keep the tunnel runtime connected in terminal 1
brt dev
# Target that attested dev runtime from terminal 2
brt eval run --dev
brt eval runs --dev --latest
# Hosted history, detail, pagination, and stable machine output
brt eval runs --limit 10 --status completed
brt eval runs 101 --verbose
brt eval runs --latest --json
brt eval runs --limit 10 --next-token MTAw --jsonProduction hosted eval requires the canonical positive-decimal project link and
the per-bot key saved by brt link --key-stdin or provisioning. Development uses
the selected profile PAT narrowed by the opaque runtime bot identity previously
attested by brt dev. --local is accepted only together with --dev, so the
two authority modes cannot be mixed implicitly.
brt eval run --dev executes against the live tunnel bot. Keep brt dev
running in another terminal for the run. After a live tunnel disconnects, the
CLI coalesces duplicate close/error signals and retries with bounded exponential
backoff for up to 120 seconds. Exhausting that budget fails loudly.
Interactive Chat uses the same explicit target model:
brt chat # production target from the canonical link and workspace PAT
brt chat --dev # attested dev runtime and profile PATThe CLI ensures the exact compatible first-party Chat integration in the
selected environment. Production provisioning uses the workspace PAT with the
canonical workspace/bot target; the conversation itself uses the Chat
webhook/user identity. It does not require a copied per-bot key. --local is
valid only together with --dev.
Administrative configuration commands use the selected workspace profile in
both environments. In production, brt config set/list/rm and
brt secret set authenticate with the workspace PAT and the canonical
workspace/bot coordinates; they do not require a copied per-bot key. Cloud
rechecks workspace membership and the owner/admin role before writes. Secret
values remain write-only and are accepted only through stdin or a value file.
On botruntime cloud, brt dev links the isolated development runtime to the
canonical production bot shown in the console. The link is also restored for
an existing development target the next time brt dev starts. The development
bot keeps its runtime ID and hosted eval history; production and development
data remain separate and the console only groups them for navigation.
Repeated attempts are isolated runs; the aggregate contains pass rate, stable/flaky classification, p50/p95 duration, and a failure histogram keyed only by assertion kind. Fixture contents, signed URLs, actor messages, and tool payloads are excluded from the manifest result and aggregate output.
The machine envelope has schemaVersion: 1 and only allowlisted target, run,
entry, verdict, timing, error-kind, and typed assertion metadata. Prompts,
user/bot messages, model responses, evidence, tool input/output, documents,
raw evaluator errors, and raw workflow failure reasons are never written to
stdout or stderr. A failed suite still prints its safe result, then exits
non-zero. Auth, target, network, HTTP, cursor, timeout, and malformed-response
failures also exit non-zero with remediation.
