ctx-zip
Keep your AI agent context small and cheap by managing tool bloat and large outputs. ctx-zip provides two complementary techniques: Tool Discovery (transform MCP servers and tools into explorable code) and Output Compaction (persist large results to storage with smart retrieval).
Works with the AI SDK for agents and loop control. See: AI SDK – Loop Control: Context Management.
Installation
npm i ctx-zip
pnpm add ctx-zip
What It Does
ctx-zip tackles two major context problems:
1. Tool Discovery & Code Generation
Transforms MCP servers and AI SDK tools into inspectable TypeScript code in a sandbox. Instead of loading hundreds of tool schemas upfront, agents explore tools on-demand using filesystem operations.
The Problem:
Context Rot
- Tool schemas consume thousands of tokens before your prompt
- Every tool output is pulled into the model context
- Every tool definition passes through model context
- Agents can't inspect implementations to understand behavior
The Solution:
- Tools are transformed to importable code that live in the sandbox filesystem (not in context)
- Progressive Exploration: Agents explore the file system on-demand with
sandbox_ls, sandbox_cat, sandbox_grep
- Agents write and execute code that combines multiple tools
- Result: Higher reliability, fast and ~80%+ token reduction for multi-tool workflows
2. Output Compaction with Smart Retrieval
Automatically persists large tool outputs to the sandbox filesystem and replaces them with concise references. Agents can retrieve content on-demand using the same sandbox exploration tools.
The Problem:
Context Rot
- Large tool outputs (search results, file contents, API responses) bloat context
- Conversation history accumulates thousands of unused tokens
- Context windows exhaust, costs increase, performance degrades
The Solution:
- Tool outputs are automatically written to the sandbox filesystem
- Replaced with short references in conversation
- Agents retrieve data on-demand with sandbox exploration tools (
sandbox_ls, sandbox_cat, sandbox_grep, sandbox_find)
- Result: ~60-90% token reduction for tool-heavy conversations
How It Works
Technique 1: Tool Discovery & Code Generation
Transform tools into explorable code that agents can inspect and execute:
import { generateText, tool } from "ai";
import { z } from "zod";
import { SandboxManager, E2BSandboxProvider } from "ctx-zip";
const sandboxProvider = await E2BSandboxProvider.create();
const manager = await SandboxManager.create({ sandboxProvider });
await manager.register({
servers: [
{ name: "grep-app", url: "https://mcp.grep.app" },
{
name: "linear",
url: "https://mcp.linear.app/mcp",
headers: { Authorization: `Bearer ${process.env.LINEAR_TOKEN}` }
},
],
standardTools: {
weather: tool({
description: "Get the weather in a location",
inputSchema: z.object({
location: z.string(),
}),
async execute({ location }) {
const temp = 72 + Math.floor(Math.random() * 21) - 10;
return { location, temperature: temp, units: "°F" };
},
}),
},
});
const tools = manager.getAllTools();
const result = await generateText({
model: "openai/gpt-4.1-mini",
tools,
prompt: "Search the codebase, check the weather, and create a Linear issue",
});
console.log(result.text);
await manager.cleanup();
What Gets Generated:
The register() call creates a directory structure in the sandbox:
/workspace/
├── mcp/ # MCP tool implementations
│ ├── grep-app/
│ │ ├── search.ts
│ │ ├── index.ts
│ │ └── _types.ts
│ ├── linear/
│ │ ├── createIssue.ts
│ │ ├── searchIssues.ts
│ │ └── index.ts
│ └── _client.ts # MCP routing client
├── local-tools/ # AI SDK tool implementations
│ ├── weather.ts
│ └── index.ts
├── user-code/ # Agent execution workspace
└── compact/ # Tool output storage (for compaction)
Exploration Tools:
Once tools are registered, agents can explore them:
sandbox_ls(path) - List directory contents
sandbox_cat(path) - Read file contents
sandbox_grep(pattern, path) - Search in files
sandbox_find(pattern, path) - Find files by name
sandbox_exec(code) - Execute TypeScript code
Example Agent Workflow:
await sandbox_ls("/workspace/mcp")
await sandbox_ls("/workspace/local-tools")
await sandbox_cat("/workspace/mcp/grep-app/search.ts")
await sandbox_exec(`
import { search } from './mcp/grep-app/index.ts';
import { createIssue } from './mcp/linear/index.ts';
import { weather } from './local-tools/index.ts';
const results = await search({ query: 'authentication bug' });
const topResult = results[0];
const weatherData = await weather({ location: 'San Francisco' });
await createIssue({
title: 'Fix auth bug from codebase search',
description: \`Found issue: \${topResult.content}\nWeather: \${weatherData.temperature}\`,
});
return { created: true, result: topResult.file };
`);
API Reference:
const manager = await SandboxManager.create({
sandboxProvider?: SandboxProvider,
sandboxOptions?: LocalSandboxOptions,
});
await manager.register({
servers?: MCPServerConfig[],
standardTools?: Record<string, Tool>,
standardToolOptions?: {
title?: string,
outputDir?: string,
},
});
manager.getAllTools()
manager.getExplorationTools()
manager.getCompactionTools()
manager.getExecutionTool()
manager.getMcpDir()
manager.getLocalToolsDir()
manager.getUserCodeDir()
manager.getCompactDir()
manager.getWorkspacePath()
await manager.cleanup()
Technique 2: Output Compaction with Smart Retrieval
Automatically reduce context size by managing large tool outputs. Two strategies available: write-to-file (persist to storage with on-demand retrieval) or drop-results (remove outputs entirely).
import { generateText, tool } from "ai";
import { z } from "zod";
import { compact, SandboxManager } from "ctx-zip";
const manager = await SandboxManager.create();
const fileAdapter = manager.getFileAdapter({ sessionId: "my-session" });
const result = await generateText({
model: "openai/gpt-4.1-mini",
tools: {
...manager.getCompactionTools(),
fetchEmails: tool({
description: "Fetch emails from inbox",
inputSchema: z.object({ limit: z.number() }),
async execute({ limit }) {
const emails = await getEmails(limit);
return { emails };
},
}),
},
prompt: "Check my latest emails and find any about 'budget'",
prepareStep: async ({ messages }) => {
const compacted = await compact(messages, {
strategy: "write-tool-results-to-file",
storage: fileAdapter,
boundary: "all",
sessionId: "my-session",
});
return { messages: compacted };
},
});
await manager.cleanup();
Compaction Strategies:
ctx-zip provides two strategies for managing tool outputs:
Strategy 1: write-tool-results-to-file (Default)
Persists tool outputs to storage and replaces them with references. Agents can retrieve data on-demand.
How it works:
- Agent calls a tool (e.g.,
fetchEmails(50))
- Large output returned (50 emails = 10,000 tokens)
compact() runs in prepareStep:
- Agent can retrieve data:
sandbox_ls(path) - List directory contents
sandbox_cat(file) - Read entire file
sandbox_grep(pattern, path) - Search within files
sandbox_find(pattern, path) - Find files by name pattern
When to use: When you need agents to access historical tool outputs later in the conversation.
Strategy 2: drop-tool-results
Removes tool outputs entirely from the conversation, replacing them with a simple message indicating the output was dropped.
How it works:
- Agent calls a tool (e.g.,
fetchEmails(50))
- Large output returned (50 emails = 10,000 tokens)
compact() runs in prepareStep:
- Detects tool output
- Replaces output with:
"Results dropped for tool: fetchEmails to preserve context"
- No storage required - outputs are permanently removed
When to use: When tool outputs are only needed for immediate processing and don't need to be referenced later. Maximum token savings, simplest setup.
Storage Location (write-tool-results-to-file only):
When using SandboxManager with write-tool-results-to-file strategy:
/workspace/
└── compact/
└── {sessionId}/
└── tool-results/
├── fetchEmails.json
├── searchGitHub.json
└── getWeather.json
Each tool overwrites its own file on subsequent calls (one file per tool type).
Note: The drop-tool-results strategy doesn't use storage - outputs are removed from the conversation entirely.
Boundary Strategies:
Control which messages get compacted:
boundary: "all"
boundary: { type: "keep-first", count: 5 }
boundary: { type: "keep-last", count: 20 }
Sandbox Tools for Retrieval (write-tool-results-to-file only):
When using write-tool-results-to-file, use compaction-specific tools that default to the workspace root:
const manager = await SandboxManager.create();
const tools = manager.getCompactionTools();
Note: The drop-tool-results strategy doesn't require retrieval tools since outputs are permanently removed.
Example: Drop Strategy (No Storage Required)
import { generateText, tool } from "ai";
import { z } from "zod";
import { compact } from "ctx-zip";
const result = await generateText({
model: "openai/gpt-4.1-mini",
tools: {
fetchEmails: tool({
description: "Fetch emails from inbox",
inputSchema: z.object({ limit: z.number() }),
async execute({ limit }) {
const emails = await getEmails(limit);
return { emails };
},
}),
},
prompt: "Summarize my latest emails",
prepareStep: async ({ messages }) => {
const compacted = await compact(messages, {
strategy: "drop-tool-results",
boundary: "all",
});
return { messages: compacted };
},
});
API Reference:
const compacted = await compact(messages, {
strategy?: "write-tool-results-to-file" | "drop-tool-results",
storage?: FileAdapter | string,
boundary?: Boundary,
sessionId?: string,
fileReaderTools?: string[],
});
Combining Both Techniques
Use tool discovery and compaction together for maximum efficiency:
import { generateText } from "ai";
import {
SandboxManager,
compact,
E2BSandboxProvider,
} from "ctx-zip";
const sandboxProvider = await E2BSandboxProvider.create();
const manager = await SandboxManager.create({ sandboxProvider });
await manager.register({
servers: [
{ name: "grep-app", url: "https://mcp.grep.app" },
],
});
const fileAdapter = manager.getFileAdapter({
sessionId: "combined-session",
});
const tools = manager.getAllTools();
const result = await generateText({
model: "openai/gpt-4.1-mini",
tools,
prompt: "Search for authentication bugs in the codebase and summarize",
prepareStep: async ({ messages }) => {
const compacted = await compact(messages, {
strategy: "write-tool-results-to-file",
storage: fileAdapter,
boundary: "all",
sessionId: "combined-session",
});
return { messages: compacted };
},
});
console.log(result.text);
await manager.cleanup();
Benefits:
- MCP tools explored on-demand (no upfront schema loading)
- Large search results compacted to sandbox storage
- Same exploration tools work for both tool discovery and compacted output retrieval
- Maximum token efficiency and simplified API
Sandbox Providers
ctx-zip supports three sandbox environments:
Local Sandbox (Default)
import { SandboxManager, LocalSandboxProvider } from "ctx-zip";
const manager = await SandboxManager.create();
const provider = await LocalSandboxProvider.create({
sandboxDir: "./.sandbox",
cleanOnCreate: false,
});
const manager = await SandboxManager.create({ sandboxProvider: provider });
E2B Sandbox
import { SandboxManager, E2BSandboxProvider } from "ctx-zip";
const provider = await E2BSandboxProvider.create({
apiKey: process.env.E2B_API_KEY,
timeout: 1800000,
});
const manager = await SandboxManager.create({ sandboxProvider: provider });
Vercel Sandbox
import { SandboxManager, VercelSandboxProvider } from "ctx-zip";
const provider = await VercelSandboxProvider.create({
timeout: 1800000,
runtime: "node22",
vcpus: 4,
});
const manager = await SandboxManager.create({ sandboxProvider: provider });
Examples
See the examples/ directory:
-
examples/mcp/ - MCP server integration with grep.app
local_mcp_search.ts - Local sandbox
e2b_mcp_search.ts - E2B sandbox
vercel_mcp_search.ts - Vercel sandbox
-
examples/tools/ - AI SDK tool transformation
weather_tool_sandbox.ts - Transform and explore standard tools
-
examples/ctx-management/ - Full-featured compaction demo
email_management.ts - Interactive email assistant with multi-environment support
API Overview
SandboxManager
class SandboxManager {
static async create(config?: {
sandboxProvider?: SandboxProvider,
sandboxOptions?: LocalSandboxOptions,
}): Promise<SandboxManager>
async register(options: {
servers?: MCPServerConfig[],
standardTools?: Record<string, Tool>,
standardToolOptions?: ToolCodeGenerationOptions,
}): Promise<void>
getAllTools(): Record<string, Tool>
getExplorationTools(): Record<string, Tool>
getExecutionTool(): Record<string, Tool>
getMcpDir(): string
getLocalToolsDir(): string
getUserCodeDir(): string
getCompactDir(): string
getWorkspacePath(): string
getFileAdapter(options?: {
prefix?: string,
sessionId?: string,
}): FileAdapter
static createLocalFileAdapter(options: LocalFileAdapterOptions): FileAdapter
async cleanup(): Promise<void>
}
Compaction
function compact(
messages: ModelMessage[],
options: CompactOptions
): Promise<ModelMessage[]>
interface CompactOptions {
strategy?: "write-tool-results-to-file" | "drop-tool-results",
storage?: FileAdapter | string,
boundary?: Boundary,
sessionId?: string,
fileReaderTools?: string[],
}
type Boundary =
| "all"
| { type: "keep-first"; count: number }
| { type: "keep-last"; count: number }
TypeScript Support
Full TypeScript support with exported types:
import type {
SandboxProvider,
FileAdapter,
CompactOptions,
Boundary,
E2BSandboxOptions,
LocalSandboxOptions,
VercelSandboxOptions,
} from "ctx-zip";
License
MIT
Contributing
Contributions welcome! Please open an issue or PR.