gcf-python 2.2.1__tar.gz → 2.3.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.
Files changed (39) hide show
  1. {gcf_python-2.2.1 → gcf_python-2.3.0}/.github/workflows/ci.yml +9 -1
  2. {gcf_python-2.2.1 → gcf_python-2.3.0}/CHANGELOG.md +29 -0
  3. {gcf_python-2.2.1 → gcf_python-2.3.0}/PKG-INFO +58 -10
  4. {gcf_python-2.2.1 → gcf_python-2.3.0}/README.md +53 -5
  5. {gcf_python-2.2.1 → gcf_python-2.3.0}/pyproject.toml +5 -5
  6. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/__init__.py +33 -1
  7. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/generic.py +11 -3
  8. gcf_python-2.3.0/src/gcf/generic_delta.py +487 -0
  9. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_conformance_v2.py +85 -0
  10. gcf_python-2.3.0/tests/test_generic_delta.py +141 -0
  11. gcf_python-2.3.0/tests/test_generic_delta_session.py +187 -0
  12. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_roundtrip_v2.py +74 -0
  13. gcf_python-2.3.0/uv.lock +8 -0
  14. {gcf_python-2.2.1 → gcf_python-2.3.0}/.github/FUNDING.yml +0 -0
  15. {gcf_python-2.2.1 → gcf_python-2.3.0}/.github/workflows/publish.yml +0 -0
  16. {gcf_python-2.2.1 → gcf_python-2.3.0}/.gitignore +0 -0
  17. {gcf_python-2.2.1 → gcf_python-2.3.0}/LICENSE +0 -0
  18. {gcf_python-2.2.1 → gcf_python-2.3.0}/assets/gcf-python-diagram.png +0 -0
  19. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/__main__.py +0 -0
  20. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/cli.py +0 -0
  21. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/constants.py +0 -0
  22. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/decode.py +0 -0
  23. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/decode_generic.py +0 -0
  24. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/delta.py +0 -0
  25. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/encode.py +0 -0
  26. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/scalar.py +0 -0
  27. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/session.py +0 -0
  28. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/stream.py +0 -0
  29. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/stream_generic.py +0 -0
  30. {gcf_python-2.2.1 → gcf_python-2.3.0}/src/gcf/types.py +0 -0
  31. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/__init__.py +0 -0
  32. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_decode.py +0 -0
  33. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_delta.py +0 -0
  34. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_encode.py +0 -0
  35. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_generic.py +0 -0
  36. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_roundtrip.py +0 -0
  37. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_session.py +0 -0
  38. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_stream.py +0 -0
  39. {gcf_python-2.2.1 → gcf_python-2.3.0}/tests/test_stream_generic.py +0 -0
@@ -13,7 +13,11 @@ jobs:
13
13
  matrix:
14
14
  python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
15
15
  steps:
16
+ # Check out gcf-python and the shared-fixtures gcf repo as SIBLINGS so the
17
+ # conformance runner's ../gcf/tests/conformance path resolves on CI.
16
18
  - uses: actions/checkout@v4
19
+ with:
20
+ path: gcf-python
17
21
  - uses: actions/checkout@v4
18
22
  with:
19
23
  repository: blackwell-systems/gcf
@@ -22,9 +26,13 @@ jobs:
22
26
  with:
23
27
  python-version: ${{ matrix.python-version }}
24
28
  - run: pip install -e ".[dev]" || pip install -e . && pip install pytest
29
+ working-directory: gcf-python
25
30
  - name: Unit tests
26
31
  run: pytest tests/ -v --ignore=tests/test_conformance_v2.py --ignore=tests/test_roundtrip_v2.py
27
- - name: Conformance tests (133 fixtures)
32
+ working-directory: gcf-python
33
+ - name: Conformance tests (shared fixtures)
28
34
  run: pytest tests/test_conformance_v2.py -v
35
+ working-directory: gcf-python
29
36
  - name: Property-based round-trip (100K random + 100K adversarial)
30
37
  run: pytest tests/test_roundtrip_v2.py -v
38
+ working-directory: gcf-python
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.3.0 (2026-07-12)
4
+
5
+ ### Generic-profile delta encoding (SPEC §10a)
6
+
7
+ - Full producer + consumer implementation of generic-profile delta, byte-for-byte interoperable with `gcf-go`:
8
+ - `GenericSet` (keyed record set), `GenericDeltaPayload`
9
+ - `generic_pack_root` (`gcf-pack-root-v1`, generic profile) with a purpose-built cell canonicalization decoupled from the wire cell encoder: collision-free (null/bool/number bare, strings always quoted) and record-safe. Fields and records sort by UTF-8 byte order to match Go's `sort.Strings`.
10
+ - `diff_generic_sets` (the blessed producer path; centralizes the keyed-diff invariants), `encode_generic_full`, `encode_generic_delta`
11
+ - `decode_generic_full`, `decode_generic_delta` (consumer wire parsing)
12
+ - `verify_generic_delta` (atomic apply + `new_root` verification)
13
+ - Re-anchor session helper (SPEC §10a.8): `GenericDeltaSession` (`current_full`, `next`) with `ReanchorPolicy` / `fixed_n(n)` / `size_guard()` cadence policies and `DEFAULT_REANCHOR_N = 15`. Producer-side sugar over the primitives; introduces no new wire syntax (every emission is exactly `encode_generic_full` / `encode_generic_delta` output). Re-anchor cadence is byte-for-byte identical to `gcf-go` (size guard uses UTF-8 byte length to match Go's `len(string)`), verified by the shared `generic-delta-session` conformance fixtures.
14
+ - Delta is opt-in and bilateral; the existing `encode_generic` path is unchanged (backward compatible).
15
+
16
+ ### Tests
17
+
18
+ - Unit suite mirroring `gcf-go`: self-proving round-trip (diff -> encode -> apply -> recomputed root), determinism / row-order invariance, no-type-collision canonicalization, every invariant/error path, full-payload wire round-trip, the complete server -> wire -> consumer end-to-end loop, and malformed-wire-fails-closed.
19
+ - Conformance runner support for `generic-pack-root`, `generic-delta`, `generic-delta-verify`, `generic-delta-decode` (12 shared fixtures); verified to produce identical pack roots and delta wire to `gcf-go`.
20
+ - Session helper suite (`test_generic_delta_session.py`) mirroring `gcf-go`: FixedN cadence pattern, size-guard triggering, schema-change forced full, FixedN(15)-over-30-turns count, and the load-bearing consumer-stays-in-sync check under both policies. Conformance runner support for `generic-delta-session` (3 shared fixtures: fixed-N, size-guard, schema-change).
21
+
22
+ ## v2.2.2 (2026-07-10)
23
+
24
+ ### Fixes
25
+
26
+ - **Losslessness (nested null):** a nested object that is null at an intermediate level (e.g. `{"meta": {"owner": None}}`) is no longer flattened. Previously its leaves encoded as absent (`~`) and unflattened to a missing key, silently dropping the null. Such fields now fall back to the attachment mechanism; a top-level `None` still flattens losslessly (emits `-`, reconstructs via the all-null rule). Enforced by the shared conformance fixtures `flatten/017`–`019`. Prototype pollution does not affect Python (dicts have no mutable prototype).
27
+
28
+ ### Tests
29
+
30
+ - `test_flatten_roundtrip`: aligned arrays whose shared fields are fixed-shape nested objects with a field or an intermediate nested level sometimes null/absent — the shape the prior scalar-only generator never produced, leaving the flatten/unflatten path unexercised. Verified to fail on the pre-fix encoder and pass on the fix.
31
+
3
32
  ## v2.2.1 (2026-06-23)
4
33
 
5
34
  ### Flatten Opt-Out
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gcf-python
3
- Version: 2.2.1
4
- Summary: The AI-native wire format for structured data. 50-92% fewer tokens than JSON. 100% comprehension on every frontier model. Zero dependencies.
3
+ Version: 2.3.0
4
+ Summary: The AI-native wire format for structured data. 50-92% fewer tokens than JSON, with multi-turn delta encoding for agent loops. 100% comprehension on every frontier model. Zero dependencies.
5
5
  Project-URL: Homepage, https://github.com/blackwell-systems/gcf-python
6
- Project-URL: Documentation, https://blackwell-systems.github.io/gcf/
6
+ Project-URL: Documentation, https://gcformat.com/
7
7
  Project-URL: Specification, https://github.com/blackwell-systems/gcf
8
8
  Author: Blackwell Systems
9
9
  License: MIT
10
10
  License-File: LICENSE
11
- Keywords: gcf,graph,llm,mcp,token-efficient,wire-format
12
- Classifier: Development Status :: 4 - Beta
11
+ Keywords: agents,delta,gcf,graph,llm,mcp,multi-turn,token-efficient,wire-format
12
+ Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Programming Language :: Python :: 3
@@ -32,7 +32,7 @@ Description-Content-Type: text/markdown
32
32
 
33
33
  Python implementation of [GCF](https://gcformat.com/) — the most token-efficient wire format for LLMs. A drop-in alternative to JSON and TOON for any structured data.
34
34
 
35
- **100% comprehension on every frontier model tested. 29% fewer tokens than TOON, 56% fewer than JSON across 16 datasets. 91.2% on structurally complex code graphs (vs TOON 68.2%, JSON 53.4%). 2,400+ LLM evaluations. Zero training.**
35
+ **100% comprehension on every frontier model tested. 29% fewer tokens than TOON, 56% fewer than JSON across 16 datasets. 91.2% on structurally complex code graphs (vs TOON 68.8%, JSON 54.1%). 2,400+ LLM evaluations. Zero training.**
36
36
 
37
37
  Docs: [gcformat.com](https://gcformat.com/) · [Playground](https://gcformat.com/playground.html) · [GCF vs TOON](https://gcformat.com/guide/vs-toon.html)
38
38
 
@@ -182,6 +182,44 @@ Output:
182
182
 
183
183
  Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows. Nested dicts use `## key` section headers.
184
184
 
185
+ ## Generic-Profile Delta (multi-turn)
186
+
187
+ In an agent loop the same keyed table gets re-queried turn after turn. Instead of re-sending the whole table each time, send only the changed rows (SPEC §10a):
188
+
189
+ ```python
190
+ from gcf import GenericSet, diff_generic_sets, encode_generic_delta, verify_generic_delta
191
+
192
+ base = GenericSet(key="id", fields=["id", "status"], rows=[
193
+ {"id": 1001, "status": "pending"},
194
+ {"id": 1002, "status": "shipped"},
195
+ ])
196
+ nxt = GenericSet(key="id", fields=["id", "status"], rows=[
197
+ {"id": 1001, "status": "shipped"}, # changed
198
+ {"id": 1003, "status": "pending"}, # added (1002 removed)
199
+ ])
200
+
201
+ d = diff_generic_sets(base, nxt)
202
+ wire = encode_generic_delta(d) # ## added / ## changed / ## removed
203
+ held = verify_generic_delta(base, d, d.new_root) # atomic apply + new_root verification
204
+ ```
205
+
206
+ Opt-in and bilateral, keyed on content-addressed pack roots. By the 5th overlapping call, ~97% fewer tokens than re-sending JSON.
207
+
208
+ ### Re-anchor session helper
209
+
210
+ `GenericDeltaSession` manages the delta/re-anchor cadence for you: each `next()` returns either a compact delta or, on its cadence, a full re-anchor (which re-grounds the consumer), updating its held base.
211
+
212
+ ```python
213
+ from gcf import GenericDeltaSession, fixed_n, size_guard
214
+
215
+ sess = GenericDeltaSession(base, tool="orders", policy=size_guard())
216
+ wire = sess.current_full() # transmit the base once to establish it
217
+ for snapshot in stream: # each turn's current GenericSet
218
+ wire, is_full = sess.next(snapshot) # a compact delta, or a periodic full re-anchor
219
+ ```
220
+
221
+ `fixed_n(15)` re-anchors every N turns; `size_guard()` (recommended) re-anchors once the cumulative delta reaches a full payload's size. It introduces no new wire syntax and the decoder stays cadence-agnostic, so a re-anchor is just the protocol's "full" outcome on a schedule.
222
+
185
223
  ## API
186
224
 
187
225
  | Function | Description |
@@ -190,7 +228,11 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
190
228
  | `encode_generic(data: Any) -> str` | Encode any value to GCF tabular format |
191
229
  | `decode(input_text: str) -> Payload` | Parse GCF text back to a Payload |
192
230
  | `encode_with_session(p: Payload, s: Session) -> str` | Encode with session deduplication |
193
- | `encode_delta(d: DeltaPayload) -> str` | Encode a delta (added/removed only) |
231
+ | `encode_delta(d: DeltaPayload) -> str` | Encode a graph delta (added/removed only) |
232
+ | `diff_generic_sets(base, next) -> GenericDeltaPayload` | Diff two keyed record sets (generic profile) |
233
+ | `encode_generic_delta(d) -> str` / `decode_generic_delta(s)` | Generic-profile delta wire (§10a) |
234
+ | `verify_generic_delta(base, d, root) -> GenericSet` | Atomic apply + `new_root` verification |
235
+ | `GenericDeltaSession(base, tool, policy)` | Producer-side re-anchor cadence helper (§10a.8) |
194
236
  | `Session()` | Create a new session tracker (thread-safe) |
195
237
 
196
238
  ## Types
@@ -200,7 +242,9 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
200
242
  | `Payload` | Full GCF payload: tool, budget, symbols, edges, pack root |
201
243
  | `Symbol` | Graph node: qualified name, kind, score, provenance, distance |
202
244
  | `Edge` | Directed relationship: source, target, edge type |
203
- | `DeltaPayload` | Diff between two packs: added/removed symbols and edges |
245
+ | `DeltaPayload` | Diff between two graph packs: added/removed symbols and edges |
246
+ | `GenericSet` / `GenericDeltaPayload` | Keyed record set and its generic-profile diff (§10a) |
247
+ | `GenericDeltaSession` | Stateful producer that schedules delta vs full re-anchor (§10a.8) |
204
248
  | `Session` | Thread-safe tracker for multi-call deduplication |
205
249
  | `KIND_ABBREV` / `KIND_EXPAND` | Bidirectional kind abbreviation dicts |
206
250
 
@@ -210,7 +254,7 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
210
254
 
211
255
  | | GCF | TOON | JSON |
212
256
  |---|---|---|---|
213
- | **Comprehension** (23 runs, 10 models) | **91.2%** | 68.2% | 53.4% |
257
+ | **Comprehension** (23 runs, 10 models) | **91.2%** | 68.8% | 54.1% |
214
258
  | **Generation** (28 runs, 9 models) | **5/5** | 1.0/5 | 5.0/5 |
215
259
  | **Input tokens** (500 symbols) | **11,090** | 16,378 | 53,341 |
216
260
  | **Output tokens** (100 symbols) | **5,976** | 8,937 | 16,121 |
@@ -236,7 +280,11 @@ GCF wins 15/16 datasets on the expanded [token efficiency benchmark](https://git
236
280
 
237
281
  **Zero runtime dependencies. Permanently.** All six implementations depend only on their language's standard library. No transitive dependencies. No supply chain risk. This is a permanent commitment: GCF will never take on external runtime dependencies. MIT licensed. All implementations support both generic profile (`encodeGeneric`) and graph profile (`encode`). CLI included in all 6 languages.
238
282
 
239
- **Specification:** [SPEC v3.2 Stable](https://github.com/blackwell-systems/gcf/blob/main/SPEC.md) with 173 conformance fixtures, 43,000,000,000+ lossless round-trips verified across 5 formats and 6 languages. All implementations at v2.2.0+ (Go v1.3.0). Cross-language 6x6 matrix verified.
283
+ **Specification:** [SPEC v3.2 Stable](https://github.com/blackwell-systems/gcf/blob/main/SPEC.md) with 174 conformance fixtures, 43,000,000,000+ lossless round-trips verified across 5 formats and 6 languages. All implementations at v2.2.1+ (Go v1.3.1). Cross-language 6x6 matrix verified.
284
+
285
+ ## Adopted by
286
+
287
+ [Chrome DevTools MCP](https://github.com/ChromeDevTools/chrome-devtools-mcp) (46K stars, Google Chrome DevTools team) · [Speakeasy](https://speakeasy.com) (API tooling, customers include Google, Verizon, Mistral AI, DocuSign, Vercel) · [OmniRoute](https://omniroute.online) (6.1K stars) · [NetClaw](https://github.com/automateyournetwork/netclaw) (556 stars) · [ctx](https://github.com/stevesolun/ctx) (510 stars) · [NeuroNest](https://neuronest.cc) · [Open Data Products SDK](https://opendataproducts.org/sdk/) (Linux Foundation) · [Raycast](https://raycast.com/blackwell-systems/json-to-gcf-converter) · [and more](https://gcformat.com/ecosystem/adopters.html)
240
288
 
241
289
  ## License
242
290
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  Python implementation of [GCF](https://gcformat.com/) — the most token-efficient wire format for LLMs. A drop-in alternative to JSON and TOON for any structured data.
9
9
 
10
- **100% comprehension on every frontier model tested. 29% fewer tokens than TOON, 56% fewer than JSON across 16 datasets. 91.2% on structurally complex code graphs (vs TOON 68.2%, JSON 53.4%). 2,400+ LLM evaluations. Zero training.**
10
+ **100% comprehension on every frontier model tested. 29% fewer tokens than TOON, 56% fewer than JSON across 16 datasets. 91.2% on structurally complex code graphs (vs TOON 68.8%, JSON 54.1%). 2,400+ LLM evaluations. Zero training.**
11
11
 
12
12
  Docs: [gcformat.com](https://gcformat.com/) · [Playground](https://gcformat.com/playground.html) · [GCF vs TOON](https://gcformat.com/guide/vs-toon.html)
13
13
 
@@ -157,6 +157,44 @@ Output:
157
157
 
158
158
  Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows. Nested dicts use `## key` section headers.
159
159
 
160
+ ## Generic-Profile Delta (multi-turn)
161
+
162
+ In an agent loop the same keyed table gets re-queried turn after turn. Instead of re-sending the whole table each time, send only the changed rows (SPEC §10a):
163
+
164
+ ```python
165
+ from gcf import GenericSet, diff_generic_sets, encode_generic_delta, verify_generic_delta
166
+
167
+ base = GenericSet(key="id", fields=["id", "status"], rows=[
168
+ {"id": 1001, "status": "pending"},
169
+ {"id": 1002, "status": "shipped"},
170
+ ])
171
+ nxt = GenericSet(key="id", fields=["id", "status"], rows=[
172
+ {"id": 1001, "status": "shipped"}, # changed
173
+ {"id": 1003, "status": "pending"}, # added (1002 removed)
174
+ ])
175
+
176
+ d = diff_generic_sets(base, nxt)
177
+ wire = encode_generic_delta(d) # ## added / ## changed / ## removed
178
+ held = verify_generic_delta(base, d, d.new_root) # atomic apply + new_root verification
179
+ ```
180
+
181
+ Opt-in and bilateral, keyed on content-addressed pack roots. By the 5th overlapping call, ~97% fewer tokens than re-sending JSON.
182
+
183
+ ### Re-anchor session helper
184
+
185
+ `GenericDeltaSession` manages the delta/re-anchor cadence for you: each `next()` returns either a compact delta or, on its cadence, a full re-anchor (which re-grounds the consumer), updating its held base.
186
+
187
+ ```python
188
+ from gcf import GenericDeltaSession, fixed_n, size_guard
189
+
190
+ sess = GenericDeltaSession(base, tool="orders", policy=size_guard())
191
+ wire = sess.current_full() # transmit the base once to establish it
192
+ for snapshot in stream: # each turn's current GenericSet
193
+ wire, is_full = sess.next(snapshot) # a compact delta, or a periodic full re-anchor
194
+ ```
195
+
196
+ `fixed_n(15)` re-anchors every N turns; `size_guard()` (recommended) re-anchors once the cumulative delta reaches a full payload's size. It introduces no new wire syntax and the decoder stays cadence-agnostic, so a re-anchor is just the protocol's "full" outcome on a schedule.
197
+
160
198
  ## API
161
199
 
162
200
  | Function | Description |
@@ -165,7 +203,11 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
165
203
  | `encode_generic(data: Any) -> str` | Encode any value to GCF tabular format |
166
204
  | `decode(input_text: str) -> Payload` | Parse GCF text back to a Payload |
167
205
  | `encode_with_session(p: Payload, s: Session) -> str` | Encode with session deduplication |
168
- | `encode_delta(d: DeltaPayload) -> str` | Encode a delta (added/removed only) |
206
+ | `encode_delta(d: DeltaPayload) -> str` | Encode a graph delta (added/removed only) |
207
+ | `diff_generic_sets(base, next) -> GenericDeltaPayload` | Diff two keyed record sets (generic profile) |
208
+ | `encode_generic_delta(d) -> str` / `decode_generic_delta(s)` | Generic-profile delta wire (§10a) |
209
+ | `verify_generic_delta(base, d, root) -> GenericSet` | Atomic apply + `new_root` verification |
210
+ | `GenericDeltaSession(base, tool, policy)` | Producer-side re-anchor cadence helper (§10a.8) |
169
211
  | `Session()` | Create a new session tracker (thread-safe) |
170
212
 
171
213
  ## Types
@@ -175,7 +217,9 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
175
217
  | `Payload` | Full GCF payload: tool, budget, symbols, edges, pack root |
176
218
  | `Symbol` | Graph node: qualified name, kind, score, provenance, distance |
177
219
  | `Edge` | Directed relationship: source, target, edge type |
178
- | `DeltaPayload` | Diff between two packs: added/removed symbols and edges |
220
+ | `DeltaPayload` | Diff between two graph packs: added/removed symbols and edges |
221
+ | `GenericSet` / `GenericDeltaPayload` | Keyed record set and its generic-profile diff (§10a) |
222
+ | `GenericDeltaSession` | Stateful producer that schedules delta vs full re-anchor (§10a.8) |
179
223
  | `Session` | Thread-safe tracker for multi-call deduplication |
180
224
  | `KIND_ABBREV` / `KIND_EXPAND` | Bidirectional kind abbreviation dicts |
181
225
 
@@ -185,7 +229,7 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
185
229
 
186
230
  | | GCF | TOON | JSON |
187
231
  |---|---|---|---|
188
- | **Comprehension** (23 runs, 10 models) | **91.2%** | 68.2% | 53.4% |
232
+ | **Comprehension** (23 runs, 10 models) | **91.2%** | 68.8% | 54.1% |
189
233
  | **Generation** (28 runs, 9 models) | **5/5** | 1.0/5 | 5.0/5 |
190
234
  | **Input tokens** (500 symbols) | **11,090** | 16,378 | 53,341 |
191
235
  | **Output tokens** (100 symbols) | **5,976** | 8,937 | 16,121 |
@@ -211,7 +255,11 @@ GCF wins 15/16 datasets on the expanded [token efficiency benchmark](https://git
211
255
 
212
256
  **Zero runtime dependencies. Permanently.** All six implementations depend only on their language's standard library. No transitive dependencies. No supply chain risk. This is a permanent commitment: GCF will never take on external runtime dependencies. MIT licensed. All implementations support both generic profile (`encodeGeneric`) and graph profile (`encode`). CLI included in all 6 languages.
213
257
 
214
- **Specification:** [SPEC v3.2 Stable](https://github.com/blackwell-systems/gcf/blob/main/SPEC.md) with 173 conformance fixtures, 43,000,000,000+ lossless round-trips verified across 5 formats and 6 languages. All implementations at v2.2.0+ (Go v1.3.0). Cross-language 6x6 matrix verified.
258
+ **Specification:** [SPEC v3.2 Stable](https://github.com/blackwell-systems/gcf/blob/main/SPEC.md) with 174 conformance fixtures, 43,000,000,000+ lossless round-trips verified across 5 formats and 6 languages. All implementations at v2.2.1+ (Go v1.3.1). Cross-language 6x6 matrix verified.
259
+
260
+ ## Adopted by
261
+
262
+ [Chrome DevTools MCP](https://github.com/ChromeDevTools/chrome-devtools-mcp) (46K stars, Google Chrome DevTools team) · [Speakeasy](https://speakeasy.com) (API tooling, customers include Google, Verizon, Mistral AI, DocuSign, Vercel) · [OmniRoute](https://omniroute.online) (6.1K stars) · [NetClaw](https://github.com/automateyournetwork/netclaw) (556 stars) · [ctx](https://github.com/stevesolun/ctx) (510 stars) · [NeuroNest](https://neuronest.cc) · [Open Data Products SDK](https://opendataproducts.org/sdk/) (Linux Foundation) · [Raycast](https://raycast.com/blackwell-systems/json-to-gcf-converter) · [and more](https://gcformat.com/ecosystem/adopters.html)
215
263
 
216
264
  ## License
217
265
 
@@ -4,17 +4,17 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "gcf-python"
7
- version = "2.2.1"
8
- description = "The AI-native wire format for structured data. 50-92% fewer tokens than JSON. 100% comprehension on every frontier model. Zero dependencies."
7
+ version = "2.3.0"
8
+ description = "The AI-native wire format for structured data. 50-92% fewer tokens than JSON, with multi-turn delta encoding for agent loops. 100% comprehension on every frontier model. Zero dependencies."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
11
11
  requires-python = ">=3.9"
12
12
  authors = [
13
13
  { name = "Blackwell Systems" },
14
14
  ]
15
- keywords = ["gcf", "llm", "mcp", "token-efficient", "graph", "wire-format"]
15
+ keywords = ["gcf", "llm", "mcp", "token-efficient", "graph", "wire-format", "delta", "multi-turn", "agents"]
16
16
  classifiers = [
17
- "Development Status :: 4 - Beta",
17
+ "Development Status :: 5 - Production/Stable",
18
18
  "Intended Audience :: Developers",
19
19
  "License :: OSI Approved :: MIT License",
20
20
  "Programming Language :: Python :: 3",
@@ -32,7 +32,7 @@ gcf = "gcf.cli:main"
32
32
 
33
33
  [project.urls]
34
34
  Homepage = "https://github.com/blackwell-systems/gcf-python"
35
- Documentation = "https://blackwell-systems.github.io/gcf/"
35
+ Documentation = "https://gcformat.com/"
36
36
  Specification = "https://github.com/blackwell-systems/gcf"
37
37
 
38
38
  [tool.hatch.build.targets.wheel]
@@ -39,6 +39,23 @@ from .decode import DecodeError, decode
39
39
  from .delta import encode_delta
40
40
  from .encode import encode
41
41
  from .generic import encode_generic, GenericOptions
42
+ from .generic_delta import (
43
+ GenericSet,
44
+ GenericDeltaPayload,
45
+ generic_pack_root,
46
+ diff_generic_sets,
47
+ encode_generic_full,
48
+ encode_generic_delta,
49
+ decode_generic_full,
50
+ decode_generic_delta,
51
+ verify_generic_delta,
52
+ GenericDeltaSession,
53
+ ReanchorPolicy,
54
+ ReanchorMode,
55
+ fixed_n,
56
+ size_guard,
57
+ DEFAULT_REANCHOR_N,
58
+ )
42
59
  from .session import Session, encode_with_session
43
60
  from .decode_generic import decode_generic
44
61
  from .stream import StreamEncoder
@@ -64,6 +81,21 @@ __all__ = [
64
81
  "encode_generic",
65
82
  "GenericOptions",
66
83
  "encode_with_session",
84
+ "GenericSet",
85
+ "GenericDeltaPayload",
86
+ "generic_pack_root",
87
+ "diff_generic_sets",
88
+ "encode_generic_full",
89
+ "encode_generic_delta",
90
+ "decode_generic_full",
91
+ "decode_generic_delta",
92
+ "verify_generic_delta",
93
+ "GenericDeltaSession",
94
+ "ReanchorPolicy",
95
+ "ReanchorMode",
96
+ "fixed_n",
97
+ "size_guard",
98
+ "DEFAULT_REANCHOR_N",
67
99
  ]
68
100
 
69
- __version__ = "1.0.0"
101
+ __version__ = "2.3.0"
@@ -14,8 +14,8 @@ class GenericOptions:
14
14
  no_flatten: bool = False
15
15
  """When True, disables promotion of fixed-shape nested objects to path
16
16
  columns (e.g. "customer>name"). Nested objects use attachment syntax
17
- instead. Set when targeting open-weight models that show lower
18
- comprehension on flattened encoding."""
17
+ instead. Open-weight models currently comprehend the expanded form
18
+ better; this gap is expected to close."""
19
19
 
20
20
 
21
21
  def encode_generic(data: Any, opts: GenericOptions | None = None) -> str:
@@ -171,7 +171,15 @@ def _analyze_flattenable(
171
171
  canonical_shape: dict[str, str] | None = None # key -> "scalar" | "nested"
172
172
 
173
173
  for item in arr:
174
- if field_name not in item or item[field_name] is None:
174
+ if field_name not in item:
175
+ continue
176
+ # A nested (non-top-level) null cannot be flattened losslessly: its leaves
177
+ # would encode as absent ("~") and unflatten back to a missing key, not None.
178
+ # Bail to the attachment path. A top-level None is fine (emits "-" and
179
+ # reconstructs via the all-null rule), so just skip the row from shape analysis.
180
+ if item[field_name] is None:
181
+ if parent_path != "":
182
+ return None
175
183
  continue
176
184
  v = item[field_name]
177
185
  if not isinstance(v, dict):