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
secretsis 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 asmyapp-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 asrealtime_mainnetand 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; neverbounded deployat the opened root or workload. Open requires the creator policy's egress to grantservice:capandservice:x402; runbounded oapp preflightfirst 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 withctx.services.invoke("<slug>", ...)under the app'sservice:capgrant. - 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", ...)underservice: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 declaredegresswhose allow list carries the two grantsservice:capandservice:x402(plus any credential-free hosts), and a"mode": "locked"freeze overopenAppsonly. Never freezeboundariesor setamendon the creator app; the platform derives those on the launched clone. bounded oapp preflightis READY: it is the Open gate as a dry run, and it names the ladder rung for every dependency it would refuse.policy.jsonhas no rule, function, or egress that depends on a user-held credential;bounded verifypasses; every external egress is declared.- Source rides the deploy (
sourcePush: trueor--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.