Scan any repo with SAST/SCA tools and patch the vulnerabilities using your AI assistant's LLM. Works as a slash command in Claude Code, Codex, Cursor, Gemini CLI, Aider, OpenCode, and GitHub Copilot CLI.
Project description
yobitsugi
呼継ぎ — "called-in joinery."
Type /yobitsugi in your AI coding assistant and it scans your repo with industry SAST/SCA tools, then walks you through fixes one at a time using your assistant's own model.
Works in Claude Code, Codex, Cursor, Gemini CLI, Aider, OpenCode, and GitHub Copilot CLI.
/yobitsugi .
That's it. You get a workspace dir:
~/.yobitsugi/<repo>-<timestamp>/
├── findings.json unified, deduplicated list of vulnerabilities ← the cracks
├── scan_report.json per-scanner status (ok / skipped_missing_tool / errored)
├── languages.json detected languages with file counts
└── raw/* original scanner outputs, untouched, for forensic review
Your assistant then reads findings.json, summarises it in chat, proposes a unified diff for each CRITICAL/HIGH finding, asks before applying, and applies the edit with its own native edit tool. There's no separate LLM for yobitsugi — your editor's model does all the talking.
Install
Requires Python 3.11+
pipx install yobitsugi && yobitsugi install
# or: uv tool install yobitsugi && yobitsugi install
# or: pip install yobitsugi && yobitsugi install
# or: uvx yobitsugi <args> (ephemeral, no install)
yobitsugi: command not found? Usepipx install yobitsugioruv tool install yobitsugi— both put the CLI on PATH automatically. With plainpip, add~/.local/bin(Linux) or~/Library/Python/3.x/bin(Mac) to your PATH, or runpython -m yobitsugi.
PowerShell note: Use
yobitsugi scan .not/yobitsugi .outside an assistant chat — the leading slash is a path separator in PowerShell.
Codex note: Add
multi_agent = trueunder[features]in~/.codex/config.toml. Codex uses$yobitsugiinstead of/yobitsugi.
Pick your platform
| Platform | Install command |
|---|---|
| Claude Code | yobitsugi install --platform claude |
| Codex | yobitsugi install --platform codex |
| Cursor | yobitsugi install --platform cursor --scope project |
| Gemini CLI | yobitsugi install --platform gemini |
| Aider | yobitsugi install --platform aider |
| OpenCode | yobitsugi install --platform opencode |
| GitHub Copilot CLI | yobitsugi install --platform copilot |
Bare yobitsugi install auto-detects every assistant on your machine and registers the skill for each. Add --scope project to install into the current repo instead of your home dir. Remove with yobitsugi uninstall --platform <name>. List everything with yobitsugi list-platforms.
What the skill does
When you type /yobitsugi <path>, the host assistant follows a five-step runbook installed as a markdown skill file. It's exactly what a careful security review looks like:
- Announces the plan and asks if you want to proceed. A throwaway scanner venv will be created and deleted at the end of the run — your system Python stays untouched.
- Runs
yobitsugi scan <path> --ephemeral-toolswhich detects languages, runs every matching SAST/SCA scanner, normalises the output tofindings.json, and prints a markdown summary. - Asks if you want fixes. Shows the totals (CRITICAL / HIGH / MEDIUM / LOW) and the markdown table of every finding.
- Walks each finding interactively. For every CRITICAL/HIGH finding: one-paragraph plain-English explanation, proposed unified diff inline, then "Apply this fix?" — yes/no/skip/explain-more. The assistant uses its own model and its own native edit tool. The
yobitsugibinary never edits a file. - Re-scans to confirm. Compares finding ids before and after: any ids gone are fixed, any still present are unresolved, any new ones are regressions the assistant's edits introduced. Flags regressions loudly.
The temp scanner venv is removed in a finally block at the end — on success, failure, or Ctrl-C alike.
What scanners it runs
Auto-detected per language. Missing binaries are skipped, not fatal — most are installed for you automatically when you pass --ephemeral-tools (which is what the slash command uses).
| Language | Scanners |
|---|---|
| Python | bandit, safety, pip-audit, semgrep |
| JavaScript / TypeScript | eslint (security plugins), npm audit, semgrep |
| Go | gosec, govulncheck, semgrep |
| Java | spotbugs (with FindSecBugs), semgrep |
| Ruby | brakeman, bundler-audit, semgrep |
| PHP | phpstan (security), semgrep |
| C / C++ | flawfinder, cppcheck, semgrep |
| Rust | cargo-audit, semgrep |
| Shell | shellcheck, semgrep |
| Cross-language | semgrep, trufflehog (secrets) |
What ships in the wheel
pip install yobitsugi pulls these onto your PATH automatically — no extra step:
| Scanner | How it's bundled |
|---|---|
bandit |
direct dep |
safety |
direct dep (pinned >=3.0,<3.2 to dodge the safety ↔ typer ↔ click 8.2 import crash; click<8.2 is also pinned alongside) |
pip-audit |
direct dep |
semgrep |
direct dep |
flawfinder |
direct dep |
shellcheck |
direct dep via shellcheck-py — the Haskell binary is wrapped in a Python wheel, so pip puts a real shellcheck executable on PATH |
trufflehog |
fetched on demand when you pass --ephemeral-tools: the Go binary is downloaded from the official GitHub release into the same temp dir as the scanner venv, and is removed at the end of the run. No brew install step. See "Trufflehog" below for the persistent variant. |
eslint + eslint-plugin-security |
npm installed on demand when you pass --ephemeral-tools and the repo has JS/TS code. Drops into <tmp>/node/node_modules/.bin/ next to the venv; cleaned up at the end of the run. Requires npm on the host (Node.js — yobitsugi can't bootstrap that). A bundled fallback eslint config is used when your repo has none of its own. See "ESLint" below. |
Non-Python scanners that aren't ours to bundle — eslint, npm audit, gosec, govulncheck, brakeman, bundler-audit, phpstan, cppcheck, cargo-audit, spotbugs — need their own runtime (Node / Go / Ruby / etc.). yobitsugi list-scanners shows the install hint for each.
Adding a new scanner is one YAML block in yobitsugi/data/scanners.yaml — no code change needed unless the output format is exotic.
Parallel scanning
yobitsugi scan runs scanners on a thread pool so bandit, semgrep, pip-audit, trufflehog, shellcheck etc. all execute concurrently. Each scanner is a subprocess waiting on its own child process — threads are the right shape (no GIL contention) and the wall-clock time is max(scanner_times), not sum.
yobitsugi scan ./my-project --concurrency 8 # cap at 8 in-flight (default: 6)
yobitsugi scan ./my-project --sequential # force one-at-a-time (debugging)
YOBITSUGI_SCAN_CONCURRENCY=4 yobitsugi scan ./my-project # env-var equivalent
Output streams as scanners finish:
[scan] concurrency: 6 parallel workers
→ bandit dispatched
→ semgrep dispatched
→ pip-audit dispatched
→ trufflehog dispatched
✓ bandit ok 0.2s
✓ trufflehog ok 3.1s
✓ pip-audit ok 25.4s
✓ semgrep ok 31.7s
[scan] all scanners done in 31.7s
ESLint (JS / TypeScript)
ESLint is a Node.js tool — no PyPI wrapper exists, so it can't go inside the Python venv. Same workaround as trufflehog: when yobitsugi scan --ephemeral-tools detects JavaScript or TypeScript in the repo, it npm installs eslint@^8.57 eslint-plugin-security@^3 @typescript-eslint/parser@^7 @typescript-eslint/eslint-plugin@^7 into the temp tools dir (next to the Python venv) and adds the resulting node_modules/.bin/ to PATH for the scan. The whole thing is cleaned up in the finally block.
The only requirement on the host is npm. If it's not on PATH, yobitsugi prints an install hint (brew install node / apt-get install nodejs npm / nodejs.org) and the scan continues with eslint marked skipped_missing_tool. Node itself isn't auto-installable — it's a 100MB+ runtime that needs an OS-level package manager.
If your repo already has an eslint config (.eslintrc.*, eslint.config.{js,mjs,cjs}, or an eslintConfig block in package.json), eslint uses it. If not, yobitsugi falls back to the bundled config at yobitsugi/data/eslint-security.eslintrc.json — eslint v8 schema, loads eslint-plugin-security/recommended-legacy, with a TypeScript override that pulls in @typescript-eslint/parser. That guarantees a vanilla JS/TS repo still produces findings instead of silently reporting "no issues".
For a persistent install (CI image, offline runners), use bootstrap:
yobitsugi bootstrap eslint # npm install -g eslint + plugins
yobitsugi bootstrap --dry-run eslint # preview the command
Or pass --no-fetch-native to opt out of the auto-install at scan time (e.g. if you've already done bootstrap and want a faster startup).
Trufflehog (persistent install)
The ephemeral fetch in --ephemeral-tools is enough for one-off runs and CI. If you'd rather have trufflehog stick around between runs (faster startup, works offline), use bootstrap:
yobitsugi bootstrap # auto-picks brew / apt / dnf / yum
yobitsugi bootstrap --dry-run # print the install command without running it
yobitsugi bootstrap trufflehog # be explicit about what to install
bootstrap runs the system package manager that's actually on PATH (in order: brew, apt-get, dnf, yum). On platforms without any of those, it prints the install URL.
If trufflehog is already on PATH (either via bootstrap or your own install), pass --no-fetch-native to yobitsugi scan to skip the download:
yobitsugi scan ./my-project --ephemeral-tools --no-fetch-native
What's in the summary
yobitsugi summary <workspace> --format markdown (which the skill runs for you) prints five tables:
- Run totals — findings count, scanners ok / skipped / errored.
- Findings by severity — counts per CRITICAL / HIGH / MEDIUM / LOW.
- Findings — one row per finding: severity, type, scanner, file:line, title.
- Missing scanners — every scanner that was skipped because its binary isn't installed, with the install command or hint.
- What next? — ranked next actions: install missing scanners, hand findings to the assistant for the fix loop, re-scan to validate.
Every finding has a stable id (a hash of tool + file + line + rule_id) so a re-scan computes a clean fixed / still-present / newly-introduced diff against the previous one.
Ephemeral tools mode
--ephemeral-tools is the recommended path for slash-command invocations and CI jobs. With that flag, yobitsugi scan:
- Creates a fresh temp directory and redirects its managed scanner venv there for the duration of the command.
- Detects the repo's languages and installs only the pip scanners the repo actually needs — semgrep won't be pulled into a Bash-only repo, bandit won't be pulled into a Go-only repo.
- Downloads the right trufflehog release binary for your platform into the same temp dir. trufflehog is a Go binary and can't live inside a Python venv, but the temp tools dir is on the same lifecycle —
tempfile.mkdtempon entry,shutil.rmtreein thefinally. Skip with--no-fetch-nativeif you've already got it onPATH(e.g. fromyobitsugi bootstrap). - If JS/TS files were detected,
npm installs eslint + the security and TypeScript plugins into<tmp>/node/node_modules/— same temp dir, same cleanup. Requiresnpmon the host. Falls back to the bundled eslint security config when your repo has none of its own. Skip with--no-fetch-native. - Runs the scan against the throwaway venv — scanners run in parallel via a thread pool (see "Parallel scanning" above).
PATHis auto-prepended so the temp scanners shadow anything on the system. - Deletes the temp directory in a
finallyblock. Your~/.yobitsugi/tools/is never touched.
yobitsugi scan ./services/api --ephemeral-tools
yobitsugi scan ./services/api --ephemeral-tools --no-fetch-native # offline / already-bootstrapped
If you'd rather pay the install cost once and keep scanners around, use yobitsugi install-scanners (pip scanners → ~/.yobitsugi/tools/venv/) and yobitsugi bootstrap (trufflehog → system package manager) instead.
Common commands
/yobitsugi . # inside any supported assistant — the skill drives everything
/yobitsugi . --severity CRITICAL # filter the fix loop the assistant will run
/yobitsugi . --auto # skip per-fix confirmation (assistant still shows each diff)
# Standalone binary usage (CI, headless audits, scripting):
yobitsugi scan ./services/api # scan, write findings.json
yobitsugi scan ./services/api --ephemeral-tools # …with throwaway scanner venv + auto-fetched trufflehog
yobitsugi scan ./services/api --concurrency 8 # parallel scanners, cap 8 in-flight (default 6)
yobitsugi scan ./services/api --sequential # force one-at-a-time (debugging)
yobitsugi scan ./services/api --only bandit semgrep # restrict to specific scanners
yobitsugi scan ./services/api --no-fetch-native # skip the trufflehog download (you have it already)
yobitsugi findings ~/.yobitsugi/<workspace> # pretty-print existing findings
yobitsugi findings <ws> --severity HIGH --json # JSON for piping
yobitsugi summary <ws> --format markdown # the same markdown tables the assistant sees
yobitsugi summary <ws> --format json # structured data for tooling
yobitsugi install # register skill files in every detected AI editor
yobitsugi install --platform claude # only Claude Code
yobitsugi uninstall # remove from all platforms in one shot
yobitsugi list-platforms # show all supported assistants
yobitsugi detect-platforms # only the ones installed on this machine
yobitsugi list-scanners # every scanner + install status
yobitsugi install-scanners # persistent install of pip scanners into ~/.yobitsugi/tools/venv/
yobitsugi install-scanners --all # force reinstall/upgrade all of them
yobitsugi uninstall-scanners # wipe the managed venv
yobitsugi bootstrap # persistent install of native scanners (trufflehog, eslint) via brew/apt/dnf/yum/npm
yobitsugi bootstrap eslint # just eslint (npm install -g)
yobitsugi bootstrap --dry-run # preview the install command without running it
There is no yobitsugi run, no yobitsugi fix, no yobitsugi apply, no yobitsugi rollback, no yobitsugi config. Those used to be CLI subcommands; they're now the host AI assistant's job, driven by the installed skill.
Skipping files
Most scanners walk the tree themselves, and yobitsugi excludes the common environment and build dirs by default (.venv, venv, node_modules, .tox, build, dist, site-packages, __pycache__, .mypy_cache, .pytest_cache, target, vendor, third_party, …) for bandit and semgrep.
For per-project overrides, drop the scanner's own ignore file:
- bandit —
.banditorbandit.yamlin the repo root - semgrep —
.semgrepignore - eslint —
.eslintignore - trufflehog — respects
.gitignoreautomatically (Go binary)
If you need to add a directory to yobitsugi's defaults, edit the command: line in yobitsugi/data/scanners.yaml.
Team setup
The workspace dir at ~/.yobitsugi/<repo>-<ts>/ is local to your run — don't commit it. The audit trail is your chat transcript.
Recommended flow:
- One developer (or CI) runs
/yobitsugi .and triages the findings their assistant proposes. - They commit only the source changes the assistant applied (no workspace dir).
- CI runs
yobitsugi scan . --ephemeral-toolson every PR and fails the build if new CRITICAL/HIGH findings appear (useyobitsugi findings <ws> --severity CRITICAL HIGH --jsonto assert in your pipeline). - When a scanner is missing (
status: "skipped_missing_tool"inscan_report.json), the assistant offers to install it. For CI, install the non-pip ones (shellcheck,trufflehog,gosec, etc.) in the build image and let--ephemeral-toolshandle the pip ones.
Privacy
- Scanner output stays on your machine. The
yobitsugibinary never makes a network call. - Fix generation happens in your AI editor — your model, your API key, your billing. Yobitsugi has no LLM client of its own.
- Untrusted code snippets in
findings.json'scode_snippetfield are marked as data in the skill prompt to mitigate prompt injection from malicious comments or string literals in scanned files. - No telemetry, no usage tracking, no analytics.
Full command reference
yobitsugi scan <path> # detect → run scanners (parallel) → parse to findings.json
yobitsugi scan <path> --ephemeral-tools # …in a throwaway venv that's deleted on exit (auto-fetches trufflehog)
yobitsugi scan <path> --concurrency N # cap parallel scanners (default 6, env: YOBITSUGI_SCAN_CONCURRENCY)
yobitsugi scan <path> --sequential # disable parallelism (debugging)
yobitsugi scan <path> --only bandit semgrep # restrict to specific scanners
yobitsugi scan <path> --no-fetch-native # skip the trufflehog auto-download
yobitsugi scan <path> --out <workspace> # write to a specific dir instead of ~/.yobitsugi/<name>-<ts>/
yobitsugi findings <workspace> # pretty-print
yobitsugi findings <workspace> --severity HIGH CRITICAL
yobitsugi findings <workspace> --type SQL_INJECTION XSS
yobitsugi findings <workspace> --json # raw JSON for piping
yobitsugi summary <workspace> # rich tables (default)
yobitsugi summary <workspace> --format markdown # what the assistant pastes into chat
yobitsugi summary <workspace> --format json # structured data
yobitsugi install # register skill in every detected editor
yobitsugi install --platform <name> # one specific editor
yobitsugi install --scope project # write into ./.<editor>/ instead of ~/.<editor>/
yobitsugi uninstall [--platform <name>] [--scope ...]
yobitsugi list-platforms
yobitsugi detect-platforms
yobitsugi list-scanners
yobitsugi install-scanners # persistent install of missing pip scanners → ~/.yobitsugi/tools/venv/
yobitsugi install-scanners --all # force reinstall/upgrade
yobitsugi uninstall-scanners # wipe ~/.yobitsugi/tools/
yobitsugi bootstrap # persistent install of native scanners (trufflehog via brew/apt/dnf/yum, eslint via npm)
yobitsugi bootstrap trufflehog # just trufflehog
yobitsugi bootstrap eslint # just eslint (npm install -g eslint + plugins)
yobitsugi bootstrap --dry-run # preview the install command
yobitsugi version
The unified Finding schema
Every scanner's output is normalised to this shape so the host assistant sees the same thing regardless of which tool found the bug:
{
"id": "28b33dd29e127dbf",
"tool": "bandit",
"language": "Python",
"file": "/abs/path/to/file.py",
"line": 6,
"end_line": 6,
"rule_id": "B608",
"type": "SQL_INJECTION",
"severity": "HIGH",
"confidence": "HIGH",
"title": "hardcoded_sql_expressions",
"description": "Possible SQL injection vector through string-based query construction.",
"code_snippet": "5 # SQL injection\n6 query = ...\n7 return ...",
"cwe": ["CWE-89"],
"references": ["https://..."],
"remediation_hint": null,
"package": null,
"fixed_version": null
}
type is one of: SQL_INJECTION, XSS, HARDCODED_SECRET, COMMAND_INJECTION, PATH_TRAVERSAL, WEAK_CRYPTO, INSECURE_DESERIALIZATION, SSRF, OPEN_REDIRECT, VULNERABLE_DEPENDENCY, OTHER.
Learn more
- SKILL.md — the runbook the host AI assistant follows when you type
/yobitsugi - ARCHITECTURE.md — the two halves (CLI vs skill), module map, design notes
- CHANGELOG.md — what's new, what was removed
Contributing
Issues, PRs, and new scanner/installer plug-ins are welcome.
- Fork the repo + create a branch.
pip install -e ".[dev]".- Run
ruff check yobitsugi,mypy yobitsugi, andpytestbefore pushing. - Open a PR against
main. CI runs lint + type-check + tests on Python 3.11 / 3.12 / 3.13.
Adding a scanner — one YAML block in yobitsugi/data/scanners.yaml. If the output format is exotic, add a parser to yobitsugi/core/parse.py — see yobitsugi/data/parser_recipes.md for the contract.
Adding an AI assistant — one subclass of Installer in yobitsugi/installers/<name>.py. See installers/claude.py for the simplest case and installers/cursor.py / installers/codex.py for editors that need their own frontmatter format.
See ARCHITECTURE.md for module responsibilities and design notes.
License
yobitsugi is distributed under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yobitsugi-0.1.8.tar.gz.
File metadata
- Download URL: yobitsugi-0.1.8.tar.gz
- Upload date:
- Size: 70.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae08b06b78623322a9c4bc9c86950d3a04014adc39cc8804e04c8862675c079d
|
|
| MD5 |
c3b674ee91a480444b16132c9ed29c93
|
|
| BLAKE2b-256 |
7819bec4371846fc31f42f6253200272c912bb024d598aa4e958a8ba65e5947b
|
File details
Details for the file yobitsugi-0.1.8-py3-none-any.whl.
File metadata
- Download URL: yobitsugi-0.1.8-py3-none-any.whl
- Upload date:
- Size: 70.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b50e9beb364906d0c29cce091ce8db942a8ce07af1dd168a21d7e4ab9e2db4fc
|
|
| MD5 |
758d6c6dbd22ca7ca69e6b507657834c
|
|
| BLAKE2b-256 |
2a922100d47bf3cbdd7826b993a424899b274acac891a6b74159d841d0b68afb
|