This module consists of two complete builds running in production. One is scheduled: the cron job fires, Firecrawl searches, the AI synthesizes, and a row is added to Google Sheets. The other is by event: a webhook receives a JSON payload, generates a .docx and save it to Google Drive. The diagram compares the two paths.
Illustrative diagram — conceptual recreation of the two production builds, not a real screenshot.
📅 Masterclass: Scheduled Research Agent
What it is
The first build is a scheduled research agent: a Trigger.dev task that runs on its own every morning on a cron schedule. It researches a fixed topic using the Firecrawl, synthesizes the findings with AI, and writes a structured line to the Google Sheets. All in a single file (e.g., morning-research.ts), with the topic hard-coded at the top — easy to change and version.
Why learn
The build flow
Check prerequisites
Connected repo, Trigger.dev account, MCP installed, project initialized, cloud env vars, and Firecrawl MCP with the key in .env.
Prompt in Plan Mode
“Unsupervised daily task, fixed topic, research with Firecrawl, synthesis, write one row in Sheets, no questions along the way, handle errors without crashing, log every step.”
Prepare the Sheet and deploy
Create the tab Sheet1 with a header (date, topic, summary, sources, status). Deploy and test manually in the dashboard (you can't wait for the scheduled time).
Key concepts
🎯 Practical tip
The AI may not ask clarifying questions and may make reasonable decisions on its own (columns, topic)—review and adjust afterward. Keep the topic hard-coded at the top of the file: it's trivial to change and stays under version control.
Runs unattended.
Hard-coded at the top.
The entire task in one .ts file.
Triggers in the dashboard.
🔁 OAuth refresh token
What it is
For the task to write to Google Sheets autonomously, it needs a refresh token OAuth—a one-time configuration credential that renews access without a manual login. Instead of a service account, the build uses OAuth with a client ID, client secret, and refresh token, all in the .env and in the cloud env vars.
Why learn
✓ The approach that works
- ✓Get the client ID + secret in Google Cloud Console.
- ✓When the Playground fails, run the AI's terminal script.
- ✓Paste the refresh token into .env e in Trigger.dev env vars.
✗ The Playground trap
- ✗The OAuth Playground may return “access blocked / request is invalid.”
- ✗Don’t insist on it—use the terminal script fallback.
- ✗Don’t forget the refresh token in the production environment.
Key concepts
The fallback is elegant: a script in the terminal (using the client ID + secret from .env) prints an authorization URL; you open it, authorize, and the script returns the refresh token for you to paste into .env and in the env vars. Set it up once—then the task renews access on its own with each run.
From the Cloud Console.
Renews access.
Made just once.
When the Playground fails.
🐞 A Bug That Only Appears in Production
What it is
Some errors only show up with real data in production. In the scheduled build, Firecrawl returned success: false and put the results in a property web instead of data — o shape from the response differed from what the code expected. The fix: adjust the parsing, redeploy, and trigger it again.
// o código esperava: { "success": true, "data": [ ... ] } // mas em produção veio: { "success": false, "web": [ ... ] } // ← parsing quebra aqui
Why learn
Expecting model errors is part of the process — it may assume the wrong format for an API response. What matters is the response: open the failed step, copy the complete error message, paste it into the AI to diagnose, apply the parsing fix, redeploy, and trigger it again. And this is where error handling proved its value: even with Firecrawl failing, the task didn’t crash and still wrote a partial row to Sheets.
🎯 Practical tip
After deploying, trigger it manually to test—don’t wait for the scheduled time. And confirm that the env var exists specifically in the production, not just in the dev one.
📄 Masterclass: Report via Webhook
What it is
The second build is event-driven: a task triggered by webhook. A web form sends a JSON payload (fields such as company name, industry, goal, challenge) to the webhook URL; the task generates a report .docx from these fields and saves it automatically to Google Drive. The AI fills in the report sections (executive summary, industry context, challenges) from a few input fields.
Why learn
✓ The build workflow
- ✓Prompt: webhook receives JSON, generates .docx, saves to Drive, asks no questions, handles errors, logs.
- ✓Optional Folder ID to organize the output in Drive.
- ✓Test locally with a sample payload before connecting the form.
📊 Connecting a No-Code Form
- •An n8n form trigger + an HTTP Request node.
- •POST to the webhook URL (which includes the task ID).
- •Body as named JSON
payload.
Key concepts
The task normalizes the form labels to match the expected payload shape, and the run can be fully or partially successful. The testing order is always: local first (dev server + sample payload), then with the form, and only then in production. Any form/system that supports webhooks + API works — you're not tied to a specific tool.
Form fields.
Report generated.
Folder ID organizes.
Before the form.
🔔 Webhook as a "digital doorbell"
What it is
A webhook is a "digital doorbell": a URL that listens for incoming data and, when it receives it, wakes up the task, passing the payload ahead. While cron fires on a schedule, the webhook fires in response to an event. The URL includes the task ID (e.g., webhook-report), and it's shareable and embeddable — it can come from a website, an email, or another system.
Why learn
⚠️ Without authentication, anyone can call your task
An open URL is an invitation: anyone who discovers it can trigger your task (and spend your tokens). The protection is a header Authorization: Bearer <chave> in the request.
- ✗Leave the webhook unauthenticated.
- ✗Forget the space after
Bearerbefore the key. - ✗Use the test URL instead of the production URL at the end.
Key concepts
POST https://.../webhook-report Authorization: Bearer <chave-da-API> Content-Type: application/json { "payload": { "empresa": "...", "setor": "..." } }
Wakes up the task.
Go to the URL.
Protects the endpoint.
Site, email, system.
🔗 GitHub → Trigger.dev Pipeline
What it is
O GitHub → Trigger.dev pipeline closes the iteration loop: when you change something in the editor and push to GitHub, GitHub runs the automatic deploy on Trigger.dev. The latest files are always live, with no manual deployment. It’s “commit → push → deploy” running on its own.
Why learn
Connecting GitHub to Trigger.dev
Ask the AI to set up the auto-push flow
Ask the AI to configure the workflow: editing in the editor pushes to GitHub, which deploys to Trigger.dev. Approve the bash commands.
Add the Repository Secret
On GitHub, under Settings > Secrets and Variables > Actions, create TRIGGER_ACCESS_TOKEN with the Trigger.dev secret key value.
Iterate and confirm in the dashboard
From there, each push triggers GitHub Actions, which deploys. Confirm in the Trigger.dev dashboard that the latest version is live.
Key concepts
You iterate in the editor.
Triggers the deployment.
TRIGGER_ACCESS_TOKEN.
Last deployed version.
🎯 Practical tip
With the pipeline live, the production debugging cycle is smooth: you fix it in the editor, push, and production updates automatically — without repeating the manual deployment with every iteration.
🛡️ Layered error handling
What it is
Without a self-healing agent in production, the robust error handling is what closes the agentic gap. The approach has layers: meaningful log at each step (visibility), try/catch around each external call, retries configurable with backoff and alerts of failure. Trigger.dev provides visibility and retries, but it can only retry what it recognizes as a failure.
Why learn
Layer 1 — Logging
Clear logs at every significant step: "Firecrawl returned 429 for source 3," not "task failed." Vague logs are useless.
Layer 2 — try/catch
Wrap each external API call in try/catch, log the error with context, continue where possible, and only throw on critical failures.
Retries + Alerts
Configure retries (e.g., up to 3 with exponential backoff starting at 30s) and alerts (Project Settings > Alerts) via email/Slack/webhook.
Key concepts
✓ Best practices
- ✓Log specific context (status code, which source).
- ✓Configure alerts so you know about a failure before the user does.
- ✓Wrap external calls at the right level.
✗ Mistakes to Avoid
- ✗Generic logs like "task failed."
- ✗Thinking retries will fix logic bugs (they only fix transient failures).
- ✗Deploy without configuring any failure alerts.
🔄 The human debugging loop
What it is
In production, AI still debugs — but no longer automatically. The human debugging loop is the cycle where you act as the bridge: open the red trace in the dashboard, copy the error, paste it into the AI ("here's the trace that failed; what's wrong, and how do I fix it?"), let it diagnose the issue, apply the fix, and redeploy. The trace + AI provide a quick diagnosis; a human just needs to bring the error to it.
Why learn
🔁 The four-step cycle
- 1.Open the red trace (the failed run) in the dashboard.
- 2.Copy the full error message from the step that failed.
- 3.Paste to the AI and let it identify the cause and the fix.
- 4.Redeploy and trigger it again until it passes.
Key concepts
The mindset shift is to stop being the trigger and start configuring triggers that run while you step away. Prompting and reading traces get easier with repetition—the second build is always faster than the first. And make sure every deployed task has failure alerts, so you know something broke before the user does.
Self-healing (optional): a task in production fails intermittently because the external API sometimes times out. Which feature is the best fit?
📌 Module Summary
Next Track:
Track 4 — Building Frontends & Apps: giving automation the look and feel of a product.