Skip to content

Commit d5dc484

Browse files
ericallamTrigger.dev RepoOps
authored andcommitted
feat(cli): agent-friendly trigger dev output and a tasks trigger command
`trigger dev` works better when a coding agent like Claude Code, Cursor or Codex runs it. It skips the install prompts, exits with instructions when your packages don't match the CLI version, lists the tasks it registered, and prints each run's dashboard URL and output. For everyone, failed builds now end with a line saying the dev command will rebuild once you fix the errors and which version runs still use. Retried attempts and crashed task processes now show their errors, and build errors no longer contain color codes when the output isn't a terminal. New `trigger.dev tasks trigger <task id>` command to trigger a task from your terminal. It uses the dev environment unless you pass `--env`. With `--wait`, it waits for the run, prints its output or error, and exits with code 1 if the run failed, expired or timed out. `--timeout` limits how long it waits. It fails straight away if the task id doesn't exist, and warns when the dev command isn't running. The `runs` commands now use the same dev branch as `trigger dev` when you pass `--env dev`. Mono-RevId: 83d817c031bf943b87ebdf585cbf91d3e416e7f5
1 parent 70ea83d commit d5dc484

25 files changed

Lines changed: 873 additions & 53 deletions

‎.changeset/cli-tasks-trigger.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"trigger.dev": patch
3+
---
4+
5+
Add `trigger.dev tasks trigger <task id>` to trigger a task from your terminal. It uses the dev environment unless you pass `--env`, and `--wait` waits for the run and prints its output or error, exiting with code 1 if it failed. The `runs` commands now use the same dev branch as `trigger dev` when you pass `--env dev`.
6+
7+
```bash
8+
npx trigger.dev@latest tasks trigger hello-world --payload '{"name":"Ada"}' --wait
9+
```
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"trigger.dev": patch
3+
---
4+
5+
`trigger dev` works better when a coding agent like Claude Code, Cursor or Codex runs it: it skips the install prompts, lists the tasks it registered, and prints each run's dashboard URL and output. For everyone, a failed build now ends with a line saying it will rebuild when you fix the errors, and retried attempts and crashed task processes now show their errors.

‎apps/webapp/app/routes/api.v1.projects.$projectRef.dev-status.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { devPresence } from "~/presenters/v3/DevPresence.server";
44
import {
55
authenticatedEnvironmentForAuthentication,
66
authenticateRequest,
7+
branchNameFromRequest,
78
} from "~/services/apiAuth.server";
89
import { logger } from "~/services/logger.server";
910

@@ -31,10 +32,12 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
3132

3233
const { projectRef } = parsedParams.data;
3334

35+
// Dev branches each have their own dev session
3436
const runtimeEnv = await authenticatedEnvironmentForAuthentication(
3537
authenticationResult,
3638
projectRef,
37-
"dev"
39+
"dev",
40+
branchNameFromRequest(request)
3841
);
3942

4043
const isConnected = await devPresence.isConnected(runtimeEnv.id);

‎docs/cli-runs-commands.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ npx trigger.dev@latest runs cancel run_abc123
8484

8585
<ConfigFileOptions />
8686
<ProjectRefOptions />
87-
<ParamField body="Preview branch" type="--branch | -b">
88-
Required when using `--env preview`. Specify the branch, e.g. `--branch my-branch` or `-b my-branch`.
87+
<ParamField body="Branch" type="--branch | -b">
88+
Required when using `--env preview`. Specify the branch, e.g. `--branch my-branch` or `-b my-branch`. With `--env dev`, it defaults to the same [dev branch](/deployment/dev-branches) as the dev command.
8989
</ParamField>
9090

9191
### Common options

‎docs/cli-tasks-commands.mdx‎

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
title: "CLI tasks commands"
3+
sidebarTitle: "tasks"
4+
description: "Use these commands to trigger tasks from your terminal."
5+
---
6+
7+
import CommonOptions from "/snippets/cli-options-common.mdx";
8+
import ConfigFileOptions from "/snippets/cli-options-config-file.mdx";
9+
import ProjectRefOptions from "/snippets/cli-options-project-ref.mdx";
10+
11+
## tasks trigger
12+
13+
Triggers a task and prints the run ID and its dashboard URL. It runs in the `dev` environment unless you pass `--env`, so start the [dev command](/cli-dev-commands) first.
14+
15+
<CodeGroup>
16+
17+
```bash npm
18+
npx trigger.dev@latest tasks trigger hello-world --payload '{"name":"Ada"}'
19+
```
20+
21+
```bash pnpm
22+
pnpm dlx trigger.dev@latest tasks trigger hello-world --payload '{"name":"Ada"}'
23+
```
24+
25+
```bash yarn
26+
yarn dlx trigger.dev@latest tasks trigger hello-world --payload '{"name":"Ada"}'
27+
```
28+
29+
</CodeGroup>
30+
31+
Add `--wait` to wait for the run to finish. It prints the run's output, or its error and exits with code 1 if the run failed, which makes it useful in scripts and for coding agents testing a task:
32+
33+
```bash
34+
npx trigger.dev@latest tasks trigger hello-world --payload '{"name":"Ada"}' --wait
35+
```
36+
37+
The command fails without creating a run if the current version has no task with that ID. In `dev`, it warns you when the dev command isn't running, because the run waits in the queue until it starts.
38+
39+
<ParamField body="Payload" type="--payload">
40+
The payload as JSON, e.g. `--payload '{"name":"Ada"}'`. Without it, the task gets no payload.
41+
</ParamField>
42+
43+
<ParamField body="Payload file" type="--payload-file">
44+
Read the payload from a JSON file instead.
45+
</ParamField>
46+
47+
<ParamField body="Wait" type="--wait">
48+
Wait for the run to finish, then print its output or error.
49+
</ParamField>
50+
51+
<ParamField body="Timeout" type="--timeout">
52+
With `--wait`, stop waiting after this many seconds and exit with code 1.
53+
</ParamField>
54+
55+
<ParamField body="Tag" type="--tag">
56+
A tag to add to the run. Repeat it to add more than one, e.g. `--tag cli --tag test`.
57+
</ParamField>
58+
59+
<ParamField body="Idempotency key" type="--idempotency-key">
60+
If a run with this key already exists, return it instead of creating a new one. See [idempotency](/idempotency).
61+
</ParamField>
62+
63+
<ParamField body="Delay" type="--delay">
64+
Wait before running, e.g. `30s`, `5m` or an ISO 8601 date.
65+
</ParamField>
66+
67+
<ParamField body="TTL" type="--ttl">
68+
Expire the run if it hasn't started within this time, e.g. `10m`.
69+
</ParamField>
70+
71+
<ParamField body="Queue" type="--queue">
72+
The queue to run in, instead of the queue set on the task.
73+
</ParamField>
74+
75+
<ParamField body="Machine" type="--machine">
76+
The machine to run on, e.g. `small-2x`. See [machines](/machines). Has no effect in `dev`.
77+
</ParamField>
78+
79+
## Options
80+
81+
<ParamField body="Environment" type="--env | -e">
82+
The environment to use: `dev`, `prod`, `staging` or `preview`. Defaults to `dev`.
83+
</ParamField>
84+
85+
<ConfigFileOptions />
86+
<ProjectRefOptions />
87+
<ParamField body="Branch" type="--branch | -b">
88+
The branch to use. Required with `--env preview`. In `dev`, it defaults to the same [dev branch](/deployment/dev-branches) as the dev command.
89+
</ParamField>
90+
91+
### Common options
92+
93+
These options are available on most commands.
94+
95+
<CommonOptions />

‎docs/docs.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@
279279
"cli-promote-commands",
280280
"cli-runs-commands",
281281
"cli-switch",
282+
"cli-tasks-commands",
282283
"cli-update-commands",
283284
"cli-whoami-commands"
284285
]

‎docs/snippets/cli-commands-develop.mdx‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,21 @@ You will see in the terminal that the server is running and listening for tasks.
2828

2929
It is worth noting that each task runs in a separate Node process. This means that if you have a long-running task, it will not block other tasks from running.
3030

31+
When a build fails, the dev command keeps watching your files and rebuilds as soon as you fix the errors. Until then, new runs use the last version that built successfully.
32+
33+
## Running dev from a coding agent
34+
35+
The dev command detects when a coding agent such as Claude Code, Cursor, Codex or Gemini CLI is running it, and changes its output so the agent can act on it:
36+
37+
- It skips the prompts to install the MCP server and agent skills.
38+
- If your `@trigger.dev/*` packages don't match the CLI version, it exits with instructions instead of asking whether to update them.
39+
- When the local worker is ready, it lists the task ids it registered and prints plain dashboard URLs.
40+
- Each run prints its dashboard URL, and successful runs print their output.
41+
42+
If your agent isn't detected, set the `AI_AGENT` environment variable to its name.
43+
44+
To test a task, an agent can trigger it with [`tasks trigger`](/cli-tasks-commands) and `--wait`, which prints the run's output or error.
45+
3146
## Options
3247

3348
<ConfigFileOption />

‎packages/cli-v3/src/build/bundle.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { CORE_VERSION } from "@trigger.dev/core/v3";
22
import { DEFAULT_RUNTIME, ResolvedConfig } from "@trigger.dev/core/v3/build";
33
import { BuildManifest, BuildTarget, TaskFile } from "@trigger.dev/core/v3/schemas";
4+
import chalk from "chalk";
45
import * as esbuild from "esbuild";
56
import { createHash } from "node:crypto";
67
import { basename, join, relative, resolve } from "node:path";
@@ -348,7 +349,7 @@ export function logBuildWarnings(
348349
) {
349350
const logs = esbuild.formatMessagesSync(warnings, {
350351
kind: "warning",
351-
color: options.color ?? true,
352+
color: options.color ?? chalk.level > 0,
352353
});
353354
for (const log of logs) {
354355
console.warn(log);
@@ -360,7 +361,7 @@ export function logBuildWarnings(
360361
* style esbuild would.
361362
*/
362363
export function logBuildFailure(errors: esbuild.Message[], warnings: esbuild.Message[]) {
363-
const logs = esbuild.formatMessagesSync(errors, { kind: "error", color: true });
364+
const logs = esbuild.formatMessagesSync(errors, { kind: "error", color: chalk.level > 0 });
364365
for (const log of logs) {
365366
console.error(log);
366367
}

‎packages/cli-v3/src/cli/index.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { configureProjectsCommand } from "../commands/projects/index.js";
1212
import { configurePromoteCommand } from "../commands/promote.js";
1313
import { configureRunsCommand } from "../commands/runs/index.js";
1414
import { configureSwitchProfilesCommand } from "../commands/switch.js";
15+
import { configureTasksCommand } from "../commands/tasks/index.js";
1516
import { configureUpdateCommand } from "../commands/update.js";
1617
import { configureWhoamiCommand } from "../commands/whoami.js";
1718
import { configureMintTokenCommand } from "../commands/mint-token.js";
@@ -47,6 +48,7 @@ configurePreviewCommand(program);
4748
configureProjectsCommand(program);
4849
configureOrgsCommand(program);
4950
configureRunsCommand(program);
51+
configureTasksCommand(program);
5052
configureAnalyzeCommand(program);
5153
configureMcpCommand(program);
5254
configureReportCommand(program);

‎packages/cli-v3/src/commands/dev.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { loadConfig, watchConfig } from "../config.js";
1818
import type { DevSessionInstance } from "../dev/devSession.js";
1919
import { startDevSession } from "../dev/devSession.js";
2020
import { createLockFile } from "../dev/lock.js";
21+
import { isAgent } from "../utilities/agent.js";
2122
import { chalkError } from "../utilities/cliOutput.js";
2223
import {
2324
readConfigHasSeenMCPInstallPrompt,
@@ -157,8 +158,9 @@ export function configureDevCommand(program: Command) {
157158
async function devCommand(options: DevCommandOptions) {
158159
runtimeChecks();
159160

160-
// Only show these install prompts if the user is in a terminal (not in a Coding Agent)
161-
if (process.stdout.isTTY) {
161+
// Only show these install prompts to a person. Some coding agents (e.g. Cursor) run commands
162+
// in a real terminal, so a TTY alone doesn't mean someone is there to answer them.
163+
if (process.stdout.isTTY && !isAgent) {
162164
const skipMCPInstall = typeof options.skipMCPInstall === "boolean" && options.skipMCPInstall;
163165

164166
if (!skipMCPInstall) {

0 commit comments

Comments
 (0)