Arete documentation
Workflow
For the complete documentation index optimized for AI agents, see llms.txt or llms-full.txt. A markdown version of this page is available by appending.mdto the URL or sendingAccept: text/markdown.
For AI agents: the documentation index is at llms.txt (full corpus: llms-full.txt). A markdown source for this page is /building-stacks/workflow.md.
Most applications should begin with published Program SDKs and existing live views. Turn to custom authoring only when the catalog doesn’t offer the app-shaped view you need.
Search the registry and open the exact descriptor before starting custom work:
a4 explore catalog --query "<intent>" --jsona4 explore catalog program <slug> --jsonIf a published package already provides the required capabilities, install it
instead. The advanced Rust path below assumes you have the exact local IDL for
the program. Inspect that file with a4 idl summary, a4 idl search, and the
IDL CLI reference before mapping it.
For an uncataloged or private program, supply the canonical IDL from the program’s own build or release artifacts, upstream repository, or published SDK package. An on-chain Anchor IDL is suitable only when the program intentionally publishes one and you verify its program address and provenance. If you cannot obtain a trustworthy IDL, ask the program owner rather than reconstructing one from explorer output.
This page documents the advanced Rust authoring path: define a live model, compile portable artifacts, deploy an exact StackManifest, and install the resulting SDK.
Write Rust
Define entities using #[arete] macro
Build Stack
Emit ProgramSpec, LiveSpec, and StackManifest
Deploy via CLI
Deploy the exact manifest with the CLI
Connect from App
Use generated SDK to stream
Step 1: Write Your Stack Definition
Section titled “Step 1: Write Your Stack Definition”A stack definition is a Rust module that maps structure from the IDL into a rich, queryable state ready to consume in your application layer. Using Arete’s expressive DSL, you define entities, field mappings, aggregations, computed fields, relationships, and more — all in declarative Rust syntax.
use arete::{arete, Stream};
#[arete(idl = "my_program.json")]pub mod ore_stack { #[entity] #[derive(Stream)] pub struct OreRound { #[map(RoundState::round_id, primary_key)] pub round_id: u64,
#[map(RoundState::motherlode)] pub motherlode: u64,
#[map(RoundState::difficulty)] pub difficulty: u64, }}The Rust code is purely declarative—you’re describing what data you want, not how to fetch it. Arete handles all the account parsing, event processing, and state management.
→ Stack Definitions — Learn the full DSL syntax
Step 2: Build the Stack
Section titled “Step 2: Build the Stack”When you compile your Rust project, Arete macros transform the definition directly into three explicit, content-addressed artifact kinds:
- ProgramSpec — endpoint-free program identity, public IDL, accounts, instructions, and PDAs.
- LiveSpec — entity, mapping, handler, resolver, and view behavior over exact ProgramSpecs.
- StackManifest — the client composition: aliased LiveSpecs, ProgramSpecs, and selected views. It contains no deployment URL.
cargo buildAfter building, you’ll find the generated specification in .arete/:
my-stack/├── src/lib.rs├── Cargo.toml└── .arete/ ├── ore.program-spec.json ├── OreStack.live-spec.json └── OreStack.stack-manifest.jsonThe DSL can also generate only the program layer. An IDL-only module with no
entities emits ProgramSpecs, a zero-live StackManifest, and a program-only
spec() containing generated account readers:
#[arete(idl = ["my_program.json"])]pub mod my_program {}
let spec = my_program::spec();The program-only spec() is suitable for Server::builder().spec(spec) with
Program Read HTTP routes and does not start projection work unless you enable a
live runtime.
To combine independently built live packages, assign each LiveSpec a stable alias and optionally select an exact ordered view allowlist:
a4 stack compose --name my-app \ --live markets=./markets.live-spec.json \ --live positions=./positions.live-spec.json \ --artifact-dir . \ --selected-view markets=Market/list \ --selected-view positions=Position/state \ --output ./MyApp.stack-manifest.jsonOmit --selected-view to expose every view from each supplied LiveSpec.
Step 3: Deploy with the CLI
Section titled “Step 3: Deploy with the CLI”The Arete CLI (a4) handles hosted deployment. A single command submits one
exact StackManifest. The control plane resolves its ProgramSpecs to immutable
Program Releases, prepares each aliased LiveSpec, and creates deployment and
endpoint bindings.
# Initialize project config (creates arete.toml)a4 init
# Deploy your exact manifesta4 up .arete/OreStack.stack-manifest.jsonOn success, you’ll receive a WebSocket URL:
✔ Stack pushed (v1)✔ Build completed🚀 Deployment and endpoint bindings are ready→ CLI Reference — Full command documentation
Step 4: Generate SDK and Connect
Section titled “Step 4: Generate SDK and Connect”Generate a typed SDK from the same manifest you reviewed and deployed:
a4 sdk create --manifest .arete/OreStack.stack-manifest.json --tsa4 sdk create --manifest .arete/OreStack.stack-manifest.json --rustThis creates local source containing the selected stack definition, entities,
views, and independent program SDKs. a4 sdk create does not publish an npm
package or Rust crate; package publication is a separate operator action.
For composed manifests, each --live alias=path keeps its own live transport.
Program Read bindings are selected per program, while chain and transaction
transports are supplied independently. A client must not derive any of these
endpoints from another. Import the generated source in your application:
npm install @usearete/react @usearete/sdk zod@usearete/react installs zustand itself. Hosted browser connections require the publishable key shown below even for read-only use; a wallet is not required to view data.
import { AreteProvider, useArete } from "@usearete/react";import { ORE_STREAM_STACK } from "./generated/ore-stack"; // Generated in Step 4
const publishableKey = import.meta.env.VITE_ARETE_PUBLISHABLE_KEY;if (!publishableKey) throw new Error("VITE_ARETE_PUBLISHABLE_KEY is required");
// Wrap your app<AreteProvider stack={ORE_STREAM_STACK} auth={{ publishableKey }}> <App /></AreteProvider>;
// In your componentconst stack = useArete(ORE_STREAM_STACK);const { data: rounds } = stack.views.OreRound.list.use();npm install @usearete/sdkimport { Arete } from "@usearete/sdk";import { ORE_STREAM_STACK } from "./generated/ore-stack"; // Generated in Step 4
const a4 = await Arete.connect(ORE_STREAM_STACK, { auth: { publishableKey: process.env.ARETE_PUBLISHABLE_KEY! },});
for await (const round of a4.views.OreRound.list.use()) { console.log("Round updated:", round);}use a4_sdk::prelude::*;use ore_stack::{OreStack, OreRound}; // Generated in Step 4
#[tokio::main]async fn main() -> anyhow::Result<()> { // Connect to your deployed stack let a4 = Arete::<OreStack>::connect().await?;
// Stream updates via typed views let mut stream = a4.views.ore_round.latest().listen();
while let Some(round) = stream.next().await { println!("Round #{:?}: motherlode={:?}", round.id.round_id, round.state.motherlode); }
Ok(())}Share the generated SDK with your team or publish it manually — anyone with the SDK can connect to the selected bindings when authorized. Hosted deployment does not prescribe a DNS provider; operators can hand returned endpoint bindings to their chosen DNS/CDN provider.
→ Your First Stack — Complete tutorial with working code
Next Steps
Section titled “Next Steps”| Goal | Page |
|---|---|
| Understand the DSL in depth | Stack Definitions |
| Set up your development environment | Installation |
| Build a complete example | Your First Stack |
| Learn all available macros | Macro Reference |
| Master aggregation strategies | Population Strategies |