@doist/automations-cli 0.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,45 +1,400 @@
1
- # @doist/automations-cli
1
+ # `tda`
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ Terminal client for Todoist Automations. It can inspect and manage automations, drafts,
4
+ conversations, and runs, and it uses the same persisted agent conversations and client-managed tools
5
+ as the Automations frontend.
4
6
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
7
+ The agent can create and edit automations, inspect existing automations and runs, troubleshoot
8
+ failures, and answer other automation-related questions. The CLI sends the initial message unchanged;
9
+ it does not assume that every conversation is an authoring request.
6
10
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
11
+ ## Installing
8
12
 
9
- ## Purpose
13
+ ```bash
14
+ npm install -g @doist/automations-cli@internal
15
+ ```
10
16
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@doist/automations-cli`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
17
+ The `@internal` part is required. Releases are published under that dist tag and no other, so the
18
+ usual `npm install -g @doist/automations-cli` finds no version to install for as long as Automations
19
+ is invite-only.
15
20
 
16
- ## What is OIDC Trusted Publishing?
21
+ Once installed, upgrade with `tda update`, or `tda update --check` to see what is available without
22
+ installing anything. It installs from the same `internal` tag, so there is no release channel to
23
+ choose. Re-running the install command above works just as well.
17
24
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
25
+ Signing in still needs an account with Automations access, so installing the CLI on its own grants
26
+ nothing.
19
27
 
20
- ## Setup Instructions
28
+ ## Local development
21
29
 
22
- To properly configure OIDC trusted publishing for this package:
30
+ From the monorepo root, install dependencies and create the global link once:
23
31
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
32
+ ```bash
33
+ npm install
34
+ npm run setup:cli
35
+ ```
28
36
 
29
- ## DO NOT USE THIS PACKAGE
37
+ This builds the shared workspace packages and CLI, then creates an npm link for the `tda` executable.
38
+ The link is persistent. After editing `apps/cli/src`, rebuild only the CLI:
30
39
 
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
40
+ ```bash
41
+ npm run build:cli
42
+ ```
36
43
 
37
- ## More Information
44
+ For active development, keep the bundler running instead:
38
45
 
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
46
+ ```bash
47
+ npm run dev:cli
48
+ ```
42
49
 
43
- ---
50
+ Both commands update the linked executable without recreating the link. A linked build reports its
51
+ version as `0.0.0-development`, since the real number is written at publish time, so
52
+ `tda update --check` always claims an update is available; rebuild the link rather than running
53
+ `tda update`, which would replace it with a global install. Run `npm run build:core`
54
+ after editing a shared package. Run `npm unlink --global @doist/automations-cli` to remove the link.
44
55
 
45
- **Maintained for OIDC setup purposes only**
56
+ A global install and a link cannot both own `tda`, so uninstall the published package first if you
57
+ have one.
58
+
59
+ ## Releases
60
+
61
+ `@doist/automations-cli` is published from `main` by
62
+ [`.github/workflows/release-cli.yml`](../../.github/workflows/release-cli.yml), which runs
63
+ semantic-release with the configuration in [`release.config.js`](./release.config.js). The version
64
+ comes from the conventional-commit messages that touched this directory, so nothing has to be bumped
65
+ by hand and the repository holds no version number of its own.
66
+
67
+ The workspace libraries the CLI uses are not published, so `npm run build` compiles them into
68
+ `dist/` rather than resolving them at install time. Only the packages listed under `dependencies`
69
+ are left external. Because a release is scoped to commits under `apps/cli`, a change confined to one
70
+ of those libraries does not trigger a release even though it changes what gets published; it ships
71
+ with the next release instead. Publish it sooner by landing it together with a change here.
72
+
73
+ Once linked, `tda skill install claude-code` gives your coding agent instructions for driving the
74
+ CLI. See [Agent skill](#agent-skill).
75
+
76
+ ## Authentication
77
+
78
+ Sign in with your Todoist account:
79
+
80
+ ```bash
81
+ tda auth login
82
+ ```
83
+
84
+ This opens a browser, asks Todoist to authorize the CLI, and stores the resulting token in your
85
+ operating system credential manager. `tda auth status` shows which account is signed in, and
86
+ `tda auth logout` removes the credential and tells Todoist to revoke it.
87
+
88
+ The token is minted for Automations specifically rather than for Todoist as a whole, so it grants
89
+ access to your automations and not to your tasks, projects or comments. The one exception is your
90
+ identity: signing in also asks for Todoist's `user:read` scope and reads your account id and email,
91
+ which is how the CLI knows who it stored the credential for. It lasts an hour and is renewed
92
+ automatically as commands run, so signing in is a one-off.
93
+
94
+ ### Scopes
95
+
96
+ By default the CLI asks for write access to automations, connections and chat, plus permission to
97
+ run automations. `--read-only` asks for read access instead, which leaves `automation trigger`,
98
+ `chat`, and every connector change failing with a permissions error.
99
+
100
+ ```bash
101
+ tda auth login --read-only
102
+ ```
103
+
104
+ Scopes that no command needs yet — workspaces, notifications, settings and webhooks — are not
105
+ requested by default. Ask for them up front if you want them, rather than signing in a second time
106
+ later:
107
+
108
+ ```bash
109
+ tda auth login --additional-scopes workspaces,notifications,webhooks
110
+ ```
111
+
112
+ `workspaces` covers automations that live in a Todoist workspace rather than your personal space.
113
+ They are a separate resource with their own scopes, because a workspace holds other people's
114
+ automations too.
115
+
116
+ `tda auth login --help` lists them with what each one covers.
117
+
118
+ ### Environments
119
+
120
+ `--env` selects which Automations deployment to talk to, and the account you sign in as is stored
121
+ per environment, so a staging login never leaks into a production command:
122
+
123
+ ```bash
124
+ tda --env staging auth login
125
+ tda --env staging automation list
126
+ ```
127
+
128
+ `prod` is the default. `TDA_ENV` sets it for a shell session. `--api-url` (or `TDA_API_URL`)
129
+ overrides just the API address, for a proxy or a local backend, and takes precedence over `--env`.
130
+
131
+ Signing in against `dev` needs the local backend running with `APP_URL=https://local-agentist.todoist.com`.
132
+ On its default of `http://localhost:24368`, Todoist cannot fetch the document that identifies the
133
+ CLI, so the login fails.
134
+
135
+ ### Personal API tokens
136
+
137
+ A Todoist personal API token still works, and takes over when no account is signed in:
138
+
139
+ ```bash
140
+ export TODOIST_API_TOKEN="<your Todoist personal API token>"
141
+ ```
142
+
143
+ A signed-in account wins over the variable, so logging in does not require unsetting it. The
144
+ variable is useful for CI and scripts, where opening a browser is not an option.
145
+
146
+ ### Where the credential is stored
147
+
148
+ By default, only in your operating system credential manager. On a machine without one — a
149
+ container, a headless host, some WSL setups — login fails rather than quietly writing the token to
150
+ a file. Use `--credential-store` to choose deliberately:
151
+
152
+ ```bash
153
+ tda auth login --credential-store fallback # keyring if available, config file if not
154
+ tda auth login --credential-store plaintext # config file, always
155
+ ```
156
+
157
+ `plaintext` always writes the token to `~/.config/tda/config.json`; `fallback` does so only when no
158
+ keyring is available, and otherwise behaves like the default. That file is readable by anything
159
+ running as you, so it is worth knowing which one you get. It is created `0600`.
160
+
161
+ ### Known limitation
162
+
163
+ A `tda chat` turn starts with at least ten minutes of token life, which covers any normal turn. A
164
+ turn running longer than that fails partway through, because the connection carries the token it
165
+ opened with. Re-run `tda chat continue` to resume. Fixing this properly means the SDK resolving the
166
+ token per request rather than holding the one it was built with.
167
+
168
+ ## Inspecting resources
169
+
170
+ Every resource has `list` and `view` commands. Use `--json` for complete machine-readable output:
171
+
172
+ ```bash
173
+ tda --json automation list --all
174
+ tda --json automation view <automation-id>
175
+
176
+ tda --json draft list --all
177
+ tda --json draft view <draft-id>
178
+
179
+ tda --json conversation list --status all --limit 200
180
+ tda --json conversation view <conversation-id>
181
+
182
+ tda --json run list <automation-id> --status failed --all
183
+ tda --json run list <automation-id> --status failed --since 2026-08-01 --until 2026-08-07
184
+ tda --json run view <automation-id> <run-id>
185
+ tda --json run view <automation-id> <run-id> --full
186
+ ```
187
+
188
+ Automation, draft, and run lists support `--limit`, `--cursor`, and `--all`. `--limit` controls the
189
+ total number of returned resources; `--all` removes that limit. JSON responses retain the API's
190
+ `data` and `nextCursor` fields. NDJSON emits one resource per line and adds a final
191
+ `{"_meta":true,"nextCursor":"..."}` record when another page is available.
192
+
193
+ `run list` filters on when a run was created. `--since` and `--until` each take a full ISO timestamp
194
+ (`2026-08-01T09:00:00Z`) or a plain `YYYY-MM-DD` date, and both bounds are inclusive: a plain date
195
+ covers that entire UTC day, so `--since 2026-08-01 --until 2026-08-07` returns everything from the
196
+ start of the 1st to the end of the 7th. Either bound can be used on its own; with only `--since`,
197
+ the range runs up to now.
198
+
199
+ `conversation view` returns the persisted conversation and its raw messages. `chat status` remains
200
+ focused on resumable agent state, including pending client actions.
201
+
202
+ To investigate a failing automation, an agent can list automations, inspect the selected automation,
203
+ list its failed runs, and inspect one failed run. Run details default to a compact diagnostic view
204
+ with failure, step, and tool-call errors. Use `run view --full` when raw step results and tool payloads
205
+ are needed.
206
+
207
+ ## Managing automations
208
+
209
+ Enable or disable an automation, or start a live run:
210
+
211
+ ```bash
212
+ tda automation enable <automation-id>
213
+ tda automation disable <automation-id>
214
+ tda automation trigger <automation-id>
215
+ ```
216
+
217
+ `automation trigger` only supports scheduled automations. It starts a live run and exits after the
218
+ backend accepts it; it does not wait for the run to finish. API triggers are not supported because
219
+ the command cannot provide their input payload. Webhook automations run through their configured
220
+ event.
221
+
222
+ Replace an automation's name and description together:
223
+
224
+ ```bash
225
+ tda automation update <automation-id> \
226
+ --name "Daily summary" \
227
+ --description "Creates a morning summary"
228
+ ```
229
+
230
+ Replace its schedule with either an interval or a five-part cron expression:
231
+
232
+ ```bash
233
+ tda automation schedule <automation-id> --interval "45m"
234
+
235
+ tda automation schedule <automation-id> \
236
+ --cron "0 9 * * *" \
237
+ --timezone "America/Santiago"
238
+ ```
239
+
240
+ Cron schedules require an IANA timezone. `--cron` and `--interval` are mutually exclusive, and
241
+ natural-language values such as `every day at 9am` are not supported.
242
+
243
+ These explicit mutation commands do not prompt for confirmation and do not support `--dry-run`.
244
+ Use the global `--json` or `--ndjson` option for structured results.
245
+
246
+ ## Conversations
247
+
248
+ ```bash
249
+ tda --ndjson chat start \
250
+ "Why did my daily summary automation fail yesterday?"
251
+
252
+ tda --ndjson chat continue <conversation-id> \
253
+ "Inspect its most recent run"
254
+
255
+ tda --json chat status <conversation-id>
256
+ ```
257
+
258
+ Creating an automation is another kind of conversation. State the desired publication behavior in
259
+ the message:
260
+
261
+ ```bash
262
+ tda chat start "Create and publish an automation that reschedules overdue tasks every night"
263
+
264
+ tda chat start \
265
+ "Create an automation that reschedules overdue tasks every night, but leave it as a draft"
266
+ ```
267
+
268
+ The CLI does not add publication or draft instructions to these messages.
269
+
270
+ ## Agent usage
271
+
272
+ The CLI streams one durable server turn and exits. In NDJSON mode, `turn_started` means the process is
273
+ still active, and silence produces periodic `turn_progress` heartbeats. Keep monitoring the same
274
+ process until both of these are true:
275
+
276
+ 1. It emits `turn_completed` with `terminal: true`.
277
+ 2. The process exits.
278
+
279
+ Only then should an agent invoke `tda chat continue` with the emitted conversation ID. A local
280
+ per-conversation lock rejects a concurrent turn and reports the PID that is already active. The lock
281
+ protects processes on the same machine; it is not a distributed backend lock.
282
+
283
+ In a human terminal without `--json`, `--ndjson`, or `--no-interactive`, the command remains open as
284
+ an interactive conversation.
285
+
286
+ ```ndjson
287
+ {"type":"turn_started","conversationId":"...","state":"running","terminal":false}
288
+ {"type":"turn_progress","conversationId":"...","state":"running","terminal":false,"elapsedSeconds":30}
289
+ {"type":"turn_completed","conversationId":"...","state":"completed","terminal":true,"outcome":"awaiting_input","resumeCommand":"tda chat continue ..."}
290
+ ```
291
+
292
+ If a conversation publishes an automation, `tda` archives the conversation before emitting the
293
+ terminal `turn_completed` event. Successful machine output includes `conversation_archived` and
294
+ `conversationArchived: true`. If publication succeeds but archival fails, the CLI emits a
295
+ `TDA_CHAT_ARCHIVE_FAILED` warning and completes with `conversationArchived: false`; agents must not
296
+ retry publication in response to that warning.
297
+
298
+ ## Connections
299
+
300
+ Discover every service supported by Automations and include the current user's connection status:
301
+
302
+ ```bash
303
+ tda connector list
304
+ tda connector list --query github
305
+ tda connector list --capability mcp
306
+ tda connector list --connection-status authorized
307
+ tda connector list --capability trigger --connection-status expired
308
+ tda connector list --without-connections
309
+ tda connector list --no-connections
310
+ tda connector view github
311
+ ```
312
+
313
+ `--capability` filters connectors by what they support but does not remove other capabilities or
314
+ connections from the output. When combined with `--connection-status`, both conditions must match
315
+ the same connection. `--without-connections` returns only connectors for which the user has no
316
+ connection records. `--no-connections` skips fetching connection data and omits the `connections`
317
+ field; it cannot be combined with connection filters.
318
+
319
+ List the published automations that require a connector:
320
+
321
+ ```bash
322
+ tda connector automations github
323
+ ```
324
+
325
+ Start a connection directly, or resume and repair an existing setup:
326
+
327
+ ```bash
328
+ tda connector connect github --capability mcp
329
+ tda connector wait <connection-id>
330
+ tda connector repair <connection-id>
331
+ ```
332
+
333
+ OAuth setup opens in the default browser. Managed connectors print their instructions and setup
334
+ code. Use the global `--no-open` option to print setup links without opening them.
335
+
336
+ Disconnecting is preview-only unless `--yes` is present. The CLI refuses to disconnect an exact
337
+ connection used by any enabled automation. Disabled automations do not block disconnection, but they
338
+ will need a valid connection before they can run again.
339
+
340
+ ```bash
341
+ tda connector disconnect <connection-id>
342
+ tda connector disconnect <connection-id> --yes
343
+ ```
344
+
345
+ The dependency check currently runs in the CLI before deletion and is not atomic with the backend
346
+ operation. Backend enforcement is tracked in
347
+ [#3928](https://github.com/Doist/automations/issues/3928).
348
+
349
+ ### Connections requested by chat
350
+
351
+ The backend and CLI automatically reuse the sole authorized account for a requested service. When
352
+ more than one authorized account exists, machine mode emits an `action_required` event containing
353
+ the available connection IDs. Resolve it with:
354
+
355
+ ```bash
356
+ tda --ndjson chat continue <conversation-id> \
357
+ --connection slack:mcp=<connection-id>
358
+ ```
359
+
360
+ Repeat `--connection` when several service choices are required.
361
+
362
+ When no authorized account exists, the CLI creates a connection and waits for setup to complete. For
363
+ OAuth connectors it prints the authorization URL and opens it in the default browser. For managed
364
+ connectors it prints the setup instructions and code, and opens the deep link when one is available.
365
+ Machine mode emits `connection_authorization_started`, periodic
366
+ `connection_authorization_waiting`, and `connection_authorized` events while the same process stays
367
+ alive. Pending setup is reused if the command is interrupted and resumed, avoiding duplicate
368
+ connections.
369
+
370
+ Use `--no-open` to print OAuth and managed deep-link URLs without trying to launch a browser:
371
+
372
+ ```bash
373
+ tda --no-open --ndjson chat start "Help me troubleshoot my Slack automation"
374
+ ```
375
+
376
+ ## Agent skill
377
+
378
+ `tda` ships a skill document that teaches a coding agent how to drive it: which command answers which
379
+ question, what each flag really does, the chat turn protocol, and the error codes worth branching on.
380
+ Install it for whichever agents you use:
381
+
382
+ ```bash
383
+ tda skill install claude-code # writes ~/.claude/skills/automations-cli/SKILL.md
384
+ tda skill install claude-code --local # writes ./.claude/skills/automations-cli/SKILL.md
385
+ tda skill list
386
+ tda skill update all
387
+ tda skill uninstall claude-code
388
+ ```
389
+
390
+ `tda skill list` shows every supported agent (`claude-code`, `codex`, `copilot`, `cursor`, `gemini`,
391
+ `pi`, and `universal` for `~/.agents`) along with whether its skill file is missing, current, or
392
+ outdated. A global install refuses when the agent's home directory does not exist, so a typo cannot
393
+ create a directory nothing reads; use `--local` or the `universal` target instead. Already-installed
394
+ skill files are rewritten by `npm run build:cli`, which is when the document can change, so a rebuilt
395
+ CLI never leaves an agent reading instructions that no longer match it. `tda skill update all` does
396
+ the same on demand.
397
+
398
+ The document's source is `src/lib/skills/content.ts`, and `skills/automations-cli/SKILL.md` is the
399
+ generated copy committed for review. Edit the former and run `npm run sync:skill`; `npm run check`
400
+ fails when they diverge.