This is a submission for the GitHub Finish-Up-A-Thon Challenge
What I Built
ASTronaut is a personal code snippet manager that uses GitHub Gists as its storage backend. The name is a dumb pun: it literally builds an AST (Abstract Syntax Tree) of your Java snippets using JavaParser, pulling out class and method names so you can search by structure, not just by file name.
The idea is simple: stop losing useful snippets to random notes apps or Gist pages you'll never find again. ASTronaut gives you a proper UI to create, search, edit, diff, and organize your snippets, while keeping everything synced to GitHub Gists so nothing is stuck on one machine.
Frontend Repository: https://github.com/kusoroadeolu/astronaut-ui
Backend Repository: https://github.com/kusoroadeolu/ASTronaut
The Comeback Story
The original ASTronaut had PostgreSQL, Redis, Spring Security, JWT auth, a full login/register flow, user management, admin roles, rate limiting... for a tool that only I was ever going to use.
It never shipped. Not because it didn't work, but because every time I sat down to actually use it, I had to spin up a database, a Redis instance, deal with tokens. It just killed any motivation I had. The whole point was to save me time. It wasn't doing that.
So it sat there. For a while.
When I heard about the Finish-Up-A-Thon, this was the first project that came to mind.
What Actually Changed
The revamp had one goal: make it feel like a tool, not a project.
Here's what got cut:
- The entire auth system: Spring Security, JWT, login/register, user management, all of it
- PostgreSQL and JPA, replaced by a lightweight local JSON index file
- Redis and rate limiting, pointless for a solo local tool
- Deep metadata extraction that was never actually used in search
Here's what replaced it:
- GitHub PAT in an
application.propsfile. One line of config, no OAuth flow, no callback URLs. PAT is the right call here: OAuth is for when other people are logging in with their GitHub accounts. This is just me. - GitHub Gists as storage, one Gist per snippet, no database needed
- A local JSON index loaded into a
HashMapon startup, search runs in-memory, instant, no GitHub API call on every query - A proper frontend built to spec, bundled directly into the Spring Boot JAR
The backend went from a multi-service setup to a single Spring Boot app with zero external runtime dependencies. Setup went from "spin up Docker, run migrations, configure Redis" to "add your GitHub PAT, run the JAR." That's it.
The finish line for this challenge was wiring the frontend into the JAR so everything ships as one artifact: no separate frontend process, no Node.js required to run it. That's the piece that finally made it feel done.
How The Index Works
One thing I'm kind of proud of is the index setup. Instead of hitting the GitHub API on every search, the app keeps a single dedicated Gist with the description "index.json" that acts as a local metadata store. On startup it finds that Gist (or creates it if it doesn't exist), loads it into a HashMap, and all search filtering happens in memory from there.
{
"abc123": {
"gistId": "abc123",
"name": "Spring filter chain",
"language": "JAVA",
"tags": ["spring", "security"],
"methodNames": ["doFilter", "configure"],
"classNames": ["SecurityConfig"]
}
}
Search supports structured syntax like tag:utility; language:java; method-name:parse and bare terms that match across everything. It's fast. Way faster than the old DB approach at the scale this is meant for.
The Frontend
The UI was built spec-first. Before writing any code I laid out every decision: layout, color palette, typography, component choices, how each view should behave. The whole thing.
Three column layout: narrow sidebar for navigation, snippet list in the middle, wide main panel for content. Full monospace stack across the whole UI (not just the editor) to push the "developer tool" feel. Dark theme, no gradients, no glows, nothing decorative that doesn't earn its place.
The main views:
- Snippet view with CodeMirror syntax highlighting (read-only)
- Create/edit form with a live CodeMirror editor
- Diff view: the backend returns parsed
DiffLineobjects withADDED,REMOVED,UNCHANGEDtypes, so the frontend just renders them, no diff library needed on the client - A command palette style compare flow: hit compare on any snippet, a modal opens with a search bar, pick another snippet, diff view loads
My Experience with GitHub Copilot
I used Copilot for the entire frontend. The backend was written by hand, but the React/TypeScript side was Copilot-first throughout, with me reviewing everything carefully.
The spec-first approach made a real difference here. Copilot is a lot more useful when it has actual context: visual style, component choices, interaction patterns, rather than just "build me a snippet manager". Vague prompts got vague results. Specific prompts with context got stuff I could actually use.
Where it genuinely helped:
The three-column layout: getting the shadcn/ui components wired up correctly from the start, not fighting them later.
CodeMirror 6: the API is not the most intuitive thing to work with. Copilot got the read-only viewer and the editor both working with the right extensions without a ton of back and forth.
The diff view: since the backend does the heavy lifting, the frontend just needs to render lines with the right colors. Copilot handled that cleanly.
The compare flow: the command palette modal with inline search filtering was generated almost entirely from a description of how the interaction should feel.
Honestly the biggest thing I learned is that the quality of what Copilot produces is pretty directly tied to the quality of context you give it. The spec paid off.
Demo
That's pretty much it. Is it perfect? No. But it actually runs, it's actually useful, and it finally feels like something I'd open instead of something I'd avoid. That's a win imo.
Top comments (0)