@softspark/ai-toolkit 4.16.1 → 4.18.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/README.md +13 -19
  3. package/app/.claude-plugin/plugin.json +1 -1
  4. package/app/hooks/session-end.sh +1 -13
  5. package/app/hooks.json +0 -10
  6. package/app/plugins/README.md +16 -4
  7. package/app/plugins/rtk-pack/README.md +123 -0
  8. package/app/plugins/rtk-pack/hooks/rewrite.sh +79 -0
  9. package/app/plugins/rtk-pack/plugin.json +60 -0
  10. package/app/plugins/rtk-pack/scripts/init.py +252 -0
  11. package/app/plugins/rtk-pack/scripts/status.py +105 -0
  12. package/benchmarks/ecosystem-doctor-snapshot.json +14 -15
  13. package/bin/ai-toolkit.js +15 -2
  14. package/kb/history/completed/output-filter-retirement-20260726.md +128 -0
  15. package/kb/history/completed/rtk-pack-integration-20260726.md +710 -0
  16. package/kb/procedures/maintenance-sop.md +1 -1
  17. package/kb/procedures/release-preparation-sop.md +8 -3
  18. package/kb/procedures/rtk-upstream-sync-sop.md +279 -0
  19. package/kb/reference/architecture-overview.md +2 -3
  20. package/kb/reference/cli-reference.md +4 -14
  21. package/kb/reference/enterprise-config-guide.md +1 -21
  22. package/kb/reference/hooks-catalog.md +3 -60
  23. package/kb/reference/plugin-pack-conventions.md +17 -2
  24. package/kb/reference/supported-tools-registry.md +0 -4
  25. package/llms-full.txt +1171 -402
  26. package/llms.txt +3 -1
  27. package/manifest.json +147 -36
  28. package/package.json +1 -2
  29. package/scripts/audit_skills.py +21 -0
  30. package/scripts/claude_app.py +2 -21
  31. package/scripts/config_cli.py +4 -0
  32. package/scripts/config_merger.py +0 -17
  33. package/scripts/config_validator.py +11 -138
  34. package/scripts/doctor.py +3 -20
  35. package/scripts/install.py +2 -1
  36. package/scripts/install_steps/ai_tools.py +28 -99
  37. package/scripts/install_steps/hooks.py +26 -24
  38. package/scripts/merge-hooks.py +33 -2
  39. package/scripts/output_filter_retirement.py +395 -0
  40. package/scripts/plugin.py +136 -16
  41. package/scripts/schemas/ai-toolkit-config.schema.json +0 -60
  42. package/scripts/uninstall.py +13 -27
  43. package/scripts/verify_rtk_binary.py +335 -0
  44. package/app/hooks/filter-tool-output.sh +0 -76
  45. package/app/output-filter-policy.json +0 -15
  46. package/benchmarks/output-filter/README.md +0 -11
  47. package/benchmarks/output-filter/scenarios.json +0 -25
  48. package/kb/reference/tool-output-filter.md +0 -288
  49. package/scripts/benchmark_output_filter.py +0 -343
  50. package/scripts/output_filter_cli.py +0 -347
  51. package/scripts/output_filter_hook.py +0 -23
  52. package/scripts/tool_output_filter/__init__.py +0 -33
  53. package/scripts/tool_output_filter/contracts.py +0 -173
  54. package/scripts/tool_output_filter/engine.py +0 -260
  55. package/scripts/tool_output_filter/hook_runtime.py +0 -369
  56. package/scripts/tool_output_filter/input.py +0 -56
  57. package/scripts/tool_output_filter/invariants.py +0 -40
  58. package/scripts/tool_output_filter/policy.py +0 -153
  59. package/scripts/tool_output_filter/profiles/__init__.py +0 -68
  60. package/scripts/tool_output_filter/profiles/repeat_lines.py +0 -71
  61. package/scripts/tool_output_filter/profiles/tap_success.py +0 -154
  62. package/scripts/tool_output_filter/recovery.py +0 -846
  63. package/scripts/tool_output_filter/telemetry.py +0 -13
package/CHANGELOG.md CHANGED
@@ -7,6 +7,90 @@ Versioning follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
9
9
 
10
+ ## v4.18.0 — rtk-pack, an opt-in command rewriter (2026-07-26)
11
+
12
+ ### Added
13
+
14
+ - **`rtk-pack`**, an opt-in plugin pack that rewrites Bash commands at
15
+ `PreToolUse` via [rtk](https://github.com/rtk-ai/rtk) (Apache-2.0). Nothing
16
+ installs it for you. `ai-toolkit plugin install rtk-pack` fetches a
17
+ platform-specific binary from an ai-toolkit GitHub Release and verifies its
18
+ SHA-256 before installing anything; a mismatch aborts and leaves nothing
19
+ behind. Read `app/plugins/rtk-pack/README.md` before enabling it: the rewrite
20
+ means what runs is not literally what the model asked for, and rtk applies
21
+ your permission verdict for the original command to the rewritten one.
22
+ - **`.github/workflows/rtk-build.yml`**, a manual-dispatch pipeline that
23
+ cross-builds rtk from upstream source for five targets with the compile-time
24
+ telemetry endpoint left undefined, proves each artifact starts, writes no
25
+ telemetry state and (on Linux) behaves identically with no network route,
26
+ then publishes checksummed artifacts with LICENSE and NOTICE.
27
+ - **`scripts/verify_rtk_binary.py`**, the silence verifier that pipeline uses.
28
+ A target it cannot start reports `inconclusive`, never `pass`.
29
+ - **`kb/procedures/rtk-upstream-sync-sop.md`**, the procedure for moving to a
30
+ newer upstream tag, including a re-measure gate and a published kill number.
31
+ - Plugin packs can now ship `scripts/status.py` and have `plugin status` pick it
32
+ up. This replaces a hardcoded `if name == "memory-pack"` branch, so any pack
33
+ can report its own health.
34
+
35
+ ### Changed
36
+
37
+ - **`ai-toolkit update` now updates installed plugin packs.** It reads
38
+ `plugins.json` and runs the equivalent of `plugin update --all` for every
39
+ installed pack. `--local` leaves packs alone, since they are global.
40
+ - **`plugin update` is version-aware.** `plugins.json` records the pack version
41
+ installed per editor, and an update whose manifest version matches is a silent
42
+ no-op. Previously every update removed and reinstalled unconditionally, which
43
+ for a pack that downloads a binary meant refetching it every time. `--force`
44
+ overrides; `--dry-run` reports without acting. State written before versions
45
+ were tracked updates each pack exactly once.
46
+ - Plugin packs are now covered by `audit_skills.py --ci` and by the ShellCheck
47
+ gate in CI. Both previously scanned only `app/skills`, `app/agents` and
48
+ `app/hooks`, exempting the highest-risk code in the repo.
49
+ - A pack's install-time script may be named `init.py`; `init_db.py` still works.
50
+ Previously only the latter ran, so a pack using any other name installed
51
+ successfully while doing nothing.
52
+
53
+ ### Fixed
54
+
55
+ - `plugin install` no longer aborts with `IsADirectoryError` when a pack ships a
56
+ subdirectory under `scripts/`.
57
+ - A failing pack init script now always reports, instead of printing nothing
58
+ when it exited non-zero with empty stderr.
59
+
60
+ ---
61
+
62
+ ## v4.17.0 — Native tool-output filter removed (2026-07-26)
63
+
64
+ ### Removed
65
+
66
+ - **BREAKING for anyone who opted in.** The native tool-output filter shipped
67
+ in v4.16.0 is gone: the `PostToolUse` hook `filter-tool-output.sh`, the
68
+ `scripts/tool_output_filter/` runtime, the `ai-toolkit output-filter` CLI,
69
+ the benchmark corpus, and the `toolOutputFilter` key in
70
+ `.softspark-toolkit.json`. The key is accepted and ignored rather than
71
+ rejected, so an existing config still validates; `ai-toolkit config validate`
72
+ reports it as a retired key you can delete.
73
+ - Why: measured whole-session token saving was **0.0000%** on real traffic.
74
+ Across 134 session transcripts spanning 22 projects, 7600 successful Bash
75
+ results contained 145 that parsed as simple command shapes, 18 that matched a
76
+ registered shape, and 0 that any filter accepted. The filter was correct;
77
+ its premise was not. Agent-issued commands are overwhelmingly compound
78
+ (`&&` and `;` chains, pipelines, heredocs), and the design accepted only
79
+ simple registered shapes. See
80
+ `kb/history/completed/output-filter-retirement-20260726.md`.
81
+
82
+ ### Changed
83
+
84
+ - `ai-toolkit install` and `ai-toolkit update` now remove the artifacts left by
85
+ v4.16.x: the installed hook script, the global
86
+ `hooks/output-filter-policy.json`, the managed project policy and owner
87
+ marker under `.claude/`, and stored recovery trees under
88
+ `sessions/<repo-key>/output-filter/`. Cleanup is idempotent, verifies
89
+ ai-toolkit ownership before deleting, and leaves foreign files untouched.
90
+ - The stale `PostToolUse` entry is removed from `~/.claude/settings.json` by
91
+ the existing hook strip-and-remerge cycle, so no manual edit is needed.
92
+ - Hook counts drop from 29 entries to 28 across the same 14 events.
93
+
10
94
  ## v4.16.1 — Copilot skill remnant recovery (2026-07-24)
11
95
 
12
96
  ### Fixed
package/README.md CHANGED
@@ -6,18 +6,17 @@
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
7
  [![Skills](https://img.shields.io/badge/skills-108-brightgreen)](app/skills/)
8
8
  [![Agents](https://img.shields.io/badge/agents-44-blue)](app/agents/)
9
- [![Tests](https://img.shields.io/badge/tests-1479%20passing-success)](tests/)
9
+ [![Tests](https://img.shields.io/badge/tests-1484%20passing-success)](tests/)
10
10
 
11
- ## What's New in v4.16.1
11
+ ## What's New in v4.18.0
12
12
 
13
- v4.16.1 ships the native tool-output filter introduced in v4.16.0 and fixes local updates crashing on legacy Copilot skill remnants.
13
+ v4.18.0 adds `rtk-pack`, an opt-in command rewriter, and makes `ai-toolkit update` maintain installed packs.
14
14
 
15
- - **Native tool-output filter**: opt-in `PostToolUse` filter with `off`, `observe`, and `safe` modes; ships disabled, handles only allowlisted successful Bash test/validation output.
16
- - **Exact ephemeral recovery**: every safe replacement keeps a private, bounded, session-scoped copy of the original response, recoverable via `ai-toolkit output-filter recover`.
17
- - **Output-filter CLI**: `ai-toolkit output-filter status|inspect|recover|clean` plus a deterministic benchmark for the built-in profiles.
18
- - **Stricter config validation**: unknown top-level config keys are rejected, plugin manifests must declare `requires`, and lock files go stale on toolkit version bumps.
19
- - **GitHub Copilot compatibility reference**: new `kb/reference/copilot-compatibility.md` documenting the Copilot integration surface.
20
- - **Copilot remnant recovery**: asset-only `.github/skills/ai-toolkit-*` leftovers from older cleanups are rebuilt in place instead of aborting `install --local` / `update`.
15
+ - **`rtk-pack`, opt-in only**: rewrites Bash commands at `PreToolUse` via [rtk](https://github.com/rtk-ai/rtk) (Apache-2.0). Nothing installs it for you. `plugin install` fetches a platform binary from an ai-toolkit Release and verifies its SHA-256 before installing anything. Measured saving on the reference workload is 0.0615% of input tokens; the pack README states the trust boundary and the numbers up front.
16
+ - **Binaries built from source, telemetry compiled out**: a manual-dispatch workflow cross-builds five targets with the compile-time telemetry endpoint undefined, proves each artifact starts, writes no telemetry state, and on Linux behaves identically with no network route.
17
+ - **`ai-toolkit update` maintains installed packs**: it now runs the equivalent of `plugin update --all`. Updates are version-aware, so a pack whose manifest has not moved is a silent no-op instead of a remove-and-reinstall.
18
+ - **Packs can report their own health**: `plugin status` picks up a pack's `scripts/status.py`, replacing a hardcoded per-pack branch.
19
+ - **Security gates cover packs**: `audit_skills.py --ci` and the ShellCheck gate now scan `app/plugins/`, which they previously skipped.
21
20
 
22
21
  See [CHANGELOG.md](CHANGELOG.md) for full history.
23
22
 
@@ -92,10 +91,7 @@ ai-toolkit claude-app export --verify
92
91
  ```
93
92
 
94
93
  Re-export and re-upload after toolkit or registered-rule updates. Skills work
95
- in Chat and Cowork; hooks and sub-agents are active only in Cowork. The native
96
- tool-output replacement hook remains Claude Code-only and is excluded from the
97
- Claude app archive until that runtime has an independently verified replacement
98
- contract.
94
+ in Chat and Cowork; hooks and sub-agents are active only in Cowork.
99
95
 
100
96
  ### Install Profiles
101
97
 
@@ -146,8 +142,8 @@ See [CLI Reference](kb/reference/cli-reference.md) for all commands and options.
146
142
  | `skills/` (hybrid) | 30 | Slash commands with agent knowledge base |
147
143
  | `skills/` (knowledge) | 46 | Domain knowledge auto-loaded by agents (includes 13 `<lang>-rules` skills) |
148
144
  | `agents/` | 44 | Specialized agents across 10 categories |
149
- | `hooks/` | 29 entries / 14 events + statusLine | Quality gates, path safety, prompt governance, loop guard, output filtering, session lifecycle |
150
- | `plugins/` | 11 packs | Opt-in domain bundles (security, research, frontend, enterprise, 6 language packs) |
145
+ | `hooks/` | 28 entries / 14 events + statusLine | Quality gates, path safety, prompt governance, loop guard, session lifecycle |
146
+ | `plugins/` | 12 packs | Opt-in domain bundles (security, research, frontend, enterprise, memory, rtk, 6 language packs) |
151
147
  | `constitution.md` | 7 articles | Machine-enforced safety rules |
152
148
  | `rules/` | auto-synced | Global/project rule files for Claude and other editors |
153
149
  | `kb/` | reference docs | Architecture, procedures, and best practices |
@@ -170,7 +166,7 @@ ai-toolkit/
170
166
  │ └── ARCHITECTURE.md # Full system design
171
167
  ├── kb/ # Reference docs, procedures, plans
172
168
  ├── scripts/ # Validation, install, evaluation scripts
173
- ├── tests/ # Bats and Python test suite (1479 tests)
169
+ ├── tests/ # Bats and Python test suite (1484 tests)
174
170
  └── CHANGELOG.md
175
171
  ```
176
172
 
@@ -182,9 +178,7 @@ ai-toolkit/
182
178
 
183
179
  **Machine-enforced constitution** — 7-article safety constitution enforced via `PreToolUse` hooks that actually block `rm -rf`, `DROP TABLE`, and irreversible operations. Not just documentation.
184
180
 
185
- **29 lifecycle hook entries:** Executable handlers across 14 events (SessionStart → SessionEnd, plus InstructionsLoaded + ConfigChange). Guards, governance, quality gates, session persistence, MCP health checks, revert protection, test-cohesion enforcement, loop guard, search-first discipline, and opt-in output filtering. See [Hooks Catalog](kb/reference/hooks-catalog.md).
186
-
187
- **Native tool-output filtering** — dependency-free, post-execution filtering for successful Claude Code Bash output, shipped **disabled by default** (`off`). Neither `off` nor `observe` ever replaces output; opt-in `safe` mode replaces only validated `repeat-lines` or `tap-success` results after exact ephemeral recovery is available. Failures, diagnostics, unsupported payloads, and unavailable recovery always pass through unchanged. See [Tool Output Filter](kb/reference/tool-output-filter.md).
181
+ **28 lifecycle hook entries:** Executable handlers across 14 events (SessionStart → SessionEnd, plus InstructionsLoaded + ConfigChange). Guards, governance, quality gates, session persistence, MCP health checks, revert protection, test-cohesion enforcement, loop guard, and search-first discipline. See [Hooks Catalog](kb/reference/hooks-catalog.md).
188
182
 
189
183
  **Security scanning** — `/skill-audit` for code-level risks, `/cve-scan` for dependency CVEs. Both CI-ready with exit codes.
190
184
 
@@ -3,7 +3,7 @@
3
3
  "name": "ai-toolkit",
4
4
  "displayName": "AI Toolkit",
5
5
  "description": "Professional-grade engineering skills, agents, rules, and lifecycle guardrails for Claude Code, Claude Chat, and Cowork.",
6
- "version": "4.16.1",
6
+ "version": "4.18.0",
7
7
  "author": {
8
8
  "name": "SoftSpark",
9
9
  "url": "https://github.com/softspark"
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # Fires on: SessionEnd
5
5
  # Matcher: all
6
- # The handoff snapshot is skipped for the minimal profile. Owned recovery
6
+ # The handoff snapshot is skipped for the minimal profile. Session-state
7
7
  # cleanup still runs for every profile.
8
8
 
9
9
  # shellcheck source=_session-paths.sh
@@ -18,18 +18,6 @@ if [ ! -t 0 ]; then
18
18
  INPUT=$(cat)
19
19
  fi
20
20
  SESSION_ID=$(hook_session_id)
21
- RECOVERY_ROOT="$SESSION_DIR/output-filter"
22
- OUTPUT_FILTER_CLI="${AI_TOOLKIT_OUTPUT_FILTER_CLI:-$HOME/.softspark/ai-toolkit/scripts/output_filter_cli.py}"
23
- if [ "$SESSION_ID" != "default" ] &&
24
- [ -d "$RECOVERY_ROOT" ] &&
25
- [ ! -L "$RECOVERY_ROOT" ] &&
26
- [ -f "$OUTPUT_FILTER_CLI" ] &&
27
- [ ! -L "$OUTPUT_FILTER_CLI" ] &&
28
- command -v python3 >/dev/null 2>&1; then
29
- python3 -S "$OUTPUT_FILTER_CLI" clean \
30
- --base-directory "$SESSION_DIR" \
31
- --session-id "$SESSION_ID" >/dev/null 2>&1 || true
32
- fi
33
21
 
34
22
  SESSION_STATE_CLI="${AI_TOOLKIT_SESSION_STATE_CLI:-$HOME/.softspark/ai-toolkit/scripts/session_state.py}"
35
23
  if [ "$SESSION_ID" != "default" ] &&
package/app/hooks.json CHANGED
@@ -158,16 +158,6 @@
158
158
  "command": "\"$HOME/.softspark/ai-toolkit/hooks/search-tracker.sh\""
159
159
  }
160
160
  ]
161
- },
162
- {
163
- "_source": "ai-toolkit",
164
- "matcher": "Bash",
165
- "hooks": [
166
- {
167
- "type": "command",
168
- "command": "\"$HOME/.softspark/ai-toolkit/hooks/filter-tool-output.sh\""
169
- }
170
- ]
171
161
  }
172
162
  ],
173
163
  "Stop": [
@@ -17,10 +17,22 @@ Plugin packs can target:
17
17
  These packs are not directly uploadable Claude app plugins. For Claude Chat,
18
18
  Desktop, and Cowork use `ai-toolkit claude-app export`.
19
19
 
20
- Current packs:
21
- - `security-pack`
22
- - `research-pack`
23
- - `frontend-pack`
20
+ Current packs (12):
21
+ - `csharp-pack`
24
22
  - `enterprise-pack`
23
+ - `frontend-pack`
24
+ - `java-pack`
25
+ - `kotlin-pack`
26
+ - `memory-pack`
27
+ - `research-pack`
28
+ - `rtk-pack`
29
+ - `ruby-pack`
30
+ - `rust-pack`
31
+ - `security-pack`
32
+ - `swift-pack`
33
+
34
+ `rtk-pack` is the only one that fetches a native binary at install time and the
35
+ only one that rewrites commands before they run. Read its README before
36
+ installing it.
25
37
 
26
38
  See `kb/reference/plugin-pack-conventions.md` for pack rules, validation, and adoption guidance.
@@ -0,0 +1,123 @@
1
+ # rtk-pack
2
+
3
+ Opt-in command rewriting via [rtk](https://github.com/rtk-ai/rtk), Apache-2.0.
4
+
5
+ Install: `ai-toolkit plugin install rtk-pack`. Remove: `ai-toolkit plugin remove rtk-pack`.
6
+ Nothing installs it for you, and nothing in the core depends on it.
7
+
8
+ ## Read this before installing
9
+
10
+ **This pack rewrites your commands before they run.** A `PreToolUse` hook hands
11
+ each command to `rtk`, which may replace it with an `rtk` equivalent that
12
+ produces shorter output. What executes is therefore not literally what the model
13
+ asked for.
14
+
15
+ That is a real trade-off and the reason this ships as an opt-in pack rather than
16
+ a core feature. ai-toolkit's own retired output filter explicitly refused to do
17
+ this. Adopting rtk is a deliberate reversal, made with the mechanism understood
18
+ rather than assumed.
19
+
20
+ **Your permission rules are evaluated against the original command, and the
21
+ verdict is applied to the rewritten one.** rtk checks what the model asked for
22
+ against your `settings.json`, and if a rule allows it, emits
23
+ `permissionDecision: allow` for the `rtk …` form it substituted. So an allowlist
24
+ entry for `git status` transitively authorises `rtk git status`, a command you
25
+ never wrote a rule for. With no matching allow rule, no decision is emitted and
26
+ your normal prompt appears. Verified against upstream's own test at
27
+ `src/hooks/hook_cmd.rs:1272-1283`.
28
+
29
+ If your allowlist is broad, review it before installing. If it is narrow, expect
30
+ prompts on commands that used to run without one.
31
+
32
+ Every failure path degrades to passthrough: no binary, a non-zero exit, a
33
+ timeout, or unparseable output all result in the original command running
34
+ unchanged. Removing the pack strips the hook from `settings.json`.
35
+
36
+ ## What you get, measured
37
+
38
+ On the reference workload (1224 local transcripts, 26.6 MB of successful Bash
39
+ output) rtk addresses **35.2%** of Bash bytes, which is **8.8%** of all
40
+ tool-result bytes. The projected saving is **0.12% to 0.16%** of session input
41
+ tokens, or 0.24% to 0.36% if rtk's own 60-90% claim holds on your traffic.
42
+
43
+ That is small, and it is stated up front on purpose. The arithmetic ceiling for
44
+ any tool-output mechanism on that workload is 4.5%, because tool results are
45
+ that share of input token volume, and `Read` results are 63% of them. If your
46
+ work is dominated by `cargo test`, `mvn` or `jest` output rather than file
47
+ reading, rtk is calibrated for you and will do better. Measure before believing
48
+ either number.
49
+
50
+ Full method and caveats: `kb/history/completed/rtk-pack-integration-20260726.md`.
51
+
52
+ ## The binary
53
+
54
+ Not bundled. `plugin install` fetches the artifact for your platform from an
55
+ ai-toolkit GitHub Release and verifies its SHA-256 against `plugin.json` before
56
+ installing anything. A digest mismatch aborts and leaves nothing behind. This is
57
+ the only moment the pack uses the network.
58
+
59
+ Binaries are cross-built from upstream source in ai-toolkit CI with
60
+ `RTK_TELEMETRY_URL` and `RTK_TELEMETRY_TOKEN` left undefined, so the
61
+ compile-time telemetry endpoint is absent and cannot be supplied at runtime.
62
+ Each build asserts that, runs the artifact, checks no telemetry state is
63
+ written, and on Linux confirms behaviour is unchanged with no network route.
64
+
65
+ | Platform | Artifact |
66
+ |---|---|
67
+ | macOS arm64 | `rtk-aarch64-apple-darwin.tar.gz` |
68
+ | macOS x86_64 | `rtk-x86_64-apple-darwin.tar.gz` |
69
+ | Linux x86_64 | `rtk-x86_64-unknown-linux-musl.tar.gz` (static, runs on glibc) |
70
+ | Linux aarch64 | `rtk-aarch64-unknown-linux-gnu.tar.gz` |
71
+ | Windows x86_64 | `rtk-x86_64-pc-windows-msvc.zip` |
72
+
73
+ ## One thing the binary does reach the network for
74
+
75
+ `rtk cc` (Claude economics) shells out to `npx --yes ccusage` when `ccusage` is
76
+ not already on `PATH`, which fetches and executes a third-party npm package.
77
+ That is not telemetry and never happens automatically, but it is outbound
78
+ network from a binary otherwise described as silent. Do not run `rtk cc` in an
79
+ air-gapped or policy-restricted environment.
80
+
81
+ Related: `rtk telemetry forget` on these builds prints a failure telling you to
82
+ email upstream to complete erasure. Nothing was ever sent; the message is
83
+ upstream's and does not apply here.
84
+
85
+ ## Layout
86
+
87
+ ```
88
+ ~/.softspark/ai-toolkit/
89
+ ├── hooks/plugin-rtk-pack-rewrite.sh # the PreToolUse hook
90
+ └── plugin-scripts/rtk-pack/
91
+ ├── bin/rtk # verified binary
92
+ └── version.json # pinned versions and recorded digest
93
+ ```
94
+
95
+ ## Installing from a mirror
96
+
97
+ Set `RTK_PACK_RELEASE_BASE_URL` to a base URL holding the release assets and the
98
+ install fetches from there instead of GitHub, for networks that cannot reach it
99
+ directly:
100
+
101
+ ```bash
102
+ RTK_PACK_RELEASE_BASE_URL=https://mirror.internal/rtk/v0.44.0-1 \
103
+ ai-toolkit plugin install rtk-pack
104
+ ```
105
+
106
+ The digest check is unchanged. A mirror serving different bytes is rejected
107
+ exactly like a corrupt download, so this widens where the artifact comes from
108
+ without widening what is accepted.
109
+
110
+ ## Disabling without removing
111
+
112
+ `rtk` honours `RTK_DISABLED=1` as a per-command prefix. To turn the pack off
113
+ entirely, remove it: `ai-toolkit plugin remove rtk-pack`.
114
+
115
+ ## Licence
116
+
117
+ rtk is Apache-2.0. `LICENSE` and `NOTICE` ship with every release artifact. The
118
+ NOTICE records the two build-time differences from an upstream build: the
119
+ undefined telemetry endpoint, and in-range lockfile security updates for
120
+ `anyhow` and `crossbeam-epoch`. No upstream source is modified.
121
+
122
+ Upstream `DISCLAIMER.md` is deliberately not redistributed: it states that
123
+ telemetry is collected by default, which is not true of these builds.
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env bash
2
+ # rewrite.sh — delegate PreToolUse command rewriting to the rtk binary.
3
+ #
4
+ # Fires on: PreToolUse
5
+ # Reads the Claude Code hook JSON from stdin and hands it to `rtk hook claude`,
6
+ # which emits hookSpecificOutput with permissionDecision and updatedInput.
7
+ #
8
+ # This hook rewrites the command before it runs, so what executes is not
9
+ # literally what the model asked for. That is the pack's stated trade-off; see
10
+ # the pack README. Everything here is built so that any failure degrades to
11
+ # passthrough rather than to a broken or altered command:
12
+ #
13
+ # no binary -> no output, exit 0 (command runs unchanged)
14
+ # rtk fails -> no output, exit 0
15
+ # rtk times out -> no output, exit 0
16
+ # rtk prints junk -> no output, exit 0
17
+ #
18
+ # Emitting nothing is the safe default: Claude Code treats an empty hook
19
+ # response as "no opinion" and runs the original command.
20
+
21
+ set -u
22
+
23
+ PACK_BIN_DIR="${HOME}/.softspark/ai-toolkit/plugin-scripts/rtk-pack/bin"
24
+ TIMEOUT_SECONDS=5
25
+
26
+ # Read stdin once; it is not replayable.
27
+ INPUT=$(cat)
28
+ [ -n "$INPUT" ] || exit 0
29
+
30
+ # jq is needed both to gate on the tool name and to check rtk's reply. Without
31
+ # it we cannot do either safely, so stay out of the way entirely.
32
+ command -v jq >/dev/null 2>&1 || exit 0
33
+
34
+ # A pack hook cannot declare its own matcher: plugin.py:408 looks the basename
35
+ # up in core app/hooks.json and falls back to "", so this registers against
36
+ # every tool rather than Bash alone. Gate here instead, otherwise every Read,
37
+ # Edit and Grep would spawn a subprocess for nothing.
38
+ TOOL=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
39
+ [ "$TOOL" = "Bash" ] || exit 0
40
+
41
+ RTK=""
42
+ for candidate in "${PACK_BIN_DIR}/rtk" "${PACK_BIN_DIR}/rtk.exe"; do
43
+ if [ -x "$candidate" ]; then
44
+ RTK="$candidate"
45
+ break
46
+ fi
47
+ done
48
+
49
+ # Inert when init.py could not install a binary. The pack stays wired so that a
50
+ # later `ai-toolkit plugin install rtk-pack` fixes it without touching settings.
51
+ [ -n "$RTK" ] || exit 0
52
+
53
+ # GNU timeout is `timeout`, Homebrew coreutils installs it as `gtimeout`, and
54
+ # on a bare macOS it is absent. A hung rewriter would hang the session, so use
55
+ # it when we can and accept the risk when we cannot.
56
+ TIMEOUT_CMD=""
57
+ if command -v timeout >/dev/null 2>&1; then
58
+ TIMEOUT_CMD="timeout"
59
+ elif command -v gtimeout >/dev/null 2>&1; then
60
+ TIMEOUT_CMD="gtimeout"
61
+ fi
62
+
63
+ if [ -n "$TIMEOUT_CMD" ]; then
64
+ OUTPUT=$(printf '%s' "$INPUT" | "$TIMEOUT_CMD" "$TIMEOUT_SECONDS" "$RTK" hook claude 2>/dev/null)
65
+ else
66
+ OUTPUT=$(printf '%s' "$INPUT" | "$RTK" hook claude 2>/dev/null)
67
+ fi
68
+ STATUS=$?
69
+
70
+ [ "$STATUS" -eq 0 ] || exit 0
71
+ [ -n "$OUTPUT" ] || exit 0
72
+
73
+ # Only forward something that parses as JSON. A partial write or a stray
74
+ # diagnostic on stdout would otherwise reach Claude Code as a malformed hook
75
+ # response.
76
+ printf '%s' "$OUTPUT" | jq -e . >/dev/null 2>&1 || exit 0
77
+
78
+ printf '%s\n' "$OUTPUT"
79
+ exit 0
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "rtk-pack",
3
+ "description": "Opt-in command rewriting via rtk, cross-built from source with telemetry disabled and fetched from a checksum-pinned release",
4
+ "version": "0.1.0",
5
+ "domain": "token-reduction",
6
+ "type": "plugin-pack",
7
+ "status": "experimental",
8
+ "requires": {
9
+ "ai-toolkit": ">=4.17.0",
10
+ "claude-code": ">=1.0.33"
11
+ },
12
+ "includes": {
13
+ "agents": [],
14
+ "skills": [],
15
+ "rules": [],
16
+ "hooks": ["rewrite.sh"]
17
+ },
18
+ "hook_events": {
19
+ "rewrite.sh": "PreToolUse"
20
+ },
21
+ "upstream": {
22
+ "project": "rtk",
23
+ "repository": "https://github.com/rtk-ai/rtk",
24
+ "license": "Apache-2.0",
25
+ "version": "v0.44.0",
26
+ "note": "Built from source in our CI with RTK_TELEMETRY_URL and RTK_TELEMETRY_TOKEN undefined. Cargo.lock carries in-range security updates for anyhow and crossbeam-epoch. No source modifications."
27
+ },
28
+ "binary": {
29
+ "release_repo": "softspark/ai-toolkit",
30
+ "release_tag": "softspark-rtk-v0.44.0-1",
31
+ "install_name": "rtk",
32
+ "assets": {
33
+ "darwin-arm64": {
34
+ "file": "rtk-aarch64-apple-darwin.tar.gz",
35
+ "sha256": "a69b8ccb7c516a1d6e06aff714bdc8bf0afcb2af240c5b2f6c83122743c93c56",
36
+ "member": "rtk"
37
+ },
38
+ "darwin-x86_64": {
39
+ "file": "rtk-x86_64-apple-darwin.tar.gz",
40
+ "sha256": "bda9f4a6acf87be859394d5da3a064db211a869cf331ed2c485e174f5fd81dcb",
41
+ "member": "rtk"
42
+ },
43
+ "linux-aarch64": {
44
+ "file": "rtk-aarch64-unknown-linux-gnu.tar.gz",
45
+ "sha256": "fd5f4b10ca2e96e674b437f9a00639f376b215e7d15373327142f5f8e9642795",
46
+ "member": "rtk"
47
+ },
48
+ "linux-x86_64": {
49
+ "file": "rtk-x86_64-unknown-linux-musl.tar.gz",
50
+ "sha256": "1d886b748181b78e11ea99c2f2ff60ad04a73dbc29ca20ca807f01642ebcea32",
51
+ "member": "rtk"
52
+ },
53
+ "windows-x86_64": {
54
+ "file": "rtk-x86_64-pc-windows-msvc.zip",
55
+ "sha256": "83ebf53af4f15d860cef16e8ff6fe9a5cf25fa10ed4c48a1544d359a2796ef38",
56
+ "member": "rtk.exe"
57
+ }
58
+ }
59
+ }
60
+ }