Files
6f0dfd20c5 docs: complete tooling story (pb2zap + zap2pb), zip server, ZAP-only production case (#1)
* docs: tools section (pb2zap, zap2pb), zip server page, ZAP-only production story

- content/docs/tools/: new Tooling nav group — the complete pb<->ZAP
  interop boundary. pb2zap (go/ast codemod off protobuf), zap2pb
  (the one sanctioned protobuf import: Marshal/Unmarshal/Equal/
  AppendMessage, v0.2.0), and the migration path over the existing
  schema/codegen pages.
- content/docs/zip.mdx: the ZAP-native application server — one
  Listen verb (ZAP primary, HTTP secondary), typed handlers with
  REST/OpenAPI/MCP projections, Mount composition, and the
  hanzoai/cloud case: sub-1,000-line compose root hosting ~75K LOC
  of subsystems (76:1).
- why-zap: scrub the unmeasured benchmark tables (per the
  benchmarks-page policy), replace with mechanism arguments and the
  ZAP-only-in-production account: zero gRPC, protobuf confined to
  the four-function zap2pb boundary at the OTLP edge.
- ecosystem: add zip/pb2zap/zap2pb rows; quick-start + index: link
  the new pages, drop the unmeasured 5-20x claim.

* fix(build): alias MDX collections to regenerated docs/, drop frozen .docs snapshot

next.config.mjs and tsconfig.json pointed @hanzo/docs-mdx:collections/*
at .docs/ — a snapshot frozen on Jun 1 — while the MDX plugin
regenerates docs/ on every build. Result: no page added since the
snapshot (schema, codegen, rpc, capabilities, and this PR%27s tools/zip)
was ever emitted; the site silently served 37 routes instead of 45.
Alias both resolvers at docs/ and remove .docs.

---------

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-07 17:58:42 -07:00

51 lines
3.0 KiB
Plaintext

---
title: Overview
description: The ZAP toolchain — code generation, the protobuf-migration codemod, and the one sanctioned protobuf boundary.
---
# Tools
Three tools cover the full path from a protobuf + gRPC codebase to a ZAP-native one. Each does one job. Together they are the complete pb↔ZAP interop boundary — there is nothing else to install and no fourth place where the two worlds touch.
| Tool | Direction | What it does |
|---|---|---|
| [Code generation](/docs/codegen) | `.zap` → code | Compiles a schema to zero-copy Views/Builders and typed clients/servers |
| [`pb2zap`](/docs/tools/pb2zap) | pb Go code → ZAP Go code | `go/ast` codemod that rewrites protobuf construction sites to ZAP wire constructors |
| [`zap2pb`](/docs/tools/zap2pb) | message → pb wire bytes | The single sanctioned place protobuf is imported — four functions at the interop edge |
## One schema, one wire contract
Everything starts from a `.zap` file. It is the one wire contract for a service — structs for the payloads, an interface for the RPC surface, stable opcodes for evolution. A production example, from [hanzoai/tasks](https://github.com/hanzoai/tasks) (`schema/tasks.zap`):
```zap
# Opcodes are stable across releases. Adding a new RPC appends a
# new opcode; never reuse.
struct WorkflowExecution
workflowId Text
runId Text
struct TaskQueue
name Text
kind Int8 # 0=normal, 1=sticky
interface Tasks
startWorkflow (req StartWorkflowRequest)
-> (resp StartWorkflowResponse)
signalWorkflow (req SignalWorkflowRequest)
-> (ok Bool)
```
No file IDs, no hand-written ordinals — field order is wire order, and backward compatibility comes from appending. The [Schema Language](/docs/schema) page is the syntax reference; [Code Generation](/docs/codegen) covers the front-end and every language backend (`zapgen` for Go/TS, the `zapc` binary for Rust, `zap generate` for the rest).
## Migrating off protobuf + gRPC
The migration is mechanical at the edges and honest about the middle:
1. **Port the schema.** `.proto` messages become `.zap` structs; each service method gets a stable opcode. This step is a hand-port by design — the schema is your wire contract, and it deserves review, not transliteration.
2. **Generate.** [Code generation](/docs/codegen) gives you the typed surface in every language you ship.
3. **Rewrite call sites.** [`pb2zap`](/docs/tools/pb2zap) rewrites every unambiguous protobuf construction site (`&pb.Msg{...}` → `wire.NewMsg(wire.MsgInput{...})`) across the tree and *reports* the reads and writes it leaves for a human — it never guesses.
4. **Fence the last edge.** If an external system still speaks protobuf on the wire (OTLP is the usual one), that traffic goes through [`zap2pb`](/docs/tools/zap2pb) — and only through it. One import of `google.golang.org/protobuf` per stack.
The end state is real, not aspirational: the Hanzo production stack runs ZAP-native with zero gRPC and a single four-function protobuf boundary. The full account is in [Why ZAP](/docs/why-zap#zap-only-in-production).