agent-first-data 0.28.1

A naming convention that lets AI agents understand your data without being told what it means, plus a CLI and library for reading and safely editing structured JSON, TOML, YAML, dotenv, and INI documents.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# afdata CLI reference

<!-- Generated by `afdata --docs`. Do not edit by hand. -->

A naming convention that lets AI agents understand your data without being told what it means, plus a CLI and library for reading and safely editing structured JSON, TOML, YAML, dotenv, and INI documents.

`afdata` is compiled from a closed `cli-spec-v1` registry: one source for argv parsing, typed invocation values, which parameter combinations are legal, output contracts, and help. An invocation runs only when it matches exactly one registered combination.

## Global arguments

AFDATA registers these; no command declares them, and the syntax in [Commands](#commands) leaves them out.

| Argument | Where | What it does |
|---|---|---|
| `--help` | every command | Every legal shape of that command, complete, plus its subcommands. JSON by default; `--output plain` for a terminal. |
| `--version` | afdata only | Name, version, and build identity as one protocol result. |
| `--docs` | afdata only | This document, rendered from the registry. |
| `--output <FORMAT>` | per output contract | Render as json, yaml, plain (default `json`). |
| `--output-to <DESTINATION>` | per output contract | Route results and diagnostics to split, stdout, stderr (default `split`). |
| `--stdout-file <PATH>`, `--stderr-file <PATH>` | per output contract | Append that stream to a file instead. |

Success output is protocol events, on those terms, unless a command's own **Output** line says otherwise.

A **shape** is one legal set of arguments that may appear together, under a stable id. Where a command has more than one, each id is a heading below. `--help` returns them all at once, so discovering a command costs one call; there is no recursive mode across commands, and this document is that view.

## Commands

- [`afdata add`](#afdata-add) — Add an element to a keyed list
- [`afdata emit error`](#afdata-emit-error) — Emit a terminal error event
- [`afdata emit log`](#afdata-emit-log) — Emit a diagnostic log event
- [`afdata emit result`](#afdata-emit-result) — Emit a terminal result event
- [`afdata get`](#afdata-get) — Read a document or one value as an AFDATA result
- [`afdata keys`](#afdata-keys) — List child names as raw lines, without their parent path
- [`afdata lint`](#afdata-lint) — Lint structured data for deterministic AFDATA issues
- [`afdata paths`](#afdata-paths) — List each child's full dot-path as raw lines
- [`afdata remove`](#afdata-remove) — Remove a keyed-list element by slug
- [`afdata render`](#afdata-render) — Render JSON or JSONL through AFDATA redaction and formatting
- [`afdata set`](#afdata-set) — Set a value at a dot-path, creating missing object parents
- [`afdata shell bash`](#afdata-shell-bash) — Print the sourceable Bash authoring kit
- [`afdata skill install`](#afdata-skill-install) — Install the bundled Agent Skill
- [`afdata skill status`](#afdata-skill-status) — Report whether the bundled Agent Skill is installed and current
- [`afdata skill uninstall`](#afdata-skill-uninstall) — Remove an afdata-managed Agent Skill
- [`afdata skill validate`](#afdata-skill-validate) — Validate an Agent Skill
- [`afdata unset`](#afdata-unset) — Remove one document entry
- [`afdata validate`](#afdata-validate) — Validate protocol-v1 events or a finite event stream
- [`afdata value`](#afdata-value) — Read one scalar as raw stdout bytes
- [`afdata values`](#afdata-values) — Read many scalars as raw lines, from one parse of the document

### `afdata add`

Add an element to a keyed list

```
afdata add <FILE> <KEY> <SLUG> [<FIELD=VALUE>...] --slug-field <FIELD> [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>]
```

| Argument | Meaning |
|---|---|
| `FILE` | Document file to mutate |
| `KEY` | Dot-path to the keyed list |
| `SLUG` | New element slug |
| `FIELD=VALUE` | Additional string fields |
| `--slug-field` | Field that identifies each list element |
| `--input-format` | Document format override |

### `afdata emit error`

Emit a terminal error event

```
afdata emit error <CODE> <MESSAGE> [--hint <HINT>] [--retryable]
```

| Argument | Meaning |
|---|---|
| `CODE` | Stable error code |
| `MESSAGE` | Error message |
| `--hint` | Suggested corrective action |
| `--retryable` | Mark the failure safe to retry |

### `afdata emit log`

Emit a diagnostic log event

```
afdata emit log <debug|info|warn|error> <MESSAGE>
```

| Argument | Meaning |
|---|---|
| `LEVEL` | debug, info, warn, or error |
| `MESSAGE` | Human-readable message |

### `afdata emit result`

Emit a terminal result event

```
afdata emit result <MESSAGE>
```

| Argument | Meaning |
|---|---|
| `MESSAGE` | Result message |

### `afdata get`

Read a document or one value as an AFDATA result

```
afdata get <FILE> [<KEY>] [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>] [--secret-name <FIELD>...]
```

| Argument | Meaning |
|---|---|
| `FILE` | Document file, or - for stdin |
| `KEY` | Optional dot-path |
| `--input-format` | Document format override |
| `--secret-name` | Extra exact field name to redact |

### `afdata keys`

List child names as raw lines, without their parent path

```
afdata keys <FILE> [<KEY>] [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>] [--missing-ok] [--null]
```

Output: raw bytes on success; rejects `--output` and `--output-to`; redirect with `--stdout-file` or `--stderr-file`. Failures are still strict JSON on stderr.

| Argument | Meaning |
|---|---|
| `FILE` | Document file, or - for stdin |
| `KEY` | Optional container dot-path |
| `--input-format` | Document format override |
| `--missing-ok` | Succeed with no output when KEY is absent |
| `--null` | Use NUL separators |

### `afdata lint`

Lint structured data for deterministic AFDATA issues

```
afdata lint <INPUT> [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>] [--min-severity <warning|error>]
```

| Argument | Meaning |
|---|---|
| `INPUT` | Input file, or - for stdin |
| `--input-format` | Document format override |
| `--min-severity` | Lowest severity to report; `error` drops the heuristic checks |

### `afdata paths`

List each child's full dot-path as raw lines

```
afdata paths <FILE> [<KEY>] [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>] [--missing-ok] [--null]
```

Output: raw bytes on success; rejects `--output` and `--output-to`; redirect with `--stdout-file` or `--stderr-file`. Failures are still strict JSON on stderr.

| Argument | Meaning |
|---|---|
| `FILE` | Document file, or - for stdin |
| `KEY` | Optional container dot-path |
| `--input-format` | Document format override |
| `--missing-ok` | Succeed with no output when KEY is absent |
| `--null` | Use NUL separators |

### `afdata remove`

Remove a keyed-list element by slug

```
afdata remove <FILE> <KEY> <SLUG> --slug-field <FIELD> [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>]
```

| Argument | Meaning |
|---|---|
| `FILE` | Document file to mutate |
| `KEY` | Dot-path to the keyed list |
| `SLUG` | Element slug |
| `--slug-field` | Field that identifies each list element |
| `--input-format` | Document format override |

### `afdata render`

Render JSON or JSONL through AFDATA redaction and formatting

```
afdata render <INPUT> [--secret-name <FIELD>...]
```

| Argument | Meaning |
|---|---|
| `INPUT` | Input file, or - for stdin |
| `--secret-name` | Extra exact field name to redact |

### `afdata set`

Set a value at a dot-path, creating missing object parents

#### `set-value` — Set one typed scalar or JSON value

```
afdata set <FILE> <KEY> <VALUE> [--value-type <string|number|bool|json>] [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>]
```

#### `set-null` — Set the key to null; takes no VALUE

```
afdata set <FILE> <KEY> --value-type null [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>]
```

#### `set-secret` — Set the key from a secret source, never from argv

```
afdata set <FILE> <KEY> --secret-from <SOURCE> [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>]
```

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `FILE` | Document file to mutate |
| `KEY` | Dot-path to set |
| `VALUE` | Value to write |
| `--value-type` | Exact VALUE type |
| `--secret-from` | Read a secret string from stdin, prompt, fd:N, or env:VAR |
| `--input-format` | Document format override |

### `afdata shell bash`

Print the sourceable Bash authoring kit

```
afdata shell bash
```

Output: raw bytes on success; rejects `--output` and `--output-to`; redirect with `--stdout-file` or `--stderr-file`. Failures are still strict JSON on stderr.

### `afdata skill install`

Install the bundled Agent Skill

#### `skill-install-all` — Install into every agent that supports the scope

```
afdata skill install [--agent all] [--scope <personal|workspace>] [--force]
```

#### `skill-install-agent` — Install into one named agent; only this shape accepts --skills-dir

```
afdata skill install --agent <codex|claude-code|opencode|hermes> [--scope <personal|workspace>] [--skills-dir <PATH>] [--force]
```

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--agent` | Target agent |
| `--scope` | Skill scope |
| `--skills-dir` | Explicit directory; only valid with one concrete agent |
| `--force` | Overwrite or remove an unmanaged skill |

### `afdata skill status`

Report whether the bundled Agent Skill is installed and current

#### `skill-status-all` — Report on every agent that supports the scope

```
afdata skill status [--agent all] [--scope <personal|workspace>]
```

#### `skill-status-agent` — Report on one named agent; only this shape accepts --skills-dir

```
afdata skill status --agent <codex|claude-code|opencode|hermes> [--scope <personal|workspace>] [--skills-dir <PATH>]
```

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--agent` | Target agent |
| `--scope` | Skill scope |
| `--skills-dir` | Explicit directory; only valid with one concrete agent |

### `afdata skill uninstall`

Remove an afdata-managed Agent Skill

#### `skill-uninstall-all` — Remove from every agent that supports the scope

```
afdata skill uninstall [--agent all] [--scope <personal|workspace>] [--force]
```

#### `skill-uninstall-agent` — Remove from one named agent; only this shape accepts --skills-dir

```
afdata skill uninstall --agent <codex|claude-code|opencode|hermes> [--scope <personal|workspace>] [--skills-dir <PATH>] [--force]
```

Arguments across every shape above:

| Argument | Meaning |
|---|---|
| `--agent` | Target agent |
| `--scope` | Skill scope |
| `--skills-dir` | Explicit directory; only valid with one concrete agent |
| `--force` | Overwrite or remove an unmanaged skill |

### `afdata skill validate`

Validate an Agent Skill

```
afdata skill validate <INPUT>
```

| Argument | Meaning |
|---|---|
| `INPUT` | SKILL.md file, directory, or - for stdin |

### `afdata unset`

Remove one document entry

```
afdata unset <FILE> <KEY> [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>]
```

| Argument | Meaning |
|---|---|
| `FILE` | Document file to mutate |
| `KEY` | Dot-path to remove |
| `--input-format` | Document format override |

### `afdata validate`

Validate protocol-v1 events or a finite event stream

```
afdata validate <INPUT> [--strict] [--per-event]
```

| Argument | Meaning |
|---|---|
| `INPUT` | Input file, or - for stdin |
| `--strict` | Enforce the strict protocol profile |
| `--per-event` | Validate values independently without stream lifecycle rules |

### `afdata value`

Read one scalar as raw stdout bytes

```
afdata value <FILE> <KEY> [--reveal-secret] [--default <VALUE>] [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>] [--secret-name <FIELD>...]
```

Output: raw bytes on success; rejects `--output` and `--output-to`; redirect with `--stdout-file` or `--stderr-file`. Failures are still strict JSON on stderr.

| Argument | Meaning |
|---|---|
| `FILE` | Document file, or - for stdin |
| `KEY` | Dot-path to one scalar |
| `--reveal-secret` | Allow a secret-named leaf |
| `--default` | Fallback for missing or null |
| `--input-format` | Document format override |
| `--secret-name` | Extra exact field name to redact |

### `afdata values`

Read many scalars as raw lines, from one parse of the document

```
afdata values <FILE> <KEY>... [--reveal-secret] [--default <VALUE>] [--input-format <json|toml|yaml|yml|dotenv|env|ini|toml-frontmatter|yaml-frontmatter>] [--secret-name <FIELD>...]
```

Output: raw bytes on success; rejects `--output` and `--output-to`; redirect with `--stdout-file` or `--stderr-file`. Failures are still strict JSON on stderr.

| Argument | Meaning |
|---|---|
| `FILE` | Document file, or - for stdin |
| `KEY` | Dot-path to one scalar; repeat for each value wanted |
| `--reveal-secret` | Allow a secret-named leaf |
| `--default` | Fallback for missing or null |
| `--input-format` | Document format override |
| `--secret-name` | Extra exact field name to redact |

## Exit codes

| Code | Meaning |
|---|---|
| 0 | The command ran and succeeded. |
| 1 | The command ran and failed. The event carries a domain `error.code`. |
| 2 | The invocation was rejected before anything ran. `error.code` is one of the `cli_*` codes below. |

The split is the useful one for a caller: exit 2 means the call was never made, so retrying it unchanged cannot help, while exit 1 means it was.

## CLI errors

Every structural failure emits one strict JSON `kind:"error"` event on stderr, leaves stdout empty, and exits 2. The `code` names the failure — `cli_unknown_argument` for an unknown spelling, `cli_unregistered_combination` for registered arguments in a mixture that is not, and one each for `cli_unknown_command`, `cli_missing_argument_value`, `cli_invalid_argument_value`, `cli_duplicate_argument`, `cli_unexpected_positional`, and `cli_invalid_utf8`. `message` names the offending argument and `hint` gives the command to run next; neither ever quotes a raw value, including secrets. These are decided before any config, secret source, filesystem, network, or domain I/O.

Domain failures (exit 1) carry their own stable `error.code` instead, drawn from whatever this tool defines rather than from the `cli_*` set. No error message quotes a raw value it was given — an error event is routinely logged, and the input may hold secrets.