I
I have been shipping APEX Deployment Tool for a few years now. It is a Python CLI that extracts Oracle database objects, APEX applications, and data exports into files you can version in Git, then via clever patch files deploys them anywhere. Other people also use it, which is great. The problem is I am not a professional Python developer, and after a couple of years of adding features on top of features, the code shows it.
So a two weeks ago I started a full rewrite. Not just a refactor, but a full rewrite, done almost entirely by AI, module by module. This post is about why, how, and what is still ahead.
Why the rewrite
The code quality problem was the most obvious one. The largest files had grown into multi-responsibility monsters that were hard to read and harder to change safely. Normalizers (the functions that clean up DDL before writing files) were woven into the main export script instead of living in their own testable place. Adding a new object type or tweaking cleanup behavior meant reading hundreds of lines of context to find the right spot.
No tests was the second problem. I could not add a test after the fact without essentially rewriting the thing anyway, because everything was coupled to a live database connection and global state. So every change was manual testing against a real schema. That is slow and unreliable.
Maintenance and bug fixing got harder as the codebase grew. There was no changelog, no release notes, no version pinning. Updating dependencies was a guess. Bugs came in and I fixed them by feel, not by a failing test I could point at.
And then there is the extension problem. When someone asks for a new feature, the answer was often "somewhere in the biggest file that sort of relates to it". That is how you end up with a 2600 lines long script.
Finally, some arguments were not optimal for AI-assisted use. No "-silent" flag exists in old ADT, which meant AI agents using it would either get too much noise or lose information they needed. Getting argument semantics right for both human and AI callers is actually worth thinking about carefully.
The goal with ADT.ai is to fix all of that: better code structure, full test coverage from the start (TDD), proper documentation that stays up to date because it is generated as part of the process, a real changelog, and argument design that works well for both humans and AI agents.
How we approached it
The approach was: core first, then module by module, verified against old ADT output at every step.
We started with the Python package scaffold – "pyproject.toml", proper "src/adt_ai/" layout, linting, test harness. Then the YAML config loader with inheritance. Then the Oracle connection loader. Then the Oracle gateway. Each piece got failing tests before a single line of production code. The TDD discipline was non-negotiable because it is the only way to know the thing actually works once you disconnect from a live database.
Once the core was solid, we moved to "export_db" (the database object export command) one slice at a time:
- Object discovery (querying the catalog for what exists)
- File resolver and writer (where does each object go, how do we preserve existing file casing)
- DDL normalizers (extracted from the old code, rewritten as independent, testable functions with golden-file tests)
- Grants, comments, deleted-object detection
- The CLI runner itself, with old-ADT-compatible argument aliases
After each slice: export via old ADT, commit to a temo branch, delete all files, export via new ADT.ai, diff recursively, fix until outputs match. That verification loop is the thing that gives you confidence you have not missed anything.
Codex did most of the implementation work. Claude held the architectural context, wrote the plans, reviewed the approach, and stepped in when something needed judgment rather than execution. And step in when I run out of Codex tokens. When I implemented somthing with Claude, the first task for Codex was to review this code. This combination works well for me.
We are not done yet. Patch and deploy are still ahead too. The skeleton is there; the modules are being filled in.
What is still ahead
Patch, Deploy and Dependencies modules. There are also some new features that are not in the old ADT and they will make the tool noticeably more useful for AI-assisted development workflows. You will see them when they land.
One thing that is already live: a proper CHANGELOG. Every task that completes adds an entry. It is not spectacular but it means there is actually a record of what changed and when, which the old ADT never had.
Bonus: skills in the repo
ADT.ai ships with the Claude/Codex skills that you can use to operate ADT, packed into the repository. So if you clone the repo and open it in Claude Code, the skills for exporting, deploying, and running ADT.ai are right there, and they stay current as ADT.ai evolves.
If you have been using ADT and want to try ADT.ai, the repo is at github.com/jkvetina/ADT.ai.

Comments
Post a Comment