Context Lab started with a simple question: what actually happens to an AI session when the context window fills up?
Most products hide that problem behind abstractions. Context Lab does the opposite. It makes the pressure visible.
Why this project exists
The goal was to build a local-first app for developers who want to understand:
- context growth
- truncation tradeoffs
- information loss
- checkpointing
- tool-output pruning
- the difference between a memory and a budget
Instead of building a chat assistant, the app treats context as a lab subject. That distinction shaped nearly every implementation choice.
The app structure
The project is built with:
- Next.js App Router
- React 19
- TypeScript
- Tailwind CSS
- server route handlers for the integration points
The UI lives in app/page.tsx. Shared context logic lives in lib/context/*. Local persistence is handled in lib/storage.ts.
The core event model looks like this:
export interface ContextEvent {
id: string;
type: EventType;
content: string;
timestamp: string;
importance: "critical" | "important" | "normal" | "low";
metadata?: { command?: string; category?: string };
}
That model is what makes the app feel like a lab instead of a note editor. Messages, tool calls, retrievals, and checkpoints all share one timeline.
Deterministic compression
One of the most useful parts of the app is the compression engine. The current version is intentionally deterministic so you can reason about why something survived or got dropped.
export function compress(events: ContextEvent[], strategy: StrategyId, options: CompressionOptions): CompressionResult
The supported strategies are:
- truncation
- head/tail
- extractive
- tool-prune
- hybrid
The token estimate is deliberately labeled as an estimate:
export const estimateTokens = (text: string) => Math.max(1, Math.ceil(text.trim().length / 3.8));
That keeps the demo fast and portable while leaving room for a real tokenizer integration later.
Server routes
To keep the browser UI honest, the compare and evaluation panels call real route handlers.
Compression:
await fetch("/api/compress", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ events, strategy, options }),
});
Evaluation:
await fetch("/api/evaluate", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ events, questions, summary }),
});
That split matters because it makes the UI exercise the same request path a future provider-backed version would use.
Provider handling
The app lets the user choose a provider in the interface itself:
- OpenAI
- Anthropic
- Ollama
- LM Studio
The settings stay in local storage for now, which keeps the prototype self-contained. The provider test route accepts the selected provider, base URL, model, and key, then returns a structured local response.
await fetch("/api/provider/test", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
provider,
baseUrl: providerBaseUrl,
model: providerModel,
apiKey: providerApiKey,
}),
});
What the UI teaches
The interface shows:
- editable context
- token pressure
- strategy selection
- reason inspection
- retained vs compressed items
- evaluation questions
- session growth over time
That is important because the user should not have to infer what the model is doing.
What I would add next
There are a few natural follow-on features:
- A “run all strategies” benchmark mode.
- A real tokenizer adapter for specific model families.
- Export/import of experiment sessions.
- Shareable URLs for saved experiments.
- A richer lesson mode with interactive quizzes.
- A live request path for Ollama and LM Studio.
- A future Supabase adapter for optional persistence.
Takeaway
Context Lab is an attempt to make compression legible.
By visualizing the pressure of the context window, the app helps developers answer a practical question: what should survive, what can be summarized, and what should be discarded?
Code & more: https://www.dailybuild.xyz/project/219-context-lab

Top comments (0)