Inspiration
You see a repo on Instagram or TikTok, think "that's useful", and save it. You've already done the hard part — you found it and judged it worth keeping.
Then none of those platforms index saved posts. No titles, no notes, no search. So when you actually need that tool, it's gone, somewhere in a folder of a thousand saves.
The problem isn't discovery. It's losing what you already found.
What it does
repoherald rescues repos out of social saved folders.
Instead of saving a post, you send it. A sweep reads the caption, the on-screen text or the narration, works out which repository it is, and files it in a private list per platform — with a note on why you kept it. Claim your handle and everything you ever sent before you had an account is backfilled.
So the thing you found at 1am on your phone is still there, searchable, when you're at a keyboard and actually need it.
It runs in production at repoherald.com, and native iOS and Android clients are both in store review — because saving happens on a phone, and so should the rescue.
Underneath that sits a smaller promotion mechanic: starring someone else's repo mints a credit, and credits buy a highlight in the public feed. It's deliberately the secondary half — attention you give is what buys attention you get.
How we built it
The app is Next.js on the App Router in TypeScript, with Neon Postgres and Drizzle, Clerk for identity, Stripe for payments, and an Expo client sharing the same auth. It runs in production at repoherald.com.
For this hackathon the project was imported to GitLab and given the automation it never had — a pipeline covering all nine GitLab DevSecOps stages: plan, create, verify, package, secure, release, configure, monitor, govern. Fourteen jobs, including SAST, secret detection, dependency scanning, licence policy, production build, deploy, and post-deploy verification.
Most of it is what you'd expect. Three jobs aren't:
plan:impactasks what a change can break, before anything else runs.config:driftfails the build when the code reads an environment variable.env.examplenever declares — a fresh deploy breaking in production for a reason nobody can see.healthcheckpolls the live endpoint after deploy and fails if it never returns 200. That's what makes this a loop rather than a line.
GitLab Duo Agent Platform shows up in three forms:
.gitlab/duo/mcp.jsonmakes Duo an MCP client of repoherald's own production API, so it can query the live catalogue while it reviews..gitlab/duo/mr-review-instructions.yamlholds eight Code Review rules written from this project's real invariants — credit-ledger integrity, the WebSocket driver choice, migration ordering, derived-versus-cached state — rather than generic style advice..gitlab/duo/chat-rules.mdtells any agent working here where the expensive mistakes are.
Code Review and Fix CI/CD Pipeline foundational flows are both enabled.
Challenges we ran into
The build needed a database, and failed in the worst possible way. Several
pages fetch data at build time. With no DATABASE_URL in CI, the Neon WebSocket
driver doesn't fail fast — it hangs, so pages died silently at the 60-second
static-generation timeout with no useful error. The honest fix wasn't to make the
app dynamic everywhere, or to put a production credential in CI: it was to point
the build at a disposable database branch, so the pipeline proves the app
compiles without ever touching production data.
Every Duo control was greyed out, behind a message about foundational flows. That sent us hunting for a toggle in group settings, then project settings, then the docs. The toggle was never the problem — the group was on the Free tier, and Duo Agent Platform is a paid feature. The error message described a symptom, not the cause.
Emphasis. The credit ledger is the largest thing in the codebase, so reading the code pulls you toward the promotion mechanic. The actual product promise — rescuing what you already saved — lives in four small files. We drafted a whole pitch around the wrong half before catching it. Line count is not importance.
Accomplishments that we're proud of
We tested the automation honestly instead of just configuring it.
We opened a merge request designed to look reasonable and be wrong: it replaces a
timestamp-window check with a status = 'active' filter, argued as a performance
improvement, using an index that genuinely exists.
The pipeline failed it in 28 seconds — not on the query, but because the same
change read an environment variable .env.example never declared. The job named
the variable and the file.
Then Duo found three distinct failure modes in the query itself:
- An expired highlight whose status hasn't been flipped yet scores negative — burying the repo instead of promoting it.
- A highlight whose window hasn't opened yet gets boosted early.
- Because cursors pin an older timestamp, page two can rank differently from page one, skipping or duplicating rows.
It also found a second bug nobody planted: the new cache setting accepted negative and infinite values — and the setting couldn't help anyway, because the cache key already includes a rolling time bucket. It understood the caching model better than the commit message did.
It requested changes and blocked the merge. That merge request is public, and it's the link we'd most like judges to open.
The other thing we're proud of is smaller: the pipeline deploys, and then goes back and asks production whether it's actually up. Most pipelines stop at deploy.
What we learned
Every one of these came from building the automation, not from reading docs:
Jobs/License-Scanning.gitlab-ci.ymlis retired. Licence data now comes from Dependency Scanning's SBOM.- GitLab's security templates hardcode
stage: test, so a custom stage list has to define that stage even if nothing of its own uses it. healthcheckwas polling the deployment's*.vercel.apphostname, which 308s to the canonical domain. Withoutcurl -L, a 308 is not a 200 — the job would have failed on every deploy that ever reached it..env.examplehad never been committed in this project's history. The.env*ignore rule swallowed it. The repository didn't actually carry what someone needs to run it, andconfig:drifthad no file to read.- The admin screens were being prerendered against build-time database rows. Nobody noticed until a pipeline with no database made it impossible to ignore.
The pattern underneath all of them: automation is most valuable where it tells you something about your own codebase that you believed was already fine.
What's next for RepoHerald
- Sweeps beyond Instagram. The ingest path already records where a repo was spotted — caption, on-screen text or narration — so TikTok and Facebook are the same pipeline with different readers.
- The mobile apps out of review. Both the App Store and Play Store builds are submitted and awaiting approval. Once they land, sending a post to repoherald becomes a share-sheet action rather than a DM.
- An authenticated MCP server. Today Duo and Claude Code can query the public catalogue; your own saved lists need OAuth, which isn't built yet. That's the larger half of the original idea.
- Letting the agents do more than review. Fix CI/CD Pipeline is enabled but hasn't been given real work. The honest next step is handing an agent a failing pipeline and seeing how far it gets without us.
Built With
- agentic-ai
- clerk
- devsecops
- drizzle-orm
- expo.io
- github-api
- gitlab
- gitlab-ci-cd
- gitlab-duo
- mcp
- neon
- next.js
- node.js
- postgresql
- react
- sast
- secret-detection
- semgrep
- shadcn-ui
- stripe
- tailwindcss
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.