
What fast-jev-compaction does
fast-jev-compaction is an npm library and Claude Code plugin for reducing long agent transcripts without rewriting them into a summary. Instead, it asks the Jev model to score old tool calls and tool results, then keeps, truncates, or removes them according to configurable thresholds.
User and assistant text remains verbatim and in its original order. Only tool calls and their matching results are candidates for removal. This avoids losing exact constraints, file paths, commands, and error messages through conventional summarization.
The repository contains both the reusable package under src/ and a Claude Code function-hook plugin under hooks/ and .claude-plugin/.
How compaction works
Each
tool_useis paired with itstool_resultthroughtool_use_id.Calls in the first message and the newest
preserveRecentMessagesmessages are pinned, so they are not modified.The complete conversation is presented to Jev from oldest to newest. Tool-result contents are replaced in this decision state by short notes such as
ok, 4213 chars (omitted), while tool inputs and text remain available.For every non-pinned call, Jev answers two questions: whether knowing about the call still matters, and whether the full result must remain available verbatim.
The returned probabilities are compared with
keepThreshold.The transcript is rebuilt without leaving an orphaned result behind.
Decision outcomes
If the result score meets the threshold, both the call and complete result are retained.
If only the call score meets the threshold, the call remains and the result is shortened to its first
truncateHeadCharscharacters followed by a note.If neither score meets the threshold, the call and its result are removed together.
Messages that become empty are removed. Messages that do not need changes are returned as the same objects.
Fitting large histories into Jev requests
The decision state has a default ceiling of 25000 estimated tokens. If the original state is too large, the library progressively shortens the representation shown to Jev. It truncates tool inputs, abridges long text using the head and tail, collapses old messages, reduces old calls to one-line records, omits old call-less messages, and folds runs of old call-only messages together.
These transformations affect the state used for scoring, not the preserved text in the final transcript. If the state still cannot fit, compaction throws an error.
Questions are also divided into batches so that each state-plus-question request stays below maxRequestTokens, which defaults to 30000. Requests run concurrently, and their decisions are merged.
Install the npm library
Install the package and provide a TypeSafe API key through the environment:
npm install fast-jev-compaction
export TYPESAFE_API_KEY=...Do not commit the API key or place it directly in a source file.
The default client reads process.env.TYPESAFE_API_KEY. You may also supply an apiKey option when calling the API.
Compact a transcript
Import compactMessages, prepare a transcript, and pass any options that differ from the defaults:
import {
compactMessages,
reductionRatio,
type Message,
} from 'fast-jev-compaction';
const transcript: Message[] = [
{
role: 'user',
text: 'Fix the failing test. Never edit src/generated.',
toolUses: [],
},
{
role: 'assistant',
text: '',
toolUses: [
{
tool_use_id: 'toolu_1',
tool: 'Read',
input: { file_path: 'src/a.ts' },
},
],
},
{
role: 'user',
text: '',
toolUses: [],
toolResults: [
{ tool_use_id: 'toolu_1', text: '…file contents…' },
],
},
];
const result = await compactMessages(transcript, {
preserveRecentMessages: 4,
});
console.log(result.messages);
console.log(result.decisions);
console.log(result.stats);The exported Message type is a subset of Claude Code's SessionMessage, so Claude Code session transcripts can be passed to the package directly.
Inspect whether compaction was worthwhile
The package exports reductionRatio, which can help an application decide whether to use the compacted history:
const result = await compactMessages(transcript);
if (reductionRatio(result) < 0.25) {
// Keep the original transcript or use another fallback.
} else {
// Continue with result.messages.
}The result statistics include message and character counts before and after compaction, decision counts grouped by reason, the estimated state size, the fitting stage used, and the number of Jev requests.
Configure compaction behavior
The main options are:
apiKey: TypeSafe API key. It defaults toTYPESAFE_API_KEY.model: Jev model name. The default isjev-latest.baseUrl: System One endpoint. The default ishttps://api.typesafe.ai/v1/systemone.fetch: injectable fetch implementation, particularly useful in tests.goal: ongoing task description included in the state. By default, it uses the last three user prompts.keepThreshold: minimum probability required to keep a call or full result. The default is0.5.preserveRecentMessages: number of newest messages that cannot be modified. The default is6; the first message is also always preserved.maxStateTokens: estimated token ceiling for the decision state. The default is25000.maxRequestTokens: estimated ceiling for state plus questions in one request. The default is30000.truncateHeadChars: number of leading characters retained when a result is truncated. The default is300.
const result = await compactMessages(transcript, {
goal: 'Fix the test without editing generated files',
keepThreshold: 0.6,
preserveRecentMessages: 8,
truncateHeadChars: 500,
});A higher keepThreshold requires stronger keep probabilities and can therefore remove more tool activity. Because a probability is not proof that deletion is safe, evaluate threshold changes against representative transcripts.
Use a custom Jev transport
If the built-in TypeSafe client does not fit your environment, implement the exported JevAsker interface. It requires an ask(state, questions) method. Then call compact(messages, asker, options) instead of compactMessages.
The package also exports buildJevRequest for constructing the HTTP request body and parseJevResponse for response validation. Lower-level building blocks are available for more specialized integrations:
collectToolCallspairs calls with their results.fitStateprepares a state within the configured size ceiling.batchCallsdivides questions across requests.decideCallconverts scores into a keep, truncate, or remove decision.applyDecisionsrebuilds the message history.
Install the Claude Code plugin
The plugin requires Claude Code 2.1.274 or later. Function hooks are an early-access feature, so enable them wherever Claude Code runs. For example, add the environment settings to ~/.claude/settings.json:
{
"env": {
"CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1",
"TYPESAFE_API_KEY": "<your key>"
}
}Add the repository as a plugin marketplace and install the plugin:
claude plugin marketplace add tamaratran/fast-jev-compaction
claude plugin install fast-jev-compaction@fast-jev-compactionThe installer prompts for options such as thresholds and truncateHeadChars. Leave the API-key option at its default to use TYPESAFE_API_KEY from the environment.
Restart Claude Code or run:
/reload-pluginsAfter activation, both /compact and automatic compaction pass through the Jev hook. A successful replacement reports a toast similar to fast-jev-compaction: kept N/M messages, no summary (...). If Jev fails or the reduction is insufficient, the hook falls back to Claude Code's built-in summary.
Run the plugin directly from a checkout
You can test the repository without publishing or installing it:
CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude --plugin-dir .Run this command from the repository root.
Advanced usage tips
Protect active work
Increase preserveRecentMessages when recent tool outputs are likely to be reused. Calls in these messages are pinned and cannot be removed or truncated.
Provide a precise goal
The default goal is derived from the last three user prompts. For long or shifting sessions, explicitly setting goal can give Jev a clearer description of the ongoing task.
Use statistics to define fallback policy
Inspect result.stats and reductionRatio(result) rather than accepting every compacted result automatically. Short sessions may not produce enough reduction to justify replacing the original transcript.
Plan for errors
Compaction throws when Jev fails, returns malformed data, omits a required key, or receives a history that cannot be fitted within the state limit. Wrap library calls in error handling and retain the original transcript or invoke another compaction strategy when necessary. The Claude Code hook already falls back to its built-in summary.
Understand request cost
The full fitted state is repeated for every question batch. A history near the state ceiling may therefore require one large request for each small group of questions. Review the request count in result.stats when tuning limits.
Test without network calls
The repository's unit tests use a fake Jev implementation and never contact TypeSafe. A custom JevAsker or injected fetch implementation can support the same approach in your application tests.
Development commands
When working from the repository, install dependencies and run the available checks:
npm install
npm run typecheck
npm test
npm run build
npm run validate:plugin
TYPESAFE_API_KEY="$(cat ~/.typesafe_key)" npm run demoThe demo command performs the live network check. The repository also contains a macOS SwiftUI animation under demo/JevDemo. It dramatizes compaction with a canned transcript and does not call the API:
demo/JevDemo/build.shPress space in the app to replay the animation.
Important limitations
Only tool calls and results can be removed or truncated. Text messages remain unchanged in the output.
Token counts are estimates derived from character patterns rather than a tokenizer.
Jev's probabilities do not guarantee that a result is safe to delete, although the assistant can re-run a removed tool call when necessary.
Every request batch repeats the full state, which can increase cost for histories close to the configured ceiling.
Conclusion
fast-jev-compaction offers an alternative to lossy conversation summaries by preserving user and assistant text while selectively pruning stale tool activity. Use the npm API for application-level control, the Claude Code plugin for automatic integration, and the provided thresholds, preservation settings, statistics, and fallback behavior to tune compaction for your workflow.
