✳
KAF World Apps · System blueprint

Free models.
Native apps.
Everything in one blueprint.

The full software delivery record for Petrable — prompt-to-app builder for iOS + macOS — from discovery through architecture, integration testing and release: diagrams, workflows, tech stack and every troubleshooting case file, contained in this page.

UI suite 6 / 6 green Providers 7 keyed Deploy focused-panther-579 iOS installed on FlyPhone17 macOS Petrable.app shipped Policy free-only · no paid fallback
01Technology stack

The pieces, named plainly

Every layer is free-tier or owned infrastructure. Secrets live server-side only — the apps ship zero keys.

Client

SwiftUI · iOS 17+ / macOS

Targets Forge (iPhone) & KeithableMac → ships as Petrable. xcodegen project.yml is the project source of truth.

Backend

Convex (TypeScript)

Functions: projects · messages · builder · voice · models · freeAi router · system. Dev deployment focused-panther-579.

Inference

7 free providers

Gemini → Groq → NVIDIA → GitHub → OpenRouter → Cerebras → Cloudflare. Tiered fast / balanced / smart.

Web runtime

Daytona sandboxes

Managed API + per-sandbox toolbox proxy for exec/upload; preview URLs on daytonaproxy01.

iOS runtime

Mac Worker + Chorus

Local Xcode compiles → unsigned IPA / device install path; cloud builds repair compile errors.

Voice

Groq Whisper

Mic → text transcription server-side (free). No paid STT; OpenAI path removed with its dead key.

Quality

XCTest UI suite

6 end-to-end tests incl. prompt → live preview; evidence as xcresult bundles.

Signing

Apple team V892V3PC6T

Dev certs in keychain; automatic signing; Wi-Fi install over paired device FlyPhone17.

Docs

Markdown set + this hub

Blueprint · AGENTS runbook · Free-providers board · README — linked at the foot of this page.


02Full SDLC · discovery → release

How the project was delivered

1
Discovery

Free-only mandate; strip OpenAI/Anthropic; keep Daytona + Mac worker; product renamed Petrable; brand family identified.

2
Design

Tier router with ordered fallback chain; keys in Convex env only; any single key keeps the product alive.

3
Architecture

HLD/LLD (below); provider contract pinned by live probes; Daytona proxy contract reverse-engineered from vendor SDK.

4
Implementation

freeAi.ts · builder.ts · voice.ts · rename sweep · de-branding sweep · provider keys.

5
SIT

Each seam proven live: app⇄Convex, Convex⇄7 providers, Convex⇄Daytona to status: live, voice⇄Groq, signing⇄devices.

6
Test & Q&A

6/6 UI suite (E2E demo ~70 s); flake forensics protocol; owner screenshots traced to stale sources.

7
Release

macOS shipped to /Applications; iOS installed over Wi-Fi; push / TestFlight remain owner decisions.

Workflow · dev loop
edit → xcodegen generate        # project.yml is truth
     → xcodebuild test|build   # ARCHS=arm64, no sim signing
     → xcresulttool forensics  # exact failure text
     → convex dev --once       # push backend (dev!)
     → live provider smoke     # status-code matrix
Workflow · incident
symptom → evidence ladder
  1 xcresult summary/tests
  2 UI hierarchy at failure
  3 screenshots around window
  4 reproduce ×3 (flake vs break)
→ root cause → fix code, never the assertion

03HLD · high-level design

Topology at a glance

CLIENTS iPhone · SwiftUI Petrable.app · iOS 17+ prompt · mic · preview Mac · SwiftUI Petrable.app (shipped) + Xcode dev loop BACKEND · CONVEX focused-panther-579 (dev) projects · messages · files builder.build / buildMobile queued→…→live state machine freeAi ★ tier router fast · balanced · smart chains voice.transcribe (Groq Whisper) models → FreeTier mapping env keys — only secret store AppConfig.swift hardcodes this URL FREE MODEL PROVIDERS ordered fallback chain — keys drop out if absent 1 Gemini · 2 Groq · 3 NVIDIA 4 GitHub · 5 OpenRouter 6 Cerebras · 7 Cloudflare 401/403/404/429 → next provider 300s timeout → surfaced at once every model ID live-verified see FREE_PROVIDERS.md for the board DAYTONA mgmt API + toolbox proxy {proxy}/{sandboxId}/process/execute files/upload-v2 · preview-url MAC WORKER polls jobs → Xcode → IPA local Mac, outbound only HTTPS Bearer chat REST poll
HLD — clients → Convex → free providers · sandboxes · worker. Trust boundary: all keys server-side.

04LLD · low-level design

Two state machines carry the product

4.1 · The free-model router

TIER IN 1 Gemini 2 Groq 3 NVIDIA 4 GitHub 5 OpenRouter 6 Cerebras 7 Cloudflare on 429 rate-limit · 404 retired-model · 401/403 bad key · budget-400 → try NEXT provider success → return text (empty counts as failure) all seven failed → "Every free model provider failed — name: reason · …" surfaced to the app
LLD — freeAi chain: ordered attempts, classified failures, single graceful error.

4.2 · Build pipeline (builder.build)

queued generating sandbox uploading starting live callFreeModel POST /sandbox proxy mkdir + upload-v2 ×N exec http.server :3000 ×5 preview-url ✓ error · "Build failed" + message row: status · previewUrl version++ · clearError any throw → status=error (surfaced in-app with the exact provider/Daytona message)
LLD — web build states; the app’s status chip is this machine’s current node.

4.3 · Provider contract (verified)

ProviderEnv keySmartBalancedFast
GeminiGEMINI_API_KEYgemini-3.8-flash
GroqGROQ_API_KEYopenai/gpt-oss-120bopenai/gpt-oss-20b
NVIDIANVIDIA_API_KEYnemotron-3-ultra-550bnemotron-3.5-lightning-30b
GitHubGITHUB_API_KEYdeepseek/DeepSeek-V3openai/gpt-4o-mini
OpenRouterOPENROUTER_API_KEYqwen/qwen3.8-27b:freenemotron-3.5-lightning:free
CerebrasCEREBRAS_API_KEYqwen-3.8-27b (env-pinned, £5 PayGo)
CloudflareCLOUDFLARE_API_KEY + _ACCOUNT_IDgpt-oss-120bdeepseek-r1-distill-32bllama-3.1-8b-fp8

Menu keys → tiers: free-smart · free-balanced · free-fast · fable-5 (smart). Default: free-balanced. Env override pattern: <PROVIDER>_<TIER>_MODEL.


05Workflows

How work actually moves

End-user build
type prompt (+ optional mic → Groq STT)
 → projects.create {prompt, platform}
 → schedule builder.build
 → freeAi chain serves generation
 → files saved → Daytona sandbox
 → upload → server → preview probe
 → status=live → previewButton appears
 → tap → webview renders (asserted by ForgeDemoTest)
Model incident (live)
provider 404/429 reported?
 → fetch provider /models catalogue
 → status-code matrix: tiny request × candidate
 → pin survivors in code + env
 → convex dev --once
 → re-run matrix after any provider incident
(never trust remembered model IDs)
Secret handling
set:  npx convex env set NAME "$(security \
        find-generic-password -s svc -w)"
list: env list | cut -d= -f1     # names only
leak? → rotate that provider key immediately
rules: no secrets in output/docs/chat echoes
Device install (Wi-Fi)
xcodebuild … -destination id=<udid> \
  DEVELOPMENT_TEAM=V892V3PC6T -allowProvisioningUpdates
 → devicectl device install app   # paired over Wi-Fi
 → locked screen blocks auto-launch (iOS policy)
 → launch after unlock, or tap the icon

06Platform inventory

IDs, commands, locations

ThingValue
Repo…/06_PROJECTS_AND_DEMOS/01_Rilable_Project/rilable (microSD) · GitHub rbrown101010/rilable (last push 2026-06-11)
BackendConvex dev focused-panther-579 (hardcoded in AppConfig.swift) · idle prod focused-mule-635
SigningTeam V892V3PC6T · Apple Development/ Distribution certs (Keith Fleishman)
DeviceFlyPhone17 iPhone 17 Pro — udid 2B1E2C82-73B2-5349-9640-118A61B8B5BA · sim 2F897A22-…
Keychainservices codex-{groq,nvidia,openrouter}-api-key — pipe, never print
Brand tokens…/00_Keith_Outputs/Gradus Apply/2026-09-24 Today KAF palette/
Test evidenceios/build/run14-allsuite.xcresult (6/6)
Storage order5 TB UUID C09342A1-… ≥500 GiB reserve · microSD = working vol · internal = apps only
# backend push (NON-interactive → dev deployment)
cd backend && npx tsc --noEmit -p convex/tsconfig.json && npx convex dev --once

# full test suite (sim)
xcodebuild test -project ios/Forge.xcodeproj -scheme Forge \
  -destination 'id=2F897A22-E49D-4C25-A0C4-F9E15B99E20A' \
  -derivedDataPath ios/build/build-x -resultBundlePath ios/build/runN.xcresult \
  ARCHS=arm64 CODE_SIGNING_ALLOWED=NO

07Troubleshooting playbook · case files

What broke, how we knew, what fixed it

1 · UI test failed with no useful message
SymptomXCTAssertTrue failed only.
MethodEvidence ladder: xcresult summary/tests → UI hierarchy → screenshots around window → reproduce ×3.
OutcomeFlaky timing test isolated to a sleep-vs-appearance race; fixed waits, 3/3 green. Never weaken assertions.
2 · App showed “Claude is designing your app” (string not in source)
SymptomStatus text absent from every repo file.
MethodThree-homes audit: client build ⇄ deployed backend ⇄ stored row. Grepped source, then all 23 DB rows.
OutcomeStale deployment/build — not code. Fresh builds said “Free AI is designing your app”. Always date the screenshot first.
3 · Every model suddenly 404
SymptomGemini 2.5 retired · Groq llama retired · OpenRouter :free slugs removed.
MethodFetch live catalogues; run a status-code matrix (tiny request per candidate); pin survivors; keep the chain.
OutcomeModel IDs are config, not constants — drift degrades to the next provider instead of an outage.
4 · Daytona404 “Cannot POST” (blocked every build)
SymptomOwner’s original screenshot: dead execute route — independent of model keys.
MethodVendor OpenAPI → discovered toolbox-proxy-url; llms.txt for map; npm pack the official SDK and grep basePath/auth.
OutcomeNew contract {proxy}/{sandboxId}/process/execute + Bearer → builds reached status: live. SDK source > blog posts.
5 · Secrets printed by an unfiltered env list
SymptomSix key values landed in tool output.
MethodImmediately rotated the non-owner-pasted keys (GitHub/Daytona/NVIDIA); new rule: env list | cut -d= -f1.
OutcomeHygiene baked into docs; keychain piping pattern documented.
6 · Volume degraded to multi-second reads
SymptomBuilds starved; processes in UN state; root ls hung >45 s.
MethodLatency matrix per volume (1ms / 9ms / 1–27s) → root readdir vs deep stat probe → found a pathological entry → ruled out Spotlight/Time Machine → bounded live fsck (clean).
OutcomePhysical-layer fault (cable/port) — stopped bulk jobs, continued read-only per storage standing order, reported with evidence.
7 · Convex deploy went to the wrong deployment
Symptomconvex deploy targeted prod and refused non-interactive prompting.
MethodRead CLI help; confirmed configured deployment; used convex dev --once for dev pushes.
OutcomeRule recorded: env commands default to dev, deploy defaults to prod — always confirm target.
8 · Howler stack-overflow spam (web preview)
Symptom148× RangeError: Maximum call stack from audio queue after registering sounds at boot.
MethodA/B control: disable one feature (barks) → 0 spam; enable → 148. Isolate registration timing vs audio unlock.
OutcomeRegister sounds only after audio.initiated (same as ambients) → 0 spam, playback verified.

08Testing strategy · definition of done

Green means proven

Layer 1

Static

tsc --noEmit · node --check · xcodebuild -list (xcodegen parse).

Layer 2

SIT seams

Live provider matrix · Daytona smoke to status: live + preview fetch · voice present in Groq’s catalogue · signing verify.

Layer 3

E2E

ForgeDemoTest: prompt → free generate → sandbox → live → webview. Red ≈ 490 s, green ≈ 70 s.

TestProvesState
ForgeDemoTest/testBuildAppFromPromptwhole product loop on free modelsPASS (66–93 s)
VoiceModelSpotTest/testModelMenuAndMicmodel menu + mic (STT) surfacePASS
VoiceModelSpotTest/testHomePlusMenuShowsActionshome composer menuPASS
ForgeTourTest/testTourLiveProjecttour over a live projectPASS
ForgeTourTest/testToolConnectionsSheettool connections sheetPASS
MobileSpotTest/testMobileProjectmobile project flowPASS

09Status & handoff

Done, in flight, your calls

Finished ✓

  • 7-provider free router live & verified
  • Daytona pipeline → real live previews
  • 6/6 test suite green
  • Petrable rename + Claude sweep
  • macOS shipped; iPhone installed (Wi-Fi)
  • Keys rotated/set; docs complete (this hub)

In flight 🔨

  • Brand retheme (KAF/Relo/Sermo tokens)
  • Rebuild + reinstall both platforms
  • Repeat stability runs

Needs you 🎯

  • “push it” → GitHub commit + links
  • TestFlight → bundle-id choice
  • Text-to-speech (voice out) → say yes/no
  • “V” voice company → Vapi or Voiceflow?

Handoff-ready by design: any model or developer can start at AGENTS.md, understand this page, run the suite to know if they broke something, and take §9 items as the precise backlog. The blueprint markdown carries the full prose version of everything above.


10Golden rules

Pin these above the desk

1 — Free-only. Forever.

No paid fallback. One key works; zero keys drops the provider, never the product.

2 — Evidence before edits

xcresult → hierarchy → screenshots → reproduce ×3. Fix root causes, never assertions.

3 — Live probes over memory

Third-party routes, model IDs, quotas: verify with real requests before trusting them.

4 — Secrets never in output

Names-only listings; keychain piping; rotate the moment anything leaks.

5 — project.yml is truth

Hand-edited pbxproj vanishes on the next xcodegen run — edit the yml.

6 — Names matter

Petrable to the world; match the KAF family voice, brand tokens and care in presentation.