Skip to content

v0.35.3: claude runner.start prompt leak (#478) + help-centre FAQ (#477) + local-context protection#479

Merged
Nathan Schram (nathanschram) merged 3 commits into
devfrom
fix/v0.35.3-claude-runner-start-prompt-leak
May 5, 2026
Merged

v0.35.3: claude runner.start prompt leak (#478) + help-centre FAQ (#477) + local-context protection#479
Nathan Schram (nathanschram) merged 3 commits into
devfrom
fix/v0.35.3-claude-runner-start-prompt-leak

Conversation

@nathanschram
Copy link
Copy Markdown
Member

@nathanschram Nathan Schram (nathanschram) commented May 5, 2026

Combined v0.35.3 follow-up bundle (3 commits on the same fix branch):

Commits

1. fix(security): claude runner.start no longer leaks prompt at INFO ([#478](https://github.com/littlebearapps/untether/issues/478))

The Claude runner override at runners/claude.py:run_impl had its own duplicate runner.start log call that was missed when the base runner was fixed for #205. Practical leak was Untether-preamble boilerplate; spec violation either way. Fix mirrors the base runner impl plus adds two redaction layers (redact_env_i_args + legacy-mode -- boundary).

2. docs(faq): add docs/faq/index.md for help-centre FAQPage schema ([#477](https://github.com/littlebearapps/untether/issues/477))

12 question-shaped H2 FAQs covering install, supported engines, API keys, data flow, interactive approvals, crash recovery, cost budgets, voice notes, update, uninstall, and support channels. Sourced from README + real common-channel topics. Coordinated one-line mapping PR in littlebearapps/littlebearapps.com (scripts/docs-sync.config.tsuntetherdocs/faqcategory: faq) is a separate follow-up.

3. ctx: protect docs/faq/index.md from deletion + register in local docs (#477)

Hardens the local Claude Code context so the FAQ file:

  • cannot be silently deleted, moved, or truncated (new help-faq-protect.sh Bash hook blocks rm, git rm, mv-away, > truncation)
  • has explicit guidance for when/how to update during releases (new .claude/rules/help-faq.md)
  • is registered in CLAUDE.md (new "Help-centre FAQ" section + Hooks/Rules table entries)
  • triggers an FAQ-touch-up reminder on version bumps (extended PostToolUse prompt) and on edits in docs/faq/* (extended PreToolUse Edit/Write prompt)

The hook is self-protected via release-guard-protect.sh so Claude Code can't trivially weaken it. Smoke-tested with 7 synthetic inputs covering both deny and allow paths.

What changed

File Why
src/untether/runners/claude.py Drop prompt=... from INFO runner.start; add DEBUG runner.start_prompt; redact env -i pairs and legacy-mode -- <prompt> tail before logging
tests/test_claude_runner.py 2 new regression tests (test_runner_start_does_not_log_prompt_at_info, test_runner_start_redacts_legacy_mode_prompt_in_args)
docs/faq/index.md New file — 12 H2 FAQs with full answers, no placeholders
.claude/hooks/help-faq-protect.sh New PreToolUse Bash hook (blocks delete/move/truncate of FAQ)
.claude/hooks/release-guard-protect.sh Extends Edit/Write protection list to include help-faq-protect.sh
.claude/hooks.json Registers the new Bash hook + adds HELP-FAQ branch to Edit/Write context-prompt + adds FAQ-touch-up step to version-bump checklist
.claude/rules/help-faq.md New rule — full update cadence and shape rules
.claude/rules/release-discipline.md New step 6 in version-bump checklist (FAQ touch-up scan)
CLAUDE.md New "Help-centre FAQ" section; Hooks + Rules tables updated
CHANGELOG.md Two new v0.35.3 entries: ### fixes (#478) and new ### docs subsection (#477)

Test plan

  • uv run pytest tests/test_claude_runner.py tests/test_claude_control.py tests/test_runner_utils.py tests/test_exec_runner.py tests/test_exec_bridge.py — 426 passed, 1 skipped
  • uv run ruff format --check src/ tests/ — clean
  • uv run ruff check src/untether/runners/claude.py tests/test_claude_runner.py — clean
  • jq . .claude/hooks.json — valid JSON
  • FAQ-protect hook smoke test — 7 cases (4 deny, 3 allow) all match expected outcomes
  • FAQ acceptance criteria: 12 H2 question headings (≥7 required); no TODO/placeholder; complete answers
  • Live retest on dev: runner.start [untether.runners.claude] only carries engine, resume, prompt_len, args (env redacted), no prompt='...' field
  • Smoke-checked all 12 H2 headings start with question word OR end with ?

Closes #478, closes #477.

🤖 Generated with Claude Code

The Claude runner's run_impl override at src/untether/runners/claude.py
had its own duplicate runner.start log call that was missed when the
base runner was fixed for #205. Every Claude session emitted
`prompt=prompt[:100] + "…"` at INFO level — leaking the first ~100
chars of the Untether preamble (boilerplate, but spec-violating).
Discovered during the v0.35.3 follow-up E2E pass.

Fix mirrors the base runner impl:
- INFO `runner.start`: only `engine`, `resume`, `prompt_len`, `args`
- DEBUG `runner.start_prompt`: preview of first 100 chars (opt-in)

Argv redaction also tightened:
- env -i KEY=VAL pairs redacted via redact_env_i_args (was already
  applied at subprocess.spawn but not at runner.start, so e.g.
  BWS_ACCESS_TOKEN, GEMINI_API_KEY values would land in INFO logs)
- Legacy-mode (no permission_mode) `-- <prompt>` tail collapsed to
  `-- <prompt redacted>` so prompt content never reaches INFO under
  any code path

2 new regression tests cover both control-channel and legacy modes:
- test_runner_start_does_not_log_prompt_at_info
- test_runner_start_redacts_legacy_mode_prompt_in_args

Closes #478.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 43c2b5a9-1f31-4d26-af9b-7952511ef1a6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/v0.35.3-claude-runner-start-prompt-leak

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Marketing-site infra (FAQPage extractor on
`feature/help-seo-geo-items-1-4` in littlebearapps/littlebearapps.com)
already extracts question-shaped H2s and emits Schema.org FAQPage
JSON-LD on any help article with `category: faq` frontmatter or ≥3
question-shaped H2s. No tool currently has a dedicated FAQ scaffold;
this commit closes the loop for Untether.

The new file lives at docs/faq/index.md (Diátaxis-aligned scaffold —
plain title + description frontmatter, marketing-site sync injects
category/tool/dates). 12 question-shaped H2s exceed the 7-minimum
acceptance criterion:

  1. What is Untether?
  2. How do I install Untether?
  3. Which AI coding agents does Untether support?
  4. Do I need an API key to use Untether?
  5. Where does my code and data go?
  6. How do I approve tool calls from my phone?
  7. What happens if my agent crashes or my phone loses signal mid-run?
  8. How do I keep agents from spending too much money?
  9. Can I send voice notes instead of typing?
  10. How do I update Untether?
  11. How do I uninstall Untether?
  12. Where can I get help or report a bug?

Each answer is a complete paragraph (no TODO / placeholder), sourced
from README + real common-channel topics. Cross-links to existing
help-guide URLs preserve nav chains.

Coordinated mapping in `littlebearapps/littlebearapps.com`
(`scripts/docs-sync.config.ts` → add `untether` → `docs/faq` →
`category: faq`) is a separate one-line PR per the issue's
"Coordinated mapping" section. Once both land, the next nightly sync
surfaces the FAQ at <https://untether.littlebearapps.com/help/untether/faq/>
with a visible `<script type="application/ld+json">` FAQPage block,
unlocking AI-citation surface (ChatGPT, Perplexity, Google AI
Overviews) and SERP rich-snippet eligibility.

Closes #477.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nathanschram Nathan Schram (nathanschram) changed the title fix(security): claude runner.start no longer leaks prompt at INFO (#478) fix(security): claude runner.start prompt leak (#478) + docs: add FAQ for FAQPage schema (#477) May 5, 2026
…#477)

The FAQ doc is part of the marketing-site FAQPage Schema.org pipeline
(littlebearapps/littlebearapps.com:scripts/docs-sync.config.ts → untether
→ category: faq). Removing it silently breaks the docs-sync mapping and
regresses AI-citation surface. This commit hardens local Claude Code
context so the file:

  - cannot be silently deleted, moved, or truncated by accident
  - has explicit guidance on when/how to update it during releases
  - is registered in CLAUDE.md so future contributors know it exists

Changes:

* `.claude/hooks/help-faq-protect.sh` (new) — PreToolUse Bash hook
  blocking `rm`, `git rm`, `mv`-away, and shell `>` truncation
  targeting `docs/faq/index.md`. Edits via Edit/Write/append `>>` are
  intentionally allowed — the FAQ is meant to evolve. Smoke-tested
  with 7 synthetic inputs covering both deny and allow paths.

* `.claude/hooks/release-guard-protect.sh` (updated) — also protects
  `help-faq-protect.sh` from being weakened or removed via Edit/Write.

* `.claude/hooks.json` (updated) —
  - registers help-faq-protect.sh under PreToolUse Bash
  - extends the existing Edit/Write context-prompt with a docs/faq/*
    branch (HELP-FAQ CONTEXT) reminding contributors of question-shape
    rules and the maintain-as-features-land cadence
  - extends the version-bump-checklist (PostToolUse) with an FAQ
    touch-up step

* `.claude/rules/help-faq.md` (new) — auto-loads when editing
  `docs/faq/**`. Documents the hard rules (NEVER delete; MUST update
  with feature changes), soft conventions (question-shaped H2, ≥7
  Q/A, real behaviour not aspirational), and the release-cadence
  workflow.

* `.claude/rules/release-discipline.md` (updated) — adds an FAQ
  touch-up step to the version-bump checklist.

* `CLAUDE.md` (updated) —
  - new "Help-centre FAQ" section after "Documentation screenshots"
    explaining the file's role and the no-deletion rule
  - Hooks table registers `help-faq-protect`
  - Rules table registers `help-faq.md`

Refs #477.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nathanschram Nathan Schram (nathanschram) changed the title fix(security): claude runner.start prompt leak (#478) + docs: add FAQ for FAQPage schema (#477) v0.35.3: claude runner.start prompt leak (#478) + help-centre FAQ (#477) + local-context protection May 5, 2026
@nathanschram Nathan Schram (nathanschram) merged commit de5d37e into dev May 5, 2026
21 checks passed
@nathanschram Nathan Schram (nathanschram) deleted the fix/v0.35.3-claude-runner-start-prompt-leak branch May 5, 2026 10:48
Nathan Schram (nathanschram) added a commit that referenced this pull request May 5, 2026
Bumps pre-release version so TestPyPI can publish a fresh wheel that
includes the v0.35.3 follow-up bundle merged via PR #479:
  - fix(security): claude runner.start no longer leaks prompt at INFO (#478)
  - docs(faq): add docs/faq/index.md for help-centre FAQPage schema (#477)
  - ctx: protect docs/faq/index.md from deletion + register in local docs (#477)

The rc6 wheel on TestPyPI predates this work — without the bump the
publish step skips ("File already exists") and the staging upgrade path
keeps installing the older wheel.

Per release-discipline.md, pre-release versions don't require a
CHANGELOG entry (validate_release.py skips them) and aren't tagged
(auto-tag-on-master.yml skips pre-releases).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant