This is a plan for expanding the "Build apps" section of the Shinzo docs (the build-apps repo, a Zola site). It covers the section structure, a title and description per page. Pages follow the Diátaxis model: tutorials, how-to guides, and explanation. Reference material stays in the existing top-level /reference/ section and is linked to rather than duplicated, which is the one deliberate deviation from a strict four-quadrant layout inside Build apps section.
Decisions
Two app architectures are covered, kept separate throughout. The first is the embedded local-first model: a Go app uses the app-sdk, embeds DefraDB, subscribes to Views, and queries data pushed to it over P2P. The second is the direct-query model: a TypeScript app sends signed GraphQL requests to a public Host over HTTP using @shinzo/shinzohub and @shinzo/querysig, the same model Shinzo Studio uses. A third path, running your own Host as a private Direct Client, is signposted but not taught here because it belongs to the Run section.
No billing or economics pages just yet. The concepts/economics-of-views draft stays a draft. Funding a query balance appears only as a minimal inline step where a tutorial cannot work without it, wrapped in a warning that metering details may change, since per-query metering is not finalized in the code.
Existing pages restructured freely: moved, split, retitled, with aliases preserved so old URLs keep working.
All tutorials target the public testnet by default: testnet.shinzo.network (EVM JSON-RPC on :8545, Cosmos REST on :1317, CometBFT on :26657, chain ID 91273001), with testnet tokens from faucet.shinzo.network. No tutorial requires the reader to run a Generator or a Host.
What happens to existing pages
| Existing page |
Fate |
build/create-a-view/ |
Rewritten as the "Create your first View" tutorial, testnet as the default target. |
build/create-a-view/examples/ |
Moved and reframed as the "View recipes" how-to. Aliases kept. |
build/build-an-app/ |
Split. Concepts become the "The Shinzo app model" explanation. Usage becomes the "Subscribe to Views with the app-sdk" and "Configure attestation thresholds" how-tos. The rest feeds the "Build a local-first app" tutorial. |
build/query-data/ |
Moved under how-to and restructured around tasks. Aliases kept. |
build/concepts/views-for-builders/ |
Moved under explanation with link fixes only. Aliases kept. |
build/concepts/attestation-as-a-query-filter/ |
Developed from its draft stub into an explanation page. |
build/concepts/economics-of-views/ |
Stays a draft. Excluded from the sidebar and from this plan. |
build/publish/ |
Stays a draft. Its scope is covered by the deploy steps in the View tutorials. |
New structure
build/
├── index.md (landing)
├── tutorials/
│ ├── query-your-first-view/
│ ├── create-your-first-view/
│ └── build-a-local-first-app/
├── how-to/
│ ├── find-views-and-hosts/
│ ├── connect-to-a-host/
│ ├── query-data/
│ ├── view-recipes/
│ ├── use-shinzo-studio/
│ ├── write-a-lens/
│ ├── subscribe-to-views/
│ ├── configure-attestation-thresholds/
│ ├── verify-data/
│ └── use-your-own-infrastructure/
└── explanation/
├── the-app-model/
├── choosing-an-architecture/
├── views-for-builders/
└── attestation-as-a-query-filter/
Site plumbing, to be folded into the first page-building task:
- In
config.toml, replace the two current section = "build" sidebar blocks with three groups: "Tutorials", "How-to guides", and "Explanation", listing the pages above in tree order. Pages are not auto-discovered, so nothing appears until it is listed.
- Update the navbar entry for "Build apps" so its
href points at /build/ (the landing page) instead of /build/create-a-view/.
- Keep
aliases on every moved page so old URLs (/build/query-data/, /views/examples, /views/overview, /guides, and friends) keep working.
- Run
zola build after adding each page to confirm the site compiles.
Shared instructions for page-building agents
Prepend this block to every page-building task:
You are writing one page for the Shinzo docs site (Zola) in /mnt/host/build-apps. Conventions:
- Front matter is TOML between
+++ lines with title, description, and optional aliases. Add [extra] and mermaid = true if the page includes a diagram.
- Shortcodes and macros:
{% admonition(type="note"|"tip"|"warning") %} ... {% end %}, {% mermaid() %} ... {% end %}. End each page with a ## Need help section containing the need_help macro; copy the exact usage from an existing page such as content/build/query-data/index.md.
- Numbered steps use
1. for every item and let Zola number them. Code blocks always declare a language. Shell output blocks use ```output.
- Register the page in
config.toml under the correct [[extra.sidebar]] group, then run zola build.
- Style rules, mandatory: never write "decentralized" (rewrite around the actual property, such as trustless, verifiable, or permissionless). Never write "decentralized indexer"; use "trustless blockchain data read" or "verifiable blockchain data read". Any use of "indexer", "indexing", or "index" must be immediately preceded by "trustless" or "verifiable", but prefer "Generator" for the client role and "data read" for the mechanic. Prefer chain-agnostic phrasing ("the blockchain", "smart contract", "transaction fee", "fungible token") unless the content is genuinely about one chain; literal code and API identifiers such as
eth_getLogs or ABI field names are exempt. Bold any UI element the reader is told to interact with. "View" is capitalized. Clients are "Generator client" and "Host client".
- Sources of truth on this machine:
/mnt/host/other-repos/host-client, /mnt/host/other-repos/shinzohub, /mnt/host/other-repos/web, /mnt/host/other-repos/shinzo-view-creator, /mnt/host/other-repos/blog, plus the existing docs under /mnt/host/build-apps/content/understand/ and /mnt/host/build-apps/content/reference/. The Go app-sdk is not checked out locally; rely on github.com/shinzonetwork/app-sdk and the existing content/build/build-an-app/index.md for its API. Confirm every export, command, and flag against source before writing it. Where a fact cannot be confirmed, flag it in your final report instead of guessing.
- Tutorials must work against public testnet infrastructure. Never require the reader to run a Generator or a Host.
- Terminology drift warning: older code says "Indexer" where the docs say "Generator", and "Data Feed" roughly means "View". Always use the docs terminology.
- No em dashes or en dashes anywhere in the prose.
Pages
Build apps (landing)
Path: build/index.md. Diátaxis type: landing page, a deliberate deviation used only for orientation. Front-matter description: "Choose your path for building on Shinzo: query existing Views, create your own View, or build a local-first app."
Tasks
- Turn the empty
content/build/index.md into a short orientation page, no more than about 60 lines of prose.
- Present the paths as a small table or three short blocks: query existing Views from a TypeScript app (signed GraphQL requests to a public Host, nothing local) linking to "Query your first View"; create a View with the Viewkit CLI or Shinzo Studio linking to "Create your first View" and "Create and deploy Views in Shinzo Studio"; build a local-first app with the Go app-sdk linking to "Build a local-first app". Add one line for running your own Host, marked advanced, linking to "Use your own infrastructure".
- Include one short paragraph on the shared idea: Generators produce signed primitive data, Hosts execute Views and serve results, and apps either query Hosts directly or receive pushed data locally. Link to
/understand/what-is-shinzo/ and /understand/how-it-works/ without re-explaining them.
- Add a "Before you start" list: Git, Go 1.25+ and/or Node 20+ with pnpm, a wallet funded from
faucet.shinzo.network, and a note that no hardware is required.
- No
need_help macro on this page.
Query your first View
Path: build/tutorials/query-your-first-view/index.md. Diátaxis type: tutorial. Front-matter description: "Tutorial: query a live View on the Shinzo testnet from a TypeScript app. Discover a View, pick a Host, sign a request, and print results."
Tasks
- The reader finishes with a small TypeScript script (Node, or a minimal Vite page if that is simpler) that prints the 10 latest rows of an existing testnet View. Nothing is installed locally except npm packages.
- Steps: scaffold a project and install
@shinzo/shinzohub, @shinzo/querysig, and viem. Create a client with shinzoHubTestnet from @shinzo/shinzohub/chains (chain ID 91273001, endpoints on testnet.shinzo.network). Discover a View with listViews or via the Explorer at explorer.shinzo.network, and a Host serving it with listHosts (the endpoint_address field) and listViewPools or getPoolFor (a pool is active once it has at least 3 Hosts). Fund a query balance in one short step: get testnet tokens from faucet.shinzo.network, call fundQueryBalance({amount}), and wrap the step in a warning admonition saying billing details may change and no dedicated billing guide exists yet. Sign a GraphQL query with sign() from @shinzo/querysig and show the resulting extensions object (request_signature, nonce, query_hash, request_timestamp, pool_address). POST to https://<host-endpoint>/api/v0/graphql and print the rows.
- Use a transfer-decoding View (an
EventView-style collection with hash, from, to, blockNumber, event) as the concrete query so it composes with the output of "Create your first View".
- Sources:
/mnt/host/other-repos/web/packages/shinzohub/README.md and api.md, /mnt/host/other-repos/web/packages/querysig/, and /mnt/host/other-repos/web/apps/studio/lib/pages/view/ui/view-playground.tsx for the real query flow. Confirm every export name against the package source.
- End with a "Where to next" block: "Create your first View" to own the data, "Build a local-first app" for the embedded version, "Choosing an app architecture" for the trade-offs.
need_help with client "Shinzo SDK" and the repo https://github.com/shinzonetwork/web/issues.
Create your first View
Path: build/tutorials/create-your-first-view/index.md. Diátaxis type: tutorial. Front-matter description: "Tutorial: build, test, and deploy a Shinzo View with Viewkit, from install to querying it on the public testnet."
Tasks
- Restructure the existing
content/build/create-a-view/index.md, moving it to the new path and keeping aliases = ["/views/quickstart", "/views/install", "/build", "/build/create-a-view/"].
- Keep the existing skeleton, which works: prerequisite checks, clone
shinzo-view-creator, make build, Wasmer runtime environment variables (macOS and Linux variants), viewkit view init, add query, add sdl, add lens (the decode_log lens from the wasm-bucket URL), viewkit view test, viewkit wallet generate, deploy with --target local, verify in the DefraDB Playground, then deploy to the network.
- Change the network target from devnet to the public testnet:
viewkit view deploy testdeploy --target devnet --rpc http://testnet.shinzo.network:8545/. First confirm in /mnt/host/other-repos/shinzo-view-creator/cli/view_deploy.go which --target values exist and what each does. If the CLI's devnet target is the right one for the public testnet chain (91273001), keep the flag but call the network "the public testnet" in prose and explain the flag name in a note admonition. Add a wallet-funding step (the faucet) before the network deploy, because registration is an on-chain transaction.
- Trim repetition: the current page re-prints near-identical
viewkit view inspect output after every step. Collapse these into one full inspect after all components are attached.
- Add a final "Query your View" step: find the View in the Explorer or Studio and run one GraphQL query against a public Host, linking to "Query your first View" for the mechanics. Note that on-chain registration completes asynchronously and can take around 20 seconds.
- Cross-links: "View recipes" for more examples, "Views for builders" for concepts,
/reference/components/viewkit/ for the full command list, /reference/components/lens/ for lenses.
need_help with client "Viewkit", copied from the existing page.
Build a local-first app
Path: build/tutorials/build-a-local-first-app/index.md. Diátaxis type: tutorial. Front-matter description: "Tutorial: build a Go app that embeds DefraDB via the app-sdk, subscribes to a View, and queries pushed data locally with attestation filtering."
Tasks
- The reader finishes with a running Go program that receives View data pushed from public testnet Hosts and answers queries locally, with no per-query API call.
- Steps:
go mod init and go get github.com/shinzonetwork/app-sdk. A minimal config.yaml with shinzo.minimum_attestations: 1 and logger.development: true for the tutorial. Start embedded DefraDB with defra.StartDefraInstance(config, &defra.MockSchemaApplierThatSucceeds{}) and defer Close. Define the View struct (name, query, sdl; reuse the View from "Create your first View" or a known public one) and call SubscribeTo. Wait for data, then query with defra.QueryArray[MyStruct]. Add attestation.AddAttestationRecordCollection and switch to attestation.QueryArrayWithConfiguredAttestationFilter. Run the program and watch rows arrive.
- Bootstrap connectivity: the app's DefraDB peer needs a Host connection string. Show deriving one from the on-chain host registry (
GET http://testnet.shinzo.network:1317/shinzonetwork/host/v1/hosts, the connection_string field) and defer the full mechanics to "Connect your app to a Host". If no canonical public bootstrap Host can be confirmed, flag it in your final report; this is a known open dependency.
- Treat the existing
content/build/build-an-app/index.md as the authority for API names, and keep its note that the "collection already exists" error is informational.
need_help with client "app-sdk" and the repo https://github.com/shinzonetwork/app-sdk/issues.
Find Views and Hosts
Path: build/how-to/find-views-and-hosts/index.md. Diátaxis type: how-to guide. Front-matter description: "How to discover registered Views, serving Hosts, and pools on the Shinzo network using the Explorer, Studio, the REST API, or the TypeScript SDK."
Tasks
- Cover four methods, each with a working example. Explorer:
explorer.shinzo.network/shinzohub for host and generator lists, with UI elements bolded. Studio: the view catalog at studio.shinzo.network. REST: curl examples against http://testnet.shinzo.network:1317 for /shinzonetwork/view/v1/views?include_data=true, /shinzonetwork/host/v1/hosts, /shinzonetwork/indexer/v1/indexers, and /shinzonetwork/pool/v1/views/{view_address}/pools; explain what connection_string (a libp2p multiaddr) and endpoint_address (the GraphQL URL) each mean. TypeScript: listViews, listHosts, getPoolFor, and getNetworkUnitPrice from the @shinzo/shinzohub subpath exports.
- Include the Host self-description endpoint:
GET http://<host>:8080/registration returns the Host's DID, connection_string, and endpoint_address (source: /mnt/host/other-repos/host-client/pkg/server/registration.go).
- State what does not exist: Viewkit has no list or discovery commands, so discovery happens on-chain or through the UIs. This is confirmed in the view-creator CLI source.
- Link to "Connect your app to a Host", "Query your first View", and
/reference/tools/.
Connect your app to a Host
Path: build/how-to/connect-to-a-host/index.md. Diátaxis type: how-to guide. Front-matter description: "How to connect an application to a Shinzo Host: P2P connection strings for embedded Go apps and GraphQL endpoints for direct-query TypeScript apps."
Tasks
- Split the page by architecture. Embedded (Go): get the Host's
connection_string (link "Find Views and Hosts"), add it to defradb.p2p.bootstrap_peers in the app-sdk config as a comma-separated multiaddr in the form /ip4/<ip>/tcp/9171/p2p/<peerID>. Mention that bare IPs and ip:port also work because peer IDs are auto-discovered during the handshake (behavior confirmed in /mnt/host/other-repos/host-client/pkg/host/peer_discovery.go).
- Direct query (TypeScript): resolve the Host's
endpoint_address from the registry and target POST <endpoint>/api/v0/graphql. One billed query maps to one pool. Mention the 402 and 403 rejection shapes briefly, without a billing deep-dive.
- Health checking before connecting:
GET http://<host>:8080/health, which returns JSON when the Accept: application/json header is set.
- Sources:
/mnt/host/other-repos/host-client/BUILD.md for ports (9181 GraphQL, 9182 playground, 9171 P2P, 8080 health), pkg/server/health.go, and pkg/acp/middleware.go for error codes only.
- End with a short pointer to "Use your own infrastructure" for readers who want to run everything themselves.
Query data
Path: build/how-to/query-data/index.md. Diátaxis type: how-to guide. Front-matter description: "How to query Shinzo data with GraphQL: filters, ordering, nested documents, DocIDs, CIDs, and signatures."
Tasks
- Move
content/build/query-data/index.md to the new path and keep aliases = ["/hosts/examples", "/build/query-data/"].
- Restructure the flat example list into task-headed sections, for example "Get the latest N documents", "Fetch a document by DocID or CID", "Filter by field values", "Check who signed a document", and "Count nested documents". The GraphQL content itself is sound; retitle sections so each answers a "how do I" question.
- Remove the duplicated "CID to document" and "From CID to document directly" sections, which contain identical content.
- Keep the
<Chain>__<Network>__ prefix admonition and the Host need_help macro.
- Add a short intro that disambiguates the two query surfaces: your local embedded DefraDB via the app-sdk, or a Host's
/api/v0/graphql. Same GraphQL language, different transport.
- Link to
/reference/components/viewkit/ for the filter-operator table instead of duplicating it, and to "Verify data with signatures and CIDs" for the verification material.
View recipes
Path: build/how-to/view-recipes/index.md. Diátaxis type: how-to guide, organized as a recipe collection. Front-matter description: "How to build common Views: decode event logs, filter by contract, decode multiple event types, transaction Views, and editing or rolling back a View."
Tasks
- Move
content/build/create-a-view/examples/index.md to the new path and keep aliases = ["/views/examples", "/build/create-a-view/examples/"].
- Reframe the seven examples as recipes with imperative titles: "Decode event logs", "Filter by contract address", "Decode multiple event types", "Query transactions without a lens", "Choose materialized vs on-query", "Edit and roll back a View", "Query a deployed View". The content is already good; mostly re-head and tighten the intros so each recipe states its goal up front.
- Replace the hardcoded devnet RPC
http://34.29.171.79:8545/ with the public testnet endpoint http://testnet.shinzo.network:8545/.
- Fix the stale lens-reference links so they point at
/reference/components/lens/ consistently. Keep the decode_log vs decode_log_str tip; it reflects real behavior documented in the lens reference.
- Keep the Viewkit
need_help macro. Link "Create your first View" and "Write and test a custom lens".
Create and deploy Views in Shinzo Studio
Path: build/how-to/use-shinzo-studio/index.md. Diátaxis type: how-to guide. Front-matter description: "How to create, deploy, and query Views from your browser with Shinzo Studio, without installing the CLI."
Tasks
- Task flow: open
studio.shinzo.network, connect a wallet (switch to the Shinzo testnet, chain ID 91273001), create a View (query, SDL, and a lens from the catalog: decode-log, ERC-20 transfers, ERC-20 account balances), deploy it (wallet-signed registration; registration completes asynchronously and Studio polls until the status is "registered"), then query it in the built-in GraphiQL playground by picking a Host that is a member of the View's pool.
- Bold every UI element the reader interacts with, per the style guide. Include screenshots only if the tooling to capture them exists; otherwise write the UI text precisely and note screenshots as a follow-up in your final report.
- Source of truth:
/mnt/host/other-repos/web/apps/studio/, in particular lib/entities/view/model/use-deploy-lens.ts for the deploy flow, lib/entities/lens/model/catalog.ts for the lens catalog, and lib/pages/view/ui/view-playground.tsx for querying. Describe behavior as implemented and flag anything uncertain.
- Include the query-balance funding prerequisite as one inline step, with the same minimal treatment as in "Query your first View".
- Open with a positioning sentence: Studio covers the same create, deploy, and query flow as Viewkit for developers who prefer a browser UI.
Write and test a custom lens
Path: build/how-to/write-a-lens/index.md. Diátaxis type: how-to guide. Front-matter description: "How to author a WebAssembly lens with the AssemblyScript SDK, test it locally, and attach it to a View."
Tasks
- Open with the decision point: most Views only need the prebuilt lenses from the wasm-bucket, so link
/reference/components/lens/ for the catalog and frame custom lenses as the fallback when the transform you need does not exist.
- Walk through authoring with
@shinzo/lenses (AssemblyScript): createLens(fn) for generic JSON transforms and createEvmLens(fn, Args, eventName, ..., ABI) for log decoding, using decoded.getArg(...) and ctx.args. Show one minimal complete lens, such as normalizing an address field or dropping events below a threshold. Keep it deterministic.
- Testing:
expectEvmLens(...).withTokenAddress(...).withLog(...).run() and loadWasmBytes from @shinzo/lenses/testing, then validateView() and bundleView() from @shinzo/lenses/view (or /view/node) before registration, then viewkit view test with a local --path WASM for the full-View check.
- State the determinism rules from
/reference/components/lens/: no clock, randomness, network, filesystem, or floats. Note the runtimes in one admonition (wazero in Hosts, wasmer for Viewkit's local testing).
- Mention the Rust alternative (the
sourcenetwork/lens SDK, roughly 200 to 300 KB output versus roughly 73 KB for AssemblyScript) in one paragraph and link out.
- Source:
/mnt/host/other-repos/web/packages/lenses/. Confirm all exports against the source.
Subscribe to Views with the app-sdk
Path: build/how-to/subscribe-to-views/index.md. Diátaxis type: how-to guide. Front-matter description: "How to configure and start an embedded DefraDB instance, subscribe to Views, and receive pushed data in a Go application."
Tasks
- Extract the usage material from the existing
content/build/build-an-app/index.md, which stays the authority for API names: config via config.LoadConfig with file.FindFile versus the default config; the shinzo.minimum_attestations and logger.development keys; the SchemaApplier variants (SchemaApplierFromFile, SchemaApplierFromProvidedSchema, MockSchemaApplierThatSucceeds) and when each applies, including the case where the app uses DefraDB for non-Shinzo data too; defra.StartDefraInstance and clean shutdown.
- Then cover the
View struct (only name, query, and sdl matter), SubscribeTo, the informational "collection already exists" error, and what a subscription actually does: it adds the View's SDL locally and registers the collection as a passive-replication topic so Hosts push data for it.
- Query helpers:
defra.QuerySingle and defra.QueryArray with typed structs.
- This page owns the mechanics. Attestation filtering lives in "Configure attestation thresholds" and the rationale lives in "The Shinzo app model"; link to both instead of repeating them.
need_help with client "app-sdk".
Configure attestation thresholds
Path: build/how-to/configure-attestation-thresholds/index.md. Diátaxis type: how-to guide. Front-matter description: "How to require a minimum number of Generator attestations before query results are returned in your app."
Tasks
- Build from the attestations material in the existing
build-an-app page: attestation.AddAttestationRecordCollection(ctx, defra, viewName), which pushes AttestationRecord_<View> documents alongside the View; the "collection already exists" caveat; the config-wide default via shinzo.minimum_attestations; and the four query helpers, meaning the configured variants (QuerySingleWithConfiguredAttestationFilter, QueryArrayWithConfiguredAttestationFilter) versus the per-call variants (QuerySingleWithAttestationFilter, QueryArrayWithAttestationFilter).
- Include a short decision table: when a configured default is enough versus when per-query thresholds make sense (a wallet display accepting 1 attestation versus a high-value flow requiring 3 or more). Keep the framing that this is a query-time filter, not a system-wide setting.
- Show enough of the underlying data to debug an empty result set: what an
AttestationRecord contains (attested_doc, source_doc, CIDs, doc_type, and the vote_count CRDT pcounter) and what happens when your threshold is higher than the number of available attestations.
- Link "Attestation as a query filter" for the concept, "Verify data with signatures and CIDs" for manual verification, and
/understand/core-concepts/attestation/.
Verify data with signatures and CIDs
Path: build/how-to/verify-data/index.md. Diátaxis type: how-to guide. Front-matter description: "How to verify who signed your data and navigate attestations, commits, and documents via CIDs."
Tasks
- Consolidate the verification-flavored queries currently scattered through
content/build/query-data/index.md: _version { cid signature { identity value type } } on any document; _commits(cid: ...) for commit metadata and ES256K signatures; AttestationRecord queries; resolving a CID to its document; and a brief mention of block-level BlockSignature and snapshot signatures with a link to /understand/core-concepts/attestation/.
- Frame the sections as tasks: "Check who signed a document", "Trace a document back to its attestations", "Resolve a CID to its document or commit".
- Keep examples terse, one query plus a trimmed response each. The full query catalog lives in "Query data"; this page is the trust-verification subset.
- Add one admonition on what verification does not cover (query completeness and freshness), pointing at
/understand/core-concepts/privacy/ for the roadmap framing. Do not go deep.
Use your own infrastructure
Path: build/how-to/use-your-own-infrastructure/index.md. Diátaxis type: how-to guide, deliberately a pointer page. Front-matter description: "How to run your own Host as a private Direct Client for your app: the strongest privacy and control, at the cost of operating a node."
Tasks
- Keep this page under about 100 lines. Cover when you would do this (the strongest query privacy available today, full control, no reliance on public Hosts) and the two privacy tiers documented in
/understand/core-concepts/privacy/: a standard private setup (public ShinzoHub for Views, your own Generator as the only bootstrap peer, registration skipped) versus a fully air-gapped setup (empty hub_base_url, contacts nothing but your Generator).
- Do not duplicate install or config content. Link decisively to
/run/run-a-host/install/, /run/run-a-host/private-hosts/, and /run/run-a-generator/. This page is the bridge, not the guide.
- Include the honesty point from the query-privacy blog post (
/mnt/host/other-repos/blog/query-privacy.md): running your own Host and querying it directly is the only configuration today where no third party can observe your queries.
- End with "back to building" links to "Connect your app to a Host" and "Choosing an app architecture".
The Shinzo app model
Path: build/explanation/the-app-model/index.md. Diátaxis type: explanation. Front-matter description: "How Shinzo inverts the traditional data-API model: you define the API, and pre-processed data is pushed to your application as a verifiable local cache."
Tasks
- Build from the concepts section and the USDC counter example in the existing
build-an-app page: the centralized-provider model (choose from fixed APIs, provider-side caching, your own cache on top, per-query pricing, webhook surprises) versus Shinzo's inversion (you define the API as a View, pre-processed results are pushed to you, you query your local replica as often as you like, and you pay for access to transformed data rather than per query). Keep payment discussion to one sentence at most, since there are no billing pages.
- Cover the embedded DefraDB instance as the app's verifiable cache, content-addressed documents and signatures making pushed data independently checkable, and passive replication as the delivery mechanism.
- Include one mermaid diagram of the Generator to Host to app push flow. Check
/understand/how-it-works/ first and do not duplicate its diagram; angle yours on the application boundary.
- Use chain-agnostic phrasing throughout. The USDC example is genuinely chain-specific and may keep its proper nouns, but abstract the surrounding prose.
- Link "Views for builders", "Attestation as a query filter", and "Choosing an app architecture".
Choosing an app architecture
Path: build/explanation/choosing-an-architecture/index.md. Diátaxis type: explanation. Front-matter description: "Trade-offs between the three ways to build on Shinzo: direct signed queries to Hosts, an embedded local-first client, or your own private Host."
Tasks
- This page makes the two-architectures decision legible, so give it a comparison table across latency profile (round trip versus local read), operational footprint (none, an embedded library, or a full node), trust posture (attestation-filtered Host results, the same plus local verification, or no third party sees your queries), data freshness mechanics (per-query versus pushed replication), and best fit (dashboards and serverless, stateful apps with heavy local querying, privacy-critical or compliance-bound apps).
- Follow the table with one honest paragraph per architecture: direct query (the Studio model,
@shinzo/querysig), embedded (the app-sdk), and Direct Client (your own Host). Use the "privacy posture is a dial" framing from /mnt/host/other-repos/blog/query-privacy.md: privacy features are opt-in layers, not a global switch.
- Pricing and metering are explicitly out of scope for this page.
- End with a decision guide: prototyping a web frontend points to "Query your first View", a stateful service points to "Build a local-first app", regulated or privacy-sensitive work points to "Use your own infrastructure".
Views for builders
Path: build/explanation/views-for-builders/index.md. Diátaxis type: explanation. Front-matter description: "What a Shinzo View is: a versioned bundle of query, SDL, and lenses, and how Viewkit turns primitive data into reusable data APIs."
Tasks
- Move
content/build/concepts/views-for-builders/index.md to the new path and keep aliases = ["/view-creator", "/views", "/views/overview", "/build/concepts/views-for-builders/"].
- Make light edits only. The content is already strong (purpose, pipeline mermaid, primitive collections table, the what-you-can-build list). Update the "Where to go next" links to the new paths and keep the
/reference/components/viewkit/ and /reference/components/lens/ links.
- Do not expand the page. Most of this task is the move, the alias, and the link audit.
Attestation as a query filter
Path: build/explanation/attestation-as-a-query-filter/index.md. Diátaxis type: explanation. Front-matter description: "Why attestation thresholds are a per-query trust dial, and how pushed attestation records let each app set its own bar for accepting data."
Tasks
- Replace the draft stub currently at
content/build/concepts/attestation-as-a-query-filter/, moving it under explanation/ and keeping an alias for the old path.
- Explain rather than instruct; the mechanics live in "Configure attestation thresholds". Cover why independent Generator signatures plus Host-maintained
AttestationRecords let trust be evaluated at query time, how vote_count as a CRDT pcounter merges attestations from multiple Hosts without conflicts, segmentation (you only receive attestation records for Views you subscribe to), and why different apps set different bars. Keep the framing that this is a query-time filter, not a system-wide setting.
- Connect briefly to batch and block-level signatures, then link
/understand/core-concepts/attestation/ for the platform-level picture without duplicating it.
- Sources: the attestations section of the existing
build-an-app page, ADRs 02 and 03 in /mnt/host/other-repos/host-client/adr/, and /mnt/host/build-apps/content/understand/core-concepts/attestation/.
This is a plan for expanding the "Build apps" section of the Shinzo docs (the
build-appsrepo, a Zola site). It covers the section structure, a title and description per page. Pages follow the Diátaxis model: tutorials, how-to guides, and explanation. Reference material stays in the existing top-level/reference/section and is linked to rather than duplicated, which is the one deliberate deviation from a strict four-quadrant layout inside Build apps section.Decisions
Two app architectures are covered, kept separate throughout. The first is the embedded local-first model: a Go app uses the app-sdk, embeds DefraDB, subscribes to Views, and queries data pushed to it over P2P. The second is the direct-query model: a TypeScript app sends signed GraphQL requests to a public Host over HTTP using
@shinzo/shinzohuband@shinzo/querysig, the same model Shinzo Studio uses. A third path, running your own Host as a private Direct Client, is signposted but not taught here because it belongs to the Run section.No billing or economics pages just yet. The
concepts/economics-of-viewsdraft stays a draft. Funding a query balance appears only as a minimal inline step where a tutorial cannot work without it, wrapped in a warning that metering details may change, since per-query metering is not finalized in the code.Existing pages restructured freely: moved, split, retitled, with aliases preserved so old URLs keep working.
All tutorials target the public testnet by default:
testnet.shinzo.network(EVM JSON-RPC on :8545, Cosmos REST on :1317, CometBFT on :26657, chain ID 91273001), with testnet tokens fromfaucet.shinzo.network. No tutorial requires the reader to run a Generator or a Host.What happens to existing pages
build/create-a-view/build/create-a-view/examples/build/build-an-app/build/query-data/build/concepts/views-for-builders/build/concepts/attestation-as-a-query-filter/build/concepts/economics-of-views/build/publish/New structure
Site plumbing, to be folded into the first page-building task:
config.toml, replace the two currentsection = "build"sidebar blocks with three groups: "Tutorials", "How-to guides", and "Explanation", listing the pages above in tree order. Pages are not auto-discovered, so nothing appears until it is listed.hrefpoints at/build/(the landing page) instead of/build/create-a-view/.aliaseson every moved page so old URLs (/build/query-data/,/views/examples,/views/overview,/guides, and friends) keep working.zola buildafter adding each page to confirm the site compiles.Shared instructions for page-building agents
Prepend this block to every page-building task:
You are writing one page for the Shinzo docs site (Zola) in
/mnt/host/build-apps. Conventions:+++lines withtitle,description, and optionalaliases. Add[extra]andmermaid = trueif the page includes a diagram.{% admonition(type="note"|"tip"|"warning") %} ... {% end %},{% mermaid() %} ... {% end %}. End each page with a## Need helpsection containing theneed_helpmacro; copy the exact usage from an existing page such ascontent/build/query-data/index.md.1.for every item and let Zola number them. Code blocks always declare a language. Shell output blocks use```output.config.tomlunder the correct[[extra.sidebar]]group, then runzola build.eth_getLogsor ABI field names are exempt. Bold any UI element the reader is told to interact with. "View" is capitalized. Clients are "Generator client" and "Host client"./mnt/host/other-repos/host-client,/mnt/host/other-repos/shinzohub,/mnt/host/other-repos/web,/mnt/host/other-repos/shinzo-view-creator,/mnt/host/other-repos/blog, plus the existing docs under/mnt/host/build-apps/content/understand/and/mnt/host/build-apps/content/reference/. The Go app-sdk is not checked out locally; rely ongithub.com/shinzonetwork/app-sdkand the existingcontent/build/build-an-app/index.mdfor its API. Confirm every export, command, and flag against source before writing it. Where a fact cannot be confirmed, flag it in your final report instead of guessing.Pages
Build apps (landing)
Path:
build/index.md. Diátaxis type: landing page, a deliberate deviation used only for orientation. Front-matter description: "Choose your path for building on Shinzo: query existing Views, create your own View, or build a local-first app."Tasks
content/build/index.mdinto a short orientation page, no more than about 60 lines of prose./understand/what-is-shinzo/and/understand/how-it-works/without re-explaining them.faucet.shinzo.network, and a note that no hardware is required.need_helpmacro on this page.Query your first View
Path:
build/tutorials/query-your-first-view/index.md. Diátaxis type: tutorial. Front-matter description: "Tutorial: query a live View on the Shinzo testnet from a TypeScript app. Discover a View, pick a Host, sign a request, and print results."Tasks
@shinzo/shinzohub,@shinzo/querysig, andviem. Create a client withshinzoHubTestnetfrom@shinzo/shinzohub/chains(chain ID 91273001, endpoints ontestnet.shinzo.network). Discover a View withlistViewsor via the Explorer atexplorer.shinzo.network, and a Host serving it withlistHosts(theendpoint_addressfield) andlistViewPoolsorgetPoolFor(a pool is active once it has at least 3 Hosts). Fund a query balance in one short step: get testnet tokens fromfaucet.shinzo.network, callfundQueryBalance({amount}), and wrap the step in a warning admonition saying billing details may change and no dedicated billing guide exists yet. Sign a GraphQL query withsign()from@shinzo/querysigand show the resultingextensionsobject (request_signature,nonce,query_hash,request_timestamp,pool_address). POST tohttps://<host-endpoint>/api/v0/graphqland print the rows.EventView-style collection withhash,from,to,blockNumber,event) as the concrete query so it composes with the output of "Create your first View"./mnt/host/other-repos/web/packages/shinzohub/README.mdandapi.md,/mnt/host/other-repos/web/packages/querysig/, and/mnt/host/other-repos/web/apps/studio/lib/pages/view/ui/view-playground.tsxfor the real query flow. Confirm every export name against the package source.need_helpwith client "Shinzo SDK" and the repohttps://github.com/shinzonetwork/web/issues.Create your first View
Path:
build/tutorials/create-your-first-view/index.md. Diátaxis type: tutorial. Front-matter description: "Tutorial: build, test, and deploy a Shinzo View with Viewkit, from install to querying it on the public testnet."Tasks
content/build/create-a-view/index.md, moving it to the new path and keepingaliases = ["/views/quickstart", "/views/install", "/build", "/build/create-a-view/"].shinzo-view-creator,make build, Wasmer runtime environment variables (macOS and Linux variants),viewkit view init,add query,add sdl,add lens(thedecode_loglens from the wasm-bucket URL),viewkit view test,viewkit wallet generate, deploy with--target local, verify in the DefraDB Playground, then deploy to the network.viewkit view deploy testdeploy --target devnet --rpc http://testnet.shinzo.network:8545/. First confirm in/mnt/host/other-repos/shinzo-view-creator/cli/view_deploy.gowhich--targetvalues exist and what each does. If the CLI'sdevnettarget is the right one for the public testnet chain (91273001), keep the flag but call the network "the public testnet" in prose and explain the flag name in a note admonition. Add a wallet-funding step (the faucet) before the network deploy, because registration is an on-chain transaction.viewkit view inspectoutput after every step. Collapse these into one fullinspectafter all components are attached./reference/components/viewkit/for the full command list,/reference/components/lens/for lenses.need_helpwith client "Viewkit", copied from the existing page.Build a local-first app
Path:
build/tutorials/build-a-local-first-app/index.md. Diátaxis type: tutorial. Front-matter description: "Tutorial: build a Go app that embeds DefraDB via the app-sdk, subscribes to a View, and queries pushed data locally with attestation filtering."Tasks
go mod initandgo get github.com/shinzonetwork/app-sdk. A minimalconfig.yamlwithshinzo.minimum_attestations: 1andlogger.development: truefor the tutorial. Start embedded DefraDB withdefra.StartDefraInstance(config, &defra.MockSchemaApplierThatSucceeds{})and deferClose. Define theViewstruct (name, query, sdl; reuse the View from "Create your first View" or a known public one) and callSubscribeTo. Wait for data, then query withdefra.QueryArray[MyStruct]. Addattestation.AddAttestationRecordCollectionand switch toattestation.QueryArrayWithConfiguredAttestationFilter. Run the program and watch rows arrive.GET http://testnet.shinzo.network:1317/shinzonetwork/host/v1/hosts, theconnection_stringfield) and defer the full mechanics to "Connect your app to a Host". If no canonical public bootstrap Host can be confirmed, flag it in your final report; this is a known open dependency.content/build/build-an-app/index.mdas the authority for API names, and keep its note that the "collection already exists" error is informational.need_helpwith client "app-sdk" and the repohttps://github.com/shinzonetwork/app-sdk/issues.Find Views and Hosts
Path:
build/how-to/find-views-and-hosts/index.md. Diátaxis type: how-to guide. Front-matter description: "How to discover registered Views, serving Hosts, and pools on the Shinzo network using the Explorer, Studio, the REST API, or the TypeScript SDK."Tasks
explorer.shinzo.network/shinzohubfor host and generator lists, with UI elements bolded. Studio: the view catalog atstudio.shinzo.network. REST:curlexamples againsthttp://testnet.shinzo.network:1317for/shinzonetwork/view/v1/views?include_data=true,/shinzonetwork/host/v1/hosts,/shinzonetwork/indexer/v1/indexers, and/shinzonetwork/pool/v1/views/{view_address}/pools; explain whatconnection_string(a libp2p multiaddr) andendpoint_address(the GraphQL URL) each mean. TypeScript:listViews,listHosts,getPoolFor, andgetNetworkUnitPricefrom the@shinzo/shinzohubsubpath exports.GET http://<host>:8080/registrationreturns the Host's DID,connection_string, andendpoint_address(source:/mnt/host/other-repos/host-client/pkg/server/registration.go)./reference/tools/.Connect your app to a Host
Path:
build/how-to/connect-to-a-host/index.md. Diátaxis type: how-to guide. Front-matter description: "How to connect an application to a Shinzo Host: P2P connection strings for embedded Go apps and GraphQL endpoints for direct-query TypeScript apps."Tasks
connection_string(link "Find Views and Hosts"), add it todefradb.p2p.bootstrap_peersin the app-sdk config as a comma-separated multiaddr in the form/ip4/<ip>/tcp/9171/p2p/<peerID>. Mention that bare IPs andip:portalso work because peer IDs are auto-discovered during the handshake (behavior confirmed in/mnt/host/other-repos/host-client/pkg/host/peer_discovery.go).endpoint_addressfrom the registry and targetPOST <endpoint>/api/v0/graphql. One billed query maps to one pool. Mention the 402 and 403 rejection shapes briefly, without a billing deep-dive.GET http://<host>:8080/health, which returns JSON when theAccept: application/jsonheader is set./mnt/host/other-repos/host-client/BUILD.mdfor ports (9181 GraphQL, 9182 playground, 9171 P2P, 8080 health),pkg/server/health.go, andpkg/acp/middleware.gofor error codes only.Query data
Path:
build/how-to/query-data/index.md. Diátaxis type: how-to guide. Front-matter description: "How to query Shinzo data with GraphQL: filters, ordering, nested documents, DocIDs, CIDs, and signatures."Tasks
content/build/query-data/index.mdto the new path and keepaliases = ["/hosts/examples", "/build/query-data/"].<Chain>__<Network>__prefix admonition and the Hostneed_helpmacro./api/v0/graphql. Same GraphQL language, different transport./reference/components/viewkit/for the filter-operator table instead of duplicating it, and to "Verify data with signatures and CIDs" for the verification material.View recipes
Path:
build/how-to/view-recipes/index.md. Diátaxis type: how-to guide, organized as a recipe collection. Front-matter description: "How to build common Views: decode event logs, filter by contract, decode multiple event types, transaction Views, and editing or rolling back a View."Tasks
content/build/create-a-view/examples/index.mdto the new path and keepaliases = ["/views/examples", "/build/create-a-view/examples/"].http://34.29.171.79:8545/with the public testnet endpointhttp://testnet.shinzo.network:8545/./reference/components/lens/consistently. Keep thedecode_logvsdecode_log_strtip; it reflects real behavior documented in the lens reference.need_helpmacro. Link "Create your first View" and "Write and test a custom lens".Create and deploy Views in Shinzo Studio
Path:
build/how-to/use-shinzo-studio/index.md. Diátaxis type: how-to guide. Front-matter description: "How to create, deploy, and query Views from your browser with Shinzo Studio, without installing the CLI."Tasks
studio.shinzo.network, connect a wallet (switch to the Shinzo testnet, chain ID 91273001), create a View (query, SDL, and a lens from the catalog: decode-log, ERC-20 transfers, ERC-20 account balances), deploy it (wallet-signed registration; registration completes asynchronously and Studio polls until the status is "registered"), then query it in the built-in GraphiQL playground by picking a Host that is a member of the View's pool./mnt/host/other-repos/web/apps/studio/, in particularlib/entities/view/model/use-deploy-lens.tsfor the deploy flow,lib/entities/lens/model/catalog.tsfor the lens catalog, andlib/pages/view/ui/view-playground.tsxfor querying. Describe behavior as implemented and flag anything uncertain.Write and test a custom lens
Path:
build/how-to/write-a-lens/index.md. Diátaxis type: how-to guide. Front-matter description: "How to author a WebAssembly lens with the AssemblyScript SDK, test it locally, and attach it to a View."Tasks
/reference/components/lens/for the catalog and frame custom lenses as the fallback when the transform you need does not exist.@shinzo/lenses(AssemblyScript):createLens(fn)for generic JSON transforms andcreateEvmLens(fn, Args, eventName, ..., ABI)for log decoding, usingdecoded.getArg(...)andctx.args. Show one minimal complete lens, such as normalizing an address field or dropping events below a threshold. Keep it deterministic.expectEvmLens(...).withTokenAddress(...).withLog(...).run()andloadWasmBytesfrom@shinzo/lenses/testing, thenvalidateView()andbundleView()from@shinzo/lenses/view(or/view/node) before registration, thenviewkit view testwith a local--pathWASM for the full-View check./reference/components/lens/: no clock, randomness, network, filesystem, or floats. Note the runtimes in one admonition (wazero in Hosts, wasmer for Viewkit's local testing).sourcenetwork/lensSDK, roughly 200 to 300 KB output versus roughly 73 KB for AssemblyScript) in one paragraph and link out./mnt/host/other-repos/web/packages/lenses/. Confirm all exports against the source.Subscribe to Views with the app-sdk
Path:
build/how-to/subscribe-to-views/index.md. Diátaxis type: how-to guide. Front-matter description: "How to configure and start an embedded DefraDB instance, subscribe to Views, and receive pushed data in a Go application."Tasks
content/build/build-an-app/index.md, which stays the authority for API names: config viaconfig.LoadConfigwithfile.FindFileversus the default config; theshinzo.minimum_attestationsandlogger.developmentkeys; theSchemaAppliervariants (SchemaApplierFromFile,SchemaApplierFromProvidedSchema,MockSchemaApplierThatSucceeds) and when each applies, including the case where the app uses DefraDB for non-Shinzo data too;defra.StartDefraInstanceand clean shutdown.Viewstruct (onlyname,query, andsdlmatter),SubscribeTo, the informational "collection already exists" error, and what a subscription actually does: it adds the View's SDL locally and registers the collection as a passive-replication topic so Hosts push data for it.defra.QuerySingleanddefra.QueryArraywith typed structs.need_helpwith client "app-sdk".Configure attestation thresholds
Path:
build/how-to/configure-attestation-thresholds/index.md. Diátaxis type: how-to guide. Front-matter description: "How to require a minimum number of Generator attestations before query results are returned in your app."Tasks
build-an-apppage:attestation.AddAttestationRecordCollection(ctx, defra, viewName), which pushesAttestationRecord_<View>documents alongside the View; the "collection already exists" caveat; the config-wide default viashinzo.minimum_attestations; and the four query helpers, meaning the configured variants (QuerySingleWithConfiguredAttestationFilter,QueryArrayWithConfiguredAttestationFilter) versus the per-call variants (QuerySingleWithAttestationFilter,QueryArrayWithAttestationFilter).AttestationRecordcontains (attested_doc,source_doc,CIDs,doc_type, and thevote_countCRDT pcounter) and what happens when your threshold is higher than the number of available attestations./understand/core-concepts/attestation/.Verify data with signatures and CIDs
Path:
build/how-to/verify-data/index.md. Diátaxis type: how-to guide. Front-matter description: "How to verify who signed your data and navigate attestations, commits, and documents via CIDs."Tasks
content/build/query-data/index.md:_version { cid signature { identity value type } }on any document;_commits(cid: ...)for commit metadata andES256Ksignatures;AttestationRecordqueries; resolving a CID to its document; and a brief mention of block-levelBlockSignatureand snapshot signatures with a link to/understand/core-concepts/attestation/./understand/core-concepts/privacy/for the roadmap framing. Do not go deep.Use your own infrastructure
Path:
build/how-to/use-your-own-infrastructure/index.md. Diátaxis type: how-to guide, deliberately a pointer page. Front-matter description: "How to run your own Host as a private Direct Client for your app: the strongest privacy and control, at the cost of operating a node."Tasks
/understand/core-concepts/privacy/: a standard private setup (public ShinzoHub for Views, your own Generator as the only bootstrap peer, registration skipped) versus a fully air-gapped setup (emptyhub_base_url, contacts nothing but your Generator)./run/run-a-host/install/,/run/run-a-host/private-hosts/, and/run/run-a-generator/. This page is the bridge, not the guide./mnt/host/other-repos/blog/query-privacy.md): running your own Host and querying it directly is the only configuration today where no third party can observe your queries.The Shinzo app model
Path:
build/explanation/the-app-model/index.md. Diátaxis type: explanation. Front-matter description: "How Shinzo inverts the traditional data-API model: you define the API, and pre-processed data is pushed to your application as a verifiable local cache."Tasks
build-an-apppage: the centralized-provider model (choose from fixed APIs, provider-side caching, your own cache on top, per-query pricing, webhook surprises) versus Shinzo's inversion (you define the API as a View, pre-processed results are pushed to you, you query your local replica as often as you like, and you pay for access to transformed data rather than per query). Keep payment discussion to one sentence at most, since there are no billing pages./understand/how-it-works/first and do not duplicate its diagram; angle yours on the application boundary.Choosing an app architecture
Path:
build/explanation/choosing-an-architecture/index.md. Diátaxis type: explanation. Front-matter description: "Trade-offs between the three ways to build on Shinzo: direct signed queries to Hosts, an embedded local-first client, or your own private Host."Tasks
@shinzo/querysig), embedded (the app-sdk), and Direct Client (your own Host). Use the "privacy posture is a dial" framing from/mnt/host/other-repos/blog/query-privacy.md: privacy features are opt-in layers, not a global switch.Views for builders
Path:
build/explanation/views-for-builders/index.md. Diátaxis type: explanation. Front-matter description: "What a Shinzo View is: a versioned bundle of query, SDL, and lenses, and how Viewkit turns primitive data into reusable data APIs."Tasks
content/build/concepts/views-for-builders/index.mdto the new path and keepaliases = ["/view-creator", "/views", "/views/overview", "/build/concepts/views-for-builders/"]./reference/components/viewkit/and/reference/components/lens/links.Attestation as a query filter
Path:
build/explanation/attestation-as-a-query-filter/index.md. Diátaxis type: explanation. Front-matter description: "Why attestation thresholds are a per-query trust dial, and how pushed attestation records let each app set its own bar for accepting data."Tasks
content/build/concepts/attestation-as-a-query-filter/, moving it underexplanation/and keeping an alias for the old path.AttestationRecords let trust be evaluated at query time, howvote_countas a CRDT pcounter merges attestations from multiple Hosts without conflicts, segmentation (you only receive attestation records for Views you subscribe to), and why different apps set different bars. Keep the framing that this is a query-time filter, not a system-wide setting./understand/core-concepts/attestation/for the platform-level picture without duplicating it.build-an-apppage, ADRs 02 and 03 in/mnt/host/other-repos/host-client/adr/, and/mnt/host/build-apps/content/understand/core-concepts/attestation/.