# audit-prep

Prepare Solidity projects for a security audit — test coverage, test quality, NatSpec docs, code hygiene, dependency health, best-practice enforcement, deployment readiness, and project documentation checks. Generates a scored Audit Readiness Report and optionally runs static analysis. Trigger on: "prepare for audit", "audit readiness", "pre-audit check", "audit prep", "NatSpec check", or any request to review a Solidity codebase before a security review.

- **Kind:** skill
- **Source:** https://github.com/PlamenTSV/plamen
- **Page:** https://forefy.com/skills/55914ee1-33b9-439d-8b24-c75d4405369b
- **API (JSON + files):** https://forefy.com/api/skills/55914ee1-33b9-439d-8b24-c75d4405369b

---

## SKILL.md

---
name: audit-prep
description: >
  Prepare Solidity projects for a security audit — test coverage, test quality, NatSpec docs,
  code hygiene, dependency health, best-practice enforcement, deployment readiness, and project
  documentation checks. Generates a scored Audit Readiness Report and optionally runs static analysis.
  Trigger on: "prepare for audit", "audit readiness", "pre-audit check", "audit prep", "NatSpec check",
  or any request to review a Solidity codebase before a security review.
---

# Solidity Audit Preparation — Orchestrator

Orchestrate a parallelized audit-prep pipeline.
Do NOT perform analysis — discover files, dispatch agents, compile the scored report.

## Modes

- **Default:** full pipeline, all 8 phases + static analysis offer.
- **Single phase:** `coverage` | `quality` | `docs` | `hygiene` | `deps` | `practices` | `deploy` | `context`
- **`scan`:** static analysis only.
- **`--fix`:** auto-apply fixes (NatSpec stubs, console removal, pragma locking, SafeERC20 wrapping).
- **`--report <path>`:** write markdown report to file (no ANSI codes).
- **`--no-scan`:** skip static analysis offer.
- **`--scanner <tool>`:** run specific tool without prompting.
- **`--diff <ref>`:** scope to files changed since git ref.
- **`--ci`:** JSON output. Exit 0 if score >= threshold (default 75, `--min-score N`).

## Report Format

Clean markdown. Each phase = one table with Status, Finding, and Recommendation columns.
Score summary at the end. When rendered via `--report`, produces a polished `.md` file.

The report has these sections in order:
1. Header (project, framework, scope)
2. Phase 1–8, each as a titled section with a results table
3. Score summary table
4. Quick Wins table

### Banner

Print the banner from the end of this file before doing anything else — in every mode (full pipeline, single phase, scan, fix). Always use this exact banner. Never generate, invent, or substitute a different banner. Also include it at the top of `--report` markdown files.

### Phase section template

```markdown
## 1. Test Coverage

| Status | Finding | Recommendation |
|--------|---------|----------------|
| FAIL | Compiler warning — unused param in ConfigProvider:288 | Remove or rename the unused parameter |
| PASS | 4/4 contracts have test files | — |
| PASS | Branch coverage: 95.93% | — |
```

- **Status**: `PASS` or `FAIL`
- **Finding**: concise description of what was checked and the result
- **Recommendation**: specific action to fix (only for FAIL rows; use `—` for PASS)

### Score summary

```markdown
## Score Summary

| Phase | Score |
|-------|-------|
| 1. Test Coverage | 87/100 |
| 2. Test Quality | 85/100 |
| ... | ... |
| **Overall** | **82/100 — Almost Ready** |
```

### Quick Wins

```markdown
## Quick Wins

| # | Action | Location |
|---|--------|----------|
| 1 | Create deployment scripts | scripts/deploy.ts |
| 2 | Create SECURITY.md with trust assumptions | project root |
| 3 | Add more assertions to thin tests | test/ |
```

No deduction numbers, no weights, no `[-N]` annotations. The report should read like a professional checklist a dev team can hand to their lead.

## Execution

### Turn 0 — Banner & Project Selection

First, read the VERSION file and the skill's references path in parallel:
- **Read:** `VERSION` file from this skill's base directory
- **Glob:** `**/references/shared-rules.md` — extract `{ref_path}` (the references/ directory)

Then print the banner (from the end of this file), followed by asking the user where the project is:

```json
{
  "question": "Where is the project you want to prepare for audit?",
  "header": "Project",
  "multiSelect": false,
  "options": [
    {
      "label": "Current directory",
      "description": "Use the current working directory"
    },
    {
      "label": "Local path",
      "description": "Enter a path to a local project"
    },
    {
      "label": "GitHub repo",
      "description": "Enter a GitHub URL — will clone into a temp directory"
    }
  ]
}
```

If **Current directory**: use the cwd as `{project_dir}`.
If **Local path**: user provides a path, use it as `{project_dir}`.
If **GitHub repo**: clone with `git clone <url> /tmp/audit-prep-<repo-name>` and use that as `{project_dir}`.

### Turn 1 — Discover & Prepare

Make these **parallel tool calls** in ONE message:
a. **Bash:** detect framework — check for `foundry.toml`, `hardhat.config.js`, `hardhat.config.ts`
b. **Bash:** find in-scope `.sol` files. Exclude `test/`, `script/`, `lib/`, `node_modules/`, `interfaces/`, `mocks/`. Check both `src/` and `contracts/`. If `--diff <ref>`, use `git diff --name-only <ref> -- '*.sol'`.
c. **Bash:** find test files — `find test/ -name '*.sol' -o -name '*.ts' -o -name '*.js'`
d. **Bash:** count total lines in scope — `wc -l` on discovered source files
g. **Bash:** `mkdir -p .audit-prep` -> `{bundle_dir}` = `.audit-prep` (project-relative, so agents can read it)
h. **ToolSearch:** `mcp__sc-auditor` (for scan menu in Turn 4)

Then create agent bundles in a **single Bash call**:

```bash
# File list (one per line)
printf '%s\n' <in-scope-files> > {bundle_dir}/files.txt

# Agent A — Testing (Phases 1+2)
# Gets: framework, project dir, test metadata, source file list, instructions
{
  printf 'framework: %s\nproject_dir: %s\n\n' "<fw>" "<dir>"
  echo "# Test files:"
  for f in <test-files>; do
    printf '%s (%s lines)\n' "$f" "$(wc -l < "$f")"
  done
  echo ""
  echo "# In-scope source files:"
  cat {bundle_dir}/files.txt
  echo ""
  cat {ref_path}/agents/testing-agent.md
  echo ""
  cat {ref_path}/shared-rules.md
} > {bundle_dir}/agent-a.md

# Agent B — Source Analysis (Phases 3+4+6)
# NO SOURCE CODE — agent uses Grep/Read directly on project files
{
  printf 'project_dir: %s\n\n' "<dir>"
  echo "# In-scope source files:"
  cat {bundle_dir}/files.txt
  echo ""
  cat {ref_path}/agents/source-analysis-agent.md
  echo ""
  cat {ref_path}/shared-rules.md
} > {bundle_dir}/agent-b.md

# Agent C — Infrastructure (Phases 5+7+8)
{
  printf 'framework: %s\nproject_dir: %s\n\n' "<fw>" "<dir>"
  cat {ref_path}/agents/infrastructure-agent.md
  echo ""
  cat {ref_path}/shared-rules.md
} > {bundle_dir}/agent-c.md

echo "=== Bundles ==="
wc -l {bundle_dir}/agent-*.md
```

Print: `<project> | <framework> | <N> files, <M> lines`

### Turn 2 — Spawn

**First**, create 3 tasks so the user sees progress spinners:

| Task | Subject | Active Form |
|------|---------|-------------|
| A | Test coverage & quality (Phases 1-2) | Analyzing test coverage & quality |
| B | Source code analysis (Phases 3, 4, 6) | Analyzing source code |
| C | Infrastructure checks (Phases 5, 7, 8) | Checking infrastructure |

Use TaskCreate for each, then immediately set all 3 to `in_progress` via TaskUpdate.

**Then**, in the SAME message, spawn **3 parallel Agent calls:**

**Agent A — Testing (Phases 1 + 2):**
```
Read your full bundle at {bundle_dir}/agent-a.md.
Execute Phases 1 and 2 exactly as specified.
Output ONLY the PHASE/FAIL/PASS structured format from the shared rules.
Do NOT skip any phase. Do NOT add commentary or tables.
```

**Agent B — Source Analysis (Phases 3 + 4 + 6):**
```
Read your full bundle at {bundle_dir}/agent-b.md.
Execute Phases 3, 4, and 6 exactly as specified.
Use Grep and Read to analyze the source files listed in the bundle.
Do NOT read all source files at once — use targeted queries per check.
Output ONLY the PHASE/FAIL/PASS structured format from the shared rules.
Do NOT skip any phase. Do NOT perform vulnerability analysis.
```

**Agent C — Infrastructure (Phases 5 + 7 + 8):**
```
Read your full bundle at {bundle_dir}/agent-c.md.
Execute Phases 5, 7, and 8 exactly as specified.
Output ONLY the PHASE/FAIL/PASS structured format from the shared rules.
Do NOT skip any phase. Do NOT add commentary or tables.
```

As each agent completes, mark its task as `completed` via TaskUpdate.

### Turn 3 — Score & Report

**Parse** each agent's output. For each phase, extract:
- `PHASE N |` line → phase number, name, score
- `FAIL |` lines → check name, deduction, file, then `desc:` and `fix:` on next lines
- `PASS |` lines → check name, optional `note:`

**Validate:** For each expected phase (1–8):
- Missing `PHASE N` marker → score = 0, add note "(not reported by agent)"
- Missing `SCORE:` → compute as 100 minus sum of extracted deductions
- No FAIL/PASS lines → flag "(no details reported)"

**Compute weighted score:**

| Phase | Weight |
|-------|--------|
| 1. Coverage | 15% |
| 2. Quality | 15% |
| 3. Documentation | 10% |
| 4. Hygiene | 10% |
| 5. Dependencies | 10% |
| 6. Best Practices | 15% |
| 7. Deployment | 10% |
| 8. Project Docs | 15% |

**Verdict:** 90–100 Audit Ready | 75–89 Almost Ready | 50–74 Needs Work | <50 Not Ready
**Override:** If Phase 1 (Coverage) score < 90, verdict CANNOT be "Audit Ready" — cap at "Almost Ready" and append "(coverage below 90%)".

**Render the report as clean markdown** using the format from the Report Format section.
The banner is already visible from Turn 1 — do NOT re-print it here. In `--report` files, include the banner as an uncolored code block at the top.

For each phase, build a table with Status | Finding | Recommendation columns.
FAIL rows get a specific recommendation. PASS rows get `—` in the recommendation column.
Group related PASS items into single rows where natural (e.g., "No TODOs, console imports, or commented-out code").

End with the Score Summary table and Quick Wins table.
**Quick Wins** = top 5 most impactful FAIL findings. Each shows the fix action and where to apply it.

If `--report <path>`: write the markdown to the specified file path.
If `--ci`: JSON `{"score": N, "verdict": "...", "phases": [...], "findings": [...]}`.

### Turn 4 — Scan Menu

Skip if `--no-scan`. If `--scanner <tool>`, run directly.

**Detection:**

1. **Local CLI tools (single Bash):**
```bash
echo "=== SCAN DETECTION ==="
which slither 2>/dev/null && echo "SLITHER=yes" || echo "SLITHER=no"
which aderyn 2>/dev/null && echo "ADERYN=yes" || echo "ADERYN=no"
which myth 2>/dev/null && echo "MYTHRIL=yes" || echo "MYTHRIL=no"
```

2. **MCP tools:** check ToolSearch results from Turn 1 for `mcp__sc-auditor__run-slither`, `mcp__sc-auditor__run-aderyn`.

3. **Skills:** check the available skills list for `solidity-auditor` (Pashov).

A tool is "installed" if ANY source is available (local CLI, MCP, or skill).

**Present the scan menu using AskUserQuestion with multiSelect: true.**

**Always include all four options** (Slither, Aderyn, Pashov Solidity Auditor, Import custom scanner). Set each tool's description dynamically to show its availability status and source. Never omit an option just because it was not detected — show it with "(not installed)" instead.

Example AskUserQuestion call:
```json
{
  "question": "Which scanners do you want to run?",
  "header": "Bug Scan",
  "multiSelect": true,
  "options": [
    {
      "label": "Slither",
      "description": "Static analysis for Solidity (available via MCP)"
    },
    {
      "label": "Aderyn",
      "description": "Rust-based static analyzer (installed locally)"
    },
    {
      "label": "Pashov Solidity Auditor",
      "description": "AI-powered audit skill (available as skill)"
    },
    {
      "label": "Import custom scanner",
      "description": "Provide a CLI command to run your own scanner"
    }
  ]
}
```

For the description field of Slither, Aderyn, and Pashov — set dynamically based on detection:
- Installed: `"... (available via MCP)"`, `"... (installed locally)"`, or `"... (available as skill)"`
- Not installed: `"... (not installed)"`

If the user selects **"Import custom scanner"**, follow up by asking for the CLI command to run. Execute it with the same timeout (300s) and append output to the scan results.

Findings from scanners do NOT affect the audit-prep score.

**Tool execution reference:**

| Tool | Local CLI | MCP | Skill |
|------|-----------|-----|-------|
| Slither | `slither . --filter-paths "test\|script\|lib\|node_modules"` | `mcp__sc-auditor__run-slither` | — |
| Aderyn | `aderyn .` | `mcp__sc-auditor__run-aderyn` | — |
| Pashov Solidity Auditor | — | — | `solidity-auditor` skill |

Priority when multiple sources available: MCP > local CLI > skill.

## Auto-Fix (`--fix`)

### Code fixes (applied to source files)
| Fix | Action |
|-----|--------|
| NatSpec stubs | Insert @notice, @param, @return above undocumented functions |
| Console removal | Remove console.sol imports and console.log calls |
| Pragma locking | Replace `^0.8.x` with `0.8.x` |
| SafeERC20 wrapping | Add `using SafeERC20 for IERC20;`, replace direct calls |
| SPDX headers | Add `// SPDX-License-Identifier: MIT` to files missing it (prompt for license) |

### Template generation (creates new files if missing)
| File | Content |
|------|---------|
| `SECURITY.md` | Skeleton: Roles & Permissions, Trust Assumptions, Centralization Risks, Known Risks sections. Pre-fill role names from AccessControl/Ownable usage in source. |
| `scope.md` | Generate from discovered in-scope files: contract name, file path, line count, brief description from @title NatSpec |
| `KNOWN_ISSUES.md` | Skeleton: header + "Document any known limitations, accepted risks, or intentional design trade-offs here." |

Templates are only created if the file does not already exist. The orchestrator generates these after the report, using data already collected during the pipeline (in-scope files, role names, config vars). No extra agent calls needed.

## Banner

Before doing anything else, print the banner below as plain text (not inside a code block). Apply ANSI color `\033[38;5;117m` (light sky blue) to the entire banner (both CD and SECURITY block letters), `\033[38;5;153m` (pale blue) for the subtitle, and `\033[0m` to reset at the end.

### Terminal

```
██████╗██████╗
██╔════╝██╔══██╗
██║     ██║  ██║
██║     ██║  ██║
╚██████╗██████╔╝
╚═════╝╚═════╝

███████╗███████╗ ██████╗██╗   ██╗██████╗ ██╗████████╗██╗   ██╗
██╔════╝██╔════╝██╔════╝██║   ██║██╔══██╗██║╚══██╔══╝╚██╗ ██╔╝
███████╗█████╗  ██║     ██║   ██║██████╔╝██║   ██║    ╚████╔╝
╚════██║██╔══╝  ██║     ██║   ██║██╔══██╗██║   ██║     ╚██╔╝
███████║███████╗╚██████╗╚██████╔╝██║  ██║██║   ██║      ██║
╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚═╝   ╚═╝      ╚═╝

Audit Preparation v1.0
```

### For `--report` markdown files

Use the same layout inside a code block (no ANSI codes):

```
██████╗██████╗
██╔════╝██╔══██╗
██║     ██║  ██║
██║     ██║  ██║
╚██████╗██████╔╝
╚═════╝╚═════╝

███████╗███████╗ ██████╗██╗   ██╗██████╗ ██╗████████╗██╗   ██╗
██╔════╝██╔════╝██╔════╝██║   ██║██╔══██╗██║╚══██╔══╝╚██╗ ██╔╝
███████╗█████╗  ██║     ██║   ██║██████╔╝██║   ██║    ╚████╔╝
╚════██║██╔══╝  ██║     ██║   ██║██╔══██╗██║   ██║     ╚██╔╝
███████║███████╗╚██████╗╚██████╔╝██║  ██║██║   ██║      ██║
╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚═╝   ╚═╝      ╚═╝

Audit Preparation v1.0
```

## VERSION

```

```

## evals

```

```

## evals/evals.json

```json
{
  "skill_name": "audit-prep",
  "evals": [
    {
      "id": 1,
      "name": "hardhat-small-project",
      "prompt": "prepare this project for audit",
      "project_dir": "/path/to/your/hardhat-project",
      "expected_output": "Full 8-phase audit readiness report for a Hardhat project with 4 contracts. High coverage (95%+), good practices (100), missing deploy scripts and documentation.",
      "assertions": [
        {
          "id": "format-all-phases",
          "text": "All 8 phases are reported (PHASE 1 through PHASE 8)",
          "type": "programmatic",
          "check": "grep -c 'PHASE [1-8]' should return 8"
        },
        {
          "id": "format-end-markers",
          "text": "All phases have END PHASE markers",
          "type": "programmatic",
          "check": "grep -c 'END PHASE' should return 8"
        },
        {
          "id": "format-fail-has-fix",
          "text": "Every FAIL line is followed by desc: and fix: lines",
          "type": "programmatic",
          "check": "Every FAIL block has both desc: and fix: on subsequent lines"
        },
        {
          "id": "detect-hardhat",
          "text": "Framework detected as Hardhat",
          "type": "programmatic",
          "check": "Output contains 'Hardhat' in project summary line"
        },
        {
          "id": "file-count",
          "text": "In-scope file count is 4",
          "type": "programmatic",
          "check": "Output contains '4 files'"
        },
        {
          "id": "coverage-high",
          "text": "Phase 1 coverage score >= 80 (project has 95%+ branch coverage)",
          "type": "range",
          "check": "Phase 1 SCORE >= 80"
        },
        {
          "id": "hygiene-floating-pragma",
          "text": "Phase 4 flags floating pragma ^0.8.22",
          "type": "programmatic",
          "check": "Phase 4 output contains 'floating_pragma' FAIL"
        },
        {
          "id": "practices-perfect",
          "text": "Phase 6 best practices score >= 90",
          "type": "range",
          "check": "Phase 6 SCORE >= 90"
        },
        {
          "id": "deploy-missing",
          "text": "Phase 7 flags missing deploy scripts",
          "type": "programmatic",
          "check": "Phase 7 output contains 'no_deploy_scripts' FAIL"
        },
        {
          "id": "docs-no-trust",
          "text": "Phase 8 flags missing trust assumptions",
          "type": "programmatic",
          "check": "Phase 8 output contains 'no_trust_model' FAIL"
        },
        {
          "id": "no-vuln-analysis",
          "text": "No vulnerability analysis in output (no H-01, M-01, etc.)",
          "type": "programmatic",
          "check": "Output does NOT contain '[H-0' or '[M-0' or 'vulnerability' or 'exploit'"
        },
        {
          "id": "quick-wins-present",
          "text": "Report ends with Quick Wins section",
          "type": "programmatic",
          "check": "Output contains 'Quick Wins'"
        },
        {
          "id": "no-standard-override-flags",
          "text": "NatSpec check does not flag standard ERC overrides (ownerOf, transferFrom, etc.)",
          "type": "programmatic",
          "check": "Phase 3 does NOT contain FAIL for ownerOf, transferFrom, getApproved, isApprovedForAll"
        },
        {
          "id": "no-fuzz-penalty",
          "text": "No deduction for missing fuzz tests (bonus only)",
          "type": "programmatic",
          "check": "Phase 2 does NOT contain a FAIL with deduction for no_fuzz"
        }
      ]
    },
    {
      "id": 2,
      "name": "foundry-large-project",
      "prompt": "prepare this project for audit",
      "project_dir": "/path/to/your/foundry-project",
      "expected_output": "Full 8-phase audit readiness report for a Foundry project with 38+ contracts. Uninitialized submodules, missing deploy scripts, missing documentation.",
      "assertions": [
        {
          "id": "format-all-phases",
          "text": "All 8 phases are reported (PHASE 1 through PHASE 8)",
          "type": "programmatic",
          "check": "grep -c 'PHASE [1-8]' should return 8"
        },
        {
          "id": "format-end-markers",
          "text": "All phases have END PHASE markers",
          "type": "programmatic",
          "check": "grep -c 'END PHASE' should return 8"
        },
        {
          "id": "detect-foundry",
          "text": "Framework detected as Foundry",
          "type": "programmatic",
          "check": "Output contains 'Foundry' in project summary line"
        },
        {
          "id": "file-count-large",
          "text": "In-scope file count >= 35",
          "type": "range",
          "check": "File count in summary line >= 35"
        },
        {
          "id": "deps-uninit-submodules",
          "text": "Phase 5 flags uninitialized git submodules",
          "type": "programmatic",
          "check": "Phase 5 output contains 'uninit_submodule' FAIL"
        },
        {
          "id": "practices-no-pause",
          "text": "Phase 6 flags missing emergency pause mechanism",
          "type": "programmatic",
          "check": "Phase 6 output contains 'no_emergency_pause' FAIL"
        },
        {
          "id": "deploy-missing",
          "text": "Phase 7 flags missing deploy scripts",
          "type": "programmatic",
          "check": "Phase 7 output contains 'no_deploy_scripts' FAIL"
        },
        {
          "id": "docs-no-trust",
          "text": "Phase 8 flags missing trust assumptions",
          "type": "programmatic",
          "check": "Phase 8 output contains 'no_trust_model' FAIL"
        },
        {
          "id": "no-vuln-analysis",
          "text": "No vulnerability analysis in output",
          "type": "programmatic",
          "check": "Output does NOT contain '[H-0' or '[M-0' or 'vulnerability' or 'exploit'"
        },
        {
          "id": "hygiene-floating-pragma",
          "text": "Phase 4 flags floating pragma",
          "type": "programmatic",
          "check": "Phase 4 output contains 'floating_pragma' FAIL"
        }
      ]
    }
  ]
}
```

## evals/grade.sh

```bash

```

## references

```

```

## references/agents

```

```

## references/agents/infrastructure-agent.md

# Infrastructure Agent — Phases 5, 7 & 8

You have: framework, project_dir, and Bash/Read/Glob/Grep tools.
Do NOT read source .sol files. Check project infrastructure only.

## Phase 5: Dependencies (10%)

### Foundry projects
1. `git -C <project_dir> submodule status 2>&1`
   — lines starting with `-` = uninitialized
2. For each initialized submodule: `git -C <project_dir>/lib/<dep> describe --tags 2>/dev/null`
3. Check for patched deps: `git -C <project_dir>/lib/<dep> diff --stat HEAD 2>/dev/null`

### Hardhat/npm projects
1. `cd <project_dir> && npm outdated --json 2>&1` or `pnpm outdated --json 2>&1`
2. `cd <project_dir> && npm audit --production --json 2>&1` or `pnpm audit --json 2>&1`
3. Glob for lock file: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`

### Scoring
| Check | Deduction |
|-------|-----------|
| Modified/patched dependency | -25 |
| Critical CVE (production) | -20 |
| High/moderate CVE (production) | -10 |
| Major version outdated | -15 |
| Minor version outdated | -5 |
| Missing lock file | -10 |
| Uninitialized git submodule | -10 (cap -30) |

Dev-only vulnerabilities = INFO, no deduction.

### Output:
```
PHASE 5 | Dependencies | SCORE: 70/100

FAIL | uninit_submodule | -10 | lib/openzeppelin-contracts
desc: Submodule not initialized — version unverifiable
fix: Run: git submodule update --init --recursive

PASS | no_modified_deps
note: No patched or modified dependencies detected

PASS | lock_file
note: Remappings properly configured

END PHASE 5
```

## Phase 7: Deployment Readiness (10%)

### Check 1: Clean build
Run: `forge build 2>&1` or `npx hardhat compile 2>&1`
Deduction: -50 if build fails

### Check 2: Tests pass
Run: `forge test --no-match-path "test/fork/*" 2>&1` or `npx hardhat test 2>&1` (timeout 300s)
Deduction: -30 if any tests fail (report X/Y passed)

### Check 3: Deploy scripts
Glob for: `script/Deploy*`, `scripts/deploy*`, `deploy/`, `ignition/`
Deduction: -30 if no deploy scripts found

### Check 4: Verification setup
Grep in config and deploy scripts: `--verify|etherscan|blockscout|sourcify`
Deduction: -15 if no verification setup found

### Check 5: README setup instructions
Read: README.md first 80 lines. Look for install/build/test commands.
Deduction: -15 if no setup instructions

### Check 6: Deployment documentation
Check README or docs/ for deployment procedures, network configs, multisig setup.
Deduction: -10 if missing

### Check 7: Hardcoded addresses
Grep: `0x[a-fA-F0-9]{40}` in deploy scripts (script/ or scripts/).
Check if each has an explanatory comment.
Deduction: -5 per uncommented address (cap -15)

### Check 8: Git cleanliness
Run: `git -C <project_dir> status --short 2>&1`
Check for uncommitted changes, untracked .sol files, or merge conflicts.
Deduction: -10 if working tree is dirty (uncommitted changes to .sol files)
Note: only flag changes to .sol, .json config, or script files — ignore IDE files, .DS_Store etc.

## Phase 8: Project Documentation (15%)

### Check 1: Architecture overview (-30)
Read README.md. Check for: system description, contract relationships, or diagrams.
Also check: `docs/` directory for architecture docs.

### Check 2: Trust assumptions (-25)
Check for SECURITY.md or security section in README.
Grep in README and docs/: `trust|assumption|threat|admin|privileged|centralization|role`

### Check 3: System invariants (-20)
Grep: `invariant|@custom:invariant`
Check for: `docs/invariants.md`, invariants section in README or docs.

### Check 4: Known issues (-15)
Check for: `known-issues.md`, `KNOWN_ISSUES.md`
Grep in README: `known.issue|known.limitation|known.bug|known.risk`

### Check 5: Previous audits (-10)
Glob: `audits/`, `audit-reports/`, `security/`
Grep in README: `audit|security review|formal verification`
For new/first-audit projects: skip this check (don't penalize).

### Check 6: Scope definition (-10)
Check for a file that defines audit scope:
Glob for: `scope.json`, `scope.md`, `SCOPE.md`, `scope.txt`
Also check README for a "Scope" or "Contracts" section listing in-scope files.
If none found, flag it — auditors need to know which contracts, chains, and entry points are in scope.

### Output:
```
PHASE 8 | Project Documentation | SCORE: 45/100

FAIL | no_trust_model | -25 | n/a
desc: No trust assumptions or threat model documented
fix: Create SECURITY.md with admin roles, trust boundaries, known risks

FAIL | no_scope_definition | -10 | n/a
desc: No audit scope file defining in-scope contracts and target chains
fix: Create scope.md listing contracts in scope, target chains, and entry points

PASS | architecture
note: README contains system overview with contract descriptions

PASS | known_issues
note: Known issues documented in README "Limitations" section

END PHASE 8
```

## Constraints
- Do NOT read source .sol files
- Do NOT perform security or vulnerability analysis
- Output ONLY the structured PHASE/FAIL/PASS format
- No prose, tables, or summaries

## references/agents/source-analysis-agent.md

# Source Analysis Agent — Phases 3, 4 & 6

You have: project_dir, in-scope file list, and Grep + Read tools.

**CRITICAL: Do NOT read all source files at once. Use targeted Grep queries for each check.**

## Phase 3: NatSpec Documentation (10%)

### Step 1: Count documentable elements
Run these Greps on in-scope files (use the file list from your bundle):

a) Public/external functions:
   Pattern: `function\s+\w+[^;]*(public|external)`
   Count total matches.

b) Contracts/interfaces/libraries:
   Pattern: `(abstract\s+)?(contract|interface|library)\s+\w+`

c) Events:
   Pattern: `event\s+\w+`

d) Public state variables:
   Pattern: `\w+\s+public\s+\w+;`

### Step 2: Count NatSpec coverage
a) `@inheritdoc` count — these are fully documented:
   Pattern: `@inheritdoc`

b) `@notice` before functions:
   Pattern: `@notice`
   Count total. Compare against documentable elements from Step 1.

c) Contract-level `@title`:
   Pattern: `@title`

### Step 3: Spot-check gaps
Grep for functions WITHOUT preceding NatSpec:
- Pattern: `function\s+\w+` with -B5 context
- Scan results for functions not preceded by `///` or `/**` lines
- Only report the first 10 undocumented functions (cap findings)

**Skip standard overrides:** Do NOT flag functions that are simple overrides of well-known standards (ERC20, ERC721, ERC1155, ERC4626, etc.) like `ownerOf`, `balanceOf`, `transferFrom`, `approve`, `getApproved`, `isApprovedForAll`, `safeTransferFrom`, `tokenURI`, `supportsInterface`, `totalSupply`, `decimals`, `name`, `symbol`. These are self-explanatory from the standard — `@inheritdoc` or `@notice` is nice but not required. Only flag custom project-specific functions that lack documentation.

### Step 4: Stale @param detection
Grep for `@param` with -A3 context to get the function signature below.
Check that each @param name matches an actual parameter in the function.
Flag any @param that references a parameter not in the signature (copy-paste error).
Deduction: -5 each (cap -15)

### Step 5: Missing @return for named returns
Grep for functions with named return values: `returns\s*\(.*\w+\s+\w+`
For each, check if a matching `@return` tag exists above.
Deduction: -3 each (cap -15)

### Scoring
Score = round((documented / total_required) * 100)
Each undocumented public function: -3 (cap -60)
Each undocumented contract: -5 (cap -20)
Stale @param: -5 each (cap -15)
Missing @return for named returns: -3 each (cap -15)

### Output per finding:
```
FAIL | missing_natspec | -3 | src/Vault.sol:27
desc: deposit() missing @notice and @param tags
fix: Add /// @notice and /// @param above the function

FAIL | stale_param | -5 | src/Vault.sol:30
desc: @param amount documented but parameter is named _amount
fix: Change @param amount to @param _amount

FAIL | missing_return | -3 | src/Oracle.sol:15
desc: getPrice() has named return 'price' but no @return tag
fix: Add /// @return price The current price
```

## Phase 4: Code Hygiene (10%)

Run each Grep on in-scope source files:

### Check 1: TODO/FIXME/HACK/XXX
Pattern: `TODO|FIXME|HACK|XXX`
Deduction: -3 each (cap -30)
These indicate unfinished work — must be resolved before audit.

### Check 2: Console imports
Pattern: `console\.(sol|log|2)|import.*console`
Deduction: -15 if any found

### Check 3: Commented-out code
Pattern: `^\s*//\s*(function |if \(|for \(|while |return |require\(|emit )`
Count blocks of 3+ consecutive commented lines nearby.
Deduction: -2 per block (cap -20)

### Check 4: Floating pragma
Pattern: `pragma solidity \^`
Only in project-owned files (not lib/).
Deduction: -10 if any found

### Check 5: Inconsistent pragmas
Pattern: `pragma solidity`
Collect unique versions from project-owned files.
Deduction: -10 if more than one version

### Check 6: Test imports in source
Pattern: `forge-std|import.*Test` in src/ or contracts/ only.
Deduction: -10 if found

### Check 7: require() vs custom errors consistency
Grep for both patterns:
- `require\(` — count matches
- `revert\s+\w+Error|error\s+\w+` — count custom error declarations/usage
If BOTH patterns exist with significant usage (>3 of each), flag inconsistency.
Deduction: -5

### Check 8: Unused imports
Grep: `import\s+\{([^}]+)\}\s+from` to extract named imports.
For each imported symbol, Grep for its usage in the same file (excluding the import line).
If a symbol is imported but never used in the file, flag it.
Deduction: -2 each (cap -15)
Skip if >100 import statements across the project (too costly).

### Check 9: SPDX license identifiers
Pattern: `SPDX-License-Identifier`
Grep all in-scope files. Any file missing an SPDX header gets flagged.
Deduction: -2 each (cap -10)

### Check 10: Dead internal functions
Pattern: `function\s+_\w+.*internal`
For each match, Grep the function name across all project files.
If only 1 match (the definition), it's dead.
Deduction: -5 each (cap -15)
Skip if >40 internal functions (too many to check efficiently).

## Phase 6: Best Practices (15%)

Safety, access control, and upgradeable patterns ONLY. No gas.

### S1: Unsafe ERC20
Grep: `\.transfer\(|\.transferFrom\(|\.approve\(`
For each match, check the same file for `using SafeERC20 for` or `safeTransfer`.
Exclude: ETH transfers (`address.transfer`), Uniswap Currency type.
Deduction: -10 if unsafe ERC20 calls found without SafeERC20.

### S2: CEI violations
Grep: `\.call\{value:|\.call\(abi`
For each match, Read 30 lines of the containing function.
Check if storage writes (`=`, `push`, `pop`, `delete`, `+=`, `-=`) occur AFTER the external call within the same function.
Deduction: -15 per violation (cap -30).

### S3: Missing reentrancy guard
Grep functions with `external` modifier that also contain `.call{value:`.
Check if function has `nonReentrant` or `nonreentrant` modifier.
Deduction: -10 per missing guard (cap -20).

### S4: Missing events on state changes
Grep: `function.*(external|public)` with -A20 context.
In results, check for functions with storage writes but no `emit`.
Only flag functions modifying protocol parameters (not trivial getters/views).
Deduction: -3 each (cap -30).

### S5: Zero-address checks
Grep: `constructor|function\s+(set|update|change)\w+.*address`
Check for `!= address(0)` or `== address(0)` validation.
Only flag addresses controlling funds, ownership, or critical config.
Deduction: -3 each (cap -15).

### S6: ETH via transfer/send
Grep: `\.transfer\(|\.send\(` where the target is `address` (not ERC20).
Confirm by checking the variable type or context — `payable(addr).transfer(amt)`.
Deduction: -5 each.

### S7: Unchecked .call return
Grep: `\.call\{|\.call\(`
Check each for `(bool success` or return value handling.
Deduction: -10 per unchecked call.

### S8: Single-step ownership
Grep: `Ownable[^2]|import.*Ownable\.sol`
If found without Ownable2Step, flag it.
Deduction: -5.

### S9: No emergency pause (DeFi with user funds)
Grep: `deposit|stake|lock|withdraw` in function names.
If found, check for Pausable/pause mechanism.
Deduction: -10 if holding user funds without pause.

### S10: Oracle staleness
Grep: `latestRoundData|latestAnswer`
Check for `updatedAt` or `answeredInRound` validation nearby.
Deduction: -15 if oracle used without staleness check.

### Access Control

#### A1: Unguarded admin functions
Grep: `function.*(external|public)` that contain sensitive operations.
Sensitive = `owner`, `admin`, `withdraw`, `set.*Fee`, `set.*Rate`, `pause`, `upgrade`.
Check for: `onlyOwner`, `onlyRole`, `onlyAdmin`, `require(msg.sender`.
Deduction: -10 each (cap -30).

### Upgradeable (only if proxy detected)

First check: Grep for `Initializable|UUPSUpgradeable|TransparentProxy`.
If none found, skip entirely and output:
```
PASS | not_upgradeable
note: No proxy/upgradeable pattern detected — skipping upgrade checks
```

If found:
| Check | Grep for | Deduction |
|-------|----------|-----------|
| Missing initializer | `function initialize` without `initializer` modifier | -20 |
| Missing _disableInitializers | `constructor` without `_disableInitializers` | -20 |
| Missing onlyInitializing | `function _\w+Init` without `onlyInitializing` | -10 |
| No storage gaps | Missing `__gap` AND no ERC-7201 `@custom:storage-location` | -10 |
| Unprotected upgradeTo | `upgradeTo` without access control | -20 |

## Constraints
- Use Grep and Read ONLY — no Bash commands
- Do NOT read all source files at once — use targeted queries
- Do NOT perform vulnerability analysis or threat modeling
- Do NOT flag gas optimizations
- Output ONLY the structured PHASE/FAIL/PASS format

## references/agents/testing-agent.md

# Testing Agent — Phases 1 & 2

Read your bundle for: framework, project_dir, test file list, in-scope source file list.

## Phase 1: Test Coverage (15%)

### Step 1: Run coverage
- Foundry: `forge coverage 2>&1` (timeout 300s)
- Hardhat: `npx hardhat coverage 2>&1` (timeout 300s)

If successful, extract **per-contract** line and branch coverage percentages.
Report each in-scope contract as a separate FAIL or PASS line with its coverage numbers.
If it fails (missing deps, compile error, timeout), estimate from test file matching and note "estimated".

### Step 2: Match test files to source
Compare in-scope source files against test files. A source contract has coverage if a test file exists that imports or references it.

### Step 3: Compiler health
- Foundry: `forge build 2>&1 | grep -ci warning`
- Hardhat: `npx hardhat compile 2>&1 | grep -ci warning`

### Scoring
- Base score = average branch coverage % (or estimated coverage)
- If estimated: apply -10 confidence penalty
- Compiler warnings: -10 each (cap -30) — these MUST be fixed before audit
- Untested contracts (no matching test file): -15 each (cap -45)

### Coverage threshold
After computing score, check: if branch coverage < 90%, emit this FAIL:
```
FAIL | below_threshold | -0 | n/a
desc: Branch coverage XX% — audit requires minimum 90%
fix: Add tests to reach 90%+ branch coverage before scheduling audit
```
This is informational (no extra deduction — the low base score already penalizes) but signals the project is NOT audit-ready.

### Output:
Report each contract individually, then a total line:
```
PHASE 1 | Test Coverage | SCORE: 70/100

FAIL | below_threshold | -0 | n/a
desc: Branch coverage 70% — audit requires minimum 90%
fix: Add tests to reach 90%+ branch coverage before scheduling audit

FAIL | contract_coverage | -0 | src/core/Vault.sol
desc: Vault.sol — 45% line, 32% branch
fix: Add tests for deposit(), withdraw(), and edge cases

FAIL | no_coverage | -15 | src/libs/MathLib.sol
desc: No test file for MathLib (5 functions)
fix: Create test/MathLib.t.sol with unit tests

PASS | contract_coverage | src/core/Token.sol
note: Token.sol — 98% line, 95% branch

PASS | contract_coverage | src/core/Oracle.sol
note: Oracle.sol — 100% line, 100% branch

FAIL | compiler_warning | -10 | src/Token.sol:42
desc: Compiler warning: unused variable — must fix before audit
fix: Remove or use the declared variable

PASS | total_coverage
note: Overall: 70% line, 65% branch across 8 contracts

END PHASE 1
```

## Phase 2: Test Quality (15%)

Use Grep on test files. Do NOT read full test files into context.

### Grep checks (run in parallel):

| Check | Pattern | Path |
|-------|---------|------|
| Test count | `function test\|it\(["']` | test/ |
| Assertions | `assert\|expect\(\|vm.expectRevert\|vm.expectEmit` | test/ |
| Edge cases | `address\(0\)\|ZeroAddress\|type\(uint256\).max\|MaxUint256` | test/ |
| Negative tests | `revertedWith\|reverted\|vm.expectRevert\|should revert` | test/ |
| Integration | files matching `*Integration*\|*E2E*\|*Fork*` | test/ |
| Fuzz/invariant | `testFuzz_\|test_Fuzz\|invariant_\|fuzz` | test/ |

Compute: assertion_density = assertion_count / test_count.
Compute: negative_pct = negative_test_count / test_count * 100.

### Scoring
| Check | Condition | Deduction |
|-------|-----------|-----------|
| Edge cases | None found | -25 |
| Assertion density | < 2.0/test | -15 |
| Assertion density | < 1.0/test (replaces above) | -30 |
| Negative tests | < 20% of tests | -15 |
| Integration | None found, 3+ source contracts | -10 |
| Fuzz/invariant present | Found | +5 (cap 100) |

Fuzz/invariant tests are a bonus only — do NOT deduct points if absent. Many projects outsource fuzzing to auditors.

### Output:
```
PHASE 2 | Test Quality | SCORE: 60/100

FAIL | no_fuzz | -15 | n/a
desc: No fuzz/invariant tests — protocol has math-heavy DeFi logic
fix: Add testFuzz_ and invariant_ tests for math and state transitions

FAIL | assertion_density | -15 | n/a
desc: 1.4 assertions/test (157/112) — below 2.0 threshold
fix: Add more assert/expect to tests under 2 assertions

PASS | edge_cases
note: 23 edge case checks (address(0), max values)

PASS | negative_tests
note: 35% revert checks (39/112 tests)

END PHASE 2
```

## Constraints
- Use Bash and Grep only
- Do NOT read source .sol files
- Do NOT perform security analysis
- Structured output only — no prose or tables

## references/shared-rules.md

# Shared Rules

## Output Format

Every phase outputs this exact structure:

```
PHASE <N> | <Name> | SCORE: <X>/100

FAIL | <check> | <-N> | <file:line or n/a>
desc: <one factual sentence — what is wrong>
fix: <one sentence — specific action to fix it>

PASS | <check>
note: <brief evidence>

END PHASE <N>
```

Rules:
- Every assigned phase MUST appear between PHASE and END markers
- FAIL needs: check name, deduction, file location (or `n/a`)
- `desc:` = factual problem statement
- `fix:` = specific actionable instruction (command to run, file to create, code to change)
- PASS needs: check name, optional `note:` with evidence
- Score = 100 minus deductions (min 0, max 100). Apply deduction caps from your checklist.
- One blank line between each FAIL/PASS block

Example:
```
PHASE 4 | Code Hygiene | SCORE: 80/100

FAIL | floating_pragma | -10 | src/Vault.sol:1
desc: Floating pragma ^0.8.20 allows untested compiler versions
fix: Change to pragma solidity 0.8.20 in all source files

FAIL | console_import | -15 | src/Vault.sol:5
desc: console.sol imported in production code
fix: Remove import and all console.log calls

PASS | no_todos
note: No TODO/FIXME/HACK found

END PHASE 4
```

## DO NOT Report

Never flag: gas optimizations (constant/immutable, struct packing, SLOADs, unchecked math, memory vs calldata), functions >50 lines, magic numbers, naming conventions, code style.

## DO NOT Do

- Do NOT perform security vulnerability analysis or threat modeling
- Do NOT suggest architecture changes or redesigns
- Do NOT produce prose, tables, summaries, or markdown formatting
- Do NOT output anything except the structured PHASE/FAIL/PASS format above
- Do NOT analyze files outside the project directory
- Do NOT analyze files in lib/, node_modules/, interfaces/, mocks/

## Scope

Only the project's own contracts (src/ or contracts/, excluding lib/, node_modules/, interfaces/, mocks/, test/, script/).
- `@inheritdoc` = fully documented (not a finding)
- Inline assembly = INFO only (no deduction)
- Dev-only CVEs = INFO only (no deduction)

