agent-first-data 0.21.0 → 0.23.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
@@ -19,13 +19,6 @@ console.log(render(event.toJSON(), "plain"));
19
19
 
20
20
  Useful names use TypeScript casing: `render`, `outputOptionsForPolicy`, `redactedValue`, `redactUrlSecrets`, `normalizeUtcOffset`, `isValidRfc3339Date`, `isValidRfc3339Time`, `isValidRfc3339`, `isValidBcp47`, `decodeProtocolEvent`, `cliParseOutput`, `cliParseLogFilters`, `buildCliError`, `buildCliVersion`, and `cliHandleVersionOrContinue`.
21
21
 
22
- Skill admin and stream redirection are not re-exported from the package root; import them from their own subpaths:
23
-
24
- ```typescript
25
- import { runSkillAdmin } from "agent-first-data/skill";
26
- import { installStreamRedirectFromRawArgs } from "agent-first-data/stream-redirect";
27
- ```
28
-
29
22
  ## Behavior Notes
30
23
 
31
24
  - Default redaction replaces every `_secret` or configured secret-name subtree with `***`, including objects and arrays.
@@ -34,11 +27,9 @@ import { installStreamRedirectFromRawArgs } from "agent-first-data/stream-redire
34
27
  - Logging records use `kind:"log"` with a nested `log` payload and a separate `level` field, so error-level logs are not terminal protocol errors.
35
28
  - `buildCliError(message, hint?)` returns a strict-ready CLI error with `error.retryable:false` and `trace:{}`.
36
29
  - Use `cliHandleVersionOrContinue()` before argument parsing so `--version`/`-V` always answers with a structured protocol-v1 `kind:"result"` version event — JSON by default, or `--output yaml|plain`/`--json` for another format; there is no conventional bare-text form. Pass your own value-taking global flag names so their value is not mistaken for the subcommand boundary.
37
- - Use `installStreamRedirectFromRawArgs()` (from `agent-first-data/stream-redirect`) before version/help handling if a CLI exposes `--stdout-file` or `--stderr-file`; stderr is redirected as native diagnostics, not JSON. Node fd-level redirection is process-lifetime because the standard library does not expose `dup2` restoration.
38
30
 
39
31
  ## Reference
40
32
 
41
- - Full convention and API groups: [docs/overview.md](https://github.com/agentfirstkit/agent-first-data/blob/main/docs/overview.md)
42
33
  - Formal cross-language contract: [spec/agent-first-data.md](https://github.com/agentfirstkit/agent-first-data/blob/main/spec/agent-first-data.md)
43
34
  - Conformance fixtures: [spec/fixtures](https://github.com/agentfirstkit/agent-first-data/tree/main/spec/fixtures)
44
35
  - Agent skill: [skills/agent-first-data/SKILL.md](https://github.com/agentfirstkit/agent-first-data/blob/main/skills/agent-first-data/SKILL.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-first-data",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "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.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -14,14 +14,6 @@
14
14
  ".": {
15
15
  "import": "./dist/index.js",
16
16
  "types": "./dist/index.d.ts"
17
- },
18
- "./skill": {
19
- "import": "./dist/skill.js",
20
- "types": "./dist/skill.d.ts"
21
- },
22
- "./stream-redirect": {
23
- "import": "./dist/stream_redirect.js",
24
- "types": "./dist/stream_redirect.d.ts"
25
17
  }
26
18
  },
27
19
  "files": [
@@ -1,281 +0,0 @@
1
- ---
2
- name: agent-first-data
3
- description: Apply and review the formal Agent-First Data specification using the Rust/Go/Python/TypeScript libraries or afdata CLI for naming, redaction, formatting, protocol envelopes, logging, linting, validation, and reading or safely editing structured JSON/TOML/YAML/dotenv/INI documents (and the +++/--- frontmatter block of a Markdown page) by dot-path. Use proactively when writing or reviewing structured data, configs, logs, transport payloads, database/wire fields, CLI output, compatibility-sensitive public and persistent field names, or when reading or editing a config/document/Markdown-frontmatter file from the shell.
4
- ---
5
-
6
- <!-- Canonical source: skills/agent-first-data/SKILL.md.
7
- Mirrored byte-for-byte into go/python/typescript assets/ by scripts/sync_offline_assets.py.
8
- Edit only here; run that script (checked by scripts/test.sh) to propagate. -->
9
-
10
- # Agent-First Data
11
-
12
- Use AFDATA when naming fields or reviewing structured output. The contract is naming-based: suffixes communicate units, formatting, and redaction semantics without relying on free-text inference.
13
-
14
- ## Specification workflow
15
-
16
- Treat the formal specification as normative, not the skill summary or an
17
- example payload. In a repository checkout, read these spore-root-relative
18
- sources as needed:
19
-
20
- - `spec/agent-first-data.md` — complete cross-language naming, formatting,
21
- redaction, protocol, logging, and CLI contract.
22
- - `spec/registry.json` — exact suffix metadata.
23
- - `spec/protocol-v1.schema.json` — protocol event schema.
24
- - `spec/fixtures/` — cross-language conformance cases.
25
-
26
- When only the installed skill is available, use the bundled equivalents:
27
-
28
- - `references/rules.md` — detailed suffix rules, output formatting, protocol templates, logging, CLI flags, and review checklist.
29
- - `references/registry.json` — machine-readable suffix registry; use this as the exact source for suffix metadata.
30
- - `references/protocol-v1.schema.json` — protocol event schema for `kind:"result"`, `kind:"error"`, `kind:"progress"`, and `kind:"log"` envelopes.
31
-
32
- If an example or README conflicts with the formal spec, follow the spec and
33
- report the discrepancy. Do not invent suffix meanings or reduce the protocol
34
- schema.
35
-
36
- ## Library workflow
37
-
38
- Use the library at serialization boundaries so redaction and formatting are
39
- not reimplemented ad hoc. Rust applications can build a typed protocol event
40
- and render it in the required output format:
41
-
42
- ```bash
43
- cargo add agent-first-data --no-default-features
44
- pip install agent-first-data
45
- npm install agent-first-data
46
- go get github.com/agentfirstkit/agent-first-data/go
47
- ```
48
-
49
- ```rust
50
- use agent_first_data::{json_result, render, OutputFormat, OutputOptions};
51
- use serde_json::json;
52
-
53
- let event = json_result(json!({
54
- "latency_ms": 1280,
55
- "api_key_secret": "sk-live-example",
56
- })).build();
57
- let rendered = render(event.as_value(), OutputFormat::Json, &OutputOptions::default());
58
- assert!(rendered.contains("\"api_key_secret\":\"***\""));
59
- ```
60
-
61
- For a finite CLI execution implemented in Rust, create one `CliEmitter`, select
62
- `OutputFormat` through `cli_parse_output`, enable strict protocol, and emit one
63
- terminal result or error. Handle version before clap with
64
- `cli_handle_version_or_continue(raw_args, cmd, name, display_name, version, build)`,
65
- which always answers `--version`/`-V` with a structured version event.
66
- For non-CLI HTTP/MCP/SSE serialization, call `redacted_value()` or
67
- `redact_url_secrets()` explicitly at the boundary.
68
-
69
- The same library contract is available for Go, Python, and TypeScript. Use the
70
- runtime's native names while preserving the same builders, output formats,
71
- redaction behavior, registry, schema, and conformance fixtures; consult its
72
- root-level `go/README.md`, `python/README.md`, or `typescript/README.md` when
73
- working in that runtime.
74
-
75
- ## Naming and redaction decisions
76
-
77
- - Add unit suffixes to ambiguous numeric fields: `_ms`, `_s`, `_bytes`, `_percent`, `_sats`, `_msats`, currency suffixes, and timestamp suffixes.
78
- - Use `_secret` for values/subtrees that must redact to `***` in every output format.
79
- - Use `_url` only for whole URL values whose userinfo password or suffix-named secret query params should be scrubbed.
80
- - Do not scan arbitrary free text for secrets. Rename fields or configure explicit secret names at the serialization boundary.
81
- - Before changing public API, wire, database, or persistent field names, report the compatibility impact and get approval.
82
-
83
- ## Evaluation rules
84
-
85
- - Trigger this skill for field naming, structured output, configs, logs, CLI output, protocol events, MCP/HTTP/SSE payloads, database columns, wire fields, or persisted JSON. Do not wait for the user to say "AFDATA" when the work changes those surfaces.
86
- - In a repository checkout, treat `spec/agent-first-data.md`,
87
- `spec/registry.json`, and `spec/protocol-v1.schema.json` as authoritative; in
88
- an installed skill, use their bundled `references/` equivalents. Do not
89
- replace them with invented suffix meanings, a reduced schema, or free-text
90
- interpretation.
91
- - For secrets, fix the field name or serializer configuration. Use `_secret` or configured exact secret names; do not rely on scanning arbitrary strings or object debug output.
92
- - Run `afdata lint` on JSON/JSONL examples, JSON Schema, MCP schemas, or serialized samples when the CLI is available. Run `afdata validate` on finite protocol events/streams. If a check cannot run, report that explicitly.
93
- - Before modifying an external project's public API, wire format, database schema, or persisted field names, stop and report the compatibility impact; request approval before applying the change.
94
-
95
- ## Redaction behavior contract
96
-
97
- Fields named `_secret` or `_url` and values passing through AFDATA output rendering (`render`, in any format) are automatically redacted: secrets become `***`, URL userinfo passwords and suffix-named query parameters are scrubbed. When serializing outside output formatters (HTTP, MCP, SSE), call `redacted_value()` or `redact_url_secrets()` at the serialization boundary. PII redaction, domain-specific privacy policies (header allowlists, API scope sensitivity), and per-field secret naming are each spore's responsibility; the library provides field-name-based mechanics only.
98
-
99
- ## Logging behavior contract
100
-
101
- One-time CLI output uses `json_log()` or `CliEmitter` for a single event; serialization via `render()` applies output formatting. Construct the emitter in finite mode for a one-shot command (`result`→stdout, `error`/`progress`/`log`→stderr) or stream mode for an interleaved event stream (all events on one destination) — see the Output stream contract. Long-running services or processes depending on structured logging (tonic, sqlx, hyper, etc. via tracing) initialize with `afdata_tracing::try_init()` (Rust only) to wire process-wide logging; other languages emit log events explicitly via builders or integrate their own structured logging.
102
-
103
- ## CLI workflow
104
-
105
- Install `afdata` when a shell workflow needs validation, formatting, or skill
106
- administration without embedding a library:
107
-
108
- ```bash
109
- cargo install agent-first-data
110
- ```
111
-
112
- Use it for deterministic checks:
113
-
114
- ```bash
115
- afdata lint payload.json
116
- afdata validate events.jsonl
117
- afdata render payload.json --output yaml
118
- afdata skill validate skills/example-skill
119
- ```
120
-
121
- - Every command's first positional is its input; `-` reads stdin explicitly.
122
- There is no implicit stdin fallback, and omitting the input is always a
123
- usage error that names the fix — never a hang.
124
- - Run `afdata lint` for ordinary JSON/JSONL, JSON Schema, MCP input/output
125
- schemas, or a structured document (`--input-format`/extension detection
126
- picks TOML/YAML/dotenv/INI; JSON/JSONL stays the default dual-mode input).
127
- - Run `afdata validate` for AFDATA protocol events or finite event streams.
128
- - Run `afdata render` to apply AFDATA redaction/formatting to arbitrary JSON
129
- or JSONL. `--output` accepts `json`, `yaml`, or `plain`; JSON and YAML keep
130
- original keys/values (structure-preserving), Plain is the lossy human
131
- renderer.
132
- - Treat findings as contract issues unless the owning tool intentionally
133
- documents a non-AFDATA field.
134
-
135
- ## Output stream contract
136
-
137
- AFDATA CLIs route protocol events by consumption mode, not by event shape.
138
-
139
- - A **finite one-shot command** (the default) puts `kind:"result"` on `stdout`
140
- and `kind:"error"`/`progress`/`log` on `stderr`, so `x=$(tool …)` never
141
- captures a failure as data, `tool … >/dev/null` never swallows a diagnostic,
142
- and `tool … | next` never pipes an error envelope in as input. The exit
143
- code — not the stream — is set by the terminal kind; routing follows `kind`,
144
- not the exit code.
145
- - An **event stream** (interleaved events consumed in order) keeps every event,
146
- including `error`, on one stream so ordering survives.
147
- - `afdata` and any CLI built on the library expose `--output-to
148
- <split|stdout|stderr>` (default `split`). `stdout`/`stderr` collapse the whole
149
- stream — errors included — onto one destination, for a consumer that would
150
- rather read one stream and branch on `kind`. `--output` picks the format,
151
- `--output-to` picks the destination. Send an event stream to a file by
152
- collapsing it (`--output-to stdout`) and redirecting (`--stdout-file PATH`).
153
- - The raw-scalar readers (`value`/`paths`/`keys`) are intrinsically split (raw
154
- data on `stdout`, error envelope on `stderr`) and reject a non-default
155
- `--output-to`.
156
- - When building a CLI on the library, choose the mode by how the output is
157
- consumed — do not reflexively pick finite. A plain one-shot shell command uses
158
- **finite** mode (errors → stderr, so shell capture and pipelines stay safe). A
159
- tool whose output is itself an event stream (interleaved `progress`/`log` then
160
- a terminal `result`/`error` — e.g. streaming query rows), or that is
161
- agent-facing and wants the caller to read a single structured channel and
162
- branch on `kind`, uses **stream/unified** mode (every event, errors included,
163
- on `stdout`). A stream's terminal error MUST stay on the stream, so such a tool
164
- keeps even its usage errors on `stdout` for one consistent channel. Never write
165
- to `stderr` ad hoc — route every diagnostic through the emitter so redaction
166
- and framing still apply.
167
- - Emit a terminal event with the emitter's `finish` / `finish_result` helpers,
168
- which map the write outcome to a broken-pipe-safe process exit code (success →
169
- the given code, a hung-up reader → 0, any other write failure → a nonzero
170
- output-failure code) instead of hand-rolling that dance — they work in either
171
- mode (the emitter's mode decides the stream; `finish` only maps the outcome).
172
- Construct an error with the error builder (`json_error(code, message)` with
173
- `hint`/`retryable`/extra fields as needed) — that builder *is* the error type —
174
- and pass the built event to `finish`; there is no separate error-emitting
175
- convenience.
176
-
177
- ## Document workflow
178
-
179
- Use `get`/`value`/`paths`/`keys` to read a JSON, TOML, YAML, dotenv, or INI
180
- document and `set`/`add`/`remove`/`unset` to edit one in place, instead of
181
- `sed`, regular expressions, or a generic reserializer — those can reorder
182
- keys, drop comments, or change quoting/anchors in the rest of the file. Every
183
- document command's first positional is `FILE` (or `-` for stdin on a read
184
- command); mutation commands never read stdin and reject `-` as a usage error.
185
- To edit only the metadata block of a Markdown page, pass `--input-format
186
- toml-frontmatter` (a `+++` block) or `yaml-frontmatter` (a `---` block): the
187
- same read/mutate commands then address dot-paths inside the frontmatter and
188
- leave the Markdown body byte-for-byte untouched. Frontmatter is never
189
- auto-detected — the format must be named explicitly, since extension detection
190
- only ever resolves to a whole-file format — so reach for it deliberately
191
- instead of `sed`-ing a page's `+++`/`---` header.
192
-
193
- - `get FILE` returns the whole document as one AFDATA record
194
- (`code:"document"`); `get FILE KEY` narrows it to one dot-path value in the
195
- same shape. Pass every known sensitive legacy field name with
196
- `--secret-name FIELD` (an exact field name, not a dot-path). A secret-named
197
- leaf (`_secret`/`_SECRET`, or an exact `--secret-name` match) is still
198
- redacted to `"***"` even when directly targeted — use `value
199
- --reveal-secret` when the real value is genuinely needed.
200
- - `value FILE KEY` writes only the raw scalar to stdout, with no AFDATA
201
- envelope and no forced trailing newline, for direct use in shell
202
- substitution: `value=$(afdata value config.toml server.host)`. Only scalars
203
- are supported; a container errors (`document_not_scalar`) — use `get` for a
204
- subtree. A secret-named leaf errors (`document_secret_redacted`) unless
205
- `--reveal-secret` is passed. On any failure `value`'s stdout is always
206
- empty — the error envelope goes to stderr instead — so
207
- `port=$(afdata value config.toml server.port)` never captures a JSON error
208
- as data. `--default VAL` prints `VAL` instead of erroring when the path is
209
- absent or the value is `null` (an empty string is a real value and does not
210
- trigger it), collapsing the common "read or fall back" shell idiom into one
211
- call with no `2>/dev/null` guard needed.
212
- - `paths FILE [KEY]` and `keys FILE [KEY]` enumerate a container's immediate
213
- children, one per line, with the same empty-stdout-on-failure contract as
214
- `value`. **`paths` output feeds back into afdata** (full grammar-escaped
215
- dot-paths from the root — pipe straight into `value`/`get`/`unset` or
216
- extend with `"$p.field"`); **`keys` output goes to external tools** (raw,
217
- unescaped key names/array indices — what a package manager or another CLI
218
- expects). Never use `paths`'s output as a literal name, or `keys`'s output
219
- as a dot-path — they only diverge on a key containing a dot or space, so
220
- the wrong one works until it silently doesn't. A scalar target errors
221
- (`document_not_container`); `--missing-ok` turns a missing KEY specifically
222
- into empty output + exit 0 (other errors still fail). Path grammar does not
223
- escape spaces or other IFS characters, so the only correct consumption
224
- shape is a `while IFS= read -r` loop, never `for x in $(...)`:
225
-
226
- ```sh
227
- while IFS= read -r p; do
228
- afdata value config.toml "$p.slug"
229
- done < <(afdata paths config.toml extra.tools)
230
- ```
231
- - Escape a literal dot as `\.` and a literal backslash as `\\` in a dot-path;
232
- every command shares this grammar (`paths`'s escaped output re-parses
233
- through the exact same rules it was emitted from), so an unrecognized
234
- escape or empty segment is always an error, never a guess.
235
- - `add`/`remove` operate on a keyed list — an array of objects addressed by a
236
- slug — and always require an explicit `--slug-field FIELD`; the CLI never
237
- infers an identity field. Keyed editing is implemented for JSON and YAML
238
- only; TOML, dotenv, and INI return a structured "not implemented" error, so
239
- edit their list entries by writing the whole value another way. Adding a
240
- slug that already exists, or removing/unsetting one that does not, is
241
- always an error (`document_slug_exists`/`document_slug_not_found`/
242
- `document_path_not_found`) — never a silent no-op; wrap the call yourself
243
- when idempotence is wanted.
244
- - `set`'s bare VALUE (and `add`'s `FIELD=VALUE`) is always a plain string —
245
- no shape-guessing, so a leading-zero ID or SHA never gets reinterpreted as
246
- a number. Writing an exact type goes through `--value-type
247
- string|number|bool|null|json` instead; `json` is the only entry point for
248
- an array or object. Overwriting an *existing* scalar of a different kind
249
- with a bare VALUE is a usage error that names both escape hatches (keep the
250
- type with `--value-type <kind>`, or convert explicitly with `--value-type
251
- string`) — a brand-new key never needs `--value-type`.
252
- - For `set`, choose `--secret-from stdin|prompt|fd:<N>|env:<VAR>` instead of a
253
- positional value when the value must not land in shell history or `ps`:
254
- `stdin` (pipe), `prompt` (human, terminal echo off), `fd:N` (Unix
255
- automation that needs stdin for something else), or `env:VAR` (already in
256
- the process environment). There is no inline `--secret-from=VALUE`-style
257
- argv source — that would defeat the point.
258
- - Mutations preserve the rest of the source document — comments, key order,
259
- unrelated formatting — and refuse to write through a symlink or (on Unix) a
260
- multi-link hardlink target. Treat a failed mutation as leaving the original
261
- file untouched rather than assuming a partial write, and reread before
262
- retrying. A format backend that isn't compiled in, or input outside the
263
- documented dotenv/INI dialect, is a structured error to report, not a cue to
264
- hand-edit the file. A successful mutation's result carries the `path`
265
- actually written, for confirming which file changed when scripting several.
266
- - Branch on `error.code`, not the message text: document errors use stable
267
- codes (`document_path_not_found`, `document_type_mismatch`,
268
- `document_slug_not_found`, `document_slug_exists`, `document_parse_failed`,
269
- `document_io_failed`, and a few narrower ones), while a malformed
270
- invocation (`--input-format`, `--value-type`, `FIELD=VALUE`, a mutation
271
- given `-`, …) is always `document_usage_error` at exit 2 — distinct from
272
- every runtime document error, which exits 1.
273
-
274
- ## Review checklist
275
-
276
- 1. Numeric fields with units carry the right suffix and safe integer/string representation.
277
- 2. Timestamps use `_epoch_s`, `_epoch_ms`, decimal-string `_epoch_ns`, or `_rfc3339`.
278
- 3. Secrets use `_secret` or configured exact secret names; no fallback path leaks them.
279
- 4. CLI output uses AFDATA helpers for JSON/YAML/plain formatting and structured errors, and routes by consumption mode (finite: `result`→stdout, `error`→stderr; stream: one destination) rather than writing to stderr ad hoc.
280
- 5. Logs use AFDATA structured logging or equivalent field-name redaction.
281
- 6. Transport payloads preserve the protocol envelope when AFDATA compliance is claimed.
@@ -1,66 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://agentfirstkit.org/schemas/agent-first-data/protocol-v1.schema.json",
4
- "title": "Agent-First Data Protocol v1 Event",
5
- "type": "object",
6
- "oneOf": [
7
- {"$ref": "#/$defs/resultEvent"},
8
- {"$ref": "#/$defs/errorEvent"},
9
- {"$ref": "#/$defs/progressEvent"},
10
- {"$ref": "#/$defs/logEvent"}
11
- ],
12
- "$defs": {
13
- "trace": {
14
- "type": "object"
15
- },
16
- "resultEvent": {
17
- "type": "object",
18
- "properties": {
19
- "kind": {"const": "result"},
20
- "result": true,
21
- "trace": {"$ref": "#/$defs/trace"}
22
- },
23
- "required": ["kind", "result"],
24
- "additionalProperties": false
25
- },
26
- "errorEvent": {
27
- "type": "object",
28
- "properties": {
29
- "kind": {"const": "error"},
30
- "error": {
31
- "type": "object",
32
- "properties": {
33
- "code": {"type": "string", "minLength": 1},
34
- "message": {"type": "string", "minLength": 1},
35
- "hint": {"type": "string"}
36
- },
37
- "required": ["code", "message"],
38
- "additionalProperties": true
39
- },
40
- "trace": {"$ref": "#/$defs/trace"}
41
- },
42
- "required": ["kind", "error"],
43
- "additionalProperties": false
44
- },
45
- "progressEvent": {
46
- "type": "object",
47
- "properties": {
48
- "kind": {"const": "progress"},
49
- "progress": true,
50
- "trace": {"$ref": "#/$defs/trace"}
51
- },
52
- "required": ["kind", "progress"],
53
- "additionalProperties": false
54
- },
55
- "logEvent": {
56
- "type": "object",
57
- "properties": {
58
- "kind": {"const": "log"},
59
- "log": true,
60
- "trace": {"$ref": "#/$defs/trace"}
61
- },
62
- "required": ["kind", "log"],
63
- "additionalProperties": false
64
- }
65
- }
66
- }
@@ -1,251 +0,0 @@
1
- {
2
- "$schema": "https://agentfirstkit.org/schemas/agent-first-data/registry-v1.schema.json",
3
- "schema_version": 1,
4
- "name": "agent-first-data",
5
- "description": "Machine-readable registry for Agent-First Data suffix semantics.",
6
- "safe_integer": {
7
- "minimum": -9007199254740991,
8
- "maximum": 9007199254740991
9
- },
10
- "suffixes": [
11
- {
12
- "suffix": "_ns",
13
- "category": "duration",
14
- "json_types": ["number"],
15
- "unit": "nanosecond",
16
- "formatting": {"strip_key": true, "plain_yaml": "append_unit"},
17
- "redaction": {"mode": "none"},
18
- "constraints": {"number": true}
19
- },
20
- {
21
- "suffix": "_us",
22
- "category": "duration",
23
- "json_types": ["number"],
24
- "unit": "microsecond",
25
- "formatting": {"strip_key": true, "plain_yaml": "append_unit"},
26
- "redaction": {"mode": "none"},
27
- "constraints": {"number": true}
28
- },
29
- {
30
- "suffix": "_ms",
31
- "category": "duration",
32
- "json_types": ["number"],
33
- "unit": "millisecond",
34
- "formatting": {"strip_key": true, "plain_yaml": "duration_ms"},
35
- "redaction": {"mode": "none"},
36
- "constraints": {"number": true}
37
- },
38
- {
39
- "suffix": "_s",
40
- "category": "duration",
41
- "json_types": ["number"],
42
- "unit": "second",
43
- "formatting": {"strip_key": true, "plain_yaml": "append_unit"},
44
- "redaction": {"mode": "none"},
45
- "constraints": {"number": true}
46
- },
47
- {
48
- "suffix": "_minutes",
49
- "category": "duration",
50
- "json_types": ["number"],
51
- "unit": "minute",
52
- "formatting": {"strip_key": true, "plain_yaml": "append_unit_word"},
53
- "redaction": {"mode": "none"},
54
- "constraints": {"number": true}
55
- },
56
- {
57
- "suffix": "_hours",
58
- "category": "duration",
59
- "json_types": ["number"],
60
- "unit": "hour",
61
- "formatting": {"strip_key": true, "plain_yaml": "append_unit_word"},
62
- "redaction": {"mode": "none"},
63
- "constraints": {"number": true}
64
- },
65
- {
66
- "suffix": "_days",
67
- "category": "duration",
68
- "json_types": ["number"],
69
- "unit": "day",
70
- "formatting": {"strip_key": true, "plain_yaml": "append_unit_word"},
71
- "redaction": {"mode": "none"},
72
- "constraints": {"number": true}
73
- },
74
- {
75
- "suffix": "_epoch_s",
76
- "category": "timestamp",
77
- "json_types": ["integer"],
78
- "unit": "unix_epoch_second",
79
- "formatting": {"strip_key": true, "plain_yaml": "rfc3339_datetime"},
80
- "redaction": {"mode": "none"},
81
- "constraints": {"integer": true}
82
- },
83
- {
84
- "suffix": "_epoch_ms",
85
- "category": "timestamp",
86
- "json_types": ["integer"],
87
- "unit": "unix_epoch_millisecond",
88
- "formatting": {"strip_key": true, "plain_yaml": "rfc3339_datetime"},
89
- "redaction": {"mode": "none"},
90
- "constraints": {"integer": true}
91
- },
92
- {
93
- "suffix": "_epoch_ns",
94
- "category": "timestamp",
95
- "json_types": ["string"],
96
- "unit": "unix_epoch_nanosecond",
97
- "formatting": {"strip_key": true, "plain_yaml": "rfc3339_datetime"},
98
- "redaction": {"mode": "none"},
99
- "constraints": {"decimal_integer_string": true}
100
- },
101
- {
102
- "suffix": "_rfc3339",
103
- "category": "timestamp",
104
- "json_types": ["string"],
105
- "unit": "rfc3339_datetime",
106
- "formatting": {"strip_key": true, "plain_yaml": "pass_through"},
107
- "redaction": {"mode": "none"},
108
- "constraints": {"rfc3339_datetime": true}
109
- },
110
- {
111
- "suffix": "_rfc3339_date",
112
- "category": "strict_string",
113
- "json_types": ["string"],
114
- "unit": "rfc3339_full_date",
115
- "formatting": {"strip_key": false, "plain_yaml": "pass_through"},
116
- "redaction": {"mode": "none"},
117
- "constraints": {"rfc3339_date": true}
118
- },
119
- {
120
- "suffix": "_rfc3339_time",
121
- "category": "strict_string",
122
- "json_types": ["string"],
123
- "unit": "rfc3339_partial_time",
124
- "formatting": {"strip_key": false, "plain_yaml": "pass_through"},
125
- "redaction": {"mode": "none"},
126
- "constraints": {"rfc3339_time": true}
127
- },
128
- {
129
- "suffix": "_bcp47",
130
- "category": "strict_string",
131
- "json_types": ["string"],
132
- "unit": "bcp47_language_tag",
133
- "formatting": {"strip_key": false, "plain_yaml": "pass_through"},
134
- "redaction": {"mode": "none"},
135
- "constraints": {"bcp47": true}
136
- },
137
- {
138
- "suffix": "_utc_offset",
139
- "category": "strict_string",
140
- "json_types": ["string"],
141
- "unit": "fixed_utc_offset",
142
- "formatting": {"strip_key": false, "plain_yaml": "pass_through"},
143
- "redaction": {"mode": "none"},
144
- "constraints": {"utc_offset": true}
145
- },
146
- {
147
- "suffix": "_bytes",
148
- "category": "size",
149
- "json_types": ["integer"],
150
- "unit": "byte",
151
- "formatting": {"strip_key": true, "plain_yaml": "binary_size"},
152
- "redaction": {"mode": "none"},
153
- "constraints": {"integer": true, "minimum": 0}
154
- },
155
- {
156
- "suffix": "_percent",
157
- "category": "percentage",
158
- "json_types": ["number"],
159
- "unit": "percent",
160
- "formatting": {"strip_key": true, "plain_yaml": "append_percent"},
161
- "redaction": {"mode": "none"},
162
- "constraints": {"number": true}
163
- },
164
- {
165
- "suffix": "_msats",
166
- "category": "currency",
167
- "json_types": ["integer", "string"],
168
- "unit": "millisatoshi",
169
- "formatting": {"strip_key": true, "plain_yaml": "append_unit"},
170
- "redaction": {"mode": "none"},
171
- "constraints": {"integer_or_decimal_integer_string": true}
172
- },
173
- {
174
- "suffix": "_sats",
175
- "category": "currency",
176
- "json_types": ["integer", "string"],
177
- "unit": "satoshi",
178
- "formatting": {"strip_key": true, "plain_yaml": "append_unit"},
179
- "redaction": {"mode": "none"},
180
- "constraints": {"integer_or_decimal_integer_string": true}
181
- },
182
- {
183
- "suffix": "_usd_cents",
184
- "category": "currency",
185
- "json_types": ["integer"],
186
- "unit": "usd_cent",
187
- "formatting": {"strip_key": true, "plain_yaml": "currency_minor_unit"},
188
- "redaction": {"mode": "none"},
189
- "constraints": {"integer": true}
190
- },
191
- {
192
- "suffix": "_eur_cents",
193
- "category": "currency",
194
- "json_types": ["integer"],
195
- "unit": "eur_cent",
196
- "formatting": {"strip_key": true, "plain_yaml": "currency_minor_unit"},
197
- "redaction": {"mode": "none"},
198
- "constraints": {"integer": true}
199
- },
200
- {
201
- "suffix": "_jpy",
202
- "category": "currency",
203
- "json_types": ["integer"],
204
- "unit": "jpy",
205
- "formatting": {"strip_key": true, "plain_yaml": "currency_major_unit"},
206
- "redaction": {"mode": "none"},
207
- "constraints": {"integer": true}
208
- },
209
- {
210
- "suffix": "_{code}_cents",
211
- "category": "currency",
212
- "json_types": ["integer"],
213
- "unit": "currency_minor_unit",
214
- "formatting": {"strip_key": true, "plain_yaml": "currency_code_minor_unit"},
215
- "redaction": {"mode": "none"},
216
- "constraints": {"integer": true, "code_pattern": "^[A-Za-z]{3,4}$"}
217
- },
218
- {
219
- "suffix": "_{code}_micro",
220
- "category": "currency",
221
- "json_types": ["integer"],
222
- "unit": "currency_micro_unit",
223
- "formatting": {"strip_key": true, "plain_yaml": "currency_code_micro_unit"},
224
- "redaction": {"mode": "none"},
225
- "constraints": {"integer": true, "code_pattern": "^[A-Za-z]{3,4}$"}
226
- },
227
- {
228
- "suffix": "_secret",
229
- "category": "sensitive",
230
- "json_types": ["any"],
231
- "unit": null,
232
- "formatting": {"strip_key": true, "plain_yaml": "redacted"},
233
- "redaction": {"mode": "whole_value", "marker": "***"},
234
- "constraints": {"free_text_detection": false}
235
- },
236
- {
237
- "suffix": "_url",
238
- "category": "sensitive",
239
- "json_types": ["string"],
240
- "unit": "url",
241
- "formatting": {"strip_key": false, "plain_yaml": "scrub_url"},
242
- "redaction": {
243
- "mode": "url_components",
244
- "userinfo_password": true,
245
- "query_param_secret_suffix": "_secret",
246
- "marker": "***"
247
- },
248
- "constraints": {"single_url_string": true, "free_text_detection": false}
249
- }
250
- ]
251
- }