Render Tutorials
Localhost Part 2: Run AI agents as Render Workflows

What you'll build

⏱ 5 min

In Deploy an AI code-review agent on Render you ran one agent two ways and ended up owning a file full of queue coordination. This tutorial runs the same agent a third way, on Render Workflows, where that coordination is the platform instead of your code.

The workshop repo for this track is on GitHub. Fork it, then clone your fork to follow along.

Open TypeScript workshop repo

The workshop repo for this track is on GitHub. Fork it, then clone your fork to follow along.

Open Python workshop repo

The thing you hand-rolled

Pattern 2 bought you scale and durability, and the bill was a queue helper: a stream, a consumer group, blocking reads, acks, retry-on-failure, and a pub/sub progress channel. Real code you write, debug, and keep correct. No built-in trace of which agent ran where.

That queue helper is packages/queue-agents/src/kv.ts.

That queue helper is packages/queue_agents/src/queue_agents/kv.py.

The primitive that replaces it

Render Workflows gives you one building block: the task. A task is a plain async function plus a small config object.

import { task } from "@renderinc/sdk/workflows";
export default task(
{
name: "your-review",
timeoutSeconds: 120,
retry: { maxRetries: 2, waitDurationMs: 1000, backoffScaling: 2 },
},
async function yourReview(input) {
// ...your logic...
},
);
from render_sdk import Retry, Workflows
app = Workflows()
@app.task(
name="your_review",
timeout_seconds=120,
retry=Retry(max_retries=2, wait_duration_ms=1000, backoff_scaling=2),
)
async def your_review(input: dict) -> dict:
# ...your logic...
return {}

Each task runs in its own isolated container with per-task retries, timeouts, and traces. Composition is just function calls: call a task from inside a task, wrap calls in the fan-out primitive for your track, and let the platform run the branches. The code-review pipeline becomes the same fan-out you already know, except each reviewer is a task.

Three runtime patterns, one fan-out

Here’s the same parallel review across all three patterns:

PatternHow fan-out is implementedWhat you maintain
1. NaiveParallel reviewer calls in one processNothing, but no scale or durability
2. QueueEnqueue jobs, consumer group, acks, pub/subThe whole queue and coordination
3. WorkflowParallel reviewer tasksNothing. Render does it

The punchline of the workshop: Pattern 2’s queue helper is, in Pattern 3, the Render platform.

On Workflows, the review is a tree of tasks. Each box below is a task that Render runs in its own isolated container, with retries and a trace you didn’t write:

flowchart TB
  cr["code-review<br/>task"]
  cr --> sec["security<br/>task"]
  cr --> perf["performance<br/>task"]
  cr --> ux["ux<br/>task (frontend only)"]
  sec --> judge["judge<br/>task"]
  perf --> judge
  ux --> judge

The plan

This tutorial stays deploy-first, then turns hands-on:

  1. Deploy the workflow gateway and the separate workflow service, then submit a PR from the shared workshop dashboard and read a real run trace in the Render Dashboard.
  2. Author your own review task locally, where a fast edit-run loop beats a deploy between every change.
  3. Push your task and watch it run in production.

You’ll review the same public demo PRs as Part 1. Use the LlamaIndex baseline PR for the first hosted run and when you author your review task. Use the OpenAI Agents trace PR from the dashboard picker when you want a larger diff, or the Mastra frontend PR when you want the UX reviewer to join the fan-out.

The gateway uses the same dashboard as the first two patterns. Once more than one workflow is discovered, it also shows a Workflow selector so you can choose between the built-in review task and your authored task from the same PR form.

In Pattern 3, what is the unit you author?
Troubleshooting

Find the symptom that matches what you’re seeing, then apply the fix. If you skipped Part 1, get these right before the deploy step.

The Setup attendee Blueprint names workflow won’t run on your fork. GitHub disables Actions on fresh forks. Open the fork’s Actions tab, click I understand my workflows, go ahead and enable them, then run Setup attendee Blueprint names. The fallback is local: npm run setup -- YOUR_GITHUB_USER (TypeScript) or uv run python scripts/setup_attendee.py YOUR_GITHUB_USER (Python), then commit and push.


Why setup matters. The Blueprint ships every Render resource name with a literal <YOUR_USERNAME>- prefix. The setup action replaces it with your GitHub username so you don’t collide with other attendees in the shared workspace. Skip it and the deploy fails, because <YOUR_USERNAME>- isn’t a real name. Run it before the deploy step, and confirm render.yaml shows <your-username>-... names.


Which workspace, and is it free? Confirm whether you’re deploying into a shared workshop workspace (where the gateway dashboard shows everyone’s runs) or your own account. Either way, every service is on a paid plan: there is no free tier. If a host owns the workspace, the host is billed.

What you learned

  • The same code-review agent now runs on Render Workflows
  • A task is a plain async function plus a config object, run in its own isolated container
  • Fan-out is ordinary async composition over tasks
  • Pattern 2's hand-rolled queue helper becomes the platform in Pattern 3
  • You'll deploy, then author your own task, then redeploy it