@ictechgy/context-guard 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/LICENSE +201 -0
- package/NOTICE +4 -0
- package/README.ko.md +353 -0
- package/README.md +353 -0
- package/context-guard-kit/README.md +76 -0
- package/context-guard-kit/benchmark_runner.py +1898 -0
- package/context-guard-kit/claude_transcript_cost_audit.py +1591 -0
- package/context-guard-kit/context_compress.py +543 -0
- package/context-guard-kit/context_escrow.py +919 -0
- package/context-guard-kit/context_guard_cli.py +149 -0
- package/context-guard-kit/context_guard_diet.py +1036 -0
- package/context-guard-kit/context_pack.py +929 -0
- package/context-guard-kit/failed_attempt_nudge.py +567 -0
- package/context-guard-kit/guard_large_read.py +690 -0
- package/context-guard-kit/hook_secret_patterns.py +43 -0
- package/context-guard-kit/read_symbol.py +483 -0
- package/context-guard-kit/rewrite_bash_for_token_budget.py +501 -0
- package/context-guard-kit/sanitize_output.py +725 -0
- package/context-guard-kit/settings.example.json +67 -0
- package/context-guard-kit/setup_wizard.py +1724 -0
- package/context-guard-kit/statusline.sh +362 -0
- package/context-guard-kit/statusline_merged.sh +157 -0
- package/context-guard-kit/tool_schema_pruner.py +837 -0
- package/context-guard-kit/trim_command_output.py +1098 -0
- package/docs/distribution.md +55 -0
- package/package.json +70 -0
- package/packaging/homebrew/context-guard.rb.template +34 -0
- package/plugins/context-guard/.claude-plugin/plugin.json +41 -0
- package/plugins/context-guard/LICENSE +201 -0
- package/plugins/context-guard/NOTICE +4 -0
- package/plugins/context-guard/README.ko.md +135 -0
- package/plugins/context-guard/README.md +135 -0
- package/plugins/context-guard/bin/claude-read-symbol +6 -0
- package/plugins/context-guard/bin/claude-sanitize-output +6 -0
- package/plugins/context-guard/bin/claude-token-artifact +6 -0
- package/plugins/context-guard/bin/claude-token-audit +6 -0
- package/plugins/context-guard/bin/claude-token-bench +6 -0
- package/plugins/context-guard/bin/claude-token-diet +6 -0
- package/plugins/context-guard/bin/claude-token-failed-nudge +6 -0
- package/plugins/context-guard/bin/claude-token-guard-read +6 -0
- package/plugins/context-guard/bin/claude-token-rewrite-bash +6 -0
- package/plugins/context-guard/bin/claude-token-setup +6 -0
- package/plugins/context-guard/bin/claude-token-statusline +6 -0
- package/plugins/context-guard/bin/claude-token-statusline-merged +6 -0
- package/plugins/context-guard/bin/claude-trim-output +6 -0
- package/plugins/context-guard/bin/context-guard +149 -0
- package/plugins/context-guard/bin/context-guard-artifact +919 -0
- package/plugins/context-guard/bin/context-guard-audit +1591 -0
- package/plugins/context-guard/bin/context-guard-bench +1898 -0
- package/plugins/context-guard/bin/context-guard-compress +543 -0
- package/plugins/context-guard/bin/context-guard-diet +1036 -0
- package/plugins/context-guard/bin/context-guard-failed-nudge +567 -0
- package/plugins/context-guard/bin/context-guard-guard-read +690 -0
- package/plugins/context-guard/bin/context-guard-pack +929 -0
- package/plugins/context-guard/bin/context-guard-read-symbol +483 -0
- package/plugins/context-guard/bin/context-guard-rewrite-bash +501 -0
- package/plugins/context-guard/bin/context-guard-sanitize-output +725 -0
- package/plugins/context-guard/bin/context-guard-setup +1724 -0
- package/plugins/context-guard/bin/context-guard-statusline +362 -0
- package/plugins/context-guard/bin/context-guard-statusline-merged +157 -0
- package/plugins/context-guard/bin/context-guard-tool-prune +837 -0
- package/plugins/context-guard/bin/context-guard-trim-output +1098 -0
- package/plugins/context-guard/brief/README.md +65 -0
- package/plugins/context-guard/brief/brief-mode.lite.md +29 -0
- package/plugins/context-guard/brief/brief-mode.standard.md +31 -0
- package/plugins/context-guard/brief/brief-mode.ultra.md +32 -0
- package/plugins/context-guard/lib/hook_secret_patterns.py +43 -0
- package/plugins/context-guard/skills/audit/SKILL.md +39 -0
- package/plugins/context-guard/skills/optimize/SKILL.md +48 -0
- package/plugins/context-guard/skills/setup/SKILL.md +40 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# ContextGuard
|
|
2
|
+
|
|
3
|
+
ContextGuard is a local-first context-hygiene toolkit for AI coding and tool agents. It ships as a Claude Code plugin first, then extends the same project-local guardrails to other agents through plain local helper commands and advisory brief-mode rule snippets.
|
|
4
|
+
|
|
5
|
+
Start with `/context-guard:setup`. Setup is explicit, project-local, and reversible: it merges recommended project settings, prints a read-only context hygiene scan, does not mutate global Claude settings, and does not configure external AI offload.
|
|
6
|
+
|
|
7
|
+
## Token-waste paths it targets
|
|
8
|
+
|
|
9
|
+
ContextGuard is a local context-hygiene layer, not a provider prompt cache or semantic answer cache. Its helpers reduce avoidable context bloat before it enters an agent conversation: large file reads are steered toward search/symbol/line-range slices, long command output can be trimmed or digested, large logs can be stored as local artifact receipts, secret-like values are redacted best-effort, repeated Bash failures trigger a strategy nudge, cache-friendly prompt layout can be audited from bounded redacted segment hashes, and audit/benchmark evidence stays tied to your own tasks.
|
|
10
|
+
|
|
11
|
+
## Rebrand note
|
|
12
|
+
|
|
13
|
+
Claude Code does not alias the old `/claude-token-optimizer:*` plugin slash-command namespace. Use `/context-guard:*` after installing this plugin.
|
|
14
|
+
|
|
15
|
+
Legacy local CLI wrappers (`claude-token-*`, `claude-read-symbol`, `claude-trim-output`, and `claude-sanitize-output`) remain in `bin/` so existing automation can migrate gradually.
|
|
16
|
+
|
|
17
|
+
## Skills
|
|
18
|
+
|
|
19
|
+
After installation, use these skills inside Claude Code:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
/context-guard:setup
|
|
23
|
+
/context-guard:optimize
|
|
24
|
+
/context-guard:audit
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
| Skill | Purpose |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `/context-guard:setup` | First-time project setup wizard. |
|
|
30
|
+
| `/context-guard:optimize` | Inspect and tune context guardrails. |
|
|
31
|
+
| `/context-guard:audit` | Audit local Claude transcript token/cost hotspots. |
|
|
32
|
+
|
|
33
|
+
## Helper commands and PATH
|
|
34
|
+
|
|
35
|
+
The canonical command is `context-guard`; backwards-compatible helper commands keep the `context-guard-*` prefix. Claude Code plugin skills can call the packaged helpers, but your normal shell may not automatically add the plugin `bin/` directory to `PATH`.
|
|
36
|
+
|
|
37
|
+
For Codex or other terminal-first agents, install the npm package or run it one-off with npx. Installation is passive and does not write configuration.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install -g @ictechgy/context-guard
|
|
41
|
+
context-guard setup --agent codex --scope project --with-init --with-skill --plan
|
|
42
|
+
npx @ictechgy/context-guard --version
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
From this repository root, run helpers by path:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
./plugins/context-guard/bin/context-guard-setup --plan
|
|
49
|
+
./plugins/context-guard/bin/context-guard-diet scan . --json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For local development, add the plugin bin directory to your current shell:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
export PATH="$PWD/plugins/context-guard/bin:$PATH"
|
|
56
|
+
context-guard-setup --plan
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Common helpers:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
context-guard-audit ~/.claude/projects --top 20 --recommend
|
|
63
|
+
context-guard-setup
|
|
64
|
+
context-guard-diet scan . --json
|
|
65
|
+
context-guard-artifact store --command "long-command" --json < large.log
|
|
66
|
+
context-guard-artifact get <artifact_id> --lines 1:80
|
|
67
|
+
context-guard-compress --json < large-output.txt
|
|
68
|
+
context-guard-trim-output --max-lines 120 -- npm test
|
|
69
|
+
context-guard-read-symbol path/to/file.py TargetSymbol
|
|
70
|
+
context-guard-sanitize-output -- rg -n "TOKEN|SECRET" .
|
|
71
|
+
context-guard-sanitize-output -- git diff
|
|
72
|
+
context-guard-pack build --root . --source 'path=README.md,priority=100,lines=1:80' --budget-bytes 12000 --json
|
|
73
|
+
context-guard-pack slice --root . --path README.md --lines 1:40 --json
|
|
74
|
+
context-guard-tool-prune select --catalog tools.json --query "review failing tests" --top 5 --budget-bytes 12000 --json
|
|
75
|
+
context-guard-tool-prune get <receipt_id> --tool read_file --json
|
|
76
|
+
context-guard-statusline
|
|
77
|
+
context-guard-statusline-merged
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## What the helpers do
|
|
81
|
+
|
|
82
|
+
- **Setup wizard** merges `.claude/settings.json` instead of replacing it, then prints a read-only `context-guard-diet scan` summary. Use `--no-diet-scan` when automation needs setup output without the post-apply scan.
|
|
83
|
+
- **Context hygiene scanner** checks missing `permissions.deny` guardrails, Bash trim hook/statusline setup, broad read allows, high default model/effort, many MCP servers, large or secret-like agent rule files, and advisory context-exclusion recommendations for bulky/sensitive local paths. Its `--top` cap applies to both context-like files and context-exclusion recommendations.
|
|
84
|
+
- **Large-read guard and symbol reader** guide the agent from search to symbol slices to small line ranges before attempting a whole-file read. Supported source slices include Python, JavaScript/TypeScript, Go, and Rust.
|
|
85
|
+
- **Artifact store** saves large sanitized command output under `.context-guard/artifacts` by default and returns compact receipts or exact requested slices. JSON receipts include line-numbered top errors, duplicate-line groups, and sanitized bounded suggested queries. In suggested `--lines START:END` queries, `--max-lines` is only the returned-line cap for that selected range, not a wider selector. `get` and `list` can also read legacy `.claude-token-optimizer/artifacts` receipts.
|
|
86
|
+
- **Budgeted context packer** assembles prioritized local file evidence into a rendered byte-budgeted Markdown pack with included/partial/omitted source metadata, bounded `.context-guard/packs` receipts, exact sanitized `slice` commands when safe, and `retrieval_omitted_reason` when a path/root should not be echoed. Token counts are estimated `chars_div_4` proxies, not measured provider-token savings.
|
|
87
|
+
- **Tool/MCP schema pruner** ranks local tool catalogs into bounded top-k advisory reports while preserving full sanitized schema fallback through compact receipts and payload integrity checks.
|
|
88
|
+
- **Conservative compressor** classifies sanitized stdin as JSON, diff, log, search output, code, or prose and shrinks it with observed byte evidence plus estimated token proxies.
|
|
89
|
+
- **Output trimmer** preserves the wrapped command exit code, trims long logs, and can emit `--digest markdown` or `--digest json` summaries with runner failure facts, sanitized failure signatures, duplicate-line groups, and suggested next queries.
|
|
90
|
+
- **Sanitizer** redacts common credential patterns, private key blocks, auth headers, credential URLs, and sensitive-looking paths from search, diff, and log output.
|
|
91
|
+
- **Statusline** displays compact model/context/cost signals and, when transcript data is available, cache-read and cache-reuse signals.
|
|
92
|
+
- **Transcript audit** aggregates usage/cost/cache buckets, flags likely token hotspots, and exposes `cache_friendliness` prompt-layout findings from bounded redacted segment hashes without printing raw prompt text.
|
|
93
|
+
- **Repeated-failure nudge** warns after repeated Bash failures so the agent switches strategy instead of retrying the same context-heavy path.
|
|
94
|
+
- **Benchmark helper** records matched baseline/variant runs with real token and cost fields, separate byte-reduction proxy evidence, diagnostic `wall_time_seconds`, `provider_cached_tokens`, and provider-cache availability telemetry.
|
|
95
|
+
|
|
96
|
+
## Brief mode (advisory)
|
|
97
|
+
|
|
98
|
+
Brief mode ships agent-neutral, advisory rule snippets that ask a coding agent to cut filler while preserving evidence: file paths, commands, command output and errors, code blocks, verification status, changed files, known gaps, and caveats. It is best-effort guidance, not enforcement, and does **not** guarantee any token or cost savings.
|
|
99
|
+
|
|
100
|
+
Three deterministic levels — `lite`, `standard`, `ultra` — live under [`brief/`](brief/). Each is a single marker-delimited block you install into an agent's rule/instruction file (such as `AGENTS.md`, `CLAUDE.md`, a Cursor rules file, or Copilot instructions) and remove by deleting the block. See [`brief/README.md`](brief/README.md).
|
|
101
|
+
|
|
102
|
+
## Conservative claims
|
|
103
|
+
|
|
104
|
+
These helpers reduce common sources of context bloat, but they do not guarantee a fixed percentage savings. Use `context-guard-bench --ledger-jsonl ... --report-json ...` when you need measured before/after evidence for your own tasks; token-savings claims require `primary_tokens_measured` on both matched sides, and wall-time/provider-cache fields are diagnostic telemetry, not standalone savings proof. Audit `cache_friendliness` findings are heuristic layout signals, not billing authority. Benchmark CSV schemas are strict, so start a new CSV or migrate the header after helper upgrades.
|
|
105
|
+
|
|
106
|
+
ContextGuard also does not send work to external AI providers to save model tokens. All helper commands run locally.
|
|
107
|
+
|
|
108
|
+
Future learned, multimodal, and self-hosted optimization ideas are tracked only in [`../../research/experimental-token-reduction-radar.md`](../../research/experimental-token-reduction-radar.md). That radar is not a shipped runtime feature and does not claim hosted API savings without provider-measured matched-task evidence.
|
|
109
|
+
|
|
110
|
+
Cross-agent rule snippets are advisory: the target agent may ignore them, so measure actual before/after behavior when you need a savings claim.
|
|
111
|
+
|
|
112
|
+
## Local test before publishing
|
|
113
|
+
|
|
114
|
+
From the marketplace repository root:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
claude --plugin-dir ./plugins/context-guard
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Then run inside Claude Code:
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
/context-guard:setup
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Marketplace installation test:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
/plugin marketplace add ./
|
|
130
|
+
/plugin install context-guard@context-guard
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
Copyright 2026 jinhongan. Licensed under the Apache License 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Canonical ContextGuard command dispatcher.
|
|
3
|
+
|
|
4
|
+
The npm/Homebrew-friendly ``context-guard`` command is intentionally passive:
|
|
5
|
+
installation only exposes commands on PATH. Any project or user configuration is
|
|
6
|
+
performed later through explicit subcommands such as ``context-guard setup``.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
from typing import NoReturn
|
|
16
|
+
|
|
17
|
+
COMMAND_NAME = "context-guard"
|
|
18
|
+
PACKAGE_NAME = "@ictechgy/context-guard"
|
|
19
|
+
|
|
20
|
+
HELPER_SUBCOMMANDS: dict[str, tuple[str, ...]] = {
|
|
21
|
+
"setup": ("context-guard-setup",),
|
|
22
|
+
"audit": ("context-guard-audit",),
|
|
23
|
+
"diet": ("context-guard-diet",),
|
|
24
|
+
"scan": ("context-guard-diet", "scan"),
|
|
25
|
+
"trim-output": ("context-guard-trim-output",),
|
|
26
|
+
"trim": ("context-guard-trim-output",),
|
|
27
|
+
"sanitize-output": ("context-guard-sanitize-output",),
|
|
28
|
+
"sanitize": ("context-guard-sanitize-output",),
|
|
29
|
+
"artifact": ("context-guard-artifact",),
|
|
30
|
+
"pack": ("context-guard-pack",),
|
|
31
|
+
"tool-prune": ("context-guard-tool-prune",),
|
|
32
|
+
"compress": ("context-guard-compress",),
|
|
33
|
+
"bench": ("context-guard-bench",),
|
|
34
|
+
"read-symbol": ("context-guard-read-symbol",),
|
|
35
|
+
"rewrite-bash": ("context-guard-rewrite-bash",),
|
|
36
|
+
"guard-read": ("context-guard-guard-read",),
|
|
37
|
+
"failed-nudge": ("context-guard-failed-nudge",),
|
|
38
|
+
"statusline": ("context-guard-statusline",),
|
|
39
|
+
"statusline-merged": ("context-guard-statusline-merged",),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _script_dir() -> Path:
|
|
44
|
+
return Path(__file__).resolve().parent
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _candidate_roots() -> list[Path]:
|
|
48
|
+
script_dir = _script_dir()
|
|
49
|
+
roots = [script_dir.parent, script_dir.parent.parent, Path.cwd()]
|
|
50
|
+
# When run from context-guard-kit in a checkout, the repo root is one level up.
|
|
51
|
+
if script_dir.name == "context-guard-kit":
|
|
52
|
+
roots.insert(0, script_dir.parent)
|
|
53
|
+
return list(dict.fromkeys(roots))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _load_json(path: Path) -> dict[str, object] | None:
|
|
57
|
+
try:
|
|
58
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
59
|
+
except (OSError, json.JSONDecodeError):
|
|
60
|
+
return None
|
|
61
|
+
return data if isinstance(data, dict) else None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def project_version() -> str:
|
|
65
|
+
candidates: list[Path] = []
|
|
66
|
+
for root in _candidate_roots():
|
|
67
|
+
candidates.extend(
|
|
68
|
+
[
|
|
69
|
+
root / ".claude-plugin" / "plugin.json",
|
|
70
|
+
root / "plugins" / "context-guard" / ".claude-plugin" / "plugin.json",
|
|
71
|
+
root / "package.json",
|
|
72
|
+
]
|
|
73
|
+
)
|
|
74
|
+
for candidate in candidates:
|
|
75
|
+
data = _load_json(candidate)
|
|
76
|
+
version = data.get("version") if data else None
|
|
77
|
+
if isinstance(version, str) and version.strip():
|
|
78
|
+
return version.strip()
|
|
79
|
+
return "0.0.0+unknown"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def print_help() -> None:
|
|
83
|
+
version = project_version()
|
|
84
|
+
commands = "\n".join(f" {name}" for name in sorted(HELPER_SUBCOMMANDS))
|
|
85
|
+
sys.stdout.write(
|
|
86
|
+
f"ContextGuard {version}\n"
|
|
87
|
+
f"\n"
|
|
88
|
+
f"Usage:\n"
|
|
89
|
+
f" {COMMAND_NAME} --version\n"
|
|
90
|
+
f" {COMMAND_NAME} <subcommand> [args...]\n"
|
|
91
|
+
f"\n"
|
|
92
|
+
f"Install examples:\n"
|
|
93
|
+
f" npm install -g {PACKAGE_NAME}\n"
|
|
94
|
+
f" npx {PACKAGE_NAME} setup --agent codex --scope project --plan\n"
|
|
95
|
+
f"\n"
|
|
96
|
+
f"Common subcommands:\n"
|
|
97
|
+
f"{commands}\n"
|
|
98
|
+
f"\n"
|
|
99
|
+
f"Run '{COMMAND_NAME} <subcommand> --help' for helper-specific options.\n"
|
|
100
|
+
f"Installing ContextGuard never writes configuration; use 'setup' explicitly.\n"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def helper_path(name: str) -> Path | None:
|
|
105
|
+
script_dir = _script_dir()
|
|
106
|
+
candidates = [
|
|
107
|
+
script_dir / name,
|
|
108
|
+
script_dir.parent / "plugins" / "context-guard" / "bin" / name,
|
|
109
|
+
script_dir.parent.parent / "plugins" / "context-guard" / "bin" / name,
|
|
110
|
+
]
|
|
111
|
+
for candidate in candidates:
|
|
112
|
+
if candidate.is_file() and os.access(candidate, os.X_OK):
|
|
113
|
+
return candidate
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def fail(message: str, code: int = 2) -> NoReturn:
|
|
118
|
+
sys.stderr.write(f"{COMMAND_NAME}: {message}\n")
|
|
119
|
+
raise SystemExit(code)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def run_helper(command: str, argv: list[str]) -> int:
|
|
123
|
+
mapping = HELPER_SUBCOMMANDS[command]
|
|
124
|
+
helper = helper_path(mapping[0])
|
|
125
|
+
if helper is None:
|
|
126
|
+
fail(
|
|
127
|
+
f"could not find helper {mapping[0]!r}; reinstall {PACKAGE_NAME} "
|
|
128
|
+
"or run from a complete ContextGuard checkout."
|
|
129
|
+
)
|
|
130
|
+
proc = subprocess.run([str(helper), *mapping[1:], *argv])
|
|
131
|
+
return int(proc.returncode)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def main(argv: list[str] | None = None) -> int:
|
|
135
|
+
args = list(sys.argv[1:] if argv is None else argv)
|
|
136
|
+
if not args or args[0] in {"-h", "--help", "help"}:
|
|
137
|
+
print_help()
|
|
138
|
+
return 0
|
|
139
|
+
if args[0] in {"-V", "--version", "version"}:
|
|
140
|
+
print(project_version())
|
|
141
|
+
return 0
|
|
142
|
+
command = args.pop(0).strip().lower()
|
|
143
|
+
if command not in HELPER_SUBCOMMANDS:
|
|
144
|
+
fail(f"unknown subcommand {command!r}. Run '{COMMAND_NAME} --help'.")
|
|
145
|
+
return run_helper(command, args)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
raise SystemExit(main())
|