---
title: "Caveman vs Mastra: token compression for Mastra agents"
description: "Mastra is the framework your TypeScript agent runs on. Caveman Middleware is an adapter that wraps a Mastra agent and shrinks large tool results before each model call. Keep Mastra for agents, workflo"
canonical: https://caveman.ac/compare/mastra
last-updated: 2026-10-04
---

# Caveman vs Mastra: token compression for Mastra agents

Mastra is the framework your TypeScript agent runs on. Caveman Middleware is an adapter that wraps a Mastra agent and shrinks large tool results before each model call. Keep Mastra for agents, workflows and memory, and add Caveman where tools return more text than the next step needs.

## What is Mastra?

Mastra is an open-source TypeScript framework for AI agents and applications. Its homepage calls it "the leading TypeScript agent framework", and the repo has about 28k GitHub stars. The core is Apache 2.0. Enterprise features live in `ee/` folders under a source-available Mastra Enterprise License that is free for development and testing.

It covers a lot of ground in one package:

- **Agents** with instructions, tools built with `createTool()`, and models picked with a `provider/model` string.
- **Workflows**, a graph-based engine with suspend and resume for human-in-the-loop steps.
- **Memory**, including conversation history, RAG retrieval and observational memory.
- **Processors** that run before and after the model, at each step of the loop.
- **Evals and observability**, plus Mastra Studio for building and testing agents locally.
- **MCP server** authoring.

The framework is free. Mastra's hosted platform has a $0 Starter tier (100K observability events and 24 CPU hours a month), a Teams tier at $250 a month, and custom Enterprise and self-hosted plans. Its homepage lists case studies from teams including Replit, Sanity, WorkOS and MongoDB.

## Does Caveman work with Mastra?

Yes. `@caveman-ai/middleware/mastra` is a native adapter for `@mastra/core >=1.65 <2`. You pass your existing agent to `withCavemanMastra` and call `generate` or `stream` on the result, same as before. This is the docs example:

```js
import { withCavemanMastra } from '@caveman-ai/middleware/mastra';
export async function run({ agent, messages, runtime, scope }) {
  if (runtime.mode !== "off") await runtime.ready(); // ready() throws in off mode
  const wrapped = withCavemanMastra(agent, { runtime, scope });
  return wrapped.generate(messages, { maxSteps: 4 });
}
```

Under the hood it is built on Mastra's own processor system. On each call the wrapper adds a Caveman input processor in front of the processors you configured, keeps your `prepareStep`, and registers a `caveman_retrieve` tool built with Mastra's `createTool`. Your Agent config is not mutated. Right before the provider call, eligible tool-result text in the outbound prompt is swapped for a shorter version from a local Caveman runtime. Your memory and message history keep the originals. If the model needs a detail that got cut, it calls `caveman_retrieve` and gets the exact original back.

Tool results that failed or were denied are left alone, as are user messages, system prompts and images.

For a feel of the size change: the Caveman docs send a 400-line worker log as a tool result, and the runtime counted 8,399 tokens before and 177 to 187 after across sixteen runs. Those are inferred `o200k_base` counts on one synthetic log, not a bill.

## Mastra vs Caveman: feature comparison

| | Mastra | Caveman Middleware |
| --- | --- | --- |
| What it is | TypeScript framework for agents and workflows | Adapter that shrinks tool results before model calls |
| License | Apache 2.0 core, enterprise features source-available | MIT client and adapters, BSL local runtime |
| Calls the model | Yes, through its model router | No, Mastra still makes the call |
| Agents, workflows, memory | Yes | Uses yours |
| Context trimming | `TokenLimiter` drops older messages, `ToolCallFilter` drops tool calls | Leaves history as is |
| Shrinks large tool results | Not built in | Yes, on the outbound copy |
| Getting cut content back | Dropped content is not sent | `caveman_retrieve` returns the original |
| Observability | Built-in traces, evals, Studio | Per-call decision reports |
| Hosted option | Mastra platform | None needed, runtime runs locally |
| Maturity | Established | Alpha, `0.1.0-alpha.2` |

## When should you use Mastra alone?

Use Mastra alone when your tools return short results. There is nothing to compress in a status code or a three-field JSON object, and Caveman will report `no_candidate` or `not_smaller` and send the original.

It is also the right call when `TokenLimiter` and `ToolCallFilter` already keep your context in check and answers stay good. Dropping old tool calls is cheap and simple. You only need something smarter when the tool results you keep are the expensive part.

One Mastra-specific note: when a call uses structured output, forces a specific tool, or limits `activeTools` so `caveman_retrieve` is excluded, the adapter does not offer the recovery tool for that call. Without recovery the runtime shortens nothing, so that call goes out unchanged. Plan your trial on a normal text-output agent first.

## When does adding Caveman pay off?

It pays off when a Mastra agent reads files, calls APIs that return big JSON, runs shell commands or pulls documents. Each of those results is resent on every later step. A 20k-token API response fetched at step 2 of a 10-step run rides along on eight more model calls.

Caveman shortens it on each resend. After the first cut it resends the exact same shortened bytes, reported as `reused`, so the provider's cached prefix stays byte identical.

It stacks with Mastra's processors. `TokenLimiter` decides how much history goes out. Caveman shrinks the tool results inside what is left, at the last moment before the provider call.

If the Caveman runtime is unreachable, the call goes through with the original input. After three straight failures the adapter skips the runtime for 30 seconds. The agent keeps running either way.

## How to add Caveman to a Mastra agent

1. `npm install @caveman-ai/middleware @caveman-ai/sdk`
2. Start the runtime with `CAVEMAN_MODE=compress caveman start`.
3. Wrap the agent: `withCavemanMastra(agent, { runtime, scope })`.
4. Log `onReport` and look for `applied` and `reused`.

The [Mastra switch guide](/switch/mastra) walks through each step with the runtime setup, scope and rollback. The [supported frameworks page](https://docs.caveman.so/docs/sdk/middleware/frameworks) has the version gates, and [how to measure agent cost](/guides/measure-agent-cost) shows how to judge the result on finished tasks.

## FAQ

**Does Caveman replace Mastra?**
No. Mastra still runs your agents, workflows, memory and model calls. Caveman only shortens tool-result text in the copy of the request sent to the provider.

**Does it work with `agent.stream()`?**
Yes. `withCavemanMastra` wraps both `generate` and `stream`.

**Will it change what Mastra stores in memory?**
No. The shortened text exists only in the outbound request. Your stored messages and tool results keep their original content.

**Where does the scope come from?**
You pass one, or a function that builds it from Mastra's `requestContext`. Derive it from your authenticated user and conversation, never from model input.

**Does Caveman need Mastra's hosted platform?**
No. The adapter and runtime run in your own environment, next to Mastra wherever you deploy it.

## Sources

- [Mastra homepage](https://mastra.ai/)
- [Mastra docs](https://mastra.ai/docs)
- [Mastra processors](https://mastra.ai/docs/agents/processors)
- [Mastra pricing](https://mastra.ai/pricing)
- [mastra-ai/mastra on GitHub](https://github.com/mastra-ai/mastra)
- [Caveman middleware: supported frameworks](https://docs.caveman.so/docs/sdk/middleware/frameworks)
