4. Go and TypeScript share contracts, not bindings
Two native SDKs that share contracts.
Context
Zynactra builds services in Go and in TypeScript (NestJS, Next.js). A Go core with generated TS bindings (WASM, FFI or a local daemon) adds a runtime, a build step and failure modes to every Node service.
Decision
Two native SDKs that share contracts:
- SQL migrations (
migrations/, copied byscripts/sync-shared.mjs), - the compiled manifest JSON (
zaccess gen), - the HTTP API (
spec/openapi.yaml), - conformance fixtures (
conformance/): grants, plan-to-SQL, escalation, live decisions and admin scenarios, run by both SDKs in CI.
The CLI (zaccess) is written once, in Go.
Consequences
- Each SDK is idiomatic and dependency-light.
- Behaviour can drift only where fixtures do not reach; every bug fix adds a fixture.
- Changing a shared contract means changing both SDKs in the same PR.
3. `resource:action` keys; scope lives on the assignment
Permission keys are resource:action, split on the first colon (actions may contain colons, as in read:reason for field-level permissions).
5. Our own plan-to-SQL translator, identical in Go and TS
sqlfilter.Translate (Go) and planToSql / drizzleFilter (TS) translate exactly the operators generated policies produce (and, or, not, comparisons, in, startsWith/endsWith/contains, null checks),...