Field note 005 / Software ownership
Taking over an AI-built app without starting again
Keep what’s useful, find out how it works, and make the next change without holding your breath.
You have a working app, a repository full of code, and a growing suspicion that the next change might be awkward. Perhaps you built it yourself with an AI coding tool. Perhaps the person who built it has moved on. Either way, you’d quite like to keep the useful bits.
That’s a sensible starting point. A takeover should begin by finding out what you have and making it safer to change. A rewrite might eventually earn its place, but it shouldn’t be the price of the first conversation.
For this guide, imagine a small booking app. Customers choose a slot, staff manage availability, and a background job sends reminders. It works well enough that people now depend on it. The examples below are hypothetical, but the questions are ones you can ask of your own software.
Start with the keys
Before anyone reorganises a folder, check who can actually keep the app running. Access to the code is only one part of that.
- Source and releases: the repository, its history, and the version currently serving customers.
- Hosting and data: deployment accounts, databases, file storage and backups.
- Outside services: domain registration, email, payments, monitoring and scheduled jobs.
- Recovery: who receives billing notices, who can recover an account, and who can help if the usual owner is unavailable.
Record account owners and where credentials are managed. Keep passwords and recovery codes in an appropriate secure store, rather than dropping them into the handover document. Give people named accounts and the access their work needs.
A repository transfer doesn’t settle every permission question. For example, GitHub’s transfer documentation explains that existing collaborators can retain access. Review the resulting access list, along with the separate hosting and service accounts.
If you discover an exposed credential, treat that as an immediate security issue. For routine handovers, plan credential changes so the app can move to the new credentials before the old ones are retired. OWASP’s secrets management guidance covers access, rotation and revocation in more depth.
Get a clean copy running
Ask the incoming engineer to start from a fresh checkout using written instructions. Use a separate development environment, test credentials and suitable test data. Nobody should need to point an unfamiliar app at the live database just to find out whether it starts.
This is where small pieces of missing knowledge tend to appear: an unrecorded runtime version, a configuration setting that lives on someone’s laptop, or a database change that never made it into the repository.
For an npm project with a committed lockfile, npm ci installs from that lockfile and fails if it disagrees with the package manifest. That helps expose dependency drift. It doesn’t make an unfamiliar project safe to execute: review its scripts and run it in an appropriately isolated environment first.
Whatever the stack, record the actual steps that worked. Include how to initialise the database, create a test user and run background jobs. Mark the current release in version control. Keep dependency upgrades and broad formatting changes out of this first exercise; they make it harder to tell whether a problem was inherited or just introduced.
Find out what must keep working
Start with a walkthrough from someone who uses the app. Which task would cause trouble if it stopped working tomorrow? Which odd-looking behaviour exists because a customer needed it?
For our booking app, follow a booking all the way through: choose a slot, reserve it, send confirmation, display it to staff, then cancel it. Look at what happens to the stored data as well as what appears on screen.
Write a few tests around the important outcomes before changing the implementation. Two people trying to reserve the final slot should get a result the business understands. A customer shouldn’t be able to cancel somebody else’s booking. A cancellation should release the slot according to the agreed policy.
Some tests will capture current behaviour so you can notice accidental changes. That’s useful, but don’t turn a known bug into a permanent requirement. Record whether each behaviour is intended, tolerated for now, or waiting for a decision.
Draw a map you can use
A small diagram is enough to begin with. Show the browser, the server, the database and each outside service. Add the reminder job, which is easy to miss if everyone concentrates on the screens.
Then annotate a few things: where permissions are checked, which component owns booking availability, and what triggers a reminder. Mark anything you haven’t verified. An honest question mark is more useful than a confident box drawn from a guess.
You’re looking for places where a change might have a surprising effect. If the customer screen and staff screen each calculate availability differently, that’s worth investigating. If reminders depend on a scheduled task in a personal hosting account, that belongs in the operating notes as well as the diagram.
Make one small change safely
Choose a modest, useful first change. Correcting the wording of a reminder or fixing a well-understood validation error can teach you more about delivery than a week of rearranging files.
Carry it through the real development process: reproduce the issue, add an appropriate test, make the change, review it, deploy it to a test environment and check the result. Before releasing, agree how you’ll detect a problem and what you’ll do next.
For higher-risk changes, a limited rollout can reduce the number of users exposed while you gather evidence. Google’s guide to canary releases explains that approach. A small app may use a simpler release process; the useful habit is deciding what success and failure look like before the change goes live.
Check the recovery plan against the change itself. Reverting application code won’t restore deleted records. A database migration may also make the previous application version unusable. If you need a data restore, rehearse it in an isolated environment and understand what recent work would be lost.
Decide what deserves replacing
After that first change, the discussion becomes more concrete. You can explain what was hard, what made it hard and which improvement would make the next change easier.
Perhaps the reminder code is tangled but the booking flow is sound. Put a clear boundary around reminders, test the behaviour people rely on, and improve that part. You don’t have to replace the working booking system to fix a brittle email job.
Martin Fowler’s Strangler Fig approach describes gradual replacement of an existing system. For a small app, the relevant idea is replacing a manageable piece while the rest continues to serve users. Running old and new code together has its own cost, so choose a boundary that genuinely simplifies the work.
A wider rebuild can still be reasonable: perhaps the platform cannot support an essential requirement, or repair would cost more than a bounded replacement. Ask for the reasoning, the migration plan and the behaviour that must survive. “I wouldn’t have built it this way” isn’t enough on its own.
Leave the next person a usable handover
A good takeover leaves a short set of things someone else can use:
- A verified account inventory and a clear owner for the service.
- Setup instructions that work from a clean checkout.
- A map of the important flows and a few meaningful tests.
- A demonstrated release process and a realistic recovery plan.
- A prioritised list of remaining work, including unresolved questions.
Ask another person to follow the instructions without coaching. Their questions are a cheap way to find the gaps.
You don’t need to understand every line before making progress. You do need enough understanding to make a useful change, check its effect and recover if it goes wrong. Once you can do that, the app starts feeling like something you own.
Further reading
- GitHub: transferring a repository — what moves and what happens to access.
- OWASP: secrets management — managing credentials throughout their lifetime.
- npm: clean installs — the behaviour of a lockfile-based installation.
- Google SRE: canarying releases — evaluating a change with a limited rollout.
- Martin Fowler: Strangler Fig — improving a system through gradual replacement.