The official CLI for the RawTree analytics platform.
Built for humans, AI agents, and CI/CD pipelines.
The package/repo name is rawtree-cli, and the command you run is rtree.
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/rawtreedb/rawtree-cli/releases/latest/download/rawtree-cli-installer.sh | shgit clone https://github.com/rawtreedb/rawtree-cli.git
cd rawtree-cli
cargo install --path .git clone https://github.com/rawtreedb/rawtree-cli.git
cd rawtree-cli
cargo build --release
./target/release/rtree --helpUse a user login and select a region from the organization's catalog:
rtree --org acme cluster regions
rtree --org acme cluster sizes --region-id <REGION_ID>
rtree --org acme cluster create --region-id <REGION_ID> --name production --replicas 2 --min-size 2:8Size discovery and creation use the selected region's deployment. Omitting --region-id preserves the default backend. A selected region without a valid deployment is rejected, except for the legacy public US East region. API keys keep their embedded routing and cannot override it with --region-id.
If you installed with the GitHub Releases installer, update in place:
rtree updatertree update --json prints {"updated":true,"previous_version":"<old>","version":"<new>"},
or {"updated":false,"version":"<current>"} when already on the latest release.
Source installs aren't managed by the installer; update them with git pull && cargo install --path ..
# Authenticate (browser flow by default)
rtree login
# Create and select a database
rtree database create analytics
rtree database use analytics
# Insert a JSON row
rtree insert --table events --data '{"event":"signup","user_id":1}'
# Run a query
rtree query --sql "SELECT count(*) FROM events"
# Open the UI for the current database
rtree open- Interactive login selection:
rtree login - Direct API key save:
rtree login --api-key rt_123 - Select a database during auth in a specific cluster:
rtree login --org team-alpha --cluster production --database analytics
Interactive login offers browser-based Rawtree authentication or securely prompts
for an existing API key. Non-interactive and --json login continue to use
browser-based authentication unless --api-key is provided.
When stdin is not a terminal, login uses JSON automatically. Browser login
prints a device_approval_required JSON event to stderr before waiting for
approval. Open its verification_uri_complete link in a browser on any device.
JSON mode does not open a browser automatically; interactive terminals can use
--no-browser to print the link without opening it.
{"event":"device_approval_required","verification_uri":"<approval page>","verification_uri_complete":"<approval link>","user_code":"ABCD-EFGH","expires_in":600}Read stderr as newline-delimited JSON while the command is running. Stdout
contains the final JSON result. A successful login exits with code 0. If a
selection is needed after approval, stdout contains one of these responses and
the command exits with code 2:
{"needs":"org","orgs":["team-alpha","team-beta"]}
{"needs":"cluster","organization":"team-alpha","clusters":["production","staging"]}
{"needs":"database","organization":"team-alpha","cluster":"production","databases":["analytics","billing"]}Rerun with the corresponding --org, --cluster, or --database flag, retaining
the selections already made. A single available option is selected automatically.
An empty choices array means no resources are available at that level. Invalid
selections and API failures produce a JSON error on stderr and a nonzero exit.
Credentials and defaults are saved only after login completes. An incomplete login leaves the existing config unchanged; each retry requires browser approval again. Pass all three selectors to avoid selection retries:
rtree login --org team-alpha --cluster production --database analyticsWhen using --api-key, the CLI validates the key and any supplied organization/cluster
selectors with the server before saving it. Explicit selections are saved as defaults.
If the server omits organization/database metadata and no selection was supplied,
those settings remain unset. Commands that require a database still need --database,
RAWTREE_DATABASE, or a saved default from rtree database use <name>.
With --json, API key login returns (unset selections are null):
{"success":true,"config_path":"<path>","database":"<name>","organization":"<name>","cluster":"<name>"}--api-keyflagRAWTREE_API_KEYenvironment variable- Local config file
rtree logoutLogout clears the local config, including any saved API URL, so the next run uses
the default https://api.rawtree.com endpoint unless an override is provided.
Config file location:
- Unix:
~/.config/rtree/config.json
Resolution priority by setting:
- API KEY:
--api-key->RAWTREE_API_KEY-> config file token - API URL:
--api-url->RAWTREE_API_URL-> config file ->https://api.rawtree.com - Database:
--database->RAWTREE_DATABASE-> config file default database - Organization:
--org->RAWTREE_ORG-> config file default organization - Cluster:
--cluster->RAWTREE_CLUSTER-> config file default cluster
API keys remain restricted to their bound cluster regardless of which selector source is used.
Top-level commands:
login,logoutdatabase,organization,integration,service-account,federation-issuer,federation-rule,cluster,key,table,workflowquery,insertping,docs,status,open,completions
Global flags:
--api-url <URL>--org <ORG>--cluster <CLUSTER>--json
rtree organization list
rtree organization create team-alpha
rtree organization use team-alpha
rtree cluster list
rtree cluster use production
rtree database list
rtree database create analytics
rtree database use analyticsDatabase creation saves the selected organization, cluster, and new database locally.
With --json, creation returns {"database":{"name":"analytics"}}; listing returns
{"databases":[{"name":"analytics","s3_storage":null}]}. Database output no longer
adds organization metadata that is absent from the API response.
Organization admins can create and list service accounts after rtree login:
rtree service-account create build-jobs --org team-alpha --description "CI workloads"
rtree service-account create deployment --org team-alpha --role admin
rtree service-account list --org team-alpha --jsonNames are immutable and unique within the organization: use 1–128 lowercase
letters or digits separated by single hyphens. Descriptions accept up to 2000
UTF-8 bytes. The role defaults to member; admin is also supported. These
commands create identities without credentials; API key permissions are
configured separately. API keys cannot create or list service accounts.
The commands use the usual organization selection (--org, RAWTREE_ORG, or
the saved default), without requiring a cluster or database. JSON creation
returns the account object; listing returns {"service_accounts":[...]}.
Manage organization issuers and cluster rules with list, get ID, create,
update ID, and delete ID. Use rtree login as an organization admin. API keys
and workload access tokens cannot manage federation configuration.
rtree federation-issuer create --org team-alpha --name github \
--issuer-url https://token.actions.githubusercontent.com --json
rtree federation-issuer list --org team-alpha --json
rtree federation-issuer get "$ISSUER_ID" --org team-alpha --json
rtree federation-rule create --org team-alpha --cluster production \
--name ci-read --issuer-id "$ISSUER_ID" \
--allowed-audiences rawtree \
--claim-conditions '{"sub":"repo:acme/app:ref:refs/heads/main"}' \
--principal-type service_account --principal-id "$SERVICE_ACCOUNT_ID" \
--permission read_only --database default --enabled true --json
rtree federation-rule list --org team-alpha --cluster production --json
rtree federation-rule get "$RULE_ID" --org team-alpha --cluster production --jsonSet the IDs from the create responses or existing resources. For a personal
rule, use --principal-type user with your own user ID. Repeat
--allowed-audiences for multiple audiences. Replace --permission with one or
more --database-roles ROLE flags to use database roles; the two access modes
are mutually exclusive. --database and --enabled true|false are explicit
rule configuration, not inherited from the active database.
Issuer discovery is the default. For a separate signing-key URL, pass
--jwks-source explicit_url --jwks-url https://issuer.example.com/keys.
Updates replace the entire configuration (PUT). Use update ID with all
required create flags. Omitted optional fields, including description, are
cleared. Changes invalidate existing workload tokens. Issuers can only be
deleted after their referencing rules are deleted:
rtree federation-rule delete "$RULE_ID" --org team-alpha --cluster production --json
rtree federation-issuer delete "$ISSUER_ID" --org team-alpha --json--json preserves the API response: arrays for lists, full objects for
get/create/update, and null for successful deletion. Objects include the
configuration, IDs, and timestamps. Issuers use the organization UUID path;
rules use /v1/federation-rules with organization and cluster query parameters.
Rule scope must be selected through flags, environment variables, or saved CLI
configuration. An unknown organization never falls back to another one.
rtree format "select 1"
rtree format -q "select 1"
rtree format --query "select 1"
rtree format --sql "select 1; select 2"
cat query.sql | rtree format
cat query.sql | rtree format -
rtree format < query.sql > formatted.sql
rtree format --json < query.sqlUse stdin redirection or a pipe for large SQL documents to avoid shell argument limits.
Plain output is the complete formatted SQL, with its whitespace preserved.
--json returns { "formatted": "..." }. --sql, --query, and -q are aliases;
provide SQL once, either positionally or with one flag. Omit SQL or use - to
read from stdin, including --sql -, --query -, or -q -.
--database, --org, and --cluster honor the usual environment and
saved defaults; a database is optional for formatting.
Formatting uses the native RawTree formatter without executing SQL or adding
database query logs. Multiple statements and literal values are preserved.
Inline INSERT ... VALUES data is copied verbatim without completeness or schema
validation. The API accepts a 50 MiB JSON request, allows 100 MiB of formatted
output, and times formatting out after 30 seconds. The CLI allows 120 seconds
for the entire HTTP request, including upload/download. Ctrl-C cancels the CLI
request. Errors produce no partial formatted output.
Requires deployment of Platform PR #1468,
which adds POST /v1/query-format.
# Positional SQL
rtree query "SELECT * FROM events LIMIT 10"
# Equivalent named forms
rtree query -q "SELECT * FROM events LIMIT 10"
rtree query --query "SELECT * FROM events LIMIT 10"
rtree query --sql "SELECT * FROM events LIMIT 10"
# SQL from stdin
rtree query < query.sql
cat query.sql | rtree query
cat query.sql | rtree query -
# JSON output
rtree query --json --sql "SELECT * FROM events LIMIT 10"As with format, provide SQL once. Stdin also works with --sql -, --query -,
or -q -.
# Inline JSON
rtree insert --table events --data '{"event":"page_view"}'
# JSON/JSONL file
rtree insert --table events --file ./events.jsonl
# Public URL to JSON/JSONL
rtree insert --table events --url https://example.com/events.jsonlURL imports wait for completion and print the inserted row count and query ID.
With --json, the result is
{"inserted":1000} (or {"inserted":null} when the count is unavailable).
rtree key list
rtree key create --name ci --permission read_write
rtree key create --name temporary-ci --permission read_only --expires-at 2027-01-01T00:00:00Z
rtree key create --database analytics --name analytics-ci --permission read_write
rtree table list --database analytics
rtree table describe --database analytics events
rtree table create --database analytics events --sorting-key 'region, ifNull(cityHash64(host, instanceId), 0)'
rtree table update --database analytics events --sorting-key 'region, toStartOfHour(timestamp)'Omit --sorting-key when creating a table to choose a key automatically per part. table describe shows the current sorting key as a string. Updating the key affects new parts and later merges; existing parts may keep their previous key until they are merged. A custom sorting key cannot be reset to automatic.
API keys belong to a cluster. key list and key delete do not accept --database;
listing includes each key's default database. key create --database selects the
new key's default database, using RAWTREE_DATABASE or the saved selection when
omitted. If none is selected, the server uses default.
key create --expires-at accepts a future RFC 3339 timestamp with a timezone.
The server validates and normalizes it to UTC. Omit the flag for a key that never
expires. Create/list output includes expiration (never in text, null in JSON);
older servers that omit the field are also supported. Expiration is fixed at
creation; create a replacement key to change it. There is no key update command.
Workflows run saved SQL on demand or on a schedule and deliver results to sinks.
rtree workflow list
rtree workflow create --name errors --database analytics --schedule-cron "* * * * *" \
--sql "INSERT INTO error_counts SELECT count() FROM events WHERE level = 'error'"
rtree workflow create --name on-demand --database analytics --sql "SELECT 1"
rtree workflow create --name alerts --schedule-cron "* * * * *" --schedule-enabled false --sql - \
--sink '{"type":"table","settings":{"database":"analytics","table":"alerts"}}' \
--sink @http-sink.json \
< alerts.sql
rtree workflow get <id>
rtree workflow update <id> --schedule-cron "*/5 * * * *"
rtree workflow update <id> --schedule-cron null
rtree workflow update <id> --schedule-enabled false
rtree workflow update <id> --clear-sinks
rtree workflow delete <id>
rtree workflow run <id> --idempotency-key deploy-42
rtree workflow runs <id>
rtree workflow cancel <id> <run-id>
rtree workflow logs <id> --since 1h
rtree workflow sink create <id> @http-sink.json
rtree workflow sink update <id> <sink-id> '{"settings":{"table":"alerts_v2"}}'
rtree workflow sink delete <id> <sink-id>
rtree workflow create --help
rtree workflow update --help
rtree workflow sink create --help
rtree workflow sink update --helpWorkflow commands need both an organization and a cluster (--org/--cluster,
the environment, or the saved defaults). API keys must have admin permission.
create uses the selected database when --database is omitted.
The CLI sends --database and --sql inside the API's query object. On update,
each flag changes only that query field; the other field stays unchanged.
Creating a workflow without --schedule-cron makes it manual-only. The CLI explicitly
sends schedule: null, preserving its manual-only default. Use --schedule-cron null to
remove an existing schedule. The obsolete --interval-seconds flag is rejected.
--schedule-cron "*/5 * * * *" runs every five minutes in UTC. Five-field expressions use
minute, hour, day-of-month, month, and day-of-week; six fields include leading
seconds. The API validates the expression. Requests nest cron and pause state in
schedule, for example {"schedule":{"cron":"*/5 * * * *","enabled":false}}.
On update, omitting --schedule-cron preserves the schedule. --schedule-enabled false pauses it and
--schedule-enabled true resumes it without changing the cron expression. Adding cron to a
manual-only workflow enables scheduling by default; changing an existing cron
preserves its pause state unless you also pass --schedule-enabled true|false.
--schedule-enabled accepts an explicit boolean and requires a cron expression on create. --schedule-cron null cannot be
combined with pause/resume flags. Manual runs remain available while paused.
Text output shows active, paused, or manual, the UTC cron expression, and
the next scheduled run when available. JSON output preserves the API response.
Sinks are JSON objects, up to five per workflow. --sink takes an object, an array
of objects, @path to read a file, or - to read stdin, and can be repeated. Each
sink has a type and its settings:
{"type":"table","settings":{"database":"analytics","table":"alerts"}}
{"type":"http","settings":{"url":"https://example.com/hook","headers":{"Authorization":"Bearer ..."}}}
{"type":"slack","settings":{"integration_id":"<integration-id>","channel_name":"#alerts"}}Each create/update command's --help documents the fields, rules, and examples
for table, HTTP, and Slack sinks. Sink files keep header credentials out of shell
history. The API validates sinks and names the field it rejects. --sql - and
--sink - cannot both read stdin; use a file for one of them.
Table sinks require settings.database and settings.table. New HTTP sinks
require settings.url; settings.headers is optional. Slack sinks require the
settings.integration_id UUID of a connected Slack integration in the workflow's
organization and exactly one of settings.channel_id or settings.channel_name.
The API resolves channel names to IDs when saving. The RawTree app must be a
member of private channels. Find the integration ID with the
integration commands.
On update, --sink replaces the whole list. Include each existing sink's id to
keep it; an existing HTTP sink may omit settings, or its url or headers, to
retain them. rtree workflow get shows only the names of an HTTP sink's headers, so
send {"type":"http","id":"<sink-id>"} to keep one unchanged.
Existing table sinks require their full database/table settings. Existing Slack
sinks require their integration ID and one channel field; use the saved channel
ID to keep the same channel. Do not send both channel_id and channel_name
from a workflow response back in a sink input. Omitting --sink keeps all sinks;
--clear-sinks removes them all.
rtree workflow sink changes one sink without resending the others, and takes the
same object, file, or stdin input as --sink, but does not accept arrays.
create takes a sink without an id. update takes
the sink's ID, shown by rtree workflow get, and the settings to change, such as
{"settings":{"table":"alerts_v2"}}; settings left out keep their stored values.
HTTP headers follow the same rules as in --sink: the map lists every header to
keep, null keeps a stored value, and headers left out are removed. For example,
{"settings":{"headers":{"Authorization":null,"X-Region":"eu"}}} keeps
Authorization, adds X-Region, and removes any other header. A sink's type cannot
change, so delete it and create a new one instead.
To update one Slack sink, pass {"settings":{"channel_name":"#alerts-v2"}}
or {"settings":{"channel_id":"C0123456789"}}. Omit both channel fields to
keep the channel. integration_id is also optional on this partial update;
omitting it keeps the connected integration. For example:
rtree workflow sink create <id> \
'{"type":"slack","settings":{"integration_id":"<integration-id>","channel_name":"#alerts"}}'
rtree workflow sink update <id> <sink-id> '{"settings":{"channel_name":"#alerts-v2"}}'run returns once the run is accepted. Reusing an --idempotency-key returns the
same run instead of starting another. Logs cover the last 24 hours by
default, at most 7 days. Use --since/--until or --start-time/--end-time
to change the window.
Integrations connect an organization to external services. Slack integrations let workflow sinks post to Slack channels.
rtree integration add slack
rtree integration listadd slack opens the organization's integrations page in the browser, where
Slack's consent flow runs, and prints its URL. The page follows the API URL
(--api-url or RAWTREE_API_URL): hosted APIs open rawtree.com, or rawtree.dev
for development APIs, and other APIs,
such as a local gateway, open their own origin. RAWTREE_UI_URL overrides it.
list shows each integration's ID and Slack workspace. Integration commands need
an organization (--org, RAWTREE_ORG, or the saved default) and a user login
(rtree login); API keys are not accepted. Any organization member can list
integrations; connecting one requires an organization admin. JSON output
preserves the API response.
rtree --org team-alpha --cluster production logs --since 1h --status-codes 500Logs cover the selected cluster. The obsolete --database and --log-databases
flags are rejected because the API does not apply database filters.
rtree cluster list
rtree cluster list --json
rtree cluster sizes
rtree cluster create \
--name production \
--replicas 2 \
--min-size 2:8 \
--max-size 64:256 \
--idle-timeout-minutes 30
# Or create a cluster with customer-owned S3 storage
rtree cluster create \
--name customer-data \
--replicas 1 \
--min-size 2:8 \
--s3-storage-data-bucket acme-rawtree-data \
--s3-storage-data-path rawtree/data \
--s3-storage-backups-bucket acme-rawtree-backups \
--s3-storage-backups-path rawtree/backups \
--s3-storage-role-arn arn:aws:iam::123456789012:role/RawTreeS3Access \
--s3-storage-access-external-id rawtree-example
# Or choose explicit cluster identity with RawTree-managed default storage
rtree cluster create \
--name database-storage \
--replicas 1 \
--min-size 2:8 \
--s3-storage-access-external-id rawtree-database-access \
--s3-storage-access-resource-tag rawtree-customer-database
rtree cluster use production
rtree cluster status production
rtree cluster update production --idle-timeout-minutes 60
rtree cluster update production --idle-timeout-minutes 0
rtree cluster stop production
rtree cluster resume production
rtree cluster delete production--min-size is required and uses CPU_CORES:MEMORY_GIB format. --max-size
is optional; omitting it uses the minimum size for both bounds and disables
vertical autoscaling. Sizes are validated against the server's cluster size
catalog. Run rtree cluster sizes to see the currently available sizes; add
--json for a machine-readable response.
--idle-timeout-minutes is optional on create and update; omit it to use the
server default on create, and pass 0 to disable automatic idling.
Cluster creation forwards --s3-storage-access-external-id and --s3-storage-access-resource-tag when supplied.
The API generates omitted identity values independently as rawtree-<UUID>
using secure randomness and returns the saved values. The CLI does not generate
identity values. Both are immutable after creation.
Custom cluster storage requires --s3-storage-access-external-id to match the customer IAM role's
trust policy. --s3-storage-access-resource-tag may be supplied or generated.
Flag names follow the API field paths:
| Flag | API field | Available on |
|---|---|---|
--s3-storage-data-bucket |
s3_storage.data.bucket |
Cluster and database creation |
--s3-storage-data-path |
s3_storage.data.path |
Cluster and database creation |
--s3-storage-backups-bucket |
s3_storage.backups.bucket |
Cluster and database creation |
--s3-storage-backups-path |
s3_storage.backups.path |
Cluster and database creation |
--s3-storage-role-arn |
s3_storage.role_arn |
Cluster and database creation |
--s3-storage-access-external-id |
s3_storage_access.external_id |
Cluster creation only |
--s3-storage-access-resource-tag |
s3_storage_access.resource_tag |
Cluster creation only |
Cluster and database creation share --s3-storage-data-bucket, --s3-storage-backups-bucket, and
--s3-storage-role-arn; all three are required if any destination or role option is supplied. The optional
--s3-storage-data-path and --s3-storage-backups-path specify object-key prefixes.
rtree --org acme --cluster production database create analytics \
--s3-storage-data-bucket acme-rawtree-data \
--s3-storage-backups-bucket acme-rawtree-backups \
--s3-storage-role-arn arn:aws:iam::123456789012:role/RawTreeS3AccessDatabase creation reuses the cluster's saved identity: no external ID or tag is
accepted on database commands. Use rtree cluster status production to read the
External ID for the IAM trust policy and the resource tag value. Tag eligible
customer buckets and roles with rawtree.com/cluster=<resource-tag>.
These flags configure new resources; the API verifies access and provisions storage. The CLI does not create AWS buckets or IAM roles or migrate existing data. Omitting S3 options uses RawTree-managed cluster storage or, for a database, inherits its cluster's storage.
The API payload has an s3_storage object containing data and backups
destinations (each with bucket and optional path), plus role_arn. List/status
JSON always includes both destinations with explicit paths for custom storage
and preserves cluster s3_storage_access.external_id and
s3_storage_access.resource_tag; role ARNs and credentials are not returned. Older clusters without
saved identity show not configured in status output.
The former --s3-data-*, --s3-backup-*, --s3-backups-*, --s3-role-arn,
--s3-storage-external-id, --s3-storage-resource-tag, and legacy database
identity flags are rejected. This CLI targets
Platform PR #1482 and
must be released with that server contract.
Cluster lifecycle and provisioning changes are asynchronous. The create,
stop, resume, and delete commands return as soon as the API accepts the
request; they do not wait for the infrastructure operation to finish. After
creating, stopping, or resuming a cluster, run rtree cluster status <name-or-id> to follow its current state.
# Bash
rtree completions bash > ~/.rtree-completion.bash
# Zsh
rtree completions zsh > ~/.rtree-completion.zsh
# Fish
rtree completions fish > ~/.config/fish/completions/rtree.fishPrerequisites:
- Rust (stable)
Setup:
git clone https://github.com/rawtreedb/rawtree-cli.git
cd rawtree-cli
cargo check
cargo fmt --all -- --check
cargo test --lockedThe Tests workflow runs the CLI's unit and mock-API contract tests on pushes
to main and pull requests. New PR updates cancel obsolete runs. It also runs tests/live_platform.rs against the full
Platform Docker Compose stack on same-repository changes. That test uses the
Platform launcher to create a local organization and cluster, then checks CLI
database creation, insertion, querying, API key login, and deletion through the real API.
It also logs in with the local test user's email and password, verifies API access
using the saved session, logs out, and checks that credentials are cleared and API
access requires authentication again.
Workflow tests cover definition updates, manual and scheduled execution,
pause/resume, cancellation, idempotency, table sink delivery, per-sink changes,
and logs.
They run through the real CLI and clean up their workflows and databases.
The Platform repository continues to test API endpoints directly.
The Docker job checks out private rawtreedb/rawtree-platform at main. It
requires a read-only deploy key on the Platform repository, with its private SSH
key stored as PLATFORM_REPO_SSH_KEY in this repository's GitHub Actions secrets.
The job also requires DOCKERHUB_USERNAME and DOCKERHUB_TOKEN secrets to pull
the private RawTree server, keeper, and backend images. Use a read-only Docker Hub
token with access to those repositories.
The integration job uses Platform's arc-runner-set-platform-arm64 runner pool.
It reuses the published backend image
only when its source revision is an ancestor of the checked-out Platform main
and its backend release inputs are unchanged. It pulls the verified image by
digest; if the inputs differ or revision metadata is missing, it builds from
source. The frontend is built for the local test URL. Compose still starts the
full stack, waits for healthy services, and bootstraps the test identity. Build
and startup timings appear as separate CI steps. Private Platform layers are
never stored in the public CLI repository's Actions cache.
Fork pull requests run the unit and mock-API tests;
GitHub does not pass the private checkout secret to those runs.
To run the real test locally, start Platform from its checkout with
bash scripts/codex/run-local-compose.sh 18087, then set
RAWTREE_LIVE_API_URL=http://localhost:18087 and the
RAWTREE_LIVE_SESSION_TOKEN, RAWTREE_LIVE_ORGANIZATION, and
RAWTREE_LIVE_CLUSTER values from that checkout's ignored .env.local.
Also set RAWTREE_LIVE_EMAIL from
RAWTREE_LOCAL_BOOTSTRAP_EMAIL in the same file. The login test approves the
CLI device challenge with that bootstrap session, then checks saved-session use
and logout against the real API.
Run cargo test --locked --test live_platform -- --ignored in this checkout.
Run locally:
cargo run -- --help- Repository/package name:
rawtree-cli - Executable name:
rtree