Building for openapps.xyz (oApps)
An oApp is an app that outlives its creator: it launches on
openapps.xyz (the older oapps.fun and oapps.org
addresses redirect there), gets a token, a build fund, and a community that
governs it. Bounded is the steward that operates it.
Everything in this skill follows from one design goal:
The creator must not be able to rug the app. Not "promises not to";
structurally can't.
So for oApps:
- Everything must be Bounded-owned. Hosting, data, auth, payments,
wallets, onchain access, AI: all provided by the runtime, billed to the
app's own credit pool, governed by its proven policy.
- Zero secrets. No API keys, no vendor accounts, no credentials in
anyone's drawer. A key in the creator's name is exactly the lever the rule
removes, so
secrets is refused on an oApp function.
- If Bounded can't do it, you can't do it. A smaller app nobody can kill
beats a bigger app with a kill switch. What Bounded cannot do yet is
requested once, platform-wide, never worked around with a personal key.
Reference router
Read only the page for the current step.
| Task or term |
Read |
Local -> Bounded -> Open -> Commence, sitePrivate, one launch per creator app, oapp_creator_already_launched, /a/<slug>, what Open publishes, sourcePush |
lifecycle |
publish-oapp refusals, required boundaries rows, boundaries.egress, the service:cap and service:x402 grants, gov-frozen, reproducible dist (static / built), no-frontend apps, bounded propose |
launch gate |
A requested capability: native or live, callable through x402, or request it; readiness; forbidden dependencies; X402_FETCH; bounded services request |
capability ladder |
bounded oapp preflight (what Open would refuse, with the ladder), bounded oapp rehearse, bootstrap from zero data |
rehearse |
| Everything to confirm before Open and before Commence |
checklist |
Mechanics (policy, functions, wallets, payments) live in bounded-backend,
bounded-frontend, and bounded-onchain.
The lifecycle in one screen
- Local. A normal repo; nothing deployed.
- Bounded (development).
bounded init, bounded verify, bounded deploy,
bounded site deploy dist --with-source. The app gets a development address
such as myapp-x7k2.bounded.page; keep it private (sitePrivate) and do
not flip it public yourself. Keep the creator app at the protocol it was
created with: do NOT re-create it as realtime_mainnet and do not pass
--protocol. Open does the mainnet part.
- Open (public, awaiting Commence). Completed Open creates a venue-owned
root and workload on Solana mainnet (the platform sets this; the on-chain
owner is a Bounded-custodied key, not your wallet), publishes the workload
site and source at
https://<workloadAppId>.bounded.page, and the venue
page at /a/<slug> (the older /l/ links redirect). Your creator app stays
a disconnected sandbox; never bounded deploy at the opened root or
workload. Open requires the creator policy's egress to grant service:cap
and service:x402; run bounded oapp preflight first to see everything
Open would refuse.
- Commence. An explicit action that claims the app's slug on openapps.xyz, writes the
listing, creates the token sale, and starts the Gauntlet. One creator app
launches exactly once: after Commence the slug is permanent and frozen, and
a further opening is refused with
oapp_creator_already_launched (409). Pick
the slug before Commence; start a different app for a second oApp.
onchain: true collections are not Openable yet
(oapp_opening_onchain_policy_unsupported); embedded wallets, payments, and
plugin calls are fine. Say so plainly and stop rather than work around it.
Launch economics
Openings whose sealed head selects transfer-fee-v1 use a CCA with 65% Treasury / 30% initial liquidity / 2.5% creator / 2.5% OpenApps allocations in USDC.
The minimum is $5,000 plus the requirement to retain six months of baseline operating costs after setup costs, assuming no future trading revenue.
The app token's fixed 1% transfer fee belongs entirely to Treasury in app tokens.
The canonical DAMM v2 pool has a separate fixed 0.5% USDC fee with OnlyB and dynamic fees disabled.
After Meteora's 20% protocol share, actual net receipts of the designated launch position split 50% creator / 50% OpenApps.
Additional app positions earn for the app, and product revenue belongs entirely to the app.
Existing launches retain their sealed model.
Accrued transfer fees appear as pending token claims; they are not spendable USDC or prepaid Bounded credits.
The managed brain can request fee collection with a credit ceiling without a holder proposal.
The treasury policy fixes the withdrawal authority and destination; Bounded supplies collection infrastructure, transaction signing and credit billing.
Holder-governed reserve conversions target six months of baseline USDC expenses and start below three months by default.
See token transfer fees for collection and pending balances.
The capability ladder
For EVERY capability the user asks for, resolve in this order and never skip to
a workaround. bounded services search "<need>" tells you the rung: each item
is live, callable, or requestable.
- Native or live first:
ctx.ai, ctx.email, files, auth, collections,
payment rails, embedded wallets and DEX/token plugins, or a live catalog
action called from a function with ctx.services.invoke("<slug>", ...)
under the app's service:cap grant.
- Callable through x402 second: the counterparty prices itself with x402,
so Bounded pays it per call from the steward relay wallet on the app's
behalf, no approval needed
(
ctx.services.invoke("X402_FETCH", ...) under service:x402).
- Request it, then call it out:
bounded services request "<what you need>" files it once with the Capability Hub; the Hub emails you when it is
live. Say what can't be done yet, which person-held dependency it would
need, why the rule exists, and the nearest compliant alternative. Then build
the compliant version. Never "temporarily" add a user-held secret.
Details, readiness, forbidden dependencies, and relay semantics: docs/capability-ladder.md.
Before you let go
- Boundaries are written early:
posture: "closed", binding: "all", a declared
egress whose allow list carries the two grants service:cap and
service:x402 (plus any credential-free hosts), and a "mode": "locked"
freeze over openApps only. Never freeze boundaries or set amend on the
creator app; the platform derives those on the launched clone.
bounded oapp preflight is READY: it is the Open gate as a dry run, and it
names the ladder rung for every dependency it would refuse.
policy.json has no rule, function, or egress that depends on a user-held
credential; bounded verify passes; every external egress is declared.
- Source rides the deploy (
sourcePush: true or --with-source), the synced
tree is the real complete project, and a deployed dist is reproducible from it.
- The user knows Open publishes the site, the source, and the boundaries, and
that a no-frontend app's home page is the public repo view.
Full list: docs/checklist.md.
1---2name: oapps-fun3description: Build an app destined for openapps.xyz (an oApp): the zero-secrets discipline, why every capability must be steward-owned ("if Bounded can't do it, you can't do it"), how to call out unsupported capabilities honestly, the x402 relay fallback for services Bounded doesn't natively provide, how to request a capability Bounded lacks, and the lifecycle: private bounded.page development, completed Open publication at the exact workload app-id host, and explicit Commence for the oApps slug, listing, token, and Gauntlet. Use whenever a user says the app will launch on openapps.xyz (oapps.fun redirects there), become an oApp, be community-owned / token-governed, or "outlive its creator". Part of the Bounded skill family; the mechanics live in bounded-backend / bounded-onchain.4---56# Building for openapps.xyz (oApps)78An **oApp** is an app that outlives its creator: it launches on9[openapps.xyz](https://openapps.xyz) (the older oapps.fun and oapps.org10addresses redirect there), gets a token, a build fund, and a community that11governs it. Bounded is the steward that operates it.1213Everything in this skill follows from one design goal:1415> **The creator must not be able to rug the app.** Not "promises not to";16> structurally can't.1718So for oApps:1920- **Everything must be Bounded-owned.** Hosting, data, auth, payments,21 wallets, onchain access, AI: all provided by the runtime, billed to the22 app's own credit pool, governed by its proven policy.23- **Zero secrets.** No API keys, no vendor accounts, no credentials in24 anyone's drawer. A key in the creator's name is exactly the lever the rule25 removes, so `secrets` is refused on an oApp function.26- **If Bounded can't do it, you can't do it.** A smaller app nobody can kill27 beats a bigger app with a kill switch. What Bounded cannot do yet is28 requested once, platform-wide, never worked around with a personal key.2930## Reference router3132Read only the page for the current step.3334| Task or term | Read |35|---|---|36| Local -> Bounded -> Open -> Commence, `sitePrivate`, one launch per creator app, `oapp_creator_already_launched`, `/a/<slug>`, what Open publishes, `sourcePush` | [lifecycle](docs/lifecycle.md) |37| `publish-oapp` refusals, required `boundaries` rows, `boundaries.egress`, the `service:cap` and `service:x402` grants, `gov-frozen`, reproducible dist (`static` / `built`), no-frontend apps, `bounded propose` | [launch gate](docs/launch-gate.md) |38| A requested capability: native or live, callable through x402, or request it; readiness; forbidden dependencies; `X402_FETCH`; `bounded services request` | [capability ladder](docs/capability-ladder.md) |39| `bounded oapp preflight` (what Open would refuse, with the ladder), `bounded oapp rehearse`, bootstrap from zero data | [rehearse](docs/rehearse.md) |40| Everything to confirm before Open and before Commence | [checklist](docs/checklist.md) |4142Mechanics (policy, functions, wallets, payments) live in **bounded-backend**,43**bounded-frontend**, and **bounded-onchain**.4445## The lifecycle in one screen46471. **Local.** A normal repo; nothing deployed.482. **Bounded (development).** `bounded init`, `bounded verify`, `bounded deploy`,49 `bounded site deploy dist --with-source`. The app gets a development address50 such as `myapp-x7k2.bounded.page`; keep it **private** (`sitePrivate`) and do51 not flip it public yourself. Keep the creator app at the protocol it was52 created with: do NOT re-create it as `realtime_mainnet` and do not pass53 `--protocol`. Open does the mainnet part.543. **Open (public, awaiting Commence).** Completed Open creates a venue-owned55 root and workload on Solana **mainnet** (the platform sets this; the on-chain56 owner is a Bounded-custodied key, not your wallet), publishes the workload57 site and source at `https://<workloadAppId>.bounded.page`, and the venue58 page at `/a/<slug>` (the older `/l/` links redirect). Your creator app stays59 a disconnected sandbox; never `bounded deploy` at the opened root or60 workload. Open requires the creator policy's egress to grant `service:cap`61 and `service:x402`; run `bounded oapp preflight` first to see everything62 Open would refuse.634. **Commence.** An explicit action that claims the app's slug on openapps.xyz, writes the64 listing, creates the token sale, and starts the Gauntlet. **One creator app65 launches exactly once**: after Commence the slug is permanent and frozen, and66 a further opening is refused with `oapp_creator_already_launched` (409). Pick67 the slug before Commence; start a different app for a second oApp.6869`onchain: true` collections are not Openable yet70(`oapp_opening_onchain_policy_unsupported`); embedded wallets, payments, and71plugin calls are fine. Say so plainly and stop rather than work around it.7273## Launch economics7475Openings whose sealed head selects `transfer-fee-v1` use a CCA with 65% Treasury / 30% initial liquidity / 2.5% creator / 2.5% OpenApps allocations in USDC.76The minimum is $5,000 plus the requirement to retain six months of baseline operating costs after setup costs, assuming no future trading revenue.77The app token's fixed 1% transfer fee belongs entirely to Treasury in app tokens.78The canonical DAMM v2 pool has a separate fixed 0.5% USDC fee with OnlyB and dynamic fees disabled.79After Meteora's 20% protocol share, actual net receipts of the designated launch position split 50% creator / 50% OpenApps.80Additional app positions earn for the app, and product revenue belongs entirely to the app.81Existing launches retain their sealed model.82Accrued transfer fees appear as pending token claims; they are not spendable USDC or prepaid Bounded credits.83The managed brain can request fee collection with a credit ceiling without a holder proposal.84The treasury policy fixes the withdrawal authority and destination; Bounded supplies collection infrastructure, transaction signing and credit billing.85Holder-governed reserve conversions target six months of baseline USDC expenses and start below three months by default.8687See [token transfer fees](../bounded-onchain/docs/token-transfer-fees.md) for collection and pending balances.8889## The capability ladder9091For EVERY capability the user asks for, resolve in this order and never skip to92a workaround. `bounded services search "<need>"` tells you the rung: each item93is `live`, `callable`, or `requestable`.94951. **Native or live first**: `ctx.ai`, `ctx.email`, files, auth, collections,96 payment rails, embedded wallets and DEX/token plugins, or a live catalog97 action called from a function with `ctx.services.invoke("<slug>", ...)`98 under the app's `service:cap` grant.992. **Callable through x402 second**: the counterparty prices itself with x402,100 so Bounded pays it per call from the steward relay wallet on the app's101 behalf, no approval needed102 (`ctx.services.invoke("X402_FETCH", ...)` under `service:x402`).1033. **Request it, then call it out**: `bounded services request "<what you104 need>"` files it once with the Capability Hub; the Hub emails you when it is105 live. Say what can't be done yet, which person-held dependency it would106 need, why the rule exists, and the nearest compliant alternative. Then build107 the compliant version. Never "temporarily" add a user-held secret.108109Details, readiness, forbidden dependencies, and relay semantics: [docs/capability-ladder.md](docs/capability-ladder.md).110111## Before you let go112113- Boundaries are written early: `posture: "closed"`, `binding: "all"`, a declared114 `egress` whose allow list carries the two grants `service:cap` and115 `service:x402` (plus any credential-free hosts), and a `"mode": "locked"`116 freeze over `openApps` only. Never freeze `boundaries` or set `amend` on the117 creator app; the platform derives those on the launched clone.118- `bounded oapp preflight` is READY: it is the Open gate as a dry run, and it119 names the ladder rung for every dependency it would refuse.120- `policy.json` has no rule, function, or egress that depends on a user-held121 credential; `bounded verify` passes; every external egress is declared.122- Source rides the deploy (`sourcePush: true` or `--with-source`), the synced123 tree is the real complete project, and a deployed dist is reproducible from it.124- The user knows Open publishes the site, the source, and the boundaries, and125 that a no-frontend app's home page is the public repo view.126127Full list: [docs/checklist.md](docs/checklist.md).