Skip to main content

builder

Get permission for an app or agent to use a person's Vana data, read it, and verify the requested result. Use for consuming-app integration, including the developer's own collected data, grants, escrow, fees, saved app delivery and connector iteration. Source collection belongs to connect-data.

Source facts

Repository
vana-com/vana-cli
Last source activity
November 6, 2026 at 03:57
Detected SKILL.md language
English
Stars
2
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
builder
description
Get permission for an app or agent to use a person's Vana data, read it, and verify the requested result. Use for consuming-app integration, including the developer's own collected data, grants, escrow, fees, saved app delivery and connector iteration. Source collection belongs to connect-data.
# Builder Read workflows with `vana skills show <id> --json`. The response includes full instructions and required reference content; installation into the agent's harness is optional. Use `connect-data`, `create-connector` or `builder` as the requested goal needs them. The `vana app` command group is the builder side of Vana: register once, ask a person for access, read what they approved, pay the fee from escrow. Every command takes `--json` and returns one outcome object; branch on the exit code, read `code` for the reason and `remedy` for the next command. Start from the person's intended result and continue through the app handoff and verification they requested. Select the commands yourself; the person handles account choices, sign-in, consent and any spending decision. Use the intended app's existing backend key, owner, Account deployment and network. An app name does not select its credentials. Keep keys server-side and out of chat, browser code and saved reports. For an app integration, read [delivery and verification](reference/verification.md) before requesting access. It covers readiness, real approval, bounded reads, durable storage, display, recovery and same-grant iteration for any consumer. The instructions and required references are public. The user's app supplies its own storage and UI; no reference app or observability service is required. ## The loop ```bash vana app register --network moksha --app-url http://localhost:3000 --app-name "<your name>" # create and test first vana app request --network moksha --scopes spotify.savedTracks # ask a person vana app read --network moksha spotify.savedTracks --grant <id> --pay # read and pay ``` Check `vana app whoami --json` first and reuse an appropriate registration. Register with the name the person should see on the approval page, such as your agent's name. The CLI remembers the name for this app key and falls back to "Vana CLI" when a request has no name. Use your app's HTTP(S) URL. A localhost URL works for testing. Vana Account needs the URL to claim the app, and the gateway registration keeps its original URL. Or ask a question instead of reading raw data, in one command: ```bash vana app ask "Which genres fill their saved tracks?" --network moksha \ --sources spotify.savedTracks --derived myapp.genres --pay ``` `request` prints an approval URL and waits. The person opens it, approves, and the grant id comes back to the terminal. The read command returns data; an app integration must also verify its own save and display. The `--pay` examples require an agreed fee-asset limit before execution. ## Exit codes Branch on these instead of parsing text. | Code | Meaning | What to do | | ---- | ----------------------------------- | ---------------------------------------------------------------------- | | 0 | done | continue | | 1 | failed | read `message`, do not retry blindly | | 2 | bad usage | fix the command | | 3 | no grant, or it does not cover this | `vana app request` again | | 4 | payment required | inspect the quote and obtain a spending limit before paying or funding | | 5 | no server answered | the owner's Personal Server is offline; not your fault, retry later | | 6 | not ready yet | wait and repeat, using any interval the payload names | | 7 | a person has to act | surface the URL to a human | ## Asking for access ```bash vana app request --network moksha --scopes spotify.savedTracks,spotify.playlists --json ``` Waits up to ten minutes by default (`--timeout <seconds>`). On approval the outcome carries `grantId` and the exact read command in `remedy`. One grant per owner and app: an approval replaces the grant's scopes, it does not add a second grant. So when this machine already holds an approval for the app key, `request` reads that live grant and asks for the union, and prints what it keeps, adds and removes before creating the request. Give up a scope with `--remove-scopes a,b`; pick whose grant to extend with `--owner <address>` when more than one person approved; send `--scopes` verbatim with `--no-merge-grant`. `--json` carries `kept`, `added`, `removed`, `removeScopes` and `grantUnion.status` (`merged`, `no_live_grant`, `owner_unknown`, `owner_ambiguous`, `disabled`, `unavailable`). With no earlier approval the person is unknown until they approve, and the approval page keeps what they already granted. `--remove-scopes` is always sent, even when the live grant could not be read; then it prints as "Removing (if shared)" and the approval page drops those entries if the grant holds them. When no human is watching the terminal, do not block: ```bash vana app request --network moksha --scopes spotify.savedTracks --no-input --json ``` That exits **7** immediately with `approvalUrl` in the payload. Hand the URL to the person however you can, then come back later: ```bash vana app requests list --json # find the id you did not keep vana app requests show dcr_... --json # did they approve yet? ``` `show` refreshes from the service and writes the result down, so once it reports a `grantId` that id stays available offline. Both commands check each grant at the gateway: `data.grant.state` is `revoked` or `replaced` (one grant per owner and app, so a later approval replaces its scopes) when it no longer holds, and `unverified` when the gateway did not answer. If creation was interrupted, use the saved recovery command instead of creating another request. Builds with `request --resume` expose the saved setup ID through `vana app requests list --json`. Check `vana app request --help` before using the option on an older installed CLI. Resume preserves the app, environment, network and original payload; an unavailable service does not authorize a replacement request or another payment. ## Asking a question instead of reading raw data Prefer this when you want an answer rather than a dataset. The question is computed on the person's own server over sources **your app never reads**; you end up holding a grant on the answer only. ```bash vana app ask "Which genres fill their saved tracks?" --network moksha \ --sources spotify.savedTracks \ --derived myapp.genres \ --pay --json ``` `ask` runs the whole path for you: it asks the person (same approval URL and `--no-input` behavior as `request`), waits for the answer to settle, then reads it. The derived scope must be in your own namespace, never sharing a first segment with a source. Both `--sources` and `--derived` are required. The request grants the derived scope only; the sources go to the person's server as the question's inputs, so `app request` refuses a question whose source is also listed in `--scopes`. Two commands let you drive the same path by hand: ```bash vana app status myapp.genres --json # is the answer coming, and when vana app lineage myapp.genres --json # what it was computed from ``` `status` finds the grant and server from your own request history, so you do not have to keep ids around. Its states map onto the exit codes: exit 6 means pending or recomputing, and the payload names the interval the server wants you to wait; exit 0 means ready and the remedy is the read command. **Do not poll `status` in a tight loop.** It is free to you and it can trigger a recompute, which spends inference budget without reading anything. Use the interval the server names. ### What it costs Two separate costs, reported separately: - the compute itself reports `computeCost: null`, which means **unpriced, not free**; treat a number appearing there as a normal change - reading the derived scope is an ordinary billable read, with the same `--pay` and `--max-fee` gates as any other read ## Reading ```bash vana app read spotify.savedTracks --grant 0x... --json ``` Without `--pay` a priced read stops at exit **4** and tells you the cost, so you always see the price before spending: ```json { "code": "payment_required", "message": "This read costs 0.01 USDC.e and --pay is not set." } ``` Add `--pay` to settle it from escrow, and `--max-fee` to refuse anything above a limit. **The limit is in the fee's own asset**, which is not always VANA: on mainnet a data-access fee is quoted in USDC.e. ```bash vana app read spotify.savedTracks --grant 0x... --pay --max-fee 0.05 --json ``` Two things worth knowing: - The fee settles **before** data is served, so a blind retry after a failure can pay twice. The CLI stores the signed payment header and replays it, so re-running a failed read does not settle a second fee. Never work around this by looping. - In human mode the data goes to stdout alone and the summary to stderr, so `vana app read ... | jq` is clean. ## Two delivery paths, one command Some owners serve their data from a Personal Server they run; others from a TEE sandbox reached through the gateway's job queue. **You never choose.** `read` takes the path the access request reports and handles both. What differs, if you see it in the output: - `delivery: "personal_server"` can cost a fee and produces a receipt - `delivery: "enclave"` reports `paid: false`, because the gateway currently admits those jobs at zero price; that is a protocol state, not a promise that enclave reads stay free - an enclave read can return exit 6 while the owner's sandbox wakes, which takes seconds. Run the same command again rather than treating it as a failure ## Paying ```bash vana app escrow balance --json vana app escrow fund --amount 1 --json # native VANA vana app escrow fund --amount 5 --asset 0xF1815... --json # an ERC20, no gas ``` Fund the asset the reads are actually priced in, which the exit-4 payload names as `asset`. On mainnet, funding requires `--yes` and spends real money. An ERC20 deposit (USDC.e) goes through the gateway relayer, which pays the gas, so the app wallet needs only the token, not VANA. `--self-pay-gas` sends it from the app wallet instead. A native VANA deposit always pays its own gas. To link the app to the signed-in person's Account, run `vana app claim --network <network> --json`. If needed, use `vana login` first. Exit 7 returns `data.claimUrl` for the person to open. After they complete the existing Account page, run `vana app claim --network <network> --resume --json`. Only exit 0 with `data.ownership: "owned"` confirms the link. Pending or unavailable confirmation is not completion. The Account page also provides funding; claiming itself does not move funds. ## Checking your work ```bash vana app whoami --json # who am I, registered? vana app onchain spotify.savedTracks --owner 0x... --json # version, hashes, deletion ``` Match the result to the user's goal using the [verification procedure](reference/verification.md). A grant proves permission; a read proves receipt; neither proves the consuming app saved or displayed it. Verify those outcomes at the actual app. Keep collection, consent, reading, storage and display as separate observed results. ## Networks Everything defaults to **mainnet**, where fees are real USDC.e. A read never pays by itself: it stops at exit 4 with the price until you pass `--pay`, and `--max-fee` caps it. Pass `--network moksha` to try a flow on the testnet first, where fees are play money. ## Failure notes an agent gets wrong - Exit 5 with `owner_not_ready` means the person never finished setting up a Personal Server. Retrying cannot fix it; they have to act. - Exit 5 otherwise means their server is offline right now. The CLI already tried every server they registered. - Exit 6 is normal, not a failure. Wait and repeat. - A denied request is exit 3 and is final. Do not re-ask in a loop. - `ask` stops at whatever `request` returned. Exit 7 there means the person has not approved yet, not that anything failed. - A derivative that fails with `source_missing` (exit 5) means the person has not connected a source yet. Retrying will not change that.
View on GitHub