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