City council approves new cycle lanes for the river district
Drafted from stage 4's run
Statusdrafted
A web app that pulls articles from RSS feeds, has an AI model score each one, and drafts only the ones that clear a quality threshold, in English and Arabic. Publishing is left to an editor.
Model calls cost money, and cheaper models score lower on the same rubric. So anything that can be rejected without a model call is rejected first, each remaining item gets one scoring call, and the threshold moves with the model, so one platform setting holds across ten providers.
Plays the six stages below in order, about 45 seconds. Scroll or press Esc to stop.
Offline runs of the deployed Lambda's own orchestrator and quota code, with the model and the database stubbed. The articles, model scores and plan counts are illustrative; lines starting with [harness] come from the test harness, and the italic lines mark trims.
A run starts from the article queue's Run Full Cycle button as one GraphQL mutation. The Lambda records a job, hands the work to a second invocation of itself, and returns the job id straight away.
The other way in is the daily schedule. At 08:00 UTC, workspaces set to daily or weekdays get up to 10 articles written from their own topic list, as many as the workspace sets. That path skips scraping, scoring and the threshold. Its topic is still checked against the blocklist.
Four answers to the one-token probe Illustrative input
validateModel and its error classifier, run offline against a stubbed provider. The four status codes are the inputs.Every workspace gets the platform's shared RSS feeds, 13 in the code's defaults, plus any it adds. Before a model sees an item, two checks that cost nothing remove what shouldn't be scored.
7 scraped, 5 queued for scoring Illustrative input
normalizeUrl and matchBlockedPattern on these items; the existing article's source URL and the block pattern are illustrative. The log lines are from the offline run of the real orchestrator.Up to a per-run cap, each queued item gets one model call with a fixed system prompt that asks for relevance, quality and trending, each out of 100. The workspace's voice and keywords don't enter scoring.
0.5 × relevance + 0.4 × quality + 0.1 × trending.Three numbers become one Illustrative input
The platform sets one quality threshold. The workspace's chosen model shifts it by a fixed offset, because cheaper models score lower on the same rubric, and the result is clamped between 20 and 95. Items below it are never drafted.
effective = clamp(round(platform threshold + model offset), 20, 95)
This gate covers the article queue's runs. The scheduled daily run, described in stage 1, doesn't pass through it.
Five scored items against the line Illustrative input
node offline-quota.js period 2026-10 Pro, 499 used: allowed, counter now 500 Pro, 500 used: QuotaExceededError: AI generation cap reached (500/500 this period). Upgrade the plan to continue. No plan, 10 used: QuotaExceededError: AI generation cap reached (10/10 this period). Upgrade the plan to continue.
ClearedAbove this line a run has spent a one-token probe and one model call per scored item. Below it, each draft takes at least three more calls, and ends as a draft for an editor, not a published article.
The workspace's AI profile goes in front of the drafting prompt as one line of guidelines: voice, reading level, target length, keywords and the citation rule. Its custom rules go at the end.
drafted.What changes when you change the voice Illustrative input
buildSystem output for an illustrative profile: the default 1,200 words, two keywords, citations on and one custom rule. Switching voice changes one phrase. The six voices are the ones the product's AI Studio offers.Nothing the pipeline writes is published by the pipeline. Drafts wait in the article queue for someone with the Editor role or above.
published. Reject sets it to rejected and hides the article.One draft, two possible endings Illustrative input
City council approves new cycle lanes for the river district
Drafted from stage 4's run
Statusdrafted
Every piece below is in the deployed backend definition; nothing here is planned work. One Amplify app builds the backend and the server-rendered front end together, in one job per deploy of the main branch.
The Angular and Ionic app, rendered on the server by a Node 20 compute function, with static files served alongside.
Sign-in by email or phone, with optional SMS or authenticator-app MFA. After sign-up, onboarding creates the user's workspace and makes them its Owner.
32 data models, plus custom mutations backed by Lambda: start a run, manage members, check out, open the billing portal.
33 functions. The pipeline runs in one of them, with a 900-second limit and 1 GB of memory. The others include membership, billing, email, webhooks, account deletion, the public API, the sitemap and the scheduled jobs.
The tables behind the GraphQL models. The pipeline writes its job, queue and article rows directly.
Eight scheduled rules, among them scheduled generation at 08:00 UTC, trial reminders at 09:00 UTC and a publishing check every 5 minutes.
Checkout for subscriptions and the customer portal. A webhook with a verified signature keeps each workspace's plan and status in step.
Article images in S3, and transactional email through SES.
The repository documents no benchmarks. These are the numbers that could be checked: one by re-running the code, one from the hosting service, and one that is only an estimate in the code.
The effective threshold is computed in the web app, to preview it, and in the Lambda, to enforce it. Both were run on every catalog model at every step of the product's slider, 0 to 100 in steps of 5.
The offsets on this page are the Lambda's values for the twelve models the landing page lists.
Amplify builds the backend and the server-rendered front end in one job. The last three deploys of the main branch:
Between about 13 and 27 minutes each, all successful.
The model picker shows a cost per call from token counts fixed in the code: 3,500 in and 800 out to score, 6,000 in and 2,500 out per drafting call. These are estimates, not measurements.
The draft estimate covers the English body alone. A draft also writes the Arabic version and makes smaller headline and translation calls.
My Stream runs at feed.geohashim.com. Sign up and create a workspace, choose a model and an editorial voice in AI Studio, add your own RSS feeds, then press Run Full Cycle in the article queue and watch the job.
The source code is private.