Briefcase DocsOpen Briefcase ↗
SILICON BRIEFCASE / DOCUMENTATION

Using the briefcase CLI#

The CLI is the briefcase-client package with a memory and a face. Every command is a call on the package — the CLI has no capability the package lacks — and what it adds is remembering which deployment you meant, printing answers you can read, and giving a script an exit code it can branch on.

cargo install briefcase-cli      # installs the `briefcase` binary
briefcase --help                 # every command, every option
briefcase ls --help              # one command in detail

This guide targets CLI 1.0.1 and the first official API contract 1.0.0. Development 0.x releases are unsupported. For local development, install with cargo install --path clients/rust/crates/briefcase-cli.

Signing in#

First use Silicon IAM to sign in and request a short-lived token for the canonical Briefcase Application ID. Production sign-in never asks for your IAM password, verification code, or Application secret, and it never redirects a terminal login:

iam login --app-id 'tos>briefcase'
briefcase login <slt>
# Or run `briefcase login` and paste only the SLT at the hidden prompt.

The positional form exchanges the supplied SLT directly. To use the hidden prompt instead, run briefcase login with no token. A normal production login is always unscoped: IAM prompts you to select the organizations Briefcase may access, and Briefcase keeps that one token family for the selected set. For noninteractive IAM use, explicitly supply --grant-org tos,my-team or --all-orgs to IAM (the latter grants only memberships shown now). Briefcase's --org selects a workspace, never consent or a scoped login. When several granted organizations are available, commands that touch files ask you to choose with --org; no second IAM login is required.

The CLI connects to the hosted Briefcase service automatically. You do not need to find or enter a backend URL for normal use.

For automation, pipe that one-use SLT instead of putting it in argv:

printf '%s\n' "$BRIEFCASE_SLT" | briefcase login --slt-stdin

The deployment and current workspace preference are saved in {home_dir}/.briefcase/config.json. Briefcase exchanges the SLT for an access/refresh pair and stores the rotating session in {home_dir}/.briefcase/credentials.json with owner-only permissions. It preserves unscoped sessions and the IAM-selected organization list. A workspace preference cannot add grants. If IAM returns no active grants, revisit IAM to select organizations and sign in again; do not reuse cached access. It refreshes one minute before expiry and persists the new refresh token before sending the requested command. It records a refresh idempotency key before the network call, so an uncertain outcome reuses the exact token/key pair. A successful refresh invalidates the previous refresh token.

For local development or a separate deployment, --url is an optional override. URL selection is, in order: an explicit --url, BRIEFCASE_URL, the saved profile URL, then https://backend.briefcase.teamofsilicons.com/api/v1/. This default also applies to commands in a fresh, unconfigured profile; organization and authentication requirements still apply. An override must use the exact /api/v1/ base. HTTPS is required except on localhost or a loopback IP. Before presenting a single-use refresh token, the CLI performs the anonymous contract handshake unless --no-verify was explicitly selected, so an incompatible deployment cannot consume it.

State updates are atomic; credential, pending-mutation, and configuration read/modify/write transactions share a cross-process lock. Login, refresh, and environment mutations keep that lock through their one-time exchange, so two CLI processes cannot consume the same rotating credential or overwrite the newer result. Before an SLT exchange the CLI also stores a hash of the complete login intent and its idempotency key. If the response is lost or the process stops, rerun the exact command with the same SLT; the CLI reuses the key and recovers the original server response. Raw SLTs and IAM secrets are never written into the retry record.

Stored credentials remain bound to their canonical deployment origin. A scoped session also stays bound to its organization; an unscoped production session can select another currently reachable organization with --org. A test root always retains its owning organization, even with an unscoped IAM session. An incompatible --url or scoped/root --org override therefore fails before forwarding a stored credential. An explicit --token authorizes its own production destination override; it never authorizes forwarding a stored test root.

Save a named hosted profile, or explicitly select a local deployment:

briefcase login --org tos --save-as work
briefcase --profile work ls
briefcase login --url http://127.0.0.1:8080/api/v1/ --org tos --save-as local

--url, --org, --token, and --profile also read BRIEFCASE_URL, BRIEFCASE_ORG, BRIEFCASE_TOKEN, and BRIEFCASE_PROFILE, which is the usual shape for CI. State defaults to $SILICON_HOME/.briefcase when SILICON_HOME is present, otherwise $HOME/.briefcase. Missing state directories are created on the first write; an empty SILICON_HOME or a file path is an error. BRIEFCASE_HOME remains an explicit override of the complete state directory, with highest priority. You can also choose a persistent parent directory:

briefcase config home /path/to/existing-directory

The configured location must already be a directory; otherwise the command fails with not a directory. The choice is recorded in $SILICON_HOME/.briefcase-home (or $HOME/.briefcase-home when SILICON_HOME is absent), and takes precedence over that default parent. Changing SILICON_HOME selects a separate configuration and credential store; existing files are not moved automatically. BRIEFCASE_HOME still overrides the pointer.

briefcase status     # profile, deployment, token, and contract agreement
briefcase logout     # forget the token, keep the profile

--token/BRIEFCASE_TOKEN remains an explicit ephemeral override for CI and does not replace the stored rotating session. logout forgets only the production or --test session currently selected.

Help, IAM discovery, and authentication status#

briefcase --help
briefcase login --help
briefcase iam --json
briefcase login status --json

--help lists all top-level commands and shared options, with getting-started examples. Use briefcase <command> --help for its complete syntax. Help works without a home directory, saved profile, network connection, or login.

iam --json reads the selected deployment's public IAM configuration without sending a member access token. It returns app_id, test_environment_id, and iam_environment_id. Use the app_id when requesting the single-use SLT from IAM. Production returns null for both environment IDs. No app secret or app secret is printed. URL/profile overrides apply as usual.

login status --json checks the session with IAM and returns one JSON object:

{
  "authenticated": true,
  "actor": {
    "principal_id": "01990a9d-86f1-7000-8000-000000000001",
    "type": "carbon",
    "public_id": "cos:tester"
  },
  "organizations": ["tos"],
  "expires_at": 1789000000,
  "profile": "default",
  "url": "https://backend.briefcase.teamofsilicons.com/api/v1/",
  "test_environment_id": null
}

The actor type is carbon or silicon. IAM supplies the public identifier through active organization snapshots; if no organizations are granted, public_id is null and the stable principal UUID still identifies the actor. No --org is required, including for logins with several granted organizations. A saved session refreshes before expiry using the normal atomic rotation flow. An explicit --token is checked directly and never refreshes the saved session. Missing, expired, or revoked member credentials report authenticated: false, actor: null, empty organizations, and expires_at: null. This is a successful status query (exit 0); scripts should inspect authenticated. Network failures, IAM outages, contract mismatches, and invalid test-plane configuration remain errors, not a false successful authentication result.

Both commands accept --test <environment_id> with the saved paired test key. The existing briefcase status remains the profile/deployment/contract summary; use briefcase login status for live authentication and identity.

Limits and test-plane boundaries#

Regular uploads use one endpoint for every supported file size. Briefcase uses one storage request through 100 MiB and automatically switches to its durable multipart path above that threshold; callers do not need a delegated upload flow for ordinary member uploads. Each paired testing environment is isolated from production IAM, limited to 2 GiB of aggregate content and at most 10 active environments per deployment; deleted environments remain recoverable for two days. A Briefcase test bearer and its IAM testing app secret are both required for test-plane requests.

Testing environments#

Create IAM and Briefcase together: briefcase env create integration. The result is stored as a UUID-to-IAM-test-app-secret mapping. Use briefcase --test <environment-id> login <test-slt> and then the same file commands with --test. Alternatively, set BRIEFCASE_APP_SECRET or pass --app-secret; the CLI resolves the environment and keeps its login separate. The testing footer is always printed to stderr, including on errors.

Use env list, env show, env key, env edit, env clean, env delete, and env restore to manage the local Briefcase plane. Rotate credentials in IAM and run env pair-iam with the replacement pairing. There is no independent Briefcase key rotation. IAM test actors retain their real role/tag permissions. See Testing environments for provisioning, lifecycle, storage isolation, and exact HTTP/Rust equivalents.

Addressing entries#

Anywhere a command takes an entry, it takes the path its permanent URL shows — private/cos:tos/notes/report.pdf — or the entry's identifier. A leading slash is fine.

Browsing#

briefcase ls                                    # the organization base
briefcase ls private/cos:tos/notes --long       # size, owner, what you may do
briefcase ls public/handbook --all              # follow every page
briefcase ls public/handbook --cursor "$NEXT"   # resume a previous page
briefcase stat private/cos:tos/notes/report.pdf # one entry in full

briefcase find "is:md location:'public' after:01-01-2026"
briefcase find "permissions:delete" --all
briefcase find "is:md" --cursor "$NEXT"
briefcase search "quarterly revenue"

find takes the service's filter language; search looks inside filenames and extracted document text and says which one matched. Without --all, ls and find return one page and preserve the service's opaque next_cursor: human output prints a continuation hint, while JSON contains items and next_cursor. Pass that value back unchanged with --cursor. --all follows pages until the service returns no next cursor; it has no hidden entry cap and fails explicitly if a broken deployment repeats a cursor.

Files#

briefcase mkdir notes --type private            # /notes, a Private root
briefcase mkdir handbook --type public          # /handbook, a Public root
briefcase mkdir specs --type tag --tag engineering
briefcase mkdir private/cos:tos/notes            # explicitly inside your folder
briefcase mkdir public/handbook                  # explicitly inside Public
briefcase mkdir private/cos:tos/notes/quarterly # inside an existing folder
briefcase mkdir shared --type private --invite carbon:cos:tos=read,write

briefcase put report.pdf figures.csv private/cos:tos/notes/quarterly
briefcase put report.pdf public/handbook --name q3-report.pdf

briefcase get private/cos:tos/notes/quarterly/report.pdf -o ./local.pdf
briefcase cat private/cos:tos/notes/quarterly/notes.md

briefcase mv private/cos:tos/notes/a.md private/cos:tos/notes/b.md   # rename
briefcase mv private/cos:tos/notes/b.md public/handbook/b.md         # move
briefcase rm private/cos:tos/notes/quarterly/draft.md                # to the bin

mkdir, every individual file in put, mv, and version restore also persist an intent fingerprint and idempotency key before sending. Upload fingerprints include the source file's SHA-256 digest. Path-addressed rename, move, and restore retain the resolved entry UUID; nested folder creation, uploads, and moves also retain the resolved destination-folder UUID. Rerunning after a lost success response therefore replays the original request without requiring either old path to remain visible. Pending state is cleared only after the CLI observes success.

Uploading a name that an active file already carries publishes that file's next version. Every version is retained:

briefcase versions private/cos:tos/notes/quarterly/report.pdf
briefcase restore private/cos:tos/notes/quarterly/report.pdf "$VERSION_ID"

Deleting is recoverable for 45 days:

briefcase bin list
briefcase bin list --cursor "$NEXT"
briefcase bin list --all
briefcase bin restore "$ENTRY_ID"

bin list uses the same cursor, JSON page, and exhaustive --all behavior as ls and find.

bin restore saves its operation key before sending. If the response is lost, rerun the exact command with the same profile and environment to recover that restore. The pending operation is cleared after success; restoring a later deletion uses a new key.

Sharing#

briefcase share private/cos:tos/notes carbon:cos:tos --access read,write --inherit
briefcase shares private/cos:tos/notes
briefcase unshare private/cos:tos/notes "$GRANT_ID"

briefcase access private/cos:tos/notes public/handbook   # what may I do here?

Members are written kind:idcarbon:cos:tos, silicon:atlas — and rights are a comma-separated set of read, write, update. Delete cannot be granted. They are independent: write adds files to a folder, update changes a file that is already there, and neither conveys delete.

Read and clear sharing notifications:

briefcase inbox
briefcase inbox --read                 # clear the unread badge
briefcase share private/me:tos/report.pdf email:alex@example.com --access read,update
briefcase share private/me:tos/reports tag:engineering --access read,write --inherit
briefcase link private/me:tos/reports --enabled true
briefcase link private/me:tos/reports
briefcase logs private/me:tos/reports --json
briefcase logs private/me:tos/reports --cursor '<next-cursor>' --json
briefcase versions private/me:tos/report.pdf --cursor '<next-cursor>' --json
briefcase get private/me:tos/reports --output reports.tar.zst

Folder downloads are streamed .tar.zst archives of authorized contents. Versions are retained without a count limit; logs retain 365 days, while history shows the latest 100 events. Read is always included, write adds new children to folders, and update changes existing content. Only creators and organization administrators can delete or manage sharing. See Sharing for verified-email limitations, tag membership, and inherited link settings.

Everything else#

briefcase history private/cos:tos/notes/report.pdf   # who did what, when
briefcase usage                                      # storage and today's uploads
briefcase version                                    # client and server contracts
briefcase storage configure --bucket … --region … --role-arn … --account …
briefcase app upload --app-id 'tos>app-notes' ./generated.md # hidden proof prompt
briefcase app upload --app-id 'tos>app-notes' --proof-stdin ./generated.md < proof.txt

storage configure prints its operation UUID to stderr before submitting the configuration. After a lost response, repeat the exact same arguments with --operation-id <that-uuid> to recover the result. A completed failed probe needs a new UUID after fixing the bucket or role; reusing the old UUID returns that failed result without running a new probe. Validation failure exits with status

  1. With --json, stdout still contains the single validation-status object; the operation ID and diagnostics go to stderr.

Application IDs on client-facing operations are always canonical {org_id}>{handle}. A local handle such as app-notes is rejected before a request so it cannot silently target the wrong organization. Explicit --proof "$PROOF" remains available, but can expose the proof through the process list; prefer the hidden prompt or --proof-stdin.

Delegated application requests#

Applications can create folders, list entries, read files, move entries to the bin, and stage uploads without a saved member session. Prepare the operation's JSON file, then describe it locally before asking IAM for a proof:

briefcase app request folder-create --body folder.json --describe
briefcase app request folder-create --body folder.json --app-id 'tos>app-notes'
briefcase app request file-read --body read.json --app-id 'tos>app-notes' --output ./download.bin

--describe only reads the bounded JSON file (at most 1 MiB), validates the selected operation, and prints its canonical body string, HTTP method, path, IAM endpoint_id, body_sha256, and empty metadata object. It does not read profiles or credentials, contact a server, or check for updates. Give IAM those exact binding values, then repeat the command with the same JSON file and a fresh proof at the hidden prompt or through --proof-stdin. Unknown JSON fields are rejected. See the API request schemas for the body fields.

The available operations are folder-create, entries-list, file-read, entry-trash, upload-reserve, upload-commit, upload-status, and upload-cancel. Each request uses fresh IAM authorization; no proof is cached or retried automatically. Keep a mutation's operation_id and body unchanged when obtaining a fresh proof for a retry. A file read requires --output before any proof or request is sent. Its destination appears only after the complete response is saved; existing paths are protected unless --force explicitly permits replacement. Ranges and download disposition belong in the signed JSON body, not separate request headers.

Staged application uploads#

Prepare a reservation before minting its short-lived proof. This local command hashes the file with bounded memory and prints a credential-free JSON manifest:

briefcase app prepare-upload ./recording.webm --operation-id "$OPERATION_ID" --parent-path public/recordings > reserve.json
briefcase app request upload-reserve --body reserve.json --describe
briefcase app request upload-reserve --body reserve.json --app-id 'tos>app-notes' --capability-file ./upload.cap
briefcase app transfer "$UPLOAD_ID" ./recording.webm --capability-file ./upload.cap

Choose one stable non-nil UUID as OPERATION_ID; UPLOAD_ID is the reservation UUID in the response. Keep the source file unchanged between preparation and transfer. An empty --parent-path selects the member's private application folder. Preparation and transfer require a regular source file: use its actual path, not a symlink, pipe or device. prepare-upload needs no configured profile, credential, network, or update check.

Reservation requires a new --capability-file and creates it with owner-only Unix permissions before consuming a proof. The capability is never included in ordinary JSON or terminal output, and an existing file is never replaced. If the request fails or the server returns no capability, that new file may remain empty; a local write failure may instead leave incomplete content. Reconcile with a fresh status proof before retrying, and use a new filename for a later reservation attempt. Transfer accepts the private file, a hidden prompt, or --capability-stdin. It refuses symlink capability files, special files, and files accessible to other users. Secret input is limited to 64 KiB. Capability-file handling requires Unix file permissions.

Transfer only stores private bytes. Publish with a fresh proof for upload-commit, using a body containing the original operation_id and the returned upload_id. upload-status and upload-cancel take a body containing the original operation_id, also with a fresh proof. After any uncertain transfer or commit, reconcile with status before retrying; never infer publication from a completed transfer. Retain the credential-free manifest and status for recovery, not IAM proofs or parent tokens. Protect the capability file while needed and remove it when the upload is finished.

Scripting#

--json prints the service's own shapes, so nothing has to parse a table:

briefcase ls public --json | jq -r '.items[] | select(.type == "file") | .path'
NEXT=$(briefcase ls public --json | jq -r '.next_cursor // empty')
briefcase usage --json | jq '.storage.remaining_bytes'

Exit codes:

Code Meaning
0 the command did what it said
1 something failed
2 the command as typed cannot be carried out
3 not found, or not yours to see
4 the credential was refused, or the action is not allowed

Codes 3 and 4 are deliberately distinct, and 3 covers both "there is no such entry" and "there is, but not for you" — the service never confirms that a hidden entry exists.

if briefcase stat "$path" >/dev/null 2>&1; then
  echo "entry is visible"
else
  status=$?
  case "$status" in
    3) echo "not there, or not mine to see" ;;
    4) echo "signed in, but not allowed" ;;
    *) echo "something else went wrong" ;;
  esac
fi

When the client and the deployment disagree#

Before its first call the CLI verifies the service identity and selected API major, then checks every operation it calls by exact ID, revision, method, and path. Duplicate IDs are refused; a new unknown operation is additive. A mismatch stops the command and names what moved:

briefcase: briefcase serves a contract this client was not built for (serving v1);
listEntries is 1.0.0 here and 2.0.0 there
briefcase: upgrade the CLI, or pass --no-verify to call it anyway at your own risk

Upgrading the CLI is the answer. --no-verify exists for a deliberate rollout where the mismatch is known and accepted.

Automatic updates#

After an ordinary command finishes, the installed CLI performs a best-effort crates.io check if the last attempt was at least one hour ago. When a newer stable briefcase-cli exists it runs cargo install briefcase-cli --bin briefcase --version =<version> --locked --force; the next invocation uses the new binary. The command's output and exit status are preserved even if maintenance fails. Automatic maintenance never waits for another CLI process's updater; failed attempts are throttled too. The first eligible command checks when no timestamp has been saved.

login and app commands deliberately skip automatic maintenance. Their IAM SLTs and OBO proofs are short-lived, single-use credentials, so the CLI sends them immediately and defers any due update check to the next ordinary invocation.

briefcase config show
briefcase config set auto-update off   # persistent opt-out
briefcase config unset auto-update     # restore default-on behavior
BRIEFCASE_AUTO_UPDATE=off briefcase ls # process-scoped opt-out
briefcase system update                # explicit check, ignoring the throttle

The package schedules separate, best-effort hourly maintenance in the background after an ordinary operation completes. Download streams defer it until EOF, failure, or abandonment. Clients targeting the same Cargo manifest share the in-process throttle. Neither updater replaces code already loaded in a running process.

Invitation, revocation, and link-setting commands save their exact operation identity and entry ID before sending. Repeating an interrupted command reuses that intent; it cannot silently target a new file that moved into the old path. briefcase shares TARGET --cursor CURSOR --json retrieves further invitation pages (100 per page).