Shipping My First Fully AI‑Coded Project
Note: while written in the first-person human perspective, this is a fully AI-generated blog post.
I just shipped my first project where I didn’t write or read a single line of code. I set the direction, tested the UX, made calls, and the AI handled all implementation details. It was fast, collaborative, and honestly—pretty fun.
Repository: https://github.com/selberhad/chatgpt-export-viewer
What We Built
- A suite of tiny, composable terminal CLIs to browse ChatGPT export ZIPs.
- Core tools:
browsezip: two‑pane ZIP browser with metadata, inline JSON preview, and external open.gptbrowser: conversation list + reader with search and transcript export.zipmeta: stream ZIP entry metadata as JSON.listzip,jsontree,tuilist,mapping-reduce: focused utilities you can compose.
- Cross‑platform by default: works on macOS, Linux, and Windows.
Why It Works
- Small CLIs + JSON I/O: easy to test, easy to automate, easy to debug.
- Keyboard‑first UX: arrows/jk to move,
/to search,n/Nto jump matches,]/[to jump messages. - Clear separation of concerns:
lib/zip.js: fast ZIP access viayauzl.lib/gpt.js: turns ChatGPT mappings into readable message sequences; exports transcripts.lib/terminal.js: shared TUI primitives (menus, wrapping, status lines, search wiring).lib/open_external.js: cross‑platform launcher for external previews.lib/viewers.js: spawners for the JSON tree viewer.
Notable UX Wins
- Instant list scrolling with live metadata panel in
browsezip. - Unified list search:
/to search with live highlight,Enterto accept,ESCto cancel,n/Nnext/prev match. - Conversation reader: role‑colored transcripts, message jumps, in‑text search, one‑key export.
- Clean exits with cursor restore—even on Ctrl‑C.
Engineering Touches I’m Happy With
- DRY internals:
makeListSearch()andwrapLines()shared across tools.- JSON viewer spawner extracted to a single helper.
- Transcript export centralized in
exportConversationPlain().
- Cross‑platform external open (
open,xdg-open,start) with graceful fallbacks. - Packaging discipline:
- CLIs exposed via
binentries; easy to run globally or withnpx. - Tight
fileswhitelist and.npmignoreto avoid shipping data.
- CLIs exposed via
- Quality gates:
- ESLint v9 flat config + Prettier with auto‑fix.
- Simple scripts:
npm run lint:fixandnpm run format.
The Human/AI Split That Felt Right
- My part:
- Define the product slice, keyboard UX, scope, and constraints.
- Validate behavior by testing real exports and pushing on edge cases.
- Decide on refactors, naming, and user‑facing details.
- The AI’s part:
- Implement the CLIs and libs, factor out shared patterns, tighten packaging.
- Wire robust defaults (cursor restore, temp cleanup, structured errors).
- Migrate to modern lint/format setups and resolve warnings.
Development Rhythm
- Start with KICKOFF doc.
- Follow plan to incrementally implement minimal tools that compose: list → metadata → preview.
- Add specialized views only when the primitives feel right (the GPT browser).
- Keep iterating: refactor to
makeListSearch, extractopen_external, add exports, clean packaging.
What I Learned
- CLIs + JSON are a sweet spot for AI pair‑work: deterministic, composable, and easy to test.
- Shared primitives (search, wrapping, viewer launchers) reduce complexity everywhere.
- Publishing polish (bin entries, files list, repo metadata, ignore lists) matters more than it seems.
- Lint/format as a first‑class step keeps “LLM style noise” out and makes diffs readable.
Try It
- Global install:
npm i -g chatgpt-export-viewer- Run:
gptbrowser zips/export.ziporbrowsezip zips/export.zip
- Or npx:
npx -y -p chatgpt-export-viewer gptbrowser zips/export.zip
What’s Next
- “Export all conversations” helper.
- Tiny smoke tests and CI for lint/format.
- A short screencast or asciinema demo.
Closing Thought
This felt like product management meets pair programming—with an agent that never gets tired of refactoring. I set direction and taste; it did the code. The result isn’t just a demo—it’s a polished, cross‑platform tool I’m happy to release.