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

# App SDK

> Talk to the uOS shell from inside your Mini App

Load the SDK from the uOS host. Call `uOS.ready()` when your UI is ready. That dismisses the loading splash.

```html theme={null}
<script src="https://www.uos.agency/uos-app-sdk.js"></script>
<script>
  (async () => {
    await uOS.ready();
    const ctx = await uOS.getContext();
    // {
    //   host: 'uOS',
    //   appId: string,
    //   user: { address: string | null },
    //   theme: 'light' | 'dark',
    //   locale: string
    // }
  })();
</script>
```

The file is served from the uOS origin as `/uos-app-sdk.js` (for example `https://www.uos.agency/uos-app-sdk.js`).

Your app still renders without the SDK. The splash also clears on the iframe `load` event, but you get no wallet, context, or window control through the bridge.

## API

| Method                                          | Permission                                    | Description                                                                                                                                                                                                   |
| ----------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uOS.ready()`                                   | none                                          | Hide the splash; signal successful boot. Returns `{ ok: true }`                                                                                                                                               |
| `uOS.getContext()`                              | none                                          | `{ host: 'uOS', appId, user: { address }, theme, locale }`. `address` is `null` when no wallet is connected; `theme` is `'light'` or `'dark'`; `locale` is the host `navigator.language` (fallback `'en-US'`) |
| `uOS.openUrl(url)`                              | none                                          | Ask uOS to open an `http:`/`https:` URL in a new tab. Returns `{ ok: true }` when `url` is a string (non-http(s) URLs are ignored by the shell)                                                               |
| `uOS.close()`                                   | none                                          | Close this app window. Returns `{ ok: true }`                                                                                                                                                                 |
| `uOS.wallet.request({ method, params })`        | `wallet:request` (+ `wallet:sign` for writes) | EIP-1193-style request                                                                                                                                                                                        |
| `uOS.fs.read(path)`                             | `filesystem:read`                             | Read from `/apps/<appId>/…`. Returns `{ content }` (`content` is `null` if the path is missing or not a file)                                                                                                 |
| `uOS.fs.write(path, content)`                   | `filesystem:write`                            | Write under that directory. Returns `{ ok: boolean }`                                                                                                                                                         |
| `uOS.fs.list(path)`                             | `filesystem:read`                             | List that directory (`path` defaults to `/`). Returns `{ entries }` (empty array if the directory is missing)                                                                                                 |
| `uOS.net.fetch({ url, method, headers, body })` | `network:fetch`                               | Host-mediated public http(s) fetch. Returns `{ status, body }`. Disallowed/missing URL → `-32602`; timeout/network failure → `4900`                                                                           |
| `uOS.agents.call(payload)`                      | `agents:call`                                 | Not implemented yet; returns `4100` without permission, `4200` when granted                                                                                                                                   |
| `uOS.storage.ipfs(payload)`                     | `storage:ipfs`                                | Not implemented yet; returns `4100` without permission, `4200` when granted                                                                                                                                   |
| `uOS.on(event, fn)`                             | none                                          | Subscribe to host events. The host does not emit events yet                                                                                                                                                   |

`net.fetch` is mediated by the uOS host (`POST /api/apps/net-fetch`): the bridge only accepts public `http:`/`https:` URLs (no localhost, private, link-local, or userinfo hosts), then the server re-checks with DNS resolution (rejects hosts that resolve to private/reserved addresses), does not follow redirects (`redirect: 'error'`), sends `credentials: 'omit'`, times out after 10 seconds, and caps the response body at 256 KB. Only `method: 'POST'` is sent as POST; any other method (including omitted) is sent as GET.

Filesystem paths are relative to the app's private directory. Path segments of `..` are rejected (`-32602`).

`entry.url` must not resolve to the uOS shell origin — the host refuses to embed same-origin apps.

## Wallet

When embedded in uOS, route wallet calls through the bridge so the user's session is reused and every write gets a consent sheet above your iframe:

```js theme={null}
const embedded = window.parent !== window && window.uOS;

async function getAccounts() {
  if (embedded) {
    return uOS.wallet.request({ method: "eth_requestAccounts" });
  }
  return myOwnConnector.request({ method: "eth_requestAccounts" });
}
```

Read methods (need `wallet:request` only; no consent sheet):

* `eth_accounts`
* `eth_requestAccounts`
* `eth_chainId`
* `net_version`

`eth_accounts` and `eth_requestAccounts` are answered from the connected wagmi address (or `[]` if disconnected) without calling the provider.

Everything else (including `personal_sign`, `eth_sendTransaction`, typed data) needs `wallet:sign` and per-request approval. Rejection rejects the promise with an `Error` whose `.code` is `4001`.

## Error codes

| Code     | Meaning                                                                                                |
| -------- | ------------------------------------------------------------------------------------------------------ |
| `4001`   | User rejected the request                                                                              |
| `4100`   | Permission not granted in your manifest (or not consented)                                             |
| `4200`   | Capability not implemented by this host version                                                        |
| `4900`   | Wallet, filesystem, or `net.fetch` unavailable (no provider, missing FS module, timeout/network error) |
| `-32601` | Unknown method                                                                                         |
| `-32602` | Malformed params (invalid path, disallowed `net.fetch` URL, missing required fields)                   |

## Runtime

Your app runs in:

```html theme={null}
<iframe
  sandbox="allow-scripts allow-forms allow-popups allow-modals allow-same-origin"
  allow="clipboard-write"
>
```

on **your** origin. The host validates `event.origin` against your `entry.url` origin and `event.source` against your iframe. Wallet consent sheets render in the uOS window chrome above the iframe, so your app cannot cover them.

## Next

[Publish to the App Store](/developers/publish) when your manifest and SDK are ready.
