Inspiration

Agentic development is a quick way to code and solve problems, but it is nearsighted, seldom understandable or aligned with human intent. Tests and linters catch local problems but rarely show how one change affects the whole repository.

I wanted to keep LLM agents on a leash, to ensure my code style is enforced. Partially, the idea from this project came from the blog post about the bun rewrite in rust, which talks about how hard it is to enforce a style guide in LLMs on large codebases. We also got inspired by https://github.com/hslee16/Archy when making our parsing engine.

Now, I already use My Code, My Rules (MCMR) in a few projects of my own to control code quality and reduce bugs. It forces every agent to consider both the part it is changing and the whole software system around it, including interfaces between different languages.

What it does

My Code, My Rules is a repository-wide policy engine. A Rust kernel reads the whole codebase once (Python, Rust, Typescript, C++) and converts the repository into typed fact tables queried by 285 rules.

By default, MCMR only runs deterministic, local, and stateless modes, and model judgment and external evidence are opt-ins.

The retrieved data powers deterministic and contextual rules, which can be easily defined as python functions defining a dependency injection pattern. The users can then build or toggle rules as they like to suit their liking.

Contextual rules make external calls to openrouter (Deep Seek V4 Flash 0731) or can use claude code / codex harnesses. These kinds of rules provide the model with a global view of the codebase graph and calls, ensuring best software architectures practices are enforced.

Rules output Findings, which name exact source locations and measurements. With writeback enabled, these populate datahub with schemas, lineage, ownership, tags, and governance as evidence. That is how we can keep track of how our codebase evolves and the agent can use this to understand what is critical or harder to update, and MCMR can even use datahub as a provider for more rules.

For repairs, MCMR can run autofixes, if those are defined by the rule, but the point is to use MCMR in a feedback loop with an agent trying to fix everything.

How we built it

We started by defining the rule interface, which is a simple python decorator and defining all rules based on several books on coding best practices, blog posts and projects like pylint, clippy, ruff, etc. Each rule explain its motivation and references in their docstrings.

The Rust kernel uses oxc, tree-sitter, and ruff_python_parser. Python bindings are available via PyO3 and Maturin expose its facts to Python, where each rule runs one declarative Polars query.

Contextual candidates are batched so one model request evaluates several cases. DataHub reads use GraphQL, HTTPX, and SQLGlot. Writeback uses assertions, lineage, incidents, and run records.

Challenges we ran into

Originaly, each rule run through loops, entirely parsing the python codebase via ast, but profiling showed this approach was impossible, so converting all codebase information to a set of linked tables was the best solution we could come up on time. This allowed a rust backend to quickly fill the tables and since polars is already built on rust, sending the tables to python was not so hard.

An assertion indexing race made DataHub writeback take minutes, but declaring all assertions before reporting their results reduced it to seconds.

Autofix is still very limited, but we could built solutions for a few deterministic rules.

Accomplishments that we're proud of

MCMR analyzes a multi-language repository through one shared fact graph.

MCMR has a very simple interface that let's users play around to build powerful and fast rules with a lot of flexibility.

The demo extracts 188 facts from 3 files and reports 81 precise findings in under 1 sec (deterministic only).

We could translate recommendations and ideas of software engineering from several books and popular authors in a way that composes itself, but doesn't lock the user. You don't need to agree with the rule default settings nor that it has to exist in your codebase.

We use MCMR to control LLM agents, preserve software architecture, and reduce bugs and regressions during development thanks to its integration with Datahub, which allows us to study how code evolves.

What we learned

LLMs can be the solution for hard application of soft rules. Especially rules that are not easy to code and require some expertise knowledge about mistakes that can be made during development. Instead of providing them with the code itself, if we give LLMs metadata and statistics about the codebase, they can also use that to reason much more globally but still within context.

Metadata history becomes valuable when targeted toward action.

DataHub knows a field changed while the repository knows where it is used. Together, they identify the affected line, owner, downstream impact, and whether a safe replacement exists.

Agents need durable and deterministic memory, not just the current written code.

What's next for My Code, My Rules

We improve autofix so it can be more flexible and use it even for contextual rules.

We also need stronger contextual evaluations, safer DataHub retries, and support for more languages and include config files in the analysis.

Built With

Share this project:

Updates