@fatecannotbealtered-/jira-cli 1.1.0 → 1.1.1

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.
@@ -0,0 +1,691 @@
1
+ # Agent-Facing CLI Design Spec
2
+
3
+
4
+ This document defines the machine contract a CLI must honor when called by an AI agent. The goal: agents can call it reliably, parse it reliably, recover and retry reliably, and never block or mis-write in a non-interactive setting.
5
+
6
+ ## 1. Core rules
7
+
8
+ 1. stdout is the contract: emit a single valid JSON document by default; no logs, progress, prompts, or color codes mixed in.
9
+ 2. stderr is the side channel: progress, warnings, debug, and error explanations all go to stderr.
10
+ 3. Machine-first: default `--format json`; `text` is for humans only; `raw` is for raw bytes, logs, diffs passed through verbatim.
11
+ 4. Non-interactive safe: write operations must not wait on keyboard input; use `--dry-run` + `--confirm <token>`.
12
+ 5. Deterministic: same input produces the same output structure; field names, field order, and schema version stay stable.
13
+ 6. Least surprise: queries don't change state; a write with no valid confirm token must fail rather than proceed.
14
+ 7. Recoverable: error codes, exit codes, and `retryable` must be stable enough for an agent to decide retry, back off, or ask the user.
15
+
16
+ ## 2. Global flags
17
+
18
+ | Flag | Meaning |
19
+ |------|---------|
20
+ | `--format json/text/raw` | Output format, default `json` |
21
+ | `--json` | Compatibility alias for `--format json`; not recommended for new calls |
22
+ | `--fields <a,b,c>` | Return only selected fields, reduces tokens (query commands) |
23
+ | `--compact` | Compact JSON output, strips redundant whitespace (query commands) |
24
+ | `--dry-run` | Simulate a write, return a change preview and `confirm_token` |
25
+ | `--confirm <token>` | Carry the dry-run token to actually execute the write |
26
+ | `--quiet` | Suppress progress/prompts on stderr, never suppress errors |
27
+
28
+ `update` commands may add tool-specific flags such as `--target-version` or
29
+ `--channel`, but they must keep the common lifecycle flags: `--check`,
30
+ `--dry-run`, and `--confirm <token>`.
31
+
32
+ Format responsibilities:
33
+
34
+ - `json`: structured machine output, the default, and the only format recommended for agents.
35
+ - `text`: human-readable, may change, must not be parsed programmatically.
36
+ - `raw`: unwrapped bytes / log / diff, passed through verbatim, no JSON envelope.
37
+
38
+ ## 3. Unified output envelope
39
+
40
+ Success and failure share one shape. The agent only needs to check `ok` first.
41
+
42
+ Success:
43
+
44
+ ```json
45
+ {
46
+ "ok": true,
47
+ "schema_version": "1.0",
48
+ "data": {},
49
+ "meta": {
50
+ "duration_ms": 0
51
+ }
52
+ }
53
+ ```
54
+
55
+ Failure:
56
+
57
+ ```json
58
+ {
59
+ "ok": false,
60
+ "schema_version": "1.0",
61
+ "error": {
62
+ "code": "E_NOT_FOUND",
63
+ "message": "human readable message",
64
+ "details": {},
65
+ "retryable": false
66
+ },
67
+ "meta": {
68
+ "duration_ms": 0
69
+ }
70
+ }
71
+ ```
72
+
73
+ Conventions:
74
+
75
+ - Every JSON response must include `ok` and `schema_version`.
76
+ - `data` is always the command's business payload; do not hoist business fields to the envelope top level.
77
+ - `error.code` is a stable semantic enum, prefixed with `E_`.
78
+ - `error.message` is for humans; agents should not parse it.
79
+ - `error.details` holds structured context; must be redacted.
80
+ - `error.retryable` tells the agent whether it may back off and retry automatically.
81
+ - `meta.duration_ms` records command execution time.
82
+ - A breaking schema change must bump the `schema_version` major version.
83
+
84
+ ## 4. stdout / stderr rules
85
+
86
+ - In `json` mode, stdout may contain only one JSON document, or NDJSON for explicitly streaming commands.
87
+ - stderr may carry progress, warnings, and diagnostics.
88
+ - On error in `json` mode, the failure envelope is that single JSON document on stdout — agents always parse stdout and check `ok`, never scrape stderr. stderr may add human-readable explanation.
89
+ - `--quiet` may only suppress non-error info on stderr.
90
+ - No banners, prompts, progress bars, or color codes before/after the JSON on stdout.
91
+ - stdout / stderr are always **UTF-8 encoded, no BOM**, newline `\n`, so agents parse reliably across platforms (especially Windows).
92
+
93
+ ## 5. Streaming output (NDJSON)
94
+
95
+ Large output, log streams, subscription streams, and per-item batch results use NDJSON. Each line must be an independent valid JSON object — easy to consume streaming, low memory, interruptible:
96
+
97
+ ```jsonl
98
+ {"ok":true,"schema_version":"1.0","type":"item","data":{}}
99
+ {"ok":true,"schema_version":"1.0","type":"item","data":{}}
100
+ {"ok":true,"schema_version":"1.0","type":"summary","data":{"count":2}}
101
+ ```
102
+
103
+ Conventions:
104
+
105
+ - Normal queries use a single JSON envelope by default.
106
+ - Use NDJSON only when the command is explicitly a log / stream / subscribe / batched-stream.
107
+ - NDJSON lines must include `ok`, `schema_version`, `type`.
108
+ - The final line should use `type: "summary"`.
109
+ - True binary or plain-text passthrough goes through `--format raw`, not wrapped into one giant JSON.
110
+
111
+ ## 6. Exit code table
112
+
113
+ | Code | Meaning | Agent behavior |
114
+ |------|---------|----------------|
115
+ | 0 | Success | continue |
116
+ | 1 | Generic error | read the error envelope to decide |
117
+ | 2 | Argument/usage error | don't retry, fix args |
118
+ | 3 | Resource not found | don't retry |
119
+ | 4 | Permission/auth/config failure | don't retry, surface credentials or permission |
120
+ | 5 | Confirmation required but token missing | run dry-run for a token, then retry |
121
+ | 6 | Precondition conflict or invalid token | re-read state, then retry |
122
+ | 7 | Retryable transient error (network/rate-limit/server) | back off and retry |
123
+ | 8 | Timeout | back off and retry |
124
+ | 9 | Human action required (see §15.3, optional) | relay to the user, run `resume` once done |
125
+
126
+ Error codes and exit codes must align:
127
+
128
+ - `E_USAGE` / `E_VALIDATION` -> 2
129
+ - `E_NOT_FOUND` -> 3
130
+ - `E_AUTH` / `E_FORBIDDEN` / `E_CONFIG` -> 4
131
+ - `E_CONFIRMATION_REQUIRED` -> 5
132
+ - `E_CONFLICT` -> 6
133
+ - `E_NETWORK` / `E_RATE_LIMITED` / `E_SERVER` -> 7
134
+ - `E_TIMEOUT` -> 8
135
+ - `E_HUMAN_REQUIRED` -> 9 (optional, only when §15.3 is enabled)
136
+
137
+ ## 7. Write flow (dry-run -> confirm)
138
+
139
+ A write command must first support `--dry-run`, returning a preview and a token:
140
+
141
+ ```json
142
+ {
143
+ "ok": true,
144
+ "schema_version": "1.0",
145
+ "data": {
146
+ "preview": {
147
+ "changes": [
148
+ {
149
+ "action": "delete",
150
+ "resource": "mail",
151
+ "id": "123",
152
+ "before": {},
153
+ "after": null
154
+ }
155
+ ]
156
+ },
157
+ "confirm_token": "ct_9f2a...",
158
+ "expires_at": "2026-06-05T12:00:00Z"
159
+ },
160
+ "meta": {
161
+ "duration_ms": 0
162
+ }
163
+ }
164
+ ```
165
+
166
+ The second step carries the token to execute:
167
+
168
+ ```bash
169
+ tool resource delete --id 123 --confirm ct_9f2a...
170
+ ```
171
+
172
+ Confirm-token conventions:
173
+
174
+ - The token must bind a hash of the operation content: command path, args, target resource ID, calling account, permission context.
175
+ - The hash must be keyed (HMAC) with a machine-local secret (e.g. `~/.<tool>/confirm.secret`, created on first use, `0600`), so a token cannot be fabricated by recomputing a public hash — it must come from a real `--dry-run` on the same machine.
176
+ - When a resource version is available, also bind it (version, etag, changekey, or updated_at) to prevent state drift.
177
+ - The token must expire; `expires_at` is ISO 8601 UTC.
178
+ - On expiry, changed args, or changed target state, execution returns `E_CONFLICT`, exit code 6.
179
+ - With no token, return `E_CONFIRMATION_REQUIRED`, exit code 5.
180
+ - dry-run must not cause external side effects, but may read state to build the preview.
181
+
182
+ ## 8. Query, pagination, and field selection
183
+
184
+ Query commands support, by default:
185
+
186
+ - `--fields <a,b,c>`: return only selected fields; when dotted paths are supported, declare it in reference.
187
+ - `--compact`: strip JSON whitespace.
188
+ - `--limit`: cap the number of returned items.
189
+ - `--cursor` or `--offset`: pagination cursor or offset.
190
+
191
+ Suggested pagination shape:
192
+
193
+ ```json
194
+ {
195
+ "items": [],
196
+ "count": 0,
197
+ "next_cursor": null,
198
+ "has_more": false
199
+ }
200
+ ```
201
+
202
+ Conventions:
203
+
204
+ - All IDs are strings, even if numeric underneath.
205
+ - All times are ISO 8601 UTC.
206
+ - List order must be stable; declare the default sort in reference.
207
+ - Query commands must not fall into an interactive prompt just because an optional filter is missing.
208
+
209
+ ## 9. Idempotency and concurrency safety
210
+
211
+ Write commands should support idempotent semantics where possible:
212
+
213
+ - Create-type commands should support `--request-id` or `--idempotency-key`.
214
+ - Retrying the same idempotency key must not create duplicate resources.
215
+ - Update/delete commands should record the target resource version during dry-run.
216
+ - If a version change is detected at confirm time, return `E_CONFLICT`.
217
+ - Batch writes should return per-item results; don't hide other items' status because one failed.
218
+
219
+ Suggested batch-write result:
220
+
221
+ ```json
222
+ {
223
+ "results": [
224
+ {
225
+ "id": "1",
226
+ "ok": true,
227
+ "action": "deleted"
228
+ },
229
+ {
230
+ "id": "2",
231
+ "ok": false,
232
+ "error": {
233
+ "code": "E_NOT_FOUND"
234
+ }
235
+ }
236
+ ],
237
+ "summary": {
238
+ "ok_count": 1,
239
+ "error_count": 1
240
+ }
241
+ }
242
+ ```
243
+
244
+ ## 10. Sensitive data and auditing
245
+
246
+ - password, token, secret, authorization header, cookie must not appear in stdout, stderr, error.details, or the audit log.
247
+ - dry-run previews must redact sensitive fields.
248
+ - reference/context/doctor must not leak plaintext credentials.
249
+ - context may report whether credentials exist, but only as a boolean or redacted summary.
250
+ - The audit log should record command path, redacted args, calling account, time, exit code, duration.
251
+ - `--quiet` must not disable auditing.
252
+
253
+ ## 11. Self-description commands (reference / context / doctor / changelog)
254
+
255
+ ### reference
256
+
257
+ Declares the tool's capabilities, commands, params, output schema, error codes, and permission levels, so an agent understands the tool first.
258
+
259
+ ```json
260
+ {
261
+ "ok": true,
262
+ "schema_version": "1.0",
263
+ "data": {
264
+ "tool": "tool-name",
265
+ "version": "1.0.0",
266
+ "release_readiness": {
267
+ "level": "beta",
268
+ "fcc_required": true,
269
+ "fcc_status": "verified",
270
+ "mock_upstream_required": true,
271
+ "mock_upstream_status": "verified",
272
+ "live_smoke_required_for_stable": true,
273
+ "live_smoke_status": "missing",
274
+ "reason": "Stable requires recorded live smoke/E2E evidence.",
275
+ "required_evidence": [
276
+ "functional_contract_coverage_100",
277
+ "mock_upstream_contract_tests",
278
+ "recorded_live_smoke_for_stable"
279
+ ]
280
+ },
281
+ "commands": [
282
+ {
283
+ "path": "resource delete",
284
+ "type": "write",
285
+ "description": "Delete a resource",
286
+ "params": [
287
+ {
288
+ "name": "id",
289
+ "type": "string",
290
+ "required": true,
291
+ "multiple": false
292
+ }
293
+ ],
294
+ "output_schema": {}
295
+ }
296
+ ],
297
+ "exit_codes": {}
298
+ },
299
+ "meta": {
300
+ "duration_ms": 0
301
+ }
302
+ }
303
+ ```
304
+
305
+ `release_readiness` is the machine-readable release gate. It must appear in
306
+ `reference` for every AI-native CLI:
307
+
308
+ - `level`: `stable`, `beta`, or `unpublishable`.
309
+ - `stable`: FCC is 100%, mock upstream/contract tests cover external behavior,
310
+ and at least one recorded live smoke/E2E run exists for the release candidate.
311
+ - `beta`: FCC is 100% and mock upstream/contract tests exist, but live
312
+ smoke/E2E evidence is missing or explicitly not available yet.
313
+ - `unpublishable`: any public behavior lacks command-level coverage, or mock
314
+ upstream/contract tests cover only happy paths while failure/auth/pagination/
315
+ empty/rate-limit behavior remains untested.
316
+ - `fcc_status`, `mock_upstream_status`, and `live_smoke_status` use
317
+ `verified`, `missing`, `not_applicable`, or `unknown`; `stable` may not use
318
+ `missing` or `unknown` for any required item.
319
+ - `required_evidence[]` names the evidence an agent or release script should
320
+ inspect before trusting the level.
321
+
322
+ ### context
323
+
324
+ Reports the current runtime, config, target, and credential status.
325
+
326
+ ```json
327
+ {
328
+ "ok": true,
329
+ "schema_version": "1.0",
330
+ "data": {
331
+ "env": "prod",
332
+ "account": "user@example.com",
333
+ "config": {},
334
+ "credentials": {
335
+ "configured": true
336
+ }
337
+ },
338
+ "meta": {
339
+ "duration_ms": 0
340
+ }
341
+ }
342
+ ```
343
+
344
+ ### doctor
345
+
346
+ Environment and risk check-up; each item gives an actionable fix.
347
+
348
+ ```json
349
+ {
350
+ "ok": true,
351
+ "schema_version": "1.0",
352
+ "data": {
353
+ "checks": [
354
+ {
355
+ "check": "auth",
356
+ "status": "pass",
357
+ "fix": null
358
+ },
359
+ {
360
+ "check": "network",
361
+ "status": "fail",
362
+ "fix": "set HTTP_PROXY or check VPN"
363
+ },
364
+ {
365
+ "check": "release_readiness",
366
+ "status": "warn",
367
+ "fix": "record live smoke/E2E evidence before declaring stable"
368
+ }
369
+ ]
370
+ },
371
+ "meta": {
372
+ "duration_ms": 0
373
+ }
374
+ }
375
+ ```
376
+
377
+ `doctor` must include `check: "release_readiness"` with the same release level
378
+ reported by `reference`. Use `pass` for `stable`, `warn` for intentional `beta`,
379
+ and `fail` for `unpublishable` or for a declared `stable` state with missing
380
+ evidence. The check should include an actionable `fix` when the status is not
381
+ `pass`.
382
+
383
+ ### changelog
384
+
385
+ Reports **what changed between versions** so an agent that just self-updated can refresh its knowledge instead of reusing stale patterns. This is the time-axis complement to `reference` (which describes current capabilities).
386
+
387
+ ```bash
388
+ tool changelog # all version changes
389
+ tool changelog --since 1.0.3 # only versions newer than 1.0.3
390
+ ```
391
+
392
+ ```json
393
+ {
394
+ "ok": true,
395
+ "schema_version": "1.0",
396
+ "data": {
397
+ "current_version": "1.1.0",
398
+ "since": "1.0.3",
399
+ "entries": [
400
+ {
401
+ "version": "1.1.0",
402
+ "date": "2026-06-07",
403
+ "changes": {
404
+ "added": [
405
+ "..."
406
+ ],
407
+ "changed": [
408
+ "..."
409
+ ],
410
+ "fixed": []
411
+ }
412
+ }
413
+ ]
414
+ },
415
+ "meta": {
416
+ "duration_ms": 0
417
+ }
418
+ }
419
+ ```
420
+
421
+ Conventions:
422
+
423
+ - **Single source of truth**: `changelog` output is derived from `CHANGELOG.md` (embedded into the binary at build time by `## [version]` section); no separate data maintained. Same source as release notes.
424
+ - `--since <version>` returns only entries strictly newer than that version, for an agent that "last saw version X" to pull the delta.
425
+ - Change categories follow Keep a Changelog: `added` / `changed` / `fixed` / `deprecated` / `removed` / `security`.
426
+ - After a successful self-update, the tool should hint the agent to run `changelog --since <old version>` (see §14).
427
+
428
+ ## 12. Command design conventions
429
+
430
+ 1. Use the shortest command that completes a clear task; reduce combinatorial complexity.
431
+ 2. Query commands support `--fields` and `--compact` by default to cut tokens.
432
+ 3. Write commands must support `--dry-run` and `--confirm`.
433
+ 4. Naming uses `<noun> <verb>` or `<verb> <noun>` style, consistent across the tool.
434
+ 5. Don't require agents to parse help text; `--help` is for humans, machine capability is exposed via `reference`.
435
+ 6. All times ISO 8601 UTC; all IDs strings.
436
+ 7. On failure, return a structured error rather than a half-finished success payload.
437
+ 8. Avoid ambiguous params; booleans are flags, enums are bounded choices.
438
+
439
+ ## 13. Functional contract coverage and release gate
440
+
441
+ Functional Contract Coverage (FCC) is the release blocker: every public behavior
442
+ an agent can rely on must have automated command-level test coverage. Numeric
443
+ line or branch coverage is useful engineering telemetry, but it is secondary and
444
+ must not be used as a substitute for missing functional contract tests.
445
+
446
+ A public functional contract is anything declared in:
447
+
448
+ - `README.md` / `README_zh.md`, `SKILL.md`, or Skill reference pages;
449
+ - `tool reference`, `--help`, `context`, `doctor`, `changelog`, or `update`
450
+ output;
451
+ - JSON envelope fields, command output schemas, global flags, error codes, exit
452
+ codes, retryability, and stdout/stderr behavior;
453
+ - documented config/env variables, credential handling, write safety, update
454
+ verification, Skill sync, and `_untrusted` security guarantees.
455
+
456
+ Required coverage for each public command or contract:
457
+
458
+ - success path;
459
+ - missing/invalid arguments;
460
+ - missing config, missing auth, or permission failure when applicable;
461
+ - upstream API failure, network failure, rate limit, or timeout when applicable;
462
+ - JSON envelope shape, output schema, exit code, and stderr/stdout boundary;
463
+ - non-interactive behavior: no prompts, no blocking, and write commands use
464
+ `--dry-run` -> `--confirm <token>`;
465
+ - regression test for every bug fix that changes observable behavior.
466
+
467
+ What `FCC = 100%` means:
468
+
469
+ - every command/flag/output/error behavior listed in the public contract is
470
+ mapped to at least one automated test, or explicitly marked non-applicable;
471
+ - command-level tests validate the CLI boundary, not just internal helpers;
472
+ - broad generated code, version constants, build metadata, or unreachable
473
+ platform guards may be excluded from numeric coverage, but not from FCC if
474
+ they are documented public behavior;
475
+ - a release cannot be tagged while known FCC gaps remain;
476
+ - `fcc_status: "verified"` must be machine-backed by an enumeration guard
477
+ test: enumerate every leaf command from live `reference` output and assert
478
+ each one is invoked by at least one command-level test. The guard skips
479
+ while the status is honestly declared `missing`, and fails if the claim is
480
+ flipped to `verified` without the coverage (the template ships this guard).
481
+
482
+ CI should run the unit and command-level suites for every PR. Numeric coverage
483
+ thresholds may ratchet upward over time per repository, but the release standard
484
+ is absolute: public functional contracts must be covered.
485
+
486
+ ### Release readiness levels
487
+
488
+ Release readiness is deliberately stricter than "tests pass":
489
+
490
+ - **Stable**: FCC is 100%; mock upstream/contract tests cover success,
491
+ validation, config/auth/permission failures, upstream/network/rate-limit/
492
+ timeout failures, empty results, pagination, output schema, exit codes, and
493
+ stdout/stderr boundaries; at least one live smoke/E2E run has been recorded
494
+ for the release candidate.
495
+ - **Beta**: FCC is 100% and mock upstream/contract tests meet the same
496
+ behavioral breadth, but recorded live smoke/E2E evidence is missing or the
497
+ project explicitly declares that live E2E is not available yet.
498
+ - **Unpublishable**: any public command/flag/output/error behavior lacks
499
+ command-level coverage, or mock upstream tests only cover happy paths.
500
+
501
+ `reference.release_readiness` and `doctor.checks[]` are the machine-readable
502
+ surface for this gate. A repository may choose not to publish `beta` artifacts,
503
+ but it must not describe itself as `stable` without the live evidence above.
504
+
505
+ ## 14. Versioning and compatibility
506
+
507
+ - `schema_version` is the output schema version, not the tool version.
508
+ - A breaking schema change bumps the major version, e.g. `1.x` -> `2.0`.
509
+ - Non-breaking added fields may keep the major version.
510
+ - Deprecated fields should keep a compatibility window and be marked deprecated in reference.
511
+ - Compatibility aliases may exist but should not be the recommended usage in new docs.
512
+ - Agents should rely on `reference`, not `--help` or README.
513
+
514
+ ### Version negotiation (tool version ↔ Skill expectation)
515
+
516
+ A Skill is a snapshot of the capabilities the day it was written; once the binary version drifts, things misalign: a Skill written for v1.1 against a v1.0 binary will silently call commands that don't exist.
517
+
518
+ - The tool must report its own version: `tool --version` and `context.data.version`.
519
+ - The Skill declares a minimum compatible version in frontmatter (see SKILL-SPEC `requires.min_version`).
520
+ - `doctor` should include a check "does the current version meet the declared minimum"; if not, give a `fix` (upgrade command), status `fail`.
521
+
522
+ ### Self-update and Skill-sync loop
523
+
524
+ For tools with `self-update`, after a successful update they **must close both
525
+ refresh loops**:
526
+
527
+ 1. the binary/package is current;
528
+ 2. the bundled Agent Skill directory is current, with the same end state as
529
+ running `npx skills add <repo> -y -g`.
530
+
531
+ The user-facing Skill install command stays `npx skills add ...`; the binary
532
+ must not expose a separate `install-skill` command. During update, however, the
533
+ tool owns the full lifecycle and must either sync the entire `skills/<tool>/`
534
+ directory or return an explicit `skill_sync_status` and `skill_sync_command`
535
+ that the agent can execute before using new behavior.
536
+
537
+ Required update contract:
538
+
539
+ - `update --check` is read-only. It reports current/target versions,
540
+ install method, whether a binary/package update is available, whether Skill
541
+ sync is needed or supported, and signature/checksum availability.
542
+ - `update --dry-run` returns a preview with every local change: binary/package
543
+ update, Skill directory sync, signature/checksum verification, and the
544
+ `confirm_token`.
545
+ - `update --confirm <token>` performs the update. It must verify release
546
+ integrity before replacing files or running a package manager update.
547
+ - If update succeeds, return `previous_version`, `current_version`,
548
+ `skill_sync_status`, and enough verification metadata for the agent to audit
549
+ what happened.
550
+ - If binary/package update succeeds but Skill sync fails, return a non-success
551
+ or partial-success status with `skill_sync_command`; the agent must not use
552
+ newly documented behavior until the Skill sync has completed.
553
+
554
+ Version notification contract:
555
+
556
+ - `update --check` actively checks the latest release and refreshes the local
557
+ update notice cache.
558
+ - `doctor` may actively check with a short timeout; network failure must not
559
+ make `doctor` fail by itself.
560
+ - `context` and `--help` only read the local cache and must not contact remote
561
+ registries or GitHub.
562
+ - When an update is available, JSON command data includes `notices[]` with
563
+ `type: "update_available"`, current/latest versions, install method,
564
+ `recommended_command`, release URL when known, checked-at timestamp, and
565
+ machine-readable next steps. Text/help output may append one concise hint.
566
+
567
+ Release verification baseline:
568
+
569
+ - Verify the archive/package against `checksums.txt`; checksum mismatch, missing
570
+ checksum file, or missing archive entry fails closed.
571
+ - Signed releases should sign `checksums.txt` with Sigstore/Cosign keyless
572
+ signing from the tagged GitHub Actions release workflow. Verifiers should
573
+ validate the bundle against the expected repository workflow identity and the
574
+ GitHub OIDC issuer.
575
+ - Update results carry `signature_status` (a short string describing where
576
+ release integrity verification happened: e.g. `verified`, `not_checked`,
577
+ `handled_by_npm_installer`, `manual_release_verification_required`) and
578
+ `signature_verified` (true only when local Sigstore verification actually
579
+ ran and succeeded). Never imply checksum verification is a signature.
580
+
581
+ - After `update --confirm <token>` succeeds, return `previous_version` and `current_version` in `data`.
582
+ - Also hint in the result: `run "changelog --since <previous_version>" to see what changed`.
583
+ - Agent convention: after self-update, before continuing, read `changelog --since <old version>` (see the SKILL-SPEC recipe).
584
+
585
+ ## 15. Optional patterns (enable as needed)
586
+
587
+ These three patterns are **not for everyone**: implement them if your tool needs them, ignore them otherwise — zero overhead. They let the spec scale with tool complexity — a simple tool stays light, a complex tool need not reinvent the wheel. Each is marked "when applicable."
588
+
589
+ ### 15.1 Credential lifecycle (when tokens expire)
590
+
591
+ **When applicable**: credentials are not static but expire / need refresh — OAuth access_token (WeChat Official Account ~2h), cookie / session (Xiaohongshu), temporary STS credentials, etc. Tools with static username/password skip this section.
592
+
593
+ - Beyond "is it configured," `context.data.credentials` should report **validity and expiry** (redacted):
594
+
595
+ ```json
596
+ {
597
+ "credentials": {
598
+ "configured": true,
599
+ "valid": true,
600
+ "expires_at": "2026-06-07T12:00:00Z",
601
+ "refreshable": true
602
+ }
603
+ }
604
+ ```
605
+
606
+ - When a token is expired and cannot auto-refresh, the operation returns `E_AUTH` (exit 4), with `details` indicating re-auth is needed.
607
+ - Tools that can auto-refresh should do so **transparently**, not bothering the agent; degrade to `E_AUTH` only if refresh fails.
608
+ - `doctor` adds a `check: "credentials"` item; for near-expiry give `warn` + a renew `fix`.
609
+ - Refresh tokens and secrets are always redacted — never in stdout / stderr / details.
610
+
611
+ ### 15.2 Async job lifecycle (long jobs: submit -> poll -> fetch result)
612
+
613
+ **When applicable**: the operation can't return a result synchronously — async SQL execution / approval (Archery), bulk send, scrape/crawl jobs, large exports. Commands that return results synchronously skip this section.
614
+
615
+ - The submit command returns a `job_id` and status immediately, without blocking:
616
+
617
+ ```json
618
+ {
619
+ "ok": true,
620
+ "schema_version": "1.0",
621
+ "data": {
622
+ "job_id": "job_abc123",
623
+ "status": "pending",
624
+ "poll": "tool job status --id job_abc123",
625
+ "result": "tool job result --id job_abc123"
626
+ },
627
+ "meta": { "duration_ms": 12 }
628
+ }
629
+ ```
630
+
631
+ - Status queries return a stable enum: `pending` / `running` / `succeeded` / `failed` / `cancelled`, with progress (e.g. `progress`, `eta_seconds`).
632
+ - Result and status are fetched separately: after `succeeded`, use the `result` command to pull data (large results via NDJSON / `--format raw`).
633
+ - A `failed` result uses the standard error envelope; `retryable` indicates whether the whole job can be retried.
634
+ - Submission of a write-type long job still goes through `dry-run → confirm`; the `job_id` is created only after confirm.
635
+
636
+ ### 15.3 Human-in-the-loop checkpoints (when a human must scan / solve captcha / approve)
637
+
638
+ **When applicable**: a step mid-flow must be completed by a human — QR login / captcha (Xiaohongshu), approver sign-off (Archery), secondary confirmation. Fully automated tools skip this section.
639
+
640
+ - When stuck at a human step, **don't block, don't guess** — return a dedicated signal so the agent hands off to the user:
641
+
642
+ ```json
643
+ {
644
+ "ok": false,
645
+ "schema_version": "1.0",
646
+ "error": {
647
+ "code": "E_HUMAN_REQUIRED",
648
+ "message": "Scan the QR code to continue",
649
+ "details": { "action": "scan_qr", "resume": "tool login resume --id sess_1", "qr_path": "/tmp/qr.png" },
650
+ "retryable": false
651
+ },
652
+ "meta": { "duration_ms": 30 }
653
+ }
654
+ ```
655
+
656
+ - `E_HUMAN_REQUIRED` uses exit code `9` (added beyond the existing 0–8; not reusing `4`, to distinguish "bad credentials" from "waiting on a human action").
657
+ - `details.action` is a stable enum describing what the human must do; `details.resume` gives the command to continue after the human is done.
658
+ - Agent convention: on `E_HUMAN_REQUIRED` → relay `message` and the required action to the user → wait for them → run `resume`; do not auto-retry.
659
+
660
+ ## 16. Design checklist
661
+
662
+ > Items marked `(optional)` only apply when the corresponding optional pattern is enabled.
663
+
664
+ - [ ] Default `--format json`
665
+ - [ ] stdout contains only valid JSON / NDJSON, no pollution
666
+ - [ ] Logs and progress all go to stderr
667
+ - [ ] Success/failure share one envelope, with `ok` and `schema_version`
668
+ - [ ] `error` has semantic `code`, `details`, `retryable`
669
+ - [ ] Exit codes tiered and consistent with `retryable`
670
+ - [ ] Write commands have the dry-run / confirm-token loop
671
+ - [ ] Confirm token binds operation args, account, permission context, resource version
672
+ - [ ] Provides `reference` / `context` / `doctor`
673
+ - [ ] Provides `changelog [--since]`, same source as CHANGELOG/release-notes
674
+ - [ ] Tool reports its own version (`--version` and `context.version`)
675
+ - [ ] `reference` reports `release_readiness`, and `doctor` checks it
676
+ - [ ] (with self-update) `update --check` / `--dry-run` / `--confirm` are implemented
677
+ - [ ] (with self-update) release integrity is verified, and signature status is explicit
678
+ - [ ] (with self-update) whole Skill directory sync is part of the update result
679
+ - [ ] (with self-update) post-update returns previous/current version and hints to read changelog
680
+ - [ ] Query commands support `fields` / `compact`
681
+ - [ ] List commands support pagination or explicitly state none is needed
682
+ - [ ] Functional Contract Coverage is 100% for public README / Skill / reference / help / context / doctor / changelog / update behavior
683
+ - [ ] Stable releases have recorded live smoke/E2E evidence; otherwise the tool declares `beta`
684
+ - [ ] All times ISO 8601 UTC
685
+ - [ ] All IDs strings
686
+ - [ ] Secrets redacted end to end
687
+ - [ ] Schema changes have a versioning/compat policy
688
+ - [ ] stdout/stderr are UTF-8 without BOM
689
+ - [ ] (optional · expiring tokens) `context`/`doctor` report credential validity and expiry; refresh failure degrades to `E_AUTH`
690
+ - [ ] (optional · long jobs) submit returns `job_id` + status enum, status/result separated
691
+ - [ ] (optional · human needed) stuck human steps return `E_HUMAN_REQUIRED` (exit 9) + `resume`, no auto-retry