Skip to content

release: promote main to prod — v0.7.9 (8-platform deep parity + suppression + GitHub Action @v1 fix)#92

Merged
Raftersecurity merged 46 commits into
prodfrom
main
May 8, 2026
Merged

release: promote main to prod — v0.7.9 (8-platform deep parity + suppression + GitHub Action @v1 fix)#92
Raftersecurity merged 46 commits into
prodfrom
main

Conversation

@Rome-1
Copy link
Copy Markdown
Collaborator

@Rome-1 Rome-1 commented May 8, 2026

Summary

First main→prod cut since #49 (v0.7.1-series hotfix). 66 commits land 7 substantial features, 4 quality fixes, and the test-suite repair that unblocks Validate Release. Bumps to 0.7.9 (skipping 0.7.8 — feature scope is minor-bump worthy).

Headline changes since #49

Bead / PR Description
rf-65zg (#88) rafter agent verify — Python parity across all 8 platforms, Continue/Aider coverage, --json (CI consumable), --probe runtime mode for Claude Code
rf-q7j (#57) First-class .claude/agents/rafter.md Claude Code sub-agent — calling agents invoke via Agent(subagent_type="rafter"), hard-restricted to Bash/Read/Grep
rf-zgwj (#91) OpenClaw integration rebuilt as a ClawHub-shaped skill — install moved to canonical ~/.openclaw/workspace/skills/rafter-security/SKILL.md; legacy strip on reinstall; re-included in --all
rf-svn3 (#81) Cursor deep support — per-skill rules, sub-agent, full pre/post-tool hooks
rf-0vr3 (#84) Windsurf deep support — pruned broken hooks, per-skill rules, AGENTS.md
rf-acz0 (#86) Continue.dev per-skill rules + --local (project) scope install
rf-du2o (#85) Aider read-only context — RAFTER.md + .aider.conf.yml read: integration
rf-d8s (#66) Suppress findings via .rafter.yml ignore: + emit _suppressed in JSON output
rf-zfhj (#76) GitHub Action surfaces HTTP error body on scan API failures (no more silent curl exit 22)
rf-ovql, rf-044o (#87) Codex + Gemini hook matchers verified against current upstream docs
rf-o329 (#89) docs/adding-a-platform.md onboarding contract for new agent integrations

Quality fixes in this PR

  • rf-6s9l, rf-b9l8, rf-blvo (14f3eb9) — 13 Node tests across 4 files updated to match the schema changes that landed in rf-0pch (wrapped --json shape), rf-d8s (Suppression.source field), and rf-zgwj (OpenClaw path). Test-only changes; Validate Release green on dc81574. Independent code review caught a stale staged production-code change before commit; pushed clean.
  • rf-zfhj action (a)v1 major-version tag retagged to current main HEAD on 2026-05-07 (was stuck at 24454ed with unquoted YAML descriptions, breaking every PR run that used Raftersecurity/rafter-cli@v1). Will fast-forward v1 again to the v0.7.9 tag once this PR merges.

Out of scope (filed for follow-up)

  • rf-lyj9 (P1) — rafter skill install --platform openclaw still uses the pre-rf-zgwj flat path. Two install entrypoints now write to different locations on the same platform. Filed today during code review of this release.

Test plan

  • Validate Release green on 14f3eb9 (test fixes) and dc81574 (version bump)
  • validate-versions confirms Node 0.7.9 == Python 0.7.9
  • test-package: tarball ships resources/pre-commit-hook.sh; rafter agent install-hook end-to-end works post-npm install -g
  • test-build: 1716 Node tests passing in clean-HOME (was 1716 passing / 13 failing pre-fix)
  • CI on the merge commit re-confirms before publish.yml fires

Post-merge actions (will be done by jack)

  1. Tag v0.7.9 on the merge commit
  2. Fast-forward v1 to that tag (delete + recreate, same pattern as 2026-05-07 retag)
  3. Watch publish.yml push to npm (@rafter-security/cli@0.7.9) and PyPI (rafter-cli==0.7.9)

🤖 Generated with Claude Code

Rome-1 and others added 30 commits April 27, 2026 02:50
…-pkn)

Adds AGENTS.md as the cross-agent (Codex/Cursor/Aider/etc.) entrypoint for
this repo. CLAUDE.md is referenced for the project-specific rules; AGENTS.md
adds the new COLLAB.md collaboration convention:

- Read COLLAB.md at session start and before suggesting tooling/workflow.
- Keep COLLAB.md up to date with surgical entries — go-to commands, tools,
  and tips that are not obvious from existing docs.
- Surface promising third-party tools the agent doesn't have, but DO NOT
  INSTALL anything without explicit per-session user approval. Past COLLAB.md
  endorsements are NOT consent.
- Treat COLLAB.md privacy as inheriting the repo's visibility; never put
  secrets, internal URLs, or session tokens in it.
- COLLAB.md is not a permission grant, not a substitute for review, not the
  source of truth for architecture.

Pending Rome's explicit approval (rf-6va) before merge — AGENTS.md is
public-facing.
…ence not applied

Local secret scans now emit a top-level JSON object instead of a bare array.
The new shape carries scan-mode metadata so agents and reviewers know that
findings come from pure pattern matching with no agentic-intelligence triage:
they should investigate each finding, but absence of triage is not an excuse
to dismiss them. Coordinate with rf-d8s on the `_note` key convention.

Schema:
  { "_note": "...", "scan_mode": "local", "triage_applied": false,
    "results": [...same as before...] }

`rafter issues create from-scan --from-local` accepts both new and legacy
shapes for forward-compat reading of older scan exports.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
OpenCode appeared in the supported-platforms badge row but no --with-opencode
init flag exists. The plain-text platform list already omits it; the badge
was the only inconsistency.

Source: drafts/consistency-audit/REPORT.md H5 (commit 8bedf63, since reverted).
Other audit findings target docs.rafter.so and rafter.so — separate rigs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Establishes ground truth for what each of the 8 supported agent platforms
currently gets vs. what Claude-Code+Codex parity requires. Cross-references
install code, recipes, and verify checks. Surfaces concrete findings:

- Continue.dev hook file is almost certainly a silent no-op (we write
  Claude's PreToolUse format to .continue/settings.json, which Continue.dev
  doesn't read)
- Cursor + Windsurf install hooks the recipes don't mention (silent install,
  unverified runtime fire)
- Gemini's rf-yit skills-registration shipped but verify only checks MCP
- Aider has no hook surface; closest interjection point is its --read files
  (currently not used)
- rafter agent verify is structurally weak: file-presence only, doesn't
  cover Continue.dev or Aider, no runtime probe
- Three platforms have no instruction file (Windsurf, Continue.dev, Aider)
- Four platforms have no skills install (Cursor, Windsurf, Continue.dev, Aider)

Refines the rf-cia work order: verify-and-prune-broken-installs FIRST
(reduces surface area), then verify upgrade, then per-platform skills/
instructions, then onboarding doc. Roughly 7-8 days total.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…zfhj)

Symptom: action fails with bare "curl exit 22" and no diagnostic info,
because `curl -fsS` suppresses the response body on HTTP >= 400. This
hides 401 (bad/expired API key), 403 (quota), 404 (endpoint moved),
422 (schema mismatch), and 5xx (backend) all behind the same opaque exit.

Fix: replace `-fsS` with explicit status capture (`curl -sS -o file -w
%{http_code}`) in all four scan API calls (POST trigger, GET poll, GET
results in 3 formats). On non-2xx, emit `::error::` with the HTTP code
and the server's `.error` field (or raw body if not JSON). On curl
transport error, log and exit/retry.

Security: API key is never echoed (only used in `-H x-api-key:` header).
Server response body cannot contain the API key — verified by reading
the rafter.so /api/static/scan route handler. GitHub Actions also
auto-masks `inputs.api-key` in logs as defense in depth.

Bead: rf-zfhj

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Continue.dev does not read ~/.continue/settings.json and has no
hooks.PreToolUse / PostToolUse field in its config schema. Current versions
use ~/.continue/config.yaml; legacy uses config.json. Confirmed against
docs.continue.dev/customize/deep-dives/configuration: settings.json is
not a Continue.dev config file. The hook install we shipped was a silent
no-op at runtime — files written, never consumed.

This PR brings the install behavior in line with what recipes/continue-dev.md
has always documented: MCP-only.

Removed:
- installContinueDevHooks function from node/src/commands/agent/init.ts +
  its call site
- continueHooks ComponentSpec from node/src/commands/agent/components.ts
- _continue_hooks ComponentSpec from python/rafter_cli/commands/agent_components.py
- continue.hooks expectation from agent-components.test.ts and
  test_agent_components.py
- Pre-existing platform-integration tests asserting the broken behavior
- "MCP + hooks" prompt phrasing in interactive init flow (now "MCP server")

Added:
- 3 Node tests in platform-integration.test.ts (Continue.dev hooks pruned
  describe block) — assert no settings.json is written, pre-existing
  user settings.json is untouched, MCP install still works
- 3 Python tests in test_agent_init.py (TestContinueDevHooksPruned) —
  same shape

Updated:
- shared-docs/PLATFORM_PARITY_AUDIT.md: Continue.dev row marked pruned
- CHANGELOG.md: Removed entry under [Unreleased]

Test results:
- 83 tests pass across the two Node test files I touched
  (platform-integration.test.ts + agent-components.test.ts)
- 1206 of 1207 Python tests pass; one pre-existing failure
  (test_version_matches_pyproject) is a stale local rafter-CLI version,
  not related to this PR
- Pre-existing Node failures tracked separately under rf-kqn4

Out of scope for this PR (next phases of rf-cia):
- Cursor + Windsurf hook schema verification (similar prune may apply)
- rafter agent verify gaining --probe runtime check
- Skills install for Cursor/Windsurf/Continue/Aider via platform-native
  primitives

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Followed up Phase a/b with thorough docs research per platform. Two
cross-cutting findings change the support plan:

1. .claude/agents/ is multi-platform — Cursor reads both .cursor/agents/
   AND .claude/agents/. Our rf-q7j sub-agent install is already half-
   supported on Cursor for free. We should ship .cursor/agents/rafter.md
   for Cursor-only users and document the cross-platform nature.

2. AGENTS.md is multi-platform — Windsurf reads AGENTS.md natively from
   any workspace directory. Our rf-djw Codex install is already quietly
   helping Windsurf users. AGENTS.md should be the rafter cross-platform
   context standard.

Per-platform reality check (each row updated with concrete file paths,
schemas, stability status from current vendor docs):

- Cursor: full hook + rule + sub-agent + MCP support. Hooks at
  ~/.cursor/hooks.json with events including preToolUse, postToolUse,
  beforeShellExecution, beforeMCPExecution. Rules at .cursor/rules/*.mdc
  with 4 activation modes. Sub-agents at .cursor/agents/*.md. Plan: add
  preToolUse/postToolUse hooks beyond just beforeShellExecution; migrate
  consolidated rule to one-per-skill; ship Cursor sub-agent.

- Windsurf: rich rules + MCP, NO hooks. Rules at .windsurf/rules/*.md
  (workspace, 12KB/file) + ~/.codeium/windsurf/memories/global_rules.md
  (global, 6KB total). YAML frontmatter with trigger field. Reads
  AGENTS.md natively. Plan: drop broken hook install; add per-skill
  rules; surface AGENTS.md write for Windsurf users.

- Aider: NO hooks, NO skill primitive, but --read flag is settable in
  .aider.conf.yml. CONVENTIONS.md is the community pattern. MCP support
  unconfirmed by docs — current YAML mcp-server-command append likely
  another silent no-op. Plan: verify MCP; add RAFTER.md + read: config.

- Continue.dev (phase b done): rules at .continue/rules/*.md, per-rule
  files. Plan: add per-skill rules; confirmed no hooks ever.

Plan tabulated per surface (Hooks / Rules / Sub-agent / AGENTS.md / MCP)
showing today vs. goal. Refines rf-cia into concrete platform-by-platform
deliverables.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
test+fix: custom-patterns / policy-merge / policy-export tests + gitleaks/binary-manager fix (gt-pvx)
docs: remove aspirational OpenCode badge from README (rc-dn0)
rf-cia phase a+b: platform parity audit + Continue.dev hooks prune
…ig/status/verify)

Adds 69 tests covering every agent subcommand surface — flag handling,
exit codes, output formats, audit logging, cross-command integration,
and the audit-helper unit functions. Tests invoke the built dist CLI
(not tsx) for speed; suite finishes in ~75s.

Synthetic test secrets are composed via concatenation so the file does
not itself trip secret-scanning push protection.

Closes rc-tx7
Implements snapshot/regression testing with golden file comparisons for both
Node.js and Python scanner implementations. Fixtures are generated at test
time (not committed) to avoid triggering GitHub push protection.

Tests cover: single file scans (5 fixture types), directory scanning, redaction
accuracy, and line/column position verification. Golden files are identical
across both implementations, validating cross-implementation consistency.

Regenerate golden files with: UPDATE_SNAPSHOTS=1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
docs: add AGENTS.md with COLLAB.md collaborator-notes instruction (rf-pkn)
The "Scanned by Rafter" badge in README.md, the badge gallery in
badges/README.md, and the outreach disclosure templates in
outreach-drafts.md all linked to https://github.com/raftercli/rafter,
which 404s. The actual repo is github.com/Raftersecurity/rafter-cli.

A broken badge on first click is a poor trust signal for security
adopters. From rf-v85b (closed PR #70) consumer-perspective review.
Skill install functions copied only SKILL.md, silently dropping any
docs/ reference material. Recursive copy keeps the full skill tree
intact so future docs/ subfolders ship to users instead of being
stripped at install time.

- Node installSkillDir uses fs.cpSync(..., recursive: true)
- Python _copy_skill_tree walks importlib.resources, skipping
  __init__.py and __pycache__

npm pack already includes resources/**, so no packaging changes
needed; verified by adding a temporary docs/ folder and confirming
both the npm tarball listing and a live install drop docs/*.md
under .agents/skills/rafter/docs/.
feat: add JSON _note to rafter scan local (rf-0pch)
Pricing is marketing content; rafter brief is an agent-facing CLI surface
for setup, commands, and skills. Pricing belongs at rafter.so and in the
README, not in the brief topic registry.

Removed from both implementations:
- node/src/commands/brief.ts: pricing topic entry (description + render).
- python/rafter_cli/commands/brief.py: pricing entry in TOPIC_DESCRIPTIONS
  + pricing branch in _render_topic.

Tests updated to assert the removal:
- topic-listing tests now assert pricing is NOT in the listed topics.
- pricing rendering tests replaced with a "rejected, exit code != 0" check.

The 'all' topic was unaffected (it only combines scanning + setup; never
included pricing).

29/29 Node brief tests + 35/35 Python brief tests green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
chore(rf-lun4): drop 'pricing' topic from rafter brief
Bundleable internal-docs PR from rf-93jx audit (closed PR #68).
All in-repo doc fixes; no public-site copy changes; no command behavior changes.

H1 - Badge URL 404 (16 places): github.com/raftercli/rafter ->
  github.com/Raftersecurity/rafter-cli in README.md (4) + badges/README.md (12).

H3 - README scan command sweep: 'rafter agent scan' and 'rafter scan local' ->
  'rafter secrets' (current canonical, since 0.7.4) in README.md, SKILL.md,
  llms.txt, recipes/pre-commit.md, shared-docs/CLI_SPEC.md, badges/README.md.
  CLI_SPEC.md keeps its parenthetical alias note for grep landing.

M2 - Audit log event types: scan_executed and config_changed are defined
  in the type union but never emitted. Annotated as 'reserved for future use'
  in README.md and SKILL.md (matches what docs.rafter.so already says).

M5 - node/README.md slimmed from 708 lines to 55 lines: thin pointer to
  root README + Node-specific install/build notes. Same content shows up
  on npmjs.com without re-deriving the full reference there.

L1 - URL casing standardized: raftersecurity/rafter-cli ->
  Raftersecurity/rafter-cli (canonical org casing) in README.md, SKILL.md,
  llms.txt, recipes/pre-commit.md, action.yml.

Closes rf-8fhj. Tests untouched (doc-only); 41 pre-existing
platform-integration failures on main are not introduced by this PR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
docs: sweep deprecated scan command + fix 404 badge URLs (rf-8fhj)
docs: fix broken repo URL in README badges (rf-6epe)
Re-runs the rf-cia parity audit after phase a+b shipped. Confirms
Continue.dev hooks pruning landed in both Node + Python; matrix updated
to v0.7.7 state; eight followup beads filed for the remaining gaps
(Cursor full hooks + rules, Windsurf hook prune + rules, Continue.dev
rules, Aider MCP-or-drop + RAFTER.md, agent verify Python parity +
probe, Gemini E2E re-verify, adding-a-platform doc, OpenClaw activity
check).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
… pre/post-tool hooks (#81)

Brings Cursor up to Claude-Code parity (rf-cia phase c).

Hooks (~/.cursor/hooks.json):
  Adds preToolUse + postToolUse alongside the existing beforeShellExecution.
  Idempotent across all three events; non-rafter entries preserved.

Rules (~/.cursor/rules/):
  Replaces the consolidated rafter-security.mdc with four per-skill .mdc
  files — rafter, rafter-secure-design, rafter-code-review, rafter-skill-review.
  Each rule's frontmatter description is reused verbatim from its SKILL.md
  (trigger-first per rf-4ei/rf-8po), alwaysApply: false. Legacy file is
  auto-removed on reinstall.

Sub-agent (~/.cursor/agents/rafter.md):
  Reuses the rf-q7j Claude-Code sub-agent body. Cursor frontmatter has no
  tools: field — that line is stripped at install time so tools inherit
  from the parent agent.

Components:
  cursor.instructions now manages rules + sub-agent together for
  rafter agent enable/disable. cursor.hooks now covers all three events.

Tests (TDD):
  13 new Node tests in cursor-deep-support.test.ts (preToolUse/postToolUse,
  idempotency, preservation, --local install, frontmatter shape, body
  contents). 12 new Python tests across TestInstallCursorHooks /
  TestInstallCursorRules / TestInstallCursorSubAgent. Existing
  platform-integration tests updated to match the new layout. All Python
  agent-init tests (58) and the Cursor + agent-components Node tests pass.

Smoke-tested: rafter agent init --local --with-cursor produces hooks.json,
mcp.json, four rules, and the sub-agent file in both Node and Python builds.

Sub-agent body sourced from rf-q7j (PR #57); included here so this PR is
self-contained — merging either order produces the same final file.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
… rules + AGENTS.md (#84)

Brings Windsurf to the integration shape Windsurf actually consumes (rf-cia phase c).

Pruned:
- ~/.windsurf/hooks.json install (Node + Python). Windsurf has no documented
  hook surface; pre_run_command / pre_write_code were silently ignored at
  runtime. Independently flagged by the rf-cia gap reports (rf-p1ri, rf-vayl)
  and the research bead (rf-s1n3). Same prune pattern as Continue.dev hooks
  in rf-cia phase b.
- windsurf.hooks ComponentSpec dropped from both Node and Python registries.

Added:
- Per-skill rules under .windsurf/rules/<skill>.md with Windsurf YAML
  frontmatter (trigger: model_decision + description). Four files mirror
  the Cursor pointer-rule pattern: rafter, rafter-secure-design,
  rafter-code-review, rafter-skill-review.
- windsurf.rules ComponentSpec replaces windsurf.hooks in the registry —
  manageable via rafter agent enable/disable.
- AGENTS.md write at workspace root for --with-windsurf. installGlobalInstructions
  now consolidates Codex + Windsurf into a single AGENTS.md (both read it),
  with the marker-block pattern preserving user content.
- --local (project-scope) install for Windsurf. Project install ships rules
  + AGENTS.md; user install additionally registers the MCP entry.

Test results:
- 5 new Node tests + 4 new Python tests under TestInstallWindsurfRules.
- Combined-platforms integration test updated to assert no hooks.json,
  per-skill rules present, and AGENTS.md written.
- agent-components tests in both impls updated to expect windsurf.rules.

The 9 pre-existing Gemini failures in node/tests/platform-integration.test.ts
are unchanged by this work (they fail on main too).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…read: (#85)

Brings Aider integration to the only intercept Aider actually consumes
(rf-cia phase c).

Pruned:
- mcp-server-command: rafter mcp serve append in .aider.conf.yml (Node + Python).
  Aider has no native MCP support; the unknown YAML key was silently
  ignored at runtime. Independently flagged by gap reports rf-p1ri / rf-vayl
  and research bead rf-s1n3. Same prune pattern as Continue.dev hooks
  (rf-cia phase b) and Windsurf hooks (rf-0vr3).
- aider.mcp ComponentSpec dropped from both registries; replaced by aider.read.

Added:
- RAFTER.md write at workspace root with the rafter security context block
  (uses the existing injectInstructionFile marker pattern).
- read: list entry for RAFTER.md in .aider.conf.yml. Preserves any existing
  read: entries; preserves other YAML keys; handles read: as missing/scalar/list.
- aider.read ComponentSpec — manageable via rafter agent enable/disable.
- --local (project-scope) install: writes RAFTER.md + edits .aider.conf.yml
  in cwd, no Aider install required on the machine.
- Migration: reinstalling on top of an older .aider.conf.yml strips the legacy
  mcp-server-command line (with or without the preceding comment marker).

Brief and recipe rewritten to document the new shape (no MCP, RAFTER.md +
read: list).

Test results:
- 6 new Node tests in describe("Aider read-only context (--with-aider)")
- 6 new Python tests in TestInstallAiderRead
- agent-components tests in both impls updated and green
- Combined "All 8 platforms" integration test updated and green
- Brief tests in both impls remain green (Aider brief still mentions MCP in
  its "no native MCP support" sentence, satisfying the existing assertion)

Live smoke (Node): rafter agent init --local --with-aider with a pre-existing
.aider.conf.yml containing the legacy mcp-server-command line strips the
legacy line, preserves model: + a pre-existing read: entry, and adds RAFTER.md
to read:.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
… install (#86)

Adds the rules surface Continue.dev natively reads — previously rafter
shipped MCP-only support for Continue (rf-cia phase c).

Added:
- 4 per-skill rule files at .continue/rules/<skill>.md with Continue.dev YAML
  frontmatter (`name:`, `description:`, `alwaysApply: false`):
  rafter, rafter-secure-design, rafter-code-review, rafter-skill-review.
- continue.rules ComponentSpec in both Node and Python registries —
  manageable via rafter agent enable/disable.
- --local (project-scope) install. Project install ships rules only; user
  install additionally registers the MCP entry under ~/.continue/config.json.
- Recipe rewritten to document rules + MCP + project-scope install.

Continue.dev has no documented hook surface — the prior hooks install was
pruned in rf-cia phase b. Rules + MCP are the only intercepts.

Test results:
- 2 new Node tests in describe("Continue.dev rules (--with-continue)")
- 3 new Python tests in TestInstallContinueDevRules
- agent-components tests in both impls updated and green
- Combined "All 8 platforms" integration test asserts the rules ship — green
- Live smoke (Node + Python): rafter agent init --local --with-continue
  writes 4 rules and no MCP entry; user-scope install adds MCP entry too.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…urrent docs (#87)

Both hook installs were flagged as "schema unverified" by the rf-cia
gap reports (rf-p1ri, rf-vayl). Re-verified against current upstream docs:

Codex (rf-ovql) — schema confirmed against developers.openai.com/codex/hooks:
- ~/.codex/hooks.json with PreToolUse/PostToolUse/PermissionRequest/
  SessionStart/UserPromptSubmit/Stop. Matches what we install.
- PreToolUse intercepts Bash + apply_patch (file edits) + MCP tool calls
  per the docs. We previously matched only "Bash", missing file edits.
- Updated PreToolUse.matcher from "Bash" to "Bash|apply_patch" (Node + Python).
  PostToolUse stays catch-all.
- The Bash-only-fires-reliably caveat from upstream issues #16732 / #20204
  is unchanged; widening the matcher just stops us from leaving hook events
  on the table when they would have fired.

Gemini (rf-044o) — schema confirmed against geminicli.com/docs/hooks/reference:
- ~/.gemini/settings.json with BeforeTool/AfterTool. Matches our install
  (Gemini's hook docs were absent at the time of the rf-cia research bead;
  they have since been published).
- Matchers are regex against built-in tool names. Our matcher
  "shell|write_file" worked by substring (matched "shell" in
  "run_shell_command"), but is fragile if Gemini ever tightens to exact-name.
- Updated BeforeTool.matcher from "shell|write_file" to
  "run_shell_command|write_file|replace|edit" (Node + Python). Uses the
  documented built-in names verbatim.

Test results:
- Updated Codex matcher assertion in node/tests/platform-integration.test.ts
- Updated Gemini matcher assertion in node/tests/platform-integration.test.ts
- Codex tests: 2/2 green
- Python agent_components tests: 14/14 green

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
- Canonicalize on `rafter secrets` (was incorrectly documenting the now-
  deprecated `rafter scan local` alias).
- Make local-vs-remote split explicit up top so agents pick the right
  command on first read.
- Surface RAFTER_API_KEY and inline a `.rafter.yml` example so common
  agent tasks (suppression, custom patterns, command policy) don't need
  a docs round-trip.
- Distinguish `scan.exclude_paths` (whole files) from
  `rafter agent baseline` (specific known findings).
- Replace placeholder exit-code blurb with the actual matrix from
  CLI_SPEC.md (0/1/2 local; +3/4 remote).
- Trim "9 platforms" to actual 8 agent platforms + Gitleaks binary.
- Drop hard-coded pricing, defer to rafter.so/pricing.
- 3 quiz agents read only the new file and answered 6/6 correctly each.
…iiev)

Parity pass over PR #63 to verify rafter-cli/llms.txt tells the same story as
docs.rafter.so/llms.txt and the public site llms.txt. Adds the vision framing
both other surfaces carry while keeping the technical accuracy of the rewrite.

- Lead with "shift security left into the agent's feedback loop"
- Add "agent-first primitive designed to live inside the loop" paragraph
- Rename "remote SAST/SCA" to "Rafter Code Security Engine" (matches docs)
- Cross-link the three llms.txt surfaces

Gitleaks naming kept (CLI codebase ships gitleaks); docs-site Betterleaks
rebrand tracked separately as rf-0hnb.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Rome-1 and others added 16 commits May 3, 2026 19:52
`rafter agent init --with-claude-code` now drops a first-class sub-agent
definition at <root>/.claude/agents/rafter.md alongside the existing skills
install. Claude Code surfaces sub-agents in the calling agent's tool list
(via Agent(subagent_type='rafter')), making delegation the natural motion
for "is this safe / secure / production worthy?" questions. Skills only
appear in the activation prompt — passive — so this directly attacks the
organic-invocation gap they don't close.

The sub-agent body documents the tier hierarchy honestly:
  rafter run                — default; remote SAST+SCA; needs RAFTER_API_KEY
  rafter run --mode plus    — agentic deep-dive on suspicious patterns
  rafter secrets            — offline secrets-only fallback (NOT a code scan)

Toolset is hard-restricted to Bash, Read, Grep — no code modification, no
commits, no non-rafter scanners. If RAFTER_API_KEY is unset the sub-agent
must fall back to `rafter secrets` AND say so explicitly in its verdict
(no silent tier downgrades).

Single canonical content shipped from both implementations:
  node/resources/agents/rafter.md
  python/rafter_cli/resources/agents/rafter.md  (byte-identical mirror)

Tests: 6 new Node tests (claude-code-subagent.test.ts) + 5 new Python tests
(TestInstallClaudeCodeSubAgents in test_agent_init.py) covering frontmatter
shape, body content (tier hierarchy + trigger phrasing), idempotency,
overwrite-on-stale, --local project install, and gating on --with-claude-code.

Out of scope (separate bead rf-0z9, on hold for review): `rafter review`
standalone command via Claude Agent SDK (BYOK).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sub-agent file (`rafter.md`) was already laying out three CLI tiers and four
skills, but the language stopped short of telling agents *not* to stop at the
local tier — and didn't link to the per-skill `docs/` files that hold the
actual judgment-layer content. Both gaps were called out in the rf-lxfh hook.

Changes (byte-identical between Node + Python copies):

- Section heading now reads "DO NOT stop at 'local'" and a new
  "Anti-patterns that count as 'stopping at local'" sub-list spells out the
  four common failure modes (treating `rafter secrets` as a security scan,
  silent downgrade when no API key, CLI-only with no skill, eyeballing a
  third-party skill instead of running `rafter-skill-review`).
- Skills section reframed as "the judgment layer the scanner can't reach"
  and now lists every per-skill `docs/` sub-doc so the calling agent knows
  what's pullable on demand without flooding context.
- Routing table extended with a "How do I read this finding?" row pointing
  at `rafter/docs/finding-triage.md`, and the existing rows nudge toward
  CLI **and** skill rather than CLI **or** skill.

No code logic changes — this is content in `resources/agents/rafter.md`
that ships verbatim to `<root>/.claude/agents/rafter.md` via
`rafter agent init --with-claude-code`. All 6 Node + 5 Python sub-agent
tests still pass (the `test_subagent_body_references_tier_hierarchy`
assertion is satisfied by the new heading).
feat(rf-q7j): ship rafter as a Claude Code sub-agent
docs: rewrite llms.txt for accuracy + agent comprehension (rf-sext)
feat: add golden file snapshot testing for scan output (rc-yvi)
…rfacing-rf-zfhj

fix(github-action): surface HTTP error body on scan API failures (rf-zfhj)
fix: ship docs/ alongside SKILL.md when installing skills (rf-gh7)
test(node): full agent subcommand coverage (rc-tx7)
…-json, --probe (#88)

Verify is now 10 checks across all 8 supported platforms in both impls,
plus optional runtime probe. Closes rf-cia phase d.

Python parity (3 missing checks ported from Node):
- _check_gemini, _check_cursor, _check_windsurf
- Python verify now matches Node's coverage 1:1.

Continue.dev + Aider coverage (both impls):
- checkContinueDev / _check_continue_dev: walks .continue/config.json
  mcpServers (handles both array and object schemas).
- checkAider / _check_aider: parses .aider.conf.yml, confirms RAFTER.md
  is in `read:` AND on disk (rf-du2o-aware). Falls back gracefully if
  the YAML is unparseable.

--json:
- Stable schema {checks: [{name, status, detail}], summary: {...}}
  with status ∈ {pass, warn, fail}. Schema documented in
  shared-docs/CLI_SPEC.md. Intended for CI consumption.

--probe (rf-65zg core):
- Runtime probe for Claude Code: synthesize a PreToolUse stdin payload
  with a unique-per-run sentinel command (rm -rf /tmp/rafter-probe-<pid>-<ts>),
  invoke `rafter hook pretool`, and assert ~/.rafter/audit.jsonl received
  a command_intercepted entry for the sentinel.
- Catches the rf-luk-style "wrote file but the hook never fires" failure
  mode without needing to drive Claude Code itself.
- Audit-entry shape accepts both entry.action.command (current) and
  entry.command (older audit writers).
- Codex/Cursor/Gemini probes can be added in follow-ups using each
  platform's documented stdin payload.

Drive-by fix:
- Claude Code hook check now substring-matches the hook command, so both
  Node's bare `rafter hook pretool` and Python's absolute-path install
  variant (e.g. /home/u/.local/bin/rafter hook pretool) verify clean.

Test results:
- Python: 39 verify tests (added 17 new) + 14 components + 76 init = 121 green
- Node: 13 agent verify tests (added 4 new), all green
- Live smoke (Node): rafter agent verify --probe --json with Claude Code
  installed produces pass; with Claude Code uninstalled produces warn.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Single canonical document for adding rafter integration to a new agent
CLI / IDE. Closes rf-cia phase d and resolves audit cross-cutting gap #5.

Contents:
- TL;DR 5-question contract (hooks, skills/rules, instruction file, MCP,
  sub-agent) with explicit "if no, document it; don't drop it" guidance.
- File-by-file checklist across both impls (init.ts/agent.py,
  components.ts/agent_components.py, verify.ts, tests, recipes, README,
  CLI_SPEC, audit doc, CHANGELOG).
- Decision tree per integration shape: hook-schema verification before
  install, skill primitive table per platform, AGENTS.md cross-platform
  win, MCP config-path catalogue, sub-agent state-of-the-art (Claude only
  today).
- Dual-impl rule with the lessons from the rf-cia gap reports baked in
  ("Python missing" recurring entry; static-resource files in both trees).
- Verification gate: file-presence tests + a --probe branch for any
  platform with a hook surface (rf-65zg). The probe is the only thing
  that catches rf-luk-style "wrote file but never fires" failures.
- Worked example for a fictional "Cleo" platform showing every file a
  complete PR touches.
- Known exceptions section documents the deviations (OpenClaw category
  mismatch, Aider's read:-only shape, no-hook-surface platforms, Gemini's
  runtime skill registration).

README links it under Documentation. Audit doc cross-cutting gap #5
flipped to resolved.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…p) (#90)

Activity check (rf-0lig acceptance #1): OpenClaw is highly active in 2026
— top GitHub repository, 4000+ ClawHub skills, regular releases through
April 2026. The platform itself is alive and growing.

But the current rafter integration shape — a markdown file dropped at
~/.openclaw/skills/rafter-security.md — doesn't match ClawHub's actual
skill packaging format. The platform doesn't load it as a real skill;
the install is a wrong-shape no-op.

Decision: demote from --all (don't ship a wrong-shape integration to
users who didn't explicitly ask for it). Keep --with-openclaw as
explicit opt-in for users who want the file regardless.

- node/src/commands/agent/init.ts: wantOpenClaw = opts.withOpenclaw only
  (was: opts.withOpenclaw || (opts.all && !opts.local))
- python/rafter_cli/commands/agent.py: same in want_openclaw
- Tests unchanged: no test asserted OpenClaw lands under --all (verified
  by grep). Existing 19 OpenClaw tests cover --with-openclaw, all green.
- Audit doc records the decision.
- Filed rf-zgwj (P2) for the proper ClawHub-skill rebuild that lets us
  put OpenClaw back into --all.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…d (rf-d8s) (#66)

Adds an ignore: section to .rafter.yml so agents can mark known-safe
findings (test fixtures, doc examples, etc) without piping false-positives
through to every scan. Each entry takes paths globs, optional rules
filter, and a free-form reason that surfaces in the JSON output.

Suppressed findings are not silently dropped — when any rule fires, JSON
output is wrapped in {_note, _suppressed, results} so consumers can see
exactly what was hidden and why. Plain array form is preserved when no
suppression occurs, keeping backwards compatibility with existing
parsers. Suppression is now applied at the scan-command boundary, so it
works for both the regex engine and Gitleaks (previously only regex).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…91)

The rafter ≤ 0.7.7 OpenClaw install wrote a single markdown file at
~/.openclaw/skills/rafter-security.md — a path OpenClaw never read at
runtime (rf-0lig identified this as a wrong-shape no-op).

Per docs.openclaw.ai/tools/skills, OpenClaw auto-discovers skills from
<workspace>/skills/<name>/SKILL.md, where the default workspace is
~/.openclaw/workspace/. Rebuild:

- Install path: ~/.openclaw/workspace/skills/rafter-security/SKILL.md
  (directory + canonical SKILL.md filename, not a loose markdown file).
- Frontmatter: added the ClawHub-required top-level fields name,
  description, version. Existing openclaw runtime block kept (the schema
  accepts both top-level `openclaw:` and `metadata.openclaw` aliases).
- Synced Node ↔ Python SKILL.md content (they had drifted). Both now
  ship the same 0.7.7-version frontmatter.
- Detection: ~/.openclaw (the platform root), not ~/.openclaw/skills/
  (which only exists after a previous skill install). Fixes a false
  negative on fresh OpenClaw installs.
- Migration: reinstall strips the legacy
  ~/.openclaw/skills/rafter-security.md (and its empty parent dir).
  Verify warns when only the legacy file is present and prints the
  migration command.
- Re-included in --all (reverting the rf-0lig demote). The new shape is
  what the platform actually consumes.

Tests:
- 5 new Node tests in openclaw-integration.test.ts (canonical-path
  install, ClawHub frontmatter shape, legacy-strip migration, two new
  SkillManager helpers); existing 16 updated; 21/21 green.
- 5 new Python tests across TestInstallOpenClawSkill +
  TestCheckOpenClaw (canonical path, legacy migration, legacy-only
  warning); 128/128 in agent_init+components+verify suites green.
- Live smoke (Node + Python): legacy-only HOME → reinstall strips
  legacy, writes canonical SKILL.md; verify reports
  `Rafter skill installed (v0.7.7)`.

Recipe rewritten with the canonical install command, ClawHub frontmatter
example, and migration explanation.

Closes rf-zgwj. Audit doc OpenClaw row flips to fully-shipped.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Fixes the 13 failing tests in CI Validate Release across 4 files. All
test-only; no production code touched.

- secret-scanning-e2e.test.ts (6 cases) + agent-commands.test.ts (3 cases):
  use parsed.results instead of bare-array indexing. The wrapped
  {_note, scan_mode, triage_applied, results, _suppressed?} shape is
  permanent now (rf-0pch / 927df6a) — tests just hadn't caught up.

- custom-patterns.test.ts (3 cases): add source: ".rafterignore" to the
  asserted Suppression shape. The source field was added in rf-d8s
  (49fabf4) to distinguish .rafterignore vs .rafter.yml suppressions in
  JSON output.

- platform-integration.test.ts (1 case): assert the new ClawHub-shaped
  OpenClaw skill path (~/.openclaw/workspace/skills/rafter-security/SKILL.md)
  introduced in rf-zgwj (b9f40c8).

Independent reviewer confirmed: schema-vs-test direction is correct on
all three causes (intentional changes, stale tests). Python parity
already in place. No production code, no behavior change.

Closes rf-6s9l, rf-b9l8, rf-blvo.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bumps Node + Python in lockstep (validate-release.yml enforces match).

Skipping 0.7.8 because the [Unreleased] block accumulated 7 features
(rf-65zg agent verify, rf-q7j Claude sub-agent, rf-zgwj OpenClaw rebuild,
rf-acz0 Continue, rf-du2o Aider, rf-d8s suppression, rf-svn3 Cursor) plus
the rf-zfhj v1-tag fix and the rf-6s9l/rf-b9l8/rf-blvo test-suite repair —
that's a minor-bump worth of work, not a patch.

Also bumps the rafter-security SKILL.md frontmatter version (Node + Python
resources + recipe) so ClawHub's metadata schema check matches the package
version on install.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Raftersecurity Raftersecurity merged commit d16e154 into prod May 8, 2026
15 of 23 checks passed
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.

2 participants