ai-patchlab
CLAUDE.md1 starsChanged 30 days agoMITView on GitHub
Ce fichier est lu automatiquement par Claude Code au début de chaque session. Il définit les règles, standards et contexte du projet.
- Reads credentials
- Installs packages
In this repository25 other files it gives its agents.
- AGENTS.mdAGENTS.md
- audit-projectSkill
- cleanupSkill
- create-skillSkill
- dailySkill
- dependency-checkSkill
- documentSkill
- execute-prpSkill
- ez-project-workflowSkill
- fix-issueSkill
- generate-prpSkill
- housekeepingSkill
- kickoffSkill
- monitor-setupSkill
- nextSkill
- performanceSkill
- pipelineSkill
- refactorSkill
- retrospectiveSkill
- review-codeSkill
- rollbackSkill
- security-scanSkill
- statusSkill
- tddSkill
- upgrade-statusSkill
The file
Show its rules and text
We split this CLAUDE.md into the rules it gives an agent
45 rules. About 0 are common, 31 are distinctive, and 14 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈31
Distinctive · estimate
This author's own choices. Worth a look.
14
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 11
Always read ROADMAP.md at the start of a new conversation to understand the current state
- Distinctive: line 12
Check DECISIONS.md for past architectural decisions and context
- Distinctive: line 13
Check PRPs/ folder for any existing implementation plans
- Distinctive: line 14
Read examples/ before implementing new features to match existing patterns
- Distinctive: line 15
Check INITIAL.md for the current feature requirements
- Very specific: line 16
Run /status at the start of a session for a quick project snapshot
- Very specific: line 99
Use async/await for all I/O when async is appropriate (the scanner core is synchronous on purpose because it shells out via subprocess.run.
- Very specific: line 102
Use pathlib.Path for file paths
- Very specific: line 103
Use pydantic models for data validation (config).
- Very specific: line 104
Always run external scanner subprocesses with shell=False and an explicit argv list
- Distinctive: line 110
Keep utils genuinely generic
- Very specific: line 126
Every suppression step in run_scan records what it removed via summarize_removed(before, after, reason_code) — a narrower report must never …
- Very specific: line 175
Use the Task tool with the matching subagent_type to delegate a focused job:
- Very specific: line 249
Always include id (AUTO_INCREMENT), created_at, updated_at
- Distinctive: line 252
Use parameterized queries — NEVER string concatenation for SQL
- Distinctive: line 261
ALWAYS wrap external calls (API, scraping, DB) in try/except
- Distinctive: line 264
NEVER silently suppress errors
- Distinctive: line 265
Use custom exception classes for domain-specific errors
- Distinctive: line 272
Test critical calculation functions thoroughly
- Very specific: line 273
Use pytest-asyncio for async tests
- Distinctive: line 278
Create a branch for each feature
- Distinctive: line 281
Never commit directly to main
- Distinctive: line 282
Run tests before committing
- Distinctive: line 285
Always check ROADMAP.md first
- Very specific: line 287
Add timestamp (YYYY/MM/DD) when status changes
- Distinctive: line 288
Update ROADMAP.md after completing each task
- Very specific: line 291
All architectural decisions are logged in DECISIONS.md
- Distinctive: line 292
Before making a structural decision, check DECISIONS.md for precedent
- Very specific: line 293
Use the architect agent (/architect or Task tool) for complex decisions
- Very specific: line 316
All external scanners are optional — if a tool is missing, the adapter emits a normalized info finding (e.g.
- Distinctive: line 325
Keep things SIMPLE — MVP first, iterate later
- Distinctive: line 326
Read examples in examples/ before implementing anything new
- Distinctive: line 328
Do NOT over-engineer — no premature abstractions
- Distinctive: line 329
When in doubt, ask before assuming
- Distinctive: line 335
When something is painful in an implementation, fix the underlying AI layer — not just the code.
- Distinctive: line 337
Rule: never review the implementer's work in the same context window that produced it.
- Distinctive: line 347
After completing any feature or fix, ALWAYS update ROADMAP.md (mark items done with date)
- Distinctive: line 348
After any structural change (new files, new folders, new dependencies), update the relevant sections of THIS file (CLAUDE.md)
- Distinctive: line 349
If AGENTS.md exists, update the matching sections there too so Codex and Claude stay aligned
- Very specific: line 350
After completing a PRP, move it to PRPs/done/ with date prefix
- Distinctive: line 351
After creating temporary/scratch files for debugging, DELETE them when done
- Distinctive: line 352
If CLAUDE.md.proposed exists and changes have been applied, DELETE it
- Distinctive: line 353
If AGENTS.md.proposed exists and changes have been applied, DELETE it
- Distinctive: line 354
When committing, include doc updates in the same commit or a separate "docs:" commit immediately after
- Distinctive: line 355
NEVER leave documentation out of sync with code
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Project: ai-patchlab
Ce fichier est lu automatiquement par Claude Code au début de chaque session. Il définit les règles, standards et contexte du projet.
About
AI PatchLab is an AI-assisted security remediation toolkit. The MVP focuses on a local Python scanner that accepts a repository path, normalizes security findings, and writes JSON plus Markdown reports for remediation planning.
This project can optionally include a parallel Codex/OpenAI runtime via AGENTS.md and .agents/skills/.
Project Awareness & Context
- Always read ROADMAP.md at the start of a new conversation to understand the current state
- Check DECISIONS.md for past architectural decisions and context
- Check PRPs/ folder for any existing implementation plans
- Read examples/ before implementing new features to match existing patterns
- Check INITIAL.md for the current feature requirements
- Run
/statusat the start of a session for a quick project snapshot
Tech Stack
- Python 3.11+
- Local CLI scanner foundation (Semgrep, Gitleaks, Trivy, pip-audit, opt-in local AI review)
- JSON and Markdown report generation
- Data stack selected for repository analysis workflows
- MySQL 8.0 (aiomysql for async, available but not required in v0.1)
- Playwright (optional extra
[scraping], si scraping requis plus tard) - Discord webhooks (alertes optionnelles plus tard)
- Loguru (logging)
- pytest + pytest-asyncio + pytest-mock (testing)
- ruff + black (linting/formatting)
- httpx (async HTTP client)
- pydantic + pydantic-settings + python-dotenv (validation + config)
- Standard-library
subprocessfor external scanner runners (no remote endpoints)
Key Directories
fingerprint/— Web template fingerprinting (v0.1, experimental): seed loader, extractors, indexer CLI, web probe, matchers, scoring, JSON+MD match report. Local-first, single-target probe, probabilistic signal only.fingerprint/models.py— Frozen dataclasses (RepoFingerprint,AssetFingerprint,HtmlSignature,MatchResult,MatchSignal) and the canonicalband_for_score()helper used by writer and validatorfingerprint/config.py—FingerprintConfig(pydantic-settings,AI_PATCHLAB_FINGERPRINT_env prefix): bytes cap per asset, asset cap per target, timeouts, user agentfingerprint/git_seeds.py— Loader + validator forfingerprint/seeds/repos.json+ deterministicslug_from_repo_urlfingerprint/seeds/repos.json— Curated seed list (committed; expand via PR only)fingerprint/extractors/— Pure functions over a cloned repo:favicon.py,static_assets.py,html_signatures.pyfingerprint/repo_index.py— Clones a seed viascanner.git_source.cloned_repo, runs extractors, writesfingerprint/db/<slug>.jsonfingerprint/run_index.py— CLI:.venv/Scripts/python.exe fingerprint/run_index.py --rebuild/--repo-url <url>fingerprint/web_probe.py— Synchttpx.Clientprobe with robots.txt respect, scheme allowlist, hard bytes/asset caps; optionaltransport=param for testsfingerprint/matchers/—asset_hash.py,html_regex.py; registered infingerprint/matchers/__init__.py:MATCHERSfingerprint/scoring.py— Bounded weighted score (WEIGHT_VALUES) — single source of truth, tested directlyfingerprint/run_match.py— CLI:.venv/Scripts/python.exe fingerprint/run_match.py --target <url>→ writesreports/fingerprint/match_<host>_<UTC>.json+.md; always exits 0fingerprint/report.py— JSON + Markdown writer for match results; disclaimer block is mandatoryfingerprint/db/— Per-repo fingerprint JSONs (gitignored except.gitkeep; regenerable from seeds)reports/fingerprint/— Generated match reportsscanner/— Scanner CLI, finding model, recommendation enrichment, report generation, scanner registryscanner/run_scan.py— CLI entry point (.venv/Scripts/python.exe scanner/run_scan.py --repo <path>or--from-git-url <url>)scanner/git_source.py— Shallow-clone a public git URL into a temp directory via thecloned_repocontext manager; cleanup-on-exit,shell=False, no remote API callsscanner/paths.py—rebase_finding_paths(findings, repo_root)rewrites each finding'sfile(andidwhen it embeds the same path) to a repo-relative POSIX path so reports survive temp-dir cleanupscanner/ignore.py—apply_ignore(findings, patterns)+load_ignore_patterns(path)provide.gitignore-style path suppression of findings (used by the--ignore-fileCLI flag). Empty-file findings are never suppressed.DEFAULT_SAMPLE_IGNORE_PATTERNSholds the demo/sample/example subtree patterns opted into via the--ignore-samplesflagscanner/models.py— NormalizedFindingdataclass + severity/confidence enums +FINDING_FIELDS;Finding.is_metaflags scanner-infrastructure findings that--min-severitymust never dropscanner/recommendations.py— Deterministic keyword-based recommendation enrichmentscanner/coverage.py— Per-scanner coverage derived from meta findings (ToolCoverage,build_coverage,EXPECTED_TOOLS,is_complete); feedsreports/coverage.jsonand the report's Scan Coverage blockscanner/verdict_corpus.py— Corpus validation and aggregation (validate_payloadreports every problem in one pass,load_corpusreadscorpus/verdicts/)scanner/run_verdict_check.py— CLI:--check <verdicts.json>(exit 2 on any problem, required by/dailyPhase 4) and--summary(count the whole corpus)scanner/run_orphan_check.py— CLI: finds/dailyruns that died without recording themselves (aruns_recententry leftin-progressby an earlier day, orreports/<slug>/output newer thanlast_runwith no post and no run record). Exit 2 on any orphan, required by/dailyPhase 0;--write-pausecreates.daily-paused,--acknowledgecloses the orphans after reviewcorpus/verdicts/— Committed dismissal corpus, one file per scan; the durable half, sincereports/is gitignoredscanner/verdicts.py— Dismissal records (VerdictRecord,summarize_removed,count_by_reason,load_records) with closedSCANNER_REASON_CODES/CURATION_REASON_CODESvocabularies; feedsreports/verdicts.jsonand the report's Dismissed sectionscanner/report_markdown.py— Markdown rendering, split out ofreport.pyto stay under the 300-line ceiling (write_markdown_reportis still re-exported fromscanner.report)scanner/confidence.py— CentralizedFinding.confidencerules (one function per scanner +confidence_for_meta_findingfor sharednot-installed/scan-error/ etc.)scanner/report.py— JSON + Markdown report writers (severity-grouped, "Top Findings" highlight block, patch suggestion blocks); also exposesfilter_by_min_severityandselect_top_findingsscanner/config.py— Disabled-by-default AI review configuration loaded from environment /.env(AI_PATCHLAB_*)scanner/remediation/— Deterministic patch suggestion engine (patch_suggestions.py) for known vulnerability patternsscanner/scanners/— Scanner adapters:semgrep.py,gitleaks.py,trivy.py,dependency_scan.py,ai_review.py, pluscommon.pyplaceholder helper and__init__.pyregistry (SCANNERS)scanner/tools/— External scanner process runners:semgrep_runner.py,gitleaks_runner.py,trivy_runner.py,pip_audit_runner.py,ai_review_runner.pyreports/— Generated security reports (security_report.json,security_report.md)reports/verdicts.json— Dismissal corpus: one row per rule family removed, with a reason code and a countreports/coverage.json— Per-scanner coverage manifest written on every scan (what each tool actually examined, plus acompleteflag)reports/raw/— Raw scanner JSON outputs (semgrep.json,gitleaks.json,trivy.json,pip-audit.json,ai-review.jsonwhen enabled)src/— Legacy scaffold entry point (kept for template parity)src/main.py— Legacy point d'entrée (python -m src.main) — currently a loguru-wired async stub with TODOs.github/workflows/ci.yml— CI: ruff + black + pytest on Python 3.11 and 3.13 (the 3.13 leg catches stdlib removals such as PEP 594 droppingcgi)reports/disclosures/— Drafted private disclosure emails awaiting a manual send (gitignored with the rest ofreports/)tests/— Tests pytest (test_scanner_foundation.py,test_semgrep_scanner.py,test_gitleaks_scanner.py,test_trivy_scanner.py,test_dependency_scan.py,test_ai_review.py,test_patch_suggestions.py,test_recommendations.py,test_meta_findings.py,test_confidence_field_rules.py,test_coverage.py,test_verdicts.py,test_verdict_corpus.py,test_orphan_check.py)tests/conftest.py— Fixtures partagées (mock_db,mock_http_client,mock_discord,test_config, sessionevent_loop)examples/— Code de référence — LIRE AVANT D'IMPLÉMENTER (api_client, config, discord_alert, mysql, playwright_scraper, scheduler, service)PRPs/— Product Requirements Prompts (actifs)PRPs/done/— PRPs complétés (archive —2026-05-12-trivy-integration.md,20260513-phase-3-ai-review-behavior.md)PRPs/templates/— Templates PRP réutilisables (prp_base.md)docs/— GitHub Pages site (Jekyll, themecayman):_config.yml,index.md(landing: intro, six featured scans, compact 83-row table),scan-log.md(full prose archive of every scan entry),fixed.md+clean.md(curated collections generated from the index table — never from keyword inference),scans/(per-scan write-ups), top-level pages (work-with-me.mdconversion funnel,daybreak-and-local-first.mdpositioning essay vs OpenAI Daybreak),templates/scan-post.md(template, excluded from publish)logs/— Log files (gitignored except .gitkeep)AGENTS.md— Codex/OpenAI runtime instructions (kept in parity with this file).agents/skills/— Codex skills for repeatable workflows (one folder per skill — kickoff, generate-prp, execute-prp, fix-issue, pipeline, tdd, review-code, refactor, retrospective, next, upgrade-status, status, audit-project, housekeeping, cleanup, security-scan, dependency-check, performance, document, monitor-setup, rollback, create-skill, daily, ez-project-workflow).claude/commands/— Claude slash command definitions (one Markdown file per command).claude/agents/— Claude subagent definitions (architect, code-reviewer, debugger, dependency-manager, documentation-writer, integration-tester, orchestrator, performance-profiler, refactorer, release-manager, researcher, security-auditor, smart-context, tester).claude/pipelines/— Reusable pipeline YAML definitions (feature.yml,bugfix.yml,security.yml,release.yml)
Coding Standards
Python
- Type hints REQUIRED on all functions
- Docstrings Google-style on public functions
- Files max 300 lines — split if bigger (note:
scanner/remediation/patch_suggestions.pyis ~280 lines and approaching the limit) - Variable/function names in English
- Comments OK in French
- Use
async/awaitfor all I/O when async is appropriate (the scanner core is synchronous on purpose because it shells out viasubprocess.run;src/main.pyand DB code use async) - Logging with
loguru— never use print() in production code (note:scanner/run_scan.pyusesprint()only to emit CLI report paths; this is intentional for the local CLI surface) - Config via
.envfiles /AI_PATCHLAB_*env vars — never hardcode secrets (seeexamples/config_pattern.pyandscanner/config.py) - Use
pathlib.Pathfor file paths - Use
pydanticmodels for data validation (config); use@dataclass(frozen=True)for internal normalized records (e.g.Finding) - Always run external scanner subprocesses with
shell=Falseand an explicit argv list
File Structure
- One class per file for major components
- Group related functions in modules
__init__.pyshould only contain imports (thescanner/scanners/__init__.pyregistry tupleSCANNERSis the canonical pattern for scanner registration)- Keep utils genuinely generic
Naming
- Files:
snake_case.py - Classes:
PascalCase - Functions/variables:
snake_case - Constants:
UPPER_SNAKE_CASE - Private: prefix with
_
Scanner adapter contract
- Each scanner in
scanner/scanners/exposes onescan_<name>(repo_path: Path, reports_dir: Path) -> list[Finding]function and is registered inscanner/scanners/__init__.py:SCANNERS - Scanners must never raise on a missing or failing external tool — emit a normalized
infofinding instead so the report still completes - Each adapter pipes its findings through
apply_patch_suggestions(enrich_findings(...))before returning - Each external tool runner lives in
scanner/tools/<tool>_runner.py, returns a frozen*Resultdataclass, writes the raw JSON toreports/raw/<tool>.json, and usessubprocess.run(..., shell=False, check=False)with captured stdout/stderr - New scanners must follow the same registry + runner split — do not call subprocesses directly from
scanner/scanners/* - Any finding built with
confidence_for_meta_finding(...)must also setis_meta=Trueso--min-severitycannot drop it - Every suppression step in
run_scanrecords what it removed viasummarize_removed(before, after, reason_code)— a narrower report must never shrink its own numbers silently (ADR-016) reason_codevalues are a closed vocabulary inscanner/verdicts.py; add a code to the module rather than inventing one at a call site, or the corpus stops being countable- Curation rows are hand-written JSON, so the dataclass never runs on them —
/dailyPhase 4 MUST get exit 0 fromscanner/run_verdict_check.py --checkbefore publishing (ADR-017).ruleis required on every row;verdicttakes one of five values and the sentence goes indetail confirmed-realis first-party only; an upstream dependency merely behind a fixed version isdependency-currency- Coverage is derived from the raw
collect_findingsoutput beforeapply_ignore(scanner/run_scan.py) —--ignore-filedoes not exempt meta findings, so deriving it later would let a path pattern hide the fact that a tool never ran - Adding a scanner to
SCANNERSrequires adding itsFinding.toolvalue toscanner/coverage.py:EXPECTED_TOOLS;tests/test_coverage.py::TestRegistryDriftfails until you do Finding.confidencevalues come fromscanner/confidence.py— never inlineconfidence="high"/"medium"/"low"in a scanner adapter; add or reuse a rule function instead
Fingerprint adapter contract
- Extractors in
fingerprint/extractors/are pure functions over a cloned repo path (and the activeFingerprintConfigwhen bytes caps matter). They never call subprocess, never reach the network, and never raise on a missing file — they returnNoneor an empty tuple. - Matchers in
fingerprint/matchers/take a(RepoFingerprint, TargetSnapshot)pair and returnlist[MatchSignal]. They are registered infingerprint/matchers/__init__.py:MATCHERS. A mismatch is the empty list, not an exception. - The indexer (
fingerprint/repo_index.py:index_seed) is the only place that performs a git clone in this module. It clones throughscanner.git_source.cloned_repo— never re-implement cloning. - The web probe (
fingerprint/web_probe.py:fetch_target) is the only place that makes outbound HTTP requests. Scheme allowlist ishttp/httpsonly;robots.txtis honoured before any other fetch; bytes per asset and total assets per target are hard-capped. - The match CLI (
fingerprint/run_match.py) always exits 0 (partial-result discipline). An empty DB, an unreachable target, a bad scheme, and a robots disallow all produce a valid JSON + Markdown report with the appropriatenotesvalue. - The Markdown report ALWAYS includes the disclaimer (
fingerprint/report.py:DISCLAIMER). Tests assert the disclaimer is present even for empty result sets, and that attribution words ("confirmed", "proven", "stolen", "copied") never appear. - Score banding goes through
band_for_score()infingerprint/models.py— single source of truth for both the validator (MatchResult.__post_init__) and the writer. - Seed list (
fingerprint/seeds/repos.json) is curated and committed. Adding a new entry is a human PR — never auto-discover repos via the GitHub API.
Slash Commands (Claude Code)
/kickoff — Interview interactive → génère INITIAL.md
/generate-prp FILE — Recherche + génère un PRP d'implémentation
/execute-prp FILE — Exécute un PRP (implémente la feature)
/review-code — Code review automatisée
/status — Snapshot rapide de l'état du projet
/next — Suggère les 1-3 prochaines actions selon l'état actuel du projet
/upgrade-status — Compare le projet au template courant; liste les features manquantes
/audit-project — Audit du CLAUDE.md
/cleanup — Analyse de dead code
/housekeeping — Mise à jour docs post-implémentation
/rollback — Rollback sécuritaire des changements
/retrospective [PRP] — Rétrospective: vide=sprint 2 semaines, "last" ou nom de PRP=self-healing per-PRP en contexte frais
/create-skill DESC — Génère un nouveau skill (command + agent) à partir d'une description
/upgrade-to-project — Upgrade MVP vers Project mode (orchestrator + extended phases)
/security-scan [PATH] — Full security audit: secrets, deps vulnérables, OWASP patterns
/refactor [PATH] — Analyse code smells + complexité, refactoring ciblé avec validation
/fix-issue DESC — End-to-end: diagnose -> fix -> test -> review -> commit
/idea-to-pr DESC — End-to-end: idea -> research -> design -> implement -> test -> review -> PR
/pipeline NAME [DESC] — Execute un pipeline (feature, bugfix, security, release, ou custom)
/dependency-check — Audit dependances: vulnerabilites, updates, compatibilite
/do DESC — Smart router (file: `smart-router.md`): décris ce que tu veux → route vers la bonne action
/document [SCOPE] — Auto-génère la documentation (api, data, architecture, modules, all)
/performance [PATH] — Profile le code, identifie bottlenecks et optimisations
/monitor-setup [TYPE] — Configure health checks, alerting, uptime (health, alerts, uptime, all)
/tdd DESC — Implémentation Red-Green-Refactor stricte (Iron Law: pas de code sans test failing observé)
/daily [MODE] — Pipeline autonome quotidien scan→curation→post→issue→PR (MODE: vide=autonome, --dry-run, --status-only). Garde-fous: 1 scan/jour, quality-gate sur dépôt d'issue, détection strict-norm, kill switch `.daily-paused`, interrupted-run guard (`scanner/run_orphan_check.py`)Claude Subagents (.claude/agents/)
Use the Task tool with the matching subagent_type to delegate a focused job:
architect— high-impact design decisions (output an ADR)code-reviewer— diff-level reviewdebugger— failure reproduction and root-causedependency-manager— dependency upgrades and auditsdocumentation-writer— generate or refresh docsintegration-tester— end-to-end / integration test designorchestrator— multi-phase Project-mode workflowsperformance-profiler— profiling and hot-path analysisrefactorer— code-smell and refactor planningrelease-manager— release checklist executionresearcher— codebase / external researchsecurity-auditor— security review (used by/security-scan)smart-context— keeps this file aligned with reality (used by/audit-project)tester— unit test design and execution
Codex Skills (.agents/skills/)
Mirror of slash commands for the Codex runtime: kickoff, generate-prp, execute-prp, fix-issue, pipeline, tdd, review-code, refactor, retrospective, next, upgrade-status, status, audit-project, housekeeping, cleanup, security-scan, dependency-check, performance, document, monitor-setup, rollback, create-skill, daily, plus ez-project-workflow (operating rules). AGENTS.md lists which Claude commands intentionally have no Codex mirror (/do, /idea-to-pr, /upgrade-to-project).
Pipelines (.claude/pipelines/)
feature.yml— feature deliverybugfix.yml— defect triage and fixsecurity.yml— full security audit pipelinerelease.yml— release checklist
Common Commands
# Dev
.venv/Scripts/python.exe scanner/run_scan.py --repo "C:\path\to\repo" # Run scanner foundation
.venv/Scripts/python.exe scanner/run_scan.py --repo "." --reports-dir reports # Self-scan
python -m src.main # Legacy entry point
.venv/Scripts/python.exe -m pytest tests/ -v # Run all tests
.venv/Scripts/python.exe -m pytest tests/ -v -k "test_name" # Run specific test
# Lint & Format
.venv/Scripts/ruff.exe check scanner src/ tests/ fingerprint/ # Lint
.venv/Scripts/ruff.exe check scanner src/ tests/ fingerprint/ --fix # Auto-fix lint issues
.venv/Scripts/python.exe -m black scanner src/ tests/ fingerprint/ # Format
# Web template fingerprinting (experimental)
.venv/Scripts/python.exe fingerprint/run_index.py --rebuild # Rebuild local DB from seed list (real git clones)
.venv/Scripts/python.exe fingerprint/run_match.py --target https://example.com # Probe a single live URL against the local DB
# Setup (nouveau projet)
python -m venv .venv && source .venv/bin/activate # REQUIRED - never run off the global interpreter
pip install -e ".[dev]" # Install deps from pyproject.toml
pip install -e ".[scraping]" # Optional Playwright extra
cp .env.example .env # Configure environment
# External scanners (install separately, must be on PATH)
semgrep --version
gitleaks version
trivy --version
.venv/Scripts/python.exe -m pip install pip-audit && pip-audit --version
# Optional AI review (disabled by default — see scanner/config.py)
$env:AI_PATCHLAB_AI_REVIEW_ENABLED = "true"
$env:AI_PATCHLAB_AI_REVIEW_PROVIDER = "local_command"
$env:AI_PATCHLAB_AI_REVIEW_COMMAND = "C:\tools\ai-review-wrapper.cmd"
# Database
# Schema in docs/schema.sql (not yet created — `docs/` is empty)MCP Servers
- memory — Persistance Claude Code entre sessions
- mysql — Accès direct à la DB via
@bytebase/dbhub(configurerMYSQL_DSNdans.env)- Utilise la variable
MYSQL_DSNau format:mysql://user:password@host:port/database - cPanel:
mysql://cpaneluser_dbuser:password@sql.yourhost.com:3306/cpaneluser_dbname - Requiert: IP whitelistée dans cPanel > Remote MySQL
- Premier lancement:
npx @bytebase/dbhub@latest --helppour pré-cacher le package
- Utilise la variable
Database Conventions
- MySQL tables in
snake_case - Always include
id(AUTO_INCREMENT),created_at,updated_at - Indexes on frequently queried columns
- Schema migrations: append new SQL to
docs/schema.sqlwith date comment - Use parameterized queries — NEVER string concatenation for SQL
- Connection pooling with aiomysql
- Migration format in
docs/schema.sql:-- Migration: YYYY-MM-DD — Description ALTER TABLE ... ;
Error Handling
- ALWAYS wrap external calls (API, scraping, DB) in try/except
- Log errors with full context using loguru
- Retry logic with exponential backoff for network calls (see
examples/api_client_pattern.py) - NEVER silently suppress errors
- Use custom exception classes for domain-specific errors
- Scanner runners catch
OSErrorandsubprocess.TimeoutExpired, write a safe empty raw JSON, and return a structured*Resultinstead of propagating
Testing
- pytest for all tests (
pytest-asynciomode isauto, seepyproject.toml) - Fixtures in
tests/conftest.py(DB mock, HTTP mock, Discord mock, test config, session event loop) - Mock external calls (API, DB, subprocess) in unit tests
- Test critical calculation functions thoroughly
- Use
pytest-asynciofor async tests - Markers available:
@pytest.mark.slow,@pytest.mark.integration - Each scanner adapter has a dedicated test module under
tests/test_<scanner>.py
Git Workflow
- Create a branch for each feature
- Descriptive commit messages in English
- Format:
type: description(feat, fix, refactor, docs, test) - Never commit directly to main
- Run tests before committing
Roadmap Management
- Always check ROADMAP.md first
- Progression:
[ ]Todo →[-]In Progress 🏗️ →[x]Done ✅ - Add timestamp (YYYY/MM/DD) when status changes
- Update ROADMAP.md after completing each task
Architecture Decisions
- All architectural decisions are logged in
DECISIONS.md - Before making a structural decision, check DECISIONS.md for precedent
- Use the architect agent (
/architector Task tool) for complex decisions - Format: ADR (Architecture Decision Record) — date, decision, context, consequences
- Current ADRs of record: ADR-001 scaffold, ADR-002 data stack, ADR-003 placeholder adapters, ADR-004 Gitleaks, ADR-005 Semgrep, ADR-006 recommendation enrichment, ADR-007 patch suggestions, ADR-008 Trivy, ADR-009 pip-audit, ADR-010 disabled-by-default AI review boundary, ADR-011 centralized scanner confidence rules, ADR-012 probabilistic web template fingerprinting boundary, ADR-013 meta findings exempt from severity filtering, ADR-014 field-derived confidence tiers, ADR-015 coverage is a report artifact, ADR-016 dismissals recorded as counted rule families, ADR-017 a closed vocabulary needs a closer
Known Gotchas
- Do not tag scan posts by keyword inference. A classifier over post bodies was built and rejected 2026-09-18: validated against 9 posts of known ground truth it gave klavis 6 finding classes where the real finding was dependency CVEs, and got 3 of 9 project families wrong (OpenBiliClaw as "developer tooling", tracecat as "MCP server"). Post bodies discuss false positives and credited defences at length, so matching them tags a clean scan with the class it dismissed. On a site whose whole argument is that pattern-matching produces plausible-but-wrong results, publishing plausible-but-wrong tags is self-refuting. Grouping pages are generated from the curated index table instead — hand-maintained, verified data
- Roughly half of scan targets land on a disclosure channel the pipeline cannot use. Measured 2026-09-18: 14 disclosures went through an autonomous channel (GitHub private vulnerability reporting, or a public issue), 12 needed a human to send an email or a DM. Every pipeline stoppage in the project's history came from the human-gated half — a six-report backlog (25 days, 4 scans lost) and one undeliverable High (33 days, 3 scans lost).
/dailyguardrail 9 now makes channel viability a target-SELECTION criterion, tiered on queue depth, and guardrail 8 definesunreachableas the only way to close a report that no channel can carry. The tiering is deliberate: PVR-enabled repos skew mature and commercially backed, so a permanent preference would bias the series away from the small projects that most need review - A headless
/dailythat dies leaves no trace unless the run recorded itself first. From 2026-09-25 to 2026-10-03 seven runs scanned a repo and then ended in curation on a model safety stop (the log endsAPI Error: ... safeguards flagged this session ... Details: [cyber]), before Phase 6 wrote any state.last_runstayed stale, the one-scan-per-day rule never fired, seven scans were lost and nothing was published; the pipeline was paused on 2026-10-04. The fix is a run record opened at target pick plusscanner/run_orphan_check.pyin Phase 0. The safety stop itself is platform-side: this repo can detect it, not prevent it. The scheduled wrapper lives OUTSIDE the repo (%USERPROFILE%\ai-patchlab-daily\run-daily.ps1, Task Scheduler taskai-patchlab-daily, 09:00) and writes UTF-16 logs tologs\daily_<date>_<time>.logbeside it (read them withencoding='utf-16';catshows spaced-out text). Until 2026-10-13 it always exited 0, so Task Scheduler showed success for dead runs; it now exits 1 when Claude fails and 3 when the run ended with.daily-pausedpresent - Semgrep is a Python program on the shared user-site interpreter, not a standalone binary like gitleaks/trivy. Anything that breaks that interpreter breaks Semgrep too — a pydantic downgrade on 2026-08-20 made
semgrep --versionraise ImportError and every scan would have silently lost 52% of its coverage. The project.venvdoes NOT protect it. Checksemgrep --versionbefore trusting a scan; repair withpython -m pip install --user --upgrade "pydantic>=2.11" "httpx>=0.27" - ALWAYS run through
.venv(.venv/Scripts/python.exeon Windows). The project ran for three months off the shared user-site and on 2026-08-20 an unrelatedpip installdowngraded pydantic to 1.x and httpx to 0.21:scanner,fingerprintand every test stopped importing, while the scan pipeline had passed hours earlier. A global interpreter is a shared mutable dependency - Meta findings (
Finding.is_meta=True) survive--min-severitybut are NOT yet exempt from--ignore-filesuppression - a path pattern can still hide a coverage warning. Any new finding built withconfidence_for_meta_finding(...)must also setis_meta=True; the two always travel together - Semgrep coverage comes from the
errorsarray, neverpaths.skipped. Across the scan seriesskippedhas been empty on every run where rules timed out - including a run where both subprocess-injection rules timed out on the 20k-line file that was the whole API surface.scan_semgrepemitssemgrep-partial-coveragenaming eachrule -> filepair that did not run ai-patchlaband2026-05-12are template placeholders replaced by ez-new-project.ps1 — do not remove from template source files- aiomysql: toujours fermer le pool avec
await db.disconnect()dans le finally - Playwright:
wait_until="networkidle"peut timeout sur les SPA — utiliser"domcontentloaded"si nécessaire - Discord webhooks: rate limit de 30 messages/minute par webhook
- pydantic-settings: les variables .env sont case-insensitive par défaut
- MCP MySQL (dbhub): si le password contient
@,:,/ou%, il faut l'URL-encoder dans le DSN - cPanel MySQL: les noms de DB et users sont préfixés (ex:
cpaneluser_dbname) — ne pas oublier le préfixe - AI review must remain disabled by default and local-first. Never add a default remote provider, default endpoint, default model, or default token variable. Any future remote/paid provider requires explicit configuration and a new ADR.
- Scanner subprocess invocations MUST use
shell=Falseand an explicit argv list —shell=Trueis the exact anti-pattern the patch engine warns about (seescanner/remediation/patch_suggestions.py:SUBPROCESS_SHELL_SUGGESTION) - Semgrep on Windows: when not on
PATH, the runner falls back toPath.home() / AppData/Roaming/Python/Python313/Scripts/semgrep.exe(seescanner/tools/semgrep_runner.py:PIP_USER_SEMGREP_PATH). The Python minor version is hardcoded — if the user installs under a different Python version, the runner will silently skip Semgrep until the constant is updated - Semgrep UTF-8 output (Windows, 2026-06-11 fix): Semgrep writes its
--outputJSON via Python's default text codec, which on Windows is the locale codepage (cp1252). A repo with non-Latin-1 source content (Chinese/Japanese/Korean comments, emoji) crashes Semgrep mid-write withUnicodeEncodeError, leaving a 0-byte report and exit code 2._build_semgrep_envnow forcesPYTHONUTF8=1+PYTHONIOENCODING=utf-8in the child env to prevent this. As defense-in-depth,scan_semgreptreats an empty/0-byte report as asemgrep-scan-errorfinding (not silently zero findings). NOTE: the scan-error finding isinfoseverity, so a run with--min-severity mediumstill filters it from the report — RESOLVED 2026-08-21: scanner-infrastructure findings now carryis_meta=Trueand are exempt from--min-severity - All external scanners are optional — if a tool is missing, the adapter emits a normalized
infofinding (e.g.semgrep-not-installed,gitleaks-not-installed,trivy-not-installed,pip-audit-not-installed,ai-review-disabled) instead of failing - pip-audit supports requirements files,
pyproject.tomlprojects, orpylock.*.tomllocked projects — the runner picks the first match in that order - AI review timeouts default to 120s (
AI_PATCHLAB_AI_REVIEW_TIMEOUT_SECONDS); on timeout the runner writes[]toreports/raw/ai-review.jsonand emits a normalized error finding so the report still completes - Fingerprint web probe respects
robots.txt. Be careful when crafting tests:urllib.robotparsersplits the live user-agent on/before matching, so a robots.txt block forai-patchlab-fingerprint/0.1is matched asai-patchlab-fingerprint(drop the version when authoring rules) - Fingerprint matching is a SIGNAL, not an attribution. The Markdown report must keep the
DISCLAIMERblock and must never claim a match is "confirmed", "proven", "stolen", or "copied" — these words are blocked by a regression test intests/test_fingerprint_report.py - The fingerprint CLI accepts exactly one
--targetper invocation. No--targets-fileflag exists by design — multi-target scanning would require a new ADR - Fingerprinting must not add DOM-parser dependencies (
beautifulsoup4,lxml) or browser stacks (playwright,selenium). v0.1 stays onre+hashlib+httpxonly
IMPORTANT RULES
- Keep things SIMPLE — MVP first, iterate later
- Read examples in examples/ before implementing anything new
- Validate each step before moving to the next (Plan → Implement → Validate)
- Do NOT over-engineer — no premature abstractions
- When in doubt, ask before assuming
- Proactively suggest improvements when you spot issues
- ULTRATHINK before making architectural decisions
- Log architectural decisions in DECISIONS.md
Self-Healing Layer (AI-layer evolution)
When something is painful in an implementation, fix the underlying AI layer — not just the code. The "AI layer" is everything that shapes how the coding agent behaves: CLAUDE.md, AGENTS.md, examples/, .claude/commands/, .claude/agents/, .claude/pipelines/, .agents/skills/, PRP templates.
Rule: never review the implementer's work in the same context window that produced it. The writer is biased about its own output ("kid grading own homework"). Always run reviews and retrospectives in a fresh conversation.
Workflow:
/execute-prp <prp>→ implements + housekeeps + outputs handoff message (does NOT self-review)- New conversation →
/retrospective last→ identifies AI-layer drift and proposes concrete file edits - User approves the proposed edits → applied to CLAUDE.md / examples / skills / agents
When to skip: trivial implementations, doc-only changes, or PRPs that went perfectly clean. The retrospective should produce zero items in those cases.
AUTOMATIC HOUSEKEEPING (do this without being asked)
- After completing any feature or fix, ALWAYS update ROADMAP.md (mark items done with date)
- After any structural change (new files, new folders, new dependencies), update the relevant sections of THIS file (CLAUDE.md)
- If
AGENTS.mdexists, update the matching sections there too so Codex and Claude stay aligned - After completing a PRP, move it to
PRPs/done/with date prefix - After creating temporary/scratch files for debugging, DELETE them when done
- If CLAUDE.md.proposed exists and changes have been applied, DELETE it
- If AGENTS.md.proposed exists and changes have been applied, DELETE it
- When committing, include doc updates in the same commit or a separate "docs:" commit immediately after
- NEVER leave documentation out of sync with code
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

