Quick start¶
How do you go from no Brama state to one answered request? This page is the
one happy path: install an exact release, run the safe first command,
provision the installation's trust material, start the gateway through its
launcher, and verify it with the two health endpoints and one model listing.
Everything else — client provisioning, production ingress, failure guidance —
lives in ONBOARDING.md, configuration,
and the runbook.
Install an exact release¶
Download the release for your platform from https://brama.wisent.com/download,
verify the manifest's signature and the archive's digest, and unpack it, as
Download shows step by step. Pin
the version release.json names: installation and rollback always
name an exact release.
Maintainers working on unreleased source run the same commands from a
checkout with cargo run --locked -- instead of ./bin/brama.
Run the safe first command¶
detect reads local hardware, performs no provider request, reads no
credential, creates no Brama state, and incurs no model cost. Captured from
a 0.2.38 development build (values are host-specific):
$ ./bin/brama detect
GPU Type: apple_silicon
GPU Name: Apple M2 Max
VRAM: 48.0 GB
RAM: 64.0 GB
CPU Cores: 12
CUDA: false
Metal: true
$ ./bin/brama version
{"product":"brama","version":"0.2.38","source_revision":"development","platform":"development-host","built_at":"not-recorded"}
Neither command starts a service.
Provision trust material once¶
Serving traffic takes more than the archive. The release ships no signing key: the workload registry pins the absolute path and SHA-256 of the binary allowed to redeem a capability, and a build machine cannot know either. Provision this installation once:
bin/provision-skarbiec-trust
This writes the signed policy, workload registry, trust root, receipt
command, and workload proof key. Re-running it replaces the installation's
identity, so it refuses without --force. The launcher refuses to start
until this material exists.
Start the gateway¶
src/release/bin/start-with-skarbiec
The launcher is the supported start path: it materializes the vault, starts
the owner-bound capability socket, reads client bearers and request-sign
identities from their Skarbiec items, assembles BRAMA_MODEL_ALIASES and the
capability maps, and finally execs brama serve --port 8080 (override with
BRAMA_PORT_OVERRIDE or PORT). Starting the binary directly fails closed —
captured, exit 1:
Server error: BRAMA_MODEL_ALIASES is required and is assembled by
src/release/bin/start-with-skarbiec from the sealed policy directory. Starting the
binary directly cannot obtain it: launch the gateway through that launcher, or
export the variable yourself. Restarting an unlaunched process will not
repair this.
The gateway binds loopback unless BRAMA_BIND_ADDRESS names an IP address.
Standalone Brama Desktop instead launches its bundled binary with
brama serve --local-credentials-stdin, passing a provider-to-credential
JSON object once over standard input; the credentials live only in zeroizing
process memory.
The desktop runtime requests an operating-system-assigned port and reads the
bound address from its own child's startup output. Its health check reports the
actual GET endpoint and transport error, non-success HTTP status and
body, JSON decoding error, or unexpected build.product. Desktop
shows that cause as its startup error. A successful health check establishes
process identity, not working provider credentials or a completed model
request.
The desktop repository's tests/local-runtime qualification runs
the real Brama executable through the same local runtime controller. Configure
BRAMA_RUNTIME_BIN, its independently selected
BRAMA_TEST_RUNTIME_SOURCE_REVISION,
BRAMA_TEST_DESKTOP_SOURCE_REVISION, and an unused
BRAMA_DESKTOP_STATE_DIR below that checkout's .build.
Run swift test --filter LocalRuntimeHealth. The journey observes
the bound endpoint and build identity, stops only its own isolated child, and
checks that the closed listener reports the failed health operation.
BRAMA_TEST_HEALTH_REFUSALS names a JSON array of actual unhealthy
service origins and their independently observed causes, with fields
origin and observedCause. Use real HTTP-status,
malformed-JSON and wrong-product observations; the journey creates no substitute
HTTP server. Reports and health responses remain under
.build/real-tests/local-runtime. These checks do not qualify
native graphical rendering, provider readiness or inference.
The native Runtime and readiness readers also retain failed response-header reads, body-read failures with observed byte count and HTTP status, and JSON decoder causes. Non-success runtime responses use the same typed refusal decoder as control operations, preserving the gateway's inventory or authorization cause rather than replacing it with “unexpected response.” Readiness still accepts the documented 503 readiness body. A transport failure is not described as a deadline expiring.
For native-client refusal qualification, BRAMA_TEST_NATIVE_READ_REFUSALS names a JSON array of real endpoint observations: {"origin":"https://your-isolated-gateway.example","surface":"stats","observedCause":"independently observed cause"}. Supported surfaces are health, stats and readiness; stats cases require BRAMA_TEST_STATS_BEARER from the isolated fixture. Run swift test --filter actualNativeReadRefusalsRetainObservedCauses with BRAMA_TEST_DESKTOP_SOURCE_REVISION. Use actual HTTP refusal, interrupted-body and malformed-JSON observations, not a simulated server. Reports contain diagnostic text but no bearer. The real child journey also checks the native health reader's source identity and both native readers after its owned listener closes. These API journeys do not establish visual rendering or provider success.
Verify liveness, then readiness¶
$ curl -s http://127.0.0.1:8080/health
{"build":{...,"version":"0.2.38"},"dependencies":"not_probed","status":"ok"}
/health proves only that the process is up; its body says
"dependencies": "not_probed". Do not stop here — it answers ok even when
every credential redemption is refused.
$ curl -s http://127.0.0.1:8080/readyz
{..., "providers":[{"credential":true,"provider":"openai"}], "ready":true,
"reason":"every configured provider credential was obtained, every active
subscription redeemed, and every vault account carries the agent tag that
makes it routable", ...}
/readyz redeems one capability per configured provider and one credential
per active subscription, and is the only evidence the gateway can serve. A
503 body names the providers or subscriptions that failed, without secret
material — the five reason sentences are decoded in the
runbook; the evidence rule is stated in
architecture.
First authenticated request¶
GET /v1/models is the first non-billable machine workflow:
$ curl -s -H "Authorization: Bearer $BRAMA_CLIENT_TOKEN" \
http://127.0.0.1:8080/v1/models
{"data":[{"id":"302ai/MiniMax-M1","object":"model","owned_by":"302ai"}, ...]}
Then one completion — this spends real provider quota:
curl -s -H "Authorization: Bearer $BRAMA_CLIENT_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"model": "wisent-backend",
"messages": [{"role": "user", "content": "Say hello in one sentence."}]}' \
http://127.0.0.1:8080/v1/chat/completions
The response is one OpenAI-compatible chat.completion document; add
"stream": true for server-sent events. The model name must be an alias your
bearer's allowlist permits, a canonical provider/model route, or a selector
— the vocabulary is in concepts/alias and
concepts/client-identity, and the full
request contract in http-api.