Skip to content

Commit a49ecad

Browse files
hyperpolymathclaude
andcommitted
docs: add UNIFIED-ZIG-API-STACK.adoc playbook
The authoritative reference for the hyperpolymath unified-zig-api stack, replacing the retired haxadeca-v-api / unified-v-api. Points at proven/ (Idris2 core) + zig-api/ (Idris2 ABI + Zig runtime + C adaptor) as the canonical four-layer foundation that every Zig-edge repo consumes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 203979f commit a49ecad

1 file changed

Lines changed: 345 additions & 0 deletions

File tree

UNIFIED-ZIG-API-STACK.adoc

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
// Copyright (c) 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
3+
// (MPL-2.0 is the automatic legal fallback until PMPL is formally recognised)
4+
= Unified Zig API Stack — Authoritative Playbook
5+
:toc:
6+
:toc-placement: preamble
7+
:doctype: article
8+
9+
The canonical reference for every Zig-edge repo wiring into the
10+
hyperpolymath API stack. Read this before designing or wiring any
11+
Zig-facing service boundary.
12+
13+
== TL;DR
14+
15+
The unified-zig-api stack replaces the retired haxadeca-v-api / unified-v-api /
16+
v-grpc / v-rest / v-zig-ffi / v-idris-abi family. It is organised as four
17+
vertically-stacked layers:
18+
19+
[none]
20+
- *Layer 1 — Idris2 core* (`verification-ecosystem/proven/`): formally verified
21+
primitive operations; the ultimate source of trust.
22+
- *Layer 2 — Idris2 ABI* (`developer-ecosystem/zig-api/src/ZigApi/ABI/`): dependent-type
23+
proofs of the C ABI surface — tag round-trips, safe-path soundness, injectivity,
24+
memory layout.
25+
- *Layer 3 — Zig runtime* (`developer-ecosystem/zig-api/ffi/zig/src/`): C-ABI
26+
implementations of core, process, gnosis, and connector subsystems;
27+
exports the `uapi_*` symbol set.
28+
- *Layer 4 — C adaptor* (`developer-ecosystem/zig-api/generated/abi/zig_api.h`):
29+
auto-generated from the Idris2 ABI; consumed by any language that speaks C FFI.
30+
31+
Edge repos consume from this stack only. Never re-roll equivalent functionality
32+
inline.
33+
34+
== The Four Layers
35+
36+
=== Layer 1 — Idris2 core (`verification-ecosystem/proven/`)
37+
38+
*What it is.* A formally verified safety library: 104 modules in
39+
`src/Proven/` written with `%default total`, zero `believe_me`, zero
40+
`assert_total`. Every function is proved to terminate, cover all cases, and
41+
return a value — no runtime exceptions possible.
42+
43+
*Canonical entry points for consumers.*
44+
45+
[cols="1,3"]
46+
|===
47+
| Path | Purpose
48+
49+
| `core-only.ipkg`
50+
| Minimal package — import only the Idris2 proofs, no FFI dependency.
51+
Preferred when you need proof witnesses in your own Idris2 ABI layer.
52+
53+
| `api/`
54+
| High-level module surface for direct Idris2 consumers.
55+
56+
| `bindings/`
57+
| Language-specific thin wrappers (18 complete, 102 scaffolded).
58+
C, Rust, Python, ReScript bindings are production-ready;
59+
others are research-stage.
60+
61+
| `ffi/zig/src/main.zig`
62+
| Zig bridge: wraps Idris2 RefC output, exposes `proven_ffi_*` C symbols.
63+
|===
64+
65+
*CRG grade:* C (Beta) — core proven, Rust/Python/C bindings tested; 102
66+
targets scaffolded. Never reimplement logic in bindings; call Zig FFI only.
67+
68+
=== Layer 2 — Idris2 ABI (`developer-ecosystem/zig-api/src/ZigApi/ABI/`)
69+
70+
*What it is.* Dependent-type proofs of the C ABI surface shared with the Zig
71+
runtime. These proofs run at compile time; any ABI drift is a type error.
72+
73+
*Modules present.*
74+
75+
[cols="1,3"]
76+
|===
77+
| File | Content
78+
79+
| `Types.idr`
80+
| `Platform`, `Result` codes (11 variants), `Handle`, `Slot`, `ValidSlot`,
81+
platform pointer-width claims.
82+
83+
| `Http.idr`
84+
| `Method` (7 variants), `ServerState` (4 variants), `HealthStatus`,
85+
`RouteDescriptor`. Includes `methodTag`, `methodFromTag`, round-trip proofs.
86+
87+
| `Process.idr`
88+
| `IsSafePath` structural proof, `ExecResult`, `GnosisRenderCmd`.
89+
A `GnosisRenderCmd` cannot be constructed for an unsafe path without
90+
discharging the `IsSafePath` proof — path safety is mandatory, not advisory.
91+
92+
| `Connector.idr`
93+
| `ServiceId` (11 variants, 0–10), `ConnectorState` (6 variants),
94+
`GrooveManifest`. `serviceIdTag` + `serviceIdFromTag` with round-trip proof.
95+
96+
| `Layout.idr`
97+
| Machine-checked memory layout claims: tag-count bounds (all enums fit in u8),
98+
pool/sentinel bounds (capacity 64, sentinel 255, 64 < 255),
99+
`@sizeOf` claims (handle = 8 bytes, slot = 1 byte).
100+
101+
| `Proofs.idr`
102+
| Cross-cutting proofs: slot validity (sentinel 255 cannot build `ValidSlot`),
103+
round-trip completeness across all five enum types, `SafePath` soundness
104+
(empty allowlist denies; head-match accepts), health status contract
105+
(200/503 codes, distinctness, 5xx range).
106+
107+
| `Foreign.idr`
108+
| `%foreign` declarations for every `uapi_*` symbol in the Zig runtime,
109+
plus safe `IO` wrappers. This is the Idris2 entry point for consumers.
110+
|===
111+
112+
*Package file:* `zig-api/zig-api.ipkg` — includes all seven ABI modules.
113+
114+
=== Layer 3 — Zig runtime (`developer-ecosystem/zig-api/ffi/zig/src/`)
115+
116+
*What it is.* Native C-ABI implementation of the API surface. Built with
117+
Zig 0.15.2. Produces `libzig_api.so` (shared) and `libzig_api.a` (static).
118+
119+
*Modules.*
120+
121+
[cols="1,3"]
122+
|===
123+
| Module | Responsibility
124+
125+
| `lib.zig`
126+
| Root entry point. Re-exports all `uapi_*` symbols. Provides the three
127+
lifecycle functions: `uapi_init`, `uapi_teardown`, `uapi_version`.
128+
129+
| `core.zig`
130+
| `Result` enum (mirrors `ZigApi.ABI.Types`), thread-local error storage,
131+
`Pool(T, N)` generic with mutex for fixed-capacity slot management.
132+
133+
| `process.zig`
134+
| Safe-path validation (allowlist prefix match), `runProcess`,
135+
`runGnosis` (shells out to the `gnosis` binary on `$PATH`).
136+
137+
| `gnosis.zig`
138+
| HTTP/1.1 server pool. Replaces v-grpc + v-rest. Handles `/render`,
139+
`/context`, `/health`, `/`, and gRPC-style `/gnosis.GnosisService/*` paths.
140+
`uapi_gnosis_{create,start,stop,destroy,state,health}`.
141+
142+
| `connector.zig`
143+
| 64-slot HTTP connector pool for 11 hyperpolymath services.
144+
`uapi_connector_{create,health,call,destroy,state}`.
145+
`uapi_connector_call` is the universal request dispatcher.
146+
|===
147+
148+
*Build:* `just build` from `zig-api/`. Recipes: `build`, `test`,
149+
`check-abi`, `test-integration`.
150+
151+
*Current version:* 0.15.2 (matches Zig toolchain; see `ffi/zig/build.zig`).
152+
153+
=== Layer 4 — C adaptor (`developer-ecosystem/zig-api/generated/abi/zig_api.h`)
154+
155+
The machine-readable contract between the Zig runtime and every non-Idris2
156+
consumer. Auto-generated from the Idris2 ABI. *Never edit by hand.*
157+
158+
Exposes: lifecycle (`uapi_init`, `uapi_teardown`, `uapi_version`), all
159+
`UAPI_OK`/`UAPI_ERR_*`/`UAPI_SERVER_*`/`UAPI_CONNECTOR_*`/`UAPI_SERVICE_*`/
160+
`UAPI_METHOD_*` constants, and the full `uapi_gnosis_*` and
161+
`uapi_connector_*` function set.
162+
163+
When the Idris2 ABI changes, the header must be regenerated — not patched
164+
manually. The regeneration pipeline is currently manual (see §10).
165+
166+
== How to Consume
167+
168+
=== From Idris2
169+
170+
Import `ZigApi.ABI.Foreign` (which re-exports all seven ABI modules).
171+
Link against `libzig_api` at build time via the `zig-api.ipkg` package.
172+
173+
[source,idris]
174+
----
175+
import ZigApi.ABI.Foreign
176+
177+
main : IO ()
178+
main = do
179+
Ok <- uapiInit | _ => putStrLn "init failed"
180+
h <- gnosisCreate 8091
181+
Ok <- gnosisStart h | _ => putStrLn "start failed"
182+
-- use the server
183+
gnosisStop h
184+
gnosisDestroy h
185+
uapiTeardown
186+
----
187+
188+
=== From another Zig project
189+
190+
Option A — link the shared library and `@cImport` the header:
191+
192+
[source,zig]
193+
----
194+
const c = @cImport(@cInclude("zig_api.h"));
195+
196+
pub fn main() !void {
197+
_ = c.uapi_init();
198+
defer c.uapi_teardown();
199+
const slot = c.uapi_connector_create(c.UAPI_SERVICE_VERISIMDB,
200+
"http://127.0.0.1:8100");
201+
defer c.uapi_connector_destroy(slot);
202+
// ...
203+
}
204+
----
205+
206+
Option B — add `libzig_api` as a `build.zig` dependency and import symbols
207+
directly from the Zig modules (internal use only; C ABI is the stable surface).
208+
209+
=== From Rust
210+
211+
Use `bindgen` to generate Rust bindings from `zig_api.h`, or use the
212+
scaffolded bindings in `verification-ecosystem/proven/bindings/rust/`
213+
if you also need proven primitives. Link against `libzig_api.so`/`.a`.
214+
215+
=== From ReScript / JavaScript via Deno
216+
217+
Use `Deno.dlopen` against `libzig_api.so` (Linux) to call `uapi_*`
218+
symbols directly. No Node bindings are available; Deno FFI is the path.
219+
220+
=== From Julia
221+
222+
Use `ccall` against `libzig_api.so`. Example:
223+
`ccall((:uapi_init, "libzig_api"), UInt8, ())`.
224+
Julia-specific wrappers are not yet written; `ccall` is the direct path.
225+
226+
== Wiring a New Edge Repo
227+
228+
A new Zig-edge repo is one that calls hyperpolymath services via
229+
`libzig_api` or extends the Idris2 ABI with repo-specific types.
230+
231+
. *Create from template.* Clone `hyperpolymath/rsr-template-repo`, run
232+
`just init`, and customise placeholders.
233+
. *Add `libzig_api` to `build.zig`.* Reference the shared library output
234+
from `developer-ecosystem/zig-api/ffi/zig/` or install it system-wide via
235+
`just install` from the `zig-api` Justfile. A minimal skeleton:
236+
+
237+
[source,zig]
238+
----
239+
const zig_api = b.addSharedLibraryFromPath(
240+
.{ .name = "zig_api", .path = .{ .cwd_relative = PATH_TO_LIBZIG_API } },
241+
);
242+
exe.linkLibrary(zig_api);
243+
exe.addIncludePath(.{ .cwd_relative = PATH_TO_GENERATED_ABI });
244+
----
245+
. *Place repo-specific Idris2 ABI proofs in `src/abi/` of the edge repo.*
246+
Import `ZigApi.ABI.Types` and `ZigApi.ABI.Connector` from `zig-api.ipkg`
247+
(add it as a dependency in the edge repo's `.ipkg`). Extend, do not fork.
248+
. *Use the Groove protocol* for inter-service communication wherever possible
249+
(see `standards/groove-protocol/`). `zig-groove-bridge` in
250+
`developer-ecosystem/zig-ecosystem/connectors/zig-groove-bridge/` is the
251+
reference consumer — study `src/main.zig` before writing your own discovery
252+
or attachment logic.
253+
. *Do not re-roll connector logic.* Call `uapi_connector_create` with the
254+
appropriate `UAPI_SERVICE_*` tag. All 11 services have pre-declared IDs.
255+
256+
== Authoritative Component Links
257+
258+
[cols="2,3"]
259+
|===
260+
| Component | Canonical path
261+
262+
| proven (Idris2 core)
263+
| `verification-ecosystem/proven/`
264+
265+
| zig-api Idris2 ABI
266+
| `developer-ecosystem/zig-api/src/ZigApi/ABI/`
267+
268+
| zig-api Zig runtime
269+
| `developer-ecosystem/zig-api/ffi/zig/src/`
270+
271+
| zig-api C header
272+
| `developer-ecosystem/zig-api/generated/abi/zig_api.h`
273+
274+
| zig-groove-bridge (reference edge)
275+
| `developer-ecosystem/zig-ecosystem/connectors/zig-groove-bridge/`
276+
277+
| bridge-nginx-zig (skeleton)
278+
| `developer-ecosystem/bridge-nginx-zig/`
279+
280+
| Groove protocol spec
281+
| `standards/groove-protocol/`
282+
283+
| rsr-template-repo
284+
| `hyperpolymath/rsr-template-repo` (GitHub)
285+
|===
286+
287+
== Retirement Note
288+
289+
The following repos are retired. Their content has been moved to
290+
`developer-ecosystem/v-ecosystem/v-api-interfaces/` for potential donation to
291+
the V community. Do not model any new work on them.
292+
293+
* `developer-ecosystem/v-grpc/`
294+
* `developer-ecosystem/v-rest/`
295+
* `developer-ecosystem/v-zig-ffi/`
296+
* `developer-ecosystem/v-idris-abi/`
297+
* `developer-ecosystem/haxadeca-v-api/`
298+
* `developer-ecosystem/unified-v-api/`
299+
300+
The trigger was the estate-wide V-lang ban on 2026-04-10 (V-lang detected via
301+
`v.mod` / `vpkg.json`; note: `.v` extension is Verilog, not V-lang).
302+
303+
== Current Status
304+
305+
[cols="1,1,3"]
306+
|===
307+
| Component | Readiness | Notes
308+
309+
| `proven` (Idris2 core)
310+
| ACTIVE
311+
| 104 modules, `%default total`, 0 `believe_me`, 49 tests.
312+
18 bindings complete; 102 scaffolded.
313+
314+
| `zig-api` (Idris2 ABI + Zig runtime)
315+
| PRODUCTION-ADJACENT
316+
| Idris2 ABI fully proved; Zig runtime builds and passes unit tests;
317+
integration tests require `gnosis` binary on `$PATH`.
318+
319+
| `zig-groove-bridge`
320+
| PARTIAL
321+
| Dodeca-API + discovery logic written; attachment / full Groove manifest
322+
negotiation being unblocked.
323+
324+
| `bridge-nginx-zig`
325+
| SKELETON
326+
| `build.zig` and directory structure present; HTTP proxy logic not yet written.
327+
|===
328+
329+
== Open Questions / Deferred
330+
331+
* *proven -> zig-api active wiring.* `zig-api`'s `Foreign.idr` references
332+
`libzig_api` only. The narrative goal of calling `proven_ffi_*` symbols from
333+
within the Zig runtime (e.g. using `proven` SafeMath for buffer bounds in
334+
`gnosis.zig`) is described in `zig-api/EXPLAINME.adoc` but not yet wired.
335+
Until wired, proven and zig-api are parallel stacks that share the Idris2/Zig
336+
FFI pattern but do not chain.
337+
338+
* *C adaptor auto-regeneration pipeline.* `zig_api.h` is marked
339+
`AUTO-GENERATED` but no `just` recipe or CI step currently regenerates it
340+
from the Idris2 ABI source. Manual sync is a drift risk. A `just gen-header`
341+
recipe invoking `idris2` + an extraction pass is needed.
342+
343+
* *Template repo for new edges.* `rsr-template-repo` does not yet include a
344+
`build.zig` skeleton that depends on `libzig_api`. A `just new-zig-edge`
345+
subcommand in `scaffoldia` or a template overlay is the right long-term fix.

0 commit comments

Comments
 (0)