A companion to our workingset study. I read the source, ran the tests, and verified the claims on this open-source SDK for multi-turn agent sessions.
ContextForge and workingset solve the exact same family of problem: do not put everything in the context window. But they are optimized for different data and different workflows.
My tool (workingset) is optimized for markdown vaults. It compacts a folder of notes into a budget-capped brief. It is a read-path tool creating a static snapshot, best for loading your customer or project context cheaply.
ContextForge is optimized for code and multi-turn agent sessions. It is an open-source Python SDK built by another engineer (Betanu701). It ingests a codebase into a SQLite knowledge tree, retrieves a working set via a BM25 index, and features a code-generation path that compacts generated files to their signatures before carrying them forward. This is a code-first design.
The shared vocabulary is intentional. The term "working set" in my prior article came directly from ContextForge's walkthrough. ContextForge even has a WorkingSet dataclass in its source. This article breaks down how ContextForge works and when you should reach for it.
I verified the technical claims by reading the 2,389 lines of Python source, running the 115 passing tests, and examining the real benchmark logs provided in the repository.
ContextForge is an Apache-2.0 Python SDK for giving LLM applications persistent, searchable context without running a separate vector database or embeddings service. It works with OpenAI, Azure OpenAI, Anthropic, and local OpenAI-compatible servers (like llama-server, vLLM, Ollama, and LM Studio).
Storage is handled by a SQLite hierarchical document store (a knowledge tree). The index is an in-memory BM25-style keyword index. It provides sub-millisecond search without external embedding models.
Here is the real quickstart code snippet:
import asyncio
import os
from contextforge import ContextForge
async def main() -> None:
forge = ContextForge(
provider="openai",
api_key=os.environ["OPENAI_API_KEY"],
db_path="./memory.db",
)
await forge.ingest_text(
"Our API uses JWT authentication. Access tokens expire after 1 hour. "
"Refresh tokens are valid for 30 days.",
title="API Auth",
category="engineering",
)
response = await forge.chat("How long are API tokens valid?")
print(response)
forge.close()
asyncio.run(main())
The query path relies on keyword extraction and branch loading. I verified the exact steps by reading the docstrings in infinite_context.py:
I tested the WorkingSet retrieval locally. I ingested 4 documents totaling 108 tokens. I then queried "how long do auth tokens last". The WorkingSet loaded exactly 2 of the 4 nodes: the auth document and a roadmap document that also mentioned auth. The total context loaded was 58 tokens instead of 108. It is real BM25 keyword retrieval in action.
This is the differentiator. The generate_project method builds an entire project file-by-file. After each file is generated, its full content is compacted to its signatures. It keeps imports, class definitions, and method declarations, but strips all method bodies. The signatures are carried forward as context for the next file.
I verified this compact-to-signatures behavior locally. A 202-token auth.py file body compacted to 77 tokens of signatures. For a realistic 5K-token file, the reduction is closer to 10x.
Here is the full generated body:
import jwt
from datetime import datetime, timedelta
class AuthService:
def __init__(self, secret_key: str):
self.secret_key = secret_key
async def login(self, user_id: str) -> str:
payload = {
"sub": user_id,
"exp": datetime.utcnow() + timedelta(hours=1)
}
return jwt.encode(payload, self.secret_key, algorithm="HS256")
And here is the compacted signature that ContextForge carries forward to subsequent turns:
import jwt
from datetime import datetime, timedelta
class AuthService:
def __init__(self, secret_key: str): ...
async def login(self, user_id: str) -> str: ...
This mechanism is what allows ContextForge to scale to large codebases. File 1 and file 1,000 use the exact same VRAM footprint.
The SDK includes a set_permanent_context(text) method which stores a permanent prefix (like a system contract or safety rules) prepended to every request. The docstring notes this "benefits from KV-cache prefix caching" so that "after the first request it costs effectively 0 tokens of recomputation."
I need to be honest here, just as I was in my prior article: real KV-cache control only exists when you self-host inference using tools like vLLM, llama.cpp, or SGLang. Against hosted APIs (OpenAI, Anthropic, Azure), you get provider-managed prompt caching. You do not get programmable KV control. The "0 tokens after first request" benefit is fully realized on local endpoints and only partially on hosted ones. This is exactly why ContextForge natively supports a local provider alongside the cloud endpoints.
The repository includes a 15-turn benchmark comparing ContextForge to an Azure AI Foundry Agent. Both sides use GPT-5.4. They were queried against a real CMS Medicare Part D dataset on Microsoft Fabric.
I am including the real numbers here. Notice that the Foundry Agent actually won 5 of the 15 turns (T03, T04, T07, T09, T12). ContextForge won the other 10. The blog does not hide the turns where the competitor won.
| Turn | Topic | FA Avg | CF Avg | Winner |
|---|---|---|---|---|
| T01 | Quinolone drugs, FL internists, 2022 | 9.0 | 10.0 | CF |
| T02 | Top 5 FL cities for quinolones | 9.0 | 10.0 | CF |
| T03 | ACE inhibitors top 10, TX, 2021 | 5.5 | 3.0 | FA |
| T04 | Top 20 Houston ACE inhibitor providers | 5.0 | 3.0 | FA |
| T05 | Total drug cost, Houston ACE inhibitors | 9.5 | 10.0 | CF |
| T06 | Year-over-year comparison 2020 vs 2021 | 9.0 | 10.0 | CF |
| T07 | Top 10 states by statin claims, 2022 | 9.0 | 8.5 | FA |
| T08 | Top 10 statin drugs in CA, 2022 | 3.0 | 6.5 | CF |
| T09 | CA statins, Family Practice providers | 5.5 | 2.0 | FA |
| T10 | FL quinolones revisited for 2023 | 1.0 | 9.5 | CF |
| T11 | ARB prescribers with a redacted surname filter | 9.0 | 10.0 | CF |
| T12 | Summary/recall of all drug classes | 9.0 | 1.0 | FA |
| T13 | Beta blockers, NY cardiologists, 2022 | 5.0 | 10.0 | CF |
| T14 | CA vs TX statin cost comparison | 5.5 | 10.0 | CF |
| T15 | Final synthesis | 3.0 | 9.0 | CF |
The key pattern is that the Foundry Agent holds up on early turns but degrades after T08 as conversation context grows. A content filter triggered on the accumulated drug prescription context, and token-window pressure eroded quality. ContextForge is immune because it manages context externally, injecting fresh context per turn.
Honesty Caveat: This benchmark is not turnkey-reproducible. It requires private Azure AI Foundry access, Microsoft Fabric, Power BI, and the specific CMS Medicare Part D warehouse. The repository is explicit that the benchmark code is a reproducibility record, not a clone-and-run script. This is the exact same honesty posture I take with my own benchmarks.
You can install the package with support for all providers:
pip install contextforge[all]
If you run a local endpoint, ContextForge supports it out of the box using httpx without requiring vendor SDKs. Common local endpoints include:
| Runtime | Base URL |
|---|---|
| llama-server | http://localhost:8080/v1 |
| vLLM | http://localhost:8000/v1 |
| Ollama | http://localhost:11434/v1 |
| LM Studio | http://localhost:1234/v1 |
| text-generation-webui | http://localhost:5000/v1 |
You can ingest code directly, then chat with the agent while it maintains context:
await forge.ingest_code("./src/")
response = await forge.chat("Where is the user login logic?")
When should you reach for which tool? They belong to the same family but target completely different optimizations.
| Feature | workingset | ContextForge |
|---|---|---|
| Primary Use Case | Markdown vaults, static context briefs | Code generation, multi-turn agent sessions |
| Context Method | Budget-capped summary snapshot | Dynamic BM25 injection, signature compaction |
| Best For | "Load my project context cheaply on the read path" | "Build an application file-by-file without token overflow" |
| Footprint | Lightweight script | Full Python SDK backed by SQLite |
| Limitations | Not optimized for source code or dynamic state | Heavier dependency, best with self-hosted endpoints for full KV benefits |
If you are building code-heavy agents or multi-turn systems, ContextForge provides an elegant, locally-backed alternative to heavy vector databases.