Skip to content
Thyme Docs

CI & Non-Interactive Use

Every thyme command runs without a terminal. A prompt is only ever reached when a TTY is attached and no flag already supplied the value, so a pipeline never blocks on a picker nobody can answer.

# Either position works
thyme --ci upload my-task -w ws_123abc -p proj_456def --tag v2
thyme upload my-task -w ws_123abc -p proj_456def --tag v2 --ci

Flags

FlagAliasDescription
--ciNever prompt. Confirmations are answered yes; any other missing value is an immediate error.
--yes-yAnswer confirmations yes, but keep the other prompts. Useful on a terminal when you only want to skip Proceed with upload?.

Both are accepted on the root command and on every command that can prompt (init, new, run, login, upload).

Automatic detection

You usually don't need --ci at all. Non-interactive mode turns itself on when either:

  • any of CI, CONTINUOUS_INTEGRATION, THYME_CI, or THYME_NON_INTERACTIVE is set to anything other than 0, false, off, no, or empty — this covers GitHub Actions, GitLab CI, CircleCI, Buildkite, and most others out of the box; or
  • stdin or stdout is not a terminal — a pipe, a container started without a TTY, or a subprocess spawned by a coding agent.

--ci exists to force the behavior where none of that applies, and THYME_CI=1 does the same from the environment.

The failure contract

A missing value exits with code 2 and a message naming the flag that supplies it, along with the accepted values:

■  A workspace is required when prompts are unavailable (--ci was passed).
│  Pass `--workspace <id>`. Available: ws_123abc (Acme), ws_456def (Acme Staging)

Missing interactive inputs use exit code 2. Ordinary task, authentication, and upload failures use 1. Some local simulation diagnostics are warnings rather than process failures; see known limitations.

Every prompt and its flag

CommandPromptNon-interactive path
initproject namethyme init <name> argument
newtask namethyme new <name> argument
runtask pickerthyme run <task> argument
run --simulate-callbacksoutcome picker--callback <outcome>
loginre-authenticate?answered yes
login --tokenpaste API keypiped on stdin
login --rewrite-api-urlAPI URL--api-url <url>
uploadtask pickerthyme upload <task> argument
uploadworkspace picker-w, --workspace <id>
uploadproject picker-p, --project <id>
uploadversion tag-t, --tag <tag>
uploadproceed?answered yes

list, logout, api-url, and the management commands never prompt — they are flag-driven already, and the management commands print raw JSON to stdout for piping into jq.

Authenticating without a browser

A pipeline can supply THYME_AUTH_TOKEN and skip thyme login. Stored credentials take precedence, so use a clean runner without saved personal credentials. Management calls need a key with the appropriate scopes and workspace binding.

export THYME_AUTH_TOKEN="$THYME_API_KEY"   # Console → API Keys → Create Key

If you do need to log in from a pipeline:

  • thyme login --token reads the key from stdin when there's no terminal, keeping it out of your shell history and the process list:

    echo "$THYME_API_KEY" | thyme login --token
  • thyme login --browserless prints a pairing code and polls, so someone can approve from another device.

  • The default browser flow fails immediately without a terminal rather than polling for five minutes for an approval that can't happen.

The optional permissions manifest has a known local loader issue in CLI 0.10.0; do not treat local validation as a substitute for upload and cloud permission checks.

Output

Spinners collapse to plain single-line output off a TTY, so CI logs stay readable instead of filling with animation frames. Colors follow the usual rules — disabled when stdout isn't a terminal, kept when a CI variable is present, since most CI log viewers render ANSI.

A pipeline example

export THYME_AUTH_TOKEN="$THYME_API_KEY"
export THYME_API_URL="$API_URL"   # API base supplied by your deployment
export SIMULATE_ACCOUNT="$EXECUTION_ACCOUNT"
export RPC_URL="$CHAIN_RPC_URL"
 
# Evaluate the task and inspect callback diagnostics
thyme run my-task --ci
thyme run my-task --callback onSuccess
thyme run my-task --callback onFail:reverted
 
# Ship an immutable version
thyme upload my-task --ci \
  -w "$THYME_WORKSPACE_ID" \
  -p "$THYME_PROJECT_ID" \
  --tag "v$BUILD_NUMBER"

The example assumes Deno and project dependencies are installed, the task returns calls and defines the selected callbacks, and it does not hit the manifest-loader limitation above. Callback diagnostics require inspection because callback errors do not necessarily fail the command.

Tags are immutable; choose a distinct label for changed content, such as a build number or release version. Re-uploading the exact same name, tag, and checksum is idempotent and reuses the existing function ID; reusing a tag with different code is a conflict. See thyme upload.

Next steps