Skip to content

Commit 843d693

Browse files
Release prep v2.3.0: pyproject, README, CI, changelog
- pyproject: version 2.2.2 -> 2.3.0 (was out of sync with __init__.py), Documentation URL -> https://gcformat.com/ (was a stale github.io link), Development Status Beta -> Production/Stable, description mentions multi-turn delta, keywords += delta/multi-turn/agents. - README: document the new generic-profile delta (§10a) and the re-anchor session helper (§10a.8) with examples; add them to the API and Types tables. These were the headline v2.3.0 features and were previously undocumented. - CI: fix the conformance step that never actually ran (the runner resolves a sibling ../gcf, but CI checked the fixtures repo out to a subdir). Now checks out gcf-python and gcf as siblings with working-directory: gcf-python. - CHANGELOG: finalize v2.3.0 date.
1 parent 0fc2581 commit 843d693

4 files changed

Lines changed: 61 additions & 9 deletions

File tree

.github/workflows/ci.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ jobs:
1313
matrix:
1414
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
1515
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.
1618
- uses: actions/checkout@v4
19+
with:
20+
path: gcf-python
1721
- uses: actions/checkout@v4
1822
with:
1923
repository: blackwell-systems/gcf
@@ -22,9 +26,13 @@ jobs:
2226
with:
2327
python-version: ${{ matrix.python-version }}
2428
- run: pip install -e ".[dev]" || pip install -e . && pip install pytest
29+
working-directory: gcf-python
2530
- name: Unit tests
2631
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)
2834
run: pytest tests/test_conformance_v2.py -v
35+
working-directory: gcf-python
2936
- name: Property-based round-trip (100K random + 100K adversarial)
3037
run: pytest tests/test_roundtrip_v2.py -v
38+
working-directory: gcf-python

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Changelog
22

3-
## v2.3.0 (unreleased)
3+
## v2.3.0 (2026-07-12)
44

55
### Generic-profile delta encoding (SPEC §10a)
66

README.md

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,44 @@ Output:
157157

158158
Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows. Nested dicts use `## key` section headers.
159159

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+
160198
## API
161199

162200
| Function | Description |
@@ -165,7 +203,11 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
165203
| `encode_generic(data: Any) -> str` | Encode any value to GCF tabular format |
166204
| `decode(input_text: str) -> Payload` | Parse GCF text back to a Payload |
167205
| `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) |
169211
| `Session()` | Create a new session tracker (thread-safe) |
170212

171213
## Types
@@ -175,7 +217,9 @@ Works on dicts, lists, and primitives. Lists of uniform dicts get tabular rows.
175217
| `Payload` | Full GCF payload: tool, budget, symbols, edges, pack root |
176218
| `Symbol` | Graph node: qualified name, kind, score, provenance, distance |
177219
| `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) |
179223
| `Session` | Thread-safe tracker for multi-call deduplication |
180224
| `KIND_ABBREV` / `KIND_EXPAND` | Bidirectional kind abbreviation dicts |
181225

pyproject.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "gcf-python"
7-
version = "2.2.2"
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."
99
readme = "README.md"
1010
license = {text = "MIT"}
1111
requires-python = ">=3.9"
1212
authors = [
1313
{ name = "Blackwell Systems" },
1414
]
15-
keywords = ["gcf", "llm", "mcp", "token-efficient", "graph", "wire-format"]
15+
keywords = ["gcf", "llm", "mcp", "token-efficient", "graph", "wire-format", "delta", "multi-turn", "agents"]
1616
classifiers = [
17-
"Development Status :: 4 - Beta",
17+
"Development Status :: 5 - Production/Stable",
1818
"Intended Audience :: Developers",
1919
"License :: OSI Approved :: MIT License",
2020
"Programming Language :: Python :: 3",
@@ -32,7 +32,7 @@ gcf = "gcf.cli:main"
3232

3333
[project.urls]
3434
Homepage = "https://github.com/blackwell-systems/gcf-python"
35-
Documentation = "https://blackwell-systems.github.io/gcf/"
35+
Documentation = "https://gcformat.com/"
3636
Specification = "https://github.com/blackwell-systems/gcf"
3737

3838
[tool.hatch.build.targets.wheel]

0 commit comments

Comments
 (0)