CLI

Scripts, pipes & CI

Last updated

The CLI composes like any other command-line tool: stdin in, stdout out, JSON when you want structure. Every example below runs headless — no prompt, no interaction.

Piping context in

Piped mode runs one turn and exits. With a prompt argument, the piped text follows it as context; with none, stdin is the whole prompt. Either way it reaches the model exactly as it was piped, blank lines and indentation included. A few patterns that come up constantly:

# Review a diff before you push
git diff | tempr "Review this change for bugs and missing tests"

# Explain a failure from your build log
cat build.log | tempr "Why did this fail? Cite the relevant lines."

# Or put the instruction in the stream yourself
{ echo "Summarize these commits for the release notes:"; git log --oneline v1.2..; } | tempr

# Attach a file with @path instead of piping it
tempr "add XML doc comments to @src/Payment/PaymentRequest.cs"

# A prompt too long or too quote-heavy for the command line
tempr --prompt-file task.md

With a prompt argument, tempr waits up to 3 seconds for piped input to start, so a slow git diff still makes it. If nothing arrives (a parent process that leaves stdin open without writing to it), the prompt runs on its own and a note goes to stderr. Redirect stdin from /dev/null (NUL on Windows) to skip the wait.

One-shot agent turns

Piping is for context; for tasks that should do something, give the agent the goal directly. In scripts, add -y so file edits and allow-listed commands don't wait for approval:

tempr -y "fix the failing test in CartServiceTests and run the suite"
Caution

-y/--yolo runs this invocation in autopilot approval mode: file edits, MCP calls, and allow-listed commands run without asking. Commands that aren't allow-listed, and ones that delete, publish or force-push, still need approval — and with no terminal to ask on (piped input, --json, or CI set) they're refused and the model is told why. Add the commands a job needs with tempr config allow-command <prefix> or an .agentcommands.json file at the workspace root. Use -y for scoped tasks in workspaces you control, the same way you'd pipe a script into sh.

The JSON event stream

Add --json to any run to get newline-delimited JSON instead of formatted text — one event per line, machine-readable, then a final result object:

tempr --json -y "list the public types in this project" \
  | tail -n 1 \
  | jq '{status, summary, files: .filesChanged}'

The first line has "kind":"session" and says which session this is and how it runs: sessionId, model, workspace, version, approvalMode, webSearch, sandbox (on, network or off), and maxCostUsd when one was set. Each event line after it is {"seq", "kind", "payload"}, and the kinds cover the full agent lifecycle: run-started, assistant-start, assistant-delta, assistant-done, tool-call-request (a tool the CLI runs locally), tool-call-start and tool-call-done (tools the server runs, such as delegation, web fetches and web searches), usage, iteration-limit-reached, and turn-error / run-error. For each tool the CLI ran locally, a "kind":"tool-result" line carries callId, isError, and the output the model was given (the first 32,000 characters, with truncated set when there was more). The CLI's own lines — session, tool-result and result — have no seq.

The last line has "kind":"result" and carries status (ok, error, interrupted, step-limit, tool-refused, or cost-limit), exitCode, summary (the final answer), model, sessionId, usage, filesChanged, and, with --max-cost, spentUsd. Stream it, filter it, or tee it to a log — each line is a standalone JSON object.

Capping what a run spends

--max-cost <usd> stops the run once its model calls have cost that much — --max-cost 0.50 for fifty cents — counted from the cost each call reports, sub-agents included. The turn that crosses it is stopped like Ctrl+C stops one, the run on the server with it, and the CLI exits with code 6 and status cost-limit. Tempr's server enforces the cap as well: each run is sent what's left of it and stops before a model call that would start past it. A model whose price Tempr doesn't know reports no cost, so its calls can't be counted; the CLI says so rather than pretending the cap holds.

Your organization can also set a limit for every agent run on its Budget page. A run that reaches it stops the same way, with exit code 6 and status cost-limit, but only that turn: the session carries on, and the next run starts with a fresh limit. --max-cost can only make the limit lower.

Resuming sessions

Every run is saved automatically. List them, then pick one back up — the full conversation context comes with it:

tempr history list
tempr --id <SESSION_ID> "continue — apply the same fix to CheckoutTests"
tempr -c "now do the same for OrderTests"   # this folder's most recent session

In CI

The same pieces — one-shot run, auto-approve, JSON output — compose into pipeline steps. A minimal GitHub Actions job:

name: tempr-review
on: [pull_request]
jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - run: |
          curl -fsSL https://temprhq.io/cli/install.sh | sh
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"
      - env:
          TEMPR_LICENSE_KEY: ${{ secrets.TEMPR_LICENSE_KEY }}
        run: |
          { echo "Review this PR:"; git diff origin/main...; } \
            | tempr --json -m <model-id>
  • Store your license key as a repository secret — never inline it — and hand it to the CLI as TEMPR_LICENSE_KEY. The run signs in from it, so the key never appears on a command line.
  • Pass -m <model-id> explicitly so the run doesn't depend on a machine-local default.
  • Keep the task read-only (review, summarize, triage) unless the workspace is disposable — CI is exactly where -y deserves a second thought. On a Linux runner, -y runs its commands in the sandbox by default, so it can build and test without an allow-list while its commands can change only the checkout, the temp folders and the package caches; add --sandbox to keep them off the network too. See Sandbox.
  • GitHub Actions and most other runners set CI, so a tool call that would have asked for approval is refused instead of waiting, and there's no logo, update notice, or crash report.

Next steps