> ## Documentation Index
> Fetch the complete documentation index at: https://gora.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Build a Base or Solana AI app

> An independent end-to-end project using public Gora endpoints and your own chain contracts.

# Build a Base or Solana AI app

The standalone **Signal Lab** project is in `external/multichain-agents`. It has
its own package, WASM program, UI and contracts. It imports no Gora core code,
reads no core database and never receives an operator/provider credential.

Its independent program/UI was published through the public deployment API:
[open Signal Lab](https://86ea2cf8c74c1d78db7dd4a87c5a1d9d.apps.74.241.248.103.nip.io/apps/signal_lab/ui/)
or [download its public source](https://86ea2cf8c74c1d78db7dd4a87c5a1d9d.apps.74.241.248.103.nip.io/apps/signal_lab/ui/source.tar.gz).
Source downloads exclude credentials, keypairs and private signing journals.
The public example is v0.1.4. Independent Base/Solana paid AI, confirmed score
writes, signer revocation and exact recovery have passed on the managed
testnet. Native-wallet acceptance is still being completed; publication alone
does not establish every launch gate.

Its AI program returns `{score, reason}`. Each agent records scores in its own
Base mapping entry or Solana PDA. This is a general app workflow, not a trading endpoint.

> [!WARNING]
>
> Managed Base/Solana signing must be explicitly enabled. Check live signer,
> delivery and recovery acceptance before funding an agent. A 503 means the
> service is not enabled; working validator staking does not prove app signing.

## 1. Build your independent project

Copy/fork the separate example and choose a globally unique app ID. Update the
manifest and policy IDs, then build:

```bash theme={null}
npm ci
export CARGO=/absolute/path/to/cargo
npm run build:wasm
VITE_APP_ID=your_app_id npm run build
```

The public runtime executes WASM, not unsandboxed JavaScript/Python. Your static
frontend can use any JavaScript framework. Large images/videos can remain on HTTPS CDNs.

## 2. Deploy your own chain contract

* **Base Sepolia (84532):** deploy `contracts/base/Scoreboard.sol`.
  `recordScore(uint256)` updates the score for `msg.sender` and emits an event.
* **Solana devnet:** build/deploy `contracts/solana`. A record PDA derives from
  `["score", agent_public_key]` and stores score/update count. The agent pays
  its own PDA rent on the first update.

These are application contracts, not staking contracts. Keep deployment keys
in your protected environment and record public addresses/receipts.
`gora deploy` does not deploy chain contracts.

## 3. Publish the Gora program and UI

Install the current CLI using [Deploy to Gora](https://gora.mintlify.site/launch/deploy-to-gora.md), then:

```bash theme={null}
gora config set node.url https://gora-bridge.74.241.248.103.nip.io
openssl rand -hex 32 | gora config set api.token --stdin
gora package .
gora deploy .
```

Generate the developer token once and retain a private backup. It owns your
deployments; it is not a browser API key. Upgrading the app does not silently
replace the executable pinned by an existing agent.

Choose either UI hosting model:

* **Gora-hosted:** package `ui.dir`, then open the returned `ui_url`.
* **Your website:** publish the same static build with `VITE_GORA_API` set to
  the public bridge URL and `VITE_APP_ID` set to your app ID.

Explore curation is separate from deployment permission. Unlisted apps remain
in the registry and accessible by direct URL/app ID. Unlisting does not delete
their execution, schedules, histories or recovery paths.

## 4. Connect a user's wallet

The example supports injected Base/Solana browser wallets. Its client requests
`/auth/challenge`, verifies the exact audience/app/wallet/permissions, asks the
wallet to sign, and exchanges it at `/auth/session`. The short-lived token
stays in memory and is scoped to one app.

Inside Gora, use `window.Gora.instance(...)` and the current
`window.Gora.agentSigner(...)` helper. Keys and policy-approval signatures
stay in native code. A normal app session does not authorize spending.

```javascript theme={null}
import { GoraClient } from './src/client.mjs';
const client = new GoraClient({
  api: 'https://gora-bridge.74.241.248.103.nip.io',
  appId: 'your_app_id',
  chain: 'base' // or 'solana'
});
// Browser: connect({address, signMessage}) using your wallet adapter.
// Native Gora: connect() uses the native wallet bridge.
```

## 5. Create an agent and request AI

```javascript theme={null}
const { instance } = await client.instance('create', null, {
  nonce: 'researcher-001', // stable on retries
  name: 'Product researcher',
  config: {
    chain: 'base',
    instructions: 'Score evidence of customer demand; explain uncertainty.'
  }
});
console.log(instance.did);
// Purchase prepaid test GORA AI calls for this instance before invoking.
// See the invoice/sign/confirm flow in "Structured AI calls and testnet credits".
const result = await client.invoke(
  instance,
  'Five customers requested exportable reports.',
  false, // AI/state only
  'researcher-001-observation-001' // reuse after HTTP uncertainty
);
```

Each instance has its own configuration, state namespace, owner, executable
version and DID. Do not put secrets in configuration/prompts. See
[identity and permissions](https://gora.mintlify.site/launch/agent-identities-and-signing.md).

AI starts at **zero paid calls**. Follow [testnet GORA payment](https://gora.mintlify.site/launch/ai-credits.md)
before the first invocation. Buying ordinary execution credits or funding the
agent's ETH/SOL wallet does not pay its AI bill.

## 6. Authorize bounded chain writes

```javascript theme={null}
import { scorePolicy } from './src/policies.mjs';
await client.signer('authorize', instance, {
  chain: 'base',
  policy: scorePolicy('base', 'YOUR_DEPLOYED_SCOREBOARD_ADDRESS')
});
const { signers } = await client.signer('list', instance);
```

Review the separate custody approval: app, executable, DID, chain, targets,
argument ranges, expiry, fee ceiling and transaction count. Funding is another
user-signed transaction to the returned **agent** address; signer creation
does not move funds. Use only test ETH/devnet SOL; Solana also needs PDA rent.

Invoke with `record_on_chain: true`. The WASM result proposes a template and
arguments, validators attest execution, and the managed signer checks its
policy before signing and delivering the transaction.

## 7. Verify execution, delivery and recovery separately

1. Read the finalized request, output and receipt.
2. Read `/v1/settlements/{request_id}` using the same caller authentication.
3. Require `confirmed`, then independently read the contract/PDA and transaction
   on the correct testnet. Two Base L2 confirmations are not Ethereum L1 finality.

Reuse request IDs after HTTP uncertainty. Never create a second spending
request merely because polling timed out. Signed nonce/blockhash failures are
reconciled using the original bytes, not automatically re-signed.

Acceptance should cover a Base agent, a Solana agent, a second owner's
isolation, a rejected out-of-policy call, revoke and return of test funds.
Creating 1,000 identities does not prove 1,000 concurrent AI calls or throughput.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.