This article is published in English.
Unrestricted Browser Automation Agents with Node.js
Wire a browser-driving agent with clear tool boundaries, safety gates, and operable logging.
This walkthrough rebuilds an operable path for: How to Build an Unrestricted Browser Automation AI Agent using Node.js, Playwright, Bright Data, and Gemini. Focus on contracts, checks, and code you can drop into a repo without guessing intent. For Overview, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion.
Introduction
For Introduction, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive.
await page.goto(url)
await page.click(selector)
await page.type(selector, text)
What We Are Building
For What We Are Building, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive.
Prerequisite
For Prerequisite, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive. For Prerequisite, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion.
Building Sikki Project
For Building Sikki Project, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments. Checkpoint after expensive model calls so a retry does not re-bill the same work.
Step 1: Create the Project
For Step 1: Create the Project, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Checkpoint after expensive model calls so a retry does not re-bill the same work.
mkdir sikki-agent
cd sikki-agent
npm init -y
npm pkg set type=module
npm install playwright
npm install @google/genai
npm install dotenv
npm install chalk
npm install ora
sikki-agent
index.js
.env
screenshots/
reports/
package.json
Step 2: Get Gemini API Key
For Step 2: Get Gemini API Key, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish. Checkpoint after expensive model calls so a retry does not re-bill the same work. For Step 2: Get Gemini API Key, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion.
GEMINI_API_KEY = your_gemini_api_key
BRIGHT_WS_ENDPOINT = //i will show you later
Step 3 : Setting up Bright Data Cloud Browser Infrastructure
For Step 3 : Setting up Bright Data Cloud Browser Infrastructure, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments. Separate planning from tool execution. The planner proposes; the executor mutates; the verifier checks outcomes against the goal.
BRIGHT_WS_ENDPOINT = "your_endpoint"
chromium.launch()
chromium.connectOverCDP()
Step 4: Connect Playwright to Bright Data
For Step 4: Connect Playwright to Bright Data, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Separate planning from tool execution. The planner proposes; the executor mutates; the verifier checks outcomes against the goal.
import { chromium }
from "playwright";
const BRIGHT_WS_ENDPOINT = "your_endpoint"
const browser =
await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT
);
const page =
await browser.newPage();
await page.goto(
"https://cnn.com"
);
console.log(
await page.title()
);
Going Deeper into SIKKI Agent Before Implementation
For Going Deeper into SIKKI Agent Before Implementation, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish. Separate planning from tool execution. The planner proposes; the executor mutates; the verifier checks outcomes against the goal. For Going Deeper into SIKKI Agent Before Implementation, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion.
SIKKI is Not A Scraper
For SIKKI is Not A Scraper, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive.
ProductPriceAcer Nitro V$899ASUS TUF$949MSI Thin$979
The Architecture Behind SIKKI
For The Architecture Behind SIKKI, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive.
SIKKI
Strategic Intelligence Commerce Kernel
┌──────────────────────────────┐
│ Browser Layer │
│ Playwright + Bright Data │
└──────────────────────────────┘
│
▼
┌──────────────────────────────┐
│ Extraction Layer │
│ Product │
│ Price │
│ Rating │
│ Seller │
│ Availability │
└──────────────────────────────┘
│
▼
┌──────────────────────────────┐
│ AI Layer │
│ Gemini │
└──────────────────────────────┘
│
▼
┌──────────────────────────────┐
│ Analysis Layer │
│ Cheapest Products │
│ Market Average │
│ Competitor Comparison │
│ Trend Analysis │
└──────────────────────────────┘
│
▼
Markdown / CSV
Dashboard Export
Building The Extraction Layer
For Building The Extraction Layer, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive. For Building The Extraction Layer, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion.
const products = await page.evaluate(() => {const items = [];
document.querySelectorAll('[data-component-type="s-search-result"]')
.forEach(card => {
const title =
card.querySelector('h2 span')?.innerText;
const price =
card.querySelector('.a-price .a-offscreen')
?.innerText;
const rating =
card.querySelector('.a-icon-alt')
?.innerText;
const link =
card.querySelector('h2 a')
?.href;
if(title && price){
items.push({
title,
price,
rating,
link
});
}
});
return items;
});
console.log(products);
[
{
title: "Acer Nitro V Gaming Laptop",
price: "$899",
rating: "4.5 out of 5 stars",
link: "https://..."
},
{
title: "ASUS TUF Gaming A15",
price: "$949",
rating: "4.4 out of 5 stars",
link: "https://..."
}
]
Giving SIKKI A Brain
For Giving SIKKI A Brain, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments. Checkpoint after expensive model calls so a retry does not re-bill the same work.
const prompt = `You are an ecommerce analyst.
Analyze the following products.
${JSON.stringify(products)}
Return:
1. Cheapest product
2. Average price
3. Best rated product
4. Summary of the market
5. Recommendation
`;
Building the Final SIKKI Agent
For Building the Final SIKKI Agent, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Checkpoint after expensive model calls so a retry does not re-bill the same work.
Step 1: Create the Agent File
For Step 1: Create the Agent File, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish. Checkpoint after expensive model calls so a retry does not re-bill the same work. For Step 1: Create the Agent File, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion.
import "dotenv/config"; //to use environment variables from .env file
import fs from "fs"; //to read and write files
import { chromium } from "playwright";
import { GoogleGenAI } from "@google/genai";
//api keys and endpoints from environment variables
const BRIGHT_WS_ENDPOINT = process.env.BRIGHT_WS_ENDPOINT;
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
//initialize the GoogleGenAI client with the Gemini API key
const ai = new GoogleGenAI({
apiKey: GEMINI_API_KEY,
});
//the prompt to send to the Gemini API
const prompt = "Write a short introduction to the Gemini API.";
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: prompt,
});
console.log(response.text);
Step 2: Setup Playwright to connect to Bright Data’s WebSocket
For Step 2: Setup Playwright to connect to Bright Data’s WebSocket, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments. Separate planning from tool execution. The planner proposes; the executor mutates; the verifier checks outcomes against the goal.
//setup Playwright to connect to Bright Data's WebSocket endpoint and navigate to Amazon search results for "gaming laptop"
async function main(){
const browser = await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT);
const page = await browser.newPage();
const query = "gaming laptop";
const searchUrl = `https://www.amazon.com/s?k=${encodeURIComponent(query)}`;
console.log("Navigating Bright Data Playwright to:", searchUrl);
await page.goto(searchUrl, { waitUntil: "domcontentloaded" });
const title = await page.title();
console.log("Amazon search page title:", title);
console.log("Bright Data navigation complete for query:", query);
await browser.close();
}
main();
Step 3: Extract Product Information
For Step 3: Extract Product Information, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Separate planning from tool execution. The planner proposes; the executor mutates; the verifier checks outcomes against the goal.
// Playwright to connect to Bright Data's WebSocket endpoint and navigate to Amazon search results for "gaming laptop"
async function main(){
const browser = await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT);
const page = await browser.newPage();
const query = "gaming laptop";
const searchUrl = `https://www.amazon.com/s?k=${encodeURIComponent(query)}`;
console.log("Navigating Bright Data Playwright to:", searchUrl);
await page.goto(searchUrl, { waitUntil: "domcontentloaded" });
const products = await page.evaluate(() => {
const data = [];
document
.querySelectorAll('[data-component-type="s-search-result"]')
.forEach((card) => {
const title = card.querySelector("h2 span")?.innerText;
const price = card.querySelector(".a-price .a-offscreen")?.innerText;
const rating = card.querySelector(".a-icon-alt")?.innerText;
if (title && price) {
data.push({
title,
price,
rating,
});
}
});
return data;
});
console.log("Step 3: Extract Product Information");
console.log(products);
const title = await page.title();
console.log("Amazon search page title:", title);
console.log("Bright Data navigation complete for query:", query);
await browser.close();
}
main();
Step 4: Ask Gemini To Analyze The Market
For Step 4: Ask Gemini To Analyze The Market, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish. Separate planning from tool execution. The planner proposes; the executor mutates; the verifier checks outcomes against the goal. For Step 4: Ask Gemini To Analyze The Market, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion.
const prompt = `You are an ecommerce analyst.
Analyze these products:
${JSON.stringify(products)}
Return:
1. Cheapest Product
2. Average Market Price
3. Best Rated Product
4. Competitor Comparison
5. Final Recommendation
`;
const result = await model.generateContent(prompt);
const analysis =
result.response.text();
### 3. Best Rated Product
There are three products tied for the highest rating of **5.0 out of 5 stars**:
1. **HP OMEN 16" Gaming Laptop Computer** (Intel Ultra 9 285H, NVIDIA GeForce RTX 5070 8GB, 16GB DDR5, 1TB PCIe SSD, 144Hz IPS WUXGA Display) at **$1,745.99**
2. **HP OMEN 16 Slim RTX 5070 Gaming Laptop** (Intel Ultra 9 285H, NVIDIA RTX 5070, 32GB DDR5, 1TB SSD, 16" FHD+ Anti-Glare) at **$1,929.00**
3. **ASUS ROG Strix G16 Gaming Laptop** (Intel Core i7 14650HX, NVIDIA RTX 5060, 32 GB DDR5 RAM, 1 TB SSD, 16" FHD+ LED Display, & Gaming Accessories) at **$1,999.99**
**Analysis:** It's noteworthy that two HP OMEN laptops achieved perfect ratings, both featuring high-end Ultra 9 CPUs and RTX 5070 GPUs.
This suggests strong customer satisfaction with HP's premium gaming line.
The ASUS ROG Strix G16 also achieved a 5.0 rating,
despite having a slightly lower-tier GPU (RTX 5060) than the
HP OMENs in this bracket, possibly due to the included
"Gaming Accessories" and overall perceived value.
The Alienware product has no rating, so it cannot be considered here.
Step 5: Export The Sikki Market Report
For Step 5: Export The Sikki Market Report, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive.
const report = `
# SIKKI Market Report
## Search Query
${query}
## Products
${JSON.stringify(products, null, 2)}
## Gemini Analysis
${analysis}
Generated: ${new Date().toISOString()}
`;
fs.writeFileSync(reportPath, report, "utf8");
import "dotenv/config"; // use environment variables from .env file
import fs from "fs";
import { chromium } from "playwright";
import { GoogleGenAI } from "@google/genai";
const BRIGHT_WS_ENDPOINT = process.env.BRIGHT_WS_ENDPOINT;
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
if (!BRIGHT_WS_ENDPOINT) {
throw new Error("Missing BRIGHT_WS_ENDPOINT environment variable.");
}
if (!GEMINI_API_KEY) {
throw new Error("Missing GEMINI_API_KEY environment variable.");
}
const ai = new GoogleGenAI({
apiKey: GEMINI_API_KEY,
});
async function retryWithBackoff(fn, maxRetries = 5, initialDelayMs = 2000) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
const errorMsg = error?.message || error?.status || JSON.stringify(error);
if (attempt === maxRetries) {
console.error(`Final attempt failed. Error: ${errorMsg}`);
throw error;
}
const delayMs = initialDelayMs * Math.pow(2, attempt - 1);
console.log(`Attempt ${attempt} failed: ${errorMsg}`);
console.log(`Retrying in ${delayMs}ms... (${attempt}/${maxRetries})`);
await new Promise((resolve) => setTimeout(resolve, delayMs));
}
}
}
async function main() {
let browser;
try {
browser = await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT);
const page = await browser.newPage();
const query = "gaming laptop";
const searchUrl = `https://www.amazon.com/s?k=${encodeURIComponent(query)}`;
console.log("Connecting Playwright to Bright Data...");
console.log("Navigating to:", searchUrl);
await page.goto(searchUrl, { waitUntil: "domcontentloaded" });
const products = await page.evaluate(() => {
const data = [];
document
.querySelectorAll('[data-component-type="s-search-result"]')
.forEach((card) => {
const title = card.querySelector("h2 span")?.innerText;
const price = card.querySelector(".a-price .a-offscreen")?.innerText;
const rating = card.querySelector(".a-icon-alt")?.innerText;
if (title && price) {
data.push({
title,
price,
rating,
});
}
});
return data;
});
console.log(`Extracted ${products.length} products.`);
const analysisPrompt = `You are an ecommerce analyst.
Analyze these products:
${JSON.stringify(products)}
Return:
1. Cheapest Product
2. Average Market Price
3. Best Rated Product
4. Competitor Comparison
5. Final Recommendation
`;
console.log("Sending products to Gemini for analysis (with retry logic)...");
const analysisResult = await retryWithBackoff(async () => {
return await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: analysisPrompt,
});
}, 5, 2000);
const analysis = analysisResult.text || "No analysis text returned.";
const report = `# SIKKI Market Report
## Search Query
${query}
## Products
${JSON.stringify(products, null, 2)}
## Gemini Analysis
${analysis}
Generated: ${new Date().toISOString()}
`;
fs.writeFileSync("sikki-report.md", report, "utf8");
console.log("Step 5: Export the Results");
console.log("Report generated: sikki-report.md");
console.log("Final analysis saved. Open sikki-report.md to review the result.");
await browser.close();
} catch (error) {
console.error("Error:", error.message || error);
if (browser) {
await browser.close().catch(() => {});
}
process.exit(1);
}
}
main();
Step 6: Teach SIKKI To Capture Evidence
For Step 6: Teach SIKKI To Capture Evidence, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive.
const searchScreenshot = path.join(screenshotDir, "search-results.png");
await page.screenshot({ path: searchScreenshot, fullPage: true });
const summaryPath = path.join(screenshotDir, "top-product-summary.png");
await cards[0].screenshot({ path: summaryPath });
Step 7: Capture Every Product Page
For Step 7: Capture Every Product Page, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish. Bound tool schemas tightly. Wide free-text args invite injection and make audits expensive. For Step 7: Capture Every Product Page, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion.
const normalized = normalizeAmazonUrl(p.url, p.title);
await retryWithBackoff(async () =>
await page.goto(normalized, { waitUntil: "domcontentloaded", timeout: 120000 }),
3,
1500
);
await page.waitForTimeout(800);
await page.screenshot({ path: outPath, fullPage: true });
Step 8: Create a CSV Export
For Step 8: Create a CSV Export, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments. Checkpoint after expensive model calls so a retry does not re-bill the same work.
const csvLines = ["TITLE,PRICE,RATING,URL"];
enriched.forEach((p) => {
const safe = (s) => `"${String(s || "").replace(/"/g, '""')}"`;
csvLines.push([safe(p.title), safe(p.price), safe(p.rating || ""), safe(p.url || "")].join(","));
});
fs.writeFileSync(csvPath, csvLines.join("\n"), "utf8");
Step 9: Generate A Dashboard Summary
For Step 9: Generate A Dashboard Summary, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph. Checkpoint after expensive model calls so a retry does not re-bill the same work.
const priced = enriched.filter((p) => !isNaN(p.priceValue));
const cheapestObj = priced.length ? priced.reduce((a, b) => (a.priceValue <= b.priceValue ? a : b)) : null;
const avgPriceVal = priced.length ? (priced.reduce((s, p) => s + p.priceValue, 0) / priced.length).toFixed(2) : “N/A”;
const bestRatedObj = enriched.slice().sort((a, b) => {
const ra = parseFloat((a.rating || “”).split(“ “)[0]) || 0;
const rb = parseFloat((b.rating || “”).split(“ “)[0]) || 0;
return rb — ra;
})[0] || null;
const dashboard = [];
dashboard.push(“==================================”);
dashboard.push(“SIKKI MARKET DASHBOARD”);
dashboard.push(“==================================”);
dashboard.push(`Query: ${query}`);
dashboard.push(`Products Extracted: ${enriched.length}`);
dashboard.push(`Cheapest Product: ${cheapestObj ? `${cheapestObj.title} | ${cheapestObj.price}` : “N/A”}`);
dashboard.push(`Average Price: ${avgPriceVal === “N/A” ? “N/A” : `${avgPriceVal}`}`);
dashboard.push(`Best Rated: ${bestRatedObj ? `${bestRatedObj.title} | ${bestRatedObj.rating || “N/A”}` : “N/A”}`);
dashboard.push(“\nTop 5 Products:”);
enriched.slice(0, 5).forEach((p, i) => {
dashboard.push(`${i + 1}. ${p.title} | ${p.price} | ${p.rating || “N/A”} | ${p.url || “N/A”}`);
});
fs.writeFileSync(dashboardPath, dashboard.join(“\n”), “utf8”);
Where To Go From Here
For Where To Go From Here, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Document the happy path and the recovery path together. Retries, human gates, and dead-letter handling are part of the product, not later polish. Checkpoint after expensive model calls so a retry does not re-bill the same work. For Where To Go From Here, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Treat this stage as a contract between inputs and validated outputs. Name the artifacts, define success checks, and refuse silent partial completion.
Conclusion
For Conclusion, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state. Record timings and cost next to functional results. Visibility early prevents surprise bills when the path moves from demo to shared environments. Separate planning from tool execution. The planner proposes; the executor mutates; the verifier checks outcomes against the goal.
Operational checklist
For Operational checklist, define the inputs, the owner of the step, and the exit criteria before changing code. Operators should be able to re-run the step from a known checkpoint without guessing hidden state.
Prefer small, testable units over sprawling scripts. When a step fails, the failure should point at a single responsibility rather than a tangled pipeline.
Checkpoint after expensive model calls so a retry does not re-bill the same work.
Understand the event loop boundaries: what blocks the thread versus what waits on the kernel.
Write a short runbook: how to rotate keys, how to drain the queue, how to roll back the last change.
Keep configuration outside application code. Environment files, secret stores, and feature flags belong in one place operators can audit without reading the whole graph.
Before promoting the stack, freeze versions, capture a golden transcript for the critical path, and confirm rollback steps. Shared environments need rate limits, tenancy checks, and a clear owner for secret rotation. Prefer boring reliability over clever one-off demos.