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

What I Built

Every developer's bookmark folder is a quiet graveyard of good intentions. Over the last eight years, I bookmarked 1,832 posts on X/Twitter — clever Unity water shaders from 2019, procedural foliage breakdowns, weekend game-jam physics toys, and open-weight model releases — telling myself "I'll build something with this on Saturday." Almost none of them were ever opened again.

For Week 4: Ghost in the Machine — where Halloween meets Día de los Muertos — I built Ghosts of the Feed: an interactive digital ofrenda (altar) that honors those forgotten ideas and lets them speak back.

Instead of a cold productivity dashboard, Ghosts of the Feed treats every saved post as a spirit waiting in the dark:

  • Candlelit Ofrenda Shelf: Each bookmark is placed on a velvet altar card with a flickering votive flame, a badge showing how long it has waited (some for 8 years), and a pulsing marigold whisper ("Unheard since you bookmarked me — Light candle & listen →").
  • In-Browser Séance with Google Gemma 3 270M: When you bring a card to the altar and press ✦ Summon this ghost, onnx-community/gemma-3-270m-it-ONNX runs 100% locally inside a browser Web Worker via @huggingface/transformers. Speaking in the first person as that forgotten post, Gemma remembers what it was when you saved it and proposes one concrete thing you can still build with it today.
  • Spectral Voice via ElevenLabs: As soon as Gemma finishes writing the ghost's response, ElevenLabs (eleven_multilingual_v2) speaks the epitaph aloud while the altar candle flares in sync (with a zero-config Web Speech fallback for judges testing without an API key).
  • Eternal Memory & Hybrid Search via Tiger Data: Powered by Tiger Cloud (TimescaleDB + pgvector + pg_textsearch), the app tracks your bookmark history in time-partitioned hypertables, fuses semantic vector search (halfvec(384)) with BM25 keyword search via Reciprocal Rank Fusion (RRF), and permanently carves each summoned ghost's epitaph into stone so answered spirits turn jade on the shelf (Put to Rest).

Demo

1. The Candlelit Altar Shrine (Gemma 3 270M in-browser ONNX + ElevenLabs neural voice)

Ghosts of the Feed — Altar Shrine

2. The Ofrenda Shelf & Timeline of the Unanswered (TimescaleDB Continuous Aggregate + seance_rituals Hypertable)

Ghosts of the Feed — Ofrenda Cards & Timeline

3. Hybrid Semantic + Keyword Search (pgvector HNSW Cosine + pg_textsearch BM25 via Reciprocal Rank Fusion)

Ghosts of the Feed — Tiger Data Hybrid RRF Search

Run the Demo Locally in 60 Seconds (Zero Login or API Keys Required)

git clone https://github.com/eduardconstantin/ghosts-of-the-feed.git cd ghosts-of-the-feed npm install npm run dev 
  1. Open http://localhost:5173. The repo ships with public/bookmarks-demo.json and a pre-seeded Tiger Data snapshot (src/tiger-cache.json) so the timeline, hybrid RRF search, and séance work out of the box with zero credentials.
  2. Click any offering card on the shelf (or filter by year in the Timeline of the Unanswered (2018 – 2026) bar chart).
  3. Click ✦ Summon this ghost at the altar. On the first summon, Gemma 3 270M (fp16 ONNX) downloads into your browser cache and generates the ghost's first-person reply on your machine.
  4. Type a mood or concept into the search bar — e.g. abandoned shader water unity — to see Tiger Data Reciprocal Rank Fusion rank ghosts by combined pgvector HNSW cosine similarity (VEC #1) and pg_textsearch BM25 rank (BM25 #2).
  5. (Optional) Add ELEVENLABS_API_KEY and TIGER_DATABASE_URL in .env (see .env.example) to enable live ElevenLabs neural speech and live Tiger Cloud writes.

Code

Ghosts of the Feed

An interactive Día de los Muertos ofrenda for forgotten X/Twitter bookmarks — powered by in-browser open-weight AI (Gemma 3 270M), ElevenLabs neural voice, and Tiger Data (TimescaleDB + pgvector + pg_textsearch BM25).

Built for the Hacktoberfest 2026 Open-Source AI Challenge: Week 4 ("Ghost in the Machine").

Ghosts of the Feed — Candlelit Altar Shrine

Screenshots

1. The Altar Shrine (Gemma 3 270M + ElevenLabs + Tiger Data)

Ghosts of the Feed Altar Shrine

2. The Ofrenda Shelf & Timeline of the Unanswered (TimescaleDB Continuous Aggregate)

Ghosts of the Feed Ofrenda Shelf

3. Hybrid Semantic + Keyword Search (pgvector HNSW Cosine + pg_textsearch BM25 RRF)

Tiger Data Hybrid RRF Search

Why We Built It

Every developer's X bookmarks folder is a graveyard of good intentions — shaders we meant to study, papers we swore we'd read, weekend game-jam mechanics from seven years ago that we saved and never opened again.

In the spirit of Día de los Muertos and Ghost in the Machine…




How I Built It

flowchart LR subgraph Browser["Browser (Local Private Archive)"] UI["Día de los Muertos Altar & Ofrenda Shelf"] WW["Web Worker: Gemma 3 270M (fp16 ONNX)"] UI -->|"1. Summon ghost"| WW WW -->|"2. First-person epitaph"| UI end subgraph ViteServer["Local Vite Middleware (/api/*)"] SPEAK["POST /api/speak"] SEARCH["GET /api/tiger/search"] REST["POST /api/tiger/rest"] MINILM["Open-Weight MiniLM-L6-v2 (384-d halfvec)"] SEARCH --> MINILM end subgraph PartnerTech["Partner Technologies"] EL["ElevenLabs TTS API (eleven_multilingual_v2)"] TIGER[("Tiger Data: TimescaleDB Hypertables + pgvector HNSW + BM25")] end UI -->|"3. Speak aloud"| SPEAK --> EL UI -->|"4. Carve epitaph"| REST --> TIGER UI -->|"Hybrid RRF query"| SEARCH --> TIGER

Step 1: Exporting 1,832 X Bookmarks with @steipete/bird & the x-bookmarks Skill

Getting your own bookmarks out of X/Twitter without paying for an enterprise API tier was the first hurdle we solved. We used the open-source x-bookmarks agent skill together with @steipete/bird — a fast GraphQL CLI for X that authenticates using your existing local browser session.

  1. Install the real bird CLI (watch out for the npm name collision!): Many READMEs say npm i -g bird-cli, which actually installs an unrelated scaffolding package on npm. The real X/Twitter CLI is @steipete/bird:
 npm install -g @steipete/bird@0.8.0 npx -y skills add sharbelxyz/x-bookmarks -g -y 
  1. Close your browser & verify your session (bird whoami): Chromium-based browsers (Chrome, Brave, Edge, Opera) lock their SQLite Network/Cookies database while running, and cookie expiration timestamps (expires_utc) in modern Chromium profiles exceed 53-bit JavaScript numbers (13471969281000000), which requires Node 24+ (node:sqlite with readBigInts: true).
 # Chrome / Brave default profile: bird --cookie-source chrome --chrome-profile "Default" whoami # Opera / custom Chromium profile directory: bird --cookie-source chrome --chrome-profile-dir "/path/to/Opera Stable/Default" whoami 
  1. Export all bookmarks to JSON (--all --json): Once bird whoami prints your handle, paginate through your entire bookmark history and write it to public/bookmarks.json (which is gitignored so your personal archive is never committed):
 bird --plain \ --cookie-source chrome \ --chrome-profile "Default" \ bookmarks --all --json > public/bookmarks.json 

Alternative (X API v2 OAuth 2.0 PKCE): If you prefer not to use browser cookies, the x-bookmarks skill also includes scripts/x_api_auth.py and scripts/fetch_bookmarks_api.py, which output the exact same { "tweets": [...] } JSON schema. You can also upload any export file directly in the app via the Load another export button on the shelf.

Step 2: Repairing Code Page 437 Mojibake (src/repair.js)

Our Windows shell redirection initially mangled UTF-8 curly apostrophes and emojis through Code Page 437 (What’s became WhatΓÇÖs). Writing a 30-line CP437-to-UTF-8 byte decoder (src/repair.js) restored all 1,832 bookmarks cleanly before embedding them.

Step 3: In-Browser Gemma 3 270M & Fixing GatherBlockQuantized

We ran onnx-community/gemma-3-270m-it-ONNX inside a dedicated Web Worker (src/seance.worker.js) so token generation never blocks the candle animations. When we first tested the 4-bit quantized graph (model_q4.onnx), ONNX Runtime Web threw:

Can't create a session. ERROR_CODE: 9, ERROR_MESSAGE: Could not find an implementation for GatherBlockQuantized(1) node with name '/model/embed_tokens/Gather_Quant'

Because the ONNX graphs are open on Hugging Face, we inspected the operator nodes across model_q4.onnx, model_quantized.onnx, and model_fp16.onnx, verified that fp16 avoids GatherBlockQuantized, and switched the worker cleanly:

// src/seance.worker.js import { pipeline, env } from "@huggingface/transformers"; env.allowLocalModels = false; const MODEL = "onnx-community/gemma-3-270m-it-ONNX"; let generator = await pipeline("text-generation", MODEL, { dtype: "fp16", // Avoids GatherBlockQuantized op unsupported in WASM runtime progress_callback: (update) => self.postMessage({ type: "progress", update }), }); 

Step 4: Tiger Data Hypertables, Continuous Aggregates & Hybrid RRF Search

Using the Tiger MCP gateway connected to our Tiger Cloud service (TimescaleDB 2.30.2 + pgvector 0.8.7 + pg_textsearch 1.5.1), we created:

  1. ghost_bookmarks & seance_rituals hypertables with columnstore compression (tsdb.enable_columnstore = true) and a real-time continuous aggregate (ghost_bookmarks_yearly using time_bucket(INTERVAL '1 year', spoken_at)).
  2. ghost_souls hybrid search table storing 384-dimensional halfvec(384) embeddings from open-weight Xenova/all-MiniLM-L6-v2 indexed with HNSW (halfvec_cosine_ops) alongside a pg_textsearch BM25 index (USING bm25 (content) WITH (text_config = 'english')).
  3. Single-query Reciprocal Rank Fusion (rrf_search_ghosts):
CREATE OR REPLACE FUNCTION rrf_search_ghosts( query_text TEXT, query_vec halfvec(384), match_limit INT DEFAULT 36 ) RETURNS TABLE ( tweet_id TEXT, rrf_score DOUBLE PRECISION, semantic_rank BIGINT, bm25_rank BIGINT ) LANGUAGE sql STABLE AS $$ WITH semantic AS ( SELECT g.tweet_id, ROW_NUMBER() OVER (ORDER BY g.embedding <=> query_vec) AS s_rank FROM ghost_souls g WHERE g.embedding IS NOT NULL ORDER BY g.embedding <=> query_vec LIMIT 60 ), keyword AS ( SELECT g.tweet_id, ROW_NUMBER() OVER (ORDER BY g.content <@> to_bm25query(query_text, 'ghost_souls_bm25_idx')) AS k_rank FROM ghost_souls g WHERE query_text IS NOT NULL AND btrim(query_text) <> '' ORDER BY g.content <@> to_bm25query(query_text, 'ghost_souls_bm25_idx') LIMIT 60 ) SELECT COALESCE(s.tweet_id, k.tweet_id) AS tweet_id, (COALESCE(2.0 / (60 + s.s_rank), 0.0) + COALESCE(1.0 / (60 + k.k_rank), 0.0))::DOUBLE PRECISION AS rrf_score, s.s_rank AS semantic_rank, k.k_rank AS bm25_rank FROM semantic s FULL OUTER JOIN keyword k ON s.tweet_id = k.tweet_id ORDER BY rrf_score DESC LIMIT match_limit; $$; 

Why Does Open Innovation Matter?

Our social-media bookmarks are an intimate map of our curiosity — years of late-night rabbit holes, half-formed side projects, and personal tastes.

  1. Your personal archive stays on your machine: By running Gemma 3 270M (onnx-community/gemma-3-270m-it-ONNX) directly inside a browser Web Worker and embedding queries locally with open-weight MiniLM-L6-v2 (Xenova/all-MiniLM-L6-v2), you don't have to upload your entire private bookmark export to a proprietary LLM API just to reflect on what you saved.
  2. Works after platforms and APIs change: Twitter/X has repeatedly locked down its API pricing and endpoints. Paired with open-source export tooling (@steipete/bird), open PostgreSQL extensions (TimescaleDB, pgvector, pg_textsearch), and open-weight ONNX models cached in the browser, your ofrenda keeps working even when the lights (or the internet) go out.
  3. Inspectable & repairable when things break: When the 4-bit Gemma graph failed on GatherBlockQuantized in WASM, open weights and open ONNX graphs meant we could inspect the exact operator nodes and switch to fp16 in minutes instead of waiting on a black-box vendor ticket.

My Agent Session & How We Used DevRelay

I built Ghosts of the Feed in Cursor with an AI coding agent, using DevRelay (devrelay-challenges, devrelay-knowledge, devrelay-sponsor-skills, and devrelay-publishing) alongside the Tiger MCP gateway throughout the entire build:

  1. Discovering the Challenge & Rubric via DevRelay: We used the devrelay-challenges skill and the DEV Events API (full_details on Event #82) together with the authoritative DevRelay Knowledge Base (https://devrelay.com/knowledge/dev-challenges, /knowledge/hacktoberfest, and /knowledge/dev-guidelines) to inspect the exact Week 4: Ghost in the Machine theme, submission rules, required tags (#hf26challenge, #devchallenge), and partner prize tracks before writing a single line of code.
  2. Exporting the X Archive Safely: The agent installed the x-bookmarks skill and @steipete/bird, diagnosed the Opera SQLite lock and Node 24 readBigInts requirement for Chromium cookie timestamps, and exported all 1,832 bookmarks locally.
  3. Provisioning Tiger Data with Official Agent Skills: Using Tiger MCP's view_skill (setup-timescaledb-hypertables, pgvector-semantic-search, and postgres-hybrid-text-search), the agent provisioned the ghost_bookmarks and seance_rituals hypertables, the ghost_bookmarks_yearly continuous aggregate, and the halfvec(384) HNSW + BM25 Reciprocal Rank Fusion function directly on our Tiger Cloud service.
  4. Iterating on the Día de los Muertos Altar UI: Using live browser snapshots, we evolved the UI from a simple grid into a candlelit retablo shrine with velvet votive cards, flickering flames, and real-time Tiger Data telemetry, and structured this submission post using devrelay-publishing.

The Spirit of It

Día de los Muertos isn't about ghosts that scare you — it's about setting out a candle and remembering the voices and sparks that shaped you. Every bookmark in that folder was a moment where something made you stop scrolling and think, "I want to build that someday." Putting them on an ofrenda lets them ask for one more chance.

Prize Categories

  • Best Use of Gemma: Runs Google's open-weight gemma-3-270m-it (onnx-community/gemma-3-270m-it-ONNX) 100% in-browser inside a Web Worker (fp16 ONNX) to channel each forgotten bookmark in the first person.
  • Best Use of ElevenLabs: Gives every summoned bookmark a spoken neural voice via eleven_multilingual_v2 through a secure local server route (/api/speak), synchronized with the altar's flickering candle.
  • Best Use of Tiger Data: Combines TimescaleDB hypertables (ghost_bookmarks, seance_rituals), a real-time time_bucket continuous aggregate (ghost_bookmarks_yearly), and in-database Reciprocal Rank Fusion across pgvector (halfvec(384) HNSW cosine) and pg_textsearch (BM25 <@>).