Deploy to Gora
The fastest way to ship a Gora app is the live public testnet. No signup and no local infrastructure — install the CLI, set a developer token, point it at the endpoint, and deploy. The public testnet requires a developer token that is your identity. Execution and AI use bounded testnet credits; consult current pricing and balances before enabling automation. For endpoints, deployed contract IDs, and what the testnet supports today, see Connect to the testnet.Prerequisites
-
the
goraCLI — install it with:This addsgorato~/.gora/bin(make sure that directory is on yourPATH). The fresh testnet mirror has macOS ARM64 (macOS 11+) and Linux x86_64 (glibc 2.39+, such as Ubuntu 24.04+) packages. Checksums are mandatory. Other platforms need a matching current build from source; do not substitute an old CLI release for these managed-app interfaces. - a developer token you choose — your testnet identity, not a frontend API key or an unlimited inference allowance.
1. Create an app and point it at the testnet
Configuration belongs to the current app folder; it is not inherited from its parent. Create the project first, then configure it:/v1/*) and the dev bridge routes:
--node <url> on individual commands. Check the endpoint is up:
caller set to your token’s dev_… identity.
2. Build the app
hello-alice
deploys as hello_alice.
3. Deploy
- app artifact bytes or source
- manifest JSON
- policy JSON
- deterministic package metadata
- optional contract bindings
- a static UI bundle, when
ui.diris configured
gora deploy . upgrades the app in place — same app_id, new
version. Existing user instances remain pinned to their original executable;
an app upgrade is not permission to silently change their code or vault policy.
4. Invoke
node.url, add
--node https://gora-bridge.74.241.248.103.nip.io.
5. Inspect
Build a complete app: program, UI and user instances
The same interfaces support trading bots, research assistants and other apps. For example, a Fieldnotes-style research assistant can classify an observation, return a typed object and retain notebook history without any transaction authority. Its program and UI deploy to Gora; no developer-hosted server is required afterward.Return a structured LLM object
The public runtime executes WASM. Importgora.llm_json(ptr, len, out_ptr, out_cap) -> i32 and pass serialized JSON such
as:
/llm endpoint and no API key belongs in the UI.
Validators replay the captured host response; they do not each purchase a
separate model answer. A valid JSON object is not proof that its advice is
correct: apply deterministic business rules before any consequential action.
Use the public input_get, caller_get, state_get, state_put and
set_output host imports for input, trusted execution context, persistent state
and output. A wallet-instance invocation receives:
caller_get, not
from fields supplied by the user. Bound retained history and handle failed LLM
calls explicitly; do not turn a failure into an invented successful result or
an on-chain action.
Package a rich static UI
Build your frontend intodist and add this field to gora.app.json:
gora build, gora validate, gora package and
gora deploy .. Use relative asset URLs (for example, Vite base: './'). Open
the registry’s returned ui_url; the managed testnet serves each app from its
own HTTPS origin and supports SPA history routes. A multi-screen interface,
interactive charts and client-side state work normally there. Render actual
instance state and receipts, not fabricated balances or simulated success.
The bundle limit is 256 files, 2 MiB of base64 per file and 8 MiB of base64 in
total. Hidden files, symlinks and paths escaping the app are rejected. Host large
images and videos on HTTPS CDNs and reference them from the UI; use lazy loading,
video controls and useful error states. Plain HTTP mixed content is blocked.
CDN media is not stored on the Gora chain. On a self-hosted installation without
per-app origins, the sandbox fallback requires hash routing and does not offer
ordinary localStorage/history routing.
Give each customer their own identity and state
Inside the native Gora app, the wallet bridge handles authentication without exposing its session token to frontend code:did:gora:testnet:<instance_id>; do not hash the ID again when anchoring it to
a contract. Instances have isolated state, wallet ownership, version-pinned
code and independently configurable instructions. Update configuration with
Gora.instance('config', id, {config, revision}); stale revisions are rejected.
An ordinary browser does not automatically have Gora.instance. Integrate its
wallet with POST /auth/challenge (chain, address, app_id), sign the exact
returned message and exchange it at POST /auth/session
(challenge_id, signature). Use the returned bearer for that app and caller.
Base uses EIP-191 personal-sign, Solana signs raw bytes, and Algorand signs raw
Ed25519 bytes without an additional message prefix. A developer token identifies
the developer, not the end customer’s wallet, and must never be used as a
shared browser credential.
Optional recurring execution and pause
For a program designed to handle a recurring action, create a schedule withGora.instance('schedule', id, {schedule_id, input, interval_seconds}).
Each execution receives a fresh trusted submission timestamp; do not freeze one
into the schedule input. Disabling the instance through its configuration
({config, revision, enabled:false}) prevents new instance execution.
Developer/operator schedule owners can pause an individual schedule through
POST /v1/schedules/:id with {"enabled":false} and resume with
{"enabled":true}. This preserves the schedule ID, caller, run counter and last
request. Do not delete/recreate it to pause, and do not use a nonexistent CLI
schedule pause command. Pausing does not cancel already submitted transactions
or revoke authority previously granted by an on-chain wallet policy.
Posting an existing owned schedule through the creation endpoint also preserves
its run counter and request history. An identical active request leaves its next
run time unchanged; a paused resume or changed input/interval keeps the next
request number at N+1. App, instance, caller, payer and request-prefix bindings
cannot be changed under that ID. Use a fresh ID/prefix for a genuinely new
schedule; deleting and recreating an old ID is not the resume mechanism.
On-chain apps: link contract metadata before deploy
Application callbacks currently settle on Algorand testnet, using managed gateway v4771952005 and algod https://testnet-api.algonode.cloud.
Algorand staking remains 764254589 with GORA ASA 764254575. Validator staking
is also live on Base Sepolia and Solana devnet; this does not imply application
callback gateways are deployed on those chains. Full IDs and endpoints:
Connect to the testnet.
If your app targets a chain gateway or app contract, link that metadata before
deploy:
gora.app.json with a contract binding. Skip this step for
off-chain-only apps.
Autonomous actions without signing every transaction
A user can create an independent policy-vault contract with their wallet, fund it and authorize specific target methods and limits. The vault is an Algorand application account with no private key. The LLM does not sign transactions or receive unrestricted access to the wallet. A managed relayer submits a context-bound oracle proof; the vault checks it and executes only permitted inner transactions. The owner signs setup, deposits and policy changes, but does not need to approve each already-authorized action. The wallet owns withdrawal, revocation and recovery controls. On-chain policies limit target/method, amounts, budgets and numeric arguments; target contracts must additionally enforce their own financial invariants. Use the approved vault artifact and ABI below, not imports from Gora core or operator credentials. The managed anchor verifier accepts the approved vault program shape, not any contract an app claims to control. After creating a compatible vault, its wallet owner attaches it withGora.instance('vault', instance_id, {chain:'algorand-testnet', app_id:vaultId}).
Gora verifies live bytecode, canonical testnet genesis, owner, instance ID, app
hash and artifact hash before accepting the anchor. A developer-token-owned
instance is not a substitute for a wallet-owned instance in this flow.
Obtain the approved vault and wallet descriptors
The pilot’s public vault artifact contains base64 approval/clear programs, schemas and constructor argument order. Pin the decoded approval program’s SHA-256 to02789d101bad218a494aea6e8781fd76c1ebbb26d94676fb5620f9efb5ff6035.
This release uses 16 integer / 6 byte global fields, zero local fields and one
extra program page. Use the registry’s ui_url when resolving assets; the shared
bridge URL is not interchangeable with an app’s dedicated UI origin.
The public Northstar manifest
provides complete working descriptors under
dev_registry.manifest_json.interface.actions (parse manifest_json first if
returned as a string). Reuse the descriptor shapes for create_vault,
fund_vault_algo, opt_in_vault, fund_vault_asset, authorize_market,
revoke_vault, owner_close_position and withdraw_collateral in your own
manifest. Keep your own app ID, executable, strategy and wallet-owned instance;
do not reuse Northstar’s identity or vault.
For create_vault, call Gora.action('create_vault', {parameters}) with the
artifact’s approval_program_base64 mapped to parameters.approval_program
and clear_program_base64 mapped to parameters.clear_program, plus:
instance_hash: the new instance’s 32-byte hex ID, without hashing it again.app_hash: SHA256 of your UTF-8 app ID;artifact_hash: that instance’s pinned WASM SHA-256;policy_hash: your initial 32-byte policy digest.network_hash: the canonical Algorand testnet genesis hash, hex-encoded.gateway_id:"771952005";asset_id: the collateral ASA ID.max_per_call,daily_budget,lifetime_budget: decimal base-unit strings chosen and reviewed by the owner, not proposed unrestricted limits from an LLM.
$.wallet.algorand. Register
gora:actionComplete, gora:actionFailed and gora:actionCancelled listeners
before calling it; match event.detail.action_id. After successful creation,
read event.detail.output.tx_hash, then
GET /chains/algorand/transactions/:txid for the confirmed application-index.
Attach that ID with Gora.instance('vault', ...), fund the vault’s minimum
balance, opt it into collateral, deposit and authorize only your intended
target methods and numeric limits. An app creation receipt alone does not fund
or authorize a vault. Later owner actions use the same native bridge, for example:
external/gora-vault/sdk/index.mjs in this checkout, with its ABI in that
repository’s README. It is not an npm-published dependency. The artifact,
public descriptors and encoding contract here do not require core source access.
Return a vault command from WASM
After obtaining a schema-validated LLM decision, the program validates it against strategy limits and fresh on-chain state. For an authorized action it returns achain_callback with this shape; variables below are calculated by your
program, not literal placeholder strings to send:
caller_get submission time, not
user input; it must still be more than 15 seconds and at most one hour ahead
when settlement validates it. Re-read the vault’s current policy hash, owner,
network and executable/instance bindings before constructing the intent.
packed_args is count:u8 followed by repeated length:u16BE || argument_bytes;
the first argument is the authorized UTF-8 method. There are 1–8 arguments and
at most 1024 packed bytes. resources is asset_count:u8 || asset_ids:u64BE[] || app_count:u8 || app_ids:u64BE[] || account_count:u8 || account_public_keys:bytes32[].
With no extras it is three zero bytes (base64 AAAA). The relayer supplies the
gateway, target and collateral references plus gateway/allowance boxes; include
any target-specific boxes and stay within Algorand’s combined resource limit.
Calculate the exact signed-result binding, where || means byte concatenation,
all integers are uint64 big-endian and all identity/hash fields are 32 raw bytes:
Display execution and chain confirmation separately
An execution result can contain a proposedchain_callback while settlement
is still pending. Read /v1/requests/:id/receipt for the committed execution
proof, /v1/jobs/:id for execution status and /v1/settlements/:id for chain
delivery. Wallet sessions can read only their own caller/app evidence.
Show pending, confirmed and failed delivery distinctly, and show the callback
transaction ID and confirmation round before reporting an on-chain action as
complete. A no-action result has no chain settlement; a failed callback must
not be shown as a trade. Gateway deposit cleanup is subsequent operational work,
not a second trade.
Node API reference
All routes live behind the public URL:
Limits: artifacts up to 5 MiB, request bodies up to 8 MiB.
What deploy does not do
gora deploy does not:
- deploy smart contracts
- submit chain transactions
- sign with user keys
- pay chain gas
Alternative: run a local node
If you want the full deploy + invoke + inspect loop on your own machine, the dev node is built into the CLI:--contract-registry <json>— expose chain contract metadata--token <bearer>— requireAuthorization: Beareron writes; mandatory if you bind anything other than 127.0.0.1--signing-request-sink <bridge-url>— forwardmobile_signing_request/chain_callbackoutputs to a Dev Bridge
--node http://127.0.0.1:8080 (or set node.url to it) in the
commands above.
Next: Test with mobile.