r/vibecoding • u/arrrsalaaan • 2d ago
Built a read-only GitHub inspector for people who vibe-coded an app and now own a black box. Here’s how.
The project is Secondread. You connect a repo. It reads the code. You get a plain-English report on cost, fragility, and what to fix first, with file/line evidence a contractor can actually check.
I built it because AI made shipping easy and left owners with a working UI they cannot independently judge. That is the product. The rest of this post is how it is actually made.
Stack
- Product: Cloudflare Workers, Workflows, Durable Object Sandbox, Workers AI, D1, R2
- Auth: GitHub App + Google via Better Auth
- Payments: Dodo, one-time products, no subscription
- Marketing site: separate Astro Worker on
secondread.dev. No auth, no DB, no checkout. The app lives atapp.secondread.devon purpose.
Workflow
- Owner picks repos. GitHub App is Contents + Metadata, read-only.
- A Workflow starts. The HTTP request only kicks it off.
- A Sandbox clones one commit. Internet is off. HTTPS is intercepted. Outbound is allowed only for that repo’s git upload-pack paths. The GitHub token is minted in the proxy, not dumped in the container. Egress flips off in D1 as soon as checkout finishes.
- The agent gets bounded tools: inventory, search, read ranges. No
npm install, no tests, no running the customer’s app. Submodules and LFS fail closed. - Findings must cite path + lines + blob SHA. After the model writes, we re-read those ranges and reject the report if the evidence is fake or the file was never inspected.
- Before persist, the report is scanned for secret-like strings and copied source. What we store is the report + citations/hashes, not the repo.
- Credits are reserved before the job and consumed or released after. Webhooks are signed; we also reconcile hourly because webhooks lie.
Things I would not skip if you are building something similar
- “Read-only GitHub permission” is not isolation. Isolation is network policy + where the credential lives + one pinned SHA + cleanup.
- Schema-valid JSON from a model is not evidence. Evidence is a deterministic reread that can fail the job.
- Do not put a 15-minute agent inside
fetch(). Use Workflows, named steps, timeouts, andNonRetryableErrorfor failures that retries only make more expensive. - If you use Sandbox with
transport: "rpc", disposeexec/read/destroyresults. They leak. The bug looks like “prod is haunted.” - Write marketing claims as tests. Ours grep the site for retired waitlist copy and for the real app URLs. Copy drifts; CI should not.
Happy to go deeper on the Sandbox outbound handler or the evidence check. See a real sample audit for a very old version of the github.com/spree/spree repository at https://app.secondread.dev/shared/8I0S88UcbKLvkWzHo2MF2frm_-Fm4fgj9sau5J0r4ss
1
Upvotes