From 6af84c071b29c3b476733f2ff60a6ee8ca4c9c75 Mon Sep 17 00:00:00 2001 From: Matt Lehman Date: Thu, 12 Feb 2026 15:04:41 -0500 Subject: [PATCH] Pivot to local-first public release with GitHub Pages --- .github/workflows/fly-deploy.yml | 87 ------ .gitignore | 2 - CLAUDE.md | 183 ++--------- Dockerfile.fly | 21 -- Makefile | 13 +- README.md | 240 +++----------- assets/brand/yappybara-lockup.svg | 4 +- docs/deploy-queue.md | 35 --- docs/distribution.md | 52 ---- docs/family-launch.md | 52 ---- docs/fly-api-rollout.md | 130 -------- docs/github-pages.md | 65 ++-- fly.toml | 39 --- interview-app/.env.example | 2 +- interview-app/fly.toml.example | 39 --- interview-app/public/index.html | 4 +- interview-app/server.js | 4 +- interview-app/test.js | 14 +- site/404.html | 25 +- site/app.js | 281 ----------------- site/assets/logo-lockup.svg | 4 +- site/index.html | 148 ++++----- site/styles.css | 498 +++++++----------------------- 23 files changed, 330 insertions(+), 1612 deletions(-) delete mode 100644 .github/workflows/fly-deploy.yml delete mode 100644 Dockerfile.fly delete mode 100644 docs/deploy-queue.md delete mode 100644 docs/distribution.md delete mode 100644 docs/family-launch.md delete mode 100644 docs/fly-api-rollout.md delete mode 100644 fly.toml delete mode 100644 interview-app/fly.toml.example delete mode 100644 site/app.js diff --git a/.github/workflows/fly-deploy.yml b/.github/workflows/fly-deploy.yml deleted file mode 100644 index 6cd9237..0000000 --- a/.github/workflows/fly-deploy.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: Deploy Fly API - -on: - push: - branches: [main] - paths: - - 'fly.toml' - - 'Dockerfile.fly' - - '.dockerignore' - - 'interview-app/**' - - '.github/workflows/fly-deploy.yml' - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: fly-main - cancel-in-progress: true - -jobs: - deploy: - name: Deploy interview-app to Fly - runs-on: ubuntu-latest - env: - FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} - FLY_APP_NAME: ${{ vars.FLY_APP_NAME }} - FLY_PRIMARY_REGION: ${{ vars.FLY_PRIMARY_REGION }} - FLY_VOLUME_NAME: ${{ vars.FLY_VOLUME_NAME }} - FLY_VOLUME_SIZE_GB: ${{ vars.FLY_VOLUME_SIZE_GB }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup flyctl - uses: superfly/flyctl-actions/setup-flyctl@master - - - name: Deploy - run: | - if [ -z "${FLY_API_TOKEN}" ]; then - echo "Missing FLY_API_TOKEN repository secret." - echo "Add it in GitHub: Settings -> Secrets and variables -> Actions -> New repository secret." - exit 1 - fi - - APP_FROM_CONFIG="$(awk -F'\"' '/^app[[:space:]]*=/ { print $2; exit }' fly.toml)" - APP_NAME="${APP_FROM_CONFIG:-${FLY_APP_NAME}}" - PRIMARY_REGION="${FLY_PRIMARY_REGION:-ord}" - VOLUME_NAME="${FLY_VOLUME_NAME:-yappybara_data}" - VOLUME_SIZE_GB="${FLY_VOLUME_SIZE_GB:-1}" - - if [ -z "${APP_NAME}" ]; then - echo "Unable to determine Fly app name." - echo "Set repository variable FLY_APP_NAME or app = \"...\" in fly.toml." - exit 1 - fi - - if [ -n "${APP_FROM_CONFIG}" ] && [ -n "${FLY_APP_NAME}" ] && [ "${APP_FROM_CONFIG}" != "${FLY_APP_NAME}" ]; then - echo "Ignoring stale FLY_APP_NAME='${FLY_APP_NAME}' and using fly.toml app '${APP_FROM_CONFIG}'." - fi - - APP_INFO_OUTPUT="$(flyctl status --app "${APP_NAME}" 2>&1 || true)" - if ! echo "${APP_INFO_OUTPUT}" | grep -q "App"; then - if echo "${APP_INFO_OUTPUT}" | grep -qi "app not found"; then - echo "Fly app ${APP_NAME} does not exist yet. Creating it now..." - flyctl apps create "${APP_NAME}" - else - echo "${APP_INFO_OUTPUT}" - echo "Unable to access Fly app '${APP_NAME}'. Check that FLY_API_TOKEN has deploy access to this app." - exit 1 - fi - fi - - if ! flyctl volumes list --app "${APP_NAME}" | grep -q "${VOLUME_NAME}"; then - echo "Fly volume ${VOLUME_NAME} does not exist yet. Creating it now..." - flyctl volumes create "${VOLUME_NAME}" \ - --yes \ - --app "${APP_NAME}" \ - --region "${PRIMARY_REGION}" \ - --size "${VOLUME_SIZE_GB}" - fi - - echo "Deploying to Fly app: ${APP_NAME}" - flyctl deploy \ - --remote-only \ - --app "${APP_NAME}" \ - --config fly.toml diff --git a/.gitignore b/.gitignore index f4c41c3..b6c44b4 100644 --- a/.gitignore +++ b/.gitignore @@ -72,8 +72,6 @@ interview-app/last-fix.md interview-app/build-summary.md interview-app/builds/ interview-app/public/builds/ -interview-app/fly.toml -interview-app/.fly/ # Feedback transcripts and archives (local working files) feedback/* diff --git a/CLAUDE.md b/CLAUDE.md index 98c4419..3798e0f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,167 +1,50 @@ # CLAUDE.md - - +## Project summary -## What is this project? +Yappybara is a local-first AI app ideation and prototyping workspace. -Yappybara is a toolkit for helping kids (ages 9-14) design and build their first app using Claude Code. It includes a voice-powered interview app, sketch tools, and an automated build system. The app idea hasn't been captured yet — run `/idea-capture` with the interview transcript to fill this in. +Primary path: +- run `interview-app/` locally, +- iterate on prompts/spec/prototype quickly, +- keep infra cost near zero. ---- +This repo is intentionally aligned to: +- no required Fly.io backend, +- free GitHub Pages site in `site/`, +- local persistence and local execution by default. -## Voice Interview App +## Core runtime -The `interview-app/` directory contains a browser-based interview tool. It uses: -- **Web Speech API** for speech-to-text and text-to-speech (runs in Chrome) -- **Claude Agent SDK** for conversation (uses your Claude Max subscription, no API key needed) -- **Built-in drawing tool** for sketching app ideas directly in the browser +- `interview-app/server.js` — Express server + orchestration +- `interview-app/public/index.html` — browser UI +- `interview-app/builder.js` — prototype builder +- `interview-app/mechanic.js` — patch/fix loop +- `interview-app/safety.js` — response/preview sanitization -To run: `make interview-setup` (once), then `make interview` - -No API key needed — uses your existing Claude Code auth. Sketches are saved to `docs/sketches/` automatically. - -## Media Safety Rules - -- NEVER attempt to read audio or video files (`.wav`, `.mp3`, `.m4a`, `.mp4`, `.mov`, etc.) -- Audio is handled by the browser's Web Speech API; Claude only ever sees text -- The `/sketch` skill can read images (photos of drawings) — images are allowed -- Sketches from the interview app are saved to `docs/sketches/` - ---- - -## Important Context for Claude - -**The creator is a kid (ages 9-14) and very intelligent.** When explaining things: -- Use clear, direct language - no corporate jargon or hand-waving -- It's okay to use real technical terms, but explain them the first time ("a *component* is a reusable piece of UI, like a building block") -- Be encouraging and enthusiastic about their ideas -- When there are choices to make, present 2-3 options with honest trade-offs -- Default to the simplest approach that works -- Ask "does that make sense?" and actually mean it - -**A parent or mentor is always present** during Claude interactions. They can help with: -- Account setup (App Store, hosting, etc.) -- Approving any spending or cloud resources -- Git operations and deployment -- Answering questions about the real world - -**The goal:** Show that a kid with a good idea and AI tools can build something real that helps people. Ship fast, learn by doing, iterate based on feedback. - ---- - -## Tech Stack - - - -| Layer | Choice | Notes | -|-------|--------|-------| -| **App Framework** | Expo (React Native) | One codebase for iOS, Android, and web | -| **Language** | TypeScript + React | Industry standard, tons of learning resources | -| **Backend** | Supabase | Free tier: database, auth, file storage, real-time | -| **Hosting (web)** | Vercel | Free tier for the web version | -| **Mobile builds** | EAS Build | Free tier for iOS/Android builds | -| **CI/CD** | GitHub Actions | Auto-test on every push | - -**Why these choices:** -- **Expo** handles iOS + Android + Web from one codebase. No need to learn Swift AND Kotlin AND React separately. -- **Supabase** has a generous free tier (500MB database, 1GB file storage, 50K monthly active users). That's plenty to launch and get real users. -- **Vercel** hosts the web version for free. -- **Total cost to launch: $0.** Costs only start if the app gets thousands of users (a good problem to have). - ---- - -## Project Structure - -``` -interview-app/ # Voice interview tool (browser-based) - server.js # Express server + Anthropic API - public/index.html # Chat UI with speech + drawing - uploads/ # Uploaded sketch photos -app/ # Expo app (screens, components, navigation) - (tabs)/ # Tab-based navigation screens - components/ # Reusable UI components - lib/ # Utilities, API client, helpers - assets/ # Images, fonts, icons -docs/ - sketches/ # Processed sketch specs (from interview + /sketch) - BUILD-PLAN.md # Phased build plan -feedback/ # Saved interview transcripts -supabase/ # Database migrations and config -CLAUDE.md # This file -INTERVIEW.md # Interview script -README.md # Project docs -``` - ---- - -## Development Commands - -```bash -# Run the voice interview (first time: make interview-setup) -make interview - -# Start the app in development mode (opens in browser + Expo Go on phone) -make dev - -# Run tests -make test - -# Build for web -make build-web - -# Create a preview build for phone testing -make build-preview - -# Check for problems -make lint -``` - ---- - -## Database Tables - - - ---- - -## Environment Variables +## Local commands ```bash -# Supabase (get these from supabase.com dashboard) -EXPO_PUBLIC_SUPABASE_URL=https://your-project.supabase.co -EXPO_PUBLIC_SUPABASE_ANON_KEY=your-anon-key +make interview-setup +make interview # Claude-enabled mode +make interview-demo # local-only mode +make interview-test ``` ---- - -## Screens - - - ---- - -## Roadmap +## Safety + constraints -### Done -- [x] Project template ready -- [ ] Interview completed -- [ ] Sketches processed -- [ ] Plan created +- Never read raw audio/video blobs in tooling flows. +- Treat user/project files as local-first and avoid adding remote dependencies unless explicitly requested. +- Prefer deterministic edits and test-backed changes. -### Phase 1: Get it running -- [ ] Create Expo project -- [ ] Set up navigation -- [ ] Build home screen +## Public site -### Phase 2: Core features -- [ ] +- `site/` is deployed by `.github/workflows/pages.yml` +- custom domain target: `yappybara.dev` +- DNS automation script: `scripts/configure-namecheap-github-pages.mjs` -### Phase 3: Make it look great -- [ ] Apply design from sketches -- [ ] Add animations -- [ ] Test on real phone +## Release posture -### Phase 4: Share it with the world -- [ ] Deploy web version -- [ ] Build for iOS/Android -- [ ] Share with friends for feedback +- MIT licensed +- CI test workflow in `.github/workflows/ci.yml` +- keep docs and workflows aligned with local-first + free-hosting strategy diff --git a/Dockerfile.fly b/Dockerfile.fly deleted file mode 100644 index de4e910..0000000 --- a/Dockerfile.fly +++ /dev/null @@ -1,21 +0,0 @@ -FROM node:22-slim - -WORKDIR /app - -ENV NODE_ENV=production - -COPY interview-app/package*.json ./ -RUN npm ci --omit=dev && npm cache clean --force - -COPY interview-app/ ./ - -RUN mkdir -p /data - -ENV PORT=8080 -ENV YAPPY_STORAGE_DIR=/data -ENV FORCE_HTTP=true -ENV AUTO_GENERATE_CERTS=false - -EXPOSE 8080 - -CMD ["node", "server.js"] diff --git a/Makefile b/Makefile index 18a5e5d..e95aef6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # App Makefile # These commands will work once the Expo project is created -.PHONY: dev test build build-web build-preview lint clean setup help interview interview-demo interview-setup interview-test feedback restart resume yappybara-install yappybara-install-plugin yappybara-launch deploy-queue +.PHONY: dev test build build-web build-preview lint clean setup help interview interview-demo interview-setup interview-test feedback restart resume yappybara-install yappybara-install-plugin yappybara-launch help: ## Show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' @@ -75,7 +75,7 @@ interview: ## Start the voice interview app (uses Claude Max subscription) interview-demo: ## Start kid-safe demo mode (no Claude login required) @cd interview-app && YAPPY_MODE=demo node server.js -yappybara-install: ## One-command local install for families (set YAPPY_INSTALL_PLUGIN=1 to add Claude plugin) +yappybara-install: ## One-command local install (set YAPPY_INSTALL_PLUGIN=1 to add Claude plugin) @if [ "$${YAPPY_INSTALL_PLUGIN:-0}" = "1" ]; then \ ./scripts/install-yappybara.sh --with-plugin; \ else \ @@ -85,12 +85,5 @@ yappybara-install: ## One-command local install for families (set YAPPY_INSTALL_ yappybara-install-plugin: ## Install Yappybara Claude plugin from this repo marketplace @./scripts/install-claude-plugin.sh -yappybara-launch: ## Fast launcher for kid-safe demo mode +yappybara-launch: ## Fast launcher for local demo mode @$(MAKE) interview-demo - -deploy-queue: ## Show recent parent deploy requests captured locally - @if [ -f interview-app/data/deploy-requests.jsonl ]; then \ - tail -n 20 interview-app/data/deploy-requests.jsonl; \ - else \ - echo "No deploy requests yet."; \ - fi diff --git a/README.md b/README.md index e114d22..36fa269 100644 --- a/README.md +++ b/README.md @@ -2,240 +2,98 @@ ![Yappybara Logo](assets/brand/yappybara-lockup.svg) -A toolkit for helping kids build their first app with AI. Yappybara guides a young creator through an interview about their app idea, then builds a working prototype — all through a friendly voice conversation with a capybara named Bart. +Yappybara is a local-first AI app ideation and prototyping workspace. -## What It Does +It gives you a fast loop: +1. chat through an app idea, +2. shape the spec, +3. generate a working prototype, +4. iterate. -1. **Interview** — Bart (a goofy capybara) chats with your kid about their app idea using voice or text. No tech jargon, just a fun conversation about what they want to build. -2. **Sketch** — A built-in drawing tool lets them sketch their ideas right in the browser, or upload photos of paper sketches. -3. **Build** — When Bart understands the idea, Dash (another capybara) automatically builds a working HTML prototype they can see and play with. -4. **Fix** — A "fix this!" panic button lets the kid report problems, and Wrench (the mechanic capybara) patches things up. +## Positioning -The whole experience is designed to feel like chatting with a friend, not using a developer tool. +- Engineer-focused +- Local-first +- Free to use locally +- No required hosted backend -## Parent Supervision And Legal Notice +This repository intentionally does **not** depend on Fly.io or a paid hosted API layer for the core workflow. -- Yappybara is an AI-assisted educational tool and should be used only with active parent/guardian supervision. -- AI output can be wrong, incomplete, or occasionally inappropriate even with filters in place. -- Do not enter sensitive personal data (full names, addresses, phone numbers, passwords, financial, medical, or legal details). -- Yappybara is not a medical, legal, financial, or emergency service. -- Foundational model providers also require policy/terms compliance for age and safety: - - Anthropic Consumer Terms: https://www.anthropic.com/legal/consumer-terms - - Anthropic Usage Policy: https://www.anthropic.com/legal/aup - - OpenAI Terms of Use: https://openai.com/policies/terms-of-use/ +## Why this is cheap -## Prerequisites - -- [Node.js](https://nodejs.org/) 18+ -- Optional for full AI mode: a [Claude Max subscription](https://claude.ai/) (or Claude Code/API access) -- Chrome (for voice features via Web Speech API) +- `interview-app/` runs locally on your machine +- Data stays in local files (`interview-app/data/`, `interview-app/apps.json`) +- GitHub Pages hosts `site/` for free +- Domain can be pointed with standard DNS records (no app hosting bill) ## Quick Start ```bash -# Clone the repo git clone https://github.com/obsecurus/yappybara.git cd yappybara - -# Install dependencies make interview-setup - -# Start the interview app -make interview - -# OR: zero-login demo mode (best for first-time kid sessions) make interview-demo ``` -Open the URL shown in your terminal (usually `http://localhost:3456`). Your kid can talk or type to Bart, draw sketches, and watch their app idea come to life. - -`make interview-demo` runs local practice mode and does not require Claude auth. It is ideal for quick setup and classrooms. - -### One-command Family Install - -```bash -# Install everything for local sessions -make yappybara-install - -# Optional: also install the Claude Code plugin from this repo -YAPPY_INSTALL_PLUGIN=1 make yappybara-install - -# Launch kid-safe mode -make yappybara-launch -``` - -### Assistant modes - -- `YAPPY_MODE=auto` (default): tries Claude first, then falls back to local practice mode if unavailable. -- `YAPPY_MODE=claude`: requires Claude; returns an error if Claude is unavailable. -- `YAPPY_MODE=demo`: local kid-safe mode only (no Claude required). - -### Billing modes (cost control) - -- `YAPPY_BILLING_MODE=subscription` (default): subscription-first mode. If `ANTHROPIC_API_KEY` is set, Yappybara ignores it to avoid accidental API charges. -- `YAPPY_BILLING_MODE=api`: usage-based API billing (requires `ANTHROPIC_API_KEY`). -- `YAPPY_BILLING_MODE=user_api`: parent BYOK mode. Server ignores its own API key and requires each family to provide their own key in-browser. -- `YAPPY_BILLING_MODE=auto`: uses API billing when a key is present, otherwise Claude login/subscription. - -### Claude Code Plugin - -This repo ships a plugin marketplace and plugin package: +Then open `http://localhost:3456`. -```bash -make yappybara-install-plugin -``` - -Manual commands: +For full Claude-backed mode: ```bash -claude plugins marketplaces add https://raw.githubusercontent.com/Obsecurus/yappybara/main/.claude-plugin/marketplace.json -claude plugins install yappybara-family-kit +make interview ``` -### Accessing from another device - -The server prints a LAN URL and QR code on startup. The app now auto-generates local HTTPS certs in dev mode when needed, so voice input can work from another device on the same network. - -
-HTTPS details (optional) +## Runtime modes -Voice input (microphone) requires HTTPS when accessing from another device. On startup, `interview-app/server.js` will try to generate `interview-app/certs/cert.pem` and `interview-app/certs/key.pem` automatically in non-production mode. +- `YAPPY_MODE=auto` (default): Claude first, fallback to local demo +- `YAPPY_MODE=claude`: require Claude +- `YAPPY_MODE=demo`: local-only demo mode -If you want to force HTTP for local testing, run with: +## Main commands ```bash -AUTO_GENERATE_CERTS=false make interview +make interview-setup # install interview-app dependencies +make interview # start full mode (Claude) +make interview-demo # start local-only mode +make interview-test # run interview-app tests ``` -Or disable HTTPS explicitly: +## GitHub Pages (`yappybara.dev`) -```bash -FORCE_HTTP=true make interview -``` -
- -## Website (GitHub Pages) - -This repo includes a cheap static website in `site/` for `https://yappybara.dev`. - -- `site/` is a browser-only \"Yappybara Lite\" interview demo. -- `interview-app/` is the full backend-powered experience (Claude integration + prototype builder). - -Deploy docs: `docs/github-pages.md` -Distribution docs: `docs/distribution.md` -Fly API rollout docs: `docs/fly-api-rollout.md` -Fly CI deploy workflow: `.github/workflows/fly-deploy.yml` -Fly config: `fly.toml` -Family launch docs: `docs/family-launch.md` -Deploy queue docs: `docs/deploy-queue.md` -Legal/supervision docs: `docs/legal-supervision.md` +The public site is in `site/` and deploys via `.github/workflows/pages.yml`. -Branding assets/docs: `assets/brand/` and `docs/branding.md` +Setup guide: +- `docs/github-pages.md` -## How the Interview Works +## Namecheap DNS automation -Bart follows a natural conversation flow: -- **What's the idea?** What problem does it solve? -- **Who's it for?** Friends, family, everyone? -- **Walk me through it** — What do you see when you open the app? -- **What's the vibe?** Colors, style, inspiration? -- **What makes it special?** Why would someone use this over alternatives? - -After a few minutes of chatting, Bart automatically triggers a build phase where Dash creates a working prototype. The kid gets to see their idea come to life in real time. - -## Parent/Mentor Tools - -While your kid is chatting with Bart, you can: +Use the existing script to configure apex + `www` for GitHub Pages: ```bash -# Send feedback without interrupting (e.g., "responses are too long") -make feedback MSG="too verbose" - -# Restart the server transparently -make restart - -# Resume from a previous session -make resume - -# View recent deploy requests from parents -make deploy-queue +node scripts/configure-namecheap-github-pages.mjs +node scripts/configure-namecheap-github-pages.mjs --apply ``` -There's also a structured interview script in `INTERVIEW.md` if you want to do an offline interview first and then feed the transcript to Claude. +Required secrets are documented in `.env.secrets.example`. -## Local Persistence + Deploy Queue +## Repository layout -- Project data is persisted in: - - `interview-app/apps.json` - - `interview-app/data/apps/*.json` (per-app local vault backup) -- Parent "Deploy Your App" requests are logged locally in: - - `interview-app/data/deploy-requests.jsonl` -- Deploy requests are intentionally queued for manual fulfillment (domain + Fly.io + payment confirmation). - -## Project Structure - -``` -interview-app/ # The voice interview + builder app - server.js # Express server + Claude Agent SDK - safety.js # Shared kid-safety sanitizers/filters - builder.js # "Dash" — builds HTML prototypes - mechanic.js # "Wrench" — auto-fixes bugs - public/index.html # Chat UI with speech + drawing - data/ # Local persistence vault + deploy queue - run.sh # Auto-restart wrapper -plugins/ # Claude Code plugin packages - yappybara-family-kit/ # Commands + skills for family sessions -.claude-plugin/ # Plugin marketplace manifest -CLAUDE.md # Project context for Claude Code -INTERVIEW.md # Offline interview script -Makefile # Dev commands -.claude/ # Local private Claude workflows (excluded from git) -.devcontainer/ # VS Code dev container (optional) -.github/workflows/ci.yml # CI pipeline for interview app checks/tests -.github/workflows/pages.yml # GitHub Pages deployment workflow -site/ # Static website for yappybara.dev -assets/brand/ # Logo files for GitHub/website branding +```text +interview-app/ # local app server + UI +site/ # static marketing/docs site for GitHub Pages +scripts/ # setup + DNS helper scripts +.github/workflows/ # CI + Pages deploy workflow +assets/brand/ # logo assets ``` -## The Capybara Crew - -| Character | Role | Personality | -|-----------|------|-------------| -| **Bart** | Interviewer | Goofy, enthusiastic hype-buddy. Asks about the idea, never about tech. | -| **Dash** | Builder | Hyperactive speedster with headphones. Builds prototypes fast. | -| **Wrench** | Mechanic | Calm fixer with goggles. Patches bugs when the kid hits "fix this!" | - -## Building the Actual App - -Once the interview captures the idea, you can build a real app in the Expo workspace: +## Tests ```bash -make setup # Create the Expo project (one-time) -make dev # Start development +cd interview-app +node --check server.js builder.js mechanic.js safety.js +AUTO_GENERATE_CERTS=false node --test test.js ``` -Private/internal Claude skill packs are intentionally kept out of this public repo. - -## Default Tech Stack - -| Layer | Tool | Cost | -|-------|------|------| -| App framework | Expo (React Native) | Free | -| Database + Auth | Supabase | Free tier | -| Web hosting | Vercel | Free tier | -| Phone builds | EAS Build | Free tier | - -**Total cost to launch: $0.** Works on iPhone, Android, and web from a single codebase. - -## Safety - -Yappybara is built for kids (ages 9-14): -- All AI responses are filtered for age-appropriate content -- External images are blocked in generated prototypes (emoji and CSS art only) -- Content Security Policy headers prevent loading external resources -- Demo mode runs locally with no model-provider calls -- Claude mode sends prompts/responses to Anthropic per their terms and policies - ## License MIT diff --git a/assets/brand/yappybara-lockup.svg b/assets/brand/yappybara-lockup.svg index 0ddade7..b6b3c39 100644 --- a/assets/brand/yappybara-lockup.svg +++ b/assets/brand/yappybara-lockup.svg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c7e4d32ad8e087bd8985b2e7d5f5d2411c807a82dd4fe5101895c35c72d686e -size 2095 +oid sha256:9a475b588bf3bca317f662d1630f4479e9e09418dd48f4012d5090597d727f71 +size 2092 diff --git a/docs/deploy-queue.md b/docs/deploy-queue.md deleted file mode 100644 index 6256e27..0000000 --- a/docs/deploy-queue.md +++ /dev/null @@ -1,35 +0,0 @@ -# Deploy Queue (Parent Requests) - -Yappybara captures deployment interest locally so families can request publishing from inside the app. - -## What happens in app - -1. Kid builds a prototype. -2. Parent clicks **Deploy Your App**. -3. Parent enters email, optional name, desired subdomain, and notes. -4. Request is saved locally and attached to that app record. - -## Stored files - -- Queue log: `interview-app/data/deploy-requests.jsonl` -- App metadata: `interview-app/apps.json` -- Per-app backup: `interview-app/data/apps/.json` - -## API endpoints - -- `POST /api/deploy-request` -- `GET /api/deploy-requests?limit=25` - -## Environment knobs - -- `YAPPY_DEPLOY_DOMAIN` (default: `yappybara.dev`) -- `YAPPY_DEPLOY_PRICE_USD` (default: `5`) -- `YAPPY_STORAGE_DIR` (set `/data` on Fly to persist queue/build artifacts) - -## Ops workflow (manual for now) - -1. Review queue with `make deploy-queue`. -2. Confirm payment and parent contact. -3. Set up subdomain and cert. -4. Deploy app artifact to Fly.io. -5. Mark request complete in your internal tracking. diff --git a/docs/distribution.md b/docs/distribution.md deleted file mode 100644 index d22fb2f..0000000 --- a/docs/distribution.md +++ /dev/null @@ -1,52 +0,0 @@ -# Distribution Plan (Low Friction + Monetizable) - -Goal: kids can play instantly, non-technical parents do not need local setup, and you can monetize publishing. - -## Recommended architecture - -1. GitHub Pages (`site/`) for discovery and lightweight browser demo. -2. Hosted Fly app (`interview-app/`) for full experience (`play.yappybara.dev` style URL). -3. Optional local launcher for power users (`make interview`, plugin flows). - -## Why this is the best fit - -- GitHub Pages is static-only and cannot run your Node API. -- Fly can run the full app + API and persist queue/build files via volumes. -- You can keep one low-cost shared runtime, then charge for “deploy my kid’s app” fulfillment. - -## Product tiers to ship - -### Tier 1: Instant demo (free) - -- URL: `https://yappybara.dev` -- Static demo only, no account friction. - -### Tier 2: Hosted builder (paid Claude usage behind your backend) - -- URL: `https://play.yappybara.dev` (Fly) -- Full interview/build flow via hosted API. -- Best for non-technical families. - -### Tier 3: Deploy request (parent upsell) - -- In-app button: `Deploy Your App`. -- Captures parent contact + requested domain. -- Queue processed by you (manual first, automated later). - -## Safety defaults - -- Parent supervision gate before interaction. -- Strict server/client sanitizers. -- One-tap panic + feedback. -- Regression tests for: - - profanity/slur filtering - - one-question/short-response constraints - - unsafe HTML stripping - -## Rollout - -1. Launch hosted Fly API/app first. -2. Keep plugin/installer as optional power-user paths. -3. Add payment + deploy automation once hosted traffic is stable. - -See: `docs/fly-api-rollout.md` diff --git a/docs/family-launch.md b/docs/family-launch.md deleted file mode 100644 index 818c26c..0000000 --- a/docs/family-launch.md +++ /dev/null @@ -1,52 +0,0 @@ -# Family Launch Guide - -This guide is the fastest path to get kids playing with Yappybara on a local network. - -Legal and supervision reference: `docs/legal-supervision.md` - -## 1) Install in one command - -```bash -make yappybara-install -``` - -Optional plugin install in same step: - -```bash -YAPPY_INSTALL_PLUGIN=1 make yappybara-install -``` - -## 2) Start a kid-safe session - -```bash -make yappybara-launch -``` - -This runs demo mode (no Claude login required) so first sessions start quickly. - -## 3) Switch to full Claude mode when ready - -```bash -make interview -``` - -Default billing behavior is subscription-first (`YAPPY_BILLING_MODE=subscription`), so accidental API-key charges are avoided unless explicitly enabled. - -## 4) Use the website as front door - -- Public link: `https://yappybara.dev` (GitHub Pages) -- Pages offers an instant lightweight demo -- Full voice + build experience stays local in `interview-app/` - -## 5) Publish app requests from parents - -After a prototype is built, parents can use **Deploy Your App** in the app tab. - -- Requests are stored locally in `interview-app/data/deploy-requests.jsonl` -- Review queue: - -```bash -make deploy-queue -``` - -- Fulfillment is currently manual: payment confirmation, subdomain setup, and Fly.io deploy. diff --git a/docs/fly-api-rollout.md b/docs/fly-api-rollout.md deleted file mode 100644 index 2a02314..0000000 --- a/docs/fly-api-rollout.md +++ /dev/null @@ -1,130 +0,0 @@ -# Fly.io API Rollout (Non-Technical Parent Friendly) - -This is the path to move Yappybara from local-only to a hosted service parents can use with one URL. - -## Target architecture - -1. `yappybara.dev` (GitHub Pages): marketing + lite demo. -2. `play.yappybara.dev` (Fly): full Yappybara web app + API from `interview-app/server.js`. -3. `api` and UI stay same origin on Fly, so no browser CORS complexity. -4. Persistent app state on Fly Volume via `YAPPY_STORAGE_DIR=/data`. - -## Why Fly works for this - -- Native app deployment and config (`fly deploy`, `fly.toml`): [Fly Launch](https://fly.io/docs/launch/), [App Config](https://fly.io/docs/reference/configuration/). -- Persistent storage with volumes: [Fly Volumes](https://fly.io/docs/volumes/overview/). -- Optional encrypted runtime secrets (only if you choose server-owned billing): [Fly Secrets](https://fly.io/docs/apps/secrets/). -- Custom subdomains + certs: [Fly Custom Domains](https://fly.io/docs/networking/custom-domain/). -- Pricing reference: [Fly Pricing](https://fly.io/docs/about/pricing/). - -## Repo artifacts added for hosting - -- `fly.toml` (repo root; used by Fly GitHub integration) -- `Dockerfile.fly` (repo root; builds `interview-app/`) -- `interview-app/Dockerfile` (subdir deploy option) -- `interview-app/fly.toml.example` (reference config) -- `interview-app/.dockerignore` -- `YAPPY_STORAGE_DIR` support in `interview-app/server.js` - -## Day-1 hosted deploy - -Create app + volume (example region `ord`): - -```bash -fly apps create yappybara-api -fly volumes create yappybara_data --region ord --size 3 -``` - -Set required runtime env: - -```bash -fly secrets set YAPPY_MODE=claude \ - YAPPY_BILLING_MODE=user_api \ - YAPPY_DEPLOY_DOMAIN=yappybara.dev \ - YAPPY_DEPLOY_PRICE_USD=9 -``` - -Deploy: - -```bash -fly deploy --config fly.toml -``` - -Smoke test: - -```bash -curl -s https://yappybara-api.fly.dev/api/health -``` - -## GitHub auto-deploy - -This repo includes `.github/workflows/fly-deploy.yml`. - -On every push to `main` that touches `interview-app/`, GitHub Actions runs: - -```bash -flyctl deploy --remote-only --config fly.toml -``` - -Configure in GitHub: - -1. Add repository secret `FLY_API_TOKEN`. -2. Optional: add repository variable `FLY_APP_NAME` if app name is not `yappybara-api`. -3. Ensure Fly app + volume already exist before first workflow run. - -## Domain wiring - -1. Keep root/apex (`yappybara.dev`) on GitHub Pages. -2. Add a new subdomain for full app (`play.yappybara.dev`) pointing to Fly. -3. Run `fly certs add play.yappybara.dev`. -4. Update `site/` CTA buttons to send parents to `https://play.yappybara.dev`. - -## Monetization path (deploy-your-app fee) - -Start simple, then automate: - -### Phase A: Manual charge + manual deploy (fastest launch) - -1. Parent submits `Deploy Your App`. -2. You invoice manually or send payment link. -3. After payment, you provision domain + deploy artifact. - -### Phase B: Payment-gated queue - -1. Add checkout flow (Stripe Payment Links or Checkout): [Stripe Payment Links](https://docs.stripe.com/payment-links). -2. Store payment status on request (`pending` -> `paid`) via webhook: [Stripe Webhooks](https://docs.stripe.com/webhooks). -3. Only allow fulfillment when status is `paid`. - -### Phase C: Automated fulfillment worker - -1. Worker polls paid requests. -2. Publishes app artifact. -3. Configures DNS/cert and marks request `live`. -4. Sends parent completion email. - -## Suggested pricing model - -Use a simple margin formula per deployment: - -`price = fly_runtime_cost + model_cost + domain/dns_ops + support_buffer + margin` - -Practical launch strategy: - -1. Start with a fixed one-time deployment fee (`$9-$19`). -2. Track real per-deploy costs for 2-4 weeks. -3. Adjust price once your real margin is known. - -## Operational guardrails - -1. Keep one shared Fly app at first; do not create one Fly app per child yet. -2. Persist all queue/build data to `/data` volume. -3. Add rate limiting before public launch. -4. Keep parent-supervision disclaimers visible in hosted UI. -5. For `YAPPY_BILLING_MODE=user_api`, do not set a server Anthropic key; each family supplies their own key in browser. - -## Next technical increments - -1. Add `POST /api/deploy-request/:id/mark-paid` (admin-auth protected). -2. Add an internal worker script for paid-request processing. -3. Add request status timeline fields (`requested`, `paid`, `provisioning`, `live`, `failed`). -4. Add email notification hooks (request received / app live). diff --git a/docs/github-pages.md b/docs/github-pages.md index 805a196..8790dd6 100644 --- a/docs/github-pages.md +++ b/docs/github-pages.md @@ -1,23 +1,32 @@ -# GitHub Pages + yappybara.dev +# GitHub Pages + `yappybara.dev` -This repo now includes a static site in `site/` that can be deployed with GitHub Pages at near-zero cost. +This repo ships a static website from `site/` and deploys it with GitHub Actions. -## 1) Deploy the Pages site +Goal: free public landing page, no backend hosting bill. -1. Push `main` with `site/` and `.github/workflows/pages.yml`. -2. In GitHub: `Settings -> Pages`, set source to **GitHub Actions**. -3. Wait for the "Deploy GitHub Pages" workflow to finish. +## 1) Enable GitHub Pages (Actions) -## 2) Set the custom domain +In GitHub: +1. Open `Settings -> Pages` +2. Set **Build and deployment** source to **GitHub Actions** -1. In `Settings -> Pages`, enter `yappybara.dev` as the custom domain. -2. Ensure HTTPS is enabled (GitHub usually enables this after DNS propagates). +The workflow `.github/workflows/pages.yml` deploys on pushes to `main` that touch `site/**`. -`site/CNAME` already contains `yappybara.dev`. +## 2) Custom domain -## 3) DNS records in Namecheap +`site/CNAME` is already set to: -For apex + `www`, use: +```text +yappybara.dev +``` + +After Pages is enabled: +1. In `Settings -> Pages`, set custom domain to `yappybara.dev` +2. Enable HTTPS once DNS has propagated + +## 3) Namecheap DNS records + +For GitHub Pages custom domain support: - `@ A 185.199.108.153` - `@ A 185.199.109.153` @@ -25,20 +34,21 @@ For apex + `www`, use: - `@ A 185.199.111.153` - `www CNAME obsecurus.github.io` -These values come from GitHub's custom domain guidance for Pages. +## 4) DNS automation script -## 4) Optional automation via Namecheap API - -You can update DNS from this repo with: +Dry run: ```bash node scripts/configure-namecheap-github-pages.mjs -node scripts/configure-namecheap-github-pages.mjs --apply ``` -The script reads `.env.secrets` and preserves unrelated existing DNS records while replacing only `@` and `www`. +Apply: + +```bash +node scripts/configure-namecheap-github-pages.mjs --apply +``` -### Required `.env.secrets` variables +Required `.env.secrets` values: - `NAMECHEAP_API_KEY` - `NAMECHEAP_API_USER` @@ -46,6 +56,17 @@ The script reads `.env.secrets` and preserves unrelated existing DNS records whi - `NAMECHEAP_CLIENT_IP` - `NAMECHEAP_DOMAIN` (defaults to `yappybara.dev`) -Notes: -- Namecheap API requires your client IP to be whitelisted in Namecheap API settings. -- If your key in `.env.secrets` has smart quotes, the script strips them automatically. +Optional: + +- `GITHUB_PAGES_USER` (defaults to `obsecurus`) +- `GITHUB_PAGES_CNAME_TARGET` (defaults to `${GITHUB_PAGES_USER}.github.io`) + +## 5) Verify + +- Pages URL: `https://obsecurus.github.io/yappybara/` +- Custom domain: `https://yappybara.dev` + +If custom domain is still pending: +- verify DNS records, +- verify Namecheap API whitelist for `NAMECHEAP_CLIENT_IP`, +- wait for DNS propagation. diff --git a/fly.toml b/fly.toml deleted file mode 100644 index e781625..0000000 --- a/fly.toml +++ /dev/null @@ -1,39 +0,0 @@ -app = "yappybara" -primary_region = "ord" - -[build] - dockerfile = "Dockerfile.fly" - -[env] - PORT = "8080" - YAPPY_MODE = "claude" - YAPPY_BILLING_MODE = "user_api" - YAPPY_STORAGE_DIR = "/data" - YAPPY_DEPLOY_DOMAIN = "yappybara.dev" - YAPPY_DEPLOY_PRICE_USD = "9" - FORCE_HTTP = "true" - AUTO_GENERATE_CERTS = "false" - -[http_service] - internal_port = 8080 - force_https = true - auto_start_machines = true - auto_stop_machines = true - min_machines_running = 0 - processes = ["app"] - - [[http_service.checks]] - interval = "15s" - timeout = "5s" - grace_period = "20s" - method = "GET" - path = "/api/health" - -[[vm]] - memory = "1gb" - cpu_kind = "shared" - cpus = 1 - -[[mounts]] - source = "yappybara_data" - destination = "/data" diff --git a/interview-app/.env.example b/interview-app/.env.example index 51f8a49..a5b4941 100644 --- a/interview-app/.env.example +++ b/interview-app/.env.example @@ -1,4 +1,4 @@ -# Minimal env for hosted API mode (Fly.io) +# Optional env for hosted API mode PORT=8080 YAPPY_MODE=claude YAPPY_BILLING_MODE=user_api diff --git a/interview-app/fly.toml.example b/interview-app/fly.toml.example deleted file mode 100644 index 1031cd8..0000000 --- a/interview-app/fly.toml.example +++ /dev/null @@ -1,39 +0,0 @@ -app = "yappybara-api" -primary_region = "ord" - -[build] - dockerfile = "Dockerfile" - -[env] - PORT = "8080" - YAPPY_MODE = "claude" - YAPPY_BILLING_MODE = "user_api" - YAPPY_STORAGE_DIR = "/data" - YAPPY_DEPLOY_DOMAIN = "yappybara.dev" - YAPPY_DEPLOY_PRICE_USD = "9" - FORCE_HTTP = "true" - AUTO_GENERATE_CERTS = "false" - -[http_service] - internal_port = 8080 - force_https = true - auto_start_machines = true - auto_stop_machines = true - min_machines_running = 0 - processes = ["app"] - - [[http_service.checks]] - interval = "15s" - timeout = "5s" - grace_period = "20s" - method = "GET" - path = "/api/health" - -[[vm]] - memory = "1gb" - cpu_kind = "shared" - cpus = 1 - -[[mounts]] - source = "yappybara_data" - destination = "/data" diff --git a/interview-app/public/index.html b/interview-app/public/index.html index 5f6c6ca..444d517 100644 --- a/interview-app/public/index.html +++ b/interview-app/public/index.html @@ -2168,7 +2168,7 @@

Scan to Connect