Add aai dev/share/deploy and make starter templates deployable beyond Vercel#51
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Each starter (audio-transcription, live-captions, voice-agent) now ships a
Procfile (`web: uvicorn api.index:app --host 0.0.0.0 --port ${PORT:-3000}`)
and runtime.txt (python-3.12), so a `git push` deploys to Render, Railway,
Heroku, and Cloud Run buildpacks with no typed start command. Vercel ignores
both. READMEs document the "Deploy elsewhere" path.
The init template contract gate (run by scripts/check.sh) now boots each
template's Procfile command for real and asserts it serves GET / with 200,
plus validates the runtime pin. Static mirrors added to the pytest contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Run the guided setup without prompts; defaults on when an agent/CI is detected. Promotes output._is_agentic() to public is_agentic() now that it's used cross-module (pyright strict rejects private cross-module use). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Curl-style authenticated passthrough to the AssemblyAI REST and LLM-gateway APIs, driven by bundled OpenAPI specs. Bundled-only (no live fetch), multi-spec/multi-host resolution via environments.active(), spec-driven auth, keyring-only key, full Vercel-parity surface (passthrough + list + picker + --show-code). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dev_command Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The contract gate boots the real Procfile but only curls GET /; the
install test just imports the module. Neither touches the /api/*
surface, so a route that imports fine but raises on every request
slips through. Add an in-process TestClient test that drives each
route for both outcomes — outbound call succeeds (assert the documented
200 body) and outbound call raises (assert the graceful 502 {"detail"}).
Covers all three template api/index.py files to 100%.
Also strip ASSEMBLYAI_BASE_URL in isolate_env so template-import
behavior doesn't vary with the dev's environment.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…prompt Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ploys don't crash public/ is Vercel's reserved CDN output dir and is omitted from the Python lambda, so StaticFiles(directory=public/static) raised at import -> FUNCTION_INVOCATION_FAILED. Move assets to a bundled static/ dir FastAPI owns; add a contract test forbidding public/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ys don't crash on the venv console-script shebang Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…to surface the URL Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…to 'fly launch' when fly.toml is missing Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…der/Cloudflare-Containers build a working image Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…images Scaffolds each template and runs docker build to prove the shipped Dockerfile works (deps install, COPY layout, CMD). Self-skips without Docker; shellcheck-linted by check.sh. Verified all 3 images build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…he fly.toml preflight Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t matches the app Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ex checks type-narrow Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t instead of a cryptic Bearer/SDK failure Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| return probe.getsockname()[1] | ||
|
|
||
|
|
||
| def _terminate(proc: subprocess.Popen[str]) -> str: |
There was a problem hiding this comment.
Reading and returning raw subprocess stdout in _terminate can expose secrets or user-controlled output; avoid returning/embedding full process output or sanitize/truncate it before including in messages.
Details
✨ AI Reasoning
The new helper reads the child process' stdout and returns it verbatim. Returning raw process output and later interpolating it into failure messages can expose secrets or other sensitive, user-controlled content emitted by that process. This was introduced in the PR (new _terminate function) and increases the risk of logging sensitive runtime output from spawned template processes.
🔧 How do I fix it?
Keep sensitive data such as emails, passwords, and tokens out of logs. When logging values tied to a user, prefer a safe identifier like a user ID over the raw input, and strip line breaks from any user-provided text you do log.
Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- test_deploy_help_lists_flags: CI renders --help with ANSI color, which inserts escape codes mid-flag (--<ESC>...-fly), breaking the substring match. Strip ANSI before asserting. - test_init_template_stream: _load_app booted keyless, so the new missing-API-key guard returned 500 instead of 502/200. Inject a dummy key (preserving a pre-set one), matching the other template suites. Was masked locally by the repo .env. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
New commands
aai dev— boot a scaffolded template'sProcfileweb process locally (live reload + browser open). Boots the same command hosts run, so everyaai devsmoke-tests the deploy artifact.aai share— same boot, exposed on a public*.trycloudflare.comURL via a cloudflared quick tunnel (cloudflaredadded to the Homebrew formula).aai deploy— confirm-gated (y/N,--yes) deploy to Vercel (default,--prod), Railway (railway up, thenrailway domainfor the URL), or Fly (fly launch). Requires the target CLI with an install hint; no formula deps for Railway/Fly.Templates made portable beyond Vercel
static/instead of the Vercel-reservedpublic/(which Vercel drops from the Python lambda →FUNCTION_INVOCATION_FAILED). Regression guard added.python -m uvicornin the Procfile (fixes the Railway/Nixpacks venv console-script shebang crash).Dockerfile(+.dockerignoreso.envisn't baked in,EXPOSE 8080) for Fly / Railway / Render-Docker / Cloudflare Containers.ASSEMBLYAI_API_KEYis unset instead of a crypticBearer/SDK failure.Supporting
aai_cli/init/{devserver,procfile,tunnel}.py;runner.run_server/spawn.scripts/docker_build_check.shbuilds all three template images (verified locally)../scripts/check.sh(100% patch coverage, mutation gate, build + twine).Note
This branch also carries in-progress work from a parallel session interleaved with the above —
aai onboard --non-interactiveandaai apidesign docs. Worth confirming/splitting before merge if you want a tightly-scoped PR.🤖 Generated with Claude Code