agent-first-data 0.14.2__tar.gz → 0.16.0__tar.gz
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.
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/PKG-INFO +11 -11
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/README.md +10 -10
- agent_first_data-0.16.0/agent_first_data/__init__.py +92 -0
- agent_first_data-0.16.0/agent_first_data/assets/protocol-v1.schema.json +84 -0
- agent_first_data-0.16.0/agent_first_data/assets/registry.json +260 -0
- agent_first_data-0.16.0/agent_first_data/assets/skills/agent-first-data/SKILL.md +64 -0
- agent_first_data-0.16.0/agent_first_data/assets/skills/agent-first-data/references/protocol-v1.schema.json +66 -0
- agent_first_data-0.16.0/agent_first_data/assets/skills/agent-first-data/references/registry.json +260 -0
- agent_first_data-0.16.0/agent_first_data/assets/skills/agent-first-data/references/rules.md +347 -0
- agent_first_data-0.16.0/agent_first_data/cli.py +336 -0
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/agent_first_data/format.py +672 -162
- agent_first_data-0.16.0/agent_first_data/stream_redirect.py +173 -0
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/agent_first_data.egg-info/PKG-INFO +11 -11
- agent_first_data-0.16.0/agent_first_data.egg-info/SOURCES.txt +22 -0
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/pyproject.toml +9 -1
- agent_first_data-0.16.0/tests/test_cli.py +316 -0
- agent_first_data-0.16.0/tests/test_format.py +428 -0
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/tests/test_no_stderr_policy.py +2 -0
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/tests/test_skill.py +3 -5
- agent_first_data-0.16.0/tests/test_stream_redirect.py +62 -0
- agent_first_data-0.14.2/agent_first_data/__init__.py +0 -122
- agent_first_data-0.14.2/agent_first_data/afdata_logging.py +0 -197
- agent_first_data-0.14.2/agent_first_data/cli.py +0 -189
- agent_first_data-0.14.2/agent_first_data.egg-info/SOURCES.txt +0 -16
- agent_first_data-0.14.2/tests/test_afdata_logging.py +0 -255
- agent_first_data-0.14.2/tests/test_cli.py +0 -173
- agent_first_data-0.14.2/tests/test_format.py +0 -288
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/agent_first_data/skill.py +0 -0
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/agent_first_data.egg-info/dependency_links.txt +0 -0
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/agent_first_data.egg-info/top_level.txt +0 -0
- {agent_first_data-0.14.2 → agent_first_data-0.16.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-first-data
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.0
|
|
4
4
|
Summary: A naming convention that lets AI agents understand your data without being told what it means.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/agentfirstkit/agent-first-data
|
|
@@ -14,22 +14,21 @@ pip install agent-first-data
|
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
```python
|
|
17
|
-
from agent_first_data import output_json, output_plain
|
|
17
|
+
from agent_first_data import json_result, output_json, output_plain
|
|
18
18
|
|
|
19
|
-
value =
|
|
20
|
-
|
|
21
|
-
"result": {
|
|
19
|
+
value = json_result(
|
|
20
|
+
{
|
|
22
21
|
"api_key_secret": "sk-123",
|
|
23
22
|
"latency_ms": 1280,
|
|
24
23
|
"db_url": "postgres://user:p@ss@db/app?token_secret=abc",
|
|
25
|
-
}
|
|
26
|
-
|
|
24
|
+
}
|
|
25
|
+
).build()
|
|
27
26
|
|
|
28
27
|
print(output_json(value))
|
|
29
28
|
print(output_plain(value))
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain
|
|
31
|
+
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain` (each takes an optional keyword-only `options=`), `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, `cli_handle_version_or_continue`, `decode_protocol_event`. Skill admin and stream-redirect helpers live in `agent_first_data.skill` and `agent_first_data.stream_redirect` (import the submodule directly).
|
|
33
32
|
|
|
34
33
|
Logging is available through `init_logging_json`, `init_logging_plain`, `init_logging_yaml`, `span`, and `get_logger`.
|
|
35
34
|
|
|
@@ -44,13 +43,14 @@ init_logging_json("INFO", secret_names=("authorization",))
|
|
|
44
43
|
- Default redaction replaces every `_secret` or configured secret-name subtree with `***`, including objects and arrays.
|
|
45
44
|
- `_url` fields scrub userinfo passwords and secret-named query parameters; surrounding whitespace is trimmed and internal whitespace redacts the whole field.
|
|
46
45
|
- YAML/plain quote and escape keys as well as values, sort by UTF-16 code unit order, and render nested objects in arrays as canonical JSON.
|
|
47
|
-
- Logging records use `
|
|
48
|
-
- `build_cli_error(message, hint?)` returns
|
|
46
|
+
- Logging records use `kind:"log"` with a nested `log` payload and a separate `level` field, so error-level logs are not terminal protocol errors.
|
|
47
|
+
- `build_cli_error(message, hint?)` returns a strict-ready CLI error with `error.retryable:false` and `trace:{}`.
|
|
49
48
|
- Use `cli_handle_version_or_continue()` before argument parsing so bare `--version` stays conventional and `--version --output json|yaml|plain` stays structured.
|
|
49
|
+
- Use `agent_first_data.stream_redirect.install_from_raw_args()` before version/help handling if a CLI exposes `--stdout-file` or `--stderr-file`; stderr is redirected as native diagnostics, not JSON.
|
|
50
50
|
|
|
51
51
|
## Reference
|
|
52
52
|
|
|
53
53
|
- Full convention and API groups: [docs/overview.md](https://github.com/agentfirstkit/agent-first-data/blob/main/docs/overview.md)
|
|
54
54
|
- Formal cross-language contract: [spec/agent-first-data.md](https://github.com/agentfirstkit/agent-first-data/blob/main/spec/agent-first-data.md)
|
|
55
55
|
- Conformance fixtures: [spec/fixtures](https://github.com/agentfirstkit/agent-first-data/tree/main/spec/fixtures)
|
|
56
|
-
- Agent skill: [skills/agent-first-data.md](https://github.com/agentfirstkit/agent-first-data/blob/main/skills/agent-first-data.md)
|
|
56
|
+
- Agent skill: [skills/agent-first-data/SKILL.md](https://github.com/agentfirstkit/agent-first-data/blob/main/skills/agent-first-data/SKILL.md)
|
|
@@ -5,22 +5,21 @@ pip install agent-first-data
|
|
|
5
5
|
```
|
|
6
6
|
|
|
7
7
|
```python
|
|
8
|
-
from agent_first_data import output_json, output_plain
|
|
8
|
+
from agent_first_data import json_result, output_json, output_plain
|
|
9
9
|
|
|
10
|
-
value =
|
|
11
|
-
|
|
12
|
-
"result": {
|
|
10
|
+
value = json_result(
|
|
11
|
+
{
|
|
13
12
|
"api_key_secret": "sk-123",
|
|
14
13
|
"latency_ms": 1280,
|
|
15
14
|
"db_url": "postgres://user:p@ss@db/app?token_secret=abc",
|
|
16
|
-
}
|
|
17
|
-
|
|
15
|
+
}
|
|
16
|
+
).build()
|
|
18
17
|
|
|
19
18
|
print(output_json(value))
|
|
20
19
|
print(output_plain(value))
|
|
21
20
|
```
|
|
22
21
|
|
|
23
|
-
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain
|
|
22
|
+
Useful names use Python casing: `output_json`, `output_yaml`, `output_plain` (each takes an optional keyword-only `options=`), `redacted_value`, `redact_secrets_in_place`, `redact_url_secrets`, `parse_size`, `normalize_utc_offset`, `is_valid_rfc3339_date`, `is_valid_rfc3339_time`, `cli_parse_output`, `cli_output`, `build_cli_error`, `build_cli_version`, `cli_handle_version_or_continue`, `decode_protocol_event`. Skill admin and stream-redirect helpers live in `agent_first_data.skill` and `agent_first_data.stream_redirect` (import the submodule directly).
|
|
24
23
|
|
|
25
24
|
Logging is available through `init_logging_json`, `init_logging_plain`, `init_logging_yaml`, `span`, and `get_logger`.
|
|
26
25
|
|
|
@@ -35,13 +34,14 @@ init_logging_json("INFO", secret_names=("authorization",))
|
|
|
35
34
|
- Default redaction replaces every `_secret` or configured secret-name subtree with `***`, including objects and arrays.
|
|
36
35
|
- `_url` fields scrub userinfo passwords and secret-named query parameters; surrounding whitespace is trimmed and internal whitespace redacts the whole field.
|
|
37
36
|
- YAML/plain quote and escape keys as well as values, sort by UTF-16 code unit order, and render nested objects in arrays as canonical JSON.
|
|
38
|
-
- Logging records use `
|
|
39
|
-
- `build_cli_error(message, hint?)` returns
|
|
37
|
+
- Logging records use `kind:"log"` with a nested `log` payload and a separate `level` field, so error-level logs are not terminal protocol errors.
|
|
38
|
+
- `build_cli_error(message, hint?)` returns a strict-ready CLI error with `error.retryable:false` and `trace:{}`.
|
|
40
39
|
- Use `cli_handle_version_or_continue()` before argument parsing so bare `--version` stays conventional and `--version --output json|yaml|plain` stays structured.
|
|
40
|
+
- Use `agent_first_data.stream_redirect.install_from_raw_args()` before version/help handling if a CLI exposes `--stdout-file` or `--stderr-file`; stderr is redirected as native diagnostics, not JSON.
|
|
41
41
|
|
|
42
42
|
## Reference
|
|
43
43
|
|
|
44
44
|
- Full convention and API groups: [docs/overview.md](https://github.com/agentfirstkit/agent-first-data/blob/main/docs/overview.md)
|
|
45
45
|
- Formal cross-language contract: [spec/agent-first-data.md](https://github.com/agentfirstkit/agent-first-data/blob/main/spec/agent-first-data.md)
|
|
46
46
|
- Conformance fixtures: [spec/fixtures](https://github.com/agentfirstkit/agent-first-data/tree/main/spec/fixtures)
|
|
47
|
-
- Agent skill: [skills/agent-first-data.md](https://github.com/agentfirstkit/agent-first-data/blob/main/skills/agent-first-data.md)
|
|
47
|
+
- Agent skill: [skills/agent-first-data/SKILL.md](https://github.com/agentfirstkit/agent-first-data/blob/main/skills/agent-first-data/SKILL.md)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates."""
|
|
2
|
+
|
|
3
|
+
from agent_first_data.format import (
|
|
4
|
+
LogLevel,
|
|
5
|
+
Event,
|
|
6
|
+
EventBuildError,
|
|
7
|
+
json_result,
|
|
8
|
+
json_error,
|
|
9
|
+
json_progress,
|
|
10
|
+
json_log,
|
|
11
|
+
ResultBuilder,
|
|
12
|
+
ErrorBuilder,
|
|
13
|
+
ProgressBuilder,
|
|
14
|
+
LogBuilder,
|
|
15
|
+
validate_protocol_event,
|
|
16
|
+
validate_protocol_stream,
|
|
17
|
+
EventDecodeError,
|
|
18
|
+
DecodedResult,
|
|
19
|
+
DecodedError,
|
|
20
|
+
DecodedProgress,
|
|
21
|
+
DecodedLog,
|
|
22
|
+
decode_protocol_event,
|
|
23
|
+
RedactionPolicy,
|
|
24
|
+
OutputStyle,
|
|
25
|
+
OutputOptions,
|
|
26
|
+
output_json,
|
|
27
|
+
output_yaml,
|
|
28
|
+
output_plain,
|
|
29
|
+
redacted_value,
|
|
30
|
+
redact_url_secrets,
|
|
31
|
+
parse_size,
|
|
32
|
+
normalize_utc_offset,
|
|
33
|
+
is_valid_rfc3339_date,
|
|
34
|
+
is_valid_rfc3339_time,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
from agent_first_data.cli import (
|
|
38
|
+
OutputFormat,
|
|
39
|
+
LogFilters,
|
|
40
|
+
CliEmitter,
|
|
41
|
+
cli_parse_output,
|
|
42
|
+
cli_parse_log_filters,
|
|
43
|
+
cli_output,
|
|
44
|
+
build_cli_error,
|
|
45
|
+
build_cli_version,
|
|
46
|
+
cli_render_version,
|
|
47
|
+
cli_handle_version_or_continue,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
"LogLevel",
|
|
52
|
+
"Event",
|
|
53
|
+
"EventBuildError",
|
|
54
|
+
"json_result",
|
|
55
|
+
"json_error",
|
|
56
|
+
"json_progress",
|
|
57
|
+
"json_log",
|
|
58
|
+
"ResultBuilder",
|
|
59
|
+
"ErrorBuilder",
|
|
60
|
+
"ProgressBuilder",
|
|
61
|
+
"LogBuilder",
|
|
62
|
+
"validate_protocol_event",
|
|
63
|
+
"validate_protocol_stream",
|
|
64
|
+
"EventDecodeError",
|
|
65
|
+
"DecodedResult",
|
|
66
|
+
"DecodedError",
|
|
67
|
+
"DecodedProgress",
|
|
68
|
+
"DecodedLog",
|
|
69
|
+
"decode_protocol_event",
|
|
70
|
+
"RedactionPolicy",
|
|
71
|
+
"OutputStyle",
|
|
72
|
+
"OutputOptions",
|
|
73
|
+
"output_json",
|
|
74
|
+
"output_yaml",
|
|
75
|
+
"output_plain",
|
|
76
|
+
"redacted_value",
|
|
77
|
+
"redact_url_secrets",
|
|
78
|
+
"parse_size",
|
|
79
|
+
"normalize_utc_offset",
|
|
80
|
+
"is_valid_rfc3339_date",
|
|
81
|
+
"is_valid_rfc3339_time",
|
|
82
|
+
"OutputFormat",
|
|
83
|
+
"LogFilters",
|
|
84
|
+
"CliEmitter",
|
|
85
|
+
"cli_parse_output",
|
|
86
|
+
"cli_parse_log_filters",
|
|
87
|
+
"cli_output",
|
|
88
|
+
"build_cli_error",
|
|
89
|
+
"build_cli_version",
|
|
90
|
+
"cli_render_version",
|
|
91
|
+
"cli_handle_version_or_continue",
|
|
92
|
+
]
|
|
@@ -0,0 +1,84 @@
|
|
|
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
|
+
"retryable": {"type": "boolean"},
|
|
36
|
+
"hint": {"type": "string"}
|
|
37
|
+
},
|
|
38
|
+
"required": ["code", "message", "retryable"],
|
|
39
|
+
"additionalProperties": true
|
|
40
|
+
},
|
|
41
|
+
"trace": {"$ref": "#/$defs/trace"}
|
|
42
|
+
},
|
|
43
|
+
"required": ["kind", "error"],
|
|
44
|
+
"additionalProperties": false
|
|
45
|
+
},
|
|
46
|
+
"progressEvent": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"properties": {
|
|
49
|
+
"kind": {"const": "progress"},
|
|
50
|
+
"progress": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"properties": {
|
|
53
|
+
"message": {"type": "string", "minLength": 1}
|
|
54
|
+
},
|
|
55
|
+
"additionalProperties": true
|
|
56
|
+
},
|
|
57
|
+
"trace": {"$ref": "#/$defs/trace"}
|
|
58
|
+
},
|
|
59
|
+
"required": ["kind", "progress"],
|
|
60
|
+
"additionalProperties": false
|
|
61
|
+
},
|
|
62
|
+
"logEvent": {
|
|
63
|
+
"type": "object",
|
|
64
|
+
"properties": {
|
|
65
|
+
"kind": {"const": "log"},
|
|
66
|
+
"log": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"properties": {
|
|
69
|
+
"message": {"type": "string", "minLength": 1},
|
|
70
|
+
"level": {"enum": ["debug", "info", "warn", "error"]},
|
|
71
|
+
"code": false
|
|
72
|
+
},
|
|
73
|
+
"not": {
|
|
74
|
+
"required": ["code"]
|
|
75
|
+
},
|
|
76
|
+
"additionalProperties": true
|
|
77
|
+
},
|
|
78
|
+
"trace": {"$ref": "#/$defs/trace"}
|
|
79
|
+
},
|
|
80
|
+
"required": ["kind", "log"],
|
|
81
|
+
"additionalProperties": false
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
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": {"string": 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": "_size",
|
|
157
|
+
"category": "size",
|
|
158
|
+
"json_types": ["string"],
|
|
159
|
+
"unit": "byte_size_input",
|
|
160
|
+
"formatting": {"strip_key": false, "plain_yaml": "pass_through"},
|
|
161
|
+
"redaction": {"mode": "none"},
|
|
162
|
+
"constraints": {"parse_size_units": ["B", "kB", "MB", "GB", "TB", "KiB", "MiB", "GiB", "TiB"]}
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"suffix": "_percent",
|
|
166
|
+
"category": "ratio",
|
|
167
|
+
"json_types": ["number"],
|
|
168
|
+
"unit": "percent",
|
|
169
|
+
"formatting": {"strip_key": true, "plain_yaml": "append_percent"},
|
|
170
|
+
"redaction": {"mode": "none"},
|
|
171
|
+
"constraints": {"number": true}
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"suffix": "_msats",
|
|
175
|
+
"category": "currency",
|
|
176
|
+
"json_types": ["integer", "string"],
|
|
177
|
+
"unit": "millisatoshi",
|
|
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": "_sats",
|
|
184
|
+
"category": "currency",
|
|
185
|
+
"json_types": ["integer", "string"],
|
|
186
|
+
"unit": "satoshi",
|
|
187
|
+
"formatting": {"strip_key": true, "plain_yaml": "append_unit"},
|
|
188
|
+
"redaction": {"mode": "none"},
|
|
189
|
+
"constraints": {"integer_or_decimal_integer_string": true}
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"suffix": "_usd_cents",
|
|
193
|
+
"category": "currency",
|
|
194
|
+
"json_types": ["integer"],
|
|
195
|
+
"unit": "usd_cent",
|
|
196
|
+
"formatting": {"strip_key": true, "plain_yaml": "currency_minor_unit"},
|
|
197
|
+
"redaction": {"mode": "none"},
|
|
198
|
+
"constraints": {"integer": true}
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"suffix": "_eur_cents",
|
|
202
|
+
"category": "currency",
|
|
203
|
+
"json_types": ["integer"],
|
|
204
|
+
"unit": "eur_cent",
|
|
205
|
+
"formatting": {"strip_key": true, "plain_yaml": "currency_minor_unit"},
|
|
206
|
+
"redaction": {"mode": "none"},
|
|
207
|
+
"constraints": {"integer": true}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"suffix": "_jpy",
|
|
211
|
+
"category": "currency",
|
|
212
|
+
"json_types": ["integer"],
|
|
213
|
+
"unit": "jpy",
|
|
214
|
+
"formatting": {"strip_key": true, "plain_yaml": "currency_major_unit"},
|
|
215
|
+
"redaction": {"mode": "none"},
|
|
216
|
+
"constraints": {"integer": true}
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"suffix": "_{code}_cents",
|
|
220
|
+
"category": "currency",
|
|
221
|
+
"json_types": ["integer"],
|
|
222
|
+
"unit": "currency_minor_unit",
|
|
223
|
+
"formatting": {"strip_key": true, "plain_yaml": "currency_code_minor_unit"},
|
|
224
|
+
"redaction": {"mode": "none"},
|
|
225
|
+
"constraints": {"integer": true, "code_pattern": "^[A-Za-z]{3,4}$"}
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"suffix": "_{code}_micro",
|
|
229
|
+
"category": "currency",
|
|
230
|
+
"json_types": ["integer"],
|
|
231
|
+
"unit": "currency_micro_unit",
|
|
232
|
+
"formatting": {"strip_key": true, "plain_yaml": "currency_code_micro_unit"},
|
|
233
|
+
"redaction": {"mode": "none"},
|
|
234
|
+
"constraints": {"integer": true, "code_pattern": "^[A-Za-z]{3,4}$"}
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"suffix": "_secret",
|
|
238
|
+
"category": "sensitive",
|
|
239
|
+
"json_types": ["any"],
|
|
240
|
+
"unit": null,
|
|
241
|
+
"formatting": {"strip_key": true, "plain_yaml": "redacted"},
|
|
242
|
+
"redaction": {"mode": "whole_value", "marker": "***"},
|
|
243
|
+
"constraints": {"free_text_detection": false}
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"suffix": "_url",
|
|
247
|
+
"category": "sensitive",
|
|
248
|
+
"json_types": ["string"],
|
|
249
|
+
"unit": "url",
|
|
250
|
+
"formatting": {"strip_key": false, "plain_yaml": "scrub_url"},
|
|
251
|
+
"redaction": {
|
|
252
|
+
"mode": "url_components",
|
|
253
|
+
"userinfo_password": true,
|
|
254
|
+
"query_param_secret_suffix": "_secret",
|
|
255
|
+
"marker": "***"
|
|
256
|
+
},
|
|
257
|
+
"constraints": {"single_url_string": true, "free_text_detection": false}
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-first-data
|
|
3
|
+
description: Apply Agent-First Data naming, redaction, formatting, protocol envelope, logging, and CLI lint/validate workflows when writing or reviewing structured data, configs, logs, transport payloads, database/wire fields, or CLI output in any language. Use proactively before adding, renaming, serializing, or changing public API, wire, database, or persistent field names that may need AFDATA suffixes.
|
|
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
|
+
## Read references as needed
|
|
15
|
+
|
|
16
|
+
- `references/rules.md` — detailed suffix rules, output formatting, protocol templates, logging, CLI flags, and review checklist.
|
|
17
|
+
- `references/registry.json` — machine-readable suffix registry; use this as the exact source for suffix metadata.
|
|
18
|
+
- `references/protocol-v1.schema.json` — protocol event schema for `kind:"result"`, `kind:"error"`, `kind:"progress"`, and `kind:"log"` envelopes.
|
|
19
|
+
|
|
20
|
+
## Naming and redaction decisions
|
|
21
|
+
|
|
22
|
+
- Add unit suffixes to ambiguous numeric fields: `_ms`, `_s`, `_bytes`, `_percent`, `_sats`, `_msats`, currency suffixes, and timestamp suffixes.
|
|
23
|
+
- Use `_secret` for values/subtrees that must redact to `***` in every output format.
|
|
24
|
+
- Use `_url` only for whole URL values whose userinfo password or suffix-named secret query params should be scrubbed.
|
|
25
|
+
- Do not scan arbitrary free text for secrets. Rename fields or configure explicit secret names at the serialization boundary.
|
|
26
|
+
- Before changing public API, wire, database, or persistent field names, report the compatibility impact and get approval.
|
|
27
|
+
|
|
28
|
+
## Evaluation rules
|
|
29
|
+
|
|
30
|
+
- 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.
|
|
31
|
+
- Treat `references/registry.json` and `references/protocol-v1.schema.json` as authoritative. Do not replace them with invented suffix meanings, a reduced schema, or free-text interpretation.
|
|
32
|
+
- 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.
|
|
33
|
+
- 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.
|
|
34
|
+
- 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.
|
|
35
|
+
|
|
36
|
+
## Redaction behavior contract
|
|
37
|
+
|
|
38
|
+
Fields named `_secret` or `_url` and values passing through AFDATA output formatters (`output_json`, `output_yaml`, `output_plain`) 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.
|
|
39
|
+
|
|
40
|
+
## Logging behavior contract
|
|
41
|
+
|
|
42
|
+
One-time CLI output uses `json_log()` or `CliEmitter` for a single event; serialization via `cli_output()` applies output formatting. 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.
|
|
43
|
+
|
|
44
|
+
## CLI workflow
|
|
45
|
+
|
|
46
|
+
When the project has the `afdata` CLI available, use it for deterministic checks:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
afdata lint <file-or-stdin>
|
|
50
|
+
afdata validate <file-or-stdin>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- Run `afdata lint` for ordinary JSON/JSONL, JSON Schema, or MCP input/output schemas.
|
|
54
|
+
- Run `afdata validate` for AFDATA protocol events or finite event streams.
|
|
55
|
+
- Treat findings as contract issues unless the owning tool intentionally documents a non-AFDATA field.
|
|
56
|
+
|
|
57
|
+
## Review checklist
|
|
58
|
+
|
|
59
|
+
1. Numeric fields with units carry the right suffix and safe integer/string representation.
|
|
60
|
+
2. Timestamps use `_epoch_s`, `_epoch_ms`, decimal-string `_epoch_ns`, or `_rfc3339`.
|
|
61
|
+
3. Secrets use `_secret` or configured exact secret names; no fallback path leaks them.
|
|
62
|
+
4. CLI output uses AFDATA helpers for JSON/YAML/plain formatting and structured errors.
|
|
63
|
+
5. Logs use AFDATA structured logging or equivalent field-name redaction.
|
|
64
|
+
6. Transport payloads preserve the protocol envelope when AFDATA compliance is claimed.
|