# annotation

This skill should be used when the user says "find annotations", "list audit tags", "show @audit comments", "compile annotations", "/annotation", "find todos", "find audit comments", "what did I annotate", "annotation summary", "list audit findings", "what's annotated", or wants to discover, list, or filter @audit-* comment annotations scattered throughout a codebase. This skill is for annotation discovery only — how annotations are used downstream (spawning subagents, cross-referencing findings, etc.) is out of scope.

- **Kind:** skill
- **Source:** https://github.com/JoranHonig/grimoire
- **Page:** https://forefy.com/skills/111959b1-4801-4f26-9d57-358aca72b8d9
- **API (JSON + files):** https://forefy.com/api/asr/111959b1-4801-4f26-9d57-358aca72b8d9

---

## SKILL.md

---
name: annotation
description: >-
  This skill should be used when the user says "find annotations", "list audit
  tags", "show @audit comments", "compile annotations", "/annotation",
  "find todos", "find audit comments", "what did I annotate", "annotation
  summary", "list audit findings", "what's annotated",
  or wants to discover, list, or filter @audit-* comment annotations
  scattered throughout a codebase. This skill is for annotation discovery only —
  how annotations are used downstream (spawning subagents, cross-referencing
  findings, etc.) is out of scope.
user_invocable: true
---

# Annotation

Find `@audit` annotations in a codebase and return them as structured JSON.

## Workflow

1. Determine the target directory — the project root, a `src/` subdirectory, or whatever the user specified.
2. Run the discovery script against the target directory.
3. Present results to the user in their requested format (JSON for programmatic use, table for overview).

## Invocation

```
uv run skills/annotation/scripts/find-annotations.py <directory> [--tag TAG] [--format json|table]
```

- `directory` — path to scan (usually the project root or `src/`)
- `--tag` — filter to a specific tag, exact match (e.g., `audit-high`, `audit-todo`)
- `--format` — `json` (default) or `table` for human-readable output

## Output

Each annotation is returned with six fields:

| Field | Description |
|-------|-------------|
| `file` | Relative path from the scanned directory |
| `line` | Line number (1-indexed) |
| `tag` | Tag name — `audit`, `audit-ok`, `audit-high`, `audit-todo`, etc. |
| `content` | Text after the tag on the same line |
| `context_type` | Enclosing scope type (`function`, `contract`, `trait`, etc.) or `unknown` |
| `context_name` | Name of the enclosing scope or `unknown` |

## Language Support

The script has two tiers of support:

- **All languages** — grep-based discovery. Finds annotations in any text file. Context fields are `unknown`.
- **Rust and Solidity** — tree-sitter parsing resolves `context_type` and `context_name` to the enclosing function, contract, trait, impl, or module. Falls back to grep if tree-sitter dependencies are not installed.


## Annotation Types

Refer to `references/annotation-format.md` for the full taxonomy of supported `@audit` tag types.

## examples

```

```

## examples/solidity-audit-annotations.md

# Example: Solidity Audit Annotations

A worked example showing annotation discovery across a Solidity codebase with mixed tag
types. Demonstrates both grep and tree-sitter output, tag filtering, and table format.

## Sample Source

Imagine a Solidity codebase with these annotated files:

**src/Vault.sol:**
```solidity
contract Vault {
    // @audit-high unchecked arithmetic in deposit calculation
    function deposit(uint256 amount) external {
        balances[msg.sender] += amount;
    }

    // @audit-ok checked: reentrancy guard present via modifier
    function withdraw(uint256 amount) external nonReentrant {
        require(balances[msg.sender] >= amount);
        balances[msg.sender] -= amount;
        (bool ok, ) = msg.sender.call{value: amount}("");
        require(ok);
    }

    // @audit-todo verify fee calculation matches whitepaper spec
    function calculateFee(uint256 amount) internal view returns (uint256) {
        return amount * feeRate / 10000;
    }
}
```

**src/Oracle.sol:**
```solidity
contract PriceOracle {
    // @audit-med stale price check uses 1 hour — is this too generous?
    function getPrice(address token) external view returns (uint256) {
        require(block.timestamp - lastUpdate[token] < 1 hours);
        return prices[token];
    }

    // @audit can this be manipulated via flash loan?
    function updatePrice(address token, uint256 price) external onlyReporter {
        prices[token] = price;
        lastUpdate[token] = block.timestamp;
    }
}
```

## Invocation — All Annotations

```bash
python3 skills/annotation/scripts/find-annotations.py ./src
```

### JSON Output (with tree-sitter)

```json
[
  {
    "file": "Vault.sol",
    "line": 2,
    "tag": "audit-high",
    "content": "unchecked arithmetic in deposit calculation",
    "context_type": "contract",
    "context_name": "Vault"
  },
  {
    "file": "Vault.sol",
    "line": 7,
    "tag": "audit-ok",
    "content": "checked: reentrancy guard present via modifier",
    "context_type": "contract",
    "context_name": "Vault"
  },
  {
    "file": "Vault.sol",
    "line": 15,
    "tag": "audit-todo",
    "content": "verify fee calculation matches whitepaper spec",
    "context_type": "function",
    "context_name": "calculateFee"
  },
  {
    "file": "Oracle.sol",
    "line": 2,
    "tag": "audit-med",
    "content": "stale price check uses 1 hour — is this too generous?",
    "context_type": "contract",
    "context_name": "PriceOracle"
  },
  {
    "file": "Oracle.sol",
    "line": 8,
    "tag": "audit",
    "content": "can this be manipulated via flash loan?",
    "context_type": "function",
    "context_name": "updatePrice"
  }
]
```

### JSON Output (grep fallback — no tree-sitter)

Same structure, but `context_type` and `context_name` are `"unknown"` for every entry:

```json
[
  {
    "file": "Vault.sol",
    "line": 2,
    "tag": "audit-high",
    "content": "unchecked arithmetic in deposit calculation",
    "context_type": "unknown",
    "context_name": "unknown"
  }
]
```

## Invocation — Filter by Tag

Find only high-severity annotations:

```bash
python3 skills/annotation/scripts/find-annotations.py ./src --tag audit-high
```

```json
[
  {
    "file": "Vault.sol",
    "line": 2,
    "tag": "audit-high",
    "content": "unchecked arithmetic in deposit calculation",
    "context_type": "contract",
    "context_name": "Vault"
  }
]
```

## Invocation — Table Format

```bash
python3 skills/annotation/scripts/find-annotations.py ./src --format table
```

```
FILE                                      LINE  TAG             CONTEXT                        CONTENT
------------------------------------------------------------------------------------------------------------------------
Vault.sol                                    2  audit-high      contract:Vault                 unchecked arithmetic in deposit calculation
Vault.sol                                    7  audit-ok        contract:Vault                 checked: reentrancy guard present via modifier
Vault.sol                                   15  audit-todo      function:calculateFee          verify fee calculation matches whitepaper spec
Oracle.sol                                   2  audit-med       contract:PriceOracle           stale price check uses 1 hour — is this too gen...
Oracle.sol                                   8  audit           function:updatePrice            can this be manipulated via flash loan?

Total: 5 annotation(s)
```

## Design Choices

- **One annotation per line.** Multi-line comments produce one entry at the line containing the `@audit` tag. The agent can read surrounding lines from the file if more context is needed.
- **Tag filtering is exact match.** `--tag audit` matches only bare `@audit`, not `@audit-high`. Run without `--tag` to get everything, then filter programmatically if needed.
- **Tree-sitter resolves to the innermost scope.** An annotation inside `calculateFee` within `Vault` reports `function:calculateFee`, not `contract:Vault`. Annotations at contract level (outside any function) report the contract.
- **Grep fallback is intentionally simple.** It may pick up `@audit` inside string literals. This is acceptable — agents can verify by reading the actual source line.

## references

```

```

## references/annotation-format.md

# Annotation Format

Reference for `@audit` annotation types, the JSON output schema, and the two-tier
language support model.

## Annotation Types

| Tag | Meaning | When to use |
|-----|---------|-------------|
| `@audit` | General annotation | Comments, questions, observations, anything worth flagging |
| `@audit-ok` | Checked — not an issue | Code verified safe for a specific concern; documents due diligence |
| `@audit-info` | Informational finding | Design note or non-security observation worth reporting |
| `@audit-low` | Low severity finding | Minor issue with limited impact |
| `@audit-med` | Medium severity finding | Meaningful issue requiring attention |
| `@audit-high` | High severity finding | Serious vulnerability with significant impact |
| `@audit-crit` | Critical severity finding | Exploitable vulnerability with severe impact |
| `@audit-todo` | Action item | Something to investigate, verify, or follow up on |
| `@audit-<custom>` | User-defined tag | Any `@audit-` prefix followed by a word — the taxonomy is extensible |

The regex pattern `@audit(?:-([\w]+))?` matches all of these, including custom tags.

## JSON Output Schema

The script outputs a JSON array. Each element has these fields:

```json
{
  "file": "src/vault/Vault.sol",
  "line": 42,
  "tag": "audit-high",
  "content": "unchecked arithmetic in balance calculation",
  "context_type": "function",
  "context_name": "calculateBalance"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `file` | string | Path relative to the scanned directory |
| `line` | integer | 1-indexed line number |
| `tag` | string | Tag without the `@` prefix — `audit`, `audit-ok`, `audit-high`, etc. |
| `content` | string | Text following the tag on the same line (comment-closing tokens stripped) |
| `context_type` | string | Enclosing scope type or `"unknown"` if grep-scanned |
| `context_name` | string | Enclosing scope name or `"unknown"` if grep-scanned |

## Context Resolution

**Grep tier (all languages):** Finds annotations reliably but cannot resolve the enclosing
scope. Both `context_type` and `context_name` are `"unknown"`. May produce false positives
if `@audit` appears inside string literals rather than comments.

**Tree-sitter tier (Rust and Solidity):** Parses the file into an AST and only matches
annotations inside comment nodes — no false positives from strings. Walks up the AST to
find the innermost enclosing scope:

| Language | Supported context types |
|----------|------------------------|
| Rust | `function`, `impl`, `trait`, `module` |
| Solidity | `function`, `modifier`, `constructor`, `contract`, `library`, `interface` |

If tree-sitter dependencies are not installed, Rust and Solidity files are scanned with the
grep fallback automatically. Install dependencies from `scripts/requirements.txt` for full
context resolution.

## File Filtering

The scanner skips:

- Directories: `.git`, `node_modules`, `target`, `build`, `out`, `dist`, `__pycache__`, `.venv`, `venv`
- Binary file extensions: images, archives, compiled artifacts, lock files
- Files larger than 1 MB

## scripts

```

```

## scripts/find-annotations.py

```python

```

## scripts/main.py

```python

```

## scripts/pyproject.toml

```toml

```

## scripts/requirements.txt

```

```

