OrbitSafe is our submission for the Stellar Hacks: Agents hackathon.
It gives an AI agent a governed wallet instead of a free-spending hot wallet. The owner signs a policy first. The agent can then spend only inside that policy. Paid calls leave receipts, blocked calls leave policy decisions, and the dashboard makes both visible in one place.
This repository contains the working judge demo. The demo runs on Stellar testnet on purpose so it can be replayed safely and consistently. The architecture is still aimed at mainnet deployment.
If you open the app and run the intended flow, these are the proof points that matter:
- The owner connects
Freighterand signs the spending policy. - The policy defines budget, per-request cap, and allowlist.
- The agent runs paid
researchandsummarizecalls overx402. - If
MPPis configured, the agent also runsverifythrough anMPPsession. - OrbitSafe blocks requests that exceed the cap or fall outside the allowlist before payment moves.
Paid execution traceshows the rail, amount, payer, network, and receipt or transaction reference.Activity ledgerrecords both approved spend and blocked policy decisions.
That is the product claim: not just "agents can pay", but "agents can pay under explicit controls".
apps/web: Next.js dashboardapps/api: Express API withx402,MPP, policy enforcement, and SQLite state
OrbitSafe adapts to the rails you configure:
full: paidx402research, paidx402summary, thenMPPverifyx402-only: paid research and summaryverify-only:MPPverify withoutx402
For the hackathon, the ideal path is full, but the repo can still demonstrate the core product in x402-only mode.
- Install dependencies.
npm install- Copy the testnet environment file.
cp .env.example .env- Prepare three wallets.
owner: aFreighterwallet used for browser auth and policy signingagent: a backend wallet used asAGENT_WALLET_SECRETops: a backend wallet used asX402_RECEIVER_ACCOUNTand, when needed,MPP_FEE_PAYER_SECRET
- Fund the testnet wallets.
- Fund
agentandopswith testnetXLM - Add a testnet
USDCtrustline for both - Fund testnet
USDCthrough the Circle faucet: https://faucet.circle.com/
- Fill
.env.
Minimum values for an x402 run:
ORBITSAFE_BOOTSTRAP_OWNER_ADDRESSAGENT_WALLET_SECRETX402_RECEIVER_ACCOUNT
Additional values for the full MPP path:
MPP_SECRET_KEYMPP_CHANNEL_CONTRACTMPP_COMMITMENT_PUBLIC_KEYMPP_COMMITMENT_SECRETMPP_FEE_PAYER_SECRET
- Start the app.
npm run dev- Web:
http://localhost:3000 - API:
http://localhost:3001
This is the cleanest way to run the hackathon demo:
- Connect
Freighterwith the approved owner wallet. - Open the policy and confirm budget, cap, and allowlist.
- Resume the policy if it is paused.
- Use
Prepare recordingto clear spend, receipts, and ledger state. - Press
Run. - Show
Run summary. - Show
Paid execution trace. - Show
Activity ledger. - Trigger
Blocked by cap. - Trigger
Blocked by allowlist.
What the judges should walk away with is simple: OrbitSafe lets an agent pay for tools on Stellar, but only inside rules the owner signed first.
STELLAR_NETWORK_LABELSTELLAR_HORIZON_URLSTELLAR_RPC_URLSTELLAR_NETWORK_PASSPHRASESTELLAR_USDC_ISSUERX402_NETWORKX402_FACILITATOR_URLX402_RECEIVER_ACCOUNTAGENT_WALLET_SECRET
MPP_NETWORKMPP_PRICE_VERIFY_CENTSMPP_SECRET_KEYMPP_CHANNEL_CONTRACTMPP_COMMITMENT_PUBLIC_KEYMPP_COMMITMENT_SECRETMPP_FEE_PAYER_SECRET
ORBITSAFE_DB_PATHORBITSAFE_AUTH_TTL_SECONDSORBITSAFE_BOOTSTRAP_OWNER_ADDRESS
The included demo is testnet-first. For a real mainnet deployment, you will need:
- a real pubnet Soroban RPC provider
- a mainnet facilitator
- funded mainnet
XLMaccounts - mainnet
USDCtrustlines and balances - a deployed and funded mainnet one-way
MPPchannel contract
Do not reuse a testnet database for mainnet.
For orbitsafe.xyz, the repo includes a simple production stack:
docker-compose.prod.ymldeploy/web.Dockerfiledeploy/api.Dockerfiledeploy/Caddyfile.env.production.exampleSECURITY-LAUNCH-CHECKLIST.md
Minimal deploy sequence:
cp .env.production.example .env
docker compose -f docker-compose.prod.yml build
docker compose -f docker-compose.prod.yml up -dExpected DNS for the included Caddy config:
orbitsafe.xyzwww.orbitsafe.xyzapi.orbitsafe.xyz
The containers use Node 25 because OrbitSafe relies on the built-in node:sqlite driver.
- The policy engine uses cents internally to avoid float drift.
- The API keeps policy, ledger state, auth challenges, and MPP state in SQLite.
- The public
/healthroute stays intentionally minimal. - Only the API process should receive payment secrets in production.
- The current deploy profile is single-instance. If you scale horizontally, move state off local disk.