PACE: Giving AI-Assisted Development a Memory of the Project

A working note on why AI-assisted development keeps running into the same wall, and what a project-scoped context layer would have to get right.
There’s a particular kind of pull request that has become common enough to be recognisable. The code is clean. The tests pass. The naming is idiomatic. And the first substantive review comment is some version of: this isn’t how we do it here.
This post is about the gap that comment reveals, and about PACE — Persistent AI Context Engine — a project I’ve been building to explore whether that gap can be closed with infrastructure rather than with more careful prompting. PACE is early. Its core works; large parts of the ambition around it do not exist yet. I’ll be specific about which is which, because a post that blurs the two isn’t worth reading.
The review comment that keeps recurring
Picture a developer adding a feature to an established service — a billing service, say, five years old, with the accumulated scar tissue that implies. They describe the feature to an assistant. They get back a reasonable-looking implementation: a new handler, a couple of helpers, some tests.
Review finds three things. The handler talks to the customer database directly, bypassing an access layer the team introduced specifically to keep that dependency in one place. It reimplements a retry-and-idempotency pattern that already exists two directories over under a name nobody would guess. And it takes an approach that was explicitly considered and rejected eighteen months ago, for reasons written down in a decision record that nobody reads and the assistant never saw.
None of this is dramatic. It’s a normal review. But notice what happens next.
The developer explains the abstraction in follow-up prompts. They paste in a chunk of the decision record. They point at the existing helper. The second attempt is better. The change ships. The explanation evaporates — it lived in a chat session that ends when the tab closes.
Three weeks later a teammate touches the same service and reconstructs the same explanation from scratch, slightly differently. The reviewer catches slightly different things, because reviewers are human and attention is finite. And the same two or three people who actually hold the system’s history in their heads get pulled into another review, because they’re the only ones who reliably notice.
The cost here isn’t the bad first draft. Bad first drafts are cheap now. The cost is that project knowledge gets reconstructed by hand, per person, per task, per tool, and then thrown away. Multiply that across a team and a year and it becomes one of the more expensive things an engineering organisation does without ever putting it on a roadmap.
To be fair about the landscape: modern assistants are not blind. Many index the repository, read instruction files, and follow rules the team has written down. The problem I’m describing isn’t that tools can’t see code. It’s that seeing code is not the same as knowing which of the many things visible in a repository actually govern the change in front of you — and context is not the only reason AI-generated code goes wrong.
Code shows you what exists, not what was decided
A repository is a complete record of what a system currently is and a very incomplete record of why. That gap has a specific shape, and it’s worth naming the parts.
Rejected alternatives leave no trace. The simpler design that would have been obvious to any competent engineer, and that failed for a reason nobody wants to rediscover — it isn’t in the code, because it isn’t in the code. An assistant reading the repository sees a structure that looks needlessly indirect and has every reason to propose the simpler thing. So does a new hire, for the same reason.
Deliberate compromises look like mistakes. A duplicated model in two services can be an accident or a considered decoupling choice. The code reads identically either way. “Clean this up” is correct in one case and a regression in the other, and only the reasoning distinguishes them.
Constraints outlive their explanations. A service can’t call another synchronously because of a latency budget agreed with a downstream team. A table can’t gain a column without a migration window. These are real, current, binding — and typically recorded, if at all, somewhere other than the code.
The knowledge is scattered by nature. Decision records answer why. Documentation answers how it’s meant to work. The dependency graph answers what breaks if I change this. Review history answers what we keep getting wrong. Recent commits answer what’s in flux right now. Test coverage answers how confident should I be. Each of those answers a different part of a single engineering question — “is this change safe and appropriate?” — and they live in different systems with different lifecycles. That fragmentation is the underlying problem. I want to be careful here: PACE does not connect to everywhere this knowledge might live, and any tool claiming otherwise deserves scrutiny about which sources it actually reads.
More context is not automatically better context
The obvious response — throw everything at the model, context windows are large now — is wrong in an interesting way, and understanding why is most of the design problem.
Four properties matter independently:
Relevance. A change to a payment handler is governed by a handful of decisions and constraints out of possibly hundreds. Including the rest doesn’t just waste budget; it dilutes the signal that mattered.
Freshness. A decision record from 2023 may have been superseded in 2024. A cached summary may describe a module that has since been rewritten. Stale material is worse than absent material, because it’s confidently wrong.
Authority. Not all project knowledge carries the same weight, and this is the distinction I find most important in practice. An accepted architectural decision is a commitment the team made. The code is the ground truth of what currently runs. An inferred summary — a heuristic risk score, a generated description of a module’s purpose — is a guess produced by a machine reading other machine-readable things. Those three are not interchangeable, and a system that flattens them into one undifferentiated pile of “context” will eventually let a guess override a decision.
flowchart TB
A["Recorded facts<br/>(code, dependencies, commits, coverage)"] --> D["Assembled context<br/>for this task"]
B["Accepted decisions<br/>(ADRs, constraints, conventions)"] --> D
C["Inferred signals<br/>(risk scores, summaries, derived hints)"] --> D
D --> E["Guidance the developer reads<br/>and is expected to question"]
B -. "outranks" .-> C
A -. "outranks" .-> C
The dotted edges are the point: an inferred signal is a hint, not a ruling. When a derived summary contradicts an accepted decision or the actual code, the derived summary should lose, and the disagreement should be visible rather than silently resolved.
Attention. Even with a large window, models weight what they’re given unevenly. A long, contradictory, partially-stale context is not a superset of a short, well-chosen one. It can be strictly worse.
So the engineering problem isn’t storage. It’s selection under a budget: given a task, decide what small subset of everything known about this project actually bears on it, and assemble that within a fixed token allowance. Getting freshness and conflict handling right at that level is genuinely hard, and I’d describe PACE’s current handling as functional rather than solved — snapshot invalidation is incomplete, and there’s no universal policy for resolving a superseded decision record against a conflicting convention file.
The individual solves this; the team doesn’t
One more failure mode deserves its own paragraph, because it’s the one that quietly determines whether AI assistance improves a team or just improves a few individuals on it.
An experienced engineer will, over a few weeks, develop a genuinely good working prompt for a codebase. It names the abstractions, mentions the constraints, warns about the traps. It’s effective. It’s also private — sitting in their notes, their shell history, their editor config.
Instruction files in the repository are the natural fix, and for many teams they’re a good one. They’re versioned, reviewed, shared. But they’re also a single flat document that everyone reads for every task, which means they get long, then get skimmed, then get stale, then get contradicted by a decision nobody went back to update. They work well up to a size and then stop scaling — not because the idea is wrong, but because “what governs this change” is a query, and a static file can’t answer a query.
That, roughly, is the line where a dedicated context service starts to be worth its cost: when the knowledge is large enough that selection matters, distributed enough that no single document holds it, and valuable enough that a handful of people keep getting interrupted to restate it.
What PACE actually is
PACE is a self-hostable developer-context service, scoped to a project. Its implemented core does five things:
- Gathers evidence about the project. It ingests repository content and developer events, and derives code and architecture signals from them — structure, relationships, change activity, coverage, risk indicators.
- Stores that as durable project intelligence, rather than as a per-session index that disappears.
- Selects what matters for a specific task, rather than returning everything it knows.
- Assembles that selection into context within a token budget, and can use it in model-assisted guidance.
- Retains inspectable records — persisted context snapshots, guidance sessions, project guidance, and versioned artifacts with review workflows — so that what was assembled can be examined later rather than being taken on faith.
You reach it through a dashboard, a CLI, a REST API, and a VS Code extension. Those differ in maturity: the API and dashboard are the most developed, the CLI covers a useful slice, and the extension is a working prototype rather than a polished product. Model access works against Ollama, Anthropic, and OpenAI-compatible services — which is not the same as saying every coding tool you already use is integrated. It isn’t.
I sometimes describe PACE as a control plane for project context. In ordinary language: it’s the place a team configures and manages what their AI tooling knows about their project, separate from the tools themselves — one authority that clients ask, rather than each tool maintaining its own private idea of the codebase.
The diagram reads left to right. On the left are the sources: developer tools, repositories, and inputs from the team itself. In the centre, two distinct bodies of knowledge sit side by side — code evidence derived from the repository, and recorded project guidance contributed by people. The pipeline between them gathers candidate material, selects what’s relevant to the task, applies the project’s constraints, and compiles a bounded context. On the right are intended outcomes: more relevant guidance, easier onboarding, earlier visibility of risk, and artifacts that can be reviewed rather than trusted blindly. A feedback loop runs back from outcomes into project evidence, so that what happened informs what gets assembled next time.
Two labels deserve honest treatment.
“Project Bible” is the diagram’s name for the body of accepted decisions, constraints, terminology, and guidance that a team has deliberately recorded. The label is evocative and slightly misleading, so let me defuse it: it is not infallible and not automatically authoritative. It’s a maintained artifact, and like any maintained artifact it can be out of date, internally inconsistent, or simply wrong. Its value is that it’s explicit — someone chose to write it down, and someone can be pointed at it when it turns out to be stale.
The organisational-governance elements are labelled ROADMAP, and that label is accurate. Organisation-wide policy, cross-team knowledge, and team-awareness features are ambitions, not shipped capabilities. Similarly, “architecture-safe guidance” describes an intent, not a guarantee — PACE can surface a constraint that a proposed change appears to violate; it cannot promise that a change is architecturally sound. And the infrastructure boxes in the diagram indicate where things run, not evidence of comprehensive security review or enforced tenant isolation. More on that below.
Treat the whole image as a conceptual overview: it shows relationships and intent, not a runtime trace and not a completion certificate.
Persistent evidence is not perfect memory
It’s worth separating two ideas that get conflated. PACE persists project evidence: repository-derived intelligence, recorded decisions, snapshots of what was assembled for a task, guidance sessions. That’s durable and inspectable.
It does not follow you between applications, remember every conversation you’ve had with every tool, or maintain an accurate model of your unfinished intentions. First-class memory — durable task threads, promoted summaries, goals that survive across sessions — is a design direction, not a current capability. Anyone promising automatic cross-tool memory today should be asked exactly which tools, storing exactly what.
Who this is for
These are intended audiences and plausible use cases. They’re hypotheses about who benefits, not validated customer segments — PACE has no adoption data I could honestly cite.
Developers in established codebases are the everyday users. They need to know, while writing a change, which conventions apply and which decisions constrain them — not in review, when the cost of being wrong is a rewrite.
Staff engineers and architects are the people currently paying the highest tax. They are the ones repeatedly explaining why a boundary exists. The value proposition for them is leverage: write the reasoning down once in a form the tooling can select from, instead of restating it in every review.
Platform and developer-experience teams are the likeliest internal champions, because they own the question “how do we make AI-assisted development work consistently across a team?” rather than for whoever happens to be good at prompting.
Engineering managers and CTOs are the ones who decide whether this is worth hosting. Their questions are about review cycles, maintainability, onboarding time, and whether AI adoption is actually improving delivery rather than shifting effort from writing to reviewing.
New team members may get the most immediate benefit, since a context layer is essentially a queryable version of what experienced colleagues already carry around.
Regulated and security-sensitive organisations are a potential future audience with demanding prerequisites — not a current one. Enforced access isolation, privacy-aware ingestion, and production hardening are prerequisites for that setting, and PACE does not meet them today. No compliance posture is claimed.
When you don’t need this
A context service has real setup and maintenance costs: hosting it, ingesting repositories, keeping decisions and constraints current, connecting clients. Skip it if you’re working on a small or short-lived project, a codebase straightforward enough that reading it answers most questions, or a team whose documentation and existing assistant workflows already work. “We wrote a good instructions file and it’s enough” is a legitimate resting place, and probably the right one for a lot of teams.
Three situations, honestly framed
Crossing a service boundary. A developer adds a feature that needs data owned by another service. What matters: the recorded decision that established the boundary, any constraint on how the services communicate, the existing access path, and whether anyone changed that area recently. PACE can bring those into view while the change is being designed, and can produce a snapshot showing what informed it. What it can’t do: confirm the constraint is still current if nobody updated it, or judge whether this case warrants an exception. That’s an architect’s call, and it stays one.
Onboarding into a codebase with history. A new engineer meets a module whose structure looks strange. What matters: the decision that produced it, the constraint that keeps it that way, and the surrounding code relationships. PACE can surface the reasoning alongside the code so it’s discoverable rather than tribal. The limits are honest ones — if the reasoning was never recorded, no context layer conjures it, and inferred explanations of why code looks the way it does are guesses that should be labelled as such.
Planning a refactor. Before committing, you want to know what depends on the target, where coverage is thin, and what’s changed recently. PACE can assemble dependency relationships, coverage information, and change activity into one bounded picture, which is genuinely useful for sequencing work. But derived risk signals are heuristics, code analysis fidelity varies by language, and no context layer tells you whether the refactor is a good idea. Tests and review still decide that.
What this cannot promise
A short, blunt list, because the failure mode of posts like this is a limitations section that reads like modesty theatre.
- Better context does not guarantee correct code. It improves the odds that generated code fits the system. It doesn’t make the model right.
- Stale or conflicting knowledge degrades guidance. If your decision records are wrong, PACE will faithfully surface wrong decisions. Freshness and conflict resolution are ongoing engineering problems here, not solved ones.
- Architecture checks and risk signals are heuristic. They surface concerns worth a human look. They don’t enforce correctness, and they will produce both false positives and misses.
- Human review and testing remain necessary. Nothing about this shifts responsibility for a change away from the engineer making it and the reviewer approving it.
- Ingesting a repository creates obligations. Source code contains secrets, personal data, and material that shouldn’t leave a boundary. Content-level privacy controls and enforced project-level access isolation are prerequisites for sensitive use, and they are not complete in PACE today. I’ll say that plainly rather than publish details.
- It costs effort to run. A service to host, evidence to keep current, guidance to maintain. That’s a real ongoing tax, and if the knowledge burden isn’t large it won’t pay for itself.
And a few things PACE explicitly does not do, since adjacent products sometimes claim them: it is not a universal transparent proxy in front of your existing AI tools, it does not enforce organisation-wide policy, it does not provide automatic memory across tools, it does not coordinate multi-agent work, and it does not prevent conflicting concurrent changes.
How you’d know whether it’s working
If you were evaluating this idea — PACE or anything like it — these are the questions I’d want answered. They’re evaluation criteria, not results I can report.
- Does the guidance actually reference relevant project decisions, or generic best practice dressed up as project knowledge?
- Do reviewers spend less time restating conventions the team already agreed on?
- Can a new developer find the reasoning behind a surprising piece of code without asking a person?
- Are architectural concerns surfaced early enough that acting on them is cheap?
- Is the assembled context inspectable — can you see what informed a suggestion and judge whether it was the right material?
- Does the benefit exceed the cost of running the service and keeping its knowledge current?
That last one is the real test, and it’s the one most likely to come back negative for a given team. I’d rather that be answered honestly than assumed.
Back to the pull request
Return to the billing service. The version of that afternoon I’m building toward isn’t one where the assistant is smarter. It’s one where the constraint on direct database access, the existence of the retry helper, and the record of the rejected approach are available at the moment the change is being written — because the project holds them, not because the developer remembered to paste them in.
The change still needs review. The tests still need to pass. The engineer still owns it. What changes is that the review is about the substance of the feature rather than about re-teaching the system’s history for the fourth time this quarter, and the explanation the developer gave last time doesn’t have to be given again.
PACE is one attempt at that, with a working core and a good deal still unbuilt. Whether the approach is right is an open question, and I’d rather hold it open than close it with a claim I can’t support.
So here’s the question I’d genuinely like other people’s answers to: what do you find yourself explaining to your AI tools over and over — the constraint, the convention, the decision that keeps getting rediscovered — and what would it take for your project to hold that instead of you?