Build a First Draft app locally
Internal alpha · macOS
Describe an app in Claude Code, review its Foundation Plan, compile it into a local folder, and run it on your Mac. Then build its iPhone and Android clients locally. Preview Android in Android Studio's local Emulator, and preview iPhone in Revyl through a Cloudflare Tunnel. First Draft's service generates and verifies the source. Your computer runs the resulting application.
Start in an empty folder. You do not need to clone Drawing Board, create a Codespace, or create a GitHub repository. Drawing Board's current setup targets Codespaces. Local Git history is useful for checkpoints; the development loop below also builds uncommitted edits.
1. Install the tools for the steps you want
The complete iPhone-and-Android path uses a Mac because local iOS builds require Xcode.
| Tool or account | What it is for |
|---|---|
| Node.js 22 or newer and npm | Install and run First Draft. |
| Claude Code and a signed-in account | Describe the app and use the Skill. |
| First Draft pilot access and an API token | Send the Plan to the compilation service. |
| Git | Save local checkpoints; GitHub publication is optional. |
| Ruby, Bundler, Node, and PostgreSQL | Run the generated Rails app; follow its generated version files. |
| Xcode with iOS Simulator support | Build the iPhone Simulator application. |
| Android Studio / Android SDK | Build Android and run its Emulator; install SDK 36 and build-tools 36.0.0. |
| JDK 17 | Build the Android APK from the command line for Revyl. |
| cloudflared | Give Revyl an HTTPS address for local Rails. |
| Revyl CLI and a Revyl account | Upload local builds and run hosted preview devices. |
Use a Ruby/Node version manager rather than macOS's system Ruby. If your version manager normally gets its selection
from a repository file, select Node before starting in the empty folder. Once the app exists, its .ruby-version
and .node-version tell you what to install. Keep PostgreSQL running while you use the app.
You can begin planning before installing Xcode or Android Studio. Install those before the native build steps. Simulator and Emulator previews do not install the application on a physical phone.
2. Install the Skill and CLI
In Terminal:
npm install --global @firstdraft.com/cli@latest @firstdraft.com/claude-code@latest
firstdraft --version
Installing @latest selects the current release. The
npm package page lists published versions. Public installation
requires no npm account or npm login.
If global installation reports a permissions error, fix your Node installation's user-owned package location;
do not run the installation with sudo.
This guide loads the npm plugin directly with Claude's supported
--plugin-dir option. The public marketplace is
another installation option; the command below loads the npm-installed plugin directly. The plugin includes a
compatible CLI; Claude should use its helper rather than an older firstdraft executable elsewhere on your computer.
3. Create the app folder and connect to First Draft
mkdir -p ~/code/reading-list
cd ~/code/reading-list
Choose a new folder, outside another Git repository. Keep the installed plugin outside this folder: Compilation will turn this folder into the Rails application.
Sign in at First Draft using the shared pilot credentials and your GitHub account, open API tokens, and create a token. Ask the First Draft operator for the pilot credentials if you do not have them. Production accounts and tokens are separate from staging.
In the same Terminal, enter the token at a hidden prompt. This works in macOS's default zsh and in Bash:
unset FIRSTDRAFT_API_URL
printf 'First Draft API token: '
read -r -s FIRSTDRAFT_API_TOKEN
printf '\n'
export FIRSTDRAFT_API_TOKEN
Paste only at that prompt, then press Return. Do not put the token in chat, a screenshot, a command's text, or Git. It stays in this shell and its child processes. A new Terminal needs the connection configured again. Claude's account login and First Draft's API token serve different services. The CLI defaults to production; unsetting the URL removes an override left by an earlier staging trial. A folder already pushed to staging remains pinned there. Start this production trial in a new folder.
For operator testing, supply a staging token through FIRSTDRAFT_STAGING_API_TOKEN and use
firstdraft --staging plan push or firstdraft --staging plan compile. The CLI does not use the production
token for staging. Tell the Skill explicitly when the app should use staging.
4. Start Claude and describe a small app
From that same folder and Terminal:
claude --plugin-dir "$(npm root --global)/@firstdraft.com/claude-code"
Complete Claude's sign-in if prompted. Keep one conversation through planning, Compilation, and the first run. For example:
/firstdraft:create-full-stack-app
Build a Reading List. Each book has a required title and author, an optional note, and a finished checkbox that starts unchecked. Let anyone list, view, add, edit, and delete books. Include three sample books. Generate both iPhone and Android clients using Hotwire Native. This is a public demonstration with disposable data and no accounts. Use First Draft's service, put the compiled app in this local folder, and run it locally. Show me the Plan, warnings, and support gaps before compiling. Do not publish to GitHub or deploy.
If you have a sketch or prototype, give Claude its files and describe the intended screens. The Plan captures structured behavior; reproducing the prototype's visual design is a later coding task.
Ask Claude to preserve decisions that the Plan cannot express in implementation-notes.md. Requested clients and
other structured features should remain in the Plan even when the service reports a support gap.
Using Codex instead
The same plugin also installs in Codex. Install it as the
Skills README describes. Configure the token as in step 3, then
start Codex CLI from this folder in that Terminal; the desktop app may not inherit Terminal exports. Make the same
request with $firstdraft:create-full-stack-app. The rest of this guide applies with Codex in place of Claude. This
local walkthrough has been exercised with Claude Code; a fresh Codex run of it has not been recorded yet.
5. Review the Plan and compile into this folder
Claude submits .firstdraft/foundation-plan.json for analysis. Review the app's records, actions, access rules,
sample data, and selected clients. Read the actual warnings and complete support gaps. A valid Plan can still
contain features the Compiler leaves unfinished.
When the result matches your intent, tell Claude:
I approve this Plan and the gaps you showed me. Compile with
--output .into this folder. Preserve the planning material under.firstdraft/design/. Then inspect the generated baseline and help me run it locally. Do not create a GitHub repository or deploy.
The command for this local path is:
firstdraft plan compile --output .
Claude uses the installed Skill's CLI helper for that command. Local root output is the default: plan compile
writes into the current folder, and GitHub publication requires plan compile --github. The explicit --output .
spelling makes the destination clear. The installed Skill supplies the schema compatible with its bundled CLI;
use that schema when authoring a Plan. Older Plans are not migrated.
After success:
app/ config/ db/ spec/ bin/ Rails application
ios/ Selected iPhone project
android/ Selected Android project
.firstdraft/submitted-foundation-plan.json
.firstdraft/gaps.json
.firstdraft/design/ Original planning folder and implementation notes
Continue ordinary development from this root. Later First Draft planning commands run from .firstdraft/design/.
If a command reports an uncertain remote outcome, retain the files and have Claude inspect the retained status;
do not repeatedly start Compilation.
6. Save the baseline and boot Rails
Ask Claude to initialize local Git if needed, inspect the files selected for the first commit, and commit the generated baseline. Keep API tokens, private CLI state, and local environment files out of Git. No remote repository is needed. You can build and preview later uncommitted edits with the commands below.
From the generated root, install the Ruby and Node versions named by its version files. Start PostgreSQL 18.
If you use asdf, set ASDF_RUBY_VERSION and ASDF_NODEJS_VERSION to those versions; asdf does not necessarily read
.ruby-version and .node-version without its legacy-file setting. Then run:
bin/setup --skip-server
bin/dev
Leave bin/dev running. Open localhost:3000 in your browser. Create a book, reopen it, edit
it, and delete it. Submit an empty required field once to check validation. Have Claude explain any difference
between the Plan, the gap report, and the running app.
7. Give Revyl an address for local Rails
Revyl's hosted devices need an HTTPS address for Rails. The local Android Emulator in step 10 does not. In a second Terminal:
cloudflared tunnel --url http://localhost:3000
Copy the https://…trycloudflare.com address from the output. Keep cloudflared running. This temporary public
address exposes the development app, so use the disposable sample data.
Stop Rails with Control-C, then restart it with the tunnel's exact hostname allowed:
RAILS_DEVELOPMENT_HOSTS=YOUR-TUNNEL.trycloudflare.com bin/dev
Open the tunnel address in a browser and check that your app loads.
Rails provides this environment setting; no source change is needed. Do not clear the host allowlist or disable CSRF protection. A newly started Quick Tunnel normally has a new address; update the native preview's server argument accordingly.
See Cloudflare's Quick Tunnel instructions.
8. Sign into Revyl
Install the Revyl CLI using its official installer, then:
export PATH="$HOME/.revyl/bin:$PATH"
revyl --version
revyl auth login
revyl auth status
Revyl's service can reject an outdated CLI. Run revyl upgrade when it asks for an update. An older revyl
elsewhere on your PATH can shadow the new one, so check the version printed here.
Confirm that the CLI and Revyl website use the same workspace. Uploading an already-built application does not require Revyl remote builds or a GitHub connection. Hosted devices consume Revyl usage.
Preview one platform at a time. Stop a session when finished; closing its browser tab does not stop the device.
9. Build and preview iPhone locally
Use a complete Xcode installation with the iOS Simulator components installed.
Build a Debug Simulator application in the already ignored tmp/ directory:
xcodebuild build -quiet \
-project ios/FoundationApp.xcodeproj -scheme FoundationApp \
-configuration Debug -destination 'generic/platform=iOS Simulator' \
-derivedDataPath tmp/ios-preview \
-onlyUsePackageVersionsFromResolvedFile \
ARCHS='arm64 x86_64' ONLY_ACTIVE_ARCH=NO \
CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO
ditto -c -k --sequesterRsrc --keepParent \
tmp/ios-preview/Build/Products/Debug-iphonesimulator/FoundationApp.app \
tmp/ios-preview/FoundationApp.app.zip
Create a Revyl app once and note the returned ID:
revyl app create --name "Reading List iPhone" --platform ios --json
Upload the locally built app, replacing IOS_APP_ID with that ID:
revyl build upload --file tmp/ios-preview/FoundationApp.app.zip \
--app IOS_APP_ID --platform ios --yes --json
Use the returned build_id and your current tunnel address to start a device:
revyl device start --platform ios --build-version-id IOS_BUILD_ID \
--launch-env APP_ROOT_URL=https://YOUR-TUNNEL.trycloudflare.com \
--timeout 600
Open the Viewer link. Check the list, details, and form. Pull down to refresh after a Rails change; the device
keeps the same native binary. When finished, stop it with revyl device stop.
10. Build and preview Android locally
Preview Android in Android Studio's local Emulator. In Android Studio's SDK Manager, install Android SDK platform 36 and build-tools 36.0.0. In Device Manager, create a phone with an Android 16 / API 36 system image with Google APIs. The app requires Android System WebView 120 or newer; if it reports an outdated WebView, use a newer image.
Open android/ in Android Studio. In Run → Edit Configurations, select the app configuration and set its
Launch Flags to --es APP_ROOT_URL http://10.0.2.2:3000. Select the debug build variant and your Emulator,
then click Run. Android Studio builds and installs the app with its bundled Gradle JVM; keep that default.
10.0.2.2 is the Emulator's address for your Mac, so this path needs no tunnel. Check the list, details, and form.
Optional: preview Android in Revyl
Revyl's hosted Android devices also need Android System WebView 120 or newer, and an image can ship an older one. Check the actual device: if the app reports an outdated WebView, stop the device and use the Emulator instead. Do not sign into Google Play on a hosted device to update it.
Build the APK from the command line with JDK 17. With Homebrew and the default macOS SDK location:
brew install openjdk@17
export JAVA_HOME="$(brew --prefix openjdk@17)/libexec/openjdk.jdk/Contents/Home"
export ANDROID_HOME="$HOME/Library/Android/sdk"
bin/android build
If your SDK is elsewhere, set ANDROID_HOME to the path shown in Android Studio. The generated Gradle wrapper
builds android/app/build/outputs/apk/debug/app-debug.apk locally.
Create the Android app once, then upload using its returned ID:
revyl app create --name "Reading List Android" --platform android --json
revyl build upload --file android/app/build/outputs/apk/debug/app-debug.apk \
--app ANDROID_APP_ID --platform android --yes --json
Start a device with the returned build_id:
revyl device start --platform android --build-version-id ANDROID_BUILD_ID \
--launch-env APP_ROOT_URL=https://YOUR-TUNNEL.trycloudflare.com \
--timeout 600
Check the list, details, and form in the Viewer. Stop the session with revyl device stop when finished.
11. Continue building
Read the generated README and UI.md, plus .firstdraft/gaps.json and the retained implementation notes. Have
Claude explain the generated models, routes, controllers, views, and native shells before making the first change.
Then adapt the UI to your sketch or implement the next small feature in ordinary source.
Rails changes appear after refreshing the running app. No Compile, native build, upload, commit, or push is needed for that loop. Swift or Kotlin changes require another local build. In the Emulator, click Run again. For Revyl, rerun the same build command, reuse the platform's Revyl app ID, stop the old device, and start one with the newly returned build ID. Xcode and Gradle reuse their local build caches. You can checkpoint with Git when a change is ready.
The generated bin/ios simulator-artifact, bin/android apk-artifact, and preview revyl wrappers are a separate
commit-labelled artifact workflow. Their default preview path uses GitHub builds. The direct development commands
above deliberately build the current working files and upload them through Revyl's CLI.
Stop any Revyl sessions and the Emulator, then press Control-C in the cloudflared and Rails terminals when done. Your local source and database remain on your computer. Back them up or publish to a private repository when you choose.