Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .github/workflows/require-design-doc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Require Design Doc

# CI check for issue #67 Phase 1: any PR that adds a feature-class file
# (new CLI command, new parser, new engine, new MCP hook) MUST also add:
# - at least one new .md under docs/design/
# - at least one new .md under docs/plans/
#
# Exemptions:
# - PRs labeled: skip-design-doc, bug, chore, dependencies, refactor,
# documentation, test
# - PRs that do not add any feature-class file
#
# The actual logic lives in scripts/check_design_doc.py. This workflow
# just wires up the GitHub events and passes PR metadata (labels) to the
# script via environment variables.

on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
# Run on any PR targeting main. The script is a no-op if no
# feature-class files are added, so we don't need path filters.

permissions:
contents: read
pull-requests: read

jobs:
check-design-doc:
runs-on: ubuntu-latest
if: github.repository == 'Wolfvin/CodeLens'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # need full history for git diff vs base

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Fetch base branch
run: |
# The pull_request event gives us github.event.pull_request.base.ref
# but the local clone only has the PR head. Fetch the base so the
# diff works.
git fetch origin "${{ github.event.pull_request.base.ref }}"

- name: Run design-doc check
env:
# Pass PR labels to the script as a comma-separated string.
# The script reads GITHUB_PR_LABELS and applies exemptions.
GITHUB_PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }}
run: |
python3 scripts/check_design_doc.py \
--base "origin/${{ github.event.pull_request.base.ref }}" \
--head HEAD \
--repo-root .

- name: Annotate PR on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: [
'## Design doc check failed',
'',
'This PR adds feature-class file(s) but is missing the required design and/or plan documentation.',
'',
'See the error in the **Require Design Doc** workflow run for details, or read [`docs/design/README.md`](https://github.com/Wolfvin/CodeLens/blob/main/docs/design/README.md) and [`CONTRIBUTING.md`](https://github.com/Wolfvin/CodeLens/blob/main/CONTRIBUTING.md#design-documents--implementation-plans) for the policy.',
'',
'If this PR is genuinely too small to warrant a design doc (e.g., adding a single flag to an existing command), apply the `skip-design-doc` label and explain why in the PR description.',
].join('\n')
});
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [8.2.0] — Unreleased

### Design Document & Implementation Plan Convention (issue #67 Phase 1)

CodeLens now has a convention for capturing design decisions and
implementation plans as Markdown files in the repo, enforced by CI.

**What's new:**

- `docs/design/template.md` — template for design docs (Problem, Goal,
Changes, Trade-offs, Open Questions, Findings).
- `docs/plans/template.md` — template for implementation plans
(phase-based checklist with acceptance criteria).
- `docs/design/README.md`, `docs/plans/README.md` — usage guides for
both directories.
- Four backfilled design docs for features that shipped before the
convention existed:
- `docs/design/taint-engine.md` — AST taint analysis (issue #49)
- `docs/design/mcp-server.md` — MCP server architecture
- `docs/design/plugin-system.md` — Plugin system
- `docs/design/graph-model.md` — SQLite graph model (v8.2)
- `scripts/check_design_doc.py` — CI check that enforces the
requirement. A PR that adds any new file matching
`scripts/commands/<name>.py`, `scripts/parsers/<name>_parser.py`,
`scripts/<name>_engine.py`, or `scripts/mcp_hooks/<name>.py` MUST
also add at least one new `.md` under `docs/design/` AND one under
`docs/plans/`. Template and README files do NOT count.
- `.github/workflows/require-design-doc.yml` — GitHub Actions workflow
that runs the check on every PR (opened, synchronized, reopened,
labeled, unlabeled). Posts a comment on the PR explaining how to
fix the failure.
- `CONTRIBUTING.md` — new "Design Documents & Implementation Plans"
section documenting the requirement, exemptions, and how to run the
check locally.
- `tests/test_check_design_doc.py` — full test coverage for the
check script, including end-to-end tests with a real temp git repo.

**Exemptions:** PRs labeled `skip-design-doc`, `bug`, `chore`,
`dependencies`, `refactor`, `documentation`, or `test` are exempt.
PRs that do not add any feature-class file are also exempt (no-op).

**Scope note:** This is Phase 1 only. Phase 2 (VitePress homepage at
`codelens.dev`) and Phase 3 (live demo with interactive dashboard)
remain open — they are multi-week content projects tracked in issue
#67.

### LSP Status Entry-Point Unification (issue #33)

The `codelens --lsp-status` top-level flag (intercepted in
Expand Down
84 changes: 78 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,87 @@ CodeLens uses a modular engine architecture. To add a new analysis capability:

1. **Check existing issues** for similar proposals
2. **Decide: plugin or built-in?** — Since v8.0, CodeLens supports plugins (rule_pack / engine / formatter / command). If your analysis is self-contained, ship it as a plugin (see `scripts/plugin_system.py`). If it needs tight integration with the registry or other engines, add it as built-in.
3. **For built-in engines**: Follow the naming convention `yourfeature_engine.py`
4. **Implement the engine** following the pattern of existing engines (return `{status, workspace, findings, summary}`)
5. **Add a command module** in `commands/yourfeature.py` with `add_args(subparser)` and `execute(args)` functions
6. **Add tests** in `tests/`
7. **Sync command counts** — see "Syncing Command Counts" below; do NOT hand-edit the count in `README.md`, `SKILL.md`, `SKILL-QUICK.md`, `pyproject.toml`, `skill.json`, or `scripts/mcp_server.py`
8. **Update documentation** in `SKILL.md`, `SKILL-QUICK.md`, `README.md`, and `CHANGELOG.md`
3. **Write a design doc** — see [Design Documents & Implementation Plans](#design-documents--implementation-plans) below. The CI check enforces this for any PR that adds a feature-class file.
4. **For built-in engines**: Follow the naming convention `yourfeature_engine.py` (top-level file under `scripts/`)
5. **Implement the engine** following the pattern of existing engines (return `{status, workspace, findings, summary}`)
6. **Add a command module** in `commands/yourfeature.py` with `add_args(subparser)` and `execute(args)` functions
7. **Add tests** in `tests/`
8. **Sync command counts** — see "Syncing Command Counts" below; do NOT hand-edit the count in `README.md`, `SKILL.md`, `SKILL-QUICK.md`, `pyproject.toml`, `skill.json`, or `scripts/mcp_server.py`
9. **Update documentation** in `SKILL.md`, `SKILL-QUICK.md`, `README.md`, and `CHANGELOG.md`

Commands auto-register via `commands/__init__.py` — no manual wiring needed.

### Design Documents & Implementation Plans

Any PR that adds a **feature-class** file MUST also add a design doc and an
implementation plan. This is enforced by the
`Require Design Doc` GitHub Actions workflow (see
`.github/workflows/require-design-doc.yml`).

#### What counts as a feature-class file?

A PR is feature-class if it adds any new file matching one of these patterns:

| Pattern | Meaning |
|---|---|
| `scripts/commands/<name>.py` | New CLI command |
| `scripts/parsers/<name>_parser.py` | New tree-sitter language parser |
| `scripts/<name>_engine.py` | New top-level analysis engine |
| `scripts/mcp_hooks/<name>.py` | New MCP hook |

`__init__.py` files, fallback parsers (`fallback_<lang>.py`), test files, and
pure docs changes are NOT feature-class.

#### What do I need to add?

For a feature-class PR, add **both**:

1. **A design doc** at `docs/design/<feature>.md`
- Copy `docs/design/template.md` and fill in the sections.
- The design doc captures WHY the feature exists and WHAT trade-offs were
considered. It is the record of decisions, not a tutorial.
2. **An implementation plan** at `docs/plans/<feature>.md`
- Copy `docs/plans/template.md` and fill in the phases.
- Each phase should be independently mergeable. If a phase has more than
~10 files or ~500 lines, split it.

The CI check (script: `scripts/check_design_doc.py`) verifies both files
exist. `template.md` and `README.md` do NOT count — you must add a
feature-specific doc.

#### Exemptions

If your PR is feature-class by the file pattern but the change is genuinely
too small to warrant a full design doc (e.g., adding a single flag to an
existing command, or restoring a previously-removed command), apply the
`skip-design-doc` label to the PR and explain why in the PR description.

Other labels that exempt a PR from the requirement: `bug`, `chore`,
`dependencies`, `refactor`, `documentation`, `test`.

#### Running the check locally

Before pushing:

```bash
# From repo root, with your feature branch checked out:
python3 scripts/check_design_doc.py --base origin/main --head HEAD
```

Exit code 0 = compliant, 1 = missing docs. The script is the same one CI
runs, so a local pass guarantees a CI pass (assuming labels match).

#### Existing design docs

Backfilled design docs for features that shipped before this convention:

- [`docs/design/taint-engine.md`](docs/design/taint-engine.md) — AST taint analysis (issue #49)
- [`docs/design/mcp-server.md`](docs/design/mcp-server.md) — MCP server architecture
- [`docs/design/plugin-system.md`](docs/design/plugin-system.md) — Plugin system
- [`docs/design/graph-model.md`](docs/design/graph-model.md) — SQLite graph model

Use these as examples of the expected depth and tone.

### Syncing Command Counts (issue #38)

The number of CLI commands and MCP tools must never be hand-edited in
Expand Down
45 changes: 45 additions & 0 deletions docs/design/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Design Documents

This directory holds **design docs** for CodeLens features. A design doc
captures WHY a feature exists and WHAT trade-offs were considered — it is the
record of decisions, not a tutorial.

## When is a design doc required?

A PR that adds a new feature to CodeLens MUST include a design doc. The CI
check in `.github/workflows/require-design-doc.yml` enforces this.

A PR is "feature-class" if it adds any new file under:

- `scripts/commands/` (new CLI command)
- `scripts/parsers/` (new language parser)
- `scripts/*_engine.py` (new analysis engine — top-level files only)
- `scripts/mcp_hooks/` (new MCP hook)

Bug fixes, refactors, dependency bumps, and pure docs changes are exempt. If
your PR is feature-class but the change is genuinely too small for a full
design doc (e.g., adding a single flag to an existing command), apply the
`skip-design-doc` label and explain why in the PR description.

## How to use the template

1. Copy `template.md` to `<feature-name>.md` (kebab-case, e.g.
`cross-file-taint.md`).
2. Fill in every section. If a section does not apply, write "N/A — <reason>"
rather than deleting it.
3. Link the design doc from your PR description.
4. Also create a corresponding implementation plan in
[`../plans/`](../plans/) — the CI check requires both.
5. After the PR merges, update the `Findings` section with a 1-paragraph
retrospective. Do NOT delete the design doc.

## Existing design docs

| Doc | Feature | Issue | PR | Status |
|---|---|---|---|---|
| [`taint-engine.md`](./taint-engine.md) | Taint analysis engine (cross-file unification, `ast_taint_engine.analyze_workspace`) | #49 | #140 | Accepted |
| [`mcp-server.md`](./mcp-server.md) | MCP server architecture (JSON-RPC over stdio, 61 tools) | — | — | Backfill |
| [`plugin-system.md`](./plugin-system.md) | Plugin system (4 types: rule_pack, engine, formatter, command) | — | — | Backfill |
| [`graph-model.md`](./graph-model.md) | SQLite graph model (`graph_nodes` + `graph_edges` schema) | — | — | Backfill |

When you add a new design doc, add a row to this table.
Loading
Loading