@fatecannotbealtered-/jira-cli 1.0.6 → 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.
- package/.agent/AGENT.md +59 -0
- package/.agent/AGENT_zh.md +59 -0
- package/.agent/CLI-SPEC.md +691 -0
- package/.agent/CLI-SPEC_zh.md +641 -0
- package/.agent/SEC-SPEC.md +142 -0
- package/.agent/SEC-SPEC_zh.md +126 -0
- package/.agent/SKILL-SPEC.md +199 -0
- package/.agent/SKILL-SPEC_zh.md +195 -0
- package/AGENTS.md +17 -0
- package/CHANGELOG.md +66 -3
- package/CODE_OF_CONDUCT.md +35 -0
- package/CODE_OF_CONDUCT_zh.md +35 -0
- package/CONTRIBUTING.md +24 -4
- package/LICENSE +1 -1
- package/NOTICE.md +10 -0
- package/README.md +95 -433
- package/README_zh.md +130 -0
- package/SECURITY.md +39 -0
- package/docs/COMPATIBILITY.md +28 -0
- package/docs/E2E.md +42 -0
- package/docs/LIVE-SMOKE-EVIDENCE.md +77 -0
- package/docs/OPEN_SOURCE_CHECKLIST.md +37 -0
- package/package.json +24 -18
- package/scripts/run.js +32 -9
- package/skills/jira-cli/SKILL.md +120 -308
- package/skills/jira-cli/test-prompts.json +27 -0
- package/scripts/install.js +0 -136
|
@@ -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
|