Mirroring the SDLC
Everyone had written off our legacy KDB batch workflow as non-automatable. The stack was never the problem. I gave an LLM the same lifecycle I use as a developer, one tool per SDLC stage, and the loop closed.
$ render article.mdx
Everyone had written off our legacy KDB batch workflow as non-automatable. The stack was never the problem. I gave an LLM the same lifecycle I use as a developer, one tool per SDLC stage, and the loop closed.
$ render article.mdx
Search posts, research, projects and tags, or jump to a page.
Every AI coding agent demo looks the same. A modern repo, a popular language, a test suite that runs in seconds. The agent writes code, runs the tests, sees green, everyone applauds. The unspoken assumption is that the feedback loop already exists. The agent just gets to borrow it.
My day job is the opposite of that demo. I build data and workflow platforms for investment management at Connor, Clark & Lunn Financial Group, on the data management team. A large part of what we run is ETL batch processing built on kdb+/qkdb+ is a columnar time-series database with its own language, q. It is everywhere in finance and nearly invisible outside it, which is part of why tooling for it lags so far behind the mainstream.: high volumes of market and reference data from vendors like Bloomberg, Datastream, and FundApps, orchestrated by an in-house batch processing application that schedules and executes KDB batch jobs. There is no npm test. There is no local environment that resembles production. If you had asked me a year ago whether this workflow was automatable with an LLM, I would have said no, and I would have pointed at the stack as the reason.
I was wrong, but not about the stack. The stack was never the problem. The problem was that the agent had no way to do anything. So I built the tools that let it, and the organizing principle turned out to be simple: mirror the SDLC. Every stage of the software development lifecycle I walk through as a developer, the agent gets as a tool.
This wasn't my first attempt at pointing AI at this stack. I'd already built tooling that investigates production issues by correlating code search, our data systems, and ticket history, work that cut multi-day investigations down to minutes. That tooling works well, but it's read-only. It can tell you what's wrong. It can't fix anything.
The obvious next question was whether an LLM could do the fixing: branch, change, deploy, run, verify. And that's where the stack stops being a talking point and starts being a wall, because fixing requires a feedback loop, and ours only existed in human hands.
Here's what shipping a change to one of our batch processes actually involves:
git push. It means getting the code where the batch processor can see it and, often, creating or configuring a job in the batch processing application itself.Steps 4 through 7 are the heart of the job, and they're exactly the steps a stock coding agent can't touch. An LLM with repo access could do steps 2 and 3, badly and without context, and then hand me something it had no way to verify. That's not automation. That's a very confident intern who has never seen the system run.
The shift was to stop asking "can the model write q?" and start asking "what would the model need to check its own work the way I do?" Written down, my workflow is just the SDLC in miniature: plan, branch, code, deploy, run, test, observe, iterate. None of those stages is magic. Each one is a set of concrete operations against concrete systems: git, the codebase, Jira, Azure DevOps, the dev environment, the batch processor, the data.
So that became the design spec. For every stage of the lifecycle I go through, build a tool the LLM can call. Not a general-purpose "do anything" interface, but a mirrored lifecycle:
| SDLC stage | What I do at my desk | What the agent got |
|---|---|---|
| Plan | Read the Jira work item | Jira and Azure DevOps visibility |
| Branch | Cut a git branch | Branch management tools |
| Code | Search and edit q | Code search tuned for the codebase |
| Deploy | Ship to dev, configure the batch job | Deploy and job-creation tools |
| Run | Execute the job | Run tools on the batch processor |
| Test | Construct edge cases in dev data | Data-editing tools |
| Review | Open a PR | The same PR, read by a human |
Source control. Tools to manage branches with git: create a branch for the work item, commit changes, keep the work isolated the same way mine is. This sounds trivial, but it matters. It means the agent's work follows the same path to review as a human's, and nothing lands anywhere without going through a PR in Azure DevOps.
Code search. Tools to search the codebase, tuned for the reality of q. Generic search gets you surprisingly far, but the agent needed ways to trace where a table is loaded, which processes touch it, and where a function is defined versus where it's called. This is also where the LLM's tolerance for terse, alien code turned out to be a strength. It reads q without the flinch most developers have.
Work tracking. Visibility into Jira: the work item being implemented, its description and acceptance criteria, related items. This grounds the change in why, not just what: the same context I'd load into my own head before touching anything. The agent can also see Azure DevOps, where our repos and PRs live.
Deployment. Tools to deploy changes to the dev environment, including creating and configuring jobs in the batch processing application. This was the piece that made everything else real. Deployment in our world is not a generic operation. It's specific knowledge about how code gets from a branch to a place the batch processor can execute it. Encoding that as a tool meant encoding institutional knowledge that previously lived in people's heads.
Execution. Tools to actually run the jobs. We already had a service for initiating and monitoring KDB batch processes, built for other purposes years earlierA .NET service originally built so languages other than q could initiate and monitor batch processes. Nobody involved was thinking about agents at the time, which is exactly the point: good interfaces get reused in ways you didn't plan for., and the agent's run tool sits on top of it. Kick off the job in dev, get the result back: success, failure, logs, output. This is the agent's equivalent of running the test suite, except the "test suite" is the real batch processor doing a real run against dev data.
Test data. Tools to edit data in the dev environment. This one is the most underrated of the set. Our processes are ETLs; their correctness lives in how they handle data, especially the audit checks and the loading frameworks that aggregate multi-source data. Giving the agent the ability to construct scenarios (insert the bad row, stage the malformed input, set up the condition that should trip an audit) is what turned "the job ran" into "the job is correct." Verification without the ability to arrange the preconditions is just observation.
With the full set in place, the loop closes. The agent picks up a work item from Jira, branches, searches the code, makes its change, deploys to dev, creates the job, and runs it. Then it does the thing that actually earns trust: it goes looking for ways it might be wrong. It edits dev data to set up an edge case, reruns, checks that the audit fired, fixes what didn't work, and repeats. What comes out the other end is not "here's some q code that looks plausible." It's "here's a change that ran, against these scenarios, with these results," attached to a branch ready for human review.
The difference between those two outputs is the entire difference between an LLM demo and an LLM you'd let near a production data platform.
The model was never the bottleneck; the feedback loop was. The same model that flails when it can only read code becomes methodical when it can deploy, run, and observe. Almost all of the capability gain came from tools, not from anything model-side.
"Legacy" is not the same as "non-automatable." The stack everyone points to as the blocker (kdb+, an in-house scheduler, no modern CI) is really a list of missing interfaces. Every one of those interfaces can be built. The work is unglamorous, but it's ordinary engineering, and you only have to do it once. Some of it we'd even already done for other reasons; the services we'd built around the batch processor became the substrate for the agent's tools.
Mirroring the SDLC is the right decomposition. I didn't invent an agent architecture; I transcribed my own workflow. Whenever I was unsure what tool to build next, the question "what would I do next at my desk?" answered it. The lifecycle you already trust for humans is the scaffolding the agent needs, including its guardrails. Dev-only access and PR review aren't restrictions bolted onto the agent; they're the same controls the SDLC already imposes on me.
Test-data editing is the sleeper feature. Everyone builds the deploy tool and the run tool. The tool that lets the agent construct edge cases in dev data is what makes verification mean something. For ETL work especially, correctness is a property of code and data, and the agent needs its hands on both.
None of this replaced the review step, and it shouldn't. Everything still lands as a PR, read by a human, with the run results attached. What changed is what arrives in that PR: work that has already been through the same lifecycle I would have put it through myself.
The code for all of this stays inside the firm. The method doesn't, which is why I'm writing it up.
0 comments
Sign in to join the discussion