CODECUBE VENTURES

Chimpiler - From Morning Idea to Shipped .NET Tool by Evening

Chimpiler - From Morning Idea to Shipped .NET Tool by Evening

Chimpiler started one morning when I got tired of writing another EF Core migration for an ordinary schema change.

The workflow is familiar: update a model, run dotnet ef migrations add, check in the migration code, apply it, repeat. That still makes sense when a change needs custom data work or a carefully staged rollout. But for a lot of model-shaped changes, it felt like ceremony I should be able to avoid.

So I wondered whether I could take the compiled DbContext model and turn it directly into a DACPAC. By evening, the first version of Chimpiler was on GitHub and published as a NuGet tool.

That's pretty much how Chimpiler started. A small enough problem to work on in the morning, and something other people could install by the end of the day. Since then, the repo has become a place for me to try other practical .NET tooling ideas.

Starting with EF Core models

The original command is chimpiler ef-migrate. It reads DbContext types from a compiled assembly and generates a DACPAC for each context. It doesn't need a live database connection, existing EF Core migrations, or hand-written schema SQL.

chimpiler ef-migrate -a path/to/YourApp.dll

You can also select one fully qualified context name and choose the output directory:

chimpiler ef-migrate -a path/to/YourApp.dll \
  -c YourNamespace.OrdersDbContext \
  -o ./dacpacs

Under the covers, Chimpiler loads the assembly through reflection, finds the DbContext types, builds each EF Core runtime model, and translates the relational metadata into SQL Server schema objects with DacFx. The result is one DACPAC per context, ready for something like SqlPackage or an Azure DevOps pipeline.

That doesn't make migrations obsolete. They're still the right tool when a deployment is more than “make the database look like this model,” especially for custom transformations and staged changes. ef-migrate is for the other cases, when the model is the source of truth and a state-based schema artifact is what I actually want to ship.

Applying DACPACs to PostgreSQL

One of the newer experiments is chimpiler dacpac apply. It reads a SQL Server Database Project DACPAC through DacFx's public model APIs, validates a small supported subset, and makes its own PostgreSQL DDL plan.

export CHIMPILER_DACPAC_CONNECTION_STRING="Host=localhost;Database=app;Username=app;Password=..."

chimpiler dacpac apply ./Database.dacpac \
  --provider postgresql \
  --dry-run

I wanted this path to be pretty cautious. Planning is deterministic and state-based, with no rename inference; a rename becomes an addition and a destructive removal. --dry-run still takes the advisory lock, inspects the target catalog, and prints the SQL plan, but rolls the transaction back without changing the schema. You can also write the plan to a file for review:

chimpiler dacpac apply ./Database.dacpac --script ./deployment.sql

Each apply uses a PostgreSQL transaction and transaction-scoped advisory lock, so an error rolls back the whole deployment. Drops and type changes are rejected unless --allow-destructive is supplied. Unsupported object types, expressions, and DACPAC pre- or post-deployment scripts fail closed instead of being guessed at.

This isn't SqlPackage pointed at PostgreSQL. DacFx's deployment APIs target SQL Server. Chimpiler only uses DacFx to read the package model; it handles the compatibility checks, catalog inspection, planning, PostgreSQL SQL generation, and execution itself.

A local knowledge base for agent work

Chimpiler also has kb, a local GraphRAG-style knowledge base for command-line and agent workflows:

chimpiler kb init
chimpiler kb add ./docs
chimpiler kb graph-search "how do I generate a dacpac?"

Everything lives in one SQLite database by default. There's no cloud service or Python environment involved. The default embedding provider works without a download, or you can install a local ONNX model for better semantic retrieval:

chimpiler kb models install default

The graph part is evidence-first. Indexing creates document, chunk, and structural nodes, but doesn't try to infer people, organizations, or relationships from prose. An agent reviews the retrieved source and registers entities and relationships against exact evidence. Then graph-search expands through those agent-authored, evidence-backed links. The result is a trail to inspect, not a substitute for reading the cited source.

That's a boundary I want to keep with tools like this: make the local part easy to run, but leave the important judgments visible and reviewable.

A couple of other details

There was also an earlier Docker-based OpenClaw manager called clawcker. It was a useful experiment, but it's being deprecated and isn't where I'm taking Chimpiler.

The name still makes me smile. I've always liked the simian thread running through Ximian, Mono, and Xamarin, and somehow “Chimpiler” hadn't already been claimed.

For now, Chimpiler is still small by design. It's a place to take one of those “I wish this .NET workflow were less awkward” thoughts and see if I can turn it into a useful command.

See more in the archives