Arete documentation
CLI Command Reference
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 /cli/commands.md.
Complete reference for the Arete CLI (a4).
Your agent runs most of these commands for you. The ones you are most likely to
type yourself are a4 init to set a project up, a4 doctor to check that it is
healthy, and a4 auth signup to create an account.
Installation
Section titled “Installation”Prebuilt, signed binary. No Rust toolchain or account required.
curl -fsSL https://arete.run/install.sh | sh # macOS / Linuxirm https://arete.run/install.ps1 | iex # Windows PowerShellnpx @usearete/a4 install # if you prefer npm (same as npm install -g @usearete/a4)The bootstrapper downloads the release asset for your platform plus checksums.txt and its minisign signature, verifies the SHA-256 (and the signature when minisign is available), then hands off to a4 self install, which copies the binary to ~/.local/bin/a4 (%USERPROFILE%\.local\bin\a4.exe on Windows), writes ~/.arete/receipt.json, adds the directory to your shell profile, and prints these two lines last on stdout:
A4_BIN=/Users/x/.local/bin/a4export PATH="$HOME/.local/bin:$PATH"Shells that were already open captured PATH before the install. Use the A4_BIN path or run the export line in that shell. If another a4 is earlier on PATH (~/.cargo/bin/a4, an npm shim), the installer warns and names the file; it never deletes it.
Installer arguments (sh -s -- [VERSION] [--no-modify-path] [--install-dir DIR]):
| Argument / variable | Description |
|---|---|
VERSION, A4_VERSION | Install a specific version instead of the latest |
--install-dir <DIR>, A4_INSTALL_DIR | Install directory (default ~/.local/bin; XDG_BIN_HOME is honoured) |
--no-modify-path, A4_NO_MODIFY_PATH=1 | Do not edit shell profiles or the Windows user PATH; CI also skips it |
Then, in a project:
a4 init -y # arete.toml, AGENTS.md block, CLAUDE.md import, skills, MCP configa4 doctor --json # ready when the JSON status is "ok"a4 explore --json # live data, no account neededBuilding from source
Section titled “Building from source”Only for unreleased builds. A Cargo-built binary is not managed by the installer: a4 self update refuses it and tells you to run cargo install a4-cli --force instead.
cargo install a4-cliGlobal Options
Section titled “Global Options”| Option | Description |
|---|---|
--config, -c <path> | Path to arete.toml (default: arete.toml) |
--json | Output as JSON on stdout; logs go to stderr. Every object has schemaVersion |
--yes, -y | Accept defaults; never prompt |
--non-interactive | Never prompt; a missing required input is an error naming the flag to pass |
--verbose | Enable verbose output |
--api-url <url> | Override the API endpoint |
--help, -h | Show help |
--version, -V | Show version |
--completions <SHELL> | Generate shell completions (bash, zsh, fish, powershell, elvish) |
Prompts are also disabled when A4_NON_INTERACTIVE=1 or CI is set, or when stdin is not a terminal. No command ever waits on stdin in those cases.
Exit codes: 0 success (including warnings), 1 command failure, 2 usage error, 10 update available (a4 self update --check only).
JSON output and key spelling
Section titled “JSON output and key spelling”The CLI reads API responses whose multi-word keys are snake_case or camelCase. A JSON object may use either spelling of a key but not both: the CLI rejects a response that carries both as a duplicate field.
--json output depends on how the CLI models the data:
- Modeled fields keep the same keys whichever spelling the API sends. For example,
a4 stack list --jsonanda4 build status --jsonprintwebsocket_urlandcreated_at.a4 explore --jsonkeeps its own camelCase keys. - Objects the CLI does not model pass through with the keys the API sent, so their inner keys can be either spelling. This applies to
websocket_auth,http_authandprovenanceina4 build status --json,knowledgeina4 explore --json, and everythinga4 know --jsonprints.
Scripts that read inside those pass-through objects should accept both spellings.
Quick Reference
Section titled “Quick Reference”| Command | Description |
|---|---|
a4 create [name] | Scaffold a new app from a template |
a4 init | Set up the project for Arete and coding agents |
a4 doctor | Check install, project, auth, agents |
a4 self install | Finish installing the a4 binary |
a4 self update / a4 upgrade | Update a4 in place |
a4 self uninstall | Remove a4 |
a4 mcp | Run the stream MCP server (stdio) |
a4 auth signup | Register an agent account |
a4 login / a4 auth login | Save an API key (accounts are free) |
a4 program build <idl> | Build a portable ProgramSpec |
a4 stack compose | Compose live views and program SDKs |
a4 sdk describe <alias> | Print an installed SDK’s reference (views, fields, reads) |
a4 sdk create --manifest ... --ts | Generate a TypeScript SDK offline from a StackManifest |
a4 sdk create --manifest ... --rust | Generate a Rust SDK from a StackManifest |
a4 sdk create --program-spec ... --rust | Generate a Rust (or --python) program SDK from a ProgramSpec |
a4 sdk create --manifest ... --rust --program-extensions <program>=<bundle> | Embed a program’s own bundle in a Rust (or --python) stack SDK |
a4 up <manifest> | Deploy one exact StackManifest |
a4 up <alias> | Deploy an installed stack |
a4 protocol init [dir] | Scaffold a protocol project (a tip jar with automations) |
a4 protocol deploy [dir] | Upload a built protocol and deploy it privately |
a4 protocol actions [protocol|deployment] --wallet <pubkey> | What a wallet can do now on a deployment |
a4 dev up | Develop against your cloud dev environment, redeploying on change |
a4 dev status|list|checkpoint|rebase|fund|warp|… | Manage and drive the dev environment |
a4 protocol search [query] | Search the callable protocols listed on Arete |
a4 protocol show <slug> | One listed protocol: trust tier, steps, install command |
a4 protocol request-listing | Ask for your deployment to be listed |
a4 protocol listing-status | Your deployment’s listing state |
a4 protocol webhook add|list|remove|test | The webhook endpoints that receive your deployment’s events |
a4 squads status|list|attach | Your account’s Squads multisigs (set them up on the dashboard) |
a4 protocol squads proposer|status [target] | Bring your own Squads multisig: the proposer and its status |
a4 status | Show project overview |
a4 stack list | List deployed stacks |
a4 telemetry status | Show telemetry status |
a4 explore, a4 explore stacks | Discover installable stacks |
a4 explore programs | Discover installable standalone programs |
a4 explore stack <ref> | Inspect an exact stack install descriptor |
a4 explore program <ref> | Inspect an exact program install descriptor |
a4 get <Entity>/<view> --stack <ref> | Read a view’s current entities once, as JSON |
a4 stream <Entity>/<view> --stack <ref> | Stream a view’s live updates |
a4 know search --query <intent> | Search the knowledge layer by intent |
a4 know protocol <slug> | Curated knowledge for one protocol |
a4 know program <slug> | Curated annotations for one program |
a4 know recipe <slug> | One cross-protocol recipe |
a4 know concepts | Concept and category vocabularies |
Create a New App
Section titled “Create a New App”a4 create [name]
Section titled “a4 create [name]”Scaffold a new Arete project from a template. This is the fastest way to get started.
# Interactive — prompts for name and templatenpx @usearete/a4 create
# With project namenpx @usearete/a4 create my-app
# A protocol with a React app and an automations servernpx @usearete/a4 create my-app --template protocol-appAvailable templates:
| Template | Aliases | Description |
|---|---|---|
protocol | A protocol: the a4 protocol init tip jar and its automations | |
protocol-app | The protocol, plus a React app on its client (dev-only tools gated on the dev environment) and an automations server with a Privy signer | |
react-ore | ore-react | ORE mining rounds viewer (React + Vite) |
rust-ore | ore-rust | ORE mining rounds client (Rust + Tokio) |
typescript-ore | ore-typescript, ts-ore, ore-ts | ORE mining rounds client (TypeScript CLI) |
Options:
| Flag | Description |
|---|---|
--template <name> | Skip interactive selection |
--offline | Use cached templates only |
--force-refresh | Clear template cache and re-download |
--skip-install | Don’t run npm install automatically |
The protocol templates are built into the CLI; they install the System
Program from the registry, so they need your login. The ORE templates are
downloaded from GitHub releases and cached in ~/.arete/templates/.
Project Setup
Section titled “Project Setup”a4 init
Section titled “a4 init”Set up the current directory for Arete and for the coding agents that work in it.
a4 init -y # the agent running it + agents with project configa4 init -y --json # machine-readable reporta4 init -y --dry-run # report what would change, write nothinga4 init -y --global # skills and MCP config for your user, not the projecta4 init -y --agents cursor,codex # explicit agent list (also: all | none)a4 init -y --no-skills --no-mcp # manifest and AGENTS.md onlyWhat it writes (every item is an upsert and reports created | updated | unchanged | skipped(reason)):
| Item | Path | Notes |
|---|---|---|
| Manifest | arete.toml | Created if absent; left untouched if present unless --force, which rewrites only [project]. Name from --name or the directory basename |
| Auth profile | .arete/auth.toml | Project scope only. Non-secret default selecting only the restricted agent profile; a repository cannot select human |
| Agent guidance | AGENTS.md | A managed block between <!-- BEGIN:arete v2 --> and <!-- END:arete -->; content outside the markers is never touched |
| Claude Code bridge | CLAUDE.md | Created as @AGENTS.md, or that line is inserted first if the file exists |
| Gemini context | .gemini/settings.json | context.fileName gains AGENTS.md (Gemini CLI only) |
| Skills | per agent, e.g. .claude/skills/, .agents/skills/ | Runs npx -y skills add AreteA4/skills --skill '*' --agent <ids> -y. skipped(npx not found) without Node; the fix is printed |
| MCP config | per agent (table below) | Two servers: arete (stdio, a4 mcp) and arete-docs (https://docs.arete.run/mcp). Only these two keys are set; the rest of the file is preserved |
Options:
| Flag | Description |
|---|---|
-y, --non-interactive | Never prompt |
--json | JSON report (below) |
--dry-run | Same report with dryRun: true and would-* statuses; writes nothing |
--force | Rewrite the [project] block of an existing arete.toml |
--name <project> | Project name (default: directory basename) |
--agents <list|all|none> | Agents to configure (default: env or project signal) |
--global | Install skills and MCP config for your user instead of the project |
--no-manifest, --no-agents-md, --no-skills, --no-mcp | Skip a writer |
--skills-ref <git ref> | Skills version to install (default main) |
Agent detection. An environment variable set by the agent running the command wins over project signals, which win over home-directory signals. Without --agents, init configures the agents detected by environment variable or project config. Agents found only in the home directory are listed under alsoFound (“also found; add with a4 init --agents <id>”) and not configured. The suggested command adds --global for agents whose MCP config is global only (Windsurf, Cline), and after a --global run for every agent except those whose MCP config is project only (VS Code, Roo). If no agent has an environment or project signal and --agents is absent, init still writes the agent-independent set (arete.toml, AGENTS.md, CLAUDE.md, .agents/skills, .mcp.json) and adds a warning; it does not fail.
| Agent | Project signal | MCP file (project / --global) |
|---|---|---|
claude-code | .claude/, CLAUDE.md, .mcp.json, CLAUDECODE=1 | .mcp.json / ~/.claude.json |
cursor | .cursor/ | .cursor/mcp.json / ~/.cursor/mcp.json |
vscode | .vscode/ | .vscode/mcp.json / — |
copilot-cli | .github/copilot-instructions.md | .mcp.json / ~/.copilot/mcp-config.json |
codex | .codex/ | .codex/config.toml / ~/.codex/config.toml |
opencode | opencode.json, opencode.jsonc, .opencode/ | opencode.json / ~/.config/opencode/opencode.json |
gemini-cli | .gemini/ | .gemini/settings.json / ~/.gemini/settings.json |
windsurf | .windsurf/ | — / ~/.codeium/windsurf/mcp_config.json |
cline | .clinerules/ | — / ~/.cline/mcp.json |
zed | .zed/ | .zed/settings.json / ~/.config/zed/settings.json |
amp | .amp/ | .amp/settings.json / ~/.config/amp/settings.json |
kiro | .kiro/ | .kiro/settings/mcp.json / ~/.kiro/settings/mcp.json |
roo | .roo/ | .roo/mcp.json / — |
goose | .goose/ | .goose/config.yaml / ~/.config/goose/config.yaml |
Per-host MCP shapes are listed on the MCP Server page. The command is the absolute path from the install receipt when one exists, so GUI hosts that do not inherit your shell PATH still find it.
--json output:
{ "schemaVersion": 1, "dryRun": false, "detectedAgents": [{ "id": "claude-code", "how": "env" }, { "id": "cursor", "how": "home" }], "selectedAgents": ["claude-code"], "alsoFound": [{ "id": "cursor", "fix": "a4 init --agents cursor" }], "results": [ { "item": "arete.toml", "status": "created", "path": "arete.toml" }, { "item": "agents-md", "status": "updated", "path": "AGENTS.md" }, { "item": "claude-md", "status": "unchanged", "path": "CLAUDE.md" }, { "item": "skills", "status": "skipped", "reason": "npx not found", "fix": "npx skills add AreteA4/skills" }, { "item": "mcp:claude-code", "status": "created", "path": ".mcp.json" } ], "warnings": [], "next": ["a4 doctor --json", "a4 explore --json"]}init is idempotent: running it again changes no file and reports every item as unchanged. Exit 1 only if a writer errored ("status": "error").
a4 doctor
Section titled “a4 doctor”Read-only check of everything init writes plus the environment.
a4 doctora4 doctor --jsona4 doctor --summary # the overall status first, then only what needs attentiona4 doctor --fix # re-run the init writers for every agents.* warning, then re-checkWith --summary, checks lists only the checks that need attention: warn,
fail, unknown, and info checks that carry a fix. JSON adds okCount
and infoCount (informational checks with nothing to do), which are left out;
text output starts with the status line.
| Check id | What it verifies | On failure |
|---|---|---|
cli.version | Install receipt present; current version vs latest (2 s timeout) | warn: a4 self update (info when offline) |
cli.install | Receipt binary is the running executable; no a4 shadowing it on PATH | warn with the shadowing path |
cli.path | Install directory is on PATH | warn: prints the export PATH=… line |
project.manifest | arete.toml parses | fail: a4 init / a4 config validate |
project.lock | arete.lock is fresh | warn: a4 install |
project.auth-profile | .arete/auth.toml selects only the restricted agent profile | warn/fail: a4 doctor --fix |
sdk.runtime | Installed TypeScript runtime matches the generated SDKs (see below) | warn with an npm install line; fail only for an extensionApi mismatch |
auth.credentials | Key present for the active API URL | info: a4 auth signup (not needed to explore) |
auth.whoami | Credentials are accepted by the server | fail: a4 auth login --key … |
account.plan | The account’s plan and dev environment tier | unknown when the server cannot say |
account.<surface> | One per surface the account can or can’t use (see below) | info with the reason and the unlock; warn if arete.toml uses the surface |
probe.program-read | One Program Read existence check for the first registry program in arete.toml | warn with the HTTP status and error code; retryable failures say so |
probe.chain-read | One chain account read through the gateway for the same program | warn with the HTTP status and error code; retryable failures say so |
net.api | https://api.arete.run reachable | fail |
net.docs-mcp | https://docs.arete.run/mcp reachable | warn |
tools.node | npx on PATH (skills only) | info |
tools.rust | cargo on PATH (authoring only) | info; warn if arete.toml has [authoring] |
agents.detected | Detected agents | info |
agents.<id>.mcp | Both MCP servers present with the expected shape | warn: a4 doctor --fix |
agents.<id>.skills | All six Arete workflow skills installed for that agent | warn: npx skills add AreteA4/skills --agent <id> |
agents.agents-md | AGENTS.md block present and current (v2) | warn: a4 doctor --fix |
agents.claude-md | CLAUDE.md imports @AGENTS.md (Claude Code only) | warn |
agents.gemini-context | Gemini context.fileName includes AGENTS.md (Gemini CLI only) | warn |
agents.codex-trust | Project trusted in ~/.codex/config.toml (Codex only) | info |
--json output:
{ "schemaVersion": 1, "status": "ok", "checks": [{ "id": "cli.version", "status": "ok", "detail": "0.13.0 (latest)", "fix": null }]}status is ok, warn, unknown or fail; each check is ok | warn | fail | info | unknown. unknown means a check could not be decided (for example, the account details could not be read); the overall status is unknown when that happens and nothing warns or fails. Exit 0 for ok, warn and unknown, 1 for fail. --fix never touches auth, account, network, or tool checks. Human output is one line per check followed by the list of fixes.
The account.* checks read what your account can use from GET /api/auth/entitlements with the stored key, and are skipped when no key is configured. Surfaces are program_read, chain_read, transaction_inspect, transaction_send, protocol_prepare, protocol_submit, deploy_stack, create_protocol and dev_environments; the check id uses dashes (account.transaction-send). A surface you can’t use is reported with the server’s reason and how to unlock it, not failed: reads and subscriptions work without transaction access. It is a warn when arete.toml uses it: registry program dependencies need program_read (path, workspace and IDL programs read through your local stack), a protocol or protocol dependency needs protocol_prepare and protocol_submit, a [protocol] section also needs create_protocol, a [dev] section needs dev_environments, and [authoring] stacks need deploy_stack. account.dev-environments shows your dev tier with its environment limit and usage, and account.create-protocol shows how many of your plan’s active protocol deployments are in use (at the limit it says so, with how to raise it). APIs without the entitlements route fall back to account.transactions and account.deploy, read from GET /api/auth/me.
The probe.* checks make one real read each, through the first registry program in arete.toml, and report the status and error code they got. The Program Read probe asks whether an account of the program’s first IDL account type exists at a fixed unused address; the chain probe reads the program account. A 429, a 5xx or an error the server marks retryable is an Arete-side or transient failure, not your plan; retry later. They are skipped without a registry program or when your plan doesn’t include the surface.
sdk.runtime reads the @usearete/* packages that each TypeScript output of arete.toml resolves from node_modules. It warns when @usearete/sdk, @usearete/react, and the adapters are not all one version, when more than one copy of @usearete/sdk is installed (for example node_modules/@usearete/react/node_modules/@usearete/sdk), when @usearete/sdk is missing, and when the installed runtime differs from the a4 version that generated the code. It fails only when a generated extension declares an extensionApi that differs from the installed @usearete/sdk’s, because that code cannot run. It is info (not applicable) when the project has no TypeScript outputs or no node_modules.
a4 config validate
Section titled “a4 config validate”Validate your configuration.
a4 config validateManaging the Binary
Section titled “Managing the Binary”a4 self install
Section titled “a4 self install”Finish installing the binary that is currently running. The bootstrappers (install.sh, install.ps1, npx @usearete/a4 install) call this for you; run it yourself only for a manually downloaded release asset.
a4 self install [--install-dir <DIR>] [--no-modify-path] [--source <sh|ps1|npm|manual>] [--checksums <FILE> --signature <FILE>] [--force] [--json]| Flag | Description |
|---|---|
--install-dir <DIR> | Target directory (else A4_INSTALL_DIR, XDG_BIN_HOME, ~/.local/bin) |
--no-modify-path | Skip shell-profile / Windows PATH edits (also A4_NO_MODIFY_PATH=1 or CI) |
--checksums <FILE> --signature <FILE> | Verify the minisign signature over checksums.txt and the binary’s SHA-256 before installing; omitted for manual installs ("verified": false in the receipt) |
--source <name> | Recorded in the receipt |
--force | Copy even when the target is already this binary (a re-run normally skips the copy) |
Writes ~/.arete/receipt.json (version, binary, installDir, platform, source, verified, modifyPath, installedAt), adds ~/.local/bin to ~/.profile and your shell’s rc file (or HKCU\Environment\Path on Windows, and $GITHUB_PATH in Actions) when it is not already there, and always ends stdout with the A4_BIN= and export PATH= lines. With --json the receipt plus pathModified and shadowedBy precede them.
a4 self update
Section titled “a4 self update”Replace the installed binary with a newer (or an explicitly chosen) release. a4 upgrade is an alias with identical arguments.
a4 self update # latesta4 self update 0.14.0 # specific version (downgrades allowed when explicit)a4 self update --check # exit 10 if an update is available, 0 if currenta4 self update --check --json # {"current","latest","updateAvailable"}a4 self update --dry-run # download and verify, print the plan, change nothingThe download is verified (SHA-256 and the minisign signature; mandatory here) before the binary at the receipt path is swapped in place and the receipt updated. Requires the install receipt: a Cargo-built a4 gets a4 was not installed by the Arete installer and must be rebuilt with cargo install a4-cli --force.
Once a day, when stderr is a terminal, a4 prints a4 0.14.0 is available (you have 0.13.0). Run: a4 self update after a command. Set A4_NO_UPDATE_CHECK=1 to disable this notice; it is never shown under CI, with --json, or for self, upgrade, mcp, and stream. There is no background auto-update.
a4 self uninstall
Section titled “a4 self uninstall”a4 self uninstall [--json]Removes the binary, the receipt, and the PATH lines self install added. Leaves ~/.arete/credentials.toml and prints what it left behind.
MCP Server
Section titled “MCP Server”a4 mcp
Section titled “a4 mcp”Run the Arete stream MCP server over stdio (registry discovery, knowledge layer, live entity reads). Nothing but MCP frames is written to stdout; logs go to stderr.
a4 mcpa4 init writes the config for each selected agent. The Claude Code shape (.mcp.json):
{ "mcpServers": { "arete": { "type": "stdio", "command": "a4", "args": ["--profile", "agent", "mcp"] }, "arete-docs": { "type": "http", "url": "https://docs.arete.run/mcp" } }}Generated MCP config explicitly selects the agent profile. That profile is
resolved from ~/.arete/credentials.toml before any ambient ARETE_API_KEY, so
a human key cannot accidentally override it. The npm package @usearete/mcp is
deprecated in favour of this command. Tools and per-host shapes: MCP Server.
a4 config validate
Section titled “a4 config validate”Validate your configuration.
a4 config validateAuthentication
Section titled “Authentication”Exploring and installing public SDKs needs no account. Hosted global stacks and
the knowledge layer do. Agents create or verify their restricted credential with
a4 --profile agent auth signup --if-missing; humans get keys from
arete.run/keys and use
a4 auth login --profile human --key.
a4 auth signup
Section titled “a4 auth signup”Register a new agent account and store its key.
a4 auth signup # server picks a display namea4 auth signup my-agent # explicit display namea4 --profile agent auth signup --if-missing --json # safe, idempotent bootstrapa4 auth signup --force # replace credentials that already exist for this API URLCalls POST /api/agents/signup/v2, saves the a4_ak_* key under the agent
profile in ~/.arete/credentials.toml, and prints non-secret registration
metadata. The key itself is never printed.
Options:
| Flag | Description |
|---|---|
[name] | Display name (optional) |
--if-missing | Verify and reuse a valid agent credential; sign up only when one is absent |
--force | Overwrite existing credentials for this API URL; otherwise the command refuses and points at a4 auth status |
--if-missing and --force are mutually exclusive. If verification finds an
invalid or disabled stored key, --if-missing leaves it untouched and tells the
operator how to replace it explicitly.
--json output:
{ "schemaVersion": 1, "slug": "agt_7k2m9q1r", "displayName": "my-agent", "credentialStored": true, "credentialPathKind": "default", "profile": "agent", "accountStatus": "active", "plan": "agent_trial", "trialAccessEnabled": true, "created": true }The response confirms storage but deliberately omits the secret.
Rate limit: 5 signups per hour per IP. On 429 the command points the user at
the human flow: a4 auth login --profile human --key <a4_sk_…>.
a4 auth login
Section titled “a4 auth login”Save a human-issued API key. a4 login is the same command.
# Prompts for the key only in an interactive terminala4 auth logina4 login
# Pass directly (required when non-interactive)a4 auth login --profile human --key <a4_sk_...>Options:
| Flag | Description |
|---|---|
--key, -k | API key. When omitted in a non-interactive run the error lists this flag and a4 auth signup |
a4 auth logout
Section titled “a4 auth logout”Remove stored credentials.
a4 auth logouta4 auth status
Section titled “a4 auth status”Check local authentication status.
a4 auth statusa4 auth whoami
Section titled “a4 auth whoami”Verify authentication with server.
a4 auth whoamiIt shows the account’s plan, its dev environment tier, the surfaces the
account can use and, for each one it can’t, the reason and how to unlock it.
--json carries them as plan, devTier and entitlements (a list of
{surface, allowed, reason?, unlock?}; the dev_environments entry also has
quotas with the tier’s limits and usage). An API that doesn’t report
entitlements leaves these fields null; if the lookup fails for another
reason, whoami says so on stderr and --json carries the reason as
entitlementsError.
For an agent key it also shows the plan’s usage. When used up says what
happens once the allowance is used: block (requests are refused until the
allowance resets) or metered (usage continues and is billed, shown as
overage: metered beyond allowance). --json carries the same as
usage.onExhausted and overage.
Credentials location: ~/.arete/credentials.toml. Named profiles keep the
restricted agent key separate from the broader human key. Inside a project
initialized by a4 init, CLI calls default to agent. Humans can opt in with
a4 --profile human <command>; alias a4h='a4 --profile human' is a convenient
human-only shortcut. Inside an initialized repository the safe project default
outranks inherited ARETE_PROFILE; only --profile opts up. The environment
variable remains useful outside initialized repositories.
a4 auth keys
Section titled “a4 auth keys”List, create or delete your API keys, or create a publishable key for browser code.
a4 auth keys list [--json]a4 auth keys create [--name <name>] [--expiry-days <n>] [--json]a4 auth keys delete <id> [--yes]
a4 auth keys create-publishable --origin http://localhost:5173a4 auth keys create-publishable --origin https://app.example.com --name web --env-file .env.locala4 auth keys create-publishable --origin http://localhost:5173 --jsoncreate makes a secret key and prints it once. delete revokes a key by the
ID shown in a4 auth keys list; it asks for confirmation unless --yes is
passed. When signed in with an agent key (a4 auth signup), these commands
manage the agent account’s own keys. A trial agent account can only use its
original key: have a human claim it (a4 auth claim-link) to create more keys
or publishable keys.
A publishable key is safe in browser code, but each key allows exactly one
origin (scheme://host[:port], no path or trailing slash). Create one key per
origin, for example one for http://localhost:5173 and one for production.
create-publishable options:
| Flag | Description |
|---|---|
--origin, -o <origin> | The one origin the key allows (required) |
--name, -n <name> | Key name (optional) |
--expiry-days, -e <n> | Days until the key expires (default 365) |
--env-file <path> | Write or update only the key’s environment variable in this file, creating it if needed. Relative paths must stay inside the project; absolute paths are used as given |
The command prints the environment variable to set for the framework it
detects in the project directory (the directory holding arete.toml):
| Detected | Variable |
|---|---|
Next.js (next.config.*, or next in package.json) | NEXT_PUBLIC_ARETE_PUBLISHABLE_KEY |
Vite (vite.config.*, or vite in package.json) | VITE_ARETE_PUBLISHABLE_KEY |
| Anything else | ARETE_PUBLISHABLE_KEY |
--env-file changes no other line in the file and never prints its contents.
It replaces the file atomically and keeps its permissions. A relative path may
not leave the project through a symlinked directory or name a symlink.
The path is checked before the key is created. The command never prompts, so
it is safe to script, and exits non-zero when the API call fails (as does
list).
--json output:
{ "schemaVersion": 1, "id": 42, "name": "web", "keyClass": "publishable", "origins": ["http://localhost:5173"], "expiresAt": "2027-09-25T00:00:00Z", "key": "hspk_…", "framework": "vite", "envVar": "VITE_ARETE_PUBLISHABLE_KEY", "envFile": "/home/x/app/.env.local", "envFileChange": "replaced"}envFile and envFileChange (created, appended, replaced or
unchanged) are null without --env-file. The key is shown only once.
Schema Discovery
Section titled “Schema Discovery”a4 explore catalog
Section titled “a4 explore catalog”Search the public active catalog by intent and required delivery mode:
a4 explore catalog --json # overview: first programs and stacksa4 explore catalog --query "monitor swaps" --jsona4 explore catalog --concept <slug> --kind program --mode read --jsona4 explore catalog --category <slug> --kind stack --mode subscribe --jsona4 explore catalog --kind program --target typescript --jsona4 explore catalog --vocabulary --json # slugs and names
# Inspect one exact active entrya4 explore catalog program <slug> --jsona4 explore catalog stack <slug> --json
# More or fewer fields than the brief defaulta4 explore catalog --query "monitor swaps" --full --jsona4 explore catalog --query "monitor swaps" --fields slug,kind,version,delivery.healtha4 explore catalog --vocabulary --full --json| Option | Meaning |
|---|---|
--query <text> | Free-text intent search |
--concept <slug> | Require an exact concept |
--category <slug> | Require an exact category |
--kind program|stack | Restrict package kind |
--mode read|build|subscribe | Require a delivery mode |
--target typescript|rust|python | Require a verified SDK target |
--limit, --cursor | Pagination: 10 results per page by default; pass nextCursor as --cursor with the same filters |
--vocabulary | List current concept and category slugs and names |
--full | Every field instead of the brief default (search and --vocabulary) |
--fields <a,b.c> | JSON with only these keys per entry |
--brief, --summary | JSON with the brief field set |
Brief by default. Search results keep kind, slug, name, version,
protocol, summary, modes, sdkTargets and
delivery.status/delivery.health, in human and --json output alike.
--full restores every field the server sent (concepts, score, identity
hashes such as packageReleaseHash, programIds, release notes) and, in
human output, the package release hash beside each install command.
--vocabulary lists each concept’s and category’s slug and name; --full
adds descriptions, synonyms and related slugs.
Two keys are derived from those fields. live (stacks only) is true when
the stack has a hosted stream you can subscribe to now, which is when its
modes include subscribe, and false for a definition-only stack: it
installs as a typed SDK with its Program SDKs (build transactions, read
accounts) and streams once you deploy it yourself. --mode subscribe returns
only live stacks. related lists the other results on the page that share the
entry’s protocol, as kind:slug; program, stack and protocol slugs often
differ for the same protocol. Human output marks stacks [live] or
[definition-only] and prints each result’s protocol and related slugs.
Brief JSON carries a top-level hint string saying how to get more fields
and, when nextCursor is present, the next page. --full JSON is the server
response unchanged (without live and related); when it runs past 20,000
characters, a note on stderr suggests a --fields list instead. --fields
takes top-level keys or dotted paths (delivery.status) and applies to each
search result or to a single entry.
--fields, --brief and --summary imply --json. Shaping happens in the
CLI, so it works against any server.
Without filters, a4 explore catalog prints an overview: up to 5 programs and
5 stacks (or --limit of each), with nextCursors.program and
nextCursors.stack to page one kind with --kind <kind> --cursor <cursor>.
It exits 0. --cursor without filters is an error.
A single entry (a4 explore catalog <kind> <slug>) is always complete;
--brief or --fields trim it on request.
Use catalog search when starting from intent. Open the exact result before installing or connecting; search summaries are not a substitute for the pinned descriptor.
a4 explore
Section titled “a4 explore”Discover installable resources through the same deployment-pinned descriptors
used by a4 install. Public resources work without authentication; logging in
also exposes global resources.
# List all available stacksa4 explore
# Search by intent and inspect an exact stack descriptora4 explore catalog --query "monitor swaps" --kind stack --mode subscribea4 explore stack <stack-ref>
# List and inspect standalone programsa4 explore programsa4 explore program spl-token
# Legacy stack and entity forms remain supporteda4 explore <stack-ref>a4 explore <stack-ref> <Entity>
# JSON output (for agents and scripts)a4 explore --jsona4 explore programs --jsona4 explore stack <stack-ref> --jsona4 explore program spl-token --jsona4 explore <stack-ref> <Entity> --json
# Compact by default; ask for the part you needa4 explore stack ore --jsona4 explore stack ore --views OreRound/latest,OreMiner/state --jsona4 explore stack ore --full --jsona4 explore program ore --full --jsona4 explore program ore --operation transactions.mining.deployWithCheckpoint --jsona4 explore program ore --operation deploy --jsona4 explore program ore --section accounts,types --jsona4 explore stack ore --operation transactions.mining.deployWithCheckpoint --jsonArguments:
| Argument | Description |
|---|---|
<stack-ref> | Hosted stack deployment/install reference, or a stack dependency alias from arete.toml |
<program-ref> | Program install name or program ID |
[entity] | Optional exact-LiveSpec entity drill-down (alias:entity resolves ambiguity) |
Options:
| Flag | Applies to | Description |
|---|---|---|
--summary | stack, program | The compact summary, which is also the default |
--full | stack, program | The full exploration: identity hashes, every auth surface and endpoint, SDK metadata; for a program, the IDL-level dump |
--views <ids> | stack | Only these selected views, each with its entity’s field schema. Comma-separated or repeated; prefix alias: when several LiveSpecs select the same id |
--operation <id> | program, stack | One operation, by semantic path (transactions.mining.deployWithCheckpoint), full operation id, generated binding, or raw instruction name (deploy) |
--section <name> | program | Only accounts, events, instructions (with error codes), operations, or types. Repeat the flag or comma-separate |
Output varies by specificity:
| Command | Shows |
|---|---|
a4 explore, a4 explore stacks | Available stacks |
a4 explore programs | Complete promoted Program Release + Program Read installations. Release and spec hashes need --full; --fields chooses keys |
a4 explore stack <ref> | Compact summary: live, entities and views, token-amount fields, read.* helpers, Program SDKs, stream endpoints and auth, install command |
a4 explore stack <ref> --full | Exact identities, aliases, selected views, programs, auth and auth requirements, SDK targets, the endpoints the SDK uses, install command |
a4 explore stack <ref> --views … | The named views’ schemas (field descriptions and token-amount units) and endpoints |
a4 explore program <ref> | Compact summary: instructions and accounts with their first doc line, PDAs and seeds, SDK operations, transports, install command |
a4 explore program <ref> --full | Program identity, accounts, instructions, events and types in full, Program Read, and install command |
a4 explore program <ref> --operation | One operation: generated paths, input type, required and derived accounts, signers, transaction count, errors, transport, usage |
a4 explore program <ref> --section | The named sections in detail |
a4 explore <stack> [entity] | Legacy syntax routed through descriptor-backed stack exploration |
Everything is cut from the same pinned install descriptor on the client, so
the compact forms agree with the full one. A stack or program summary, one
operation, or one view is a few KB; compact JSON carries a hint naming the
next narrower or fuller form, and a --full output past 20,000 characters ends
with one (on stderr for JSON).
Stack summary. live says whether the stack has a hosted stream. Each
entity lists its views and, under amountFields, the fields it scales as
token amounts (see Token amounts below). reads lists the read.* helpers
the stack’s SDK extension adds, with their arguments and titles, for example
read.currentRound() on ORE: call them on the installed stack. Identity
hashes, the auth of every surface and the SDK extension metadata are in
--full.
Definition-only stacks. Exploring a stack that has no hosted stream (a
catalog package nobody has deployed) does not fail. It prints kind: "stack-definition-only" and live: false with the catalog version,
protocol and summary, and the next steps: a4 install stack <slug> --ts for
its typed SDK and Program SDKs, a4 up <alias> to deploy it yourself, or
a4 explore catalog --kind stack --mode subscribe for a stack that streams
now. It exits 0.
Operations. Semantic operations (transactions.*, instructions.*,
read.*) and their generated paths come from the knowledge layer’s SDK
surface, so they need an API key (a4 auth login or a4 auth signup).
Without one, --operation still resolves raw IDL instruction names. An
operation reports only what the descriptor and surface carry. Anything else,
such as reads made while preparing, is listed under notReported rather than
guessed. --operation on a stack searches the stack’s program SDKs.
Auth requirements. The summary’s auth lists the stream and query key
classes, whether transactions need an entitlement, and the command for an
origin-bound browser key. --full output includes authRequirements: for
each surface (stream, query, chain, transaction and Program Read) it lists the accepted key classes and scopes, and whether a
transaction entitlement is required. browser appears when publishable keys
are accepted; each one is bound to exactly one origin. When the stack’s
transactions need an entitlement, account.transactions says whether your
account has transaction access: ready, not-ready with the missing
capabilities, or unknown (for example when you are not logged in).
Field descriptions. When the stack is published in the catalog, explore
attaches the curated field descriptions from the stack’s catalog knowledge.
They say how to use a field, for example which of two similar fields a live UI
should show, so read them before choosing fields. The entity drill-down
(a4 explore stack <ref> <Entity>) and --views add description to each
described field and summary to the entity and its views. The summary adds
summary to entities and views. The full output adds summary to
selectedViews and a knowledge block with each described entity and its
fieldDescriptions. Human output prints a description under its field. knowledge names the source document (slug,
documentHash). Descriptions are attached only when the knowledge was
published for the exact StackManifest being explored. Stacks without a catalog
entry, such as private or local stacks, print as before. Explore skips the
lookup for private stacks and gives up on it after 2 seconds.
{ "path": "results.pre_reveal_winning_square", "rustType": "Option<u8>", "nullable": true, "section": "results", "description": "preRevealRng modulo 25, the winning square before reveal."}Token amounts. A field the stack scales with ui_amount(decimals) (as a
#[map] transform or in a #[computed] expression) carries amount, read
from the stack’s own computations rather than guessed from names. scale is
ui for whole token units (the raw amount divided by 10^decimals, a float)
or raw for the integer base units the computation reads (often a
string-encoded u64; for SOL, lamports). decimals is the token’s decimals,
or decimalsFrom names the field holding them, and counterpart names the
emitted field with the same amount at the other scale. Which token a field
counts is in its description when the catalog has one. Human output prints an
amount: line under the field.
{ "path": "state.deployed_per_square", "rustType": "Option < Vec < u64 > >", "nullable": true, "section": "state", "amount": { "scale": "raw", "decimals": 9, "counterpart": "state.deployed_per_square_ui" }}Endpoints inside a project. When arete.toml declares the stack as a
dependency, sdkEndpoints shows which stream endpoints the generated SDK
reads. Endpoints that a4 up recorded in arete.toml take precedence over the
registry’s hosted endpoints. The set in use is used, and the other is
labelled “not used”. The summary and --views print sdkEndpoints only when
arete.toml endpoints are in use; otherwise the hosted endpoints they list are
the ones the SDK reads. You can pass the dependency alias as <stack-ref>.
Every JSON response includes schemaVersion. Exploration never selects a
latest AST independently and never falls back when an install descriptor is
incomplete. For an owned stack diagnostic, use a4 stack show <ref>.
a4 know
Section titled “a4 know”Query the curated knowledge layer: which protocols, programs, stacks, and
recipes serve an intent, and what the platform can do for each (read account
state, build transactions, subscribe to a hosted stack). Every subcommand
requires an API key saved by a4 auth login and accepts --json. search
and concepts are brief by default (see below); the other subcommands print
the API response verbatim.
# Search by intent; results carry read / build / subscribe coverage flagsa4 know search --query "monitor swaps"a4 know search --concept swap --category dex --limit 10
# One protocol: programs with roles, related protocols, live stacks, coveragea4 know protocol meteora-damm
# One program's annotations, one section at a timea4 know program meteora-cp-amm # summary (default)a4 know program meteora-cp-amm --section instructionsa4 know program meteora-cp-amm --section accountsa4 know program meteora-cp-amm --section surface # typed SDK operations with bindings
# One cross-protocol recipea4 know recipe execute-presale-purchase-via-squads
# Concept and category slugs for --concept / --categorya4 know concepts # slugs and namesa4 know concepts --full # with descriptions, synonyms and related conceptssearch options:
| Flag | Description |
|---|---|
--query, -q <text> | Free-text intent; matches concept names and synonyms first |
--concept <slug> | Filter by concept slug (see a4 know concepts) |
--category <slug> | Filter by category slug (see a4 know concepts) |
--limit <n> | Maximum number of results (default 10) |
--full | Every field per result (score, coverage_via) |
--fields <a,b.c> | JSON with only these keys (or dotted paths) per result |
--brief | JSON with only slug, type, name, protocol, summary, coverage |
At least one of --query, --concept, or --category is required.
Results keep type, slug, name, protocol, summary and coverage by
default, in human and --json output; brief JSON adds a top-level hint
naming --full, --fields and, when a page is full, a higher --limit.
--fields and --brief imply --json. a4 know concepts lists slugs and
names; --full adds descriptions, synonyms and related concepts.
program options:
| Flag | Description |
|---|---|
--section <name> | summary (default), instructions, accounts, or surface |
Slugs are bare identifiers (meteora-damm), not URLs or paths; unknown slugs
return a not-found error. The catalog is growing, so a protocol with no entry
is not evidence that it is unsupported — fall back to a4 explore and
a4 idl.
Reading Live Data
Section titled “Reading Live Data”a4 get <Entity>/<view>
Section titled “a4 get <Entity>/<view>”Read a view’s current entities once and exit. a4 get connects the way
a4 stream does (same stack resolution and credentials), waits for the
view’s snapshot, prints one JSON document and disconnects. Use it to answer
“what is the current value” questions without writing a script.
# The current ORE round (OreRound/latest is sorted newest first)a4 get OreRound/latest --stack ore --limit 1
# Only the fields you needa4 get OreRound/latest --stack ore --limit 1 \ --select id.round_id,state.total_deployed,treasury.motherlode
# One entity by keya4 get OreRound/state --stack ore --key 434161
# Filter the snapshota4 get OreRound/latest --stack ore --where 'state.total_deployed>8' --limit 5| Flag | Description |
|---|---|
-s, --stack <name> | Owned deployment or registry stack name |
--url <ws-url> | WebSocket URL instead of --stack |
-k, --key <key> | Read the one entity with this key (usually an <Entity>/state view) |
--where <expr> | Filter: field=value, field>N, field~regex (repeatable, ANDed) |
--select <paths> | Comma-separated dot paths to output |
--limit <n> | Most entities to print, in the view’s order (default 10) |
--timeout <secs> | Seconds to wait for the connection and snapshot before failing (default 15) |
Output:
{ "entities": [ { "id.round_id": "434161", "state.total_deployed": 5.002337026, "treasury.motherlode": 36.6 } ], "matching": 1, "returned": 1, "total": 1, "truncated": false, "view": "OreRound/latest"}Without --where, the server sends only --limit entities. With --where,
total counts the whole snapshot and matching the entities that passed.
a4 get exits non-zero with a message when the view is unknown, a --key
has no entity, or the snapshot does not arrive within --timeout.
Float token amounts are usually whole units and the integer fields they come
from raw base units; a4 explore stack <ref> --views <view> shows each scaled
field’s amount (see Token amounts).
a4 stream <Entity>/<view>
Section titled “a4 stream <Entity>/<view>”Follow a view’s live updates. Run a4 stream --help for filtering,
selection, history, recording and TUI options.
Dev environments. --dev streams from the stacks serving in the
project’s cloud dev environment instead of a named stack, protocol first: it
finds the project, lists its protocols and their views, mints and refreshes
session tokens itself, and follows redeploys (printing — redeployed: <old> → <new> on stderr). With
--dev the positionals are [PROTOCOL] [VIEW]. See
Streaming the stack.
| Flag | Meaning |
|---|---|
--dev | stream from the project’s dev environment; without a protocol or view, list its protocols, counts and views (--json for JSON; with --tui, browse them) |
--dev <protocol> [<view>] | one protocol (by spec name, slug, stack or deployment short id): its views as one feed, or one view by name (Instances, Activity, Participants) or id (ProtocolActivity/list) |
--instance <id> | with --dev, one instance (the id a4 dev step prints, or its short id): its state row and its activity |
--project <dir> | the a4 dev project (default: the nearest one at or above the current directory) |
--stack <name> | with --dev, a stack in the environment (a positional is then a view id); otherwise an owned deployment or registry stack |
--all | every view of the stack (except <Entity>/state views) over one connection, as one feed: JSON lines carry "protocol", "stack" and "view", and with --tui each view gets a tab plus an “All” tab |
a4 stream --deva4 stream --dev --tuia4 stream --dev localTipJar Activity --where step=opena4 stream --dev localTipJar --instance 99e8592f-6b0f-472a-9716-45ca0ef97f11a4 stream --dev --all --raw | jq -c '{protocol, stack, view, op}'Deployment
Section titled “Deployment”a4 up <manifest>
Section titled “a4 up <manifest>”Deploy the exact composition described by a local StackManifest, an
[authoring.stacks] entry, or an installed stack
(Deploying an installed stack). A composed
[authoring.stacks] entry deploys exactly what arete.lock pins for it
(Composed stacks). The control
plane resolves every ProgramSpec to an immutable hosted Program Release,
prepares each aliased LiveSpec independently, then returns deployment and
endpoint bindings. Those operational bindings are not part of the portable
StackManifest hash.
# Deploy an exact manifesta4 up .arete/MyStack.stack-manifest.json
# Deploy to brancha4 up .arete/MyStack.stack-manifest.json --branch staging
# Preview deploymenta4 up .arete/MyStack.stack-manifest.json --preview
# Preview what would be deployed (no actual deployment)a4 up .arete/MyStack.stack-manifest.json --dry-run
# Deploy the stack installed as `raydium-amm`a4 up raydium-ammOptions:
| Flag | Description |
|---|---|
--branch, -b <name> | Deploy to named branch |
--preview | Create preview deployment |
--dry-run | Show what would be deployed without deploying |
Program SDKs. When arete.lock pins a program SDK release for a program
of the deployed stack (an installed or composed stack), a4 up asks for that
program to carry it. A production deployment then lists the program SDK each
program carries:
Program SDKs: ore → ore@1.0.2 (from arete.lock) entropy: core SDK only — <reason>(catalog) marks the program’s published program SDK, and
(your program package) one of your own program packages. core SDK only
means the program carries no program SDK, and says why. --json output
includes the same report as programSdks. Branch and preview deployments are
not published, so they have no report.
If a program SDK that arete.lock pins no longer fits its program, a4 up
stops before anything is built. Run a4 update stack <alias>, then deploy
again. When the registry doesn’t report program SDKs, a4 up notes that and
deploys without the report.
a4 protocol init [dir]
Section titled “a4 protocol init [dir]”a4 protocol init [dir] creates a protocol project in dir (default: the
current directory, created when missing): a template-only tip jar in
protocol.ts whose steps (open, tip, close) are System Program
transfers; its automations in automations/index.ts (recurring tips on a
schedule, and tips for new jars on the tipJar.opened event), which
[dev.automations] in arete.toml makes a4 dev up run; the registry’s
system-program package installed as @programs/system (a4 install program system-program --as system --ts: arete.toml, arete.lock and
generated/typescript/programs/system/); package.json with
@usearete/protocol, @usearete/sdk and zod, plus @usearete/automations
and tsx for the automations; tsconfig.json mapping @programs/*;
.gitignore; and a README.md. The automations know nothing about where
they will be deployed: npx @usearete/automations add <cloudflare|vercel|node>
writes a host’s entry later (Run automations in production). It refuses to overwrite an
existing file and names it (.gitignore only gains missing lines). An
arete.toml that holds only what a4 init writes (manifest_version and
[project]) gains the protocol’s sections, so a4 init -y && a4 protocol init .
and a4 protocol init <dir> && cd <dir> && a4 init -y build the same project;
an arete.toml with dependencies, [dev] or other tables still refuses. --name <name> sets
the spec name (^[a-z][A-Za-z0-9]*$, default: the directory name in
camelCase); --no-install skips the program install.
The default requires the reviewed registry package. A registry or authentication
failure stops init with a recovery command; it never substitutes another
program identity. --local-idl explicitly scaffolds its transfer instruction
from idl/system.idl.json for offline authoring. a4 dev up and a4 protocol deploy admit local-IDL dependencies privately, record their immutable release
pins and rebuild before uploading the protocol. The prepared transaction includes any applicable platform fee.
a4 protocol init my-protocolcd my-protocol && npm install && npx arete-protocol check && a4 dev upa4 protocol deploy [dir]
Section titled “a4 protocol deploy [dir]”a4 protocol deploy [dir] builds your protocol with arete-protocol build
(from @usearete/protocol) and takes it to a private deployment. It uploads
only .arete/protocol/protocol-spec.json, plus handlers.mjs when a step has
a handler; the server derives the stack source and release from them.
a4 protocol deploy # the protocol in the current directorya4 protocol deploy ./my-protocol # builds first, then deploysa4 protocol deploy --no-build # upload the existing build, if it is currenta4 protocol deploy --dry-run # print the plan and run the server's checks; changes nothinga4 protocol deploy \ --creator-fee-wallet <pubkey> \ --resource launchDefaults=launch-defaults.jsona4 protocol deploy --no-activate --jsonThe command:
- Builds the project (
npx --no arete-protocol build), unless you pass--no-build. With--no-buildit uploads the existing.arete/protocol/output, and refuses it when a source changed since that build: the build records each source file’s hash (build-sources.json, behind the receipt’ssourceTreeSha256), and the error names the changed and deleted files. - Pushes the programs the project installed from a local IDL
(
[dependencies.programs]withsource = { idl = ... }). Arete checks templates against, compiles the stack from and pins in the protocol’s package only programs it has, and a release carries only the spec. For each such program, deploy uses the account’s program with the same ProgramSpec when there is one, or a registry program package of that exact ProgramSpec. Otherwise it registers the program asa4 program pushdoes: a private program aliased<slug>-<alias>(with the ProgramSpec digest’s first 8 characters added when that alias already names another of your programs), published as your private program package. It waits for the admission (waiting: program <alias> admission queued), at most--wait-secs; a failed admission stops the deploy.arete.tomlkeeps the IDL source.arete.lockrecords the program’sprogram_release_hash, the generated program is regenerated with it, and the project is rebuilt, so the release pins that Program Release and the protocol’s package pins the program package.a4 installkeeps the recorded release while the IDL’s ProgramSpec is unchanged. An IDL that no longer matchesarete.lockis refused: runa4 installfirst. With--no-buildthe program is pushed butarete.lockis left as it is.--dry-runlists the programs and pushes nothing. - Validates the spec locally and prints the release hash the server should derive. If the server returns a different hash, it warns and continues with the server’s release.
- Finds your protocol by slug or creates it. The slug defaults to the spec
name in kebab case (
tokenRaisebecomestoken-raise). - Uploads the release. Re-uploading an identical release is a no-op.
- Reuses a private deployment of the same release if one exists. Otherwise it publishes a version of every resource the spec declares and creates the deployment.
- Activates the deployment, unless it is already active or you passed
--no-activate. - When the deployment is active and the project installs its own protocol
(
[dependencies.protocols]with this slug, whicha4 dev upadds), updates that client to the new deployment:a4 update protocol <alias>from the registry, or, while the registry has no package release for the deployment yet, the client is generated from the deployed build with the new deployment id andarete.lockmarks itlocal_build(the command says so). Runa4 installonce the package is published.
With --dry-run and a secret key, Arete also runs the upload’s checks on
the built release without storing it: the expression type checks, and the
template checks against the pinned program specs. If the server would reject
the release, the dry run fails and prints each error’s spec path, message and
code. A template check that is pending (Arete does not have a pinned program
spec yet) is a warning. The --json plan includes the check as
plan.releaseCheck.
What happens at activation depends on the protocol:
- Template-only protocols (no handler code) activate as private
deployments at trust tier
unreviewed. While the server’s template check ispending, activation waits until the server has the program specs the templates target (step 2 pushes the project’s own). - Production protocols with handler code can’t run until an operator reviews the
release. The command creates the deployment, prints the release hash to
share with the operator, and exits 0 with status
review-required. The operator reviews the exact release; rerun deployment after review to attempt activation. Private cloud dev deployments can run handlers without review; that exception does not apply to this production command. - Public deployments can only be created by an operator. Self-serve deployments are always private.
| Flag | Description |
|---|---|
--no-build | Upload the existing .arete/protocol/ output instead of building; refused when the sources changed since that build |
--dry-run | Print the files, expected release hash, slug, and whether a deployment would be created or reused. Reads the server only when a secret key is configured |
--slug <slug>, --name <name> | Override the protocol slug (^[a-z0-9][a-z0-9-]{0,62}$) and display name |
--creator-fee-wallet <pubkey> | Wallet that receives the creator’s share of Arete’s fee on a new deployment |
--resource <name>=<file> | JSON value for a declared resource (repeatable) |
--no-activate | Create or reuse the deployment without activating it |
--json | Print the result as JSON: status, protocol, release, deployment, client (the installed client update, when there is one), warnings |
The command needs a secret API key; publishable keys are refused.
Arete sets each deployment’s fees; there is nothing to configure. To receive
the creator’s share of Arete’s fee on your protocol’s transactions, name a
wallet with --creator-fee-wallet or [protocol].creator_fee_wallet. Without
one, Arete keeps the whole fee. The wallet is fixed when the deployment is
created: a new wallet applies to the next new deployment.
Flags override the optional [protocol] section of the project’s
arete.toml. Paths in that section are relative to the project directory, and
paths passed as flags are relative to the current directory.
[protocol]slug = "token-raise"name = "Token Raise"creator_fee_wallet = "<pubkey>" # optionalaccess = "private" # the only accepted value
[protocol.resources]launchDefaults = "resources/launch-defaults.json"[protocol.resources] gives a value for each resource the spec declares, in
one of two forms:
- A string is the path to a JSON file holding the value, relative to the project directory.
- Any other TOML value (an inline table, array, number or boolean) is the value itself, converted to JSON.
[protocol.resources]launchDefaults = { tokenDecimals = 6, minRaise = 1000000 }Write a string-valued resource as a JSON file, since a string is read as a
path. Either form must match the resource’s schema in the spec, and the same
JSON rules apply to both (integers must be within the
JavaScript safe range). TOML dates are not accepted; write them as strings.
--resource <name>=<file> overrides the entry for that resource. A resource
the spec declares with no value fails the deploy with a message naming both
forms.
a4 protocol actions [protocol|deployment]
Section titled “a4 protocol actions [protocol|deployment]”a4 protocol actions lists what a wallet can do now on a protocol
deployment: the steps that create an instance, and every instance the wallet
relates to (as a participant, a role holder or the creator), newest first.
Each step shows whether it is allowed, the guard or access code when it is
not, its typed args, and the guards only its args decide (prepare evaluates
those). Name the deployment by protocol package or deployment id; --dev
asks about the project’s deployment in its dev environment instead.
a4 protocol actions token-raise --wallet <pubkey>a4 protocol actions token-raise --wallet <pubkey> --instance <id> --jsona4 protocol actions --dev --wallet default # a dev wallet name or a pubkey| Flag | Description |
|---|---|
--wallet <pubkey> | The wallet (with --dev, also a dev wallet name) |
--instance <id> | Only this instance |
--cursor <cursor> | The next page (nextCursor) |
--dev / --project <dir> | The project’s dev deployment |
--json | The answer as JSON |
a4 squads
Section titled “a4 squads”A production deployment of a protocol with Squads steps is refused
(protocol-squads-setup-required) unless the multisig in its deployment
config is an active attachment of your account: Arete’s proposer is a
member with the Initiate permission only. Set that up on the dashboard,
app.arete.run/dashboard/squads,
which works with any browser wallet (a Ledger too), or in the Squads app
(Members → Add member, paste the proposer, Initiate only, then
approve and execute). a4 squads reads your account’s setup and attaches a
multisig by address. Every command prints the dashboard link first and, for
a pending multisig, the Squads-app steps. It builds no transactions: for
scripts and hot wallets, use the Arete setup helpers of the Squads v4
program SDK (a4 install program squads-v4).
a4 squads status # setup, proposer, attached multisigsa4 squads status <M> # one multisig: members, deployments, proposalsa4 squads lista4 squads attach <M> --label Treasury| Flag | Description |
|---|---|
--label <text> | attach: a label for the dashboard (1 to 64) |
--json | The answer as JSON |
Dev environments keep their own proposer: use a4 protocol squads --dev and
a4 dev squads there.
a4 protocol squads
Section titled “a4 protocol squads”A step whose authority is squadsProposer is proposed to your team’s own
Squads v4 multisig by a proposer key Arete holds for your account (one key
per account, shared by its deployments). The proposer may only initiate:
add it to the multisig as a member with exactly the Initiate permission
(mask 1), and fund it with a little SOL, since it pays the fee and rent of
each proposal. Your members still approve and execute. Name the deployment
as a4 protocol actions does: a deployment id or a protocol package, or
--dev for the project’s dev deployment.
a4 protocol squads proposer <deployment>a4 protocol squads status <deployment> --multisig <M>a4 protocol squads status --dev --multisig <M>proposerprints the proposer’s public key and, when an RPC answers (--rpc-url,ARETE_MCP_RPC_URL, or the dev environment), its balance.statussays whether the proposer can propose to the multisig:ready,member,mask,threshold, the balance (and what one proposal needs, when the server reports it) and, when not ready, the problem and its fix:not_member(add it),permissions_invalid(remove it in Squads and add it again) orproposer_unfunded(send it SOL; in a dev environmenta4 dev fund <proposer>).
Arete builds no Squads transactions. Add the proposer on the dashboard
(app.arete.run/dashboard/squads),
in the Squads app (Members → Add member, the proposer, Initiate
only, then approve and execute), or from code with the Squads v4 program
SDK’s Arete setup helpers. In a dev environment,
a4 dev squads add-proposer
builds the config proposal locally and a dev wallet signs it.
| Flag | Description |
|---|---|
--multisig <address> | status: the multisig account, not one of its vaults |
--rpc-url <url> | Where balances are read (not with --dev) |
--dev / --project <dir> | The project’s dev deployment |
--json | The answer as JSON |
The MCP server offers the same reads as protocol_squads_proposer and
protocol_squads_status. For production deployments, attach the multisig to
your account with a4 squads or the dashboard.
a4 protocol search [query]
Section titled “a4 protocol search [query]”a4 protocol search lists the callable protocol packages that publishers
listed on Arete: protocols an app or agent installs and calls through their
hosted deployment. These are not the curated protocols of a4 know protocol,
which describe on-chain protocols. Search and show need no API key.
a4 protocol searcha4 protocol search "tip jar"a4 protocol search tips --limit 50 --jsona4 protocol show tip-jarEach row shows the slug, version, trust tier, attested executions in the last 30 days, number of steps and package reference. Reviewed protocols come first, then the most executed.
| Trust tier | Meaning |
|---|---|
reviewed by Arete | Arete reviewed this release; a4 protocol show prints the review hash |
unreviewed | Nobody at Arete reviewed its code; read its steps and spec before you rely on it |
| Flag | Description |
|---|---|
--limit <n> | Results per page, 1 to 50 (default 20) |
--cursor <cursor> | The next page (printed after the table) |
--json | The registry’s page as JSON |
a4 protocol show <slug>
Section titled “a4 protocol show <slug>”a4 protocol show prints one listing: description, package, publisher,
trust tier and review hash, attested executions, deployment id, attestation
key, each step with its scope and access, and the command that installs it
at its exact version (a4 install protocol <package>@=<version>).
a4 explore protocol <package> describes the package in full.
a4 protocol request-listing
Section titled “a4 protocol request-listing”a4 protocol request-listing asks for one of your deployments to be listed,
and a4 protocol listing-status shows where that request stands (requested,
listed, rejected with a reason, or delisted). Both need the deployment
owner’s secret key. Without --deployment, they read the project the way
a4 protocol deploy does: the protocol slug from [protocol].slug (else the
built spec’s name), then the deployment arete.lock records for the
project’s own client, else the active deployment of the built release, else
the only active deployment.
a4 protocol request-listinga4 protocol request-listing --deployment <id> --note "Ready for review"a4 protocol listing-statusa4 protocol listing-status --deployment <id> --json| Flag | Description |
|---|---|
--deployment <id> | The deployment (default: the project’s, as above) |
--dir <dir> | The protocol project to read (default .) |
--note <text> | request-listing only: a note for the reviewer |
--json | The listing state as JSON |
A request can be refused:
| Code | What to do |
|---|---|
protocol-listing-not-public | Only public deployments are listed; self-serve deployments are private. Ask Arete to make it public |
protocol-listing-edges-private | The protocol uses private stacks or programs (the error names them). Use public ones and deploy again |
protocol-listing-fee-policy | The deployment’s fees predate Arete’s current fee rules. Deploy again, then request the listing for the new deployment |
protocol-listing-not-owner | Use a secret key of the account that owns the deployment |
protocol-listing-account-standing | The account cannot list protocols right now; contact Arete support |
a4 protocol webhook
Section titled “a4 protocol webhook”a4 protocol webhook manages the endpoints that receive your deployment’s
emitted events as signed POST deliveries. Every subcommand needs the
deployment owner’s secret key and finds the deployment the way
request-listing does (--deployment, else the project’s).
add subscribes an https URL to the events the project’s build declares (or
--events) and prints the endpoint’s signing secret. The secret is shown only
once: store it where the endpoint runs as ARETE_WEBHOOK_SECRET. With
--secret-only it prints just the secret, so you can pipe it into your host’s
secret store. If you lose it, remove the endpoint and add it again.
a4 protocol webhook add --url https://app.example/arete/webhooka4 protocol webhook add --url https://app.example/arete/webhook --events tipJar.tipped,tipJar.closeda4 protocol webhook add --url https://<worker>.workers.dev/arete/webhook --secret-only \ | npx wrangler secret put ARETE_WEBHOOK_SECRETa4 protocol webhook lista4 protocol webhook test <webhook-id> # send a signed test delivery nowa4 protocol webhook remove <webhook-id> # disable the endpoint| Flag | Description |
|---|---|
--url <url> | add: the endpoint’s https URL |
--events <a,b> | add: event names (default: every event the project’s build declares) |
--secret-only | add: print only the signing secret |
--deployment <id> | The deployment (default: the project’s) |
--dir <dir> | The protocol project to read (default .) |
--json | The endpoint, list or test result as JSON |
A dev environment sends no webhooks: under a4 dev up, the project’s
automations receive the environment’s events as signed deliveries instead.
a4 dev
Section titled “a4 dev”Develop against an Arete cloud dev environment: a persistent fork of mainnet
Arete hosts for your account. a4 dev up creates or wakes the project’s
environment, serves it on 127.0.0.1 (RPC and WebSocket, no token needed),
runs the dev UI, and deploys the project’s protocol into it, redeploying on
change. Signing stays local. See
Develop with a4 dev and cloud dev environments.
a4 dev up # create or wake the environment, serve it, deploya4 dev status # the environment, the session and the chaina4 dev list # your environments and quotasa4 dev fund default 50 # 50 SOL for the dev wallet `default`a4 dev fund <owner> --mint <mint> --amount 1000000a4 dev warp +2h # move the clock forwarda4 dev checkpoint before-test # save the state; restore or branch from ita4 dev restore before-testa4 dev rebase # refetch every account you never wrotea4 dev pin <pubkey> # never refresh this accounta4 dev step open --args '{"amount":"1000"}' --wallet defaulta4 dev sleep # or let it sleep when idlea4 dev delete --yes| Command | What it does |
|---|---|
a4 dev up [--env name] [--once] [--no-deploy] [--no-ui] [--port-base n] | create or wake, serve locally, deploy and watch (--once: deploy and exit) |
a4 dev up --take-over | take the environment from another project’s a4 dev up |
a4 dev down [--sleep] [--purge] | stop a running a4 dev up |
a4 dev status, a4 dev list, a4 dev use <name> | the environment, all of yours, or point the project at another |
a4 dev wake, a4 dev sleep, a4 dev delete | lifecycle |
a4 dev checkpoint [name], --list, --delete <id|name> | checkpoints |
a4 dev restore <checkpoint>, a4 dev branch <checkpoint> <name> | undo to a checkpoint, or start a new environment from one |
a4 dev rebase, a4 dev reset [--account <pubkey>] | refresh untouched accounts, or start over |
a4 dev fund, a4 dev pin, a4 dev follow | balances and freshness of accounts |
a4 dev warp, a4 dev pause, a4 dev resume | the clock |
a4 dev scenario <file>, a4 dev preview <tx>, a4 dev repro <sig> | scenarios, previews and repro exports |
a4 dev events, a4 dev token | lifecycle events; an environment token with the RPC URLs |
a4 dev step, a4 dev wallet, a4 dev instance, a4 dev replay | drive the protocol with local dev wallets |
a4 dev sdk, a4 dev capture | the protocol client from the local build; a capture from an RPC node |
a4 dev consent <wallet> --steps <a,b> | opt a dev wallet in to the project’s [dev.automations] |
a4 dev squads create|add-proposer|show|approve|execute|vault-execute | Squads v4 multisigs in the environment, built locally and signed by dev wallets |
Every environment command takes --env <name|id> (default ARETE_DEV_ENV,
else the project’s) and --json.
a4 status
Section titled “a4 status”Show overview of all stacks, builds, and deployments.
a4 statusa4 status --jsonStack Management
Section titled “Stack Management”a4 program build <idl>
Section titled “a4 program build <idl>”Normalize an IDL into a portable, endpoint-free ProgramSpec:
a4 program build ./idl/my-program.json \ --output ./.arete/my-program.program-spec.json
# Supply the program ID when the IDL omits ita4 program build ./idl/my-program.json \ --program-id <program-id> \ --output ./.arete/my-program.program-spec.jsonThe output describes public program behavior. It does not select a hosted decoder release or Program Read endpoint.
a4 stack compose
Section titled “a4 stack compose”Compose a stack from live views and program SDKs. Parts come from published stacks and program packages, or from local LiveSpec and ProgramSpec files.
Without --output, the command writes or updates [authoring.stacks.<name>]
in arete.toml (Composed stacks). It first resolves the
registry parts and checks that they compose. A part without a version is saved
at ^<resolved version>, the way a4 install saves a package. Other keys of
an existing entry, such as deployment_name, are kept.
# ORE's round and miner views, plus the spl-token program SDKa4 stack compose --name ore-plus-token \ --live ore \ --program spl-token@^1 \ --selected-view ore=OreRound/latest \ --selected-view ore=OreMiner/state
# Also declare it under [dependencies.stacks] and install its TypeScript SDKa4 stack compose --name ore-plus-token --live ore --program spl-token@^1 --install --ts--install also declares the composed stack as [dependencies.stacks.<name>]
(source = { workspace = "<name>" }) and installs it. --ts, --rust, or
--python choose the SDK it generates and are recorded as the dependency’s
targets, as a4 install stack <ref> --ts records them. Without one, the
dependency uses [sdk].targets (TypeScript and Rust unless set). Composing
again keeps a declared dependency as written; a flag replaces only its
targets. The flags require --install.
| Value | Part |
|---|---|
--live <stack>[@<version>] | A published stack’s live views, under an alias derived from its name |
--live <alias>=stack:<stack>[@<version>] | The same, under an explicit alias |
--live [<alias>=]stack:<stack>#<live> | One live alias of a stack that has several |
--live <alias>=<path> | A LiveSpec file |
--program <package>[@<version>] | A program package’s program SDK (program:<package> forces this) |
--program <path>.json | A ProgramSpec file |
The programs a stack’s views index come with them, as that stack’s program
SDKs. A --program for the same program replaces the one the stack brings;
any other --program is an independent program. A LiveSpec file’s programs
come from --program, from a composed stack, or from a ProgramSpec found under
--artifact-dir. --artifact-dir also searches the registry cache layout
(program-spec/<hash>.json, live-spec/<hash>.json). Without
--selected-view, each alias selects every view its stack serves, or every
view of its LiveSpec file. With it, the alias=view_id values are the exact
allowlist, in command-line order.
With --output, the command writes a StackManifest instead, as it always has:
a4 stack compose --name jurassic \ --program ./programs/spl-token.program-spec.json \ --live squads=./squads.live-spec.json \ --live presale=./presale.live-spec.json \ --artifact-dir ./.arete \ --selected-view squads=Multisig/state \ --selected-view presale=Presale/list \ --output ./Jurassic.stack-manifest.jsonRepeat --program, --live, and --artifact-dir as needed. Each --live
file requires a stable alias=path pair, so multiple LiveSpecs can expose the
same entity or program names without losing ownership.
A StackManifest composes portable identities only. It contains no WebSocket,
Program Read, chain, or transaction endpoint and does not require those
transports to be co-located. It lists ProgramSpecs, not program SDKs, so
compose into arete.toml when you want each program’s SDK generated.
Publishing a composed stack to the registry, so that other projects can install it by name, is not available yet.
a4 stack list
Section titled “a4 stack list”List all stacks with their deployment status.
a4 stack lista4 stack list --jsonOutput:
STACK STATUS VERSION URLsettlement-game active v3 wss://settlement-game.stack.arete.runtoken-tracker active v1 wss://token-tracker.stack.arete.runa4 stack show <stack-name>
Section titled “a4 stack show <stack-name>”Show detailed stack information including deployment status and versions.
a4 stack show my-stacka4 stack show my-stack --version 3a4 stack show my-stack -v 3Options:
| Flag | Description |
|---|---|
--version, -v <n> | Show specific version details |
Output includes:
- Entity information
- Deployment status and URL
- Latest version details
- Recent builds
a4 stack versions <stack-name>
Section titled “a4 stack versions <stack-name>”Show version history.
a4 stack versions my-stacka4 stack versions my-stack --limit 10a4 stack versions my-stack -l 10Options:
| Flag | Description |
|---|---|
--limit, -l <n> | Maximum number of versions (default: 20) |
a4 stack delete <stack-name>
Section titled “a4 stack delete <stack-name>”Delete a stack from remote.
a4 stack delete my-stacka4 stack delete my-stack --force # Skip confirmationa4 stack delete my-stack -fOptions:
| Flag | Description |
|---|---|
--force, -f | Skip confirmation prompt |
a4 stack stop <stack-name>
Section titled “a4 stack stop <stack-name>”Stop a deployment.
a4 stack stop my-stacka4 stack stop my-stack --branch staginga4 stack stop my-stack --force # Skip confirmationOptions:
| Flag | Description |
|---|---|
--branch <name> | Branch deployment to stop |
--force, -f | Skip confirmation prompt |
SDK Dependencies
Section titled “SDK Dependencies”a4 installa4 install --lockeda4 install --checka4 install --dry-runa4 install stack ore@^1.4.0 --tsa4 install stack ore --ts --setupa4 install program spl-token@=4.0.2 --rusta4 install program ./idl/my_program.json --as my-program --tsa4 updatea4 update stack orea4 remove program spl-tokena4 remove stack ore --keep-outputWith no package argument, a4 install resolves the complete strict
arete.toml graph and atomically commits generated outputs plus
arete.lock. A package add saves dependency intent before resolving the
whole project. Use --no-save for one-off exact registry generation.
a4 install --check changes nothing. It fails unless arete.lock is fresh
and every generated protocol client is the published release arete.lock
pins: a client a4 dev generated from a local build (local_build in the
lock, project.localBuild in its sdk-provenance.json) fails it. Run it in
CI. a4 install --locked restores the published clients.
API key for installs
Section titled “API key for installs”When the registry requires it, install descriptors, resolution, artifacts and
stack schemas need an Arete API key (any plan, the free one included). Without
one a4 stops with run \a4 login` (free): create a key on the free plan and save it with a4 login, or set ARETE_API_KEY. Once logged in, a4`
sends the key with every registry request. Searching and browsing the registry
needs no key.
Signed releases
Section titled “Signed releases”The registry signs the package releases it publishes, and a4 checks those
signatures on everything it installs: the packages a4 install and
a4 update resolve, the program SDK releases a stack references, and the
stacks and programs a protocol hoists. A signature is an Ed25519 signature by
a trusted registry key over a domain-separated message binding the key id
and release’s package_release_hash. Trust anchors are compiled into each
CLI release or explicitly provisioned through
ARETE_REGISTRY_TRUSTED_KEYS_FILE. The public key endpoint
GET /api/registry/v1/keys is cached in ~/.arete for a day; its metadata
can retire matching pinned keys, but cannot introduce a new trust anchor or
replace a pinned public key. New keys require an approved CLI release or an
operator-managed trust file.
The registry returns signatures only to clients that ask for them: a4
(and a4 mcp) send X-Arete-Registry-Signatures: v1 on the registry
requests whose responses carry package releases.
Official builds enforce signatures by default. Missing or invalid signatures,
unknown keys, and releases signed only by retired keys are refused. An unsigned
publication timestamp cannot restore trust in a retired key. Bootstrap builds
without provisioned trust anchors warn instead; set
ARETE_REQUIRE_REGISTRY_SIGNATURES=1 to require signatures explicitly.
Programs from a local IDL
Section titled “Programs from a local IDL”a4 install program <path-to-idl.json> installs a program that is not in
the registry (or not yet). The IDL must be inside the project:
a4 install program ./idl/my_program.json --as my-program --tsa4 install program ./idl/legacy.json --program-id <address> --ts # an IDL with no addressRun where there is no arete.toml yet, it starts the project: it writes
arete.toml (as a4 init would) before adding the program, and removes it
again if the install fails. Inside a directory whose parent has an
arete.toml, it refuses and names that project instead.
arete.toml records the project-relative path
(source = { idl = "idl/my_program.json" }, plus program_id when given).
a4 install builds the ProgramSpec from the IDL bytes, as a4 program build and the registry do, so arete.lock pins the same ProgramSpec hash a
registry install of the same IDL would. It has no program release. The SDK is
generated as for a registry program; --as is an alias of --alias.
Importing installed programs
Section titled “Importing installed programs”A TypeScript program install writes index.ts into the program’s output
directory, and a4 install makes sure the project’s tsconfig.json maps
compilerOptions.paths["@programs/*"] to that directory
(./generated/typescript/programs/*/index.js by default, or
./generated/typescript/programs/*/index in a project that resolves modules
like a bundler, see below), so code imports the program as
@programs/<alias>. It adds only the missing key and leaves
the rest of the file as written. When there is no tsconfig.json, or it
isn’t plain JSON, a4 install prints the line to add instead.
The generated program carries programInstall (the arete.toml alias, the
program release of a registry install, and its source: the registry package
at the exact installed version, or the IDL path) and instructionShapes
(each instruction’s argument and account names). @usearete/protocol reads
both: see its README.
a4 remove <stack|program> <alias> removes the dependency from the manifest,
prunes its lock entry, and deletes only generated output whose provenance
matches that project dependency. It refuses output containing unowned files;
--keep-output removes only the manifest and lock entries.
When a dependency stops generating an SDK because its targets or
[sdk].targets changed (for example a4 install stack ore --rust after
--ts), or because a4 install <package> -o moved its output, a4 install
removes the output it no longer writes, but only when that output’s provenance
shows it is the dependency’s generated SDK and its files are unchanged.
Otherwise it keeps the directory and prints a note naming it. arete.lock does
not record output paths, so after you change outputs in arete.toml by hand,
delete the old directory yourself.
a4 sdk list reports normalized manifest dependencies and lock status.
Low-level a4 sdk create accepts explicit --manifest or
--program-spec artifact inputs and hosted exact descriptors. It is a
compatibility/direct-descriptor tool: it never writes arete.toml or
arete.lock, and a4 install never falls back to it.
a4 sdk create --program-spec <file> generates a standalone program SDK
offline for any target: a TypeScript module (--ts), a Rust crate
(--rust, named <program>-program unless --crate-name is given) or a
Python package (--python, --package-name). --extensions <dir> applies the
program package’s own extension bundle for that language, exactly as
a4 install program <package> --rust (or --python) applies the published
one; --module writes a Rust mod.rs module or a plain Python package
directory. --program-only --idl <file> does the same from a raw IDL.
a4 sdk create --rust --program-spec ./.arete/ore.program-spec.json \ --extensions ./sdks/programs/ore/rust --output ./generated/ore-programa4 sdk create --python --program-spec ./.arete/ore.program-spec.json \ --extensions ./sdks/programs/ore/python --output ./generated/ore-program-pyAn SDK generated offline has no account read endpoint. It builds
instructions and derives PDAs, but each account read fails with how to get
one: install the program from the registry (a4 install program <package>)
and use a4 dev for a dev environment. To read a self-hosted Arete server
instead, name it with --read-endpoint <url>; the SDK reads that URL and needs
no connect-time httpUrl.
a4 sdk create --ts --program-only --idl ./idl/ore.json \ --read-endpoint https://arete.example.comSDKs generated before --read-endpoint existed keep reading the connect-time
httpUrl.
With a read endpoint, a standalone program SDK reads every account its ProgramSpec declares: Rust
<account>_accounts() on the program accessor and Python
accounts.<account> return a typed reader (fetch, fetch_many, exists)
over the account’s generated model, and pdas derives every ProgramSpec PDA.
Every IDL struct and enum an account’s fields use gets a generated model too
(for ORE, Config.admin reads as an AdminConfig whose fee_rate is an
integer), so nested values are typed like the account’s own fields.
A stack SDK’s program module (Rust programs::<program>, Python
programs.<program>) exposes the same, so a program package’s extension bundle
works unchanged in both.
a4 sdk create --rust|--python --manifest <file> generates a stack SDK
offline. --extensions <dir> applies the stack’s own bundle, and
--program-extensions <program>=<bundle> embeds a stack program’s own
package bundle (a directory holding extensions.json, or that file), staged
exactly as a4 install stack <package> --rust (or --python) stages the
published one. <program> is the program’s key in the stack SDK
(programs.<program>), its IDL name, or its program ID. Repeat the flag per
program; a program without one gets no extension. Each bundle’s
extensions.json must declare "language": "rust" (or "python") and pin
"inputKind": "program-spec" with the inputHash of that program’s
ProgramSpec in the StackManifest; anything else stops generation.
a4 sdk create --rust --manifest ./.arete/OreStream.stack-manifest.json \ --extensions ./sdks/ore/rust \ --program-extensions ore=./sdks/programs/ore/rust \ --output ./generated/ore-stackEvery install regenerates the whole project, and its summary says why each dependency was generated:
Installed 2 dependencies and wrote /app/arete.lockRequested: program ore@1.0.2Regenerated: stack ore@1.0.1 (inputs unchanged)Shared: program ore@1.0.2 is also provided by stack ore (the same program SDK release, generated identically in both)Runtime: the generated TypeScript needs these packages (a4 does not change package.json): npm install @usearete/sdk@0.23.0 @usearete/react@0.23.0 "zod@^3.24.1"Auth for stack ore: Live views: signed_session Chain reads: anonymous, publishable, secret keys; scopes read Transactions: publishable, secret keys; scopes transaction:inspect, transaction:send; the account needs the transaction entitlement Browser apps need a publishable key bound to the app's origin. Run `a4 doctor` to check this account's readiness.Requested lists what the command asked for (a package add, --no-save, or
the dependencies a4 update advanced). Regenerated lists every other
dependency with a reason such as inputs unchanged, newly locked, or
resolved 1.0.2, was 1.0.1. The auth block summarizes the requirements in a
hosted stack’s install descriptor: after a stack add it covers that stack, and
after a plain a4 install every hosted stack. With the global --json flag,
stdout carries one JSON document with requested, regenerated[] (kind,
alias, version, reason), shared[], auth[], runtime[],
sdkReferences[] (see SDK reference), notes[], and
warnings[] (see When a hosted stack version is retired),
and progress moves to stderr.
When the project generates TypeScript, Runtime lists the packages the
generated code imports, as one npm install line. @usearete/* packages are
released together with a4, so they are pinned to the CLI’s own version:
@usearete/sdk always, @usearete/react when the nearest package.json
depends on react, @usearete/adapter-web3js when it depends on
@solana/web3.js or a @solana/wallet-adapter-* package, and
@usearete/adapter-kit when it depends on @solana/kit. zod uses the range
@usearete/sdk declares. Without --setup, a4 never edits package.json
or runs a package manager; run the line with the package manager you use. In
--json output the same set is runtime[], each entry a
{ "package", "version" } pair.
The summary also lists what the project still needs to type-check and run the
generated code, and where each generated SDK’s reference is, after the auth
requirements so it ends the output. It prints no code: what an SDK exposes is
in its reference, and how to use SDKs in general is in the
TypeScript SDK docs and the arete-streams and
arete-programs agent skills. A missing package.json is not an error: the
install succeeds (exit code 0) and reports what is missing. Without
--setup, a4 prints these steps; it never creates
package.json or tsconfig.json, so you can set the project up your own way
(another package manager, a workspace, your own tsconfig.json). In a
directory with no package.json, they come as one block: what is missing,
the one command that sets it up with npm, and the same steps by hand,
numbered, in the order that works from an empty directory:
Setup: . has no package.json. The generated TypeScript (ES modules) needs: package.json, @usearete/sdk, zod, "type": "module", tsconfig.json. If the user has a preferred setup (pnpm, bun, a workspace, their own tsconfig), follow it. Otherwise either: - run `a4 install --setup` (npm: writes package.json and tsconfig.json, installs the packages), or - run these in order, in .: 1. npm init -y 2. npm pkg set type=module 3. npm install @usearete/sdk@0.34.0 "zod@^3.24.1" 4. npm install -D typescript tsx @types/node 5. npx tsc --init --module nodenext --target es2022 --types nodeSDK reference: stack ore: `a4 sdk describe ore --read <name>` or `--view <Entity/view>` prints one part with the row fields it uses (or the MCP tool describe_sdk). generated/typescript/stacks/ore/README.md lists everything: its import, views, row fields (TypeScript paths with their wire names, types and units), reads and programs.Using SDKs: sessions, auth, reading views and running operations: the arete-streams agent skill, or https://docs.arete.run/sdks/typescript/a4 install --setup re-runs the install from arete.toml, so it keeps the
options the stack was added with.
--setup (on a4 install or a package add such as
a4 install stack ore --ts --setup) does those steps itself when a TypeScript
output inside the project root has no package.json at or above it and the
root has none either. Outputs outside the root are not set up. In the project
root it writes a private package.json with
"type": "module", a typecheck script (tsc --noEmit), and a start
script (tsx index.ts) only when index.ts exists, writes a tsconfig.json for Node ES modules
(module/moduleResolution NodeNext, target ES2022, strict,
types: ["node"]; include covers the root’s own .ts files, src/, the
[sdk.typescript] output directory (so stacks installed later are checked
too) and any outputs configured elsewhere, so other apps beneath the root are
not checked as Node code) unless one is at or above the root, then runs
npm install for the runtime set and npm install -D for the development
tools. It never replaces an existing file, never prompts, and does nothing
for an app that already has a package.json. The summary reports what it did:
Setup: created package.json, tsconfig.json in .Setup: ran npm install @usearete/sdk@0.34.0 zod@^3.24.1Setup: ran npm install -D typescript tsx @types/nodeIn --json output it is setup (directory, created[] file paths, ran[]
commands, and failed naming the command that failed, when one did); npm’s
own output goes to stderr. When npm fails, the install itself still succeeds
and the guidance below lists what is left to do. --setup cannot be combined
with --no-save or --dry-run.
These steps are worked out per app: each output belongs to the directory of
its nearest package.json (or the project root when there is none), so a
project whose outputs land in separate Node and React apps gets separate
advice for each.
Setupappears when nopackage.jsonis at or above an output. It names what is missing, then givesa4 install --setupand the same steps by hand (npm init -ycomes first:npm pkg setneeds apackage.json). The generated code is ES modules, so the new package is set to"type": "module", and thetsc --initstep sets the options the generated code depends on, as--setupwrites them. The separateRuntime,Dev toolsandTsconfiglines are then left out, as the block covers them, except theTsconfigline for an existingtsconfig.jsonthat hides Node’s types.Dev toolslists the development packages the app’spackage.jsondoes not declare yet:typescript, plustsxand@types/nodefor a Node app (one that does not depend onreact).Tsconfigappears for a Node app with notsconfig.json(create one withtsc --init --module nodenext --target es2022 --types node, plusnpm pkg set type=modulefor a CommonJS package), or with one whosecompilerOptions.typesomits"node".tsc --initwrites"types": [], which hides@types/nodeand makestscreportprocessandBufferas unknown (TS2591).Browser keyappears for a React app: the variable its bundler exposes to browser code (VITE_ARETE_PUBLISHABLE_KEYfor Vite,NEXT_PUBLIC_ARETE_PUBLISHABLE_KEYfor Next.js, otherwiseARETE_PUBLISHABLE_KEY) and thea4 auth keys create-publishable --origin <origin> --env-file .env.localcommand that creates an origin-bound publishable key, with the directory to run it in (it picks the variable name from, and writes the env file in, the directory it runs in). A Node app needs no key setup: outside browsers the SDK usesARETE_API_KEYwhen it is set, else thea4login.SDK referencenames, for each SDK the command installed (every SDK after a plaina4 install), thea4 sdk describe <alias>command and thedescribe_sdkMCP tool, which print one part, and theREADME.mdin its folder, which lists everything.Using SDKsnames the agent skills and docs that cover generic usage.
In --json output these are typescriptApps[], one entry per app with
directory, kind (node or browser), devRuntime[] (package names),
projectSetup (directory, missing[], note, command
(a4 install --setup), commands[]),
tsconfig (tsconfig when one exists, directory, types[], commands[])
and publishableKey (envVar, command, directory), and
sdkReferences[] (kind, alias, target, readme, command, mcpTool,
usageSkills[], usageDocs). Each field is absent when there is nothing to
report, and typescriptApps is absent without TypeScript output.
Generated TypeScript is ES module source (import/export with .js
specifiers, which module: nodenext requires and tsc, tsx, Vite and
webpack map to the .ts files). In a project that resolves modules like a
bundler, where the output’s nearest tsconfig.json sets
moduleResolution: "bundler" (or module: "preserve"), directly or through
extends, as Next.js and Vite projects do, the relative specifiers that name
the SDK’s own .ts files are written without the .js instead, extension
files included: Turbopack (next dev and next build in Next.js 16) does
not map ./name.js to ./name.ts, so the SDK builds there without
turbopack.resolveAlias entries. The SDK’s content hash covers the files as
written. A project without a tsconfig.json keeps the .js.
A project whose nearest package.json is not "type": "module"
(npm init writes "commonjs") and whose tsconfig.json sets
verbatimModuleSyntax with a module setting that follows package.json
(nodenext, node16, node18 or node20), directly or through extends, as
tsc --init does, makes tsc reject every import in the project, its own
files’ as well as the generated SDK’s.
The summary then adds a Module type line with the fix:
Module type: package.json is CommonJS and tsconfig.json sets verbatimModuleSyntax, so tsc rejects every import (yours and the generated SDK's, which is ES modules). Make the package ES modules: npm pkg set type=moduleIn --json output it is moduleType, with packageJson, required
("module") and command; it is absent when the project compiles ES modules.
SDK reference
Section titled “SDK reference”Every TypeScript SDK a4 install generates carries its own reference: a
README.md in its folder (for a stack with program SDKs, one in each
programs/<key>/ folder too) and the sdk-reference.json it is rendered
from. It lists only what is specific to that SDK:
- the module to import and the exported definition, and the key a session
registers it under (
session.stacks.ore); - for each entity, its views (
statewith its key, orlist) and the fields of its rows: the TypeScript path (id.roundId), the wire name thata4 get,a4 streamand the MCPread_viewtool print (round_id), the type (64-bit integers arebigint), nullability, and for token amounts their scale (whole units or raw base units, and the power of ten between them); - the stack extension’s
read.*helpers, with parameters, what they return, title and description; - each program: its reads, operations (
instructions.*,transactions.*), accounts, raw instructions, PDAs and helpers.
How to use SDKs in general (sessions, auth, get/getOne/use/watch,
preparing and executing operations) is not repeated there; the reference
points to the docs and agent skills.
The generated row types carry the same facts as JSDoc, so editors and grep
show them:
export interface OreRoundId { /** Wire name `id.round_id` (CLI and MCP output). `bigint` (64-bit or wider): convert with `Number()`/`String()` before `JSON.stringify`. */ roundId: bigint | null;}a4 install writes the reference from the same metadata it generates the
SDK from, so it works for every published stack and program without
republishing them. The files are part of the SDK’s payload: its provenance
lists them and its sdkOutputTreeHash covers them, like every other
generated file, so ownership and drift checks treat them the same way.
Installs by an older a4 have no reference; run a4 install to add one.
a4 sdk describe
Section titled “a4 sdk describe”a4 sdk describea4 sdk describe orea4 sdk describe ore --view OreRound/latesta4 sdk describe ore --read currentRounda4 sdk describe ore --program orea4 --json sdk describe ore --view OreRoundPrint the reference of an installed SDK, read from its folder, never from the
registry: it describes exactly the version installed. Without an alias it
lists the project’s SDKs and where their references are. --view keeps one
entity (OreRound) or one of its views (OreRound/latest) with its fields,
--read one read or program operation (by name or path), with the fields of
the entities whose rows a stack read reads (rows in the JSON), and
--program one program with its reads, operations and accounts; the filters
combine. The README opens with a Contents index of the reads, views and
programs, so the part to print can be picked from its first lines. For a
TypeScript stack SDK, the README and each selection show an Example: a
script that reads the selected read (or the first view) once, prints the
result and exits. A read’s return shape types each field that holds a view
row or a program account ({ round: OreRound | null, ... }).
--kind stack|program picks the dependency when an alias names both. With
--json, stdout is { alias, kind, target, directory, readme, reference },
where reference is the selected part of sdk-reference.json. The MCP tool
describe_sdk takes the same alias, kind, view, read and program
arguments, plus format (markdown or json), and answers for the project
the MCP server runs in.
References are generated for TypeScript SDKs. Rust and Python SDKs use the wire names as field names; see their generated sources.
SDK extension compatibility
Section titled “SDK extension compatibility”An SDK extension’s extensions.json can declare extensionApi, a positive
integer naming the extension contract it was written against. Each SDK
records its own value: arete.extensionApi in the @usearete/sdk
package.json, [package.metadata.arete] extension-api in the
arete-a4-sdk crate, and EXTENSION_API_VERSION in the arete-sdk Python
package. When an extension declares extensionApi and the SDK is already
installed where the output is generated, the two must match: a4 stops with
an error that names both values and a fix. An installed SDK that does not
record the value yet produces a warning. The Rust SDK is read from a path
dependency or [patch] entry, or from Cargo’s source cache for the release
Cargo.lock pins; the Python SDK is read from the active virtual environment
or a .venv / venv directory above the output.
Without extensionApi, the older sdkRange field is compared with the
installed SDK version and a mismatch is only a warning, since published
ranges are often older than the SDK releases they work with.
Testing an unpublished SDK extension
Section titled “Testing an unpublished SDK extension”A registry program or stack dependency can generate its SDK with an extension bundle from a local directory instead of the published one, so you can try an extension in your app before publishing it:
[dependencies.programs.ore]source = { registry = "ore" }version = "^1.0.0"extensions = { path = "./extensions/ore" }The directory holds an extensions.json manifest naming the entry and its
files, or a single index.ts, extensions.rs or extensions.py entry. It
is staged exactly as a4 sdk create --extensions <dir> stages it. The bundle
extends one target: its language (TypeScript when it declares none), which
the dependency must generate. Other targets keep the published extension.
a4 install generates the SDK with the local bundle and records its content
hash on the dependency’s arete.lock entry. The entry’s other pins stay those
of the published release:
[[dependency]]kind = "program"alias = "ore"# … the published release's pins …local_extension = "3f1c…"While a dependency uses a local extension:
a4 install --check,a4 protocol deployanda4 dev promote --checkfail.a4 install --lockedrefuses to run untilextensionsis removed.a4 dev upwatches the bundle’s files and regenerates the SDK when one changes.
The override is not part of the lock’s resolution, so adding or removing it
leaves arete.lock fresh. To go back to the published extension, publish
yours upstream with a new package release, remove extensions from
arete.toml, and run a4 install --locked. That restores the published
extension and clears local_extension.
Program SDKs in stacks
Section titled “Program SDKs in stacks”A stack is a group of live views and program SDKs. When a stack references a
program package release for one of its programs, a4 install generates that
program’s SDK, including its SDK extension, under
stacks/<alias>/programs/<program>/, and arete.lock records the release as
the program’s package_release_hash. Every generated program definition
carries the same identity: packageReleaseHash in TypeScript,
PACKAGE_RELEASE_HASH in Rust, and <PROGRAM>_PACKAGE_RELEASE_HASH in
Python. Local and path builds carry none.
Installing the same program on its own is fine. When the standalone
dependency (under its default alias) and the stack reference the same program
package release, both outputs contain byte-identical program SDK files (in
the stack, the entry module is named __arete-program.ts), and the summary
reports the program as Shared. When the releases differ, both are generated and the
summary notes the difference. A stack whose programs have no program package
release keeps generating their core program SDKs.
a4 install --locked fails if a locked stack release would resolve a
different program package release than arete.lock records; nothing is
changed. A lock written by an older a4, which records no program package
releases, still installs with --locked if it records exactly the program SDK
extensions generated for the project’s targets; otherwise run a4 install
once to record the program SDK pins.
Rust and Python stack SDKs include each program’s SDK extension for their language, so a stack installs the same program surface as the program installed on its own:
- Rust: the program’s bundle is staged under
src/programs/<program>/(programs/<program>/in--moduleoutput) and wired into that program’s module inprograms.rs. Its bindings resolve underprograms::<program>, where a standalone program crate has them at the crate root. - Python: the program’s bundle is staged in a
program_sdks/<program>/subpackage laid out like the standalone program package, and the stack’sPROGRAMS(and itsStackDef) carry the extended program.
A stack with several live views cannot include Rust or Python program SDK extensions yet: installing one for Rust or Python fails with a message rather than generating a smaller surface.
A hosted Rust or Python SDK extension must declare the language it is served for, and its files must hash to the content hash the registry resolved; otherwise the install fails and nothing is generated or locked.
A stack with several live views applies a stack extension by name, because it
has no single stack for a default export to extend. Export
defineStackExtensions<typeof X.stacks.<alias>>() bindings for live aliases
and defineProgramExtensions<typeof X.programs.<key>>() bindings for session
programs, where X is the generated <NAME>_SESSION_DEFINITION_CORE. A stack
extension cannot also extend a program whose SDK brings its own extension; the
install fails rather than applying that extension twice.
A StackManifest name may contain any characters, for example
token-balances or my.stack. Generated file names keep the name as written
(token-balances.ts, token-balances-core.ts), so a name containing /,
\, or :, or a name that is . or .., is rejected. Generated identifiers treat
every character other than a letter, digit, or _ as a word boundary:
| Stack name | TypeScript | Rust | Python |
|---|---|---|---|
token-balances | TOKEN_BALANCES_STACK, TokenBalancesStack | TokenBalancesStack, crate token-balances-stack | TOKEN_BALANCES_STACK |
token_balances | TOKEN_BALANCES_STACK, TokenBalancesStack | TokenBalancesStack, crate token_balances-stack | TOKEN_BALANCES_STACK |
my.stack | MY_STACK_STACK, MyStackStack | MyStackStack, crate my-stack-stack | MY_STACK_STACK |
9lives | A9LIVES_STACK, A9livesStack | A9livesStack, crate a9lives-stack | VALUE_9LIVES_STACK |
Type names are always UpperCamelCase. Most stack names already generated
UpperCamelCase type names and keep generating exactly the same ones: names that
are UpperCamelCase (OreStream) and names with -, . or other separators
(token-balances, my.stack). Only a name that was kept as written but is not
UpperCamelCase, such as snake_case token_balances or all-lowercase
orestream, changes: token_balances, which used to generate
token_balancesStack, generates the Rust types TokenBalancesStack,
TokenBalancesStackViews and TokenBalancesStackPrograms, and the TypeScript
types TokenBalancesStack, TokenBalancesCoreStack, TokenBalancesEntity and
TokenBalancesPrograms. After regenerating such an SDK, update code that names
the old types. Constants (TOKEN_BALANCES_STACK), file names, crate names and
Python names do not change.
If two names generate the same identifier, for example a stack my-vault and
an entity MyVaultStack, or programs token-2022 and token_2022, generation
fails with an error that names both. Rename one of them.
When a hosted stack version is retired
Section titled “When a hosted stack version is retired”A hosted stack keeps serving the version each SDK was generated for, until
that version is retired. a4 install tells you when this affects a
dependency, and names the command that installs the version served now:
- Being retired. The version is still served, and
a4 installwarns with the date it is served until. - Retired.
a4 installstill installs it:arete.lockis unchanged, and the SDK is generated as before. Its connection, however, is refused with an error that names the served version.
To move to the served version, run the command a4 install prints, for
example a4 install stack ore@1.1.0, then rebuild your application. When the
warning names only the served version, install that version the same way
(a4 install stack <name>@<version>). When it names neither, run
a4 update stack <alias> to move to the newest version your requirement
allows.
A stack whose endpoints in arete.toml point at your own deployment does
not use the hosted version, so none of this affects its SDK.
A composed stack reads the hosted versions of the stacks it takes live views
from, so it gets the same warnings, naming the composed stack. A live view from
a retired version keeps its endpoints and is refused the same way. Its version
comes from the version requirement of that live entry in
[authoring.stacks]: change it to allow the served version, then run
a4 install.
With --json, these warnings are also in the document’s warnings[], and
go to stderr instead of stdout.
Deploying an installed stack
Section titled “Deploying an installed stack”A catalog stack without a hosted stream (a definition-only package) installs as an SDK whose endpoints are empty. Deploy it to your own account by its alias:
a4 install stack raydium-amm --tsa4 up raydium-amma4 up <alias> deploys exactly the StackManifest, LiveSpecs, and ProgramSpecs
arete.lock pins for that stack. a4 install keeps them in the registry cache
(~/.arete/cache/registry/v1); each cached file must still hash to its locked
identity, and a missing entry is fetched again at the locked release.
--dry-run --local-only never fetches, so it asks you to run a4 install
instead. The alias names the deployment unless an [authoring.stacks] entry
has the same name, which takes precedence.
After the deployment is healthy, a4 up points the generated SDK at it: it
records the deployment’s endpoints for the stack in arete.toml and runs
a4 install, so the SDK connects without a URL:
[dependencies.stacks.raydium-amm]source = { registry = "raydium-amm" }version = "^1.0.0"endpoints = { live = { websocket = "wss://raydium-amm.stack.arete.run", query = "https://raydium-amm.stack.arete.run" } }endpoints names every LiveSpec of the StackManifest by alias. For a hosted
stack they replace the managed stream endpoints (its managed gateway for chain
reads and transactions stays); remove them to use the stack’s own endpoints
again. When a4 update or a new version requirement moves the stack to a
different StackManifest, a4 install notes that the recorded deployment still
serves the previous one; redeploy it with a4 up <alias>. --branch,
--preview, and --json deployments leave arete.toml unchanged; pass their
endpoints to the client instead, for example useArete(stack, { url, httpUrl })
in TypeScript.
Composed stacks
Section titled “Composed stacks”A composed [authoring.stacks] entry groups live views and program SDKs from
published stacks, program packages, and local files. a4 stack compose writes
it (and with --install --ts the dependency below), or you can write it
yourself:
[authoring.stacks.ore-plus-token]live.ore = { stack = "ore", version = "^1", views = ["OreRound/latest", "OreMiner/state"] }programs = [{ package = "spl-token", version = "^1" }]
[dependencies.stacks.ore-plus-token]source = { workspace = "ore-plus-token" }targets = ["typescript"]a4 install resolves the parts and generates the composed stack like any
other stack dependency:
const arete = useArete(ORE_PLUS_TOKEN_STACK);arete.views.OreRound.latest.use();arete.programs.ore; // the program SDK the ore stack referencesarete.programs.token; // the spl-token program SDK- Program SDKs. Every program uses its program SDK. For programs the views
index, that is the program SDK their stack references, so
programs.orehas the same operations asa4 install program ore. Aprogramsentry for the same program replaces it, and the install output says so; the entry must have the ProgramSpec the views index. - Delivery. A live alias from a stack with hosted delivery reads that
stack’s deployment. The generated SDK uses its endpoints, and its sessions
name the version that deployment serves, exactly as the stack’s own SDK
does. The install output lists the account requirements. An alias from a
definition-only stack or a LiveSpec file has no endpoints.
a4 up <name>deploys the composed stack to your account and points the dependency’s SDK at it by recordingendpoints, as it does for an installed stack. - Lock.
arete.lockpins every part: stack and program package releases, LiveSpecs, each program’s program SDK release and extensions, and the composed StackManifest.a4 install --lockedfails if any of them would change, anda4 update stack <alias>advances them. - Stack extensions. A composed stack does not include a source stack’s stack extension (for example its extra reads). The install output notes each one it leaves out.
a4 install also writes the composed StackManifest and its artifacts to
.arete/compositions/<name>/. a4 up <name> deploys them only while they
match arete.lock.
Private programs and stacks
Section titled “Private programs and stacks”Owner-private programs (a4 program push) and private production stacks
(a4 up) publish immutable, owner-scoped registry packages as part of the
same lifecycle step that makes them ready or active, so they install through
the ordinary dependency workflow:
a4 auth login # private packages require the owner's sessiona4 install program My-Program --rust # by alias (case-insensitive)a4 install program upr_AbC123... --ts # by stable referencea4 install stack my-stack-a1b2 --python # by deployed atom namea4 install # reinstall: exact lock, never floatsa4 update program my-program # explicit update to the newest revisionFour things are kept distinct:
| Concept | Where it lives | Rule |
|---|---|---|
| Remote lookup | source = { registry = "My-Program" } | Sent to the registry unchanged; an alias, a stable upr_... reference, or a deployed stack name. |
| Local alias | the [dependencies.<kind>.<alias>] key and generated module/crate/package names | Derived deterministically from the lookup (lower-case, - separators, pkg- before a leading digit, -pkg after a reserved word) or set with --alias; must be a valid identifier in Rust, TypeScript, and Python. Regeneration on another machine yields the same names. |
| Version requirement | version = "^0.1.0" | Private revisions are platform-managed (0.1.0, then the next patch); the requirement is what a4 update may advance within. |
| Exact lock | arete.lock package_release_hash | Immutable release identity; reinstall resolves exactly this, a4 update replaces it only after generation succeeds. |
Public catalog packages win name resolution; the authenticated owner’s private package is consulted next. Another account, an anonymous client, or an unknown name all receive the same not-found response, and the CLI never retries a failed manifest lookup against a differently scoped endpoint. Optional server SDK extensions are optional: without them the core client is generated.
Chain reads and transaction submission for hosted programs and stacks use the
managed Solana gateway descriptor embedded in the generated SDK, not the
tenant stream URL; a stack descriptor reporting transactions: false describes
the tenant runtime endpoint, not the account’s entitlement.
Configuration File
Section titled “Configuration File”manifest_version = 1
[project]name = "my-project"private = true
[sdk]targets = ["typescript", "rust"]
[sdk.typescript]output_dir = "./src/generated"package = "@my-org/arete-generated"
[dependencies.stacks.ore]source = { registry = "ore" }version = "^1.4.0"# Optional: read the stack from your own deployment (`a4 up ore` writes this)# endpoints = { live = { websocket = "wss://...", query = "https://..." } }# Optional: generate with a local SDK extension instead of the published one# (see Testing an unpublished SDK extension)# extensions = { path = "./extensions/ore" }
[authoring.stacks.local]manifest = "./.arete/MyStack.stack-manifest.json"artifact_roots = ["./.arete"]
# A composed stack (`a4 stack compose` writes this; see Composed stacks)[authoring.stacks.ore-plus-token]live.ore = { stack = "ore", version = "^1.0.0", views = ["OreRound/latest"] }programs = [{ package = "spl-token", version = "^1.0.0" }]Default output paths are kind-scoped. TypeScript uses
<output_dir>/stacks/<alias> or <output_dir>/programs/<alias>. Rust and
Python use those same kind directories with an <alias>-stack or
<alias>-program leaf (plus any configured prefix). Stack and program aliases
may match; explicit per-dependency outputs are used exactly as written.
Run a4 config validate for offline strict-schema, local artifact closure,
output collision, path-policy, and lock-freshness checks.
Build Process
Section titled “Build Process”Status Flow
Section titled “Status Flow”pending → uploading → queued → building → pushing → deploying → completed ↘ failedBuild Phases
Section titled “Build Phases”| Phase | Description |
|---|---|
| SUBMITTED | Queued for processing |
| PROVISIONING | Starting build environment |
| DOWNLOAD_SOURCE | Preparing source |
| INSTALL | Installing dependencies |
| PRE_BUILD | Preparing build |
| BUILD | Compiling |
| POST_BUILD | Finalizing |
| UPLOAD_ARTIFACTS | Publishing image |
| FINALIZING | Deploying to runtime |
Typical Workflows
Section titled “Typical Workflows”First-Time Setup
Section titled “First-Time Setup”# Install the CLI (macOS / Linux; Windows: irm https://arete.run/install.ps1 | iex)curl -fsSL https://arete.run/install.sh | sh
# Set up the project: manifest, AGENTS.md, skills, MCP configa4 init -y
# Verifya4 doctor --json
# Discover live data (no account needed)a4 explore --json
# Only when deploying or using the knowledge layera4 auth signup # agenta4 auth login --profile human --key <a4_sk_...> # human-issued keyDevelopment Cycle
Section titled “Development Cycle”# Make changes to stack, rebuild Rust cratecargo build
# Deploy the generated manifesta4 up .arete/MyStack.stack-manifest.json
# Check statusa4 statusBranch Deploys
Section titled “Branch Deploys”# Deploy feature brancha4 up .arete/MyStack.stack-manifest.json --branch feature-x
# Check deploymenta4 stack list
# Clean up when donea4 stack stop my-stack --branch feature-xTelemetry
Section titled “Telemetry”Arete collects anonymous usage data to improve the CLI. No personal information or project details are sent.
a4 telemetry status
Section titled “a4 telemetry status”Show current telemetry status.
a4 telemetry statusa4 telemetry enable
Section titled “a4 telemetry enable”Enable telemetry collection.
a4 telemetry enablea4 telemetry disable
Section titled “a4 telemetry disable”Disable telemetry collection.
a4 telemetry disableEnvironment Variables
Section titled “Environment Variables”| Variable | Description |
|---|---|
ARETE_API_URL | Override API endpoint |
ARETE_PROFILE | Named credential profile outside initialized repos; .arete/auth.toml wins inside them |
ARETE_API_KEY | Legacy direct key override, used only when no profile is selected |
ARETE_CREDENTIALS_PATH | Override the credentials file |
ARETE_DEV_ENV | The dev environment a4 dev commands and the MCP dev tools act on (a name or an id) |
ARETE_REQUIRE_REGISTRY_SIGNATURES=1 | Require valid registry signatures even in bootstrap builds without trust anchors; official builds enforce them by default |
A4_INSTALL_DIR | Install directory for a4 self install and the bootstrappers |
A4_NO_MODIFY_PATH=1 | Do not edit shell profiles or the Windows PATH on install |
A4_NO_UPDATE_CHECK=1 | Disable the once-per-day “update available” notice |
A4_NON_INTERACTIVE=1 | Never prompt (same as --non-interactive) |
A4_VERSION | Version for install.sh / install.ps1 to install |
CI | When set: never prompt, no PATH edits, no update notice, no telemetry banner |
DO_NOT_TRACK=1 | Disable telemetry (standard) |
ARETE_TELEMETRY_DISABLED=1 | Disable telemetry (Arete-specific) |
Error Reference
Section titled “Error Reference”| Error | Solution |
|---|---|
Not authenticated | Run a4 auth signup (agent) or a4 auth login --profile human --key <a4_sk_…> |
registry-key-required | The registry needs an API key for this request: run a4 login (free), or set ARETE_API_KEY |
Registry signature: ... | A release is unsigned or its signature does not verify; see Signed releases |
a4: command not found | Run export PATH="$HOME/.local/bin:$PATH" or use the A4_BIN= path the installer printed; a4 doctor reports this as cli.path |
a4 was not installed by the Arete installer | Reinstall with curl -fsSL https://arete.run/install.sh | sh; Cargo builds must use cargo install a4-cli --force |
Stack not found | Check a4 stack list for available stacks |
Stack file not found | Run cargo build to generate stack spec |
Build failed | Try again |
Config invalid | Run a4 config validate |
Endpoint and DNS Handoff
Section titled “Endpoint and DNS Handoff”After deployment, inspect the returned binding or use a4 stack show to obtain
the assigned endpoints. Live WebSocket/query, Program Read, chain-read, and
transaction endpoints are separate bindings and must not be derived from one
another.
a4 stack show <deployed-stack-name>Arete does not require a particular DNS provider. If a deployment should use a custom hostname, the operator configures the record, certificate, and any CDN or proxy policy with the provider of their choice after receiving the binding.