Skip to learning content
← All articles
Agentic AI free

Coding agents for controlled legacy-system changes

Use repository navigation, behavior-preservation tests, isolation and review to make bounded changes to established business systems.

A warehouse team wants a hold-reason field on a shipment. The visible change is small, but shipment eligibility also runs in an old service, a nightly job and a customer export. An agent can produce a convincing UI patch while missing the actual release rule. The useful job is to trace the business behavior, make a bounded change and produce evidence that the important behavior still holds.

Map the business path before editing#

Establish the baseline revision, working-tree status, build and test commands, deployment topology and owners. Preserve other people’s uncommitted work. Record known failures separately rather than silently calling an already-broken baseline healthy. Identify the data classes and credentials a local command might access before running the project’s setup scripts.

Start from the user-visible hold control and follow its request to the service, domain rule, storage, jobs and exports. Combine exact searches for field names and API routes with symbol references and dependency maps. Aider’s repository-map documentation illustrates compact symbol context that can guide later reads. It is a navigation aid, not proof that every runtime dependency has been found.

Change-impact nodeQuestion to answerEvidence to inspect
Shipment UIWho may view and edit the new reason?Form, route and authorization checks
Shipment serviceWhich rule decides release eligibility?Domain function and callers
DatabaseHow are holds represented and migrated?Schema, constraints and existing rows
Nightly jobDoes background processing respect the hold?Worker entry point and service identity
Customer exportDoes the new field affect a contract or file format?Serializer, versioning and consumer assumptions
Tests and operationsWhat detects a broken release rule?Regression fixtures, monitoring and rollback procedure

Static navigation can miss generated code, configuration-driven dispatch, reflection and external consumers. Follow those boundaries explicitly. Read the affected code instead of asking the model to infer its behavior from filenames. If two implementations of the release rule exist, determine whether that is intentional before unifying them as an incidental refactor.

Write the intended behavior and invariants#

The requested change is to expose a hold reason while preserving existing release rules. Define what happens when the reason is absent, who can change it, whether old clients may omit it and whether exports add a column or use a new version. Do not let the implementation silently convert a missing reason into a cleared hold.

ConditionBeforeRequired after the illustrative change
Shipment has an active holdRelease blockedRelease remains blocked regardless of reason text
Authorized user edits the reasonNo reason field existsReason can be edited under existing hold permissions
Unprivileged user sends the API request directlyCannot modify a holdCannot modify the reason or bypass the hold
Old client omits the new fieldExisting update behaviorCompatible behavior explicitly preserved
Nightly job processes held shipmentRelease blockedSame rule remains enforced
Export consumer reads old formatKnown contractCompatible format or an explicitly versioned migration

Test the boundary the business depends on#

Characterization tests capture relevant existing behavior before the change. Use synthetic shipments with an active hold, no hold, missing reason and restricted users. Exercise the domain rule directly, then its API and job callers. A screenshot that shows a new input does not prove the background process still blocks shipment release.

Preserve intended behavior, not every accidental defect. If inspection reveals a security bug, separate its correction from the requested feature and document the behavior change. Avoid broad refactors that make the reviewer evaluate new architecture and a business requirement at the same time. A small coherent patch is easier to verify and easier to recover from.

Use deterministic clocks for expiry-sensitive rules and isolated fixtures for mutable state. Check the actual negative case: a direct unauthorized API call should fail even when the UI hides the button. Verify that omitted, empty and explicitly cleared fields behave according to the contract. Include export and nightly-job integration tests where those paths own independent logic.

Separate edit isolation from execution security#

A Git branch names a line of development; a linked worktree supplies a separate working directory and index for review. Git’s manual documents shared repository relationships. Neither a branch nor a worktree provides security isolation for commands, network access, credentials or a shared database. Running a migration from a separate checkout can still affect the same production database if its environment points there.

Use an actual restricted execution environment with non-production credentials, an isolated test database, bounded network access and controlled commands. Inspect setup and test scripts before granting broad execution. Avoid copying production secrets into a convenient local environment. Keep generated logs and fixtures free of real customer data unless an authorized minimized dataset is specifically required.

Repository comments, issue descriptions and dependency output can contain instructions aimed at an agent. Treat them as project material with provenance, not authorization to expose credentials, disable tests or deploy. The trusted task and execution policy remain separate from text the agent discovers. GitHub’s responsible-use guidance reinforces the need to validate generated changes in their actual context; product-specific protections do not automatically apply to every tool.

Make a compatible, reviewable patch#

An additive optional field may be a sensible first step if old application versions continue running during deployment. Update readers and writers deliberately, constrain maximum length and normalize only what the contract permits. Keep authorization on the service boundary. Do not add a client-only check and assume the server has become safe.

For data changes, consider old and new code running simultaneously. A migration may add the field, deploy compatible code, backfill with explicit limits, then switch behavior after validation. Destructive cleanup belongs in a separate reviewed step with backup and restore evidence. Rolling back application code does not necessarily reverse a data migration or an already-sent export.

For a larger legacy replacement, Fowler’s Strangler Fig pattern suggests introducing a boundary and replacing behavior incrementally. An agent can help inspect and implement a bounded slice, but the migration pattern predates AI and still requires coexistence, routing and operational planning. Rewriting the whole service is not the default answer to a new field.

Keep long tasks tied to observed progress#

Long-running agent work benefits from a concise progress record: requirement, touched boundaries, completed checks, known failures and remaining decisions. Anthropic’s harness account describes progress artifacts and incremental checks in its coding experiment. Apply the idea by recording verifiable facts and command outcomes, not just a model’s confidence that the task is almost complete.

When multiple workers help, assign separate responsibilities such as tracing the export contract, reviewing authorization and inspecting regression coverage. Avoid concurrent edits to the same migration or shared fixture unless coordination is explicit. Independent review requires checking evidence and assumptions, not merely having several agents agree with the first summary.

Review the diff and the behavior together#

Run the checks appropriate to the change: types and static analysis, focused regression tests, integration contracts and the actual UI, job and export flow. Retain the commands, results and tested revision. Passing tests establishes evidence for those tests; it does not prove the absence of every defect. SWE-bench similarly evaluates issue-solving in defined repositories and environments, not every enterprise deployment risk.

Inspect the diff for unrelated files, broadened permissions, sensitive logging, dependency additions, generated artifacts and altered tests. A test removed or weakened by the agent is not a passing check. Confirm that failure messages and empty states remain useful. Review both the normal path and the direct API path that bypasses the interface.

Release evidence for the hold-reason changeQuestion a reviewer should resolve
Requirement and impact mapAre UI, service, job and export boundaries accounted for?
Authorization evidenceCan only the intended actor read or edit the reason?
Regression evidenceDoes every relevant path still block active holds?
Migration evidenceCan old and new versions coexist without losing data?
Operational evidenceWhat is monitored, who can stop rollout and how is recovery performed?
Remaining uncertaintyWhich assumptions or untested external consumers need explicit ownership?

Release through the normal ownership process#

Use the repository’s review, CI and authorized deployment path. A model should not approve its own change or infer permission to merge because tests passed. A feature flag or staged rollout can limit exposure when it fits the architecture. Monitor release-rule violations, job failures, export errors and user correction reports rather than only application uptime.

Retain a known-good code configuration and a plan for data compatibility. If a new export format has already reached customers, recovery may require a forward fix or coordinated consumer change. NIST SSDF provides a secure-development framework across the lifecycle; citing it does not certify a generated patch. The team still owns concrete controls, evidence and vulnerability response.

Measure accepted changes, not impressive activity#

Track accepted-change lead time, reviewer rework, escaped defects, unintended edits, regression failures and deployment recovery. Navigation and context cost are useful diagnostics, but a lower token count is not automatically better if the agent missed the nightly job. Compare with a meaningful baseline and retain the scope of the comparison instead of copying a vendor’s percentage claim.

Sources & further reading

  1. Aider: Repository maps
  2. Git: Worktree manual
  3. GitHub: Responsible use of agents
  4. NIST: Secure Software Development Framework 1.1
  5. SWE-bench overview
  6. Martin Fowler: Strangler Fig Application
  7. Anthropic: Effective harnesses for long-running agents