← All use casesUSE CASE

Competitor Price Monitor with a Memory

Watches competitor prices daily, keeps the full history in SQLite, and only speaks up when a move crosses your threshold.

scheduledbcustom-tools

model: claude-haiku · budget: $1/day · agent.js: ~89 lines

▶ Demo video — coming soon
75 seconds, deploy to running agent
VIEW SOURCE ON GITHUB ↗agent.js ↗

DEPLOY IT

git clone https://github.com/anupsinghinfra/oncell-cookbook && cd oncell-cookbook
cp .env.example .env   # add your ONCELL_API_KEY
npm run deploy price-monitor

# invoke it
curl -X POST https://api.oncell.ai/api/v1/agents/price-monitor/track \
  -H "Authorization: Bearer $ONCELL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Smoke Test Pro plan","url":"https://competitor.example/pricing","threshold_pct":5}'

You found out your competitor cut prices from a customer. On a sales call. Three weeks after it happened. Everyone has a version of this story, and everyone has the same half-fix: a bookmark folder called "competitors" that gets opened four times a year, or a browser extension that emails someone who left the company.

The real fix is boring and continuous: look at the same pages every day, write down what you saw, and say something only when the number moves enough to matter. Boring-and-continuous is exactly what software is for — except this particular job needs a scheduler that fires forever, a database that accumulates forever, and a notion of "enough to matter" per product. Suddenly the boring job has a Terraform directory.

price-monitor compresses all of it into one file, and runs on claude-haiku because a watcher that speaks once a week shouldn't cost dollars a day to stay silent.

The history is a real table

The identity in agent.js declares two SQLite tables the agent creates itself: products (what to watch and each product's threshold_pct) and prices (every observation, forever). Each daily check pass appends a row per product before it judges anything. That ordering matters: the record is unconditional, the alert is conditional. Months from now the history is there for repricing analysis whether or not anything ever "mattered" — and reading it costs zero tokens:

agent.task("history", async (args) => {
  ...
  const result = await agent.db.sql`SELECT price_usd, checked_at FROM prices WHERE product = ${name} ORDER BY checked_at`;
  return result.rows;
});

That's a direct primitive call — no LLM, no cost, just the tagged-template db interface against the agent's own SQLite.

Alert logic you can read in one breath

The threshold rule lives in the identity, in English:

"A price move matters when the absolute percent change from the most recent recorded price meets or exceeds that product threshold_pct. The first observation for a product never matters - there is nothing to compare against."

And the output contract is strict enough to pipe into Slack:

"Answer with one line per flagged move formatted as ALERT <name>: <old> -> <new> (<signed percent>), or the single line all quiet - N products checked."

No fuzzy prose. A downstream webhook can grep '^ALERT' and be done.

Tomorrow is booked by today

Every check ends with the same move the cookbook's daily-digest uses: "call schedule with in set to 1 day and note set to check." The wake intent lands in the runtime's park ledger; the run exits; tomorrow a fresh run starts with check as its prompt. There's a belt-and-braces cron registration too:

agent.schedule("daily-price-check", "daily", runCheck, { maxCost: 0.2 });

Note the numbers: each check pass is capped at 20 steps and $0.20, the track task at 6 steps and $0.05, and the identity budget caps the whole agent at perDayCents: 100. On haiku, a day of watching a dozen products lands well under a dime.

fetch_price is the single stub — the sandbox has no network of its own, so the custom tool is your window to the world. Point its run body at a scraping API or an internal price feed; the schema the model sees stays identical.

Deploy it

git clone https://github.com/oncell/oncell-cookbook && cd oncell-cookbook
cp .env.example .env   # add your ONCELL_API_KEY
npm run deploy price-monitor

Track a product and kick off the first check:

curl -X POST https://api.oncell.ai/api/v1/agents/price-monitor/track \
  -H "Authorization: Bearer $ONCELL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Pro plan", "url": "https://acme.example/pricing", "threshold_pct": 5}'

curl -X POST https://api.oncell.ai/api/v1/agents/price-monitor/check -d '{}'

Day one answers all quiet - 1 products checked (first observation, nothing to compare). The day Acme moves 7%, you get ALERT Acme Pro plan: 49 -> 52.5 (+7.1%) — and a history curl shows you exactly when.

What you didn't have to build

A cron service and its box. A database with a migration for the price table. Threshold config storage. A "first run" special case scattered through alerting code. Cost alarms for a scraper loop gone wild — the step cap, the per-run cost cap, and the daily budget are all enforced by the runtime.

You wrote two table schemas and a definition of "matters." The watcher never blinks, and it never costs more than a dollar a day.