BLOG / VIBE-CODING
The App Has No Customers, but the Button Is Tremendous
Notes from an afternoon of vibe coding, accidental product strategy, and one suspiciously confident button.
I woke up with an idea.
Not a normal idea. A platform idea.
By 9:17 a.m., I had a domain name. By 9:24, I had a logo. By 9:31, I had changed the logo because the first one didn't communicate velocity.
Do I know what the product does?
Not entirely.
But the landing page loads in 0.4 seconds, and the button has a little bounce when you click it. That's product-market fit adjacent.
A startup is just a folder called final-final-v3 that somehow acquired a payment processor.The Pitch
The app is called Pigeon.
Pigeon is an asynchronous collaboration layer for people who are already collaborating asynchronously but would like another asynchronous layer on top of it.
The value proposition is simple:
- You write a thought.
- Pigeon puts the thought in a little digital envelope.
- Somebody else receives it at an emotionally appropriate time.
- Nobody schedules a meeting.
That fourth point is the moat.
You can view the extremely real project at jawdroppuh.lol, assuming I have connected the domain by the time you read this.
The Target Audience
Pigeon is designed for:
- Founders with seven unfinished Notion workspaces
- Developers who communicate primarily through commit messages
- Designers who say “let's explore this direction” with dangerous confidence
- People who have muted every workplace notification
- Anyone currently hiding from a calendar invitation
It is not designed for:
- Organizations with a procurement department
- People who ask for an Excel export during the first demo
- My accountant
- Anyone who knows what our infrastructure costs
The Technical Architecture
I wanted the architecture to be elegant, scalable, and easy to explain.
Instead, it is currently this:
person has thought
↓
React component
↓
mysterious function
↓
database, probably
↓
another person eventually sees thoughtThe frontend began as a single component.
export default function Pigeon() {
const [messages, setMessages] = useState<string[]>([]);
function releasePigeon(message: string) {
setMessages((current) => [...current, message]);
}
return (
<main>
<h1>Pigeon</h1>
<button onClick={() => releasePigeon("Important business thought")}>
Release the pigeon
</button>
</main>
);
}Clean. Focused. Majestic.
Then I added authentication. Then animations. Then a command palette. Then I spent forty minutes making the command palette open with a keyboard shortcut that nobody knows about.
The component is now 612 lines long and has developed opinions.
A Small but Critical Utility
Every serious startup needs at least one function that sounds more important than it is.
type Message = {
id: string;
body: string;
urgency: "eventually" | "soon-ish" | "the-building-is-on-fire";
};
export function calculatePigeonVelocity(message: Message): number {
const baseVelocity = message.body.length * 0.42;
if (message.urgency === "the-building-is-on-fire") {
return baseVelocity * 10;
}
return baseVelocity;
}Is this used anywhere?
No.
But when investors inspect the repository, they're going to see the wordVelocity, and the meeting will take care of itself.
A note on scalability
We will address scalability immediately after achieving something worth scaling.
The Development Process
My process is highly disciplined.
- Open the project
- Identify the most important feature
- Notice that the border radius feels wrong
- Adjust the border radius
- Reconsider the entire visual identity
- Add one feature at 1:00 a.m.
- Discover it already exists in the browser
- Call it a prototype
The current task list looks like this:
- Purchase domain
- Create landing page
- Add tasteful glass effect
- Make tasteful glass effect slightly less tasteful
- Add button bounce
- Decide what happens after the button bounces
- Find customers
- Add pricing
- Launch
That last checkbox is sitting there looking at me. I don't care for its tone.
Commands I Have Run With Confidence
Some commands are instructions. Others are negotiations.
npm run dev
npm run build
git status
git status
git statusAnd, when things become serious:
# This usually fixes the emotional problem.
npm installFor actual documentation, I occasionally consult MDN Web Docsor search GitHub for somebody who encountered the same problem in 2017.
Never mind, fixed it.
Fixed it how, Derek? What did you see?
Current Metrics
| Metric | Value | Interpretation |
|---|---|---|
| Registered users | 1 | Strong founder adoption |
| Messages sent | 14 | All from me |
| Messages received | 14 | Excellent retention |
| Revenue | $0 | Pre-revenue |
| Button satisfaction | 96% | Self-reported |
| Console warnings | 3 | Stable |
The remaining 4% of button dissatisfaction concerns the easing curve. I'm working through it.
What I Learned
1. Motion creates confidence
If the interface responds immediately, people assume the system knows what it is doing. The system may not know. But the button knows.
2. Constraints are useful
Constraints help you locate the exact moment you stopped listening to yourself.
3. “Temporary” is a powerful database schema
{
"message": "hello",
"status": "in_flight",
"pigeonMood": "determined",
"deliveryWindow": "when_the_time_is_right",
"metadata": { "temporary": true }
}The temporary field is permanent.
An Important Aside About Names
Naming a startup is harder than building one.
- Short
- Memorable
- Available as a domain
- Easy to pronounce
- Capable of becoming a verb
“Send me a Pigeon.” “You Pigeoned the file?” “I've been Pigeoning all morning.”
That's language-market fit.
I briefly considered calling it BirdWork.
We don't need to discuss BirdWork.
The Plan From Here
Tomorrow, I will focus entirely on the core product. No redesigns. Just the essentials:
- Finish message delivery.
- Add useful empty states.
- Test the mobile experience.
- Let one other human use it.
- Remain calm while they use it incorrectly.
If that goes badly, I'll call it a research preview. Either way, we're shipping.
Final Thought
There is a strange moment in every project when the idea stops being imaginary but has not yet become sensible. That's where Pigeon is right now.
It exists. It runs. It has no customers, no revenue, and no defensible explanation for why the notification sound is a tiny man whispering “incoming.”
But it exists.
And the button?
The button is tremendous.
Filed from the founder's office, which is currently one chair, two monitors, and a bowl of cereal I no longer trust.1
1 The cereal was poured before the authentication rewrite.