Build a feature
Most of the work in a feature happens before the first line of code. You need to find where similar behaviour already lives, which helpers exist, which configuration the code actually reads in production and what else the change touches. This page walks through each of those steps with CodeZero in VS Code and Vörr in Claude or ChatGPT. It is fair about what a coding agent can already do on its own and where it needs extra setup.
When you'd do this
- You are adding behaviour to a service you know partly, such as a new endpoint, a new field on an existing flow, or a scheduled job.
- The feature probably needs logic someone has already written, such as date handling, money formatting, retries or auth checks, and you do not know where it lives.
- The feature needs a new setting or reads an existing one, and you need to know where production actually gets its value.
- You want the agent to follow the service's conventions (error handling, logging, validation, test layout) rather than invent its own.
- You want a reviewable plan and small diffs, not one large pass.
- You want to know the service's error rate and latency before release, so you can tell afterwards whether the feature changed them.
If the feature changes contracts between services, so that two or more repositories must change together, read Ship a cross-repository change as well. This page stays inside one service and only checks what sits around it.
Before you start
- CodeZero is installed in VS Code and signed in, with Claude Code, Codex, GitHub Copilot or Cursor as the agent.
- Your organisation's repositories are connected and indexed, including shared libraries and the repositories that hold deployment config (Helm charts, Kubernetes manifests, Compose files). If those are not indexed, CodeZero cannot see them either.
- The service you are changing is checked out locally. CodeZero prefers your working tree, so it sees your current branch and uncommitted work.
- For the runtime checks: Vörr is connected to Claude, ChatGPT or another MCP assistant, and your observability and CI/CD tools are connected in Vörr. ChatGPT needs a paid plan with Developer mode turned on. Vörr answers from the organisation's connected sources, and workspaces label what comes back. An admin connects sources and maintains the service map.
If any of this isn't set up yet, start here:
Operations
These are the operations that make up feature work, in roughly the order you would do them. Skip the ones that do not apply. A one-line change does not need a feature map, but a new flow usually needs all of them.
1. Map the feature area
- CodeZero: open Functions and find the functional area closest to your feature, for example Invoicing or Checkout. Read its path: Entry, Goes Through, Reads / Writes and the other repositories involved.
- CodeZero: open Graph on the service to see which modules import which, the third-party packages it uses and the tables it reads and writes.
- CodeZero Chat: ask how the area works end to end, and follow the file references it gives you.
- Agent: open the entry point and the main module in your local checkout and read them.
Explain how invoice creation works today in billing-api, from the HTTP entry point to the tables it writes. Name the files, the shared packages it imports and any other repositories involved.Using the Invoicing feature in Functions, which modules would a new 'due date' field on invoices pass through, and which of them belong to other repositories?A good result names real files, each with a reference you can open, and separates what is in this repository from what lives elsewhere. Check it by opening two or three of the referenced files. Feature names are generated once someone in the organisation selects Name all features, so treat them as a guide to where to look, not as a specification.
2. Find where similar behaviour already lives
- CodeZero: search across all indexed repositories for the behaviour, not just the name you expect. Try the topic ('due date', 'business day', 'time zone'), likely symbol names, and the libraries such code would import.
- CodeZero: for each candidate, look up the definition and its references. A helper with many callers in several services is usually the one to reuse.
- CodeZero: check owners and recent commits on the candidate, to see whether it is maintained and who to ask.
- Agent: compare the candidate's behaviour with what the feature needs before deciding to reuse it.
Before writing anything: does any repository in the organisation already compute a date in a customer's time zone, or work out a due date or business day? Search by topic as well as by name, and include shared packages. List each match with its repository, file and how many places call it.Compare the matches you found. Which one handles time zones and daylight-saving changes, which is most widely used, and which would you reuse for invoice due dates?A good result lists candidates with repository, file and caller count, and says which repositories it searched. Matching is by name and keyword, so a helper with an unusual name may only turn up through its topic words or the package that exports it. If nothing turns up, ask for the search terms that were used before you accept that the helper does not exist.
3. Learn the conventions to follow
- CodeZero: look at the repository overview for languages, frameworks and entry points, and at its declared HTTP routes to see how existing endpoints are named and grouped.
- CodeZero Chat: ask for the most similar existing feature and how it handles validation, errors, logging and tests.
- Agent: read that feature's files and its tests locally, and use them as the template.
Find the endpoint in billing-api that is most similar to 'set an invoice due date'. Show how it validates input, maps errors, logs and is tested, so the new code follows the same pattern.A good result points at one or two concrete files to copy the shape of, not general advice. If the service has more than one style, ask which is newer: recent commits per path show which pattern people are moving towards.
4. Reuse a helper instead of re-creating it
- CodeZero: confirm where the helper is defined and how the service can reach it, for example through a package dependency already in its manifest.
- CodeZero: check the service's declared dependencies to see whether the shared package is already installed, and which version.
- Agent: import and call the helper. If it is close but not quite right, propose a change to the helper in its own repository rather than writing a local copy, and treat that as cross-repository work.
billing-api needs the customer's local business date for invoice due dates. Use the existing helper you found instead of writing a new one. Check that its package is already a dependency of billing-api and at which version, and show me the import you will add.The existing helper does not support a configurable cut-off hour. Do not copy it. Tell me what change to the helper would cover our case, which other repositories call it, and whether that change would alter their behaviour.A good result reuses one helper and changes no other code to do it, or explains why it cannot. Before you accept a new helper, ask why the existing one does not fit.
5. Find the config and where it is actually set
- CodeZero: find the settings the service expects and where each one is set: each one's code default and its .env.example entry.
- CodeZero: search across indexed repositories for each setting's name, so that Helm values, Kubernetes manifests, Compose files and other config repositories turn up as well as code.
- CodeZero Graph: check the edges that come from deployment config, which show which services are wired to which through config.
- Vörr: ask which branch maps to which environment for the service, and use the config-to-code investigation to connect a runtime setting with the code that reads it.
- Agent: decide with you where the change belongs. That might be the code default, the per-environment values or both. If the deployment config lives in another repository, the plan must name that repository.
billing-api reads PAYMENT_TIMEOUT_MS. Where is it read in code, what is the code default, and where is it set for each environment? Search deployment config in every indexed repository, including Helm values, Kubernetes manifests and Compose files. Tell me which value production actually uses.The feature needs a new setting, INVOICE_DUE_DAYS. Following how billing-api handles its existing settings, list every place it must be added: code default, .env.example, and the deployment config for each environment.A good result gives the code default and every place the value is set, each with a file reference. It also says which value wins in production. Check it by opening the values file for production. If a deployment repository is not indexed, the answer can only cover the code default, so say so in the plan.
6. Check impact before you write
- CodeZero Chat: ask what the change would affect, including callers in other repositories, consumers of any route you change, and the tables you write.
- CodeZero Graph: look at inferred edges into the service (HTTP calls matched to its routes, queue consumers). Each edge shows file:line evidence, and HTTP edges also show a confidence. Use Verify on the HTTP edges that matter, so the agent checks the call site.
- Vörr: ask what depends on the service at runtime and in which environments it runs.
If we add a dueDate field to the invoice response and a new PATCH /invoices/:id/due-date route in billing-api, what else is affected? Include callers in other repositories, queue consumers of invoice events, and the tests that cover the current response.Which services call billing-api in production and staging, and what does billing-api depend on? Give the source for each relationship.A good result separates direct references from inferred relationships and gives file:line evidence for the inferred ones, with a confidence on HTTP and config edges. If a consumer in another repository needs to change too, move to Ship a cross-repository change for that part of the work.
7. Check runtime context before you change anything
- Vörr: get the service's current error rate, p95 latency (plus p50 and p99 where the source reports them) and throughput from each connected source, compared with the same window a week ago.
- Vörr: list the top errors on the endpoints you are about to touch, with counts and culprit.
- Vörr: check the recent deploys for the service across your CI/CD sources and any alerts that are currently firing.
- You: note the numbers. They are your baseline for the check after release.
For billing-api in production: error rate and p95 latency over the last 24 hours compared with 7 days ago, per source. Top 5 errors on /invoices routes with counts. Any deploys in the last 3 days and any firing alerts. Tell me how each service name was matched.A good result lists each figure with its source and the environment. It says how the service name was matched (explicit, identity, exact, name, suggested or unmapped), and it reports 'no connector' rather than a zero where a source is missing. If the service is unmapped, fix the mapping before you trust the baseline.
8. Plan with clarification questions
- CodeZero: describe the feature in Auto mode, which decides whether to plan first, or in Planned mode, which makes no code changes until you approve a plan. Normal mode skips the plan and asks you to confirm each change. Use /plan to force a plan for one request.
- CodeZero: answer the clarification questions it raises. These are the decisions the code cannot settle, such as the default value, behaviour for existing records and which time zone wins.
- You: review the plan. Check that it names the repositories it will change, the phases and the verification commands, and that it reuses the helper you found. The agent cannot approve its own plan.
/plan Add a due date to invoices in billing-api. Reuse the existing business-date helper rather than writing a new one. Add INVOICE_DUE_DAYS with a code default and per-environment values where the other settings are set. Follow the pattern of the existing invoice endpoints. Include the unit and integration tests to run as verification.A good plan has no silent assumptions. Every decision you did not make is either a question or written down as an assumption you can reject. If it plans to write a new helper or to edit only the code default for a setting that production reads from deployment config, send it back.
9. Implement task by task
- CodeZero: once you approve the plan, the work becomes tasks with dependencies, each attributed to a repository.
- Agent: run one task at a time and review its diff before the next. Edits in the plan's repositories go ahead. An edit in another of the organisation's repositories asks you first and names it, and anything outside them is refused.
- CodeZero: if the plan needs a repository that is not checked out, for example the deployment config repository, Clone is offered from Tasks.
- Optionally, hand the approved and fully clarified remainder to Coffee Mode. It does not commit, push or switch branches, and its summary records the decisions it made.
- You: review the working tree in Git Tree, then commit and push yourself.
10. Add and run tests through the plan
- CodeZero Chat: find the existing tests for the area and the fixtures they use, so new tests follow them.
- Agent: add tests for the new behaviour, including the edge cases the clarification questions raised, such as a time-zone boundary or a missing setting.
- CodeZero: the plan's verification commands run after approval without asking. Commands outside that list still ask first.
- Agent: if verification fails, fix it within the task and run the verification again before moving on.
Add tests for the invoice due date that cover a customer in UTC+10 at 23:30 local time, a customer in UTC-5, and INVOICE_DUE_DAYS unset. Follow the layout of the existing invoice tests and run the plan's verification.11. Check runtime health after release
- Vörr: confirm the deploy appears in the deploy feed for the right environment.
- Vörr: compare error rate and latency per source with your baseline, and check release health where your error tracker provides it.
- Vörr: look for new top errors on the routes you changed, and check for any regression windows Vörr detects (with Grafana connected), shown alongside deploys.
billing-api was deployed to production about an hour ago. Confirm the deploy, then compare error rate and p95 per source for the hour since with the hour before and with the same hour 7 days ago. Are there new errors on /invoices routes, and are there any regressions linked to this deploy?A good result ties the comparison to the specific deploy and flags where sources disagree, rather than averaging them. If something has moved, go to Debug a production error with the error sample and the deploy.
Without CodeZero or Vörr
A coding agent on its own is good at this work when everything it needs is in the folder you opened. It reads and edits files, greps, runs tests and git, and reasons well over what it finds. The gaps appear when the facts it needs live somewhere else.
Take the re-created helper. The feature needs a date in the customer's time zone. The agent greps the repository for getDate, dueDate and timezone and finds nothing relevant, because the helper lives in a shared repository that is not checked out. It is installed as a package, but node_modules is skipped by search tools, and it is called getBusinessDate, not getDate. Grep is literal and local, so an empty result looks like 'it doesn't exist'. Searching wider costs context and steps, so the agent stops and writes a new getDate. That one uses the server's clock, which is UTC, and it disagrees with the shared helper for customers ahead of UTC late in their evening. Two helpers now give different answers, and the bug only shows up for some customers.
To be fair, Claude Code can find that helper. If the shared repository is cloned on your machine and you tell the agent to search it, or to search the installed package with ignore rules off, it will find getBusinessDate and reuse it. It takes knowing that the shared repository exists, having it cloned and current, and asking for a broader search than the agent's default.
The config case is similar. Asked to raise the payment timeout, the agent finds Number(process.env.PAYMENT_TIMEOUT_MS ?? 5000) and changes 5000 to 8000. Production sets PAYMENT_TIMEOUT_MS in a Helm values file in a separate deployment repository, so the change does nothing there. The agent can find that file if the deployment repository is cloned and it knows to look. Nothing in the service's source says where the value comes from.
GitClear's analysis of changed code found duplicated blocks rising sharply in 2024 and copy-pasted lines outnumbering moved or reused lines for the first time. The report links this to assistants that find inserting new code easier than finding old code. The sources are on What the research says.
| Operation | Claude Code / ChatGPT on their own | With CodeZero and Vörr |
|---|---|---|
| Map the feature area | Reads the open repository well. Other repositories only if cloned and pointed at. | CodeZero Functions and Graph across indexed repositories, including ones not checked out |
| Find similar behaviour | Literal grep over cloned folders. node_modules and build output skipped by default. | CodeZero search by text, symbol and topic across the organisation, with references and caller counts |
| Reuse a helper | Possible if the shared repository is cloned and the agent is told to search it | CodeZero finds the definition, its callers and the dependency in the service's manifest |
| Find where config is set | Finds the code default. Deployment config only if that repository is cloned and the agent looks there. | CodeZero finds where each setting is defined in code and where Helm, Kubernetes and Compose config in other indexed repositories set it. Vörr adds branch-to-environment mapping and config-to-code investigation. |
| Check impact | Local find-usages. HTTP and queue consumers in other repositories are not references in source. | CodeZero cross-repository references and inferred HTTP, config and queue edges with file:line evidence, a confidence on HTTP and config edges, and Verify on HTTP edges |
| Plan and approve | Can write a plan, and plan mode or permission prompts can hold edits until you agree. Scope across repositories is up to your own settings. | CodeZero plans that the agent cannot approve itself, clarification questions, and confirmation before any edit outside the plan's repositories |
| Run tests | Runs any test command you allow | Same, plus the plan's verification commands run without asking after approval |
| Runtime before and after | Possible with a separately configured, credentialed MCP server or CLI per tool. The agent stitches the results together and guesses service names. | Vörr queries every connected source with resolved service names, match quality, environment and 'no connector' where a source is missing |
With CodeZero and Vörr
- Visibility beyond the checkout (CodeZero)
- Search, symbols, references and file reads across every indexed repository on the default branch, with your local working tree preferred where you have one.
- Prior art by topic (CodeZero)
- Topic search built from keywords, symbols and partial matches, so a helper with a different name can still turn up through what it does.
- Config provenance (CodeZero, with Vörr)
- CodeZero shows where a service's settings are defined and where deployment config in other repositories sets them. Vörr ties branches to environments and can investigate from a runtime setting back to code.
- Impact with evidence (CodeZero)
- Callers, inferred HTTP, config and queue edges with file:line evidence (and a confidence on HTTP and config edges), and Verify verdicts on HTTP edges that the whole organisation keeps.
- A reviewable path to the change (CodeZero)
- Clarification questions, a plan that names repositories, phases and verification, the agent unable to approve its own plan, and tasks you review one at a time.
- Runtime baseline and check (Vörr)
- Error rate and latency per source, never averaged, comparison windows, top errors, deploys across CI/CD and release health, each with its source and match quality.
The two products work side by side. Vörr does not run inside CodeZero, and CodeZero does not call Vörr. You take the baseline from Vörr into the plan as context, and take the deploy back to Vörr after release.
Worked example: invoice due dates in billing-api
The task: invoices from billing-api should carry a due date, a configurable number of days after the customer's local business date. All repository, file and service names below are examples.
First, prior art. The developer asks CodeZero to search before writing anything.
Prompt: Does any repository already compute a customer's local business date or due date?
Findings (searched 41 indexed repositories)
1. acme/shared-utils src/dates/businessDate.ts:12
export function getBusinessDate(at: Date, tz: string, cutoffHour = 0)
References: 9 across 4 repositories (orders-api, notifications-worker, reporting, billing-api: 0)
Package: @acme/shared-utils, already in billing-api/package.json at ^3.4.0
2. acme/reporting lib/period.py:30 def local_period_start(tz) (Python, reporting only)
3. acme/billing-api src/util/format.ts:5 formatInvoiceDate() (formatting only, no zone logic)
Note: acme/shared-utils is not checked out locally. Results are from the indexed default branch.Then config. The feature adds INVOICE_DUE_DAYS, and the developer wants to know where settings like it are set, using PAYMENT_TIMEOUT_MS as the pattern.
PAYMENT_TIMEOUT_MS
Read: acme/billing-api src/payments/client.ts:18 Number(process.env.PAYMENT_TIMEOUT_MS ?? 5000)
Example: acme/billing-api .env.example:7 PAYMENT_TIMEOUT_MS=5000
Set: acme/deploy-charts charts/billing-api/values-staging.yaml:22 PAYMENT_TIMEOUT_MS: "5000"
acme/deploy-charts charts/billing-api/values-prod.yaml:24 PAYMENT_TIMEOUT_MS: "3000"
Production uses 3000 from values-prod.yaml. The code default applies only where PAYMENT_TIMEOUT_MS is unset (local dev).
Vörr: billing-api main -> production, release/* -> staging (explicit mapping)The developer takes a baseline from Vörr in Claude before planning.
billing-api (production, matched explicitly via service map)
Datadog APM error rate 0.4% (7d ago 0.4%) p95 310 ms (7d ago 295 ms)
Sentry top issue on /invoices: TypeError in invoiceTotals.ts, 37 events / 24h
Argo CD last deploy 2 days ago, healthy
Alerts none firing
Prometheus no connector for this workspacePlanning in Planned mode raises two questions. Should existing invoices get a due date backfilled? The developer answers no, only new invoices. Which time zone applies if a customer has none set? The answer is the account's billing-country zone, already stored. The approved plan has two phases. Phase 1 is in billing-api: import getBusinessDate, add the field and the route, add INVOICE_DUE_DAYS with default 30 and an .env.example entry, and add tests. Phase 2 is in deploy-charts, which the developer cloned from Tasks: add INVOICE_DUE_DAYS to staging and production values. Verification is the unit and integration test commands for billing-api and a Helm template render for the chart.
Verification (billing-api)
npm test -- invoices 42 passed (3 new: UTC+10 23:30, UTC-5, INVOICE_DUE_DAYS unset)
npm run test:integration 18 passed
Verification (deploy-charts)
helm template charts/billing-api -f values-prod.yaml rendered, INVOICE_DUE_DAYS="30"After release, Vörr shows the deploy in the Argo CD feed for production. Error rate stays at 0.4% and p95 at 305 ms compared with the hour before, with no new issues on /invoices. The conclusion: the feature reuses the shared helper, so due dates match the orders and notifications services. The setting is set where production reads it, and runtime metrics are unchanged.
Follow-ups: the Sentry TypeError on /invoices predates this work and is worth its own ticket. formatInvoiceDate in billing-api could move to shared-utils, but that is a separate cross-repository change.
Verify and follow up
- Provenance: open the file reference behind each finding you rely on. Indexed results come from the default branch, so check how recent they are against recent commits if a repository moves fast.
- Match quality: in Vörr, check how each service name was matched and the environment, and treat name, suggested and unmapped matches as things to confirm.
- Coverage: an empty result from either product can mean 'not indexed' or 'no connector'. Ask which repositories or sources were covered before accepting a zero.
- Inferred edges: use Verify on any cross-repository edge that changes your plan, so the agent reads the call site and the verdict is kept for everyone.
- Tests and verification: check that the plan's verification commands actually exercise the new behaviour, not just that they pass.
- Next: if a consumer in another repository has to change, go to Ship a cross-repository change. If the work is well defined, see Delegate approved work. If you tidied the codebase on the way, see Refactor or upgrade safely.
Limits
- CodeZero's references and callers are matched by name and are heuristic, not compiler-accurate. Same-named symbols can appear, and dynamic calls can be missed.
- Topic search improves the odds of finding a differently named helper, but it is not guaranteed. A helper whose name and file share no words with your query may still be missed.
- The index covers committed code on the default branch. Unmerged work in other repositories, and repositories that are not connected, are not visible.
- Config found in repositories is only as complete as what is indexed. Values set outside Git, for example in a secrets manager or by hand in a cluster, will not appear in code search.
- Feature names are generated once someone selects Name all features, and may not match how your team talks about the area.
- Vörr's runtime answers depend on which tools are connected and how services are mapped. It is read-only and does not change config or deploy anything from chat.
- Neither product decides whether reusing a helper is right. Sometimes a local variant is justified, and that is a judgement for you and the helper's owners.