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

54 lines
2.3 KiB
Plaintext

---
title: pb2zap
description: go/ast codemod that migrates a Go codebase off Protocol Buffers and onto the ZAP wire.
---
# pb2zap
[`pb2zap`](https://github.com/zap-proto/pb2zap) migrates a Go codebase off Protocol Buffers and onto [ZAP](https://github.com/zap-proto/go) — zero-copy wire, no `Marshal`/`Unmarshal`, no gRPC.
It is a `go/ast` codemod, and it is **syntactic** — it does not type-check — so it runs on a tree mid-migration that does not yet compile.
```bash
go install github.com/zap-proto/pb2zap/cmd/pb2zap@latest
pb2zap -map rules.txt -w ./...
```
Without `-w` it is a dry run: it prints what it would change and touches nothing.
`rules.txt` holds one rule per line — `pbImportPath wireImportPath wirePkgName`:
```
github.com/acme/app/pb/mount_pb github.com/acme/app/wire/mount mountwire
github.com/acme/app/pb/filer_pb github.com/acme/app/wire/filer filerwire
```
## What it rewrites
The one transform that is unambiguous from syntax alone — **construction**:
```go
&mount_pb.ConfigureRequest{CollectionCapacity: n}
// becomes
mountwire.NewConfigureRequest(mountwire.ConfigureRequestInput{CollectionCapacity: n})
```
It adds the wire import, drops the pb import once nothing else references it, and **reports** (never guesses) the pb selectors it leaves — the field reads that need accessors and the writes that immutable ZAP cannot express.
## What it deliberately does not do
pb→ZAP is not a 1:1 transform; it is a **data-flow split**. A `*pb.Msg` is one type used to both build (set fields) and read (get fields). ZAP splits that into three — `Input` (build) → `[]byte` (transport) → `View` (read). A value that is constructed, threaded through several functions, mutated, then read has no single ZAP type; it has to be restructured into build-once / read-many. `pb2zap` does the safe mechanical piece and points a human at the rest, rather than emit code that compiles by accident.
## Library
```go
out, changed, pbLeft, err := pb2zap.Rewrite("file.go", src, rules)
```
Pure function, `golang.org/x/tools` only. See the [migration guide](https://github.com/zap-proto/go/blob/main/docs/migrate-from-protobuf.md).
## Related
- [Tools overview](/docs/tools) — where pb2zap sits in the migration path
- [zap2pb](/docs/tools/zap2pb) — the opposite edge: the one place protobuf wire bytes are still produced