Skip to content

Add cross-harness ghost user-installed surface detector (#166)#179

Merged
willwashburn merged 2 commits intomainfrom
worktree-agent-aeab7c4adde1e84af
Apr 28, 2026
Merged

Add cross-harness ghost user-installed surface detector (#166)#179
willwashburn merged 2 commits intomainfrom
worktree-agent-aeab7c4adde1e84af

Conversation

@willwashburn
Copy link
Copy Markdown
Member

@willwashburn willwashburn commented Apr 28, 2026

Summary

  • New detectGhostSurface(...) orchestrator + per-harness GhostSurfaceAdapters (claudeGhostAdapter, codexGhostAdapter, opencodeGhostAdapter) in @relayburn/analyze. Adapters enumerate user-installed surface files (Claude ~/.claude/{agents,skills,commands}/, Codex ~/.codex/{prompts,skills,rules,memories}/, OpenCode opencode.json declared skills + custom commands + project skills folder) and the orchestrator cross-references basenames against an observed-names set mined from the turn stream to flag ghosts that ride in every system prompt but are never invoked.
  • Surfaced via burn waste --patterns ghost-surface with a labeled section, JSON output (ghostSurface array), and unified-finding rendering (--findings). Suggested fix is a command-style WasteAction: mkdir -p <archive-dir> && mv <path> <archive-dir>/.
  • OpenCode dedup vs. Waste detectors: OpenCode-specific (skill catalog bloat, skill recall non-dedup, skill pruning protection) #54: declared catalog skills are still surfaced (so the user knows what to remove from opencode.json) but emitted with cost: 0 and a catalog (#54) note to avoid double-counting against the existing SystemPromptTax detector.
  • The GhostSurfaceInputs contract reserves a userTurnTextBySession field for the Ghost surface: detect Codex/Claude slash-command invocations from session content #172 slash-command follow-up so it can land without a breaking change. claudeGhostAdapter and codexGhostAdapter carry an inline doc note that slash-command-style invocations are not currently detected from tool calls.

Acceptance criteria

  • Single entry point (detectGhostSurface) runs per-harness adapters via DEFAULT_GHOST_ADAPTERS.
  • At least one fixture per harness covering a ghost case — including the canonical Codex prompts/openspec-archive.md example called out in the issue. Smoke-tested against the user's real ledger and it surfaced ~/.codex/prompts/openspec-archive.md as predicted.
  • OpenCode results do not double-count skills already flagged by Waste detectors: OpenCode-specific (skill catalog bloat, skill recall non-dedup, skill pruning protection) #54's catalog-bloat detector — declared catalog skills emit cost: 0 with countedByCatalogBloat: true; project-folder skills and custom commands cost normally.
  • Surfaced via burn waste alongside existing finding categories — new --patterns ghost-surface value, dedicated text/JSON sections, folded into --findings envelope.
  • claudeGhostAdapter and codexGhostAdapter carry inline notes that slash-command-style invocations are a Ghost surface: detect Codex/Claude slash-command invocations from session content #172 follow-up.
  • Build passes (pnpm run build); 727 tests pass (pnpm run test); no lint errors (no lint step in this repo).

Test plan

  • pnpm run build
  • pnpm run test (727 passed, 0 failed)
  • Smoke-tested node packages/cli/dist/cli.js waste --patterns ghost-surface and --findings against the live ledger — output renders the new Ghost user-installed surface table and surfaces real ghosts including the issue's canonical example.

Closes #166


Open in Devin Review

Detects user-installed surface files (agents/skills/commands/prompts/rules
/memories) that ride in every session's system prompt but are never invoked
in the observed window — across Claude, Codex, and OpenCode via per-harness
GhostSurfaceAdapters. Surfaced through `burn waste --patterns ghost-surface`
with a `mv <path> <archive-dir>/` command-style WasteAction. OpenCode
declared-catalog skills emit at $0 to avoid double-counting against the
existing #54 catalog-bloat detector. Adapter inputs reserve a
userTurnTextBySession field for the #172 slash-command follow-up so it can
land without a breaking change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Merge resolves the packages/cli/CHANGELOG.md conflict against #148's
OpenCode compaction-event entry by keeping both [Unreleased] bullets.

Devin review fixes (PR #179):

1. Severity / usdPerSession used cumulative cost instead of per-session
   cost. `GhostSurfaceFinding` now carries a `costPerSession` field
   (sizeTokens × dollarPerToken); the unified WasteFinding envelope reads
   that for `estimatedSavings.usdPerSession` and severity classification.
   `cost` stays cumulative so the `burn waste` ghost-surface table column
   keeps its meaning. A 100k-session × small-per-session ghost no longer
   ranks above a single high-cost retry loop.

2. Suggested-fix `mv` action interpolated paths without shell quoting
   (broken on spaces) and tried to `mv` synthetic OpenCode JSON-pointer
   paths like `opencode.json#/commands/foo` (not real files). Real-path
   ghosts now use POSIX single-quoted paths; synthetic OpenCode entries
   emit a `paste`-style instruction pointing at the config fragment to
   remove instead of an `mv` command.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@willwashburn willwashburn merged commit b0e1a17 into main Apr 28, 2026
2 checks passed
@willwashburn willwashburn deleted the worktree-agent-aeab7c4adde1e84af branch April 28, 2026 22:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Waste detector: ghost user-installed surface (cross-harness)

1 participant