diff --git a/README.md b/README.md index dc21571..3d59e0d 100644 --- a/README.md +++ b/README.md @@ -338,7 +338,7 @@ and the `shim` package does not carry the plugin folder. Clone the newest release tag to a folder you keep: ```console -git clone --depth 1 --branch v1.2.0 https://github.com/GetSHIM/shim-cli ~/.local/share/shim-cli +git clone --depth 1 --branch v1.2.1 https://github.com/GetSHIM/shim-cli ~/.local/share/shim-cli ``` Then add the plugin folder to your user `settings.json` (Command Palette, @@ -854,6 +854,7 @@ In a script, `shim ledger purge --yes` skips the question. - [Architecture](https://github.com/GetSHIM/shim-cli/blob/main/docs/architecture.md) - [Compatibility](https://github.com/GetSHIM/shim-cli/blob/main/docs/compatibility.md) - [Privacy](https://github.com/GetSHIM/shim-cli/blob/main/docs/privacy.md) +- [1.2.1 release notes](https://github.com/GetSHIM/shim-cli/blob/main/docs/releases/1.2.1.md) - [1.2.0 release notes](https://github.com/GetSHIM/shim-cli/blob/main/docs/releases/1.2.0.md) - [1.1.2 release notes](https://github.com/GetSHIM/shim-cli/blob/main/docs/releases/1.1.2.md) - [1.1.1 release notes](https://github.com/GetSHIM/shim-cli/blob/main/docs/releases/1.1.1.md) diff --git a/docs/compatibility.md b/docs/compatibility.md index d6da831..30297cf 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -202,6 +202,35 @@ tool listings). `history.jsonl`, beside `projects/`, holds one line per interactive prompt with the keys `display`, `pastedContents`, `project`, `sessionId` and `timestamp`; `sessionId` is the transcript's file name. +## 1.2.1 release evidence + +Recorded 11 October 2026 on macOS 26.4 arm64 (8 GB), uv 0.12.5, pipx 1.11.0. +The trials ran first on the released 1.2.0 from PyPI, which is what a visitor +installs, and the short re-check at the end ran on the 1.2.1 candidate wheel +and rebuilt `bin/shim.pyz`. Every trial used a scratch home (`HOME`, the XDG +folders, uv and pipx folders, `CODEX_HOME`, `COPILOT_HOME` and `TMPDIR` +inside it). Claude Code cannot sign in under a scratch home, so its live +sessions used the real home for sign-in only, with +`claude -p --setting-sources project --settings +--strict-mcp-config` and shim's config, state and temporary folders from the +scratch home. Every value was synthetic. + +| Evidence | Recorded result | +| --- | --- | +| Local gate | `python scripts/check.py` green on the 1.2.1 candidate: lint, format, types, 3,384 tests, build, `git diff --check`. | +| Install | With no Python 3.12 anywhere: `uv tool install --python 3.12 --compile-bytecode shim` fetched CPython 3.12 and installed 1.2.0 in 16 s; `pipx install --python python3.12 --fetch-missing-python shim` installed it on a standalone CPython 3.12.15 in 20 s. Upgrading 1.1.2 to 1.2.0 with `uv tool upgrade shim` and `pipx upgrade shim` left an installed Claude Code settings file unchanged. The 1.2.1 wheel installed the same way and answered `shim 1.2.1`. | +| Python 3.10 and 3.14 | The full suite at `v1.2.0`: 3,353 passed on CPython 3.10.21 and on 3.14.3. | +| Plugin archive on 3.9 | The 1.2.0 and the rebuilt 1.2.1 archives, run by the plugin launcher with only the stock macOS `python3` 3.9.6 on `PATH`, masked a recorded `Read` of a `.env` to ``, ``, `` and answered a safe prompt with nothing. | +| Downgrade | 1.1.2 refuses a settings file that holds `markers` or `diet = ["json", "html"]`, and while it does, its prompt hook withholds every prompt. | +| Claude Code | tested: 2.1.291, run on 2.1.286. Package hook, 1.2.0: a `Read` of `.env` reached the model as ``, ``, ``; a WebFetch of `https://httpbin.org/get?email=ops@example.com` with no allow rule was refused for want of permission, so the 1.1.1 fix holds; with `diet = ["json", "html"]` a `curl -s` of a 12,878-byte page reached the model converted, 10,494 bytes smaller, with `` for `billing@example.com`. An IBAN split across two ``s as `GB82 WEST 1234` and ` 5698 7654 32` reached the model as `GB82 WEST 1234 `, the same as with the default diet: the first pass masks the raw markup before the page is converted. Plugin route: `claude plugin marketplace add GetSHIM/shim-cli` and `claude plugin install shim-cli@shim-cli` in a scratch home installed 1.2.0, whose archive, loaded into a live session with no `shim-hook` on `PATH`, masked the same `.env`. 1.2.1 candidate: the `.env` read masked the same way, the WebFetch was refused the same way, and after `shim revert claude --yes` and `uv tool uninstall shim` the settings file was byte-identical to before. | +| `shim watch` | Claude Code, 1.2.0 and the candidate: reports with exact usage, the section split, `costliest`, `largest` and `largest tool result` (`Read, 42,808 bytes`), and the IBAN round trip (`3 in request, 3 in response`). `--json` `findings` held `cli.watch.large_tool_result`, valid against `docs/schemas/finding-v1.json`. In one of three identical runs, the request that carried the tool result arrived while both inspection slots were busy and was not measured, so its IBANs were not counted. A one-line `Say hi.` session in an empty folder counted 2 EMAIL in messages that Claude Code itself added. | +| Codex CLI | tested: 0.159.0. `shim install codex` and `shim doctor codex --json` into a scratch `CODEX_HOME`: the trust warning, and `plugin_not_discoverable` and `hook_activation_unverified`, schema-valid. Replayed prompt events: a report under `warn`, a block with a redacted copy under `enforce`. **No live session:** the only sign-in on the recording machine is a ChatGPT `auth.json`, which cannot be copied into a scratch `CODEX_HOME` without breaking it. | +| GitHub Copilot CLI | tested: 1.0.83, run on 1.0.85. Scratch `COPILOT_HOME`, `shim install copilot`, then `copilot -p` asked to repeat a prompt holding `ops@example.com` and `AKIAIOSFODNN7EXAMPLE`: it answered `` and ``, and `shim report` listed both as masked in the prompt. | +| VS Code | tested: 1.137.0; 1.140.0 installed. **Not run live:** the agent chat needs a signed-in session in the GUI. Replayed prompt events gave a report and, under `enforce`, a stop with a redacted copy. | +| Commands | `doctor`, `status`, `install`, `revert` for all three clients, `scan`, `redact`, `keys`, `config`, `report`, `audit`, `ledger show` and `watch`: their `--json` findings validated against `docs/schemas/finding-v1.json`. A Claude Code settings file in its own format was byte-identical after install and revert. | +| Documentation | Three simulated first-time users (Claude Code, the other clients, the cookbook end to end) and a literal copy-paste of the README install and the first three recipes. What stopped or misled them in the first ten minutes is fixed in 1.2.1; nothing stopped them. | +| Windows | Unchanged: every command still refuses with exit 2 before touching a file (`test_on_windows_every_command_refuses_before_touching_a_file`). | + ## 1.2.0 release evidence Recorded 11 October 2026 on macOS 26.4 arm64, CPython 3.13.5 for the suite and diff --git a/docs/releases/1.2.1.md b/docs/releases/1.2.1.md new file mode 100644 index 0000000..d0a6757 --- /dev/null +++ b/docs/releases/1.2.1.md @@ -0,0 +1,76 @@ +# shim-cli 1.2.1 + +1.2.1 fixes what three simulated first-time users and a literal copy-paste run +of the README and the cookbook tripped over in their first ten minutes on +1.2.0. The hook decides and masks exactly as in 1.2.0, so the detector and the +hook protocol are unchanged. The changes are in what the CLI prints, the +README's first screen and the cookbook. + +Upgrading is `uv tool upgrade shim` or `pipx upgrade shim`, or +`/plugin update shim-cli@shim-cli` in Claude Code. `shim install` writes the +same entries as in 1.2.0. + +## What the CLI says now + +- **`shim demo `** shows the synthetic sentence before and after + masking, then what that client does by default with a prompt or a tool result + like it. It used to print the same masked line for every client, though + Claude Code and Codex report a typed prompt and do not change it. `--json` is + unchanged. +- **`shim doctor`** with nothing installed says `No shim hook is installed, so + nothing is inspected twice.` It used to say `Exactly one shim hook path is + installed.` +- **`shim install claude`** no longer warns that existing hooks will be + preserved when the settings file has no hooks. Most Claude Code users already + have a `settings.json`, so most first installs printed a warning that was not + true. It now ends with the next step, `Start a new Claude Code session; /hooks + lists shim.`, and `shim install copilot` with `Start a new GitHub Copilot CLI + session; it has no trust step.` +- **A client settings file that does not parse** is named with Python's JSON + error and its line and column, by `install`, `revert`, `status` and `doctor`: + `~/.claude/settings.json is not valid JSON: Expecting value at line 1, + column 10.` They used to say only that the configuration could not be changed + safely. +- **`shim watch`** prints a two-line report when no request went through the + proxy, for example because the client was not signed in: `shim watch — 1s, 0 + requests` and `no request reached the model provider through the proxy`. It + used to print nothing after its first line. +- **`shim redact`** ends its output the way the input ended. It used to add a + newline, so `shim redact < file > copy` gave a file with a blank last line. + +## What a visitor reads + +The README opens with a quickstart and a list of what shim cannot do. The +quickstart is install, `shim demo claude` and `shim install claude`. The list +says that a prompt typed into Claude Code or Codex is not masked, that Codex +and GitHub Copilot CLI tool traffic is not inspected, that VS Code masks +nothing, which Claude Code events are only reported, and that Windows is not +supported. The install example is Claude-first, and the four screenshots are +recaptured from this release's output. + +The cookbook now warns about four traps. A second `[mode]` header makes the +settings file invalid. `--reset` turns off a ledger you turned on. Claude Code +puts email addresses of its own into a session, so `shim watch` counts them. +Pasting the redacted-prompt line makes Claude Code ask once to read a temporary +file. + +A contract test checks every `shim` command in the README, the plugin README, +the cookbook, the command reference, the findings page and `llms.txt` against +the CLI's own commands and flags. It checks 259 lines. + +The repository has issue forms, a bug report and a detection report, and a +pull request template. `CONTRIBUTING.md` says why `bin/shim.pyz` is rebuilt +only in a release commit. The Claude Code plugin installs from `main`, so an +archive rebuilt between releases ships unreleased code to plugin users. + +## What to check after upgrading + +- **Scripts that read `shim redact`:** the trailing newline is no longer added. + Input that ends with one still gets it. +- **Scripts that read `shim demo` text:** it now has `before` and `after` lines + and a sentence about the client. Read `shim demo --json` instead. +- **Scripts that read JSON errors:** `CLIENT_SETTINGS_MALFORMED`'s `error` now + ends with the file and the JSON error. Match `code`, never `error`. +- **Downgrading:** a shim-cli older than 1.2.0 refuses a settings file that + holds `markers` or whose `diet` names `html`, and **while it is refused the + prompt hook withholds every prompt**. Remove both keys before you downgrade. diff --git a/llms.txt b/llms.txt index 05b29d2..eced98a 100644 --- a/llms.txt +++ b/llms.txt @@ -16,4 +16,4 @@ What it cannot do: a prompt typed into Claude Code or Codex cannot be masked, be ## Optional -- [1.2.0 release notes](https://github.com/GetSHIM/shim-cli/blob/main/docs/releases/1.2.0.md): the newest release +- [1.2.1 release notes](https://github.com/GetSHIM/shim-cli/blob/main/docs/releases/1.2.1.md): the newest release diff --git a/plugins/shim-cli/.claude-plugin/plugin.json b/plugins/shim-cli/.claude-plugin/plugin.json index c201423..d491e90 100644 --- a/plugins/shim-cli/.claude-plugin/plugin.json +++ b/plugins/shim-cli/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "shim-cli", "displayName": "shim-cli", - "version": "1.2.0", + "version": "1.2.1", "description": "Masks secrets and personal data in the tool results Claude Code reads, before the model sees them; reports what was in your prompts; and, with `shim watch`, shows what a session sent and what it cost. Runs locally with no account, network destination or telemetry.", "author": { "name": "shim Engineering" diff --git a/plugins/shim-cli/.codex-plugin/plugin.json b/plugins/shim-cli/.codex-plugin/plugin.json index 3afaac3..58e8670 100644 --- a/plugins/shim-cli/.codex-plugin/plugin.json +++ b/plugins/shim-cli/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "shim-cli", - "version": "1.2.0", + "version": "1.2.1", "description": "Reports secrets and personal data found in your Codex prompts before they are sent, locally, with no account, network destination or telemetry. Blocking is opt in.", "author": { "name": "shim Engineering" diff --git a/plugins/shim-cli/bin/shim.pyz b/plugins/shim-cli/bin/shim.pyz index 9155a9b..b7166b9 100755 Binary files a/plugins/shim-cli/bin/shim.pyz and b/plugins/shim-cli/bin/shim.pyz differ diff --git a/plugins/shim-cli/plugin.json b/plugins/shim-cli/plugin.json index e126c39..59ab24c 100644 --- a/plugins/shim-cli/plugin.json +++ b/plugins/shim-cli/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "shim-cli", - "version": "1.2.0", + "version": "1.2.1", "description": "Finds secrets and personal data locally, in your prompts and in the tool results the agent reads, and tells you what it found. In VS Code it reports, and with enforcement on it stops a prompt or denies a tool call before it runs; a result that has already reached the model is reported, never masked. No account, no network destination, no telemetry.", "author": { "name": "shim Engineering" diff --git a/pyproject.toml b/pyproject.toml index 6385dc2..0a95e02 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "shim" -version = "1.2.0" +version = "1.2.1" description = "Local traffic visibility and privacy controls for coding agents." readme = "README.md" requires-python = ">=3.10" diff --git a/src/shim_cli/__init__.py b/src/shim_cli/__init__.py index fb22751..8cc49f7 100644 --- a/src/shim_cli/__init__.py +++ b/src/shim_cli/__init__.py @@ -1,4 +1,4 @@ import sys -__version__ = "1.2.0" +__version__ = "1.2.1" WINDOWS = sys.platform == "win32" diff --git a/uv.lock b/uv.lock index bf12ed8..ef44bd1 100644 --- a/uv.lock +++ b/uv.lock @@ -496,7 +496,7 @@ wheels = [ [[package]] name = "shim" -version = "1.2.0" +version = "1.2.1" source = { editable = "." } dependencies = [ { name = "phonenumbers" },