# Hopper Schema Architecture
## One canonical schema model
Hopper has one source of truth for state and program semantics: the Rust
code. Layout macros, instruction declarations, event definitions, and
policy bindings are the authoritative definitions. From that single
source, Hopper generates two output formats:
1. **Hopper Manifest** -- rich internal schema for tooling
2. **Hopper IDL** -- lighter public schema for clients and integrations
This keeps one truth while supporting two audiences.
## Code-First Doctrine
Canonical truth lives in code. The authoritative declarations are:
- `hopper_layout!` -- fields, offsets, sizes, versions, fingerprints
- `hopper_segment!` / segmented layouts -- segment structure, roles
- `hopper_dispatch!` -- instruction set, discriminators
- `hopper_error!` -- error codes and variants
- Policy constants -- capability-requirement bindings
- `hopper_interface!` -- cross-program read-only views
These declarations produce compile-time constants (LAYOUT_ID, LEN, DISC,
VERSION) that are deterministic and verifiable. The schema layer reads
these constants to build manifests and IDLs without duplicating truth.
## Proc Macro Policy
No proc macros are required for correctness or core functionality.
Proc macros are allowed only for:
- Schema derivation (`#[derive(HopperSchema)]`)
- Manifest export
- IDL generation
- Optional boilerplate reduction
See [PROC_MACRO_POLICY.md](PROC_MACRO_POLICY.md) for the full doctrine.
## The Hopper Manifest
### Purpose
The Manifest is Hopper's rich internal schema. It powers:
- `hopper explain` / `hopper inspect`
- `hopper compat` / `hopper diff` / `hopper plan`
- `hopper manager` (program introspection)
- Receipt rendering and migration planning
- Docs generation and test tooling
### File format
`hopper.manifest.json`
### Structure
```json
{
"format": "hopper-manifest",
"version": 1,
"program": {
"name": "hopper_registry",
"program_id": "...",
"version": "0.2.0",
"description": "Segmented registry example"
},
"layouts": [
{
"name": "Vault",
"kind": "fixed",
"version": 1,
"discriminator": 1,
"layout_id": "a1b2c3d4e5f60718",
"size": 57,
"header_size": 16,
"fields": [
{ "name": "authority", "type": "[u8;32]", "size": 32, "offset": 16 },
{ "name": "balance", "type": "WireU64", "size": 8, "offset": 48 },
{ "name": "bump", "type": "u8", "size": 1, "offset": 56 }
],
"segments": [],
"compatibility": {
"append_safe": true,
"compatible_from": [1],
"migration_required_from": []
}
}
],
"instructions": [
{
"name": "deposit",
"tag": 1,
"args": [
{ "name": "amount", "type": "u64", "size": 8 }
],
"accounts": [
{ "name": "depositor", "writable": false, "signer": true },
{ "name": "vault", "writable": true, "signer": false, "layout_ref": "Vault" }
],
"capabilities": ["MutatesState", "MutatesTreasury"],
"policy_pack": "TREASURY_WRITE",
"receipt_expected": true
}
],
"events": [
{
"name": "DepositEvent",
"tag": 1,
"fields": [
{ "name": "authority", "type": "[u8;32]", "size": 32 },
{ "name": "amount", "type": "u64", "size": 8 }
]
}
],
"policies": [
{
"name": "TREASURY_WRITE",
"capabilities": ["MutatesState", "MutatesTreasury"],
"requirements": ["Authority", "StateSnapshot", "LamportConservation", "InvariantCheck"]
}
],
"compatibility": {
"pairs": [
{
"from": "Vault@1",
"to": "Vault@2",
"toVersion": 2,
"policy": "append-only",
"backwardReadable": true
}
]
}
}
```
### Segment metadata in manifests
For segmented accounts, each segment entry includes:
| name | string | Segment identifier |
| role | string | Core / Extension / Journal / Index / Cache / Audit / Shard |
| segment_id | hex | FNV-1a hash of segment name |
| layout_ref | string | Layout name for this segment |
| required | bool | Must be present in every account instance |
| append_only | bool | Only append operations allowed |
| rebuildable | bool | Can be reconstructed from other data |
| immutable | bool | Cannot be modified after init |
## The Hopper IDL
### Purpose
The IDL is the public-facing schema for:
- TypeScript client generation
- Kotlin, Python, and Rust client generation
- Block explorers
- External integrations
- Codama-compatible tooling
### File format
`hopper.idl.json`
### Structure
```json
{
"format": "hopper-idl",
"version": 1,
"program": {
"name": "hopper_registry",
"program_id": "...",
"version": "0.2.0"
},
"instructions": [
{
"name": "deposit",
"discriminator": [1],
"args": [{ "name": "amount", "type": "u64" }],
"accounts": [
{ "name": "depositor", "writable": false, "signer": true },
{ "name": "vault", "writable": true, "signer": false }
]
}
],
"accounts": [
{
"name": "Vault",
"discriminator": [1],
"size": 57,
"fields": [
{ "name": "authority", "type": "publicKey", "offset": 16 },
{ "name": "balance", "type": "u64", "offset": 48 },
{ "name": "bump", "type": "u8", "offset": 56 }
]
}
],
"events": [
{
"name": "DepositEvent",
"discriminator": [1],
"fields": [
{ "name": "authority", "type": "publicKey" },
{ "name": "amount", "type": "u64" }
]
}
]
}
```
### What IDL excludes
- Migration planning data
- Trust profile internals
- Policy wiring details
- Receipt render metadata
- Unsafe invariant catalog
- Segment migration hints
These live in the Manifest only.
## Codama Compatibility
Hopper is Codama-compatible where it improves developer experience:
- Client generation
- Instruction/account metadata for explorers
- TypeScript ecosystem interop
Hopper does not flatten its richer state model to fit Codama. The
Manifest preserves full richness; the IDL exposes the clean public
subset; a Codama projection can be generated from the IDL.
```bash
hopper schema export --manifest # Full manifest
hopper schema export --idl # Public IDL
hopper schema export --codama # Codama-compatible projection
```
## Generation Pipeline
```
Rust declarations (hopper_layout!, hopper_dispatch!, etc.)
|
v
Schema extraction (hopper-schema crate)
|
v
Hopper Manifest + Hopper IDL + Codama projection
|
v
CLI / Manager / Clients / Planner / Receipts
```
The extraction layer lives in `hopper-schema`. It reads LayoutManifest
constants generated by macros and assembles them into the output formats.
No runtime reflection. No dynamic discovery. Everything is compile-time
deterministic.
## File Layout
```
project/
hopper.manifest.json # Rich manifest (generated)
hopper.idl.json # Public IDL (generated)
src/
lib.rs # Canonical code declarations
docs/
SCHEMA_ARCHITECTURE.md
PROC_MACRO_POLICY.md
```