# Project export: WalletOS

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: UC Berkeley AI Hackathon 2026
- Tagline: A private banker for the 99%. Talk to your money in natural language - where AI agents move, save, automate, and invest it all under your financial goals and control.
- Devpost: https://devpost.com/software/walletos
- GitHub: https://github.com/rohandash13/WalletOS
- Team: 3 GitHub contributor(s) — Rohan Dash (28 commits), Claude Opus 4.8 (20 commits), rishabh abhishetty (3 commits)

## Devpost submission (written by the team)

### Inspiration

The wealthiest 1% don't stress about money the way the rest of us do. They have CFOs, wealth managers, and private bankers who proactively move, protect, and grow their money. The other 99% get a balance screen, a transfer button, and "good luck figuring out the rest." We went to a networking event in San Francisco focused on the agentic economy - companies building the next wave of programmable money, agent-to-agent payments, and financial infrastructure. Walking out, one question stuck with us: if AI agents can now reason and act through financial tools, why does the gap between how rich people and everyone else manage money still exist? Underbanked users, people living paycheck to paycheck, families sending remittances home, they pay the most in fees, receive the least in advice, and have no one proactively managing their financial lives. Not because the knowledge doesn't exist. Because the help was never accessible. We built WalletOS to change that

### What it does

WalletOS is a private banker for the 99% — an agentic financial copilot that lets anyone talk to their money in plain English, and then actually moves it under rules they define. You say: "I get paid $2k on the 1st. Send money home to my mom every month, keep rent safe, and invest the rest low-risk — I'm a 3 out of 10 on risk." WalletOS: Parses your intent using Claude, extracting goals, amounts, cadence, and risk tolerance. Executes a real on-chain USDC transfer on Base Sepolia — verifiable live on a block explorer — so your family gets paid. Locks a rent-safe bucket so you can't accidentally overdraw rent money. Routes the remainder to the right sub-agent based on your risk score: a Stable-Invest agent for low-risk profiles (1–3), Balanced for mid-range (4–6), Growth for high-risk tolerance (7–10). Explains every decision back to you in plain English — building financial literacy as it works. Say "actually I need $200 back" and it pulls from the right bucket and confirms. Every action is auditable, every tool call is logged, and nothing moves without your stated policy allowing it. Core features: Conversational portfolio management — set goals by talking Automated recurring rules — send $50 on the 1st, protect 3 months of rent Agent marketplace — specialized sub-agents (Stable-Invest, Savings, Bill-Pay) you connect, gated by risk score Realtime portfolio events — Redis pub/sub keeps every bucket update live in the UI

### How we built it

The architecture has three layers that fit together cleanly: Reasoning layer — Claude with MCP-style tools Claude never touches the wallet directly. It only ever acts through six explicit, auditable tools: get_balance, send_payment, set_policy, create_automation, route_to_agent, explain_decision. Each tool handler enforces a spending policy, writes a transaction record, and publishes a realtime event. We run a full Claude tool-use loop: send message + tool definitions → Claude returns a tool_use block → dispatch → return tool_result → repeat → stream final explanation. This design was deliberate. Jailing Claude inside tool contracts means every money action is reviewable, and the policy layer is the only gatekeeper between "Claude thinks" and "money moves." Money rail — Coinbase CDP Wallet API on Base Sepolia We use CDP's server-wallet API to create a named, persistent wallet (demo-banker) programmatically. Funding is fully automated via cdp.evm.requestFaucet() — no website, no captcha, no manual step. Transfers go through account.transfer({ to, amount, token: "usdc", network: "base-sepolia" }) and return a real transaction hash verifiable on sepolia.basescan.org. Base Sepolia is one config flip (base-sepolia → base) from production mainnet. The architecture is production-ready. Realtime state — Redis (Upstash) + SSE Every tool action publishes to a Redis pub/sub channel (channel:events:demo). A GET /api/events SSE endpoint bridges those events to the frontend so the portfolio panel updates live — no polling, no stale state. Frontend — Next.js 15 App Router + Tailwind + shadcn/ui Three panels: Chat (the conversational agent), Automations (rule builder), and Agent Marketplace (connect sub-agents by risk tier). The frontend consumes the five API routes (/api/chat, /api/balance, /api/payment/send, /api/agent/route, /api/events) built against a strict JSON contract so both teammates could build in parallel. Agent marketplace — Fetch AI uAgents Specialized sub-agents exposed as Fetch AI uAgents, each addressable by a DID. When Claude calls route_to_agent, it selects the right agent based on risk score, sends the funds, and gets back a confirmation event. This is the backbone of the "agentic economy" vision — money routing itself between AI agents without human intermediation.

### Challenges we ran into

The CDP Sandbox trap. Coinbase has two completely different products that look similar on the surface: the Payments Sandbox (simulated fiat flows, no real chain) and the CDP Wallet API (real EVM wallets on public testnets). We spent real time figuring out why our faucet calls were failing before realizing we had the wrong product's API key entirely. The confusion cost us time we didn't have at a 24-hour hackathon. Phone verification on the CDP portal gave us an intermittent "please try again in a few minutes, your funds are safe" error while trying to enable wallet signing. We planned a viem fallback (raw EVM signing with Sepolia USDC), built it out, and then CDP started working — leaving us with two implementations to reconcile. Making Claude not just talk, but act. The hardest design challenge was constraining Claude's reasoning to operate only through tools — no raw wallet access, no ad-hoc decisions. Getting the tool-use loop right (streaming, multi-turn, policy enforcement before dispatch) required several iterations before money started moving reliably from a chat message. Agent-to-agent payments with Fetch AI introduced a second runtime (Python microservice) that needed to stay in sync with the Node.js backend over HTTP. Keeping the event schema consistent across two runtimes under time pressure was messy. "Is this crypto?" We had to find the right framing. Saying "blockchain" in a social-impact pitch risks losing the audience before you've made the point. The reframe: programmable money on testnet — the blockchain is the engine, not the product. We don't pitch Base Sepolia; we pitch "your family gets paid every month without you remembering to send it."

### Accomplishments we're proud of

A real on-chain USDC transfer triggered by a single chat message, verifiable on a public block explorer — not a mock, not a simulation, an actual Base Sepolia transaction hash. Claude reasoning about financial goals and executing multi-step plans through a fully auditable tool layer — policy enforcement, transaction logging, event publishing — all from natural language input. Programmatic testnet wallet funding via requestFaucet — zero manual steps, zero website faucets, zero captchas. The wallet is live the moment you run npx tsx scripts/setup-wallet.ts. The risk-score routing system that maps user-expressed risk tolerance (1–10, in plain English) to the right sub-agent tier — making a concept usually reserved for wealth management onboarding accessible to anyone who can say "I'm a 3 out of 10." A production-ready architecture that is one config line from mainnet. We built for testnet on purpose, but nothing in the codebase assumes it stays there.

### What we learned

Programmable money is genuinely new. Traditional banks won't give AI agents API access to move funds autonomously. Blockchain rails — even testnet ones — let you wire up an agent that actually controls money. That's not a crypto pitch; it's an architectural fact that makes the whole product possible. Tool contracts are the right abstraction for agentic finance. The MCP-style tool layer isn't just good engineering hygiene — it's the only design that's safe for money. Every action being explicit, logged, and policy-gated means you can audit what the agent did and why. Trusting a raw LLM with wallet access would be reckless; trusting a constrained tool dispatcher is defensible. Financial framing matters more than technical framing. "Base Sepolia USDC transfer" means nothing to a judge evaluating social impact. "Your mom gets paid every month without you remembering to send it" means everything. We learned to build the technical story after the human story is clear. Two runtimes under time pressure is one too many. The Fetch AI Python microservice was the right architectural call for agent-to-agent payments, but the cross-language event schema synchronization added friction at exactly the wrong moment.

### What's next

Mainnet. One line of config separates the demo from production. The real question isn't technical — it's regulatory. We'd pursue partnership with an MSB-licensed operator to handle the compliance layer while WalletOS stays the reasoning and automation stack. Voice-first interface with Deepgram. "Send money home" should be a sentence you speak, not type. Deepgram's real-time STT/TTS would make WalletOS fully accessible to users who are uncomfortable with financial apps — the exact population most underserved by current tools. Recurring automations via Orkes Conductor. The automation rules exist in the data model today; making them durable, retryable, and observable at scale needs a proper workflow engine. Orkes lets us define "send $50 on the 1st" as a workflow that survives restarts and failures. A real Fetch AI agent marketplace. Today we have one Stable-Invest agent stub. The long-term vision is an open marketplace of financial sub-agents — savings optimizers, bill negotiators, remittance routers — each addressable by DID, each transacting autonomously under user-set policies. Agent-to-agent payments on Base with Fetch AI as the coordination layer. Eval and trust scoring with Arize. As the agent makes more consequential decisions, understanding why it routed a certain way becomes critical for user trust and regulatory defensibility. Arize gives us the observability layer to trace every decision back to the model's reasoning — and to catch drift before it becomes a problem. Multilingual and low-bandwidth support. The users WalletOS is built for don't all live in San Francisco. SMS-first or USSD-first interfaces, multilingual Claude prompts, and offline-capable transaction queueing are the path to the actual 99%.

## README (from the GitHub repository)

# WalletOS

> **A private banker for the 99%.** Talk to your money in plain English — and an AI agent actually moves it, saves it, invests it, and automates it, under rules you set.

---

## The problem

The wealthy have CFOs, wealth managers, and information advantages. Everyone else gets a balance screen and a "good luck."

That gap is an **economic-opportunity gap**: people who are underbanked, living paycheck-to-paycheck, or sending money home pay the most and get the least from the financial system — not because the knowledge doesn't exist, but because the *help* was never accessible.

**WalletOS closes that gap** by giving everyone an agentic financial team in their pocket — for free.

## What it does

You talk to your money in plain English. An AI agent powered by **Claude** understands your goals, then *acts* on them through real, auditable tools:

- **Onboarding** — first you set a **risk score (1–10)** and an **"approve before moving money" limit**, so the agent never assumes your preferences or moves large amounts without you.
- **Chat** — "I get paid $2k on the 1st. Send my sister $50 every month, keep rent safe, and invest the rest low-risk." Claude parses the intent and sets it up. You can change your risk score or approval limit any time, just by saying so.
- **Automations** — recurring rules ("send $50 on payday," "protect rent first," "invest the leftover") that run when income lands. Anything over your approval limit waits for your OK.
- **Financial agents** — specialized investing agents (Savings, Stable-Invest, Balanced-Growth, Growth, High-Yield, Bill-Pay), auto-matched to your risk score, plus **create-your-own** agents from a plain-English goal. They make real on-chain agent-to-agent transfers and are discoverable on **Fetch AI's ASI:One**.
- **Fund tracking** — once money is invested, an "Invested funds" view shows each agent's principal, real on-chain balance, and simulated growth over time.

Every action is explained back to you in plain English — so it teaches financial literacy as it works.

## Demo

> *"I get paid \$2k on the 1st. Send my sister \$50 every month, keep rent safe, and invest the rest low-risk — I'm a 3 out of 10 on risk."*

1. You pick a risk score and approval limit in onboarding; Claude suggests agents that fit.
2. Claude parses the request and sets up the payday automations.
3. **Generate paycheck** lands \$2,000 (a **real, scaled on-chain USDC transfer** on Base Sepolia, verifiable on a block explorer) and runs the automations.
4. The remainder routes to the matched investing agent; moves over your limit pause for approval.
5. The portfolio updates in real time, and Claude explains *why* it did what it did.
6. *"Actually, I need \$200 back"* → it pulls from the right bucket and confirms.

## How it works

```
  Web app (Next.js + TypeScript + Tailwind), gated by Clerk auth
   Chat · Automations · Agents · Portfolio ──► Realtime events (in-memory store; optional Upstash Redis)
            │
            ▼
   Agent brain: Claude (tool-use / MCP-style tools)
     get_balance · send_payment · set_policy · create_automation · route_to_agent · rebalance_funds · explain_decision
            │
            ├──► Money rail: Coinbase CDP Wallet API — server wallet on Base Sepolia (test USDC)
            ├──► Financial agents: Fetch AI uAgents (agent-to-agent payments, ASI:One discoverable)
            └──► Automations: recurring payday rules + an approval queue
```

Claude is the reasoning layer. It only ever acts through explicit, auditable **tools** — each one enforces the spending/approval policy, records a transaction, and publishes a realtime event to the UI.

**Demo economy:** the app shows relatable dollars while settling scaled test USDC on-chain (default `1 test USDC = $1,000`, configurable via `DEMO_USD_PER_TEST_USDC`), so a \$50 payment settles as 0.05 test USDC.

## Tech stack

| Layer | Tech |
|---|---|
| Agent / reasoning | **Claude** (Anthropic) — tool-use, MCP-style tools |
| Money rail | **Coinbase CDP Wallet API** — server wallet on **Base Sepolia** testnet, programmatic faucet |
| Financial agents | **Fetch AI** uAgents — agent-to-agent payments, ASI:One / Agentverse discoverable |
| Auth | **Clerk** — sign-in, per-user state |
| State | **In-memory store** by default; **optional Upstash Redis** (set `UPSTASH_*` to use it) |
| Frontend | **Next.js (App Router) + TypeScript + Tailwind** |

## Getting started

### Prerequisites
- Node.js 20+
- An **Anthropic API key**
- A **Coinbase CDP** account → API Key ID + Secret + Wallet Secret ([portal.cdp.coinbase.com](https://portal.cdp.coinbase.com))
- **Clerk** keys (publishable + secret) for auth ([clerk.com](https://clerk.com))
- *(Optional)* an **Upstash Redis** instance — only if you want shared/persistent state instead of the in-memory store
- *(Optional)* an **Agentverse API key** — only to publish the Python financial agents to ASI:One

### 1. Install
```bash
git clone https://github.com/<you>/WalletOS.git
cd WalletOS
npm install
```

### 2. Configure `.env.local`
```bash
# Required
ANTHROPIC_API_KEY=
CDP_API_KEY_ID=
CDP_API_KEY_SECRET=
CDP_WALLET_SECRET=
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=

# Optional
# UPSTASH_REDIS_REST_URL=          # use Upstash instead of the in-memory store
# UPSTASH_REDIS_REST_TOKEN=
# DEMO_USD_PER_TEST_USDC=1000      # demo scale (default 1000)
# CDP_PAYROLL_ACCOUNT_NAME=walletos-payroll
```

### 3. Create & fund the testnet wallet (no website faucet needed)
```bash
npm run setup:wallet
```
This creates a named CDP server wallet and funds it on **Base Sepolia** with test ETH (gas) + test USDC via the CDP faucet, then prints the address and explorer links. `npm run balance` shows balances anytime.

### 4. Run
```bash
npm run dev
```
Open [http://localhost:3000](http://localhost:3000), sign in, complete onboarding, and talk to your money.

### 5. (Optional) Financial agents on ASI:One
```bash
cd agent-service
pip install -r requirements.txt
cp .env.example .env        # add AGENTVERSE_API_KEY
python register.py          # publish all 6 agents to your Agentverse account
python run_all.py           # keep running so ASI:One can reach them via mailbox
```

## Project structure

```
app/
  api/            # chat, balance, payday, reset, demo/{seed,reset}, automations,
                  # events, marketplace, agent/route, payment/send, investments,
                  # approvals, settings
  components/     # WalletDemo (chat · automations · agents · portfolio · onboarding)
  chat/ sign-in/ sign-up/   # Clerk-gated app shell
lib/
  wallet.ts       # CDP WalletService (balance, transfer, faucet, spending policy)
  tools.ts        # Claude tool definitions + dispatch (only code that moves money)
  agent.ts        # Claude tool-use loop (+ activity context, approval rule)
  agent-factory.ts# create-your-own agents from a plain-English goal
  marketplace.ts  # Fetch uAgent registry, risk gating, /route caller
  payday.ts       # paycheck simulation + payday automations + approval queue
  investments.ts  # post-investment fund tracking (principal, on-chain, growth)
  redis.ts        # realtime events + bucket ledger (in-memory or Upstash)
  adapter.ts      # backend shapes -> frontend JSON contract
  money.ts        # demo USD <-> test USDC scaling
  auth.ts profiles.ts   # Clerk auth + per-user profiles
  types.ts wallet-types.ts   # shared API/domain shapes
agent-service/    # Fetch AI uAgents (Python): savings / stable-invest / balanced-growth
                  # / growth / high-yield / bill-pay  (+ register.py, run_all.py)
scripts/
  setup-wallet.ts # one-time testnet wallet creation + funding + transfer proof
  seed-demo.ts    # seed a demo paycheck via the running server
  faucet.ts balance.ts payday.ts            # wallet/faucet/payday helpers
  demo-recipient.ts demo-transfer.ts        # demo transfer target + send proof
  verify-pipeline.ts                        # hermetic checks: math + agent routing
```



[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 61 recognized source files, 242 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code
- AI coding agent: Claude Code — evidence: config files committed to the repository; commit authorship or trailers
- AI coding agent: Codex — evidence: config files committed to the repository

## Codebase structure (from repository index)

### Files (68 of 68)

```
.commitmsg.tmp
.gitignore
agent-service/balanced_growth_agent.py
agent-service/bill_pay_agent.py
agent-service/common.py
agent-service/growth_agent.py
agent-service/high_yield_agent.py
agent-service/README.md
agent-service/register.py
agent-service/requirements.txt
agent-service/run_all.py
agent-service/savings_agent.py
agent-service/stable_invest_agent.py
agent-service/strategies.py
AGENTS.md
app/api/agent/route/route.ts
app/api/approvals/route.ts
app/api/automations/route.ts
app/api/balance/route.ts
app/api/chat/route.ts
app/api/demo/reset/route.ts
app/api/demo/seed/route.ts
app/api/events/route.ts
app/api/investments/route.ts
app/api/marketplace/route.ts
app/api/payday/route.ts
app/api/payment/send/route.ts
app/api/reset/route.ts
app/api/settings/route.ts
app/chat/ChatApp.tsx
app/chat/page.tsx
app/components/AuthActions.tsx
app/components/WalletDemo.tsx
app/globals.css
app/layout.tsx
app/page.tsx
app/sign-in/[[...sign-in]]/page.tsx
app/sign-up/[[...sign-up]]/page.tsx
CLAUDE.md
eslint.config.mjs
lib/adapter.ts
lib/agent-factory.ts
lib/agent.ts
lib/auth.ts
lib/investments.ts
lib/marketplace.ts
lib/money.ts
lib/payday.ts
lib/profiles.ts
lib/redis.ts
lib/tools.ts
lib/types.ts
lib/wallet-types.ts
lib/wallet.ts
next.config.ts
package.json
postcss.config.mjs
proxy.ts
README.md
scripts/balance.ts
scripts/demo-recipient.ts
scripts/demo-transfer.ts
scripts/faucet.ts
scripts/payday.ts
scripts/seed-demo.ts
scripts/setup-wallet.ts
scripts/verify-pipeline.ts
tsconfig.json
```

### Dependencies

- agent-service/requirements.txt: python-dotenv@>=1.0.0, uagents@>=0.22.0
- package.json: @anthropic-ai/sdk@^0.105.0, @clerk/nextjs@^7.5.7, @coinbase/cdp-sdk@^1.51.2, @tailwindcss/postcss@^4, @types/node@^20, @types/react@^19, @types/react-dom@^19, @upstash/redis@^1.38.0, dotenv@^17.4.2, eslint@^9, eslint-config-next@16.2.9, lucide-react@^0.468.0, next@16.2.9, react@19.2.4, react-dom@19.2.4, tailwindcss@^4, tsx@^4.22.4, typescript@^5

### Recent commits (newest first)

- Merge pull request #8 from rohandash13/redesign-platform-ui
- Update README to match the real stack; drop never-built services + stale docs
- Fix Agentverse registration: all 6 agents via the mailbox endpoint
- Merge pull request #7 from rohandash13/redesign-platform-ui
- Make risk score a real, persisted setting the agent can change
- Update risk score and approval limit dynamically from chat
- Require onboarding before chat; stop faking an empty wallet
- Merge pull request #6 from rohandash13/redesign-platform-ui
- Speed up onboarding suggestion with a low-effort fast path
- Merge pull request #5 from rohandash13/redesign-platform-ui
- Enforce approval threshold on payday automations + give agent activity context
- Add demo recipient + transfer helper scripts
- Add "approve before moving money" threshold + risk slider onboarding
- Render assistant replies as light markdown
- Risk-score onboarding: prompt 1-10 first, then suggest agents
- UI: "Financial Agents" + label each agent as "... Agent"
- Add simulated growth/progression to invested-funds tracking
- Resolve investing agents by display name, not just id
- Reset mirrors real on-chain USDC instead of fixed seed
- Merge origin/main (Clerk auth + per-user scoping) into redesign-platform-ui

## Key source files (fetched from GitHub, selected and truncated for size)

### CLAUDE.md

```markdown
@AGENTS.md

```

### AGENTS.md

```markdown
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->

```

### package.json

```
{
  "name": "walletos",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint",
    "typecheck": "tsc --noEmit",
    "setup:wallet": "tsx scripts/setup-wallet.ts",
    "seed:demo": "tsx scripts/seed-demo.ts",
    "faucet": "tsx scripts/faucet.ts",
    "balance": "tsx scripts/balance.ts",
    "payday": "tsx scripts/payday.ts"
  },
  "dependencies": {
    "@anthropic-ai/sdk": "^0.105.0",
    "@clerk/nextjs": "^7.5.7",
    "@coinbase/cdp-sdk": "^1.51.2",
    "@upstash/redis": "^1.38.0",
    "dotenv": "^17.4.2",
    "lucide-react": "^0.468.0",
    "next": "16.2.9",
    "react": "19.2.4",
    "react-dom": "19.2.4"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "16.2.9",
    "tailwindcss": "^4",
    "tsx": "^4.22.4",
    "typescript": "^5"
  }
}

```

### agent-service/requirements.txt

```
uagents>=0.22.0
python-dotenv>=1.0.0

```

### app/layout.tsx

```typescript
import type { Metadata } from "next";
import { ClerkProvider } from "@clerk/nextjs";
import "./globals.css";

export const metadata: Metadata = {
  title: "WalletOS | Private Banker for the 99%",
  description:
    "A demo financial copilot that turns plain-English money goals into visible, safe actions.",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body>{children}</body>
      </html>
    </ClerkProvider>
  );
}

```

### app/page.tsx

```typescript
import { auth } from "@clerk/nextjs/server";
import { redirect } from "next/navigation";
import { AuthActions } from "./components/AuthActions";

export default async function Home() {
  const { userId } = await auth();

  if (userId) {
    redirect("/chat");
  }

  return (
    <main className="public-page">
      <section className="public-card">
        <p className="eyebrow">WalletOS</p>
        <h1>Private Banker for the 99%</h1>
        <p>
          Sign in with Google to access your WalletOS profile, rules,
          automations, and demo app session.
        </p>
        <AuthActions />
        <p className="public-note">
          Demo only · Testnet USDC · Shared funded demo wallet
        </p>
      </section>
    </main>
  );
}

```

### app/chat/page.tsx

```typescript
import { ChatApp } from "./ChatApp";

export default function ChatPage() {
  return <ChatApp />;
}

```

### app/sign-in/[[...sign-in]]/page.tsx

```typescript
import { AuthActions } from "@/app/components/AuthActions";
import { auth } from "@clerk/nextjs/server";
import { redirect } from "next/navigation";

export default async function SignInPage() {
  const { userId } = await auth();

  if (userId) {
    redirect("/chat");
  }

  return (
    <main className="auth-page">
      <section className="public-card">
        <p className="eyebrow">WalletOS</p>
        <h1>Sign in</h1>
        <p>Use your Google account to open your protected WalletOS demo app.</p>
        <AuthActions />
      </section>
    </main>
  );
}

```

### app/sign-up/[[...sign-up]]/page.tsx

```typescript
import { AuthActions } from "@/app/components/AuthActions";
import { auth } from "@clerk/nextjs/server";
import { redirect } from "next/navigation";

export default async function SignUpPage() {
  const { userId } = await auth();

  if (userId) {
    redirect("/chat");
  }

  return (
    <main className="auth-page">
      <section className="public-card">
        <p className="eyebrow">WalletOS</p>
        <h1>Create account</h1>
        <p>Create your WalletOS profile with Google, then continue to the app.</p>
        <AuthActions />
      </section>
    </main>
  );
}

```

### app/api/events/route.ts

```typescript
/**
 * GET /api/events — realtime event feed (frontend contract).
 * Returns: { events: WalletEvent[] }  (newest-first)
 */
import { NextResponse } from "next/server";
import { getEventsSince } from "@/lib/redis";
import { toWalletEvents } from "@/lib/adapter";
import { requireAuth } from "@/lib/auth";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

export async function GET() {
  try {
    const session = await requireAuth();
    if (session.response) return session.response;

    const events = await getEventsSince(0, 100, session.userId);
    return NextResponse.json({ events: toWalletEvents(events) });
  } catch (err) {
    const msg = err instanceof Error ? err.message : String(err);
    return NextResponse.json({ error: msg }, { status: 500 });
  }
}

```

[51 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]