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.
Every layer is free-tier or owned infrastructure. Secrets live server-side only — the apps ship zero keys.
Targets Forge (iPhone) & KeithableMac → ships as Petrable. xcodegen project.yml is the project source of truth.
Functions: projects · messages · builder · voice · models · freeAi router · system. Dev deployment focused-panther-579.
Gemini → Groq → NVIDIA → GitHub → OpenRouter → Cerebras → Cloudflare. Tiered fast / balanced / smart.
Managed API + per-sandbox toolbox proxy for exec/upload; preview URLs on daytonaproxy01.
Local Xcode compiles → unsigned IPA / device install path; cloud builds repair compile errors.
Mic → text transcription server-side (free). No paid STT; OpenAI path removed with its dead key.
6 end-to-end tests incl. prompt → live preview; evidence as xcresult bundles.
Dev certs in keychain; automatic signing; Wi-Fi install over paired device FlyPhone17.
Blueprint · AGENTS runbook · Free-providers board · README — linked at the foot of this page.
Free-only mandate; strip OpenAI/Anthropic; keep Daytona + Mac worker; product renamed Petrable; brand family identified.
Tier router with ordered fallback chain; keys in Convex env only; any single key keeps the product alive.
HLD/LLD (below); provider contract pinned by live probes; Daytona proxy contract reverse-engineered from vendor SDK.
freeAi.ts · builder.ts · voice.ts · rename sweep · de-branding sweep · provider keys.
Each seam proven live: app⇄Convex, Convex⇄7 providers, Convex⇄Daytona to status: live, voice⇄Groq, signing⇄devices.
6/6 UI suite (E2E demo ~70 s); flake forensics protocol; owner screenshots traced to stale sources.
macOS shipped to /Applications; iOS installed over Wi-Fi; push / TestFlight remain owner decisions.
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 matrixsymptom → 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| Provider | Env key | Smart | Balanced | Fast |
|---|---|---|---|---|
| Gemini | GEMINI_API_KEY | gemini-3.8-flash | ||
| Groq | GROQ_API_KEY | openai/gpt-oss-120b | openai/gpt-oss-20b | |
| NVIDIA | NVIDIA_API_KEY | nemotron-3-ultra-550b | nemotron-3.5-lightning-30b | |
| GitHub | GITHUB_API_KEY | deepseek/DeepSeek-V3 | openai/gpt-4o-mini | |
| OpenRouter | OPENROUTER_API_KEY | qwen/qwen3.8-27b:free | nemotron-3.5-lightning:free | |
| Cerebras | CEREBRAS_API_KEY | qwen-3.8-27b (env-pinned, £5 PayGo) | ||
| Cloudflare | CLOUDFLARE_API_KEY + _ACCOUNT_ID | gpt-oss-120b | deepseek-r1-distill-32b | llama-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.
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)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)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 echoesxcodebuild … -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| Thing | Value |
|---|---|
| Repo | …/06_PROJECTS_AND_DEMOS/01_Rilable_Project/rilable (microSD) · GitHub rbrown101010/rilable (last push 2026-06-11) |
| Backend | Convex dev focused-panther-579 (hardcoded in AppConfig.swift) · idle prod focused-mule-635 |
| Signing | Team V892V3PC6T · Apple Development/ Distribution certs (Keith Fleishman) |
| Device | FlyPhone17 iPhone 17 Pro — udid 2B1E2C82-73B2-5349-9640-118A61B8B5BA · sim 2F897A22-… |
| Keychain | services codex-{groq,nvidia,openrouter}-api-key — pipe, never print |
| Brand tokens | …/00_Keith_Outputs/Gradus Apply/2026-09-24 Today KAF palette/ |
| Test evidence | ios/build/run14-allsuite.xcresult (6/6) |
| Storage order | 5 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
XCTAssertTrue failed only.npm pack the official SDK and grep basePath/auth.{proxy}/{sandboxId}/process/execute + Bearer → builds reached status: live. SDK source > blog posts.env list | cut -d= -f1.ls hung >45 s.convex deploy targeted prod and refused non-interactive prompting.convex dev --once for dev pushes.RangeError: Maximum call stack from audio queue after registering sounds at boot.audio.initiated (same as ambients) → 0 spam, playback verified.tsc --noEmit · node --check · xcodebuild -list (xcodegen parse).
Live provider matrix · Daytona smoke to status: live + preview fetch · voice present in Groq’s catalogue · signing verify.
ForgeDemoTest: prompt → free generate → sandbox → live → webview. Red ≈ 490 s, green ≈ 70 s.
| Test | Proves | State |
|---|---|---|
| ForgeDemoTest/testBuildAppFromPrompt | whole product loop on free models | PASS (66–93 s) |
| VoiceModelSpotTest/testModelMenuAndMic | model menu + mic (STT) surface | PASS |
| VoiceModelSpotTest/testHomePlusMenuShowsActions | home composer menu | PASS |
| ForgeTourTest/testTourLiveProject | tour over a live project | PASS |
| ForgeTourTest/testToolConnectionsSheet | tool connections sheet | PASS |
| MobileSpotTest/testMobileProject | mobile project flow | PASS |
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.
No paid fallback. One key works; zero keys drops the provider, never the product.
xcresult → hierarchy → screenshots → reproduce ×3. Fix root causes, never assertions.
Third-party routes, model IDs, quotas: verify with real requests before trusting them.
Names-only listings; keychain piping; rotate the moment anything leaks.
Hand-edited pbxproj vanishes on the next xcodegen run — edit the yml.
Petrable to the world; match the KAF family voice, brand tokens and care in presentation.