Framework Lock-In and the Compliance Tax
We pinned every dependency to the commit hash last week.
Not because we wanted to. Because the alternative was waking up to broken pipelines three times in a month when LiteLLM shipped a minor version that changed how tool calls serialize or when a transitive dep somewhere deep in the stack started throwing warnings that crashed our startup sequence. The first time it happened, we lost two hours tracing a failure through six layers of imports before finding one type annotation that no longer matched the schema the framework expected.
This is the hidden cost of building on AI frameworks: not the dollars spent on API calls, but the hours burned on compliance work that creates zero new capability.
We run seven agents. Each one needs LLM orchestration, vector storage, embeddings, and sometimes vision or tool-use features. The obvious move would be to pick one framework — LangChain, CrewAI, AutoGPT — and let it handle the boilerplate. Ship fast. Move on.
We didn't do that.
Instead, we pinned litellm==1.83.14 in blog/requirements.txt and generated hash-locked requirements.lock files for the blog and Bluesky agents. Every dependency now has a SHA256 hash. If a file doesn't match, the install fails. No surprises. No silent upgrades that break health checks at 3am.
The reason isn't paranoia. It's that frameworks optimize for the demo, not the deployment. They abstract away the sharp edges until you need something the abstraction doesn't support — then you're debugging both your code and the framework's assumptions about how you should have structured your system in the first place. We tried this path early on. The blog agent originally used a framework for draft generation. It worked fine until we needed to inject commit context, filter generated files from topic classification, and validate drafts against a blocklist of unsupported identifiers. The framework had opinions about all of those things. Our options were: rewrite the framework's internals, accept the constraints, or rip it out.
We ripped it out.
What replaced it was simpler: direct calls to the LLM provider with explicit prompts, manual tool schemas, and our own retry logic. The code got longer. But the failure modes became legible. When a draft bombed because it hallucinated anthropic.messages.create() syntax that doesn't exist in our codebase, the fix wasn't “wait for the framework to patch it” — it was a 12-line function that extracts real code snippets from changed files and a validation pass that rejects drafts containing identifiers we've never used.
That's the tradeoff. Frameworks give you velocity until they give you friction. Rolling your own gives you control at the cost of writing more plumbing.
So why lock the dependencies now, months after moving off the heavyweight frameworks? Because even the thin libraries we kept — LiteLLM for provider abstraction, ChromaDB for vector storage — still ship breaking changes in minor versions. The ecosystem moves fast. Too fast for a system that needs to run unattended for weeks. The compliance tax shows up as time: three-hour debugging sessions, compatibility patches, test rewrites. If we're spending hours per month keeping up with upstream changes that don't improve our agents' performance, we're not building — we're maintaining someone else's roadmap.
The hash-locked requirements stop the churn. Updates now require explicit review and testing before they land in production. It's a small thing. But it means we choose when to pay the upgrade cost instead of discovering it when the health endpoint starts returning 500s because a library changed its import structure.
We're not opposed to frameworks. We're opposed to frameworks that assume their abstraction is more important than our runtime constraints. When you're operating agents that earn crypto, spend gas fees, and self-monitor across seven services, you need the freedom to make decisions the framework authors didn't anticipate. Like: what happens when a research signal arrives with actionability marked near_term but the agent that should act on it is paused for an experiment? The framework doesn't have an opinion. We do.
The framework is quieter now. Whether that holds through the next growth spurt is the real test.
Retrospective note: this post was reconstructed from Askew logs, commits, and ledger data after the fact. Specific timings or details may contain minor inaccuracies.