Skip to content

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 .md to the URL or sending Accept: 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.


Prebuilt, signed binary. No Rust toolchain or account required.

Terminal window
curl -fsSL https://arete.run/install.sh | sh # macOS / Linux
irm https://arete.run/install.ps1 | iex # Windows PowerShell
npx @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/a4
export 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 / variableDescription
VERSION, A4_VERSIONInstall a specific version instead of the latest
--install-dir <DIR>, A4_INSTALL_DIRInstall directory (default ~/.local/bin; XDG_BIN_HOME is honoured)
--no-modify-path, A4_NO_MODIFY_PATH=1Do not edit shell profiles or the Windows user PATH; CI also skips it

Then, in a project:

Terminal window
a4 init -y # arete.toml, AGENTS.md block, CLAUDE.md import, skills, MCP config
a4 doctor --json # ready when the JSON status is "ok"
a4 explore --json # live data, no account needed

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.

Terminal window
cargo install a4-cli

OptionDescription
--config, -c <path>Path to arete.toml (default: arete.toml)
--jsonOutput as JSON on stdout; logs go to stderr. Every object has schemaVersion
--yes, -yAccept defaults; never prompt
--non-interactiveNever prompt; a missing required input is an error naming the flag to pass
--verboseEnable verbose output
--api-url <url>Override the API endpoint
--help, -hShow help
--version, -VShow 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).

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 --json and a4 build status --json print websocket_url and created_at. a4 explore --json keeps 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_auth and provenance in a4 build status --json, knowledge in a4 explore --json, and everything a4 know --json prints.

Scripts that read inside those pass-through objects should accept both spellings.


CommandDescription
a4 create [name]Scaffold a new app from a template
a4 initSet up the project for Arete and coding agents
a4 doctorCheck install, project, auth, agents
a4 self installFinish installing the a4 binary
a4 self update / a4 upgradeUpdate a4 in place
a4 self uninstallRemove a4
a4 mcpRun the stream MCP server (stdio)
a4 auth signupRegister an agent account
a4 login / a4 auth loginSave an API key (accounts are free)
a4 program build <idl>Build a portable ProgramSpec
a4 stack composeCompose live views and program SDKs
a4 sdk describe <alias>Print an installed SDK’s reference (views, fields, reads)
a4 sdk create --manifest ... --tsGenerate a TypeScript SDK offline from a StackManifest
a4 sdk create --manifest ... --rustGenerate a Rust SDK from a StackManifest
a4 sdk create --program-spec ... --rustGenerate 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 upDevelop 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-listingAsk for your deployment to be listed
a4 protocol listing-statusYour deployment’s listing state
a4 protocol webhook add|list|remove|testThe webhook endpoints that receive your deployment’s events
a4 squads status|list|attachYour 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 statusShow project overview
a4 stack listList deployed stacks
a4 telemetry statusShow telemetry status
a4 explore, a4 explore stacksDiscover installable stacks
a4 explore programsDiscover 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 conceptsConcept and category vocabularies

Scaffold a new Arete project from a template. This is the fastest way to get started.

Terminal window
# Interactive — prompts for name and template
npx @usearete/a4 create
# With project name
npx @usearete/a4 create my-app
# A protocol with a React app and an automations server
npx @usearete/a4 create my-app --template protocol-app

Available templates:

TemplateAliasesDescription
protocolA protocol: the a4 protocol init tip jar and its automations
protocol-appThe 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-oreore-reactORE mining rounds viewer (React + Vite)
rust-oreore-rustORE mining rounds client (Rust + Tokio)
typescript-oreore-typescript, ts-ore, ore-tsORE mining rounds client (TypeScript CLI)

Options:

FlagDescription
--template <name>Skip interactive selection
--offlineUse cached templates only
--force-refreshClear template cache and re-download
--skip-installDon’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/.


Set up the current directory for Arete and for the coding agents that work in it.

Terminal window
a4 init -y # the agent running it + agents with project config
a4 init -y --json # machine-readable report
a4 init -y --dry-run # report what would change, write nothing
a4 init -y --global # skills and MCP config for your user, not the project
a4 init -y --agents cursor,codex # explicit agent list (also: all | none)
a4 init -y --no-skills --no-mcp # manifest and AGENTS.md only

What it writes (every item is an upsert and reports created | updated | unchanged | skipped(reason)):

ItemPathNotes
Manifestarete.tomlCreated if absent; left untouched if present unless --force, which rewrites only [project]. Name from --name or the directory basename
Auth profile.arete/auth.tomlProject scope only. Non-secret default selecting only the restricted agent profile; a repository cannot select human
Agent guidanceAGENTS.mdA managed block between <!-- BEGIN:arete v2 --> and <!-- END:arete -->; content outside the markers is never touched
Claude Code bridgeCLAUDE.mdCreated as @AGENTS.md, or that line is inserted first if the file exists
Gemini context.gemini/settings.jsoncontext.fileName gains AGENTS.md (Gemini CLI only)
Skillsper 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 configper 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:

FlagDescription
-y, --non-interactiveNever prompt
--jsonJSON report (below)
--dry-runSame report with dryRun: true and would-* statuses; writes nothing
--forceRewrite 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)
--globalInstall skills and MCP config for your user instead of the project
--no-manifest, --no-agents-md, --no-skills, --no-mcpSkip 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.

AgentProject signalMCP 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
opencodeopencode.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").

Read-only check of everything init writes plus the environment.

Terminal window
a4 doctor
a4 doctor --json
a4 doctor --summary # the overall status first, then only what needs attention
a4 doctor --fix # re-run the init writers for every agents.* warning, then re-check

With --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 idWhat it verifiesOn failure
cli.versionInstall receipt present; current version vs latest (2 s timeout)warn: a4 self update (info when offline)
cli.installReceipt binary is the running executable; no a4 shadowing it on PATHwarn with the shadowing path
cli.pathInstall directory is on PATHwarn: prints the export PATH=… line
project.manifestarete.toml parsesfail: a4 init / a4 config validate
project.lockarete.lock is freshwarn: a4 install
project.auth-profile.arete/auth.toml selects only the restricted agent profilewarn/fail: a4 doctor --fix
sdk.runtimeInstalled TypeScript runtime matches the generated SDKs (see below)warn with an npm install line; fail only for an extensionApi mismatch
auth.credentialsKey present for the active API URLinfo: a4 auth signup (not needed to explore)
auth.whoamiCredentials are accepted by the serverfail: a4 auth login --key …
account.planThe account’s plan and dev environment tierunknown 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-readOne Program Read existence check for the first registry program in arete.tomlwarn with the HTTP status and error code; retryable failures say so
probe.chain-readOne chain account read through the gateway for the same programwarn with the HTTP status and error code; retryable failures say so
net.apihttps://api.arete.run reachablefail
net.docs-mcphttps://docs.arete.run/mcp reachablewarn
tools.nodenpx on PATH (skills only)info
tools.rustcargo on PATH (authoring only)info; warn if arete.toml has [authoring]
agents.detectedDetected agentsinfo
agents.<id>.mcpBoth MCP servers present with the expected shapewarn: a4 doctor --fix
agents.<id>.skillsAll six Arete workflow skills installed for that agentwarn: npx skills add AreteA4/skills --agent <id>
agents.agents-mdAGENTS.md block present and current (v2)warn: a4 doctor --fix
agents.claude-mdCLAUDE.md imports @AGENTS.md (Claude Code only)warn
agents.gemini-contextGemini context.fileName includes AGENTS.md (Gemini CLI only)warn
agents.codex-trustProject 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.

Validate your configuration.

Terminal window
a4 config validate

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.

Terminal window
a4 self install [--install-dir <DIR>] [--no-modify-path] [--source <sh|ps1|npm|manual>]
[--checksums <FILE> --signature <FILE>] [--force] [--json]
FlagDescription
--install-dir <DIR>Target directory (else A4_INSTALL_DIR, XDG_BIN_HOME, ~/.local/bin)
--no-modify-pathSkip 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
--forceCopy 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.

Replace the installed binary with a newer (or an explicitly chosen) release. a4 upgrade is an alias with identical arguments.

Terminal window
a4 self update # latest
a4 self update 0.14.0 # specific version (downgrades allowed when explicit)
a4 self update --check # exit 10 if an update is available, 0 if current
a4 self update --check --json # {"current","latest","updateAvailable"}
a4 self update --dry-run # download and verify, print the plan, change nothing

The 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.

Terminal window
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.


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.

Terminal window
a4 mcp

a4 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.

Validate your configuration.

Terminal window
a4 config validate

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.

Register a new agent account and store its key.

Terminal window
a4 auth signup # server picks a display name
a4 auth signup my-agent # explicit display name
a4 --profile agent auth signup --if-missing --json # safe, idempotent bootstrap
a4 auth signup --force # replace credentials that already exist for this API URL

Calls 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:

FlagDescription
[name]Display name (optional)
--if-missingVerify and reuse a valid agent credential; sign up only when one is absent
--forceOverwrite 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_…>.

Save a human-issued API key. a4 login is the same command.

Terminal window
# Prompts for the key only in an interactive terminal
a4 auth login
a4 login
# Pass directly (required when non-interactive)
a4 auth login --profile human --key <a4_sk_...>

Options:

FlagDescription
--key, -kAPI key. When omitted in a non-interactive run the error lists this flag and a4 auth signup

Remove stored credentials.

Terminal window
a4 auth logout

Check local authentication status.

Terminal window
a4 auth status

Verify authentication with server.

Terminal window
a4 auth whoami

It 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.

List, create or delete your API keys, or create a publishable key for browser code.

Terminal window
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:5173
a4 auth keys create-publishable --origin https://app.example.com --name web --env-file .env.local
a4 auth keys create-publishable --origin http://localhost:5173 --json

create 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:

FlagDescription
--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):

DetectedVariable
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 elseARETE_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.


Search the public active catalog by intent and required delivery mode:

Terminal window
a4 explore catalog --json # overview: first programs and stacks
a4 explore catalog --query "monitor swaps" --json
a4 explore catalog --concept <slug> --kind program --mode read --json
a4 explore catalog --category <slug> --kind stack --mode subscribe --json
a4 explore catalog --kind program --target typescript --json
a4 explore catalog --vocabulary --json # slugs and names
# Inspect one exact active entry
a4 explore catalog program <slug> --json
a4 explore catalog stack <slug> --json
# More or fewer fields than the brief default
a4 explore catalog --query "monitor swaps" --full --json
a4 explore catalog --query "monitor swaps" --fields slug,kind,version,delivery.health
a4 explore catalog --vocabulary --full --json
OptionMeaning
--query <text>Free-text intent search
--concept <slug>Require an exact concept
--category <slug>Require an exact category
--kind program|stackRestrict package kind
--mode read|build|subscribeRequire a delivery mode
--target typescript|rust|pythonRequire a verified SDK target
--limit, --cursorPagination: 10 results per page by default; pass nextCursor as --cursor with the same filters
--vocabularyList current concept and category slugs and names
--fullEvery field instead of the brief default (search and --vocabulary)
--fields <a,b.c>JSON with only these keys per entry
--brief, --summaryJSON 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.

Discover installable resources through the same deployment-pinned descriptors used by a4 install. Public resources work without authentication; logging in also exposes global resources.

Terminal window
# List all available stacks
a4 explore
# Search by intent and inspect an exact stack descriptor
a4 explore catalog --query "monitor swaps" --kind stack --mode subscribe
a4 explore stack <stack-ref>
# List and inspect standalone programs
a4 explore programs
a4 explore program spl-token
# Legacy stack and entity forms remain supported
a4 explore <stack-ref>
a4 explore <stack-ref> <Entity>
# JSON output (for agents and scripts)
a4 explore --json
a4 explore programs --json
a4 explore stack <stack-ref> --json
a4 explore program spl-token --json
a4 explore <stack-ref> <Entity> --json
# Compact by default; ask for the part you need
a4 explore stack ore --json
a4 explore stack ore --views OreRound/latest,OreMiner/state --json
a4 explore stack ore --full --json
a4 explore program ore --full --json
a4 explore program ore --operation transactions.mining.deployWithCheckpoint --json
a4 explore program ore --operation deploy --json
a4 explore program ore --section accounts,types --json
a4 explore stack ore --operation transactions.mining.deployWithCheckpoint --json

Arguments:

ArgumentDescription
<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:

FlagApplies toDescription
--summarystack, programThe compact summary, which is also the default
--fullstack, programThe full exploration: identity hashes, every auth surface and endpoint, SDK metadata; for a program, the IDL-level dump
--views <ids>stackOnly 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, stackOne operation, by semantic path (transactions.mining.deployWithCheckpoint), full operation id, generated binding, or raw instruction name (deploy)
--section <name>programOnly accounts, events, instructions (with error codes), operations, or types. Repeat the flag or comma-separate

Output varies by specificity:

CommandShows
a4 explore, a4 explore stacksAvailable stacks
a4 explore programsComplete 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> --fullExact 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> --fullProgram identity, accounts, instructions, events and types in full, Program Read, and install command
a4 explore program <ref> --operationOne operation: generated paths, input type, required and derived accounts, signers, transaction count, errors, transport, usage
a4 explore program <ref> --sectionThe 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>.

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.

Terminal window
# Search by intent; results carry read / build / subscribe coverage flags
a4 know search --query "monitor swaps"
a4 know search --concept swap --category dex --limit 10
# One protocol: programs with roles, related protocols, live stacks, coverage
a4 know protocol meteora-damm
# One program's annotations, one section at a time
a4 know program meteora-cp-amm # summary (default)
a4 know program meteora-cp-amm --section instructions
a4 know program meteora-cp-amm --section accounts
a4 know program meteora-cp-amm --section surface # typed SDK operations with bindings
# One cross-protocol recipe
a4 know recipe execute-presale-purchase-via-squads
# Concept and category slugs for --concept / --category
a4 know concepts # slugs and names
a4 know concepts --full # with descriptions, synonyms and related concepts

search options:

FlagDescription
--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)
--fullEvery field per result (score, coverage_via)
--fields <a,b.c>JSON with only these keys (or dotted paths) per result
--briefJSON 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:

FlagDescription
--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.


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.

Terminal window
# The current ORE round (OreRound/latest is sorted newest first)
a4 get OreRound/latest --stack ore --limit 1
# Only the fields you need
a4 get OreRound/latest --stack ore --limit 1 \
--select id.round_id,state.total_deployed,treasury.motherlode
# One entity by key
a4 get OreRound/state --stack ore --key 434161
# Filter the snapshot
a4 get OreRound/latest --stack ore --where 'state.total_deployed>8' --limit 5
FlagDescription
-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).

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.

FlagMeaning
--devstream 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
--allevery 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
Terminal window
a4 stream --dev
a4 stream --dev --tui
a4 stream --dev localTipJar Activity --where step=open
a4 stream --dev localTipJar --instance 99e8592f-6b0f-472a-9716-45ca0ef97f11
a4 stream --dev --all --raw | jq -c '{protocol, stack, view, op}'

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.

Terminal window
# Deploy an exact manifest
a4 up .arete/MyStack.stack-manifest.json
# Deploy to branch
a4 up .arete/MyStack.stack-manifest.json --branch staging
# Preview deployment
a4 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-amm

Options:

FlagDescription
--branch, -b <name>Deploy to named branch
--previewCreate preview deployment
--dry-runShow 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] 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.

Terminal window
a4 protocol init my-protocol
cd my-protocol && npm install && npx arete-protocol check && a4 dev up

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.

Terminal window
a4 protocol deploy # the protocol in the current directory
a4 protocol deploy ./my-protocol # builds first, then deploys
a4 protocol deploy --no-build # upload the existing build, if it is current
a4 protocol deploy --dry-run # print the plan and run the server's checks; changes nothing
a4 protocol deploy \
--creator-fee-wallet <pubkey> \
--resource launchDefaults=launch-defaults.json
a4 protocol deploy --no-activate --json

The command:

  1. Builds the project (npx --no arete-protocol build), unless you pass --no-build. With --no-build it 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’s sourceTreeSha256), and the error names the changed and deleted files.
  2. Pushes the programs the project installed from a local IDL ([dependencies.programs] with source = { 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 as a4 program push does: 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.toml keeps the IDL source. arete.lock records the program’s program_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 install keeps the recorded release while the IDL’s ProgramSpec is unchanged. An IDL that no longer matches arete.lock is refused: run a4 install first. With --no-build the program is pushed but arete.lock is left as it is. --dry-run lists the programs and pushes nothing.
  3. 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.
  4. Finds your protocol by slug or creates it. The slug defaults to the spec name in kebab case (tokenRaise becomes token-raise).
  5. Uploads the release. Re-uploading an identical release is a no-op.
  6. 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.
  7. Activates the deployment, unless it is already active or you passed --no-activate.
  8. When the deployment is active and the project installs its own protocol ([dependencies.protocols] with this slug, which a4 dev up adds), 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 and arete.lock marks it local_build (the command says so). Run a4 install once 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 is pending, 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.
FlagDescription
--no-buildUpload the existing .arete/protocol/ output instead of building; refused when the sources changed since that build
--dry-runPrint 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-activateCreate or reuse the deployment without activating it
--jsonPrint 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>" # optional
access = "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 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.

Terminal window
a4 protocol actions token-raise --wallet <pubkey>
a4 protocol actions token-raise --wallet <pubkey> --instance <id> --json
a4 protocol actions --dev --wallet default # a dev wallet name or a pubkey
FlagDescription
--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
--jsonThe answer as JSON

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).

Terminal window
a4 squads status # setup, proposer, attached multisigs
a4 squads status <M> # one multisig: members, deployments, proposals
a4 squads list
a4 squads attach <M> --label Treasury
FlagDescription
--label <text>attach: a label for the dashboard (1 to 64)
--jsonThe answer as JSON

Dev environments keep their own proposer: use a4 protocol squads --dev and a4 dev squads there.

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.

Terminal window
a4 protocol squads proposer <deployment>
a4 protocol squads status <deployment> --multisig <M>
a4 protocol squads status --dev --multisig <M>
  • proposer prints the proposer’s public key and, when an RPC answers (--rpc-url, ARETE_MCP_RPC_URL, or the dev environment), its balance.
  • status says 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) or proposer_unfunded (send it SOL; in a dev environment a4 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.

FlagDescription
--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
--jsonThe 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 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.

Terminal window
a4 protocol search
a4 protocol search "tip jar"
a4 protocol search tips --limit 50 --json
a4 protocol show tip-jar

Each 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 tierMeaning
reviewed by AreteArete reviewed this release; a4 protocol show prints the review hash
unreviewedNobody at Arete reviewed its code; read its steps and spec before you rely on it
FlagDescription
--limit <n>Results per page, 1 to 50 (default 20)
--cursor <cursor>The next page (printed after the table)
--jsonThe registry’s page as JSON

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 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.

Terminal window
a4 protocol request-listing
a4 protocol request-listing --deployment <id> --note "Ready for review"
a4 protocol listing-status
a4 protocol listing-status --deployment <id> --json
FlagDescription
--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
--jsonThe listing state as JSON

A request can be refused:

CodeWhat to do
protocol-listing-not-publicOnly public deployments are listed; self-serve deployments are private. Ask Arete to make it public
protocol-listing-edges-privateThe protocol uses private stacks or programs (the error names them). Use public ones and deploy again
protocol-listing-fee-policyThe deployment’s fees predate Arete’s current fee rules. Deploy again, then request the listing for the new deployment
protocol-listing-not-ownerUse a secret key of the account that owns the deployment
protocol-listing-account-standingThe account cannot list protocols right now; contact Arete support

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.

Terminal window
a4 protocol webhook add --url https://app.example/arete/webhook
a4 protocol webhook add --url https://app.example/arete/webhook --events tipJar.tipped,tipJar.closed
a4 protocol webhook add --url https://<worker>.workers.dev/arete/webhook --secret-only \
| npx wrangler secret put ARETE_WEBHOOK_SECRET
a4 protocol webhook list
a4 protocol webhook test <webhook-id> # send a signed test delivery now
a4 protocol webhook remove <webhook-id> # disable the endpoint
FlagDescription
--url <url>add: the endpoint’s https URL
--events <a,b>add: event names (default: every event the project’s build declares)
--secret-onlyadd: print only the signing secret
--deployment <id>The deployment (default: the project’s)
--dir <dir>The protocol project to read (default .)
--jsonThe 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.

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.

Terminal window
a4 dev up # create or wake the environment, serve it, deploy
a4 dev status # the environment, the session and the chain
a4 dev list # your environments and quotas
a4 dev fund default 50 # 50 SOL for the dev wallet `default`
a4 dev fund <owner> --mint <mint> --amount 1000000
a4 dev warp +2h # move the clock forward
a4 dev checkpoint before-test # save the state; restore or branch from it
a4 dev restore before-test
a4 dev rebase # refetch every account you never wrote
a4 dev pin <pubkey> # never refresh this account
a4 dev step open --args '{"amount":"1000"}' --wallet default
a4 dev sleep # or let it sleep when idle
a4 dev delete --yes
CommandWhat 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-overtake 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 deletelifecycle
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 followbalances and freshness of accounts
a4 dev warp, a4 dev pause, a4 dev resumethe clock
a4 dev scenario <file>, a4 dev preview <tx>, a4 dev repro <sig>scenarios, previews and repro exports
a4 dev events, a4 dev tokenlifecycle events; an environment token with the RPC URLs
a4 dev step, a4 dev wallet, a4 dev instance, a4 dev replaydrive the protocol with local dev wallets
a4 dev sdk, a4 dev capturethe 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-executeSquads 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.

Show overview of all stacks, builds, and deployments.

Terminal window
a4 status
a4 status --json

Normalize an IDL into a portable, endpoint-free ProgramSpec:

Terminal window
a4 program build ./idl/my-program.json \
--output ./.arete/my-program.program-spec.json
# Supply the program ID when the IDL omits it
a4 program build ./idl/my-program.json \
--program-id <program-id> \
--output ./.arete/my-program.program-spec.json

The output describes public program behavior. It does not select a hosted decoder release or Program Read endpoint.

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.

Terminal window
# ORE's round and miner views, plus the spl-token program SDK
a4 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 SDK
a4 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.

ValuePart
--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>.jsonA 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:

Terminal window
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.json

Repeat --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.

List all stacks with their deployment status.

Terminal window
a4 stack list
a4 stack list --json

Output:

STACK STATUS VERSION URL
settlement-game active v3 wss://settlement-game.stack.arete.run
token-tracker active v1 wss://token-tracker.stack.arete.run

Show detailed stack information including deployment status and versions.

Terminal window
a4 stack show my-stack
a4 stack show my-stack --version 3
a4 stack show my-stack -v 3

Options:

FlagDescription
--version, -v <n>Show specific version details

Output includes:

  • Entity information
  • Deployment status and URL
  • Latest version details
  • Recent builds

Show version history.

Terminal window
a4 stack versions my-stack
a4 stack versions my-stack --limit 10
a4 stack versions my-stack -l 10

Options:

FlagDescription
--limit, -l <n>Maximum number of versions (default: 20)

Delete a stack from remote.

Terminal window
a4 stack delete my-stack
a4 stack delete my-stack --force # Skip confirmation
a4 stack delete my-stack -f

Options:

FlagDescription
--force, -fSkip confirmation prompt

Stop a deployment.

Terminal window
a4 stack stop my-stack
a4 stack stop my-stack --branch staging
a4 stack stop my-stack --force # Skip confirmation

Options:

FlagDescription
--branch <name>Branch deployment to stop
--force, -fSkip confirmation prompt

Terminal window
a4 install
a4 install --locked
a4 install --check
a4 install --dry-run
a4 install stack ore@^1.4.0 --ts
a4 install stack ore --ts --setup
a4 install program spl-token@=4.0.2 --rust
a4 install program ./idl/my_program.json --as my-program --ts
a4 update
a4 update stack ore
a4 remove program spl-token
a4 remove stack ore --keep-output

With 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.

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.

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.

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:

Terminal window
a4 install program ./idl/my_program.json --as my-program --ts
a4 install program ./idl/legacy.json --program-id <address> --ts # an IDL with no address

Run 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.

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.

Terminal window
a4 sdk create --rust --program-spec ./.arete/ore.program-spec.json \
--extensions ./sdks/programs/ore/rust --output ./generated/ore-program
a4 sdk create --python --program-spec ./.arete/ore.program-spec.json \
--extensions ./sdks/programs/ore/python --output ./generated/ore-program-py

An 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.

Terminal window
a4 sdk create --ts --program-only --idl ./idl/ore.json \
--read-endpoint https://arete.example.com

SDKs 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.

Terminal window
a4 sdk create --rust --manifest ./.arete/OreStream.stack-manifest.json \
--extensions ./sdks/ore/rust \
--program-extensions ore=./sdks/programs/ore/rust \
--output ./generated/ore-stack

Every install regenerates the whole project, and its summary says why each dependency was generated:

Installed 2 dependencies and wrote /app/arete.lock
Requested: program ore@1.0.2
Regenerated: 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 node
SDK 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.1
Setup: ran npm install -D typescript tsx @types/node

In --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.

  • Setup appears when no package.json is at or above an output. It names what is missing, then gives a4 install --setup and the same steps by hand (npm init -y comes first: npm pkg set needs a package.json). The generated code is ES modules, so the new package is set to "type": "module", and the tsc --init step sets the options the generated code depends on, as --setup writes them. The separate Runtime, Dev tools and Tsconfig lines are then left out, as the block covers them, except the Tsconfig line for an existing tsconfig.json that hides Node’s types.
  • Dev tools lists the development packages the app’s package.json does not declare yet: typescript, plus tsx and @types/node for a Node app (one that does not depend on react).
  • Tsconfig appears for a Node app with no tsconfig.json (create one with tsc --init --module nodenext --target es2022 --types node, plus npm pkg set type=module for a CommonJS package), or with one whose compilerOptions.types omits "node". tsc --init writes "types": [], which hides @types/node and makes tsc report process and Buffer as unknown (TS2591).
  • Browser key appears for a React app: the variable its bundler exposes to browser code (VITE_ARETE_PUBLISHABLE_KEY for Vite, NEXT_PUBLIC_ARETE_PUBLISHABLE_KEY for Next.js, otherwise ARETE_PUBLISHABLE_KEY) and the a4 auth keys create-publishable --origin <origin> --env-file .env.local command 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 uses ARETE_API_KEY when it is set, else the a4 login.
  • SDK reference names, for each SDK the command installed (every SDK after a plain a4 install), the a4 sdk describe <alias> command and the describe_sdk MCP tool, which print one part, and the README.md in its folder, which lists everything. Using SDKs names 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=module

In --json output it is moduleType, with packageJson, required ("module") and command; it is absent when the project compiles ES modules.

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 (state with its key, or list) and the fields of its rows: the TypeScript path (id.roundId), the wire name that a4 get, a4 stream and the MCP read_view tool print (round_id), the type (64-bit integers are bigint), 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.

Terminal window
a4 sdk describe
a4 sdk describe ore
a4 sdk describe ore --view OreRound/latest
a4 sdk describe ore --read currentRound
a4 sdk describe ore --program ore
a4 --json sdk describe ore --view OreRound

Print 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.

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.

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 deploy and a4 dev promote --check fail.
  • a4 install --locked refuses to run until extensions is removed.
  • a4 dev up watches 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.

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 --module output) and wired into that program’s module in programs.rs. Its bindings resolve under programs::<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’s PROGRAMS (and its StackDef) 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 nameTypeScriptRustPython
token-balancesTOKEN_BALANCES_STACK, TokenBalancesStackTokenBalancesStack, crate token-balances-stackTOKEN_BALANCES_STACK
token_balancesTOKEN_BALANCES_STACK, TokenBalancesStackTokenBalancesStack, crate token_balances-stackTOKEN_BALANCES_STACK
my.stackMY_STACK_STACK, MyStackStackMyStackStack, crate my-stack-stackMY_STACK_STACK
9livesA9LIVES_STACK, A9livesStackA9livesStack, crate a9lives-stackVALUE_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.

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 install warns with the date it is served until.
  • Retired. a4 install still installs it: arete.lock is 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.

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:

Terminal window
a4 install stack raydium-amm --ts
a4 up raydium-amm

a4 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.

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 references
arete.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.ore has the same operations as a4 install program ore. A programs entry 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 recording endpoints, as it does for an installed stack.
  • Lock. arete.lock pins every part: stack and program package releases, LiveSpecs, each program’s program SDK release and extensions, and the composed StackManifest. a4 install --locked fails if any of them would change, and a4 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.

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:

Terminal window
a4 auth login # private packages require the owner's session
a4 install program My-Program --rust # by alias (case-insensitive)
a4 install program upr_AbC123... --ts # by stable reference
a4 install stack my-stack-a1b2 --python # by deployed atom name
a4 install # reinstall: exact lock, never floats
a4 update program my-program # explicit update to the newest revision

Four things are kept distinct:

ConceptWhere it livesRule
Remote lookupsource = { registry = "My-Program" }Sent to the registry unchanged; an alias, a stable upr_... reference, or a deployed stack name.
Local aliasthe [dependencies.<kind>.<alias>] key and generated module/crate/package namesDerived 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 requirementversion = "^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 lockarete.lock package_release_hashImmutable 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.

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.

pending → uploading → queued → building → pushing → deploying → completed
↘ failed
PhaseDescription
SUBMITTEDQueued for processing
PROVISIONINGStarting build environment
DOWNLOAD_SOURCEPreparing source
INSTALLInstalling dependencies
PRE_BUILDPreparing build
BUILDCompiling
POST_BUILDFinalizing
UPLOAD_ARTIFACTSPublishing image
FINALIZINGDeploying to runtime

Terminal window
# 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 config
a4 init -y
# Verify
a4 doctor --json
# Discover live data (no account needed)
a4 explore --json
# Only when deploying or using the knowledge layer
a4 auth signup # agent
a4 auth login --profile human --key <a4_sk_...> # human-issued key
Terminal window
# Make changes to stack, rebuild Rust crate
cargo build
# Deploy the generated manifest
a4 up .arete/MyStack.stack-manifest.json
# Check status
a4 status
Terminal window
# Deploy feature branch
a4 up .arete/MyStack.stack-manifest.json --branch feature-x
# Check deployment
a4 stack list
# Clean up when done
a4 stack stop my-stack --branch feature-x

Arete collects anonymous usage data to improve the CLI. No personal information or project details are sent.

Show current telemetry status.

Terminal window
a4 telemetry status

Enable telemetry collection.

Terminal window
a4 telemetry enable

Disable telemetry collection.

Terminal window
a4 telemetry disable

VariableDescription
ARETE_API_URLOverride API endpoint
ARETE_PROFILENamed credential profile outside initialized repos; .arete/auth.toml wins inside them
ARETE_API_KEYLegacy direct key override, used only when no profile is selected
ARETE_CREDENTIALS_PATHOverride the credentials file
ARETE_DEV_ENVThe dev environment a4 dev commands and the MCP dev tools act on (a name or an id)
ARETE_REQUIRE_REGISTRY_SIGNATURES=1Require valid registry signatures even in bootstrap builds without trust anchors; official builds enforce them by default
A4_INSTALL_DIRInstall directory for a4 self install and the bootstrappers
A4_NO_MODIFY_PATH=1Do not edit shell profiles or the Windows PATH on install
A4_NO_UPDATE_CHECK=1Disable the once-per-day “update available” notice
A4_NON_INTERACTIVE=1Never prompt (same as --non-interactive)
A4_VERSIONVersion for install.sh / install.ps1 to install
CIWhen set: never prompt, no PATH edits, no update notice, no telemetry banner
DO_NOT_TRACK=1Disable telemetry (standard)
ARETE_TELEMETRY_DISABLED=1Disable telemetry (Arete-specific)

ErrorSolution
Not authenticatedRun a4 auth signup (agent) or a4 auth login --profile human --key <a4_sk_…>
registry-key-requiredThe 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 foundRun 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 installerReinstall with curl -fsSL https://arete.run/install.sh | sh; Cargo builds must use cargo install a4-cli --force
Stack not foundCheck a4 stack list for available stacks
Stack file not foundRun cargo build to generate stack spec
Build failedTry again
Config invalidRun a4 config validate

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.

Terminal window
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.