Skip to content

Commit cbc53a5

Browse files
Xeclaude
andauthored
blog: add vibe coding sponsor panel trip report (#1163)
* blog: add vibe coding sponsor panel trip report Write up the experience of using AI agent teams with prepared skills to build the GitHub sponsor panel at sponsors.xeiaso.net before surgery. https://claude.ai/code/session_01TFnfEpQstoqBfVwKgDwKU7 * blog: revise sponsor panel post for clarity and voice Apply stop-slop review: remove throat-clearing openers, cut overused intensifiers, fix binary contrast patterns, tighten prose per Strunk. Fix successive-paragraph rule violations and eliminate repeated phrasing. https://claude.ai/code/session_01TFnfEpQstoqBfVwKgDwKU7 * blog: second editing pass on sponsor panel post Remove remaining slop: binary contrasts, throat-clearing, pull-quotable aphorisms, redundant "three attempts" mentions, filler intensifiers. Tighten bullet descriptions, vary paragraph structure, add concrete details to closing section. https://claude.ai/code/session_01TFnfEpQstoqBfVwKgDwKU7 * blog: third editing pass on sponsor panel post Fix remaining slop: binary contrast (worst/best case), false transformation arc (stops X starts Y), filler intensifier, staccato fragmentation, question-answered-immediately pattern. Eliminate word echoes across nearby paragraphs. Tighten per Strunk. https://claude.ai/code/session_01TFnfEpQstoqBfVwKgDwKU7 * blog: fourth editing pass on sponsor panel post Fix comma splice (Strunk Rule 5), trim redundant relative clause, de-duplicate "previous attempts" phrasing between intro and body. https://claude.ai/code/session_01TFnfEpQstoqBfVwKgDwKU7 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent b93707b commit cbc53a5

1 file changed

Lines changed: 133 additions & 0 deletions

File tree

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
---
2+
title: "Vibe Coding Trip Report: Making a sponsor panel"
3+
desc: "I needed to ship this before my surgery, so I vibe coded it. It turned out well enough."
4+
date: 2026-03-09
5+
hero:
6+
ai: ""
7+
file: ""
8+
prompt: ""
9+
social: false
10+
---
11+
12+
import Conv from "../../_components/XeblogConv.tsx";
13+
14+
I'm on [medical leave recovering from surgery](/blog/2026/killing-my-inner-necron/). Before I went under, I wanted to ship one thing I'd been failing to build for months: a sponsor panel at [sponsors.xeiaso.net](https://sponsors.xeiaso.net). Previous attempts kept dying in the GraphQL swamp. This time I vibe coded it — pointed agent teams at the problem with prepared skills and let them generate the gnarly code I couldn't write myself.
15+
16+
And it works.
17+
18+
## The GraphQL swamp
19+
20+
Go and GraphQL are oil and water. I've held this opinion for years and nothing has changed it. The library ecosystem is a mess: [shurcooL/graphql](https://github.com/shurcooL/graphql) requires abusive struct tags for its reflection-based query generation, and the code generation tools produce mountains of boilerplate. All of it feels like fighting the language into doing something it actively resists.
21+
22+
<Conv name="Cadey" mood="coffee">
23+
GitHub removing the GraphQL explorer made this even worse. You used to be able
24+
to poke around the schema interactively and figure out what queries you
25+
needed. Now you're reading docs and guessing. Fun.
26+
</Conv>
27+
28+
I'd tried building this panel before, and each attempt died in that swamp. I'd get partway through wrestling the GitHub Sponsors API into Go structs, lose momentum, and shelve it. At roughly the same point each time: when the query I needed turned out to be four levels of nested connections deep and the struct tags looked like someone fell asleep on their keyboard.
29+
30+
Vibe coding was a hail mary. I figured if it didn't work, I was no worse off. If it did, I'd ship something before disappearing into a hospital for a week.
31+
32+
## Preparing the skills
33+
34+
Vibe coding is not "type a prompt and pray." Output quality depends on the context you feed the model. Templ — the Go HTML templating library I use — barely exists in LLM training data. Ask Claude Code to write Templ components cold and it'll hallucinate syntax that looks plausible but doesn't compile. Ask me how I know.
35+
36+
<Conv name="Aoi" mood="wut">
37+
Wait, so how do you fix that?
38+
</Conv>
39+
40+
I wrote four agent skills to load into the context window:
41+
42+
- **templ-syntax**: Templ's actual syntax, with enough detail that the model can look up expressions, conditionals, and loops instead of guessing.
43+
- **templ-components**: Reusable component patterns — props, children, composition. Obvious if you've used Templ, impossible to infer from sparse training data.
44+
- **templ-htmx**: The gotchas when combining Templ with HTMX. Attribute rendering and event handling trip up humans and models alike.
45+
- **templ-http**: Wiring Templ into `net/http` handlers properly — routes, data passing, request lifecycle.
46+
47+
With these loaded, the model copies patterns from authoritative references instead of inventing syntax from vibes. Most of the generated Templ code compiled on the first try, which is more than I can say for my manual attempts.
48+
49+
<Conv name="Mara" mood="hacker">
50+
Think of it like giving someone a cookbook instead of asking them to invent
51+
recipes from first principles. The ingredients are the same, but the results
52+
are dramatically more consistent.
53+
</Conv>
54+
55+
## Building the thing
56+
57+
I pointed an agent team at a spec I'd written with [Mimi](https://mimi.xeserv.us). The spec covered the basics: OAuth login via GitHub, query the Sponsors API, render a panel showing who sponsors me and at what tier, store sponsor logos in [Tigris](https://www.tigrisdata.com/).
58+
59+
<Conv name="Cadey" mood="enby">
60+
I'm not going to pretend I wrote the spec alone. I talked through the
61+
requirements with Mimi and iterated on it until it was clear enough for an
62+
agent team to execute. The full spec is available as a gist if you want to
63+
see what "clear enough for agents" looks like in practice.
64+
</Conv>
65+
66+
One agent team split the spec into tasks and started building. A second reviewed output and flagged issues. Meanwhile, I provisioned OAuth credentials in the GitHub developer settings, created the Neon Postgres database, and set up the Tigris bucket for sponsor logos. Agents would hit a point where they needed a credential, I'd paste it in, and they'd continue — ops work and code generation happening in parallel.
67+
68+
The GraphQL code the agents wrote is _ugly_. Raw query strings with manual JSON parsing that would make a linting tool weep. But it works. The shurcooL approach uses Go idioms, sure, but it requires so much gymnastics to handle nested connections that the cognitive load is worse. Agent-generated code is direct: send this query string, parse this JSON, done. I'd be embarrassed to show it at a code review. I'd also be embarrassed to admit how many times I failed to ship the "clean" version.
69+
70+
```go
71+
// This is roughly what the agent generated.
72+
// It's not pretty. It works.
73+
query := `{
74+
viewer {
75+
sponsors(first: 100) {
76+
nodes {
77+
... on User {
78+
login
79+
name
80+
avatarUrl
81+
}
82+
... on Organization {
83+
login
84+
name
85+
avatarUrl
86+
}
87+
}
88+
}
89+
}
90+
}`
91+
```
92+
93+
<Conv name="Numa" mood="neutral">
94+
This code exists because the "proper" way kept killing the project. I'll
95+
take ugly-and-shipped over clean-and-imaginary.
96+
</Conv>
97+
98+
## The stack
99+
100+
The full stack:
101+
102+
- **Go** for the backend, because that's what I know and what my site runs on
103+
- **Templ** for HTML rendering, because I'm tired of `html/template`'s limitations
104+
- **HTMX** for interactivity, because I refuse to write a React app for something this simple
105+
- **PostgreSQL** via [Neon](https://neon.tech/) for persistence
106+
- **GitHub OAuth** for authentication
107+
- **GitHub Sponsors GraphQL API** for the actual sponsor data
108+
- **[Tigris](https://www.tigrisdata.com/)** for sponsor logo storage — plugged it in and it Just Works™
109+
110+
## The warts
111+
112+
Org sponsorships are still broken. The schema for organization sponsors differs enough from individual sponsors that it needs its own query path and auth flow. I know what the fix looks like, but it requires reaching out to other devs who've cracked GitHub's org-level sponsor queries.
113+
114+
The code isn't my usual style either — JSON parsing that makes me wince, variable names that are functional but uninspired, missing error context in a few places. I'll rewrite chunks of this after I've recovered. The panel _exists_ now, though. It renders real data. People can OAuth in and see their sponsorship status. Before this attempt, it was vaporware.
115+
116+
<Conv name="Cadey" mood="percussive-maintenance">
117+
I've been telling people "just ship it" for years. Took vibe coding to make
118+
me actually do it myself.
119+
</Conv>
120+
121+
## What I actually learned
122+
123+
I wouldn't vibe code security-critical systems or anything I need to audit line-by-line. But this project had stopped me cold on every attempt, and vibe coding got it across the line in a weekend.
124+
125+
Skills made the difference here. Loading those four documents into the context window turned Claude Code from "plausible but broken Templ" into "working code on the first compile." I suspect that gap will only matter more as people try to use AI with libraries that aren't well-represented in training data.
126+
127+
This sponsor panel probably won't look anything like it does today in six months. I'll rewrite the GraphQL layer once I find a pattern that doesn't make me cringe. Org sponsorships still need work. HTMX might get replaced.
128+
129+
But it exists, and before my surgery, shipping mattered more than polish.
130+
131+
---
132+
133+
The sponsor panel is at [sponsors.xeiaso.net](https://sponsors.xeiaso.net). The skills are in [my site's repo](https://github.com/Xe/site) under `.claude/skills/`.

0 commit comments

Comments
 (0)