Skip to content

Releases: Fiyy/gridlang

v1.0.0 — Stability marker (v2.0 roadmap complete)

04 Jun 08:05

Choose a tag to compare

v1.0.0 — Stability marker

🎉 The v2.0 roadmap is complete. v1.0 doesn't add new features — it freezes the public Python and HTTP APIs as a stable contract through the v1.x line.

Stabilized surfaces

Surface Examples
Python API parse, execute, render, apply_cell_edit, bundle_doc, CrdtDocument, CollabSession
HTTP API /api/render, /api/save, /api/cell-edit, /api/collab/*
File format section delimiter grammar, A1 refs, @source directives, chart: / format: / bind: DSL
CLI run, render, validate, info, import, export, serve, js-bundle

These surfaces follow Semantic Versioning — additive changes only until v2.0.

What's new in this release (housekeeping only)

  • CHANGELOG.md — full version history v0.2 → v1.0 in Keep a Changelog format
  • LICENSE — MIT, matching the pyproject.toml declaration
  • .github/workflows/test.yml — CI runs the 442-test suite on Python 3.9–3.12 (Ubuntu) + 3.12 (macOS), plus a CLI smoke-test over every .grid example and a js-bundle round-trip via Node
  • README badges — CI / license / Python-version / latest-release

No code in gridlang/ was touched in this commit; the 442 tests still pass unchanged.

The v0.2 → v1.0 journey

Version Theme
v0.2.0 (May 2025) Multi-sheet, 59 formulas, 9 charts, Excel I/O, live preview
v0.3.0 Chart & Format DSL
v0.4.0 Remote Data Sources (@source)
v0.5.0 Reactive Bindings (cell(), bind:)
v0.6.0 JavaScript Compute Engine
v0.7.0 JS Bundles & Extended df API (~25 methods)
v0.8.0 Collaborative editing (CRDT)
v1.0.0 Stability marker

By the numbers

  • 442 tests, 0 failures
  • 12 example .grid files
  • 21 SPEC sections covering format + every feature
  • 18 Python modules in gridlang/
  • ~250 lines of self-contained browser JS for collab

Get started:

pip install -e .
gridlang serve examples/12_collab.grid --collab --edit
# Open http://localhost:8080 in two browser tabs and edit cells live.

🤖 Generated with Claude Code

v0.8.0 — Collaborative Editing (CRDT)

04 Jun 03:46

Choose a tag to compare

v0.8.0 — Collaborative editing (CRDT)

The final item in the v2.0 roadmap (§15). Multiple browser tabs (or peers on the same network) can now edit the same .grid file at the same time; operations converge via a per-cell LWW CRDT keyed by Hybrid Logical Clock timestamps.

Try it

gridlang serve dashboard.grid --collab --edit
# Open http://localhost:8080 in two browser tabs.
# Edit a cell in tab A → within ~700ms the value appears (and flashes blue) in tab B.
# Edit the same cell in both tabs at once → the higher-HLC write wins on every replica.

Architecture (3 small modules, ~700 lines)

Module Role
gridlang.crdt HLC clocks + LWW per-cell Document + version vectors
gridlang.collab CollabSession — peers, persistence, sync
gridlang.collab_client Self-contained ~250-line browser JS

Wire protocol — JSON over HTTP

POST /api/collab/join     { peer_id? }            → { peer_id, site_id, ops, version }
POST /api/collab/leave    { peer_id }
POST /api/collab/op       { peer_id, cell, value, sheet? }  → { op, version }
POST /api/collab/poll     { peer_id, since: vv }  → { ops, version, peer_count }
GET  /api/collab/snapshot                          → { site_id, ops, version }
GET  /api/collab/stats                             → { cells, journal, peers, version }
GET  /api/collab/client.js                         → IIFE that joins + polls + applies

Version vector vv is {site_id: [wall_ms, logical]} — each peer summarizes "what I've seen from each replica" in O(sites) space.

Convergence guarantees (proven by tests/test_crdt.py)

  • Commutativityapply(a) ∘ apply(b) ≡ apply(b) ∘ apply(a)
  • Idempotence — applying the same op twice is a no-op
  • Random-permutation property — 10 random permutations of an op set yield byte-identical state on all replicas

What changed

  • Added gridlang/crdt.py, gridlang/collab.py, gridlang/collab_client.py
  • Extended gridlang/server.py with 7 collab endpoints + --collab flag
  • Added examples/12_collab.grid (multi-peer demo)
  • spec/SPEC.md §21 — full protocol, data model, convergence proof sketch, programmatic API
  • §15 marks the roadmap item DONE
  • README.md — collab section, updated CLI docs
  • 64 new tests; 442 total (was 378)

Backward compatibility

  • When --collab is off (the default), all /api/collab/* endpoints return 404. The single-user editor (gridlang serve --edit) is unchanged.
  • When on, the v0.5 contenteditable cells and bind: widgets keep working — they just commit through the CRDT layer instead of /api/cell-edit. The on-disk .grid file remains the source of truth, so gridlang run / render / exports always see the merged values.

Out of scope for v0.8 (planned for v0.9+)

  • Inserting / deleting rows or columns concurrently — would need an RGA layer beneath cell ops
  • Federation between independent servers — current implementation is single-server
  • Auth — protocol assumes peers on a trusted network

🎉 The v2.0 roadmap is now complete — multi-sheet (v0.2), Chart DSL (v0.3), Remote Data (v0.4), Reactive Bindings (v0.5), JavaScript Engine (v0.6), JS Bundles & Extended API (v0.7), and now Collaborative Editing (v0.8).

🤖 Generated with Claude Code

v0.7.0 — JS Bundles & Extended df API

03 Jun 18:35

Choose a tag to compare

Push the JS engine to its limit: standalone bundles + ~25 helper methods.

gridlang js-bundle — package a .grid file's data + compute layer into a single self-contained .js file:

gridlang js-bundle report.grid -o bundle.js     # Node bundle
gridlang js-bundle report.grid --browser ...    # Web Worker bundle
node bundle.js                                  # prints JSON

Expanded df API (8 → 25 methods):

  • Aggregations: count, variance, std, median, quantile, describe
  • Filtering: head, tail, slice, distinct, find, some, every, none
  • Sorting: sortBy({desc?}), groupBy, countBy
  • Reshaping: pluck, drop, rename, assign
  • Joins: join, leftJoin, concat
  • Conversion: toRecords, toCSV
  • Metadata: columns, shape, empty

All chainable — df.where(p).sortBy(c, {desc:true}).head(3).col("x").

JS source extraction — gridlang/js/{df_helpers,bridge_node,runtime_pipeline}.js are now plain files (no inline Python strings); shared by the in-process bridge and bundles.

378 tests. See spec/SPEC.md §20.

v0.6.0 — JavaScript Compute Engine

03 Jun 18:35

Choose a tag to compare

Author the compute layer in JavaScript by setting engine: javascript.

--- compute ---
function transform(df) {
  df.addColumn('Tax', r => r.Revenue * 0.2);
  return df;
}
  • Runs in a Node vm subprocess sandbox via JSON-over-stdio bridge
  • Curated globals: Math, JSON, Number, String, Array, Object, Date, Map, Set, Promise, Error
  • Blocked: require, process, fs, child_process, Buffer, setTimeout
  • --max-old-space-size=256, per-stage VM timeout, total wall-clock cap
  • df helpers: col, sum, mean, max, min, where, addColumn, columns, shape
  • Falls back gracefully via JsRuntimeUnavailable when Node missing
  • 48 new tests including sandbox bypass attempts

See spec/SPEC.md §19.

v0.5.0 — Reactive Bindings

03 Jun 18:35

Choose a tag to compare

Two-way binding between rendered preview and the .grid data section.

Inline cell binding via Jinja helper:

<td>{{ cell("B2") }}</td>            <!-- editable -->
<td>{{ cell("B2@sales") }}</td>      <!-- cross-sheet -->

Form-style bind: blocks:

bind: input
  cell: B2
  type: number

bind: select
  cell: A2
  options: North, South, East, West
  • POST /api/cell-edit accepts {cell: "B2", value, sheet, save}
  • apply_edit() rewrites only the target row — preserves comments, blank lines, @Directives, formulas in other cells
  • Header row (row 1) always read-only
  • 73 new tests including HTTP roundtrip via stdlib http client

See spec/SPEC.md §18.

v0.4.0 — Remote Data Sources

03 Jun 18:35

Choose a tag to compare

@Directives at the head of any data section pull CSV/JSON/xlsx from URLs or files; inline rows act as fallback.

--- data ---
@source: https://api/sales.json
@format: json
@select: data.records
@cache: 1h

# Fallback used when remote fails
Region,Total
North,100
  • file:// always allowed, http(s):// gated by --allow-remote
  • Content-addressed TTL cache (SHA1 of url+headers+format+select)
  • JSON @select supports a.b.c[0] dot-path drilldown
  • 35 new tests covering fetch, cache, fallback semantics

See spec/SPEC.md §17.

v0.3.0 — Chart & Format DSL

03 Jun 18:35

Choose a tag to compare

Declarative chart blocks (chart: bar / format: color_scale) inside the present layer.

  • 9 chart types accept references like B2:D4, agg.foo, Q1,Q2,Q3 (multi-series)
  • Cross-sheet refs: sales!Revenue, B2:D4@sales
  • A1 cell qualifier required for single-cell refs to avoid shadowing column names
  • 32 new tests, custom test runner (tests/_run_no_pytest.py) for pytest-free environments

See spec/SPEC.md §16 for the full grammar.