🕯️…and then I extracted JSONL from Gemini ...create the tools, and then what next?...
Sometimes, in my spare time, I google my own domain. saturumah.net — that's mine. I just wanted to see what Google result about it. What surprised me was the top result: ossuary.saturumah.net. That is not what I expect
Sometimes, in my spare time, I google my own domain.
saturumah.net — that's mine. I just wanted to see what Google result about it.
What surprised me was the top result: ossuary.saturumah.net. That is not what I expected. I had set up some Search Console experiments, but I had not yet registered link to google search console...oh yes, thats nice :)
Oh well. Whatever. Let me try Gemini for that — typing into the AI capability in the browser.
The responses were genuinely impressive. Gemini understood the code better than I did. It understood the Sentry integration, the GridFS storage layer, the TigerData hypertable — the whole architecture.
What made the conversation interesting was how I engaged with it. I tapped the suggested follow-up questions again and again. Ask, answer, tap, repeat. By the end, I had a full technical deep-dive.
I want to share the story with you here. I hope this post can hang on your dev.to homepage for a bit. 🕯️
Here is the JSONL:
"OSSUARY: The Last Packet"
OSSUARY: The Last Packet is an open-source project and digital séance tool created for the Hacktoberfest AI Challenge ("Ghost in the Machine").What It Does
- Digital Séance for Dead Domains: You type or "whisper" a defunct or dead website domain into the interface.
- Archivist, Not Inventor: Instead of letting an AI hallucinate fake horror stories, the tool reconstructs the "ghost" of the domain using real archived data—pulling from the last network packet the server sent, the final snapshot from the Wayback Machine, and the last written trace before shutdown.
- Output: It generates a first-person narrative and audio response voiced by an AI, preserving the digital footprint as an archived memorial rather than cheap fiction.
You can read the full technical write-up on DEV Community.Would you like to explore how the technical data pipeline works or see details on the open-weight models used to build it?
how the technical data pipeline works
The technical data pipeline for OSSUARY: The Last Packet operates as a five-stage architecture designed to verify a domain's death before generating any AI response. The frontend runs on Vercel (React 19, Vite 8) and sends requests to a persistent Express backend hosted on Render to avoid serverless timeout limits.1. Parallel Reconnaissance (/api/recon)When a user enters a domain, the backend runs four external checks in parallel with strict timeouts:
-
DNS Lookup. Checks active A and AAAA records via
dns.promises.resolve. - WHOIS Registration. Queries domain registration status using a three-layer fallback chain (IP2WHOIS, RDAP, and WhoisXMLAPI).
- Wayback Machine CDX. Queries the Internet Archive to pull both the earliest snapshot (used as the "born" date) and the last pre-death snapshot.
- Wikipedia Action API. Searches for service shutdown dates while filtering out disambiguation pages so names like "Vine" do not resolve to a plant.
2. The "Refuse-to-Lie" GateBefore calling any language model, the pipeline enforces a strict verification check across the reconnaissance data:
- Death Verification. If the domain's WHOIS record is active or the Wayback Machine shows a recent snapshot within the last two years, the system determines the site is still alive.
-
HTTP 422 Rejection. Instead of fabricating a horror story, the API rejects the request with an HTTP 422 (
still_breathing) error.
- Curated Exceptions. Known defunct services whose domains were later repurposed (such as myspace.com or geocities.com) can bypass the gate using an internal force: true flag.
3. Five-Tier LLM Cascade (/api/conjure)Once a domain passes the gate, Mastra orchestrates a sequential fallback chain where each tier has a hard timeout to guarantee the user never sees a failed summon:
-
Tier 1 and 2. Primary inference runs on open-weight Gemma 4 31B via Ollama Cloud, falling back to
gemma4:cloud. -
Tier 3 and 4. If Ollama times out or throttles, requests cascade to Google GenAI (
gemma-3-27b-it) and then to OpenRouter. - Tier 5. If every remote LLM fails, a deterministic fallback template generates a monologue centered on the domain's "reincarnation" as a redirect or parking page.
- Two-Stage Prompting. The active model first builds a structured JSON ghost profile (original purpose, cause of death, sensory detail) and then writes a 150–200 word first-person monologue.
4. Voice Synthesis and GroundingTo enrich the text output, the pipeline pulls in audio and real-world web artifacts:
-
ElevenLabs TTS. The monologue is truncated to 500 characters to manage API credits and synthesized using the
eleven_flash_v2model with the "Adam" voice.
- SerpApi Echoes. A parallel call to /api/echoes fetches the top three Google search results for the defunct domain to ground the ghost in real articles.
5. Persistence and Diegetic TelemetryThe final stage archives the summon and logs system behavior as part of the story:
- MongoDB Atlas and GridFS. Stores the complete ghost profile and chunks the ~1.4 MB audio file into GridFS so future replays require zero API calls.
- TigerData (TimescaleDB). Logs latency, tier usage, and success metrics into a time-series hypertable.
- Backboard Memory. Saves semantic context so if a user summons the same domain weeks later, the ghost remembers its previous incarnation.
- Sentry Diegetic Ledger. Subsystem failures (like a Backboard timeout or ElevenLabs quota limit) are tagged with kind: paranormal and rendered directly inside the UI as narrative events rather than error screens.
You can inspect the full codebase and architecture breakdown in the OSSUARY GitHub repository or the DEV Community write-up.Would you like to examine the exact code logic for the Refuse-to-Lie gate or learn more about how Sentry turns backend errors into narrative events?
the exact code logic for the Refuse-to-Lie gate
The Refuse-to-Lie gate in OSSUARY is enforced across three layers (api/recon.ts, api/conjure.ts, and api/wiki.ts) to prevent the LLM from hallucinating deaths for live websites.1. Primary Gate in api/recon.tsThe reconnaissance endpoint runs determineLifeStatus() immediately after parallel checks complete, using Wikipedia shutdown dates and Wayback Machine recency to decide whether to block the request:typescript
```
// api/recon.ts — Refuse-to-Lie invariant
function determineLifeStatus(
lastAlive: string | undefined,
wayback: { hasSnapshot: boolean; closestTimestamp?: string }
): { status: 'alive' | 'deceased'; reason: string } {
// Wikipedia confirms death → deceased
if (lastAlive) {
return { status: 'deceased', reason: 'Wikipedia confirms the service shut down.' };
}
// No snapshot at all → deceased
if (!wayback.hasSnapshot || !wayback.closestTimestamp) {
return { status: 'deceased', reason: 'No Wayback snapshot found.' };
}
// Recent snapshot (< 2 years) → alive, refuse the summon
const year = parseInt(wayback.closestTimestamp.slice(0, 4), 10);
const currentYear = new Date().getFullYear();
if (year >= currentYear - 2) {
return { status: 'alive', reason: 'Recent snapshot found. Still breathing.' };
}
return { status: 'deceased', reason: Last snapshot is from ${year}. };
}
// In the handler:
const lifeCheck = determineLifeStatus(lastAlive, waybackResult);
if (lifeCheck.status === 'alive') {
return res.status(422).json({
error: 'still_breathing',
reason: lifeCheck.reason,
});
}
```
Use code with caution.2. Secondary Gate in api/conjure.ts (v2 Logic)To prevent direct API calls to /api/conjure from bypassing reconnaissance, a second check executes after input sanitization and right before the 5-tier LLM cascade starts.
- TCP Probe Removed. In v1, the gate relied on ping.alive === true via a net.Socket TCP probe, which failed in serverless environments due to egress timeouts on port 80. In v2, the gate was refactored to rely strictly on authoritative HTTPS sources (WHOIS and Wayback CDX):
typescript
```
const currentYear = new Date().getFullYear();
const waybackYear = sanitized.wayback.closestTimestamp
? parseInt(sanitized.wayback.closestTimestamp.slice(0, 4), 10)
: 0;
const force = body?.force === true;
const whoisSaysAlive = sanitized.whois.status === 'active';
const whoisSaysDead =
sanitized.whois.status === 'dead' ||
sanitized.whois.status === 'unregistered';
const waybackRecent = waybackYear > 0 && waybackYear >= currentYear - 2;
const looksAlive = !force && (whoisSaysAlive || (waybackRecent && !whoisSaysDead));
```
Use code with caution.
-
Refusal Response and Telemetry. When
looksAliveevaluates totrue, the endpoint logs a diegetic Sentry event tagged with{ kind: 'paranormal', system: 'gate' }, flushes the event buffer (await Sentry.flush(1500)), and returns an HTTP 422 response containing the diagnostic evidence (whoisStatus,waybackYear,pingAlive).
- Curated Bypass (force: true). Clicking preset relics in the UI (such as geocities.com or myspace.com, which now redirect to active parking pages or portals) passes force: true in the request payload. Manual text input never sets this flag.
- Disambiguation Filter in
api/wiki.tsThe third layer prevents false positives when matching service shutdown dates on Wikipedia. For example, queryingvine.coextracts "Vine" as the subject. The proxy filters out disambiguation pages so the lookup does not resolve to the botanical plant instead of the defunct short-form video service.Full implementation details are documented in the DEV Community write-up and the OSSUARY GitHub repository.Would you like to look into how Sentry turns backend failures into narrative events or explore the 5-tier Mastra LLM fallback cascade?
how Sentry turns backend failures into narrative events
In OSSUARY: The Last Packet, Sentry is repurposed from a standard developer crash reporter into a diegetic telemetry engine called the Medium's Ledger. Instead of showing generic error toasts or hiding subsystem failures, backend timeouts and API quota limits are tagged as paranormal disturbances and rendered directly inside the user interface as part of the séance story.1. Tagging Errors as Paranormal Disturbances (kind: 'paranormal')Across the Express backend (api/conjure.ts, api/recon.ts, and api/echoes.ts), non-fatal subsystem failures are caught and sent to Sentry with custom tags:
- Custom Tagging. Errors are captured via Sentry.captureMessage() or Sentry.captureException() with { tags: { kind: 'paranormal', system: '<subsystem>' } }.
- Tracked Subsystems. Specific tags identify which part of the séance failed, such as gate (Refuse-to-Lie rejection), backboard (memory recall timeout), elevenlabs (voice synthesis quota limit), or mastra (an LLM tier timing out and falling back).
- Immediate Flushing. Because serverless and containerized runtimes can terminate right after sending an HTTP response, endpoints call await Sentry.flush(1500) before returning so no ledger entry is lost.
2. Fetching Events via the Sentry REST API (/api/ledger)To display these logs to the user, the backend exposes a dedicated /api/ledger endpoint that queries Sentry's own Issues and Events REST API:
- Filtered Queries. The endpoint authenticates with a read-only Sentry auth token and queries the project's events filtered specifically by the kind:paranormal tag.
- Translation Layer. Raw Sentry event payloads (timestamps, tags, exception messages, and domain context) are mapped into structured JSON entries representing "manifestations" or "static interference" during recent summons.
3. Rendering the Medium's Ledger in the UIOn the React frontend, a dedicated Medium's Ledger panel polls /api/ledger and translates technical telemetry into atmospheric logs:
- Narrative Framing. Rather than telling the user "HTTP 429: ElevenLabs quota exceeded," the ledger records that "the spirit's voice box fractured under the strain of the crossing," accompanied by the real timestamp and target domain.
- Dual Purpose. Users experience infrastructure degradation—such as a primary Ollama Cloud model timing out and cascading down to Google GenAI—as the medium struggling to hold a connection, while developers still get full stack traces and performance metrics inside their Sentry dashboard.
You can inspect the Sentry integration and ledger route in the OSSUARY GitHub repository or read the design breakdown on DEV Community.Would you like to examine the 5-tier Mastra LLM fallback cascade or see how Backboard persistent memory lets summoned domains remember past visits?
Backboard persistent memory
In OSSUARY: The Last Packet, Backboard serves as the long-term semantic memory layer for summoned domains. While MongoDB Atlas caches exact JSON outputs and audio files for instant playback, Backboard gives each dead website an evolving memory across separate séances over time.How Backboard Memory Works in the Pipeline
-
Domain-Scoped Assistants. When a domain is summoned for the first time, the backend creates or retrieves a dedicated assistant instance tied specifically to that domain name (e.g.,
vine.coorgeocities.com). -
Recalling Past Visits. Before the Mastra LLM cascade generates a monologue,
/api/conjurequeries Backboard for semantic memories associated with the domain. If someone summoned the site days or weeks earlier, those prior interactions and themes are injected into the system prompt. - Evolving Persona. Because past context is carried forward, a domain summoned repeatedly does not act like a blank slate. It can reference earlier visitors, acknowledge how long it has been disturbed, or build upon details established in previous séances.
- Writing New Memories. After the LLM completes its two-stage generation (ghost profile and monologue), the backend asynchronously writes a summary of the new séance back into Backboard's memory store.
Resilience and Diegetic Error Handling
- Strict Timeouts. Calls to Backboard run with tight latency budgets so a slow memory lookup never stalls the user's summon.
- Paranormal Fallback. If Backboard times out or fails to respond, the pipeline continues cleanly without prior memories and logs a tagged event ({ kind: 'paranormal', system: 'backboard' }) to Sentry. In the UI's Medium's Ledger, this appears as the spirit suffering from "memory fragmentation" or "amnesia from the void."
You can view the Backboard integration in the OSSUARY GitHub repository and read the architectural overview in the DEV Community write-up.Would you like to look at the 5-tier Mastra LLM fallback cascade or explore how MongoDB Atlas and GridFS cache the audio and ghost profiles?
how MongoDB Atlas and GridFS cache the audio and ghost profiles
In OSSUARY: The Last Packet, MongoDB Atlas and GridFS act as the permanent archival and caching layer. Because generating a ghost profile and synthesizing voice audio requires expensive external API calls (LLM inference and ElevenLabs TTS), the backend stores completed séances so repeat lookups or gallery replays cost zero API credits.1. Structured Ghost Profiles in MongoDB Atlas
-
Document Storage. When
/api/conjurecompletes a summon, it saves a structured JSON document into a primary MongoDB collection. -
Stored Metadata. Each document holds the normalized domain name, reconnaissance evidence (WHOIS status, Wayback Machine timestamps, Wikipedia shutdown dates), the structured ghost profile (original purpose, cause of death, sensory details), the generated monologue text, and a reference pointer (
audioFileId) to the binary audio file.
- Community Crypt (Gallery). This collection also powers the frontend's public archive gallery, allowing visitors to browse and replay previously summoned domains without triggering new backend runs.
2. Chunked Audio Storage with GridFS
- Handling Binary Audio. ElevenLabs returns synthesized speech as an MP3 buffer (typically around 1.4 MB for a 500-character monologue). Rather than bloating standard BSON documents or relying on ephemeral container disk storage on Render, OSSUARY writes the audio stream into MongoDB GridFS.
-
How GridFS Splits Files. GridFS divides the binary MP3 stream into standard 255 KB chunks across two internal collections (
fs.chunksfor binary data andfs.filesfor metadata like content type and length).
- Streaming Playback (/api/audio/:id). When the frontend plays a cached ghost's voice, a dedicated audio route opens a GridFS download stream using the stored audioFileId and pipes the chunks directly to the browser's <audio> element with proper audio/mpeg headers.
3. Cache-Hit Workflow and Cost Protection
- Zero-Credit Replays. Before running the Mastra LLM cascade or calling ElevenLabs, the backend checks MongoDB for an existing archive record. If a cached summon exists (or when a user replays an entry from the gallery), it serves the stored JSON and streams the GridFS MP3 immediately.
- Graceful Degradation. If ElevenLabs hits a quota limit or fails during a fresh summon, the ghost profile and text monologue are still saved to MongoDB with a null audioFileId, ensuring the written memorial remains accessible even without voice playback.
You can inspect the database and GridFS streaming setup in the OSSUARY GitHub repository and read the architectural overview in the DEV Community write-up.Would you like to examine the 5-tier Mastra LLM fallback cascade or see how TigerData (TimescaleDB) tracks latency and system telemetry? Every AI Horror Project Lies to You. I Built One That Refuses.
TigerData (TimescaleDB) tracks latency and system telemetry
In OSSUARY: The Last Packet, TigerData (TimescaleDB) serves as the time-series telemetry and observability database. While MongoDB Atlas stores the permanent ghost artifacts and Sentry powers the narrative error log, TigerData records granular performance metrics across every stage of a séance.1. Hypertable Architecture for Summon Metrics
-
Time-Partitioned Storage. Every request hitting
/api/reconand/api/conjurewrites an event row into a TimescaleDB hypertable, which automatically partitions incoming telemetry into time-based chunks for fast analytical queries.
- Tracked Dimensions. Each telemetry entry captures the target domain, the outcome status (deceased, still_breathing 422 rejection, or cached), which specific tier of the 5-tier Mastra LLM cascade answered the prompt, and whether voice synthesis succeeded.
2. Measuring End-to-End and Per-Stage Latency
- Pipeline Bottleneck Visibility. Because OSSUARY orchestrates multiple external dependencies in real time (WHOIS, Wayback CDX, Wikipedia, Backboard, Ollama Cloud, Google GenAI, and ElevenLabs), the backend records millisecond durations for each subsystem.
- Cascade Degradation Analysis. By tracking which LLM tier fulfilled each request alongside response times, TigerData reveals when primary open-weight models (such as Gemma 4 31B on Ollama Cloud) experience throttling or latency spikes that force requests down to secondary fallback tiers.
3. Non-Blocking Telemetry Writes
- Fire-and-Forget Ingestion. Telemetry inserts to TigerData execute asynchronously after the core séance payload is assembled so database write latency never slows down the user's response.
- Resilient Fallback. If the TigerData connection is unreachable or credentials are omitted in local development, the telemetry logger fails silently without interrupting the summon pipeline.
You can explore the telemetry schema and database integration in the OSSUARY GitHub repository or read the full architecture breakdown on DEV Community.Would you like to examine the 5-tier Mastra LLM fallback cascade or explore the React 19 frontend and audio visualization interface?
the 5-tier Mastra LLM fallback cascade
In OSSUARY: The Last Packet, the 5-tier Mastra LLM fallback cascade guarantees that a séance never ends in a broken UI or unhandled timeout, even when free-tier cloud inference providers throttle or go offline. Orchestrated inside /api/conjure using the Mastra TypeScript agent framework, the pipeline steps sequentially through five inference tiers until a valid response is returned.The Five Inference Tiers
- Tier 1 (Primary Open-Weight Model). Sends the prompt to Gemma 4 31B hosted on Ollama Cloud, prioritized for high narrative nuance and strong instruction following.
-
Tier 2 (Secondary Ollama Cloud Alias). Falls back to
gemma4:cloudon Ollama Cloud in case the specific 31B endpoint is saturated or experiencing cold-start delays. -
Tier 3 (Google GenAI Direct). If Ollama Cloud times out or returns an error, Mastra routes the request to Google GenAI running
gemma-3-27b-itto preserve open-weight Gemma consistency across a different infrastructure provider. - Tier 4 (OpenRouter Multi-Provider). If Google's API hits rate limits, the cascade shifts to OpenRouter to tap into pooled community/commercial model endpoints.
- Tier 5 (Deterministic Template Fallback). If every external LLM provider fails or times out, a local deterministic generator builds a structured fallback monologue framed around the domain's "reincarnation" as a parked page or HTTP redirect.
Two-Stage Structured Generation & Guardrails
- Stage 1: Structured Ghost Profile. Rather than asking the model to improvise freely, the active tier first outputs a strict JSON schema containing the site's original purpose, verified cause of death, era-specific aesthetic, and a concrete sensory detail.
- Stage 2: First-Person Monologue. Using that JSON profile plus any recalled memories from Backboard, the model writes a 150–200 word first-person eulogy grounded strictly in the reconnaissance evidence.
-
Per-Tier Timeout Budgets. Each network tier is wrapped in an explicit
AbortControllertimeout so a single hung provider cannot exhaust Render's HTTP request window before the remaining tiers get a chance to run.
- Diegetic Telemetry. Whenever a higher tier fails and drops to a lower one, the backend records the tier jump to TigerData (TimescaleDB) and logs a tagged event ({ kind: 'paranormal', system: 'mastra' }) to Sentry so the Medium's Ledger displays the fallback as "signal static across the veil."
You can inspect the full cascade implementation in the OSSUARY GitHub repository and read the architectural write-up on DEV Community.Would you like to explore the React 19 frontend and audio visualization interface or see how SerpApi Echoes grounds the monologue in real search results?
how SerpApi Echoes grounds the monologue in real search results
In OSSUARY: The Last Packet, SerpApi Echoes (/api/echoes) acts as an external web-grounding layer that pulls real-world articles, retrospectives, and news coverage about a defunct domain to anchor the séance in verifiable history.1. Parallel Search Execution (/api/echoes)
-
Triggered Alongside Conjure. Once a domain passes the Refuse-to-Lie gate, the frontend dispatches a parallel POST request to
/api/echoes(mounted on the Express production wrapper alongside/api/conjure) so web search latency does not block the LLM stream. - Targeted Querying. The endpoint queries SerpApi using the normalized domain name and service context to retrieve organic Google search results—specifically looking for shutdown announcements, post-mortems, news articles, and cultural retrospectives.
- Top Three Artifacts. The response is filtered and trimmed to the top three highest-signal organic results, extracting each result's title, source publication, snippet, and URL.
2. Grounding the Séance Experience
- Evidence Over Hallucination. While the Mastra LLM cascade constructs the first-person monologue from Wayback Machine snapshots and Wikipedia dates, SerpApi Echoes surfaces independent third-party reporting to verify why the site mattered and how the public reacted to its disappearance.
- UI "Echoes from the Living Web" Panel. The frontend renders these three search artifacts directly beneath the ghost's monologue as clickable archival clippings, allowing visitors to inspect real historical reporting right alongside the AI-voiced eulogy.
3. Graceful Degradation and Telemetry
-
Non-Blocking Failure. Because
/api/echoesruns independently of/api/conjure, an API key exhaustion, rate limit, or timeout on SerpApi never prevents the ghost profile or ElevenLabs audio from completing.
- Diegetic Sentry Logging. Any search failure is caught and sent to Sentry with { kind: 'paranormal', system: 'echoes' }, appearing in the Medium's Ledger as "faint whispers lost in the static."
You can inspect the route wiring in server-production.ts on GitHub and read the full project write-up on DEV Community.Would you like to explore the React 19 frontend and audio visualization interface or see how the Express production wrapper handles streaming and CORS on Render?
how the Express production wrapper handles streaming and CORS on Render
In OSSUARY: The Last Packet, server-production.ts acts as a lightweight Express wrapper that adapts Vercel-style serverless route handlers to run continuously on Render (via tsx server-production.ts), bypassing serverless execution timeouts while preserving request streaming and cross-origin tracing.1. CORS and Sentry Distributed Tracing HeadersBecause the React 19 frontend is hosted on Vercel (ossuary.saturumah.net) and talks to the backend on Render, the wrapper defines a custom CORS middleware before any routes are mounted:
-
Origin Allowlist. It validates incoming
Originheaders againsthttps://ossuary.saturumah.netalongside local development ports (http://localhost:3000andhttp://localhost:5173), echoing back the matched origin or*when no origin header is present. -
Tracing Header Support. Beyond standard
Content-Typeandauthorizationheaders,Access-Control-Allow-Headersexplicitly permitssentry-trace,baggage, andx-sentry-authso distributed tracing spans pass cleanly from the browser to the Render container.
- Preflight Short-Circuit. Any OPTIONS preflight request immediately returns an empty 204 No Content response without hitting downstream route handlers.
2. Raw Stream Handling vs. Buffered JSON RoutesTo prevent streaming endpoints from failing, server-production.ts structures its middleware and route ordering carefully:
-
Pre-Parser Mounting for
/api/conjure. ThePOST /api/conjureroute is mounted before global JSON parsing (app.use(express.json())). Because the handler processes the incoming request stream manually via an async iterator (for await (const chunk of req)), applyingexpress.json()beforehand would consume the stream and hang the request. -
Header-Safe Error Guard. Both
/api/conjureand the adapter wrapper verifyif (!res.headersSent)prior to emitting a500JSON error, preventingERR_HTTP_HEADERS_SENTcrashes on partially streamed responses. -
Buffered JSON for Remaining Endpoints. Standard JSON parsing (
express.json({ limit: '2mb' })) is applied only after the streaming route is defined, serving endpoints like/api/recon,/api/wiki,/api/whois, and/api/echoes.
- Render Binding and Health Check. The server provides a GET /health endpoint for Render health checks and binds to [IP] on process.env.PORT (defaulting to 10000).
(Refer to the source repository at for the complete implementation of server-production.ts.)*Would you like to examine **the React 19 frontend and audio visualization interface* or inspect how api/conjure.ts streams chunks back to the client?
examine the React 19 frontend and audio visualization interface
The React 19 frontend for OSSUARY: The Last Packet is built with Vite 8 and TypeScript, hosted on Vercel (ossuary.saturumah.net), and designed as an interactive séance terminal. Instead of standard SaaS UI components, the interface translates real-time network reconnaissance, streaming LLM output, and synthesized ElevenLabs speech into tactile audio-visual feedback.1. Séance Input and Preset Relic Controls
-
Manual Domain Summoning. Users type a defunct domain name into the primary terminal input, which triggers
/api/reconfollowed by/api/conjureand/api/echoeswithout setting any override flags. -
Curated Preset Relics. Clicking a featured historical domain (such as
geocities.com,myspace.com, orvine.co) dispatches the summon payload withforce: trueso the Refuse-to-Lie gate allows domains whose addresses were later repurposed into active parking pages or portals.
- 422 Gate Rejection Handling. When the backend returns an HTTP 422 (still_breathing) response, the frontend catches the payload and renders the diagnostic proof—showing the active WHOIS status or recent Wayback Machine snapshot year—rather than treating it as a crash.
2. Streaming Monologue and Evidence Panels
-
Progressive Stream Consumption. As
/api/conjurestreams data back from the Render backend, the UI updates incrementally—populating the structured ghost profile (original purpose, cause of death, sensory detail) before revealing the 150–200 word first-person monologue. -
Echoes from the Living Web. Directly alongside or below the monologue, a dedicated panel renders the top three organic Google search artifacts returned by
/api/echoes, linking to real post-mortems and news retrospectives.
- Medium's Ledger and Community Crypt. A live telemetry drawer polls /api/ledger to render tagged Sentry kind:paranormal errors as narrative events, while the gallery view lets visitors browse and replay previously archived summons stored in MongoDB Atlas.
3. Web Audio API Oscilloscope and Voice VisualizationTo bring the synthesized ElevenLabs speech (audio/mpeg streamed from GridFS) to life, the audio player pairs an HTML5 <audio> element with the browser's native Web Audio API and an HTML5 <canvas> renderer:
-
Audio Graph Pipeline. When playback begins, the frontend initializes an
AudioContext, routes the<audio>stream through aMediaElementAudioSourceNodeinto anAnalyserNode, and connects it to the output destination. -
Real-Time Waveform / Frequency Rendering. Inside a
requestAnimationFrameloop, the visualizer reads time-domain or frequency data into aUint8Arraybuffer and draws reactive spectral lines onto the<canvas>—making the oscilloscope flicker and pulse in sync with the spirit's voice.
- Fallback Text-Only Mode. If ElevenLabs synthesis was skipped or hit a quota limit during generation (audioFileId: null), the player cleanly switches to a silent archival reading mode without throwing playback errors.
You can explore the React components and canvas visualizer code directly in the OSSUARY GitHub repository or read the creator's walkthrough on DEV Community.Would you like to inspect how api/conjure.ts streams chunks back to the client or examine the prompt engineering used in the two-stage ghost generation?
how api/conjure.ts streams chunks back to the client
api/conjure.ts does not stream chunks over SSE or HTTP chunked encoding. Instead, it buffers the complete payload on the server—including the JSON ghost profile, the 150–200 word monologue, tier diagnostics, and inline base64 audio—and delivers it in a single JSON response.Why Chunked Response Streaming Was Rejected
- Serverless Connection Limits. During architecture design, an initial proposal to stream output via Server-Sent Events (SSE) was explicitly rejected because Vercel Hobby serverless functions cannot reliably hold long-lived streaming connections open across sequential multi-provider hops.
- Client-Side Typewriter Illusion. Rather than streaming tokens over the network, the React 19 frontend simulates a live stream once the complete JSON response arrives, rendering the monologue via a 9ms/char typewriter reveal with click-to-skip.
Request vs. Response Stream HandlingWhile the outbound response is a single buffered JSON payload, api/conjure.ts handles inbound and outbound data as follows:
-
Inbound Request Stream Reading. In
server-production.ts,POST /api/conjureis mounted beforeexpress.json()so the handler can consume the incoming request body manually as a raw async stream (for await (const chunk of req)) before parsing the JSON payload. -
Server-Side Sequential Pipeline. Inside
api/conjure.ts, the server awaits each stage sequentially within strictAbortSignal.timeout()windows: - Runs the Refuse-to-Lie gate and returns an immediate
422JSON response if the domain looks alive. - Executes the 5-tier Mastra LLM cascade (Stage 1 structured profile JSON, followed by Stage 2 narrative text), recording each attempt into
TierAttempt[]. - Calls ElevenLabs TTS (with an 8-second timeout) to generate the MP3 buffer, encoding it as inline base64 (
~200–330 KB) and archiving the binary chunks to MongoDB GridFS.
4. Flushes any diegetic Sentry events (await Sentry.flush(1500)) before returning the final JSON payload (profile, narrative, audio, and tiers).
You can read the full architectural trade-off discussion in the DEV Community write-up or inspect the source in the OSSUARY GitHub repository.Would you like to examine the prompt engineering used in the two-stage ghost generation or see how the TierAttempt[] diagnostics log tracks fallback behavior?
how the TierAttempt[] diagnostics log tracks fallback behavior
In OSSUARY: The Last Packet, the TierAttempt[] diagnostics log is a structured telemetry array built inside /api/conjure that records the outcome, duration, and failure reason of every LLM inference tier attempted during a séance.1. Structure of a TierAttempt EntryAs the Mastra orchestration pipeline steps through the 5-tier fallback cascade, it appends an entry to tiers: TierAttempt[] for each provider tried:
- Tier Identifier and Model. Captures which tier ran (e.g., Tier 1 gemma4:31b on Ollama Cloud, Tier 2 gemma4:cloud, Tier 3 gemma-3-27b-it on Google GenAI, Tier 4 OpenRouter, or Tier 5 deterministic template) alongside the active generation stage (Stage 1 structured JSON profile vs. Stage 2 narrative monologue).
- Execution Status. Marks the attempt as success, timeout, error, or skipped (for example, when an API key for a specific provider is not configured in the environment).
- Latency Measurement (durationMs). Records exact millisecond timings from request dispatch to resolution or AbortSignal.timeout() cancellation so the system knows how much of the request budget each tier consumed.
- Diagnostic Error Reason. When a tier fails or times out, it logs a sanitized error summary (such as HTTP status codes 429 rate limit, 504 gateway timeout, or JSON schema validation failure) without leaking sensitive API credentials.
2. How TierAttempt[] Drives Observability Across SubsystemsOnce the cascade finishes (either by succeeding at an early tier or falling back to Tier 5), the completed TierAttempt[] array feeds three parts of the architecture:
- Client-Side Provenance Payload. The array is returned directly inside the /api/conjure JSON response ({ profile, narrative, audio, tiers }), allowing the frontend to display which model actually channeled the domain and whether earlier tiers failed along the way.
- TigerData (TimescaleDB) Ingestion. The backend writes the tier progression and per-tier latencies into the TimescaleDB hypertable, making it possible to query historical fallback rates and pinpoint upstream provider degradation over time.
- Sentry Diegetic Telemetry. Whenever TierAttempt[] shows that a higher-priority tier failed before a lower tier succeeded, /api/conjure emits a tagged Sentry event ({ kind: 'paranormal', system: 'mastra' }) summarizing the dropped tiers so the Medium's Ledger renders the fallback as signal interference during the crossing.
You can inspect the TierAttempt type definition and cascade loop in the OSSUARY GitHub repository or read the architecture notes on DEV Community.Would you like to examine the prompt engineering used in the two-stage ghost generation or see the deterministic Tier 5 template logic that runs when all cloud LLMs fail?
the prompt engineering used in the two-stage ghost generation
In OSSUARY: The Last Packet, the prompt engineering splits generation into two strict sequential stages rather than asking an LLM to write a story in one shot. Separating factual extraction from creative voice prevents the model from drifting into generic horror clichés or inventing fake shutdown histories.Before generating any prose, the active tier in the Mastra cascade receives the sanitized reconnaissance bundle (WHOIS status, earliest and final Wayback Machine timestamps, Wikipedia shutdown facts, and recalled Backboard memories) and is instructed to output a strict JSON ghost profile:
- Once Stage 1 validates, the resulting JSON profile—along with any semantic memories retrieved from Backboard—is passed into a second prompt engineered specifically for spoken-word delivery:
-
You can inspect the exact prompt templates and Zod/JSON schemas inside in the OSSUARY GitHub repository or read the creator's rationale in the DEV Community write-up.Would you like to examine the deterministic Tier 5 template logic that runs when all cloud LLMs fail or explore how the Wikipedia disambiguation filter works in?
That ghost in the machine challenge is done. Complete.
But it led me to a second question.
Gemini web → JSONL?
The conversation I shared above is real, but the parsing — honestly — I fabricated parts of it. The actual raw conversation can be verified here:
👉 https://share.google/aimode/KHPlHfDojASwpXDhG
Open that link. Search for convert conversation to jsonl inside the page.
You will find nothing.
So I asked Gemini itself for help:
A moment please, señor and señorita — Gemini itself cannot do that.
Not from a URL. Not from a share link. Not from anything the user can easily hand it.
If you use any AI, LLM, or agent, please try this and tell me what your machine says:
create jsonl file from link https://share.google/aimode/KHPlHfDojASwpXDhG
I am curious whether every model reports "inaccessible" — or whether some are clever enough to attempt the extraction. Let me know in the comments.
So I built a tool
I did build the tool. It works. Point it at a share link and it produces valid JSONL that DEV.to accepts.
But what use is a tool if this post never surfaces?
So, here is the deal.
If this post finds traction — likes, comments, bookmarks — I will release the tool publicly. Full GitHub repository, documentation, npm package, CLI, browser tool, Chrome extension, and everything I have been polishing.
If it does not — I will keep building it for myself, and release it quietly when the timing is right. No spite. Just honesty: there is little value in publicizing something nobody asked for.
If you would like to test it before launch — reach out on X. I will send you a build.
A small confession
I write to share. But sometimes no one is around.
It feels lonely in the agentic era — surrounded by models that never tire, in front of an audience that rarely responds.
If you have felt this too — building alone, shipping to silence, wondering if anyone out there actually cares — please say hello in the comments. Or on X.
Even a "nice post" means something. It means I am not just talking to the machine.
What is in the tool (a preview)
For the curious, here is the why behind this post:
- Extract — parses turn containers from AI Mode HTML while preserving Markdown structure: headings, bold, code blocks, bullet lists.
- Scrub — 15 regex patterns for API keys (OpenAI, Anthropic, Google, AWS, Slack), JWTs, Sentry DSNs, private keys, emails, home directories, Windows paths, and IPv4. All local — nothing leaves the browser.
- Convert — 4 output formats: Claude Code (tested with DEV.to), Codex, GitHub Copilot, Markdown.
-
Validate and fix — catches the exact issues that cause
0 messages foundin DEV.to's parser.
The interesting part is not that it works. It is why it needs to exist. DEV.to's agent-session schema is undocumented. To produce a valid upload, you need the exact structure Claude Code writes to ~/.claude/projects/... — and any deviation (a stray session_meta line, an _title field, assistant content as a string instead of an array) silently fails with 0 messages found.
I reverse-engineered it over one afternoon. Documented it so you never have to.
If it ships, it will include:
- Browser tool (zero install, all local)
- CLI with
--url(Playwright),--from-console,--interactive,--slice - Bookmarklet generator
- Chrome extension (Manifest V3)
- GitHub Action
-
.geminiignorefor custom scrub patterns - Plugin system for ChatGPT, Claude.ai, and future sources
-
--dry-rundiff view
For the DEV.to team (feedback while building)
While building the tool, I ran into some rough edges in /agent_sessions/new that I think would save the next developer a few hours. The upload page already lists the six supported tools — that part is clear. The friction was somewhere else.
Context: my source is Google Gemini AI Mode (the web chat at share.google/aimode/...), which is different from Gemini CLI (the local command-line tool that DEV.to already supports). Gemini AI Mode has no native export. So I had to convert my conversation into a valid Claude Code session to get it through the parser. That is a bridge, not a match — and the parser did not make the bridge easy.
Here is what I would genuinely love to see:
1. Error diagnostics that say why it failed
When parsing fails, I get:
0 messages found
But I don't know if that means:
- Wrong tool selected — file is Claude Code but user picked Codex
- File malformed — required field is missing
-
File starts with something unexpected — e.g., a
session_metaline that isn't real Codex metadata - File is a completely different format — user is trying to upload from a tool DEV.to doesn't support yet
Something like:
Parse failed: no valid message lines found.
Detected line types:
Line 1: type="session_meta" — not supported for Claude Code
Line 2: type="user" — looks like Claude Code
Line 3: type="assistant" — looks like Claude Code
Hint: line 1 appears to be from a different format.
Try removing it, or select a different tool from the dropdown.
would have saved me three hours.
2. Distinguish "wrong tool" from "malformed file"
These are very different problems that currently produce the same silent 0 messages found:
- Wrong tool: user selected Codex but uploaded a Claude Code session
- Malformed file: correct tool, but a required field is missing
Quick hints in the error panel would help:
- "File looks like Claude Code — try selecting it from the dropdown."
- "Expected
message.rolein line 3. Found:_title."
3. Consider native support for "Gemini AI Mode" (web)
The list currently includes Gemini CLI (the local CLI tool at ~/.gemini/tmp/session-*.json). But Gemini AI Mode — the web chat at share.google/aimode/... — is a distinct use case with no native export.
Adding a parser for AI Mode share links would let thousands of developers share their Gemini web conversations without needing a bridge tool. The fact that I built one is proof of demand.
4. A generic ChatML fallback for unsupported tools
If auto-detection fails, offer a "Upload as generic format" option:
{"role": "user", "content": "..."}
{"role": "assistant", "content": "..."}
Any LLM transcript would work — Gemini AI Mode, Mistral, local models, etc. You would not need to add an extractor for every tool. This single fallback would make the upload page universal.
5. Preview three turns after successful parse
Not as a defensive "catch mistakes early" — as a confirmation that extraction worked as intended. Right now, when a file finally uploads, I still worry: did all turns make it? Is the Markdown intact? A quick preview in the curation UI would answer that in two seconds.
If anyone from the Forem team is reading this, I am happy to open detailed issues or PRs for any of the above. The tool I built is a workaround for one specific gap — but the underlying improvements would help every tool in this space.
One last thing
Here is what I would love from you, dear reader:
- Try the prompt above with your favorite LLM. Tell me what it says. I want to build a small museum of "inaccessible" responses.
- If you have built alone and felt the silence — comment. Even a single emoji.
- If you want to test the tool before I release it — ping me on X.
The ghost is out there, waiting. 🕯️
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.

