If you missed it, the previous post “The Breaking Point” sets addresses accepting that it was time for a v2.
HoffStuff has one core responsibility. Don’t tell people what someone got them.
Not “make wish lists pretty.”
Not “let people add anything from anywhere.”
No spoilers! Ever! Everything else is a bonus.

That sounds obvious until you start adding features. HoffStuff 1.0 has been running for my family since 2024, and it works. But the longer it ran, the more I noticed a quiet fear about touching it. Every new option, every UI tweak, every edge case my family kept surfacing was a chance to leak something. The rules that kept this from happening weren’t in a unified location. No, they were in my head and scattered throughout different parts of the code, not easily referenced.
Business logic in your head is a recipe for disaster

So HoffStuff 2.0 doesn’t start with fancy features. It starts with rules. Rules that guardrail everything that comes after them.
Starting from the rules
My posture is simple: define the rules before writing any code. Then, treat the rules as the source of truth and let the code conform to them. Not the other way around.
The product canon
I’ve jokingly asked for a “product canon” my entire career. The idea is a living, versioned product document treated similarly to code. It defines all of the business logic and functionality in one place. When new features are requested, the canon is updated, and developers can reference the `diff` so that everything is accounted for.
Not a wiki of unconnected pages you have to sift through.
Not a graveyard of JIRA tickets that are impossible to search.
A canonical document.
Hence: the canon.
In HoffStuff 2.0, the canon is where the business rules live:
Spoiler protection.
Visibility logic.
Who can see what about whom?
Who gets to edit a list?
“Deleted” versus “archived” definitions.
These are exactly the rules I used to keep in my head and attempt to remember each time I made a change.
They sit outside the code now. The code conforms to them.
Two things make this a critical change between versions:
First: a real product canon survives a refactor. When I rewrite something, the rules don’t disappear with the old code, because they were never in the code. They live in an external document that everything references predictably and consistently.
Second: With the rise of agentic development, a product canon simplifies everything. I can work through a plan with AI, point it at the canon, and verify it against the rules. Providing agents with an absolute source of truth, they’re able to vet my changes against them and call out potential issues. Documenting this kind of stuff no longer feels academic. It has purpose, and it forces me to reconcile the edge cases. It’s the cheapest insurance policy I can buy.
Order throughout the code
Alongside the product canon are two supplemental documents that offer additional support.
One is the architecture doc. It defines how the app is built. I read this before making any structural changes. It catches “oh wait, that’s not how we do data flow here” before I’m three files deep in a wrong pattern. It also captures reasons for doing or not doing something specific to ease context-switching.
The other is the cross-project working agreement. It clearly defines ownership across the different HoffStuff 2.0 projects.


HoffStuff 2.0 isn’t just one app. There’s the core app, and there are additional projects (an iOS companion app, a documentation site, etc.).
If I’m making changes to the documentation website and vetting some logic with an agent, I need the agent to understand the project’s context and that it is not in a position to make architectural decisions elsewhere.
The main app owns the domain.
The companions consume what the main app exposes.
If a companion needs something new, it doesn’t quietly add a column to the database. It writes a proposal, the main app implements the change, and the companion consumes it.
Order creates structure, and everybody knows who to look to for answers.
These two documents exist to prevent a specific bad behavior: the dreaded escape hatch. Hard problem, tight deadline, a small voice that says, “Just do it this way for now, we’ll fix it later.” Anyone who’s worked on a project long enough knows what I’m talking about.
Plans before code
The way the canon and the architecture doc actually get used is through a habit. Every meaningful change goes through an iterative process:
- Ideas are worked into a written proposal
- The proposal is validated against the rules, and grilling sessions produce a plan
- The plan is broken down into deliverable phases with clear goals and outputs
This is also where AI earns its keep, not as a stenographer for prompts but as an adversary against my own thinking.
I write the proposal.
I point an agent at the relevant rules.
I ask it to find the holes.
There’s a set of skills I use for this called grill-me and grill-with-docs, where the assistant interviews me about the plan and refuses to let vague answers slide.
The agent catches edge cases I wouldn’t have imagined on my own.
Some of them are small.
Most would have shipped as bugs.
A few things have surfaced that are important enough that the canon had to be updated before any code did.
The point is that the AI isn’t doing the thinking. The rules are. The AI is just very good at noticing when the plan and the rules don’t agree.
What this costs
The upfront work is real. I probably wouldn’t have done this for a smaller project or one with lower stakes. Writing rules down before writing code is, in the moment, less satisfying than just writing the code. The dopamine is delayed. You spend a couple of days hammering out a document and shipping nothing visible. The payoff comes later, every time the rules let me move faster than I could have moved without them.
Like most things, it’s not a perfect system. It requires upkeep.
Over time, the canon can drift if not properly maintained. If I add a rule in code without writing it down in the doc, the doc is now stale. The next plan referencing it could get the wrong answer. The relationship is symbiotic, but it’s still better than trying to remember everything myself.
Forcing myself to maintain a source of truth helps prevent the agents from hallucinating their own rules. If I take shortcuts and make sweeping changes without considering the consequences (and I bypass the grilling session’s objections), I could be introducing variants into the doc. To help alleviate this, I routinely review the canon document to ensure nothing is out of order.
This proactive planning has made this whole thing possible. Now, I can make real improvements to HoffStuff 2.0, including improvements that change behavior people are already used to, without the underlying fear of breaking promises. The rules are explicit. The code conforms. Churn doesn’t compound risk.
From there, the stakes scale.
HoffStuff 2.0 is meant to be self-hostable. Other people will run it. That means the core responsibility (no spoilers) has to hold for households I’ve never met, configurations I haven’t anticipated, and patterns of use I can’t predict. I was able to keep HoffStuff 1.0 under control as a single instance for my family. One instance is easy to hop into and make quick changes to fix small issues. HoffStuff 2.0 won’t just be a single instance in a controlled environment, and the promise has to survive that.

The rigor isn’t just my own discipline anymore. It’s how I make sure nobody’s gift gets spoiled, even when I’m not the one running the application.

Leave a comment