[0.42.0] - 2026-04-28
Added
- Slash-command-style invocations no longer false-flag as ghosts (#172). The
GhostSurfaceAdaptercontract gains an optionalobservedNames(inputs, candidates)hook; the orchestrator unions whatever names that returns into the per-source observed set before deciding which candidates are ghosts.claudeGhostAdapterminesuserTurnTextBySessionfor<command-name>...</command-name>markers (both<command-name>/foo</command-name>and the bare<command-name>foo</command-name>shape are recognised).codexGhostAdapterdoes a literal/<basename>match, anchored on word boundaries on both sides sohttps://example.com/foo,/foo-bar, and similar non-invocations don't false-positive. Matching is case-insensitive. Behaviour is opt-in / gated on content-sidecar availability — whenuserTurnTextBySessionis undefined or empty (sidecar pruned,content.store=off), the hook is a no-op and the detector falls back to v1 (tool-call only) behaviour. The inline doc notes onclaudeGhostAdapterandcodexGhostAdapterdocument the remaining false-negative for Codex (a prompt invoked entirely without typing/<basename>). New helpersmineClaudeCommandNamesandmineCodexSlashInvocationsare exported alongside.userTurnTextBySessionis now keyed bySourceKindfirst (Map<SourceKind, Map<string, string[]>>) so the orchestrator passes only the matching source's session texts to each adapter'sobservedNameshook — preventing Claude<command-name>/foo</command-name>markers from de-ghosting an identically-named Codex prompt and vice versa. - Oversized tool output bloat detector (#168). New
detectToolOutputBloatthat unifies two signal sources under oneToolOutputBloatshape ({ source, kind, toolName, configuredLimit?, evidencedMaxOutput, evidencedP95Output?, occurrenceCount, cost, evidence }). Signal A (Claude-only static config) reads~/.claude/settings.jsonand the project's.claude/settings.jsonand flags any mergedenv.BASH_MAX_OUTPUT_LENGTHwhose token-equivalent (chars ÷ 4) exceeds the 15000-token threshold — i.e. above 60000 characters — project settings override user, last-wins. The shape stores the raw env char value inconfiguredLimitand the converted token count inevidencedMaxOutputso consumers don't have to branch onkindto know what unit each field is in. Signal B (cross-harness session-data evidence) consumesToolResultEventRecord.contentLengthfrom the #42 substrate, maps bytes → tokens via the samebytes/4heuristic (precision deferred to #57), bucketizes by(source, toolName)post-normalizeToolNameso ClaudeBash, OpenCodebash, and Codexshellaggregate under canonicalBash, and prices the carry cost at the source turn's model input rate. Threshold defaults tomax(15000 tokens, p95 across the slice)with a sample-size guard so single-event slices don't self-exclude. New exports:detectToolOutputBloat,detectStaticConfigBloat,detectObservedBloat,loadClaudeSettings,userClaudeSettingsPath,projectClaudeSettingsPath,toolOutputBloatToFinding,BASH_MAX_OUTPUT_ENV_KEY,DEFAULT_BLOAT_TOKEN_THRESHOLD. Findings are emitted asWasteFindings withkind: 'tool-output-bloat'— Signal A pastes the corrected env line (in chars) intosettings.json; Signal B pastes ahead/tail/grepfiltering reminder for the user's CLAUDE.md / AGENTS.md. - Cross-harness ghost user-installed surface detector (#166). New
detectGhostSurfaceorchestrator + per-harnessGhostSurfaceAdapters (claudeGhostAdapter,codexGhostAdapter,opencodeGhostAdapter) flag user-installed surface files (agents/skills/commands/prompts/rules/memories) that ride in every session's system prompt but were never invoked across the observed window. Claude scans~/.claude/{agents,skills,commands}/, Codex scans~/.codex/{prompts,skills,rules,memories}/, and OpenCode walks each project'sopencode.jsondeclared skills + custom commands and the project skills folder. Output is a sortedGhostSurfaceFinding[](source,kind,path,sizeTokens,cost,sessionCount,countedByCatalogBloat?) with cost =sizeTokens × sessionCount × dollarPerToken. Adapters are declarative — adding a new harness is one entry inDEFAULT_GHOST_ADAPTERS. TheGhostSurfaceInputscontract reserves auserTurnTextBySessionfield for the #172 follow-up so slash-command invocation mining can land without a breaking change. OpenCode results dedupe against #54'sSystemPromptTax(catalog-bloat) detector by emitting declared catalog skills withcost: 0andcountedByCatalogBloat: true— the entry is still surfaced so the user knows what to remove fromopencode.json, but the dollars aren't double-counted. New finding adapterghostSurfaceToFinding(...)produces aWasteFindingwith amv <path> <archive-dir>/command-styleWasteActionper the #56 envelope.