agent-first-data 0.17.2__tar.gz → 0.17.3__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.
Files changed (24) hide show
  1. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/PKG-INFO +1 -1
  2. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/assets/skills/agent-first-data/SKILL.md +76 -6
  3. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/stream_redirect.py +5 -2
  4. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data.egg-info/PKG-INFO +1 -1
  5. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/pyproject.toml +1 -1
  6. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/tests/test_skill.py +2 -2
  7. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/tests/test_stream_redirect.py +3 -1
  8. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/README.md +0 -0
  9. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/__init__.py +0 -0
  10. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/assets/protocol-v1.schema.json +0 -0
  11. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/assets/registry.json +0 -0
  12. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/assets/skills/agent-first-data/references/protocol-v1.schema.json +0 -0
  13. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/assets/skills/agent-first-data/references/registry.json +0 -0
  14. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/assets/skills/agent-first-data/references/rules.md +0 -0
  15. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/cli.py +0 -0
  16. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/format.py +0 -0
  17. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data/skill.py +0 -0
  18. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data.egg-info/SOURCES.txt +0 -0
  19. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data.egg-info/dependency_links.txt +0 -0
  20. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/agent_first_data.egg-info/top_level.txt +0 -0
  21. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/setup.cfg +0 -0
  22. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/tests/test_cli.py +0 -0
  23. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/tests/test_format.py +0 -0
  24. {agent_first_data-0.17.2 → agent_first_data-0.17.3}/tests/test_no_stderr_policy.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-first-data
3
- Version: 0.17.2
3
+ Version: 0.17.3
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
@@ -1,6 +1,6 @@
1
1
  ---
2
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.
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, and validation. Use proactively when writing or reviewing structured data, configs, logs, transport payloads, database/wire fields, CLI output, or compatibility-sensitive public and persistent field names.
4
4
  ---
5
5
 
6
6
  <!-- Canonical source: skills/agent-first-data/SKILL.md.
@@ -11,12 +11,67 @@ description: Apply Agent-First Data naming, redaction, formatting, protocol enve
11
11
 
12
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
13
 
14
- ## Read references as needed
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:
15
27
 
16
28
  - `references/rules.md` — detailed suffix rules, output formatting, protocol templates, logging, CLI flags, and review checklist.
17
29
  - `references/registry.json` — machine-readable suffix registry; use this as the exact source for suffix metadata.
18
30
  - `references/protocol-v1.schema.json` — protocol event schema for `kind:"result"`, `kind:"error"`, `kind:"progress"`, and `kind:"log"` envelopes.
19
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, output_json};
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 = output_json(event.as_value());
58
+ assert!(rendered.contains("\"api_key_secret\":\"***\""));
59
+ # Ok::<(), agent_first_data::BuildError>(())
60
+ ```
61
+
62
+ For a finite CLI execution implemented in Rust, create one `CliEmitter`, select
63
+ `OutputFormat` through `cli_parse_output`, enable strict protocol, and emit one
64
+ terminal result or error. Handle version before clap with
65
+ `cli_handle_version_or_continue` and `VersionConfig::conventional_default()`.
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
+
20
75
  ## Naming and redaction decisions
21
76
 
22
77
  - Add unit suffixes to ambiguous numeric fields: `_ms`, `_s`, `_bytes`, `_percent`, `_sats`, `_msats`, currency suffixes, and timestamp suffixes.
@@ -28,7 +83,11 @@ Use AFDATA when naming fields or reviewing structured output. The contract is na
28
83
  ## Evaluation rules
29
84
 
30
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.
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.
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.
32
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.
33
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.
34
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.
@@ -43,15 +102,26 @@ One-time CLI output uses `json_log()` or `CliEmitter` for a single event; serial
43
102
 
44
103
  ## CLI workflow
45
104
 
46
- When the project has the `afdata` CLI available, use it for deterministic checks:
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:
47
113
 
48
114
  ```bash
49
- afdata lint <file-or-stdin>
50
- afdata validate <file-or-stdin>
115
+ afdata lint payload.json
116
+ afdata validate events.jsonl
117
+ afdata format payload.json --output yaml
118
+ afdata skill validate skills/example-skill
51
119
  ```
52
120
 
53
121
  - Run `afdata lint` for ordinary JSON/JSONL, JSON Schema, or MCP input/output schemas.
54
122
  - Run `afdata validate` for AFDATA protocol events or finite event streams.
123
+ - Omit the input path to read stdin. `--output` accepts `json`, `yaml`, or
124
+ `plain`.
55
125
  - Treat findings as contract issues unless the owning tool intentionally documents a non-AFDATA field.
56
126
 
57
127
  ## Review checklist
@@ -148,15 +148,18 @@ def _prepare_target(target_fd: int, path: str | None) -> _PreparedTarget | None:
148
148
 
149
149
  def _open_append_secure(path: str) -> int:
150
150
  nofollow = getattr(os, "O_NOFOLLOW", 0)
151
+ # O_BINARY is 0 on POSIX; on Windows it stops the C runtime from translating
152
+ # redirected `\n` into `\r\n`, so the redirect stays byte-exact.
153
+ binary = getattr(os, "O_BINARY", 0)
151
154
  try:
152
155
  info = os.lstat(path)
153
156
  except FileNotFoundError:
154
- return os.open(path, os.O_CREAT | os.O_EXCL | os.O_WRONLY | os.O_APPEND | nofollow, 0o600)
157
+ return os.open(path, os.O_CREAT | os.O_EXCL | os.O_WRONLY | os.O_APPEND | nofollow | binary, 0o600)
155
158
  if stat.S_ISLNK(info.st_mode):
156
159
  raise OSError("stream redirection target must not be a symbolic link")
157
160
  if not stat.S_ISREG(info.st_mode):
158
161
  raise OSError("stream redirection target must be a regular file")
159
- return os.open(path, os.O_WRONLY | os.O_APPEND | nofollow)
162
+ return os.open(path, os.O_WRONLY | os.O_APPEND | nofollow | binary)
160
163
 
161
164
 
162
165
  def _close_prepared(target: _PreparedTarget | None) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-first-data
3
- Version: 0.17.2
3
+ Version: 0.17.3
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agent-first-data"
3
- version = "0.17.2"
3
+ version = "0.17.3"
4
4
  description = "A naming convention that lets AI agents understand your data without being told what it means."
5
5
  license = "MIT"
6
6
  readme = "README.md"
@@ -250,7 +250,7 @@ def test_codex_workspace_scope_uses_codex_skills_dir():
250
250
  targets = _resolve_targets(spec(), opts)
251
251
  assert [t.agent for t in targets] == [SkillAgent.CODEX]
252
252
  assert targets[0].scope is SkillScope.WORKSPACE
253
- assert str(targets[0].skills_dir).endswith(".codex/skills")
253
+ assert targets[0].skills_dir.parts[-2:] == (".codex", "skills")
254
254
 
255
255
 
256
256
  def test_hermes_workspace_scope_uses_hermes_skills_dir():
@@ -258,7 +258,7 @@ def test_hermes_workspace_scope_uses_hermes_skills_dir():
258
258
  targets = _resolve_targets(spec(), opts)
259
259
  assert [t.agent for t in targets] == [SkillAgent.HERMES]
260
260
  assert targets[0].scope is SkillScope.WORKSPACE
261
- assert str(targets[0].skills_dir).endswith(".hermes/skills")
261
+ assert targets[0].skills_dir.parts[-2:] == (".hermes", "skills")
262
262
 
263
263
 
264
264
  def test_skills_dir_requires_single_agent():
@@ -46,7 +46,9 @@ def test_install_redirects_and_restores_output(tmp_path) -> None:
46
46
 
47
47
  assert stdout_path.read_bytes() == b"existing stdout\nstdout bytes\n"
48
48
  assert stderr_path.read_bytes() == b"stderr bytes\n"
49
- assert (stderr_path.stat().st_mode & 0o777) == 0o600
49
+ if os.name == "posix":
50
+ # Windows has no Unix permission bits; the 0o600 mode is ignored there.
51
+ assert (stderr_path.stat().st_mode & 0o777) == 0o600
50
52
 
51
53
 
52
54
  def test_install_rejects_symlink_targets(tmp_path) -> None: