Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.useterse.ai/llms.txt

Use this file to discover all available pages before exploring further.

The terse CLI has one scaffold command and a shared workflow CLI. terse init scaffolds a new TypeScript project. The rest of the CLI auto-detects a Terse TypeScript project from the current directory and loads workflows from the default entry file unless you pass --entry-file.
LanguageProject markersDefault entry fileGenerated file
TypeScriptpackage.json, tsconfig.jsonsrc/terse.jobs.ts (falls back to src/index.ts when loading an existing project)src/terse.generated.ts
The CLI scaffolds, generates helpers for, and runs TypeScript workflows on Node.js only. terse test and terse deploy discover every workflow registered with createJob() in the entry file’s module graph, including files reached by side-effect imports. Keep workflow name values unique.

Getting started

terse init [project-name]

Scaffolds a new TypeScript project and runs the full setup flow: install dependencies, authenticate, create a Terse project, review integrations, and generate helpers.
terse init my-project
If you omit project-name, the CLI scaffolds into the current directory. If you run terse init in an existing npm project, the CLI tells you to use terse attach instead. The flow, in order:
  1. Creates the target directory and scaffolds package.json, tsconfig.json, src/terse.jobs.ts, .env.example, and .gitignore
  2. Detects pnpm or npm and installs dependencies
  3. Runs terse auth login
  4. Creates a Terse project and writes terse.config.json
  5. Reviews your current integrations
  6. Runs terse generate
Options:
FlagDescription
-y, --non-interactiveFail fast instead of prompting. Requires a prior terse auth login. Implied automatically when stdin is not a TTY.

terse attach

Links an existing repo to Terse with a self-hosted data plane (the Hybrid deployment).
terse attach
Use terse attach when you already have an application repo and want the control plane to sync workflows to a data plane you operate instead of uploading source to be run on the Terse Cloud data plane. What it does:
  1. Authenticates with the control plane, prompting you to pick which organization owns this project when your account belongs to more than one
  2. Prints the TERSE_API_KEY for the chosen organization so you can add it to your data plane environment
  3. Creates a Terse project if the repo is not already linked
  4. Writes terse.config.json with the self-hosted data plane enabled
  5. Reviews existing integrations and, in an interactive terminal, lets you connect more
  6. Runs terse generate when the current directory matches a supported project layout
Options:
FlagDescription
-y, --non-interactiveFail fast instead of prompting. Requires a prior terse auth login. Implied automatically when stdin is not a TTY.
Before you run terse deploy, set remoteServerUrl in terse.config.json to the URL where your Terse SDK server is running.
{
    "projectId": "proj_123",
    "name": "my-app",
    "selfHosted": true,
    "remoteServerUrl": "https://your-app.example.com"
}
If your app keeps workflow definitions outside the default entry file, use --entry-file with terse test and terse deploy.

terse test [job-name]

Fetches sample events and runs a local workflow against one selected event.
terse test
terse test my-job
If you only have one workflow, the CLI selects it automatically. If you have more than one, the CLI prompts you to choose unless you pass job-name. terse test is the interactive picker and requires a terminal. In non-interactive contexts (CI, agents, scripts), use the terse test list / terse test show / terse test run subcommands below. Options:
FlagDescriptionDefault
-v, --verboseShow agent stream output during the runEnabled
--no-verboseHide agent stream output
--entry-file <path>Override the default workflow entry filesrc/terse.jobs.ts
Loads your local workflow, lets you pick a real or synthesized sample event, and runs the handler in-process. If your workflow uses a webhook trigger but no deliveries are stored yet, the CLI prints a curl example against your webhook URL instead of opening an empty picker. Run terse deploy first so the CLI prints the URL, POST a test payload to it, then run terse test again.

terse test list [job-name]

Lists sample events for a workflow and assigns each one a content-addressed id.
terse test list
terse test list my-job --json
Use this command when you want a stable handle for a sample event without opening the interactive picker. The id stays the same as long as the underlying trigger payload stays the same. With --json, the output includes webhookEndpoints (URLs you can POST to) when your workflow has a webhook trigger, useful for scripting alongside stored samples. Options:
FlagDescription
--jsonEmit JSON, including the full serialized event for each id
--entry-file <path>Override the default workflow entry file
Sample-event ids are deterministic content hashes, so the same payload keeps the same id across runs.

terse test show <id> [job-name]

Shows the contents of one sample event.
terse test show 3f4d1c8a9b12
terse test show 3f4d1c8a9b12 my-job --json
Options:
FlagDescription
--jsonEmit JSON instead of the rendered text view
--entry-file <path>Override the default workflow entry file
The CLI refetches the workflow’s current sample events and resolves the id against them.

terse test run [job-name]

Runs a workflow against an explicit sample event.
terse test run --id 3f4d1c8a9b12
terse test run my-job --event-file fixture.json
Pass exactly one of --id, --event, or --event-file. Options:
FlagDescription
--id <id>Run a sample event by its terse test list id
--event <json>Inline serialized trigger event JSON
--event-file <path>Path to a JSON file containing the serialized trigger event
-v, --verboseShow agent stream output during the run (default: enabled)
--no-verboseHide agent stream output
--entry-file <path>Override the default workflow entry file

terse deploy

Packages your local project and syncs workflows to Terse. Learn more about how deployment works.
terse deploy
terse deploy --entry-file src/server.ts
Options:
FlagDescription
--entry-file <path>Override the default workflow entry file
What happens:
  • New workflows are created on the platform
  • Existing workflows are updated
  • Workflows removed from your code are removed from Terse
  • For each workflow that includes a webhook trigger, the CLI prints a Webhook URL line after deploy so you can wire up external systems without opening the app
  • For managed projects (Terse Cloud data plane) with a local .env, the CLI offers to upload any variables not already stored as project secrets before the deploy runs. Use terse secrets for finer-grained control.
Data plane targets:
  • Managed (Terse Cloud data plane): the CLI zips the current project directory, uploads it, and the control plane runs the workflow on Terse Cloud sandboxes
  • Self-hosted data plane: the CLI reads remoteServerUrl from terse.config.json and configures the control plane to call your own server instead of uploading source. On the first deploy with a self-hosted data plane, the CLI prints a new TERSE_API_KEY and TERSE_SIGNING_SECRET — save these into your data plane environment, they will not be shown again.

Build with workspace context

terse integrate

Interactive integration management from the terminal.
terse integrate
The interactive flow fetches your current integrations, shows provider-specific status, lets you connect, disconnect, or refresh one integration at a time, and reruns terse generate after any changes. Connection types:
TypeFlowIntegrations
OAuthOpens a browser for authorization and waits for the connection to completeGitHub, Slack, Gmail, Linear, Notion, Attio
FormPrompts for credentials or account details in the terminalDatadog, PostHog, Snowflake, LaunchDarkly, WorkOS, HeyReach

terse integrate list

Lists integrations and their connection status.
terse integrate list
terse integrate list --status connected --json
Options:
FlagDescription
--status <status>Filter to connected or disconnected
--jsonEmit machine-readable JSON

terse integrate describe <type>

Shows the current status, installation type, required fields, and any setup URL for one integration type.
terse integrate describe snowflake
terse integrate describe slack --json
Use this command to inspect the schema before you build a connect command. Options:
FlagDescription
--jsonEmit machine-readable JSON

terse integrate connect <type>

Connects or refreshes one integration without using the interactive picker.
terse integrate connect snowflake --field account=my-account --field username=alice --fields-stdin <<<'{"password":"..."}'
terse integrate connect slack
Options:
FlagDescription
--field <key=value>Repeatable form field values
--fields-stdinRead a JSON object of additional field values from stdin
-f, --forceRe-run the install even if the integration is already connected
--jsonEmit machine-readable JSON
Use --fields-stdin for secrets so passwords and tokens do not end up in shell history. For form-based integrations, connect submits the provided field values immediately. For OAuth integrations, connect opens the authorization URL in your default browser and exits 2 with a handoff payload ({ "handoff": "oauth", "url", "waitCommand" } in --json mode, or an ACTION REQUIRED line otherwise). Run the printed waitCommand (e.g. terse integrate wait slack) to block until authorization completes.

terse integrate disconnect <type>

Disconnects one integration.
terse integrate disconnect snowflake
terse integrate disconnect slack --json
Options:
FlagDescription
--jsonEmit machine-readable JSON

terse integrate wait <type>

Polls until an OAuth integration finishes connecting.
terse integrate connect slack
terse integrate wait slack --timeout 300
Use this after terse integrate connect <type> for OAuth integrations such as Slack or GitHub. Options:
FlagDescription
--timeout <seconds>Timeout in seconds. Defaults to 300 and caps at 900
--jsonEmit machine-readable JSON
The list, describe, connect, disconnect, and wait subcommands do not rerun code generation for you. After a connection change, run terse generate.

terse secrets

Manages project secrets for projects using the Terse Cloud data plane. Secrets are stored on the control plane and injected into Terse Cloud sandbox runs as environment variables. Projects with a self-hosted data plane manage their own runtime env vars and these commands return an error there.
terse secrets list

terse secrets list

Lists secret names (not values) stored on the linked Terse project.
FlagDescription
--jsonEmit JSON

terse secrets add <NAME>

Adds or updates one secret. Prompts for the value as a hidden input by default, or reads it from stdin so secrets don’t end up in shell history.
terse secrets add OPENAI_API_KEY
printf '%s' "$OPENAI_API_KEY" | terse secrets add OPENAI_API_KEY --value-stdin
FlagDescription
--value-stdinRead the secret value from stdin

terse secrets remove <NAME>

Removes one secret. Prompts for confirmation in a terminal; pass --yes in scripts.
terse secrets remove OPENAI_API_KEY --yes
FlagDescription
--yesSkip the confirmation prompt

terse secrets import <file>

Imports secrets from a .env-format file. Skips entries that already exist on the server unless you pass --overwrite.
terse secrets import .env
terse secrets import .env --overwrite
FlagDescription
--overwriteUpdate existing server-side secrets with new values

terse generate

Fetches your active integrations, their workspace resources, and the current tool definitions from Terse, then writes generated helpers for your local project.
terse generate
terse generate writes src/terse.generated.ts. What the generated file contains:
CategoryExample
Resource constantsSlackChannel.Engineering
Trigger buildersTriggers.github.onPROpened(), Triggers.schedule.cron()
Skill constructorsSkills.github({ repos: [...] })
Deterministic tool wrapperstoolbox.slack.sendMessage(), agent.tools.slack.sendMessage()
toolbox.* calls a tool directly with no TerseAgent and is not limited by skills. agent.tools.* calls the same tool but is limited to skills the agent was created with. See the Triggers and Skills reference for every helper. Each integration generates typed helpers from real workspace data such as repositories, Slack channels and members, lists, projects, and tool definitions, so your workflows reference actual resources instead of raw ids. TypeScript projects also get Triggers.webhook from src/terse.generated.ts. Pass a type argument to Triggers.webhook.onRequest<YourBodyType>() so onTrigger and filter infer WebhookTrigger<YourBodyType> for event.body. See Webhook trigger. Run terse generate again after you connect or disconnect an integration, after resources change inside a connected workspace, or after you upgrade terse-cli.

Improvements

Terse surfaces suggested code patches for your deployed agents based on past runs. These commands let you browse and apply them locally.

terse list improvements

Lists pending improvements grouped by agent.
terse list improvements

terse apply [improvement-id]

Downloads the suggested patch and runs git apply against your working tree, then marks the improvement as applied on the server. With no id, the CLI prompts you to pick from pending improvements. If a clean apply fails, the CLI tries git apply --3way; if that also fails, you can opt into git apply --reject to land hunks that do apply cleanly and write .rej files for the rest.
terse apply
terse apply imp_abc123
terse apply imp_abc123 --non-interactive
Options:
FlagDescription
-y, --non-interactiveFail fast instead of prompting. Requires an improvement id and a clean apply (no --reject fallback prompt).

Observability

terse listen [job-name]

Streams live trigger events for a deployed workflow and executes the matching local workflow on your machine.
terse listen
terse listen my-workflow
What it does:
  • Opens an authenticated SSE stream to the backend for your project/workflow
  • Prints each forwarded event as it arrives
  • Runs your current local workflow code against that serialized trigger
Requirements:
  • You’re authenticated (terse auth login) or TERSE_API_KEY is set
  • The workflow is deployed in this project (terse deploy)
  • terse.config.json exists with a valid projectId
Options:
FlagDescriptionDefault
-v, --verboseShow agent stream output during the runEnabled
--no-verboseHide agent stream output
--entry-file <path>Override the default workflow entry filesrc/terse.jobs.ts
Common errors:
  • 401/403 Not authenticated: run terse auth login
  • 404 Workflow not deployed: run terse deploy first
Press Ctrl-C to stop listening.

terse replay [run-id]

Fetches the stored trigger event for one past run and re-executes the matching local workflow on your machine with verbose output.
terse replay run_abc123
The CLI resolves the local workflow by the deployed workflow name stored on that run, then executes your current local code against the saved trigger payload.

terse history [job-name]

Lists past runs for a deployed workflow or fetches the full chat history for a single run.
terse history my-job
terse history my-job --json --triggers
terse history --run-id run_abc123
When you pass job-name, the CLI matches your local workflow name to the deployed workflow on Terse. When you pass --run-id, the CLI skips workflow lookup and fetches that run directly. Options:
FlagDescription
--jsonPrint JSON instead of a table
--limit <n>Max runs to return. Default 20, max 100
--page <n>Page number, 1-indexed
--status <list>Comma-separated statuses: success, failed, cancelled, skipped, in_progress, awaiting_approval
--since <iso>Only runs at or after this ISO timestamp
--until <iso>Only runs at or before this ISO timestamp
--query <q>Free-text search across trigger, decision, and event fields
--triggersAlso fetch the input trigger event JSON for each listed run
--eventsAlso fetch the full model event stream for each listed run
--run-id <id>Show full chat events for one run instead of listing runs for a workflow
Use --triggers when you want the serialized input event for each run. Use --events when you want the full stored conversation, including the trigger payload.

terse dashboard

Opens the Terse web app in your default browser.
terse dashboard
If TERSE_FRONTEND_URL is set, the CLI opens that URL instead of production.

Authentication

terse auth login

Authenticates with Terse using a device authorization flow and saves your API key to a user-level config file.
terse auth login
Opens a browser to confirm the session, then saves an API key to your user config so later commands don’t need it inline. If your account belongs to more than one organization, the CLI prompts you to pick which one this CLI session should use. If a valid API key is already saved, the CLI reports the current user and organization instead of starting a fresh flow.

terse auth logout

Removes saved API keys from your user config.
terse auth logout

terse auth status

Shows the user and organization the saved API key belongs to.
terse auth status
Exits with code 1 if no credentials are saved or the saved key is expired.

terse auth org list

Lists organizations your account belongs to and marks the active one.
terse auth org list
terse auth org list --json
Options:
FlagDescription
--jsonEmit JSON

terse auth org switch [org-id]

Switches the active organization for this CLI session. Tokens for each organization you’ve used are cached locally, so re-switching is instant after the first time.
terse auth org switch
terse auth org switch org_123
In non-interactive terminals the org id argument is required.

Help

terse docs

Opens the Terse documentation site in your default browser.
terse docs
If TERSE_DOCS_URL is set, the CLI opens that URL instead of the public docs.

terse completion install

Installs shell tab completion for the terse binary. Detects bash, zsh, or fish from your $SHELL.
terse completion install
Open a new shell or source your shell config after installing for completion to take effect. The CLI also offers to install completion automatically the first time you run a command in an interactive terminal.

terse completion uninstall

Removes the tab-completion entries written by terse completion install.
terse completion uninstall

API key resolution

Commands that call the Terse API resolve credentials in this order:
  1. TERSE_API_KEY in the current process environment (including .env loaded from the project root)
  2. The API key saved by terse auth login
Those values are user API tokens (the same kind you create in the Terse app). Runs on the Terse Cloud data plane use separate project-scoped tokens that the control plane injects automatically — you don’t paste those into .env and you don’t need to set anything in the sandbox runtime. After terse init or terse auth login, you usually don’t need a project .env file for the CLI either, because authentication is stored per user on your machine. For a self-hosted data plane, your own server needs TERSE_API_KEY in its environment so it can authenticate with the control plane at runtime. terse attach prints the per-organization key, and terse deploy prints a project-scoped key and TERSE_SIGNING_SECRET the first time you deploy against a self-hosted data plane — copy these into your data plane secret store. terse secrets is for your own application secrets (database URLs, third-party API keys); it intentionally refuses any name that starts with TERSE_. To point the CLI at a self-hosted control plane, set TERSE_BACKEND_URL (default https://api.useterse.ai) in your shell before running any terse command.