DEV Community

Jennifer Evangelista
Jennifer Evangelista

Posted on Edited on AI-assisted

Witching Hour: What If Someone Tried to Warn You? An Open-Model Ghost Hunt Where TabPFN and Gemma Investigate Your Real Data: Ghost or Fiction?

Hacktoberfest Open-Source AI Challenge: Ghost in the Machine Submission 👻🌼

Have you ever felt watched?

Coat on. Keys in hand. You are about to go out, but something feels wrong. You put the keys down and stay home.

Now imagine watching the hallway recording afterward. The light flickers. Three knocks break the silence. Something crosses the edge of the frame.

Was it a bad bulb? A draft? Or the reason you stayed?

That is the premise of The Warning, the case at the heart of my demo. Kenji, a fictional client in Japan, brings a staged twenty-second hallway recording to a very small, very opinionated ghost-hunting crew.

Luna wants to ask the spirit. Dr. Bigotes wants to check the light bulb.

Both will have to explain what happened at seven seconds.

The Warning: a staged hallway scene, with the woman in her coat near the front door

A fictional case. A measurable flicker. And a cat who would like everyone to stop blaming ghosts.

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine.

What I Built

I built an interactive ghost-hunting web app that reimagines the Ouija board, known in Brazil as brincadeira do copo, with real measurements, machine learning and data science. The glass still moves. A spirit still answers. This time, you can inspect the clues behind the story.

Witching Hour's terminal, PARANORMAL.exe, opens three cases:

  • The House: investigate four months of readings from a real research home. Find an unusual night, then hear a ghost story, a skeptical explanation and a practical morning note about the same measurements.
  • The Unheard: investigate a recording. The browser measures light, movement and sound, marks the moments that stand out, and lets you take those clues to a fictional séance.
  • The Room: play the Ouija-inspired game with your camera and microphone. The browser learns a short baseline, notices changes around you, and lets those changes become material for the board.

What do you get at the end? For a recording, an evidence locker with timestamps, Dr. Bigotes's explanations, the fictional board conversation and Xochi's downloadable case dossier, which keeps those parts separate. For a night in The House, the result is a chart, cited crew accounts and a calm morning note you can trace back to the readings. The story can change its tone; the measurements stay available for inspection.

Two open-model tools give the crew something to work with:

TabPFN is a foundation model for tables. Instead of writing a separate rule for every room, I give it recent household readings as context. It estimates a range for a sensor reading, so the investigation can ask: how unusual was this light, temperature or energy use for this house?

Gemma is Google's family of open models. In the saved investigations, Gemma reads small evidence cards and writes the crew's accounts. The implementation also supports configured model sessions, while the public demo provides recorded or template replies. The browser measures the recording; the storyteller interprets the resulting cards.

The rule connecting them is cite or vanish. Generated crew sentences must point to known evidence, and their numerical claims must pass the validator. A citation identifies the clue that inspired a line; it does not prove the character's explanation or a supernatural cause.

And there is much more behind this ghost-hunting kit: model comparisons, a fine-tuned narrator, durable investigations, agent traces and a browser that lets the skeptic check the weather. I will open that machinery below.

A small spoiler: the presence in The Warning is a Guardian. It wanted the client to stay. But when Luna asks, “Will you come back?”, the glass spells I AM HERE.

Why is it still here? Come investigate with us.

Meet the people arguing over your hallway

Luna the Medium, Dr. Bigotes the Skeptic, and Xochi the Night Watch

Luna, the Medium, is a tiny sugar-skull ghost with a marigold crown and a crystal ball. Dramatic and whispery, she turns unusual readings into a presence in the dark and opens the Ouija board.

Dr. Bigotes, the Skeptic, is a black cat scientist with round glasses and a flashlight. He looks for the ordinary explanation. A bulb. A draft. A kettle. He is the reason Luna cannot quietly upgrade a sound spike into a recorded voice.

Xochi, the Night Watch, is a xoloitzcuintli with a lantern. She writes the quieter account: what changed and what might be worth checking in the morning.

Halloween gave me the ghost hunt, the haunted terminal and the board. Día de los Muertos inspired the marigolds, the calaverita and Xochi's role as a messenger. I wanted room for both a shiver and a gentler thought: a house remembers its previous nights, and those memories can tell a story.

First, though, the cat wants to see the recording.

Demo

Open Witching Hour. The free instance can take about 50 seconds to wake up.

It opens as a story: one screen at a time, with Next and Back, so nobody has to wonder where to scroll or what to press. (Prefer the whole page? Explore freely sits in the corner, and the first screen also offers a guided tour of the full page.)

The film (2:30): the crew tells the whole story, hand-drawn, with an original creepy score.

The tour (5:53): a real recording of the story, screen by screen.

The first screen: the crew under the title, with Begin the investigation

The story has six parts:

  1. Welcome. The crew, big. Tap a character and they introduce themselves in their own voice, in a speech bubble, with their mouth moving.
  2. The House. The haunting map alone on screen. Click a bright night and its case file opens: Luna's story, Bigotes's explanation and Xochi's note, every sentence with its citation chip. At the bottom, Call the spirit: the glass spells a short message, and Luna reads aloud, in plain words, what it means.
  3. The Unheard. Kenji's case. The clip plays while your browser measures it; Skip the video goes straight to the séance.
  4. The Room. Your turn: your camera, no camera at all, or a recording you bring. Questions are buttons, so there is never an empty chat box waiting for an answer that cannot come.
  5. How it was tested. The receipts, the planted ghosts and the model comparison.
  6. Case closed.

The Unheard: what actually changed?

Press Open the case. The evidence locker separates the staged scene into light, sound and motion events. In the archived demonstration case, those events begin at:

Time Recorded signal
7.00 s The light rises 175% in a quarter second; a separate sound event begins
8.25 s A second sound event
9.00 s The louder sound staged as three knocks
10.00 s Motion on the right side: 11% of the frame changes

The scene has a shadow because I put one in the clip. The detector reports changed pixels. Measuring a sound's level does not identify a whisper or its speaker.

Dr. Bigotes adds his notes. Luna opens the board. The fictional client's recollection becomes story context, separate from the measured evidence.

The glass starts moving. Questions become three-word answers. Then Luna asks one last thing before GOODBYE:

“Will you come back?”

The glass moves again. I AM HERE. Then the glass breaks, the crew shouts and runs, and the page hands the board to you: Now it is your turn.

The glass moving across the recorded séance board, with Luna, Dr. Bigotes and Xochi around it; the label reads Recorded demo, fictional spirit

A short extract from the recorded séance. The glass moves through the fictional dialogue; the measurements stay in the evidence locker.

The recorded séance in story mode: Luna reads the glass, Bigotes checks the evidence, Xochi keeps watch

That is a fictional Guardian speaking. The interesting technical question is how to let it speak without letting it rewrite the evidence locker.

The public site includes recorded analyses and a recorded séance. New sessions support local Ollama, a configured remote provider or fallback templates. Check the mode label: a replay or template is not fresh model inference. On the free demo a new séance uses template spirits, and the evidence picks which one: light, sound and movement together summon a Guardian, mostly sound a Lost One, mostly movement a Trickster, light alone a Watcher. Each speaks in its own recorded voice. While a spirit is choosing its words, the board says so: the spirit is gathering its words.

The House: a haunting with four months of history

A twenty-second clip can supply a flicker. A house's sensor history supplies something harder: a pattern to break.

Open The House and choose a bright square on the haunting map. Each square is a night. Its case file combines observed readings, TabPFN's expected range, the crew's accounts and citation chips. Hover a chip to find its event on the chart.

The House in story mode: the haunting map alone on screen

The source is the public Appliances energy prediction dataset: readings collected every ten minutes in a home in Stambruges, Belgium, during 2016. This is a research dataset, not footage or sensor data from the fictional Japanese client.

The saved archive covers 123 nights, with 22 anomaly events across 21 nights and cold-room checks on 39 nights. Xochi's family-note scenario is illustrative: the dataset does not establish who lived alone or needed care, and the notes are not a validated care or safety service.

A House case file with the measured series and the crew's narration

The same night can sound very different when Luna and Bigotes take turns. The chart stays put.

The Room: your turn at the board

The third case is a game. Turn on your camera and microphone, or press Play without a camera, or bring a recording of your own: your browser measures it right there and the crew investigates it the way they did Kenji's. Summon the spirit of the room and pick a question. Motion shortly after the glass stops can trigger the line: “That wasn't part of the game.”

No camera? Press Play without a camera and the board still answers. It could be you moving. It could be a curtain. The scare comes from a measured change arriving at a carefully chosen moment. The spirit remains fiction.

Code

GitHub logo jenniferevangelista-de / witching-hour

What happened in the house at 3 AM? TabPFN learns what was normal, Gemma tells the story, every sentence cites a sensor.

Witching Hour

What if someone tried to warn you, and you never heard them?

Witching Hour is a fictional ghost-hunting experience built for Halloween and Día de los Muertos, using real sensor anomaly measurements. A crew of three tiny ghost hunters carries an open-source kit, and their terminal, PARANORMAL.exe, opens three kinds of cases:

Case What you bring What the kit measures
🏚️ The House a house's sensor log (the demo uses a real house in Belgium, four months, every 10 minutes) TabPFN, the spirit meter, learns what every room should feel like at every minute of the night and flags the readings that break the pattern
🎞️ The Unheard a recording of the night you almost went out and something made you stay light, motion and sound, frame by frame, inside the browser (OpenCV does the same in Python); the moments that stand out become numbered evidence
…

The repository contains the application, staged-clip generator, recorded results, tests and production workflows. You can inspect the archived results without configuring every optional service.

The main branch, which the live demo serves, includes the upload/session fix described below.

How I Built It

Witching Hour architecture: evidence is measured by TabPFN and the browser, numbered, told by Gemma 4 locally, checked by cite or vanish, then played in the story mode on Render with ElevenLabs voices

The hardest part was giving the ghost a useful limit.

Teach the meter what this house usually does

For each sensor, TabPFN v2 reads the previous fourteen days as context, subsampled to at most 1,000 rows. It returns quantiles for each ten-minute slot from midnight to 6 AM.

The features include time, outdoor weather and comparable sensors in other rooms. I exclude peers in the target room, so a simultaneous bathroom change is less likely to be explained away by another sensor beside it.

This is retrospective conditional anomaly analysis: the model uses weather and peer readings from the night being investigated. It asks what a reading looks like given that context. It is not a forecast made before the night began.

The meter scales deviations separately above and below the predicted band. That matters for a signal such as appliance energy, with a floor near zero and a long upper tail. Sustained large deviations, or a sufficiently large single deviation, become numbered events.

Then I planted some ghosts.

In the benchmark, I added smooth artificial bumps to 240 night-sensor pairs: forty nights and six sensors. Each detector received the same perturbations, with thresholds targeting a 5% sample false-positive rate.

Detector Planted cases detected Strongest cases detected Coverage of nominal 90% band
TabPFN v2 25.0% 37.8% 94.7%
LightGBM quantile regression 9.6% 14.4% 58.8%
Same-hour seasonal rule 13.3% 21.1% 84.1%

At this operating point, TabPFN detected more planted cases than either baseline, and three quarters still went undetected. Its AUC was close to LightGBM's, 0.644 versus 0.634, and it was slower. Faint perturbations were difficult for every method.

Threshold selection and evaluation share the same sample. These are exploratory results, not a held-out guarantee of a 5% false-alarm rate in a real home.

Benchmark protocol and limitations

Each method's threshold is the 95th percentile of original-night scores in the same sample. The methods are TabPFN v2, LightGBM quantile regression and a same-hour seasonal rule. The table's coverage measures how often original readings fall inside the nominal 90% band.

Multiple sensors share each night, while the saved bootstrap resamples individual cases. Perturbing only the target sensor leaves many real household situations untested. Independent evaluation nights, a night-level bootstrap and more realistic joint sensor changes would be needed before an operational claim.

Give the storyteller evidence, then check what it returns

Gemma 4 E4B through Ollama receives compact event cards instead of the raw log. Each generated sentence returns text and citation IDs:

{
  "text": "At 05:40, the machines woke up.",
  "cites": ["E1"]
}
Enter fullscreen mode Exit fullscreen mode

Illustrative response shape; the cited event must exist in the current case.

The validator checks that citations exist and that numerical tokens match values or times allowed by the cited records, with a rounding tolerance. Failed sentences are removed, with one retry available.

That is the concrete meaning of cite or vanish. It catches missing references and unsupported numbers. It does not establish every sentence's meaning, verify units comprehensively or prove a proposed cause. Bigotes's kettle is still a hypothesis, however confidently a cat may hold his clipboard.

The archive contains 162 story entries. Its 428 sentences include 66 scripted quiet summaries and 362 with citations, rather than 428 independently verified model generations. The app labels those quiet summaries as scripted, with no model called, and its Receipts panel counts them separately.

Before settling on the local setup, I used Backboard to inspect four remote open-weight models on twelve prompts each:

Model Sentences passing the validator Clean stories
Qwen 2.5 72B 37 / 38 11 / 12
Llama 3.3 70B 48 / 50 11 / 12
Gemma 3 27B 46 / 48 10 / 12
Mistral Small 3.1 24B 13 / 13 4 / 12
Gemma 4 E4B, local reference 45 / 45 12 / 12

Mistral's perfect sentence count hides eight invalid JSON responses. The local Gemma reference allowed one retry; the remote runs were one-shot. This was useful pipeline inspection, but those conditions do not support declaring an overall model winner.

Make the board obey a contract too

The recorded séance board, labelled Recorded demo, fictional spirit, measured clues; Luna reads the glass while Bigotes checks the evidence and Xochi keeps watch

Spirit responses have a separate contract: at most three words on the board, spoken text, known evidence IDs and an explicit fictional flag. Code computes the letter-by-letter animation. Invalid responses can be retried and replaced by templates; a keyword filter adds a limited content check.

The browser pipeline samples video at four frames per second and audio in quarter-second windows. A flicker changes many pixels, so the recording analysis separates global light changes from motion. A fresh jump in sound can start another event, keeping two nearby sounds from collapsing into one. A corresponding Python path uses OpenCV and ffmpeg.

The ghost that wouldn't leave

During testing, the demo's ghost survived a change of recording. Its transcript and story context could linger, and a replay finishing late could restore the old narrative. Correct citations are useless if they belong to the wrong case.

The fix clears the case as soon as a file is selected. Recording and board versions (recordingVersion and boardEpoch) guard asynchronous work, so an old response cannot repaint a newer investigation.

The exported dossier also reports the current session's source, identifying template sessions and recorded replays without claiming a new model call.

Using synthetic footage and mocked sessions, five Playwright tests, run as six cases, check immediate clearing, current-file evidence, late answers, interrupted replays, a fresh summon and source labels in exported dossiers. The latest suite on main passes 81 tests with one warning, including all six browser cases. The evidence must belong to the recording on screen.

Teach a smaller narrator the same discipline

Could a different small model learn the crew's contract?

The Tinker experiment fine-tuned Qwen3-8B with LoRA on sixty accepted stories from before April 15. Evaluation used 36 prompts across sixteen distinct later nights.

Qwen3-8B Sentences passing Clean stories Average seconds per story
Base 84 / 88 33 / 36 2.6
Fine-tuned 124 / 125 35 / 36 3.6

The tuned model improved validator acceptance in this small held-out run, with longer output and higher latency. Its training targets were model-generated stories accepted by the same validator. This measures the output contract, not complete truthfulness.

Keep the investigation alive when a worker disappears

Temporal wraps each night in a durable workflow. In the recorded failure test, three workflows completed after scan heartbeat timeouts. Two narration activities reached attempt six while Ollama was unavailable.

Sentry records agent, model and tool spans with token and timing metadata. One trace in the captured Agents view shows one LLM call, about 2.2K tokens and 3.40 minutes. It exposes the generation wait hidden behind an instant replay. The cost chart says No data to plot; a row displays $0, which I do not treat as an audited runtime cost.

Sentry Agents view for a recorded Witching Hour investigation

The investigator can rank nights, open a case and ask the meter about a reading through tools. Mastra supplies a TypeScript version with persistent memory. Its saved three-question thread opens April 19, answers a follow-up about “that same night” without restating the date, then calls tonight.

Browserbase opens the official weather-warning page. In the recorded investigation, Gemma calls official_warnings and uses the browser excerpt in its answer.

SerpApi supplies the Google weather search used by tonight.py. The investigator's tonight tool gives that weather and TabPFN's room forecast to Gemma, as the saved tool trace shows. That projection applies the 2016 house model to newer weather without matching outcome validation; its cold probability is pointwise at the lowest-median hour, not a whole-night probability.

Render hosts FastAPI and the front end. GitHub Actions runs the production pipelines, including scans, narration and experiments.

Partner technology, in detail

Fourteen partners, each with what it does here, what was run and where the evidence lives.

🔎 Open the evidence for each partner (numbers and links)

Each block below says what the partner does in Witching Hour, what was run, and what was not.

TabPFN: the spirit meter, inside an agent

  • What it does: for every night and sensor, TabPFN v2 reads the house's previous 14 days (up to 1,000 rows) and predicts quantiles for every 10-minute slot from midnight to 6 AM. Far-out readings become numbered events (E1, E2) that every story must cite.
  • Inside a wider agent: the investigator agent calls it as a tool (expected_at: "what did the meter expect in the bedroom at 05:40?") next to tools that rank nights, open a case and read tonight's forecast (agent runs).
  • Second model: tonight.py trains a second TabPFN on the house's past nights and feeds it live weather to illustrate how each room would feel tonight.
  • Measured: 123 nights scanned, 22 events on 21 nights; planted-ghost benchmark of 240 cases against LightGBM and a seasonal rule (eval.json), limits stated above.

Gemma: every story, every spirit, on a laptop

  • What it does: Gemma 4 E4B through Ollama writes the crew's stories (96 stories, 362 cited sentences, all passed), plays the investigator agent, invents the spirits and answered the recorded séance of The Warning.
  • How it is constrained: JSON schema per answer, citation ids checked against the case, numbers checked against the cited values, one retry, then the sentence vanishes (narrator.py, spirits.py).
  • Where to see it: each story card in The House says by gemma4:e4b; the séance replay in The Unheard is the saved Gemma run (cases.json).

ElevenLabs: the whole cast has a voice

  • Crew voices: Luna is Jessica, Dr. Bigotes is George, Xochi is Matilda, all on eleven_multilingual_v2 with per-character settings (voice.py).
  • Spirit voices: every archetype a séance can summon speaks in its own voice: the Guardian, the Lost One, the Trickster, the Watcher, the Hostile Presence and the Silent One (make_seance_voices.py).
  • What was recorded: 114 audio files: 24 narrated stories of featured nights, 21 recordings of Luna explaining in plain words what each House board message means (make_board_voices.py), and 69 séance lines (Luna's questions, Bigotes's notes on every piece of evidence, Xochi's lines, the spirits' answers). About 16,700 characters in all, recorded once and shipped as files, so the free demo needs no key.
  • In the experience: tap a character on the first screen and they introduce themselves with a speech bubble and a moving mouth; Luna reads the board aloud; during a séance Luna asks, the spirit answers and Bigotes checks the evidence, each in their own voice.
  • Privacy: only fixed lines and validator-approved sentences were ever sent to ElevenLabs; no readings, recordings or visitor text.

Render: the agent's front end and API

  • FastAPI app plus the whole story-mode front end, deployed from a Blueprint with auto-deploy on every push to main. /api/health reports the live commit and "live": false when no model key is attached, and the page labels template answers accordingly.

Tinker: a smaller narrator that learned the rule

  • Qwen3-8B LoRA, 3 epochs, 60 validator-accepted stories from before April 15; tested on 36 prompts from 16 later nights: 95.5% → 99.2% sentences passing, 33 → 35 clean stories, 2.6 s → 3.6 s per story (tinker.json, train/).

Backboard: four open-weight models through one key

  • Gemma 3 27B, Llama 3.3 70B, Qwen 2.5 72B and Mistral Small 3.1 24B, same 12 prompts, JSON output, memory off, web search off, one shot each, same validator (bakeoff.py, results). The app is also wired to answer live séances through Backboard (Gemma 3 27B) when a key is set (providers.py); the public demo runs without one and says so.

Sentry Agent Tracing

  • gen_ai spans for the agent, each chat call and each tool call, with tokens and latency (tracing.py); the captured run shows one LLM call, about 2.2K tokens and 3.4 minutes on a laptop, cost "No Data".

Temporal: the night watch survives a crash

  • Each night is a durable workflow (durable.py). In the recorded test the scan activity hit heartbeat timeouts and narration reached attempt 6 while Ollama was down; all three workflows completed (temporal_summary.json).

Mastra: the investigation as a TypeScript agent with memory

  • An agent with tools and a LibSQLStore memory thread that calls the demo's API; the saved three-question thread answers a follow-up about "that same night" without restating the date.

Browserbase: the skeptic checks the weather himself

  • A real cloud browser opens the official MeteoAlarm page for Belgium; Gemma's official_warnings tool reads the excerpt (fieldwork.json, Playwright over CDP).

SerpApi: tonight's weather

  • Hourly weather for the house's town from Google results, the input of the Tonight illustration and of the agent's tonight tool (tonight.json).

GitHub Copilot category: GitHub Actions

  • Everything heavy runs in workflows: twelve parallel TabPFN shards, Gemma narration on runners, the benchmark, the Tinker fine-tune, Temporal, Mastra, the séance, the 81 tests, the screenshots and both videos (Playwright drives the live story mode and records it). No claim of the Copilot assistant itself.

Auth0 for AI Agents (home install)

  • On a home install, only signed-in, verified, allowlisted family members may ask the agent or read Xochi's live notes (auth.py, unit-tested in test_auth.py). The public demo does not use it.

Why Does Open Innovation Matter?

A house's sensor history can reveal when people sleep and when the house is empty. A hallway recording reveals much more. A household should be able to choose where analysis happens.

TabPFN on CPU, Gemma through Ollama and FastAPI on localhost give the core a route without a mandatory external model API.

Shared interfaces made the comparisons possible: substitute a detector, plant the same perturbations and inspect its distributions. Open weights let me fine-tune another narrator and test whether the same contract survives. I can change the pipeline that decides what becomes evidence.

The deployment still determines the data flow. Raw video and camera frames are analyzed in the browser. Summoning sends event descriptions and optional memory text to the application; questions and session history reach a model provider when configured. Optional services have their own flows, such as narration text to ElevenLabs and tracing metadata to Sentry.

A local-only installation can disable external services. The public demo uses a public research dataset and staged media, letting visitors explore without providing a private household's history.

The Spirit of It

Return to the hallway for a moment.

The light flickers. She pauses at the door. We want to connect those things, to give the pause a reason and the darkness a voice.

Luna can tell that story. Bigotes can interrupt it. Xochi can carry away the measurements and write something useful for the morning.

When the board spells I AM HERE, the Guardian belongs to the fiction. The event at seven seconds still belongs to the clip. Keeping both visible is the point of Witching Hour.

The evidence is real. The spirits are fiction. The feeling is yours.

Prize Categories

The categories this project enters, and where to see each one.

Category Entered What it is in Witching Hour Section
Overall Yes A ghost hunt where every spooky sentence must cite a real measurement, or vanish The whole post
TabPFN Yes The spirit meter and the Tonight model, called as a tool by the agent; benchmarked TabPFN
Gemma Yes Gemma 4 E4B, local: stories, agent, spirits, the recorded séance Gemma
Render Yes The live story mode and API, from a Blueprint Render
Tinker Yes Qwen3-8B LoRA: 95.5% → 99.2% on unseen nights Tinker
ElevenLabs Yes 114 recorded files: the crew, six spirit archetypes, Luna explaining every board ElevenLabs
Backboard Yes Four open-weight models through one key, same validator; live provider path Backboard
Sentry Agent Tracing Yes gen_ai spans for agent, chat and tool calls Sentry
Temporal Yes Night workflows that survived a killed worker and a stopped model Temporal
Mastra Yes The investigation as a Mastra agent with memory Mastra
Browserbase Yes Official weather warnings in a cloud browser, read by Gemma's tool Browserbase
SerpApi Yes Live weather for the Tonight forecast SerpApi
GitHub Copilot Yes (Actions path) The whole pipeline, tests and videos in GitHub Actions GitHub Actions
Auth0 for AI Agents Yes (home install) Verified, allowlisted family sign-in for the agent Auth0

These entries describe the implemented uses and their observed evidence. Final category eligibility is for the judges.

Credits and licenses. Built with PriorLabs-TabPFN. Application code is MIT; model terms and attributions are in NOTICE.md. Dataset: Candanedo, Feldheim & Deramaix (2017), UCI Machine Learning Repository, CC BY 4.0. The Warning and its fictional client were created for the demonstration. The crew's recorded application voices use ElevenLabs; promotional narration uses EdgeTTS. The film and the tour are rendered by video/make_videos.py in GitHub Actions (Pillow, Playwright and ffmpeg), with a synthesized drone under the voices. Application fonts: Creepster, Fredoka and Inter, under the SIL Open Font License.

AI assistance. An AI assistant helped a little along the way, and that is all.

Top comments (1)

Collapse
 
alexshev profile image
Alex Shev •

Citations become a real safety feature when they are bound to individual claims, not appended as a decorative bibliography. I’d preserve the source passage, retrieval time, and any transformation between it and the final answer. That makes disagreement productive: reviewers can challenge the evidence rather than argue with a fluent summary.