On 2026-08-18 I moved yantrikdb from AGPL-3.0 to Apache-2.0. The engine commit landed at 22:32:31 UTC. The server pull request merged at 23:29:28. Fifty-seven minutes end to end.
Almost none of that was writing. It was finding the places where the old licence had been declared and changing the declaration.
I got two of them wrong on the first pass. There is a third thing I still cannot account for.
Before you touch a file
Run this:
git log --format='%an' | sort -u
If more than one name comes back, the flip is not yours to make alone. Copyright in a contribution belongs to whoever wrote it, and relicensing the project relicenses their work too.
The engine repo is 438 commits, all mine, across a few spellings of my own name. The server repo has exactly one commit that isn't mine: PR #11, RFC 006 Phase 5, claims wire opcodes plus a new GET /v1/claims, +219/-5 across six files, merged 2026-04-18, from an outside contributor.
Why
From my own commit message: "The moat is the ecosystem — engine, server, MCP, plugin, packs, web — not the licence."
AGPL bought protection against someone standing up a hosted service on top of my work, and cost every commercial evaluation that ends at legal review. The adoption evidence says the cost is the larger number. A comparable competitor six weeks younger than yantrikdb sits at 2,608 stars against yantrikdb's 48, MIT-licensed and installable in one line. Stars are not a controlled experiment.
Apache-2.0 rather than MIT because a patent has been filed on part of this work. Apache section 3 grants patent rights explicitly, and its retaliation clause terminates the licence of anyone who sues over patents. MIT is silent on patents, which leaves an implied-licence question that corporate reviewers have to resolve themselves. That is the same friction, relocated.
Also from that commit: "This is irreversible: every version published under Apache-2.0 stays available under it permanently."
Eight files
Engine commit 4411244 touched LICENSE, a new NOTICE, README.md, pyproject.toml, crates/yantrikdb-python/pyproject.toml, and the Cargo.toml in each of yantrikdb-core, yantrikdb-python and yantrikdb-wasm.
Five manifests. Two toolchains, since both pyprojects use build-backend = "maturin". Each pyproject needed two edits rather than one, a license field and a separate trove classifier, and nothing checks that the two agree.
The README change was three lines. Two were the badge and the licence line. The third:
-The [MCP server](...) is MIT-licensed — using the engine via the MCP server does not trigger AGPL obligations on your code.
+The [MCP server](...) is MIT-licensed.
letterpress
Commit 4411244's message carved out one directory by name:
NOT included: packs/letterpress, which is AGPL-3.0-or-later and references third-party photographs under licences that require attribution. Its terms are a separate decision and are not mine to flip mechanically.
Twenty-one minutes later, at 22:53:06, commit cea13b3 flipped it anyway. Two files, packs/letterpress/README.md and packs/letterpress/pyproject.toml. The reason I gave: the pack declared license = { text = "AGPL-3.0-or-later" } in its own metadata while carrying no LICENSE file of its own, so it inherited the newly-Apache repo root and contradicted itself.
That reasoning does not answer the reason I gave twenty-one minutes earlier. The photo attribution question is about the assets. The pyproject licence field is about the code. I collapsed the two together at 17:53 local time because the contradiction was the thing in front of me. I would keep them apart if I did it again.
The server
PR #94, sixteen files. The LICENSE diff was +202/-661, Apache's text being much shorter than AGPL's. LICENSE, NOTICE, README.md, DESIGN.md, SERVER_README.md, Cargo.lock, pyproject.toml, deny.toml, four crate Cargo.tomls, four crate READMEs.
The root pyproject.toml still said AGPL-3.0-only after the first commit at 22:45:23. I caught it 36 seconds later and fixed it in SHA 96053e10. Live package metadata that would have published an AGPL classifier sitting under an Apache LICENSE file.
I opened it as a PR, and said so in the body, "so the required status checks run". Seven jobs ran: format, clippy, supply-chain, chaos-gate, and build-and-test on ubuntu, macos and windows. All seven passed on the second run. Then I went and checked: GET /repos/yantrikos/yantrikdb-server/branches/main/protection returns 404, "Branch not protected". The repo's only ruleset is called "default", with enforcement: disabled. Zero required checks. Nothing would have stopped a red merge. I open PRs out of habit, and the habit is what caught the next problem.
cargo-deny
The allow list in deny.toml had this entry, and I deleted it:
"AGPL-3.0-only", # our own license
The comment above the list went from "Our own code is AGPL-3.0." to "Our own code is Apache-2.0."
CI run 32194878789 started at 22:54:53 on SHA 96053e10. The supply-chain job runs cargo deny check licenses bans sources. Output:
error[rejected]: failed to satisfy license requirements
┌─ /home/runner/.cargo/git/checkouts/yantrikdb-1317bbf12f5451d8/42dad7f/crates/yantrikdb-core/Cargo.toml:5:12
│
5 │ license = "AGPL-3.0-only"
│ ━━━━━━━━━━━━━
│ │
│ rejected: license is not explicitly allowed
│
├ AGPL-3.0-only - GNU Affero General Public License v3.0 only:
├ - OSI approved
├ - FSF Free/Libre
├ - Copyleft
├ yantrikdb v0.15.3
└── yantrikdb-server v0.16.1
Then bans ok, licenses FAILED, sources ok, and Process completed with exit code 4.
Read the file path in that error. .cargo/git/checkouts/. The server does not pull the engine from a registry at all. Line 35 of crates/yantrikdb-server/Cargo.toml, on the failing SHA, was:
yantrikdb = { version = "0.15.3", git = "https://github.com/yantrikos/yantrikdb.git", tag = "v0.15.3" }
42dad7f is the commit that tag v0.15.3 pointed at, the last one before the relicense. cargo-deny read the licence straight out of that git checkout. crates.io was never in the server's dependency path.
The unblock was a tag, not a config edit. Engine commit 473b7ae at 23:03:14, "release: v0.15.4 — Apache-2.0 relicense + embedder-identity guard", carries tag v0.15.4. Then line 35 moved:
yantrikdb = { version = "0.15.4", git = "https://github.com/yantrikos/yantrikdb.git", tag = "v0.15.4" }
That landed as server SHA 2d770017 at 23:13:12, and CI run 32196261107 started 28 seconds after it. A new run on a new head SHA, not a re-run of the failed one.
There was another way. cargo-deny supports [licenses.exceptions], and I could have scoped an AGPL exception to our own crate and left the allow list intact. I didn't. An exception would have held the gate green while the tree was genuinely mixed, and telling me the tree is mixed is the whole job of the gate. Deleting the entry made the build fail for a true reason.
You can disagree with that.
What the registries know
None of that involved crates.io, but crates.io matters for a separate reason: a registry only learns your licence changed when you cut a release. crates.io still serves yantrikdb 0.15.3 as AGPL-3.0-only, published 2026-08-18T05:04:17Z. 0.15.4 at 23:11:19Z is the first Apache-2.0 one. Every version before it stays AGPL on crates.io permanently, for everyone who pins one.
PyPI got there first, by about a minute. Wheels uploaded 23:10:13 through 23:10:25, carrying the classifier License :: OSI Approved :: Apache Software License.
Where else the licence lived
yantrikdb-mcp's README has a competitor comparison table. The License row read:
| License | MIT (engine AGPL-3.0) | Apache 2.0 | Apache 2.0 | Apache 2.0 | MIT |
Three of the four alternatives Apache, one MIT, our own cell qualifying itself. A shorter table higher up the same file had | **License** | MIT (engine: AGPL-3.0) |. CONTRIBUTING.md there has a License section naming the engine's licence too.
Then the GitHub repo description, which is a string in GitHub's database that never touches git. The engine's already said Apache-2.0. The server's still read "Rust, AGPL, ships as library / MCP server / HTTP cluster" after PR #94 merged. I found it while writing this, in the same hour, and fixed it with gh repo edit yantrikos/yantrikdb-server --description "...".
One concrete unblock: yantrikdb-mcp was being held back from the Docker MCP Registry, which takes permissive licences only. It is eligible now.
The engine repo had 48 stars at the time of the commit and has 50 now. There is no data yet on whether any of this worked and there won't be for a while.
The linter
scripts/consistency_check.py is 108 lines and runs twice a day. Its file mtime is 23:06Z on 2026-08-18, which is to say I wrote it in the middle of all this. Its docstring lists the motivating examples: "yantrikdb-mcp's comparison table said AGPL after the Apache relicense", and "PyPI classifiers contradicting the repo LICENSE".
It queries PyPI and npm. There is no crates.io code path in it, so it could not catch a crates.io licence mismatch. For repo descriptions it checks that one exists, not what it says. Both holes are mine and I know they are there.
The one I left alone
docs/papers/ still says AGPL. Section 13.3 of skill-substrate-experience-report-v4.md reads, in full:
YantrikDB is AGPL-3.0. Non-trivial barrier for proprietary commercial adoption; appropriate for research-and-substrate positioning. Dual licensing on inquiry. I do not present AGPL as an unambiguous advantage.
That text exists at two paths, one a Zenodo bundle. It is dated and published. Rewriting it to match tonight would make it wrong about the day it carries. The repo keeps a CORRECTIONS.md, and that is where this goes.
The lockfile
Here is the part I have not worked out. The Cargo.lock sitting on the server's main branch right now records:
name = "yantrikdb"
version = "0.15.3"
source = "git+https://github.com/yantrikos/yantrikdb.git?tag=v0.15.4#42dad7f19c0b7b43b54e1af1c5c492a5c4ad10ef"
Tag v0.15.4 points at 473b7ae. 42dad7f is the pre-relicense commit. The lockfile names the new tag against the old commit and still calls it 0.15.3. That same lockfile was on the SHA where all seven checks went green, cargo-deny included. I noticed it while writing this and I have not chased it.
Pranab Sarkar, Independent Researcher. Building yantrikdb, saga-mcp, brainstorm-mcp, and icantmarket.com.
Top comments (0)