How To Preserve Software Decisions As Your Project Grows
As a software project grows, one of the easiest things to lose is not code.
It is why the code became this way.
You may remember today that:
- User information should remain on the device.
- A particular dependency was deliberately rejected.
- One screen behaves differently because of an earlier technical problem.
- A feature was intentionally left out of the first version.
- Two similar pieces of code were kept separate for a reason.
Months later, those decisions may no longer be obvious.
AI may suggest reversing them. A collaborator may assume they were accidental. Even you may forget why you made them.
The solution is not to preserve every conversation.
It is to preserve the project knowledge that future work will depend on.
Code Shows What Exists, Not Always Why
Imagine the errands app stores all tasks locally on the device.
Someone inspecting the code can see that local storage is being used.
But the code may not explain why.
Perhaps the decision was:
“The first version should work without accounts or a remote server. Personal task information should remain on the user’s device.”
That reasoning matters.
Without it, a future AI conversation might suggest moving tasks to an online database because it appears more convenient for a new feature.
Technically, that may work.
But it could contradict a deliberate product decision.
This reveals an important distinction:
The code records implementation. Project knowledge records intent and reasoning.
You need both.
Not Every Past Conversation Is Project Knowledge
When building with AI, it is easy to accumulate enormous conversation histories.
Most of them should not become permanent documentation.
A conversation might contain:
- Ideas you rejected.
- Incorrect assumptions.
- Temporary debugging experiments.
- Five possible solutions before you chose one.
- Questions that have since been answered.
- Old descriptions of features that later changed.
Saving all of that as permanent context can make the project harder to understand.
The useful question is not:
“What did we discuss?”
It is:
“What does someone working on this project later need to know?”
That usually produces a much smaller amount of information.
Preserve Decisions That Constrain Future Work
Some decisions have little effect beyond the moment they are made.
Others influence many future changes.
Those are the ones worth preserving.
For example:
“Tasks are stored locally” is important because future features involving storage need to respect it.
“We support iOS 18 and later” matters because dependency and API choices may depend on it.
“The first version does not require user accounts” affects authentication, synchronisation, storage and onboarding.
“We use the platform’s existing chart capability instead of another dependency” may prevent future AI sessions from introducing a package that was deliberately avoided.
A useful rule is:
Record decisions when forgetting them could cause future work to move in the wrong direction.
You do not need to record every button position or variable name.
Those are normally visible from the project itself.
Preserve The Reason, Not Just The Decision
A list of rules without reasoning can become dangerous.
Imagine your project notes say:
“Do not use cloud storage.”
Six months later, your requirements change and synchronisation between devices becomes essential.
Is cloud storage forbidden because of:
- Privacy?
- Cost?
- Technical complexity?
- The scope of the first version?
- A temporary limitation?
Without the reason, you cannot tell whether the old decision still applies.
A better record would be:
Decision: Keep task data on the device for the first version.
Reason: Accounts and synchronisation are outside the first release, and local storage keeps the product simpler while protecting the intended private experience.
Revisit when: Cross-device synchronisation becomes a confirmed requirement.
Now the decision can evolve intelligently.
The reason tells you what problem the decision was solving.
Distinguish Decisions From Current Project State
Projects contain at least two different kinds of useful knowledge.
Current state
This describes what the project is like now.
For example:
“Users can create, edit, complete and delete tasks.”
Or:
“The app currently stores tasks locally.”
Decision history
This explains why something important was chosen.
For example:
“We chose local storage because the first version should not require an account.”
The distinction matters because current state can change frequently.
Decision reasoning usually changes less often.
You do not want an old project note claiming:
“Task editing is not supported” after task editing has already been built.
That is stale current-state information.
At the same time, an older decision such as:
“Keep the first version account-free” may still be completely valid.
Good project knowledge makes it clear which kind of information you are reading.
Establish A Source Of Truth
As projects grow, the same fact can appear in many places.
Perhaps your storage decision exists in:
- An old AI conversation.
- A planning document.
- A comment inside the code.
- A task list.
- A newer conversation saying something different.
Which one wins?
Without an answer, conflicting project knowledge begins to accumulate.
A source of truth is the place you treat as the current authoritative version of important information.
For a small project, this does not need to be complicated.
You might keep a short project document containing:
- The product’s current purpose.
- Important technical decisions.
- Important constraints.
- Major decisions that future work must respect.
- Known decisions that are intentionally still unresolved.
The exact format matters less than consistency.
When an important decision changes, update the source of truth.
Do not expect future AI sessions to reconstruct the truth from dozens of old conversations.
Mark Old Decisions As Replaced
Changing your mind is normal.
The danger is leaving both the old and new decisions looking equally valid.
Suppose the project originally says:
“The app will never require accounts.”
Later, user research convinces you that cross-device synchronisation is essential.
The new decision might become:
“Accounts will be optional and required only for synchronisation.”
Do not simply add that underneath the old rule.
Now the project contains a contradiction.
Instead, make the relationship explicit:
Previous decision: No user accounts.
Status: Replaced.
Current decision: Accounts are optional and used for synchronisation.
Reason for change: Cross-device access became a confirmed product requirement.
This creates a useful history without making the project ambiguous.
A project should be able to change its mind without losing track of what is currently true.
Preserve Discoveries That Are Expensive To Rediscover
Not all valuable project knowledge begins as a deliberate design decision.
Sometimes you learn something through failure.
Imagine you spend an hour discovering that a particular platform behaviour causes tasks to be duplicated when information is loaded in a certain way.
You eventually find a reliable solution.
The code contains the fix.
But six months later, AI may see the implementation and suggest simplifying it back to the original broken approach.
That lesson was expensive.
Preserve it.
For example:
“Task loading deliberately happens here rather than when the screen first appears. Loading on every appearance previously caused duplicate requests.”
This is different from documenting every bug ever fixed.
The useful knowledge is the part that prevents someone from repeating a non-obvious mistake.
A good rule is:
If the reason behind unusual code would not be obvious to a competent person reading it later, preserve the reason somewhere appropriate.
Do Not Turn Documentation Into A Second Codebase
There is a danger in documenting too much.
Suppose you maintain a detailed document describing every screen, property, function and file.
Now every code change also requires a matching documentation change.
Soon the document becomes outdated.
At that point it becomes worse than having no document because it confidently tells you things that are no longer true.
The code itself should remain the main source for details that can be discovered easily by inspecting the project.
Project knowledge should concentrate on information the code cannot explain reliably:
- Intent.
- Trade-offs.
- Constraints.
- Non-obvious reasoning.
- Important rejected alternatives.
- Decisions that affect future work.
Document the knowledge, not a duplicate description of the entire codebase.
Some Decisions Belong Close To The Code
Not every explanation belongs in a central project document.
Suppose one particular function contains unusual logic because of a platform-specific behaviour.
The reason may be most useful directly beside that code.
A concise comment might explain:
“Keep this operation after the save completes; moving it earlier can display stale task data.” That information is highly local.
Someone reading the relevant code needs it there.
By contrast:
“The app does not require accounts in the first version”, affects the whole project. That belongs in broader project knowledge.
The useful question is:
“Who needs this information, and when will they need it?”
Put the knowledge where it is most likely to be encountered at the moment it matters.
Give AI The Current Decisions, Not The Entire History
Once important knowledge has been preserved properly, working with AI becomes easier.
Instead of saying:
“Read these twelve previous conversations and work out what we decided.” You can provide the current project knowledge.
For example:
“Before making changes, follow the current project decisions document. If the existing code appears to conflict with it, point out the conflict instead of silently choosing one.”
That is much stronger than relying on conversational memory.
Old conversations can still be useful when investigating how a decision was reached.
They should not need to function as the project’s primary memory.
Let The Project Become More Independent Of The Conversation
This is an important transition for a vibe coder.
At the beginning, the project may live largely inside a conversation:
You ask.
AI answers.
You make changes.
You remember what happened.
That works while the project is small.
Eventually, the project should carry more of its own knowledge.
A new AI session—or a new human collaborator—should be able to understand its important decisions without requiring you to retell the entire story.
That is a sign that the project is becoming more durable.
The conversation helped create the software.
The software should not permanently depend on remembering the conversation that created it.
Preserve Knowledge That Changes Future Decisions
The purpose of project memory is not historical completeness.
It is future usefulness.
Preserve:
- Important product decisions.
- Important technical choices.
- Constraints that future work must respect.
- Reasons behind non-obvious implementations.
- Expensive lessons you do not want repeated.
- Decisions that have been replaced and what replaced them.
Avoid filling it with information that is temporary, obvious from the code, or no longer relevant.
That completes Chapter 4.
You now have a basic process for directing AI effectively: give it the relevant context, define the change clearly, structure large work intelligently, and preserve the knowledge that should survive beyond one conversation.
Chapter 5 moves from directing AI to keeping control of the project itself.
In Blog 15, we will look at how to save working versions and make changes reversible, including why code history and backups solve different problems.