Complete reference for all configurable parameters in Active Context Pruning (ACP).
ACP reads config from up to three layers (later layers override earlier):
| Layer | Path | Scope |
|---|---|---|
| Global | ~/.config/opencode/acp.jsonc |
All sessions |
| Config dir | $OPENCODE_CONFIG_DIR/acp.jsonc |
All sessions in this config dir |
| Project | .opencode/acp.jsonc (searched upward from cwd) |
Current project only |
Tip: Add
"$schema": "https://raw.githubusercontent.com/ranxianglei/opencode-acp/master/dcp.schema.json"for IDE autocompletion.
Status legend: ACTIVE = currently used | DEPRECATED = kept for backward compatibility, scheduled for removal (may still take effect until then) | EXPERIMENTAL = may change
- Type:
boolean - Default:
true - Status: ACTIVE
- Description: Master switch. Set to
falseto completely disable ACP.
- Type:
boolean - Default:
true - Status: ACTIVE
- Description: Automatically check for and install ACP updates on startup, tracking the dist-tag/spec the plugin was installed with (
opencode-acp@stablefollows thestabletag; range specs like^1.14.0followlatest). Version-locked specs are never updated.
- Type:
boolean - Default:
false - Status: ACTIVE
- Description: Enable debug mode. When
true, ACP sends a chat notification after each compression showing block details, and setslogLeveltodebug(INFO/DEBUG logs plus per-request context snapshots at~/.config/opencode/logs/acp/). This flag overrideslogLevelwhen set totrue.
- Type:
"debug" | "info" | "warn" | "error" | "silent" - Default:
"info" - Status: ACTIVE
- Description: File log verbosity for
~/.config/opencode/logs/acp/daily/<date>.log. Defaultinfowrites decision-level events by default (nudge decisions, transform summaries, auto-update checks, model switches).warn/errorreduce output;silentdisables file logging entirely;debugadditionally enables per-request context snapshots and verbose dumps. Ignored whendebug: true.
-
Type:
string -
Default: unset —
$XDG_DATA_HOME/opencode/storage/plugin/acp(i.e.~/.local/share/opencode/storage/plugin/acp) -
Status: ACTIVE
-
Description: Directory where per-session state files (
{sessionId}.json— compression blocks, nudge state, token stats) are persisted. Path semantics:- Absolute path → used as-is
~/~/...→ expanded against the home directory- Relative path → resolved against the project directory (where opencode was started)
The directory is created automatically if it does not exist. If you set this option and the session's state file still exists at the default location, ACP logs a WARN (once per session) instead of migrating it — move the file manually if you want to keep the session history.
- Type:
"off" | "minimal" | "detailed" - Default:
"off" - Status: ACTIVE
- Description: Compression notification verbosity.
"off"— No notifications"minimal"— Brief one-line summary"detailed"— Full block details (topics, token counts, ranges)
- Type:
"chat" | "toast" - Default:
"toast" - Status: ACTIVE
- Description: Delivery method for compression notifications.
"toast"— Transient toast popup (recommended; non-blocking)"chat"— Inject as a chat message (may freeze session on providers that reject empty messages)
- Type:
string[] - Default:
[] - Status: ACTIVE
- Description: Glob patterns for files whose content should be protected from compression. When the model reads a file matching these patterns, the tool output is injected into compression summaries instead of being compressible. Example:
["**/*.env", "**/secrets.json"]
Controls ACP slash commands (/acp context, /acp stats, etc.).
- Type:
boolean - Default:
true - Status: ACTIVE
- Description: Enable or disable all
/acpslash commands.
- Type:
string[] - Default:
["task", "skill", "todowrite", "todoread", "compress", "decompress", "batch", "plan_enter", "plan_exit", "write", "edit"] - Status: ACTIVE
- Description: Tool outputs from these tools are protected from compression. These tools' outputs survive intact in visible context. An explicit array replaces the default (use
[]to protect nothing).
- Type:
boolean - Default:
true - Status: ACTIVE
- Description: Allow ACP to run in sub-agent sessions. When enabled, subagent sessions get full compression, nudge, and context-management capabilities. Set to
falseto restrict ACP to the main session only. - Migration: Moved from
experimental.allowSubAgents(defaultfalse) to top-levelallowSubAgents(defaulttrue) in v1.14.13. The oldexperimental.allowSubAgentskey is still read for backward compatibility — top-level takes priority.
Experimental features that may change or be removed.
- Type:
boolean - Default:
false - Status: EXPERIMENTAL
- Description: Enable loading custom prompt overrides from
~/.config/opencode/acp-prompts/.
Core compression behavior.
- Type:
"ask" | "allow" | "deny" - Default:
"allow" - Status: ACTIVE
- Description: Permission level for the
compresstool."allow"— Auto-approve compression calls"ask"— Prompt user before each compression"deny"— Block all compression calls
- Type:
boolean - Default:
true - Status: ACTIVE
- Description: Show compression status indicators in the chat UI.
- Type:
boolean - Default:
true - Status: ACTIVE
- Description: Inject summary buffer guidance into the system prompt, helping the model understand which blocks exist and their coverage.
- Type:
number | \${number}%`` - Default:
"80%" - Status: ACTIVE
- Description: Upper context usage threshold (as % of model context window or absolute tokens). When exceeded, ACP nudges the model to compress. Example:
"80%"or100000.
- Type:
number | \${number}%`` - Default:
"80%" - Status: DEPRECATED
- Description: Deprecated — scheduled for removal. Lower context usage threshold for turn/iteration reminder nudges. ACP stops injecting those reminders when usage drops below this level (or when the limit cannot be resolved to a concrete value, e.g. a
"X%"limit with an unknown model context window). Growth nudges are governed separately byminNudgeContextPercent. Still honored until removed; when it is removed, the lower-bound gating for turn/iteration reminder nudges is retired along with it (new sessions should rely on the growth-nudge system).
- Type:
Record<string, number | \${number}%`>` - Default:
undefined - Status: ACTIVE
- Description: Per-model override for
maxContextLimit. Keyed by model ID. Example:{"gpt-4": 80000, "claude-3-opus": "50%"}
- Type:
Record<string, number | \${number}%`>` - Default:
undefined - Status: DEPRECATED
- Description: Deprecated — scheduled for removal alongside
minContextLimit. Per-model override forminContextLimit. Still honored until removed.
- Type:
number - Default:
128000 - Status: ACTIVE
- Description: Fallback context window (absolute tokens) used when the model's limit is unknown — e.g. custom providers with no declared limit, headless spawn+resume sessions where the limit was never learned, or the brief window after a model switch invalidates a stale limit. Drives all percentage thresholds (
maxContextLimit/minContextLimit), the emergency nudge override, batch cleanup GC, and in-flight tool-output truncation. The real model limit always takes precedence when known, as do per-model overrides (modelMaxLimits/modelMinLimits). Set to0to disable the fallback (legacy behavior: no safety net until the limit is learned).
- Type:
number - Default:
5 - Status: ACTIVE
- Description: Minimum number of turns between nudge injections. Prevents nagging the model every turn.
- Type:
number - Default:
5 - Status: ACTIVE
- Description: Floor for growth-triggered nudges, as a percentage of the model context window: a growth nudge requires context usage at or above this percentage (in addition to the growth threshold). Over-max (
maxContextLimit) and the 98% emergency-override nudges bypass the floor. If the model context window is unknown, the floor is unresolvable and growth nudges fall back to growth-only behavior. Turn/iteration reminder nudges are governed byminContextLimit, not this field. The default is deliberately low: with the defaultnudgeGrowthTokens(50K), a 5% floor stays inert for typical working cycles and only binds on very large (≥2M-class) windows — a higher default (e.g. 15%) would bind on ≥400K windows and shift every compress cycle's working range upward on large-window models. Set0to disable the floor entirely, or raise it (e.g. 15–30%) to keep growth nudges waiting until a larger share of the window is in use. Can be narrowed per provider / per model viacompress.providers(issue #344).
- Type:
Record<string, ProviderOverrides>whereProviderOverrides = Partial<CompressOverridableConfig> & { models?: Record<string, Partial<CompressOverridableConfig>> }(all fields optional at both levels) - Default:
undefined - Status: ACTIVE
- Description: Nested per-provider / per-model overrides for every tunable compress field, resolved field-by-field with the cascade model > provider > global (mirrors the sibling project billion-context-pi, issue #344). Deeper levels only override when the field is explicitly set — unset fields never clear shallower values.
0/falseare explicit values, not "unset". Unknown provider/model ids fall back to the global value. Percentages and"X%"limits resolve against the active model's context window. Across the three config file layers (global → config dir → project) the maps deep-merge per provider/model key — a project layer can narrow one provider without wiping others configured in lower layers. - Overridable fields:
maxContextLimit,emergencyThresholdPercent,minNudgeContextPercent,nudgeFrequency,iterationNudgeThreshold,toolOutputNudgeThreshold,nudgeGrowthTokens,minNudgeGrowthRatio,minNudgeGrowthFloor,nudgeForce,protectedTools,showCompression,summaryBuffer,protectTags,protectUserMessages,maxSummaryLengthHard,minCompressRange,maxVisibleSegments,keepEmbedMaxChars,lastSegmentSoftBlock,preserveRecentMessages,preserveRecentTokens,preserveLastUserMessage,reasoning(nested, field-wise). - Not overridable:
permission(session-level, fixed before model info is known), the deprecatedminContextLimit/modelMinLimitsfamily, the flatmodelMaxLimits/modelMinLimitsmaps themselves, andprovidersitself.modelMaxLimitsitself is not deprecated — it remains fully supported (only outranked). FormaxContextLimitthe precedence when set nested is nested override >modelMaxLimitsflat map > global.protectedToolsset here affects the compress tool and nudge-side logic; the system-prompt protected-tools listing (shown at prompt build time, before model info is available) always reflects the global value.
{
"compress": {
"maxContextLimit": "55%",
"minNudgeContextPercent": 5,
"nudgeGrowthTokens": 50000,
"providers": {
"anthropic": {
"minNudgeContextPercent": 8,
"nudgeForce": "strong",
"models": {
"claude-sonnet-4-6": {
"minNudgeContextPercent": 30,
"maxContextLimit": "70%",
"nudgeGrowthTokens": 20000,
},
},
},
},
},
}In this example, for anthropic/claude-sonnet-4-6: the floor is 30%, the over-max band starts at 70% of the window instead of the global 55% (a larger working range before over-max nudges kick in), the growth threshold is 20K, and nudges use the strong tone (inherited from the provider level). Every other Anthropic model gets the 8% floor and strong tone but keeps the global band and 50K growth threshold; everything else uses the pure global values. Provider keys are provider ids and model keys are model ids (as reported by the active session, e.g. anthropic, claude-sonnet-4-6).
- Type:
number - Default:
50000(fixed) - Status: ACTIVE
- Description: The nudge growth threshold. ACP nudges when context grows by this many tokens since the last nudge. The default is a fixed value, identical for all model context window sizes (was previously scaled as a percentage of the window — removed in v1.14.23 because it made small-window models nudge ~4× more often).
- Type:
number - Default:
undefined - Status: ACTIVE
- Description: Token threshold for the tool-output-specific nudge. When tool outputs exceed this, a targeted nudge suggests compressing them.
- Type:
number - Default:
15 - Status: ACTIVE
- Description: Inject an iteration nudge when this many messages accumulate since the last user message (indicates long tool-use chains without user interaction).
- Type:
"strong" | "soft" - Default:
"soft" - Status: ACTIVE
- Description: Nudge tone.
"soft"— Informational, lets the model decide"strong"— More urgent, emphasizes context overflow risk
- Type:
string[] - Default:
["skill", "compress"] - Status: ACTIVE
- Description: Tool outputs from these tools are soft-filtered from compression ranges. Unlike
commands.protectedTools(hard-protect), these are excluded from compressible ranges but their content may still be referenced in summaries. An explicit array replaces the default.
Note:
"compress"is force-appended to this list regardless of user config — compression tool calls must never be lost.
- Type:
boolean - Default:
false - Status: ACTIVE
- Description: When
true,<dcp-message-id>tagged content is protected from compression.
- Type:
boolean - Default:
false - Status: ACTIVE
- Description: When
true, all user messages are protected from compression (not just the last one).
- Type:
number - Default:
20000 - Status: ACTIVE
- Description: Hard limit on summary length in characters. Compression calls with summaries exceeding this are rejected.
- Type:
number - Default:
5000 - Status: ACTIVE
- Description: Minimum estimated tokens in a compression range. Ranges smaller than this are filtered out from recommendations (not worth compressing).
- Type:
number - Default:
0.45 - Status: ACTIVE
- Description: Ratio of
nudgeGrowthTokensused to calculate the nudge growth floor. Higher value = less frequent nudges.
- Type:
number - Default:
5000 - Status: ACTIVE
- Description: Minimum nudge growth threshold in tokens. The actual threshold is
max(this, minNudgeGrowthRatio × nudgeGrowthTokens).
- Type:
number | \${number}%`` - Default:
"98%" - Status: ACTIVE
- Description: Context usage threshold for "emergency" mode. When exceeded, ACP overrides all protection filters and forcefully nudges the model to compress immediately.
- Type:
number - Default:
50 - Status: ACTIVE
- Description: Maximum number of visible context segments to display in the system prompt's segment guidance.
- Type:
number - Default:
2000 - Status: ACTIVE
- Description: Maximum characters to embed per message when using
[[KEEP:mNNNNN]]markers in compression summaries.
- Type:
boolean - Default:
true - Status: ACTIVE
- Description: When
true, the last visible segment (most recent messages) is treated as a soft-block — excluded from compression recommendations but can be overridden withdangerous: true.
- Type:
number - Default:
5 - Status: ACTIVE
- Description: Number of most recent messages to protect from compression. These messages are soft-filtered from compressible ranges. Set to
0to disable.
- Type:
number - Default:
5000 - Status: ACTIVE
- Description: Token budget for recent-message protection. In addition to the last N messages, ACP also protects messages within this token budget (expanding backward from the most recent message). Set to
0to disable.
- Type:
boolean - Default:
true - Status: ACTIVE
- Description: Always protect the most recent user message from compression, regardless of
preserveRecentMessagesorpreserveRecentTokens.
- Type:
object { drop?: boolean; threshold?: number } - Default:
{ "drop": true, "threshold": 2048 } - Status: ACTIVE (#368)
- Description: Config for dropping oversized reasoning (thinking) parts from historical
compresstool calls.compresscalls are hard-exempt from compression, so their thinking rides along every request as an unreclaimable context floor. This pass removesreasoningparts at request time (persisted history is never modified) from closed-turn compress messages whose total reasoning length exceedsthreshold. The active round (from the last genuine user message onward) is never touched. - Fields:
drop(boolean, defaulttrue) — master switch;falsedisables the whole pass.threshold(number, chars, default2048) — single-thinking size gate: the message's total reasoning length must exceed this to be dropped. Small thinkings are kept; lengths are NOT accumulated across messages.0drops any non-empty reasoning (only zero-length reasoning survives).
- Per-provider/model overrides (field-wise, via the
compress.providerscascade):
{
"compress": {
"reasoning": { "drop": true, "threshold": 2048 },
"providers": {
"my-gateway": { "reasoning": { "drop": false } },
"anthropic": {
"reasoning": { "threshold": 8000 },
"models": { "claude-opus-4-5": { "reasoning": { "threshold": 16000 } } },
},
},
},
}Resolution: model-level reasoning > provider-level reasoning > global compress.reasoning, field by field (a field set at a deeper level overrides only that field). Provider/model IDs come from the current request's model identity.
- Type:
number - Default:
32768 - Status: ACTIVE
- Description: Tokens reserved for the model's completion by the context-budget guard. The guard estimates the request's input size and, if it exceeds
window - completionReserveTokens, deterministically truncates (then clears) old compressible tool outputs until it fits — summaries, protected tools, the first user message, and the last 3 messages are never touched. The default32768covers opencode's32000max_tokensfallback for models with no declaredlimit.output. The guard is a no-op unless the model's context window is known (declaredlimit.contextin opencode.json, or a catalog entry). An absolute (number)compress.maxContextLimitdoes not enable the guard — it is a soft nudge threshold, not the backend's real limit.
Note: The GC truncation module (
gc/truncate.ts) was removed in v1.14.4. The remaininggcfields are used for block generation tracking and batch cleanup (block merging). Old config files with these fields continue to work.
- Type:
"truncate" - Default:
"truncate" - Status: DEPRECATED
- Description: Historically selected the GC algorithm. Only
"truncate"was ever implemented. Now a no-op — kept for config compatibility.
- Type:
number - Default:
5 - Status: ACTIVE
- Description: Number of message-transform cycles a compression block must survive before being promoted from
"young"to"old"generation. Old-gen blocks are eligible for batch merging bygc/merge.ts.
- Type:
number - Default:
9007199254740991(Number.MAX_SAFE_INTEGER) - Status: DEPRECATED
- Description: Historically controlled age-based block deactivation. Set to infinity — effectively disabled. Kept for config compatibility.
- Type:
number - Default:
3000 - Status: ACTIVE
- Description: Maximum length (in characters) for a merged summary when batch cleanup consolidates multiple old-gen blocks into a higher-tier block.
- Type:
number | \${number}%`` - Default:
"100%" - Status: ACTIVE
- Description: Context usage threshold that triggers emergency tool output truncation. When context reaches this level, the largest tool outputs are truncated (keeping 2000-char prefix + suffix) to free space. Set to
"200%"or higher to effectively disable. Summaries are never truncated.
Batch cleanup consolidates multiple old-gen blocks into higher-tier blocks.
- Type:
number | \${number}%`` - Default:
"55%" - Status: ACTIVE
- Description: Context usage threshold for low-priority batch cleanup. At this level, batch cleanup considers merging old-gen blocks.
- Type:
number | \${number}%`` - Default:
"75%" - Status: ACTIVE
- Description: Medium-priority batch cleanup threshold.
- Type:
number | \${number}%`` - Default:
"90%" - Status: ACTIVE
- Description: Force batch cleanup threshold. At this level, batch cleanup aggressively merges all eligible blocks.
Post-compression quality evaluation. Runs after each compression to verify summary quality.
- Type:
boolean - Default:
false - Status: ACTIVE
- Description: Enable post-compression quality evaluation. When
true, ACP evaluates each compression summary against quality metrics. Failures are logged but do not block compression (non-blocking).
- Type:
string - Default:
"rouge-recall-v1" - Status: ACTIVE
- Description: Quality gate algorithm to use. Currently only
"rouge-recall-v1"is available.
- Type:
object - Status: ACTIVE
- Description: Algorithm-specific parameters. See below.
| Parameter | Type | Default | Description |
|---|---|---|---|
layer1MinChars |
number | 200 | Minimum summary length in characters |
layer1MinRetentionPct |
number | 5.0 | Minimum content retention percentage |
layer2MaxRougeF1 |
number | 0.05 | Maximum ROUGE-1 F1 score for "too similar" detection |
layer2MaxTop20Recall |
number | 0.20 | Maximum top-20 keyword recall for quality check |
Message filters strip or deduplicate third-party plugin injections (e.g. oh-my-opencode system reminders, context dumps, task directives) from the visible context before ACP processes them. Filtered content never gets a message ref and is never counted toward context usage or compression triggers.
Since v1.14.8, ACP ships five built-in oh-my-opencode (OMO) filters, all enabled by default:
| Filter | Version | Behavior |
|---|---|---|
omo-system-reminder |
1.3.0 | Keeps the last 2 OMO <system-reminder> messages; for older ones, strips the <system-reminder> blocks and <!-- OMO_INTERNAL_INITIATOR --> markers but preserves your actual user content |
omo-context |
1.0.0 | Keeps only the latest OMO [CONTEXT] injection; drops earlier duplicates |
omo-task-directive |
1.0.0 | Keeps only the latest OMO TASK: / ## TASK directive; drops earlier ones |
omo-todo-continuation |
1.0.0 | Keeps only the latest OMO TODO CONTINUATION directive; drops earlier ones |
omo-mode-injection |
1.1.0 | Strips leading mode blocks (<ultrawork-mode>, [search-mode], …) and preserves user content |
- Type:
boolean - Default:
true - Status: ACTIVE
- Description: Master switch. When
false, no filters run.
- Type:
object—Record<filterName, { enabled: boolean; keepLast?: number }> - Default: all built-in filters enabled
- Status: ACTIVE
- Description: Per-filter configuration.
enabledtoggles a single filter on/off.keepLast(dedup filters only) sets how many of the most recent matching messages to keep — default1, exceptomo-system-reminderwhich defaults to2.
Example:
{
"messageFilters": {
"enabled": true,
"filters": {
"omo-system-reminder": { "enabled": true, "keepLast": 2 },
"omo-context": { "enabled": true },
"omo-task-directive": { "enabled": true },
"omo-todo-continuation": { "enabled": true },
"omo-mode-injection": { "enabled": true },
},
},
}{
"compress": {
"maxContextLimit": "45%",
"minContextLimit": "35%",
"preserveRecentMessages": 3,
"preserveRecentTokens": 2000,
"nudgeFrequency": 3,
},
}{
"compress": {
"maxContextLimit": "70%",
"minContextLimit": "60%",
"preserveRecentMessages": 15,
"preserveRecentTokens": 10000,
"nudgeFrequency": 8,
"protectedTools": ["skill", "bash", "read", "grep", "glob"],
},
}{}{
"compress": {
"modelMaxLimits": {
"gpt-4o": 80000,
"claude-3.5-sonnet": "60%",
"gemini-1.5-pro": 150000,
},
"modelMinLimits": {
"gpt-4o": 60000,
"claude-3.5-sonnet": "50%",
},
},
}{
"compress": {
"minNudgeContextPercent": 5,
"providers": {
"anthropic": {
"minNudgeContextPercent": 8,
"models": {
"claude-sonnet-4-6": { "minNudgeContextPercent": 30 },
"claude-haiku-4-5": { "minNudgeContextPercent": 0 },
},
},
},
},
}Floors resolve as model > provider > global (field-by-field). 0 disables the floor for that model — useful for small-window models where the growth threshold alone is the right signal.
The same cascade works for every tunable field, not just the floor — e.g. give one heavy model a tighter growth threshold and a lower over-max band while its siblings keep the global profile:
{
"compress": {
"providers": {
"anthropic": {
"models": {
"claude-sonnet-4-6": {
"nudgeGrowthTokens": 20000,
"maxContextLimit": "40%",
},
},
},
},
},
}See the compress.providers reference for the full overridable field list.
{
"protectedFilePatterns": [
"**/*.env",
"**/*.pem",
"**/*.key",
"**/credentials.json",
"**/secrets.*",
],
}The five built-in OMO filters are on by default (see messageFilters). Keep more recent system-reminders, disable a single filter, or turn the whole subsystem off:
{
"messageFilters": {
"enabled": true,
"filters": {
// keep the last 3 OMO system-reminders instead of 2
"omo-system-reminder": { "enabled": true, "keepLast": 3 },
// disable one filter, keep the rest
"omo-task-directive": { "enabled": false },
},
},
}{
// turn all message filters off
"messageFilters": { "enabled": false },
}{
// Absolute path, ~ expansion, or project-relative
"storagePath": "~/data/acp-state",
}These parameters existed in older versions and have been removed. Config files containing them will show a warning toast but continue to work.
| Parameter | Version Removed | Replacement |
|---|---|---|
strategies.deduplication.* |
PR #206 | Compression tool handles duplicates |
strategies.purgeErrors.* |
PR #206 | Compression tool handles error pruning |
compress.automaticStrategies |
PR #206 | Always-on; no config needed |
state.prune.tools |
PR #206 | Internal only; no config |
ACP validates config on load. Unknown keys and type mismatches trigger a warning toast. Valid keys are defined in lib/config-validation.ts (VALID_CONFIG_KEYS set).