Architecture
panproto is a layered Rust workspace. The bottom layer is the GAT engine; everything else builds on it. The top layer is the surfaces (CLI, WASM, PyO3, C ABI) that downstream users actually call. Each layer depends only on layers below it; the dependency graph is acyclic.
Layering
graph TD
subgraph "Surfaces"
CLI[panproto-cli<br/>schema binary]
WASM[panproto-wasm]
PY[panproto-py]
C[panproto-c]
REPL[panproto-repl]
end
subgraph "Facade"
CORE[panproto-core]
end
subgraph "Higher operations"
VCS[panproto-vcs]
GIT[panproto-git]
XRPC[panproto-xrpc]
GITREMOTE[panproto-git-remote]
PROJ[panproto-project]
CHECK[panproto-check]
end
subgraph "Codegen"
LLVM[panproto-llvm]
JIT[panproto-jit]
end
subgraph "Pipeline"
MIG[panproto-mig]
LENS[panproto-lens]
LENSDSL[panproto-lens-dsl]
IO[panproto-io]
PARSE[panproto-parse]
GRAMMARS[panproto-grammars<br/>+ grammars-{all,web,data,jvm,<br/>scripting,systems,functional,<br/>devops,mobile,music}]
end
subgraph "Protocols and theories"
PROTOS[panproto-protocols]
THEORYDSL[panproto-theory-dsl]
EXPR[panproto-expr]
EXPRPARSER[panproto-expr-parser]
end
subgraph "Foundation"
GAT[panproto-gat]
GATMACROS[panproto-gat-macros]
SCHEMA[panproto-schema]
INST[panproto-inst]
end
CLI --> CORE
WASM --> CORE
PY --> CORE
C --> CORE
REPL --> CORE
CORE --> VCS
CORE --> GIT
CORE --> PROJ
CORE --> CHECK
CORE --> MIG
CORE --> LENS
CORE --> IO
CORE --> PARSE
CORE --> LLVM
CORE --> JIT
VCS --> MIG
GIT --> VCS
XRPC --> VCS
XRPC --> SCHEMA
GITREMOTE --> VCS
GITREMOTE --> GIT
GITREMOTE --> XRPC
PROJ --> SCHEMA
CHECK --> MIG
MIG --> LENS
MIG --> SCHEMA
LENS --> SCHEMA
LENSDSL --> LENS
IO --> INST
PARSE --> INST
PARSE --> LENS
PARSE --> GRAMMARS
LLVM --> PROTOS
LLVM --> SCHEMA
JIT --> EXPR
LENS --> EXPR
MIG --> EXPR
EXPRPARSER --> EXPR
PROTOS --> SCHEMA
PROTOS --> INST
THEORYDSL --> GAT
GATMACROS --> GAT
SCHEMA --> GAT
INST --> GAT
EXPR --> GAT
The diagram shows the direction of dependency, not every individual edge. The full set is in the workspace Cargo.toml. The ten panproto-grammars-* pack crates are grouped together in the diagram: each is a leaf re-exporting a subset of the tree-sitter grammars under feature flags, consumed transitively by panproto-parse.
One arrow worth pointing out: panproto-parse depends on panproto-lens, not the other way around. The two crates meet through the enrichment_registry module in panproto-lens, a thin trait-and-registry pair the lens crate exposes for downstream crates to populate. panproto-parse installs an adapter for every parser it accepts so that protolens machinery in panproto-lens can dispatch grammar-driven enrichment synthesis without depending on tree-sitter. The mechanism is documented in Layout enrichment; the registry pattern keeps the lens crate grammar-agnostic and the dependency direction acyclic.
The boundaries
Three places in the system are boundary layers in the sense that they convert between panproto’s internal representation and an external one. They are deliberately thin and concentrated in single crates so they can be audited independently.
WASM boundary
panproto-wasm is the only crate that knows about wasm-bindgen. It exposes panproto-core to JavaScript through a slab of opaque integer handles, with MessagePack encoding for data crossing the boundary. The TypeScript SDK (@panproto/core) is a thin wrapper over the WASM exports; it adds the fluent builder ergonomics but no logic.
Python boundary
panproto-py is the only crate that knows about PyO3. It exposes panproto-core to Python with native bindings (no WASM). The Python wheel ships eleven core tree-sitter grammars; the rest are in companion panproto-grammars-* packs.
C boundary
panproto-c is the only crate that knows about C ABI. It exposes a stable C interface used by the Haskell binding (and any other non-Rust language). CBOR is the over-the-boundary format here.
The generated CLI reference
The schema binary’s --help text is the source of truth for the CLI surface. The reference/cli page is regenerated by an xtask (see xtask/src/bin/gen-cli-docs.rs) and CI fails if the page is out of date. This is the only generated file in the docs site.
Versioning
All workspace crates are versioned in lockstep at the workspace level (workspace.package.version). A release of panproto-core 0.46.0 implies every panproto-* crate at 0.46.0. The TypeScript SDK and Python SDK follow the same version. See Release process for cadence.
See also
- Crate map for one-line descriptions of every crate.
- What panproto verifies for the per-crate properties checked.
- Composing protocols by colimit for the GAT-engine consumer pattern.