Render Tutorials
Localhost Part 1: Deploy an AI code-review agent on Render

Deploy the naive agent

⏱ 5 min

Pattern 1 is the baseline: one web service that runs the whole review inside the HTTP request. It’s the simplest thing that works, and the rest of the workshop improves on it. Deploy it first so you have something live to compare against.

sequenceDiagram
  participant Browser
  participant Web as Web service
  participant DB as Postgres
  Browser->>Web: POST /api/reviews (PR URL)
  Web->>Web: run review blocks the request
  Web->>DB: persist findings + verdict
  Web-->>Browser: response, only when the review is done

The handler awaits the review and only then responds. While that runs, the request is held open.

The whole pipeline lives in packages/naive-agent/src/server.ts.

The whole pipeline lives in packages/naive_agent/src/naive_agent/server.py.

1. Deploy the Pattern 1 Blueprint

A Blueprint is Render’s infrastructure-as-code spec — a single YAML file that declares the services, databases, and environment variables for a stack. When you deploy a Blueprint, Render reads the file and provisions everything in one step.

The naive agent has its own Blueprint. It provisions a web service and a Postgres database:

Use packages/naive-agent/render.yaml.

packages/naive-agent/render.yaml
projects:
- name: <YOUR_USERNAME>-agents-workshop-naive
environments:
- name: production
databases:
- name: <YOUR_USERNAME>-naive-agent-db
plan: basic-256mb
region: oregon
postgresMajorVersion: "18"
services:
- type: web
name: <YOUR_USERNAME>-naive-agent
runtime: node
region: oregon
plan: starter
buildCommand: npm ci
startCommand: npm run start --workspace @workshop/naive-agent
healthCheckPath: /healthz
envVars:
- key: DATABASE_URL
fromDatabase:
name: <YOUR_USERNAME>-naive-agent-db
property: connectionString
- key: ANTHROPIC_API_KEY
sync: false
- key: OPENAI_API_KEY
sync: false
- key: GITHUB_TOKEN
sync: false
- key: NODE_ENV
value: production

Use packages/naive_agent/render.yaml.

packages/naive_agent/render.yaml
projects:
- name: <YOUR_USERNAME>-agents-workshop-naive
environments:
- name: production
databases:
- name: <YOUR_USERNAME>-naive-agent-db
plan: basic-256mb
region: oregon
postgresMajorVersion: "18"
services:
- type: web
name: <YOUR_USERNAME>-naive-agent
runtime: python
region: oregon
plan: starter
buildCommand: pip install uv && uv sync --frozen --no-dev --package workshop-naive-agent
startCommand: uv run python -m naive_agent.server
healthCheckPath: /healthz
envVars:
- key: DATABASE_URL
fromDatabase:
name: <YOUR_USERNAME>-naive-agent-db
property: connectionString
- key: ANTHROPIC_API_KEY
sync: false
- key: OPENAI_API_KEY
sync: false
- key: GITHUB_TOKEN
sync: false
- key: PYTHON_VERSION
value: "3.12"

The Blueprint lives inside packages/naive-agent, but Render evaluates it from the repo root. npm ci installs the workspace from the root lockfile.

The Blueprint lives inside packages/naive_agent, but Render evaluates it from the repo root. uv sync --package workshop-naive-agent installs the service package and its workspace dependencies.

Pattern 1 has one required env source and a few optional secrets:

SourceHow it is wired
DATABASE_URLfromDatabase on <your-username>-naive-agent-db
OPENAI_API_KEY / ANTHROPIC_API_KEY / GITHUB_TOKENsync: false on the service, only if you need real model output or private GitHub access
  1. Open the Blueprint flow In the Render Dashboard, click + New, then Blueprint.
  2. Connect your GitHub account Click Connect GitHub and authorize the Render GitHub app for your fork. This lets Render read the repo, deploy on push, and report status back. You only do this once.
  3. Select your fork Pick your fork from your connected repos, then click Continue.
  4. Set the Blueprint Name Name it workflow-agents-workshop-ts (TypeScript) or workflow-agents-workshop-py (Python). This is the display name for the Blueprint instance in your Dashboard.
  5. Set the Blueprint Path Set it to your track’s Pattern 1 path, exactly: packages/naive-agent/render.yaml (TypeScript) or packages/naive_agent/render.yaml (Python). Mind the hyphen vs underscore. The repo holds three Blueprints, one per pattern, and has no root render.yaml, so the default path won’t work.
  6. Pick `Create all as new services`

    Then click Deploy Blueprint.

    The Render Dashboard Blueprint setup page showing the connected fork, Blueprint Path field, and Deploy Blueprint button.
    Deploy the Pattern 1 Blueprint to create the web service and Postgres.

Use packages/naive-agent/render.yaml for the Blueprint Path.

Use packages/naive_agent/render.yaml for the Blueprint Path.

2. Review a public PR

Click on the name of the web service to open it. Once the web service is green, open its *.onrender.com URL. You’ll see the localhost Workshop: Naive Agent dashboard with a PR field, a built-in PR picker, a Review button, and an empty review table.

Use the LlamaIndex baseline PR. It is small enough for a first run and is also available from the dashboard picker.

  1. Choose the PR Pick LlamaIndex baseline from the dropdown, or paste https://github.com/run-llama/LlamaIndexTS/pull/2234 into the input.
  2. Watch the request block The button can show Reviewing..., but the handler is still waiting on the whole review before it responds.
  3. Read the result

    When the request returns, the row appears in the table with Status, Workflow, token count, and run time. Click it to inspect Reason, Reviewer findings, and Agent spans.

    The naive agent dashboard showing a completed LlamaIndex review with status, token count, runtime, findings, and agent spans.
    The completed review row, with findings and agent spans on click.

With the mock model, the output is deterministic and canned. With a provider key, exact wording varies because LLM output is nondeterministic.

3. See the limits

The row appearing only after the request completes is the whole lesson. Submit the same PR a second time and watch the browser hang until the full review finishes. Open a few tabs and submit at once — every request queues behind the same process.

With the mock model or a small PR, the response may come back fast enough that nothing visibly breaks. That’s fine. The limitations are architectural, not a demo you need to force:

  • The review runs inside the request. A larger PR or a real model would push response times past HTTP and proxy timeouts.
  • A deploy or crash kills in-flight reviews. There’s nowhere durable for the work to live.
  • Concurrent users share one process. Every “parallel” reviewer competes for the same box.
  • You can’t scale the agent independently of the web tier.

Pattern 2 exists to solve all four.

On the hosted naive agent, why does the review row appear in the table only after the request finishes?
Troubleshooting

Find the symptom that matches what you’re seeing, then apply the fix.

The Blueprint step won’t proceed or says no render.yaml found. The default path is the repo root, which has no render.yaml. Set the Blueprint Path to your track’s Pattern 1 file: packages/naive-agent/render.yaml (TypeScript) or packages/naive_agent/render.yaml (Python). Note the hyphen vs underscore.


Your fork doesn’t appear in Render’s repo picker. If you forked into a GitHub organization, an org admin may need to approve the Render GitHub app. When authorizing, grant access to that specific repo. Forking into your personal account avoids this.


The web service is stuck Deploying or the health check fails on the first deploy. A fresh basic-256mb Postgres takes one to three minutes to provision (longer when the whole room creates databases at once). The web service runs migrations on boot and can flap until the database shows Available. A first deploy that flaps then recovers is normal. Don’t panic-redeploy.


The review row appears only after the request finishes. That’s the point of Pattern 1: the handler awaits the whole review, so a slow model or large PR can blow past HTTP and proxy timeouts, and a crash loses the run. That limitation is the motivation for Pattern 2.


Local fallback fails with ModuleNotFoundError: No module named 'naive_agent'. Prefix the command with uv run: uv run python -m naive_agent.server. Bare python uses the system interpreter, which can’t see the uv workspace packages.

What you learned

  • Forked the workshop repo and deployed the Pattern 1 Blueprint (web service + Postgres)
  • Used the workshop-provided model key if present, or the mock model fallback if not
  • Reviewed the LlamaIndex baseline PR and saw the review run inside the request
  • Named the limits of in-process review: timeouts, lost work on crash, shared process, no independent scaling