@junoflow/cli 0.14.0 → 0.17.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
@@ -45,11 +45,24 @@ writes the descriptions and classifies each command's effect.
45
45
 
46
46
  ### Help
47
47
 
48
- | Command | Shows |
49
- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
50
- | `juno --help` | the groups and top-level commands. Offline. |
51
- | `juno <group> --help` | the group's commands, each with its effect and the first sentence of its description. Offline, it lists the commands alone. |
52
- | `juno <group> <verb> --help` | the tool's full description, its effect, its input schema, and what the positional and flags fill in. Needs the instance. |
48
+ | Command | Shows |
49
+ | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
50
+ | `juno --help` (or `juno`) | the guide to working with Juno, every group and top-level command, and the skill index. See below. |
51
+ | `juno <group> --help` | the skills to read first, then the group's commands, each with its effect and the first sentence of its description. Offline, it lists the commands alone. |
52
+ | `juno <group> <verb> --help` | the skills to read first, the tool's full description, its effect, its input schema, and what the positional and flags fill in. Needs the instance. |
53
+
54
+ `juno --help` is where an agent starts, with nothing installed: after the usage
55
+ lines comes the instance's guide (what Juno is made of, how to work with it from
56
+ the CLI, what only the user does), then each group and top-level command by one
57
+ line (the working-copy commands are in their group's help), and the skills
58
+ `juno skill <name>` prints, each by its first sentence. The guide and the skills
59
+ come from the instance; offline the rest is still printed, with one line on how
60
+ to connect and the reason on stderr. Bare `juno` prints the same and exits 0.
61
+
62
+ A group's or a command's help starts with a `Read first:` line when the instance
63
+ names skills for it — `Read first: juno skill diagnose state` above
64
+ `juno state --help`'s commands. Run it before the command: one call prints them
65
+ all.
53
66
 
54
67
  `juno <group>` on its own prints the group's help and exits 2. An unknown
55
68
  command suggests the closest one: `juno stat get` answers
@@ -65,9 +78,9 @@ Every command has one effect:
65
78
  - **act** does something now (calls a service, presses a button, sets a value,
66
79
  starts a run, executes code), with nothing to roll back to.
67
80
 
68
- `config set` and `agent-skill install` are **local**: they write a file on your
69
- machine and change nothing on the instance. So is `app dev`, which serves an app
70
- working copy on localhost and never connects to an instance.
81
+ `config set` is **local**: it writes a file on your machine and changes nothing
82
+ on the instance. So is `app dev`, which serves an app working copy on localhost
83
+ and never connects to an instance.
71
84
 
72
85
  No command of a lower effect is a string prefix of a command of a higher one.
73
86
  Claude Code matches a Bash permission rule by prefix, so an allowlist can list
@@ -86,27 +99,32 @@ positional; its input is a whole document (`device write`) or has no id
86
99
  | --------------------------------------- | ------------- | ----------------------------------- | ------ |
87
100
  | `juno discover <query> [--kind k]…` | `discover` | `query`; `--kind` → `kinds` | read |
88
101
  | `juno related <kind>:<id> [--degree n]` | `get_related` | `kind`, `id`; `--degree` → `degree` | read |
89
- | `juno skill [<name>] [--json]` | none | skill name | read |
102
+ | `juno skill [<name>...] [--json]` | none | skill name | read |
90
103
  | `juno ask ["<prompt>"]` | none | the prompt | act |
91
- | `juno agent-skill install` | none | none | local |
104
+ | `juno whoami` | none | none | read |
105
+ | `juno version` | none | none | read |
106
+ | `juno permissions` | none | none | read |
92
107
 
93
108
  `related` splits its positional on the first `:` only, so
94
109
  `endpoint:ha:light.hallway` is kind `endpoint`, id `ha:light.hallway`.
95
110
 
96
111
  **`state`**
97
112
 
98
- | Command | Tool | Positional | Effect |
99
- | --------------------------- | ------------------------------------- | ---------- | ------ |
100
- | `juno state get` | `get_state` | `id` | read |
101
- | `juno state get-history` | `get_state_history` | `id` | read |
102
- | `juno state get-layers` | `get_state_layers` | `id` | read |
103
- | `juno state evaluate-level` | `evaluate_level` | — | read |
104
- | `juno state preview-layers` | `edit_state_layers`, `dry_run: true` | `id` | read |
105
- | `juno state create` | `create_state` | `id` | change |
106
- | `juno state edit-layers` | `edit_state_layers`, `dry_run: false` | `id` | change |
107
- | `juno state set-value` | `set_state_value` | `id` | act |
108
- | `juno state claim` | `claim_state` | `id` | act |
109
- | `juno state release` | `release_state` | `id` | act |
113
+ | Command | Tool | Positional | Effect |
114
+ | -------------------------------- | ------------------------------------- | ---------- | ------ |
115
+ | `juno state get` | `get_state` | `id` | read |
116
+ | `juno state get-history` | `get_state_history` | `id` | read |
117
+ | `juno state get-layers` | `get_state_layers` | `id` | read |
118
+ | `juno state evaluate-level` | `evaluate_level` | — | read |
119
+ | `juno state preview-layers` | `edit_state_layers`, `dry_run: true` | `id` | read |
120
+ | `juno state list-layer-versions` | `list_state_layer_versions` | `id` | read |
121
+ | `juno state create` | `create_state` | `id` | change |
122
+ | `juno state edit-layers` | `edit_state_layers`, `dry_run: false` | `id` | change |
123
+ | `juno state restore-layers` | `restore_state_layers` | `id` | change |
124
+ | `juno state set-value` | `set_state_value` | `id` | act |
125
+ | `juno state claim` | `claim_state` | `id` | act |
126
+ | `juno state release` | `release_state` | `id` | act |
127
+ | `juno state delete` | `delete_state` | `id` | act |
110
128
 
111
129
  `preview-layers` and `edit-layers` call the same tool. The preview always sends
112
130
  `dry_run: true`, so a permission rule can allow the preview and not the edit; an
@@ -114,12 +132,23 @@ positional; its input is a whole document (`device write`) or has no id
114
132
 
115
133
  **`flow`**
116
134
 
117
- | Command | Tool | Positional | Effect |
118
- | ------------------------ | ------------------ | ---------- | ------ |
119
- | `juno flow get` | `get_flow` | `id` | read |
120
- | `juno flow set-enabled` | `set_flow_enabled` | `flow_id` | change |
121
- | `juno flow trigger` | `trigger_flow` | `flow_id` | act |
122
- | `juno flow fire-trigger` | `fire_trigger` | `flow_id` | act |
135
+ | Command | Tool | Positional | Effect |
136
+ | --------------------------- | ---------------------- | ---------- | ------ |
137
+ | `juno flow get` | `get_flow` | `id` | read |
138
+ | `juno flow list-versions` | `list_flow_versions` | `id` | read |
139
+ | `juno flow get-next-fire` | `get_next_fire` | `flow_id` | read |
140
+ | `juno flow restore-version` | `restore_flow_version` | `id` | change |
141
+ | `juno flow set-enabled` | `set_flow_enabled` | `flow_id` | change |
142
+ | `juno flow rename` | `rename_flow` | `id` | change |
143
+ | `juno flow trigger` | `trigger_flow` | `flow_id` | act |
144
+ | `juno flow fire-trigger` | `fire_trigger` | `flow_id` | act |
145
+ | `juno flow delete` | `delete_flow` | `id` | act |
146
+
147
+ Every `restore-version` row, and `state restore-layers`, takes the version as
148
+ `--version N`, numbered as its `list-versions` row lists them. `flow rename`
149
+ takes `--slug` (the new id) and `--name`, either or both, and answers the flows
150
+ whose targets named the old id as `broken_callers`. `get-next-fire` takes
151
+ `--trigger` to answer one schedule trigger rather than all of the flow's.
123
152
 
124
153
  The group's working-copy commands (`flow init`, `gen-types`, `check`, `deploy`,
125
154
  `pull`) are in [Flows as files](#flows-as-files).
@@ -131,14 +160,47 @@ The group's working-copy commands (`flow init`, `gen-types`, `check`, `deploy`,
131
160
  | `juno run list` | `list_runs` | — | read |
132
161
  | `juno run get` | `get_run` | `run_id` | read |
133
162
 
163
+ `run get --follow` streams the run's steps to stderr as they finish, then prints
164
+ the run as `run get` does once it has ended. Ctrl-C stops following (exit 130);
165
+ the run goes on.
166
+
167
+ **`timer`** and **`activity`**
168
+
169
+ | Command | Tool | Positional | Effect |
170
+ | -------------------- | --------------- | ---------- | ------ |
171
+ | `juno timer list` | `list_timers` | — | read |
172
+ | `juno activity list` | `list_activity` | — | read |
173
+
174
+ `timer list` is the Upcoming page: every flow schedule trigger and integration
175
+ schedule, soonest first. `activity list` is the dashboard's run timeline, the
176
+ last `--hours` (24), of every flow or `--flow <id>`, the newest `--limit` (200).
177
+
134
178
  **`integration`**
135
179
 
136
- | Command | Tool | Positional | Effect |
137
- | ------------------------------- | -------------------------- | ------------- | ------ |
138
- | `juno integration get` | `get_integration` | `id` | read |
139
- | `juno integration configure` | `configure_integration` | `id` | change |
140
- | `juno integration install` | `install_integration` | — | act |
141
- | `juno integration run-schedule` | `run_integration_schedule` | `integration` | act |
180
+ | Command | Tool | Positional | Effect |
181
+ | ----------------------------------- | ------------------------------ | ------------- | ------ |
182
+ | `juno integration get` | `get_integration` | `id` | read |
183
+ | `juno integration list-versions` | `list_integration_versions` | `id` | read |
184
+ | `juno integration preview` | `preview_integration` | — | read |
185
+ | `juno integration list-invocations` | `list_integration_invocations` | `id` | read |
186
+ | `juno integration get-deliveries` | `get_integration_deliveries` | `id` | read |
187
+ | `juno integration get-usage` | `get_integration_usage` | `id` | read |
188
+ | `juno integration list-registry` | `list_registry` | — | read |
189
+ | `juno integration configure` | `configure_integration` | `id` | change |
190
+ | `juno integration restore-version` | `restore_integration_version` | `id` | change |
191
+ | `juno integration set-enabled` | `set_integration_enabled` | `id` | change |
192
+ | `juno integration bind-webhook` | `bind_integration_webhook` | `id` | change |
193
+ | `juno integration install` | `install_integration` | — | act |
194
+ | `juno integration invoke-action` | `invoke_integration_action` | `id` | act |
195
+ | `juno integration run-schedule` | `run_integration_schedule` | `integration` | act |
196
+ | `juno integration upgrade` | `upgrade_integration` | `id` | act |
197
+ | `juno integration uninstall` | `uninstall_integration` | `id` | act |
198
+
199
+ `upgrade` takes the new tag or commit as `--ref`; `preview` and `install` take
200
+ their `{url, ref?, path?}` as `--input`. `invoke-action` takes the action as
201
+ `--action` and its params as `--input '{"params": {…}}'`; `bind-webhook` takes
202
+ `--slot` and `--webhook`; `list-invocations` and `get-deliveries` take
203
+ `--limit`.
142
204
 
143
205
  The group's working-copy commands (`integration init`, `gen-types`,
144
206
  `verify-types`, `check`, `deploy`, `pull`) are in
@@ -146,28 +208,68 @@ The group's working-copy commands (`integration init`, `gen-types`,
146
208
 
147
209
  **`device`**
148
210
 
149
- | Command | Tool | Positional | Effect |
150
- | --------------------- | ---------------- | ---------- | ------ |
151
- | `juno device list` | `list_devices` | — | read |
152
- | `juno device get` | `get_device` | `id` | read |
153
- | `juno device preview` | `preview_device` | — | read |
154
- | `juno device write` | `write_device` | — | change |
155
- | `juno device suspend` | `suspend_device` | `id` | act |
156
- | `juno device release` | `release_device` | `id` | act |
211
+ | Command | Tool | Positional | Effect |
212
+ | ----------------------------- | ------------------------ | ---------- | ------ |
213
+ | `juno device list` | `list_devices` | — | read |
214
+ | `juno device get` | `get_device` | `id` | read |
215
+ | `juno device preview` | `preview_device` | — | read |
216
+ | `juno device list-versions` | `list_device_versions` | `id` | read |
217
+ | `juno device write` | `write_device` | — | change |
218
+ | `juno device restore-version` | `restore_device_version` | `id` | change |
219
+ | `juno device suspend` | `suspend_device` | `id` | act |
220
+ | `juno device release` | `release_device` | `id` | act |
221
+ | `juno device delete` | `delete_device` | `id` | act |
157
222
 
158
223
  **`control`**
159
224
 
160
- | Command | Tool | Positional | Effect |
161
- | ---------------------- | ----------------- | ---------- | ------ |
162
- | `juno control write` | `write_control` | — | change |
163
- | `juno control use` | `use_control` | `id` | act |
164
- | `juno control release` | `release_control` | `id` | act |
225
+ | Command | Tool | Positional | Effect |
226
+ | ------------------------------ | ------------------------- | ---------- | ------ |
227
+ | `juno control get` | `get_control` | `id` | read |
228
+ | `juno control list` | `list_controls` | — | read |
229
+ | `juno control get-history` | `get_control_history` | `id` | read |
230
+ | `juno control get-activity` | `get_control_activity` | `id` | read |
231
+ | `juno control list-versions` | `list_control_versions` | `id` | read |
232
+ | `juno control write` | `write_control` | — | change |
233
+ | `juno control restore-version` | `restore_control_version` | `id` | change |
234
+ | `juno control use` | `use_control` | `id` | act |
235
+ | `juno control extend` | `extend_control` | `id` | act |
236
+ | `juno control release` | `release_control` | `id` | act |
237
+ | `juno control delete` | `delete_control` | `id` | act |
238
+
239
+ **`app`**
240
+
241
+ | Command | Tool | Positional | Effect |
242
+ | --------------------------- | ---------------------- | ---------- | ------ |
243
+ | `juno app get` | `get_app` | `id` | read |
244
+ | `juno app list-invocations` | `list_app_invocations` | `id` | read |
245
+ | `juno app list-versions` | `list_app_versions` | `id` | read |
246
+ | `juno app list-links` | `list_app_links` | `id` | read |
247
+ | `juno app restore-version` | `restore_app_version` | `id` | change |
248
+ | `juno app set-enabled` | `set_app_enabled` | `id` | change |
249
+ | `juno app create-link` | `create_app_link` | `id` | act |
250
+ | `juno app revoke-link` | `revoke_app_link` | `id` | act |
251
+ | `juno app delete` | `delete_app` | `id` | act |
252
+
253
+ An app link lets whoever holds it use the app without logging in. `create-link`
254
+ takes `--name` and `--expires-at` (RFC 3339); `revoke-link` takes `--link <id>`
255
+ and waits for a person, as a delete does. Each link is answered with its `url`,
256
+ never its bare token. The working-copy commands are in
257
+ [Working copies](#working-copies).
165
258
 
166
259
  **`finding`**
167
260
 
168
- | Command | Tool | Positional | Effect |
169
- | ------------------ | ------------- | ---------- | ------ |
170
- | `juno finding get` | `get_finding` | `slug` | read |
261
+ | Command | Tool | Positional | Effect |
262
+ | -------------------------- | --------------------- | ---------- | ------ |
263
+ | `juno finding list` | `list_findings` | — | read |
264
+ | `juno finding get` | `get_finding` | `slug` | read |
265
+ | `juno finding get-history` | `get_finding_history` | `slug` | read |
266
+ | `juno finding dismiss` | `dismiss_finding` | `slug` | act |
267
+
268
+ `finding list` shows open findings of every owner — flows, integrations,
269
+ devices, states and tasks — each naming its source as `owner_kind`, `owner` and
270
+ `owner_name`; `--status all` adds cleared ones, and `--owner-kind`, `--owner`
271
+ and `--severity` (a floor) narrow it. `get-history` and `dismiss` take `--key`
272
+ for a keyed finding; `get-history` also takes `--limit`.
171
273
 
172
274
  **`webhook`**
173
275
 
@@ -177,32 +279,73 @@ The group's working-copy commands (`integration init`, `gen-types`,
177
279
  | `juno webhook get-deliveries` | `get_webhook_deliveries` | `id` | read |
178
280
  | `juno webhook write` | `write_webhook` | `id` | change |
179
281
  | `juno webhook fire` | `fire_webhook` | `id` | act |
180
-
181
- **`job`** (external jobs)
182
-
183
- | Command | Tool | Positional | Effect |
184
- | ------------------------------------ | -------------- | ---------- | ------ |
185
- | `juno job list` | `list_jobs` | — | read |
186
- | `juno job get-runs` | `get_job_runs` | `id` | read |
187
- | `juno job write` | `write_job` | `id` | change |
188
- | `juno job delete` | `delete_job` | `id` | act |
189
- | `juno job run [<url>] -- <command>…` | none | ping URL | act |
190
- | `juno job ping [<url>]` | none | ping URL | act |
282
+ | `juno webhook delete` | `delete_webhook` | `id` | act |
283
+ | `juno webhook rotate-token` | `rotate_webhook_token` | `id` | act |
284
+
285
+ **`task`** (tasks)
286
+
287
+ | Command | Tool | Positional | Effect |
288
+ | ------------------------------------- | --------------------- | ---------- | ------ |
289
+ | `juno task list` | `list_tasks` | — | read |
290
+ | `juno task get-runs` | `get_task_runs` | `id` | read |
291
+ | `juno task get-occurrence` | `get_task_occurrence` | `id` | read |
292
+ | `juno task inbox` | `list_task_inbox` | — | read |
293
+ | `juno task write` | `write_task` | `id` | change |
294
+ | `juno task delete` | `delete_task` | `id` | act |
295
+ | `juno task rotate-token` | `rotate_task_token` | `id` | act |
296
+ | `juno task open` | `command_task` | `id` | act |
297
+ | `juno task snooze` | `command_task` | `id` | act |
298
+ | `juno task set-due` | `command_task` | `id` | act |
299
+ | `juno task complete` | `command_task` | `id` | act |
300
+ | `juno task skip` | `command_task` | `id` | act |
301
+ | `juno task cancel` | `command_task` | `id` | act |
302
+ | `juno task run [<url>] -- <command>…` | none | ping URL | act |
303
+ | `juno task ping [<url>]` | none | ping URL | act |
304
+
305
+ The six verb commands name the work with `--key` (the schedule's when omitted)
306
+ and take their verb's fields as flags: `open` `--at` `--within` `--reason`,
307
+ `snooze` `--until`, `set-due` `--at`, `complete` `--outcome` `--note` and
308
+ `--check <n>` (repeatable; the checklist numbers `get-occurrence` shows), `skip`
309
+ `--note`, `cancel` `--reason`. `inbox` is the people's due work, `mine` only for
310
+ a signed-in user linked to a person.
311
+
312
+ **`series`**
313
+
314
+ | Command | Tool | Positional | Effect |
315
+ | ----------------- | ------------ | ---------- | ------ |
316
+ | `juno series get` | `get_series` | `id` | read |
191
317
 
192
318
  **`credential`**
193
319
 
194
- | Command | Tool | Positional | Effect |
195
- | -------------------------- | ------------------ | ------------- | ------ |
196
- | `juno credential list` | `list_credentials` | — | read |
197
- | `juno credential set <id>` | none | credential id | act |
320
+ | Command | Tool | Positional | Effect |
321
+ | -------------------------- | ------------------- | ------------- | ------ |
322
+ | `juno credential list` | `list_credentials` | — | read |
323
+ | `juno credential delete` | `delete_credential` | `id` | act |
324
+ | `juno credential set <id>` | none | credential id | act |
198
325
 
199
326
  **`person`**
200
327
 
201
- | Command | Tool | Positional | Effect |
202
- | ------------------- | -------------- | ---------- | ------ |
203
- | `juno person list` | `list_people` | — | read |
204
- | `juno person get` | `get_person` | `id` | read |
205
- | `juno person write` | `write_person` | `id` | change |
328
+ | Command | Tool | Positional | Effect |
329
+ | -------------------------- | --------------- | ---------- | ------ |
330
+ | `juno person list` | `list_people` | — | read |
331
+ | `juno person get` | `get_person` | `id` | read |
332
+ | `juno person write` | `write_person` | `id` | change |
333
+ | `juno person test-contact` | `test_contact` | `id` | act |
334
+ | `juno person delete` | `delete_person` | `id` | act |
335
+
336
+ `test-contact` takes `--contact <id>` and really sends the test message.
337
+
338
+ **`approval`**
339
+
340
+ | Command | Tool | Positional | Effect |
341
+ | ------------------------- | ---------------- | ----------- | ------ |
342
+ | `juno approval list` | `list_approvals` | — | read |
343
+ | `juno approval get` | `get_approval` | `id` | read |
344
+ | `juno approval wait <id>` | none | approval id | read |
345
+
346
+ `list` takes `--status` (`pending`, `executed`, `denied`, …). There is no
347
+ command that approves one: see
348
+ [Destructive commands wait for a person](#destructive-commands-wait-for-a-person).
206
349
 
207
350
  **`ha`** (Home Assistant)
208
351
 
@@ -211,8 +354,22 @@ The group's working-copy commands (`integration init`, `gen-types`,
211
354
  | `juno ha get-entity` | `get_entity` | `entity_id` | read |
212
355
  | `juno ha get-entity-history` | `get_entity_history` | `entity_id` | read |
213
356
  | `juno ha list-services` | `list_services` | — | read |
357
+ | `juno ha list-entities` | `list_entities` | — | read |
358
+ | `juno ha get-diagnostics` | `get_ha_diagnostics` | — | read |
214
359
  | `juno ha call-service` | `call_service` | — | act |
215
360
 
361
+ `list-entities` takes `--query` and `--limit`.
362
+
363
+ **`mqtt`**
364
+
365
+ | Command | Tool | Positional | Effect |
366
+ | --------------------------- | ---------------------- | ---------- | ------ |
367
+ | `juno mqtt list-topics` | `list_topics` | — | read |
368
+ | `juno mqtt get-diagnostics` | `get_mqtt_diagnostics` | — | read |
369
+
370
+ `list-topics` takes `--query` (a topic filter with `+`/`#`, or a substring),
371
+ `--sort` (`recent`, `topic`, `count`) and `--limit`.
372
+
216
373
  **`script`**
217
374
 
218
375
  | Command | Tool | Positional | Effect |
@@ -226,10 +383,18 @@ under `files` by its basename and makes it the `entry`.
226
383
 
227
384
  | Command | Tool | Positional | Effect |
228
385
  | ----------------------------- | ---- | ------------- | ------ |
386
+ | `juno session list` | none | none | read |
387
+ | `juno session get <id>` | none | session id | read |
388
+ | `juno session export <id>` | none | session id | read |
389
+ | `juno session rate <id>` | none | session id | change |
229
390
  | `juno session approve <id>` | none | session id | act |
391
+ | `juno session cancel <id>` | none | session id | act |
230
392
  | `juno config set url <url>` | none | `url <url>` | local |
231
393
  | `juno config set token <key>` | none | `token <key>` | local |
232
394
 
395
+ `session list` takes `--rating`, `--profile` and `--limit`; `session get` takes
396
+ `--transcript`; `session rate` takes `--rating up|down|addressed|none`.
397
+
233
398
  There is no command that calls a tool by name. One permission rule for such a
234
399
  command would allow every act, so each tool has its own command instead, and a
235
400
  tool added to the server needs a CLI release to reach.
@@ -268,6 +433,10 @@ the same bytes. A tool that fails in its own terms answers `{"error": "…"}`;
268
433
  that is printed on stdout like any answer, and the exit code is 1. Warnings,
269
434
  progress and notes go to standard error.
270
435
 
436
+ When the instance refuses a call — that `{"error": "…"}`, or input the tool
437
+ rejects (exit 2) — and a skill explains the tool, the last line on standard
438
+ error names it: `see: juno skill state`. Read it before trying again.
439
+
271
440
  `--jq <expr>` runs the answer through [`jq`](https://jqlang.org), which must be
272
441
  on `PATH` (`jq -c` off a terminal, plain `jq` on one). A filter given this way
273
442
  stays inside the command's own permission rule, where a pipe to `jq` would need
@@ -277,19 +446,44 @@ its own. A missing `jq` or an expression `jq` rejects exits 2.
277
446
 
278
447
  One table for the whole CLI, the working-copy commands included:
279
448
 
280
- | Code | When |
281
- | ---- | ---------------------------------------------------------------------------------------------------- |
282
- | 0 | Success |
283
- | 1 | A tool answer with a top-level string `error`, a failed check or deploy, or any other failure |
284
- | 2 | Usage: an unknown command or flag, bad `--input`, input the instance rejects, a bad `--jq` |
285
- | 3 | The instance is unreachable |
286
- | 4 | A working-copy `deploy` or `check`, any kind: the instance changed since the working copy was pulled |
287
- | 5 | `juno ask` / `session approve`: the turn is still running |
288
- | 6 | `juno ask` / `session approve`: the assistant is waiting for an answer or an approval |
449
+ | Code | When |
450
+ | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
451
+ | 0 | Success |
452
+ | 1 | A tool answer with a top-level string `error`, a failed check or deploy, or any other failure |
453
+ | 2 | Usage: an unknown command or flag, bad `--input`, input the instance rejects, a bad `--jq` |
454
+ | 3 | The instance is unreachable |
455
+ | 4 | A working-copy `deploy` or `check`, any kind: the instance changed since the working copy was pulled |
456
+ | 5 | `juno ask` / `session approve`: the turn is still running; a destructive command or `approval wait`: nobody decided the approval within `--wait` |
457
+ | 6 | `juno ask` / `session approve`: the assistant is waiting for an answer or an approval |
458
+ | 130 | Ctrl-C while a destructive command waits for its approval (the request stays open), or while `run get --follow` follows (the run goes on) |
289
459
 
290
460
  An instance that does not serve a tool the CLI names is older than the CLI; that
291
461
  is also exit 2, and the message says so.
292
462
 
463
+ ### Destructive commands wait for a person
464
+
465
+ A command that deletes something, rotates a token or revokes an app link (every
466
+ `delete` command, `juno integration uninstall`, both `rotate-token` commands,
467
+ `juno app revoke-link`, and any tool the instance marks `destructive`) runs
468
+ nothing by itself. The instance holds the request until a person approves it in
469
+ Juno, in the browser; no command, tool or API key can approve it. The command
470
+ prints what needs approving and where on stderr, then waits for the decision:
471
+
472
+ ```
473
+ $ juno task delete smoke
474
+ Approval needed: delete task "smoke" (Smoke test).
475
+ Approve or deny in Juno: https://juno.example/approvals/apr_7Kq2…
476
+ waiting up to 300s… (Ctrl-C leaves the request open: juno approval wait apr_7Kq2…)
477
+ {"deleted":true,"id":"smoke","ok":true,"approval":{"id":"apr_7Kq2…","approved_by":"user:victor"}}
478
+ ```
479
+
480
+ Approved, it prints the action's result with `approval` beside it and exits as
481
+ the action would (0, or 1 on an `error`). Denied, expired, or failed when it
482
+ ran: `{"error": "denied by user:victor"}` and the like, exit 1.
483
+ `--wait <seconds>` (default 300; 0 does not wait) bounds the wait; when it runs
484
+ out the request stays open, the `approval_required` answer is printed and the
485
+ exit code is 5. `juno approval wait <id>` picks the wait up again.
486
+
293
487
  ### `juno ask` and `juno session approve`
294
488
 
295
489
  `juno ask` sends a prompt to Juno's in-app assistant through the
@@ -338,15 +532,15 @@ exits 1 without sending anything otherwise. Any other message sent to a session
338
532
  waiting for an approval denies it, and the assistant sees the message as the
339
533
  reason.
340
534
 
341
- ### `juno job run`
535
+ ### `juno task run`
342
536
 
343
- Wraps a scheduled command so its runs are reported to an external job's ping URL
344
- (`juno job write` answers it as `url`):
537
+ Wraps a scheduled command so its runs are reported to a task's ping URL
538
+ (`juno task write` answers it as `url`):
345
539
 
346
540
  ```bash
347
- juno job run https://juno.example/ping/<token> -- ./backup.sh --full
348
- juno job run --url-file .secrets/juno-jobs/backup -- ./backup.sh --full
349
- JUNO_JOB_URL=https://juno.example/ping/<token> juno job run -- python3 check.py
541
+ juno task run https://juno.example/ping/<token> -- ./backup.sh --full
542
+ juno task run --url-file .secrets/juno-tasks/backup -- ./backup.sh --full
543
+ JUNO_TASK_URL=https://juno.example/ping/<token> juno task run -- python3 check.py
350
544
  ```
351
545
 
352
546
  The command runs exactly as it would unwrapped: same stdin, the same stdout and
@@ -355,33 +549,33 @@ signal `N`; 127, or 126 for a file that is not executable, when it cannot be
355
549
  started). Everything after `--` is the command's, flags included. Juno gets a
356
550
  `start`, then the exit status with the last 64 KiB of stdout and stderr, paired
357
551
  by a run id. The URL comes from the argument, else `--url-file` (keeps the token
358
- out of `ps`), else `$JUNO_JOB_URL`; nothing else is read — no instance config,
552
+ out of `ps`), else `$JUNO_TASK_URL`; nothing else is read — no instance config,
359
553
  no API key. A report that fails is retried once and then dropped silently
360
554
  (`--verbose` prints one line): Juno turns a run it never heard about into an
361
555
  overdue finding by itself. `SIGINT`, `SIGTERM` and `SIGHUP` are passed on to the
362
556
  command.
363
557
 
364
- The wrapper never times a command out: a run that hangs stays open, and the job
558
+ The wrapper never times a command out: a run that hangs stays open, and the task
365
559
  goes down once its start plus grace has passed. A wrapper killed outright leaves
366
560
  the run open the same way.
367
561
 
368
- ### `juno job ping`
562
+ ### `juno task ping`
369
563
 
370
564
  Sends one report, for a task with no command to wrap:
371
565
 
372
566
  ```bash
373
- juno job ping --url-file .secrets/juno-jobs/digest # success
374
- juno job ping --url-file .secrets/juno-jobs/digest --start --rid r1
375
- juno job ping --url-file .secrets/juno-jobs/digest --exit 3 --rid r1
376
- juno job ping --url-file .secrets/juno-jobs/digest --fail
567
+ juno task ping --url-file .secrets/juno-tasks/digest # success
568
+ juno task ping --url-file .secrets/juno-tasks/digest --start --rid r1
569
+ juno task ping --url-file .secrets/juno-tasks/digest --exit 3 --rid r1
570
+ juno task ping --url-file .secrets/juno-tasks/digest --fail
377
571
  ```
378
572
 
379
- The URL comes from the same three places as `juno job run`'s. `--log` sends a
573
+ The URL comes from the same three places as `juno task run`'s. `--log` sends a
380
574
  log report, and `--rid` pairs a start with its finish. A report that still fails
381
575
  after one retry exits 1 with the reason.
382
576
 
383
- See [External jobs](https://boivie.github.io/juno/external-jobs/) for creating
384
- the job, the ping protocol, and systemd and crontab examples.
577
+ See [Tasks](https://boivie.github.io/juno/tasks/) for creating the task, the
578
+ ping protocol, and systemd and crontab examples.
385
579
 
386
580
  ### `juno credential set`
387
581
 
@@ -402,26 +596,30 @@ Claude Code. For the same reason there is no tool that writes a credential.
402
596
  ### `juno skill`
403
597
 
404
598
  `juno skill` lists the skills the assistant can load, one
405
- `<name> — <description>` line each. `juno skill <name>` prints one skill's body.
406
- `--json` prints the instance's JSON instead. The skills are the in-app
407
- assistant's, rendered for a reader outside Juno: where the assistant reads a
408
- tool name (`edit_state_layers`), you read the command in front of it
409
- (`juno state edit-layers`), or what to do in a working copy instead
410
- (`npm run deploy` for `submit_code`).
599
+ `<name> — <description>` line each; a description starts with when to load the
600
+ skill. `juno skill <name>` prints one skill's body, and `juno skill <a> <b> …`
601
+ several, each under a `===== <name> =====` line. `--json` prints the instance's
602
+ JSON instead (an array for several names). An unknown name fails the call with
603
+ nothing printed. The skills are the in-app assistant's, rendered for a reader
604
+ outside Juno: where the assistant reads a tool name (`edit_state_layers`), you
605
+ read the command in front of it (`juno state edit-layers`), or what to do in a
606
+ working copy instead (`npm run deploy` for `submit_code`).
411
607
 
412
- ### `juno agent-skill install`
608
+ ### `juno permissions`
413
609
 
414
610
  ```bash
415
- juno agent-skill install # .claude/skills/juno/SKILL.md
416
- juno agent-skill install --dir ~/.claude/skills/juno # for every project
417
- juno agent-skill install --allow-change # + every change command
418
- juno agent-skill install --working-copy # + the npm scripts (run it in a working copy)
419
- juno agent-skill install --agents-md >> AGENTS.md # for a harness that reads AGENTS.md
611
+ juno permissions # every read command
612
+ juno permissions --allow-change # + every change command
613
+ juno permissions --working-copy # + the npm scripts (run it in a working copy)
420
614
  ```
421
615
 
422
- Writes the skill that teaches a coding agent to use Juno — `SKILL.md` in the
423
- Agent Skills format, rendered by the instance (`GET /api/agent-skill`) — and
424
- prints a Claude Code permission block on stdout:
616
+ There is nothing to install for a coding agent: `juno --help` is the primer,
617
+ served live by the instance, and `juno skill` the topic skills. A line in your
618
+ `AGENTS.md` or `CLAUDE.md` such as "Juno home automation is operated with the
619
+ `juno` CLI; run `juno --help` first" is all an agent needs to find it.
620
+
621
+ `juno permissions` prints a Claude Code permission block on stdout, rendered by
622
+ the instance (`GET /api/agent-permissions`):
425
623
 
426
624
  ```json
427
625
  {"permissions":{"allow":["Bash(juno discover:*)","Bash(juno related:*)","Bash(juno state get:*)",…]}}
@@ -437,13 +635,8 @@ trust whatever that `package.json` says the script runs, so put them in the
437
635
  working copy's `.claude/settings.json`, never in user-wide settings. **An `act`
438
636
  command is never in the block**: it always prompts. Add one by hand if you want
439
637
  to, for example, let the agent press a test button. A command added in a later
440
- version prompts until you regenerate the block.
441
-
442
- The skill is short and stable; what changes per instance comes from `juno skill`
443
- and `--help` at run time. It records the version it was rendered at, and
444
- `juno skill`, `juno flow init` and `juno integration init` say on stderr when
445
- the instance serves a newer one. `--agents-md` prints the same text as an
446
- `AGENTS.md` section and writes nothing; `--json` prints the instance's answer.
638
+ version prompts until you regenerate the block. `--json` prints the instance's
639
+ answer.
447
640
 
448
641
  ## Choosing an instance
449
642