First off, thank you for considering contributing to CodeLens! It's people like you that make CodeLens such a great tool.
This project and everyone participating in it is governed by our Code of Conduct. By participating, you are expected to uphold this code.
Before creating bug reports, please check the existing issues as you might find that the issue has already been reported. When you create a bug report, include as many details as possible:
- Use a clear and descriptive title
- Describe the exact steps to reproduce the problem
- Provide specific examples (sample code, workspace structure)
- Describe the behavior you observed and the behavior you expected
- Include the full command and output
- Include your environment: OS, Python version, tree-sitter version
Enhancement suggestions are tracked as GitHub issues. When creating an enhancement suggestion:
- Use a clear and descriptive title
- Provide a step-by-step description of the suggested enhancement
- Provide specific examples demonstrating how it would be used
- Describe the current behavior and explain the expected behavior
- Explain why this enhancement would be useful to most CodeLens users
CodeLens uses a modular engine architecture. To add a new analysis capability:
- Check existing issues for similar proposals
- 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. - For built-in engines: Follow the naming convention
yourfeature_engine.py - Implement the engine following the pattern of existing engines (return
{status, workspace, findings, summary}) - Add a command module in
commands/yourfeature.pywithadd_args(subparser)andexecute(args)functions - Add tests in
tests/ - 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, orscripts/mcp_server.py - Update documentation in
SKILL.md,SKILL-QUICK.md,README.md, andCHANGELOG.md
Commands auto-register via commands/__init__.py — no manual wiring needed.
The number of CLI commands and MCP tools must never be hand-edited in
documentation or metadata files — it drifts every time a command is added or
removed. The single source of truth is the runtime COMMAND_REGISTRY (and
_TOOL_DEFINITIONS for MCP static tools). The scripts/sync_command_count.py
helper propagates the runtime count into every doc/metadata file.
When you add or remove a command:
# 1. Run the sync helper in --check mode to see what would change:
PYTHONPATH=scripts python3 scripts/sync_command_count.py --check
# 2. Apply the changes:
PYTHONPATH=scripts python3 scripts/sync_command_count.py --apply
# 3. Update the strict regression sentinel in tests/test_integration.py
# (TestModuleStructure.test_command_registry_has_all_commands)
# to match the new len(COMMAND_REGISTRY). This is the ONE place where
# the count is intentionally hardcoded — it is the regression anchor.
# 4. Verify:
PYTHONPATH=scripts python3 -m pytest tests/test_command_count.py tests/test_integration.py::TestModuleStructure -vThe test suite enforces this in CI:
tests/test_command_count.py::test_all_docs_in_sync_with_command_registryfails if any doc/metadata file mentions a stale count.tests/test_integration.py::TestModuleStructure::test_command_registry_has_all_commandsfails iflen(COMMAND_REGISTRY)changes in either direction (strict==, not>=).
- Check tree-sitter support for the language
- Create
parsers/yourlanguage_parser.pyfollowing thebase_parser.pypattern (preferred for accuracy) - Always add a fallback regex parser in
parsers/fallback_yourlanguage.pyso the language works even without tree-sitter installed - Update file discovery in
commands/scan.pyto recognize the file extension - Update
setup.shto install the tree-sitter grammar (if applicable) - Update
framework_detect.pyif the language has framework markers worth detecting - Add tests with sample files in the target language
- Update
references/parser-rules.mdwith the new language's parsing rules - Update
README.mdsupported languages list
# Clone the repository
git clone https://github.com/Wolfvin/CodeLens.git
cd CodeLens
# Run setup
bash setup.sh
# Create a branch for your changes
git checkout -b feature/your-feature-name
# Run tests
python3 -m pytest tests/ -v
# Or run specific test file
python3 -m pytest tests/test_html_parser.py -v- Follow PEP 8 style guidelines
- Use type hints for all function signatures
- Use docstrings (triple-quoted) for all public functions and classes
- Keep functions focused — one function does one thing
- Maximum line length: 120 characters
Each engine follows this pattern:
"""
Engine Name for CodeLens — vX
Brief description of what the engine does.
Answers: "What question does this answer?"
"""
from typing import Dict, List, Any
def your_engine(workspace: str, **kwargs) -> Dict[str, Any]:
"""
Run the engine analysis.
Args:
workspace: Absolute path to workspace root
**kwargs: Engine-specific options
Returns:
Dict with structured results following the standard format:
{
"status": "ok",
"workspace": str,
"findings": [...],
"summary": {...}
}
"""
passWhen adding a new CLI command, create a new file in the commands/ directory:
- Create
commands/yourfeature.pywith two functions:add_args(subparser)— define argparse argumentsexecute(args)— run the command and return JSON
- The command auto-registers via
commands/__init__.py(no manual wiring) - Update
skill.jsonversion and description - Add a formatter in
formatters/if markdown output is needed
- Use graceful degradation — if tree-sitter fails, fall back to regex
- Never crash the CLI — always return structured JSON with error info
- Log warnings to stderr, not stdout
- Handle missing files, encoding errors, and permission issues
- Write tests for all new engines and parsers
- Use sample code fixtures in tests (not real codebases)
- Test edge cases: empty files, files with only comments, binary files
- Test error recovery: missing registry, corrupt JSON, missing tree-sitter
- Run the full test suite before submitting:
python3 -m pytest tests/ -v
- Update documentation — README.md, SKILL.md, SKILL-QUICK.md, changelog.md
- Add a design doc for new features (see "Design Doc Requirement" below)
- Add tests for new features
- Ensure all tests pass —
python3 -m pytest tests/ -v - Follow the PR template — describe changes, motivation, testing
- One PR per feature — keep PRs focused and reviewable
- Update skill.json version if adding new commands
PRs that add a new feature must include a design doc in docs/design/.
The CI check (.github/workflows/design-doc-check.yml) automatically
detects new-feature PRs by file pattern and fails if no design doc is
included.
What counts as a "new feature"?
| Pattern | Example | Requires design doc? |
|---|---|---|
New file in scripts/commands/ |
commands/yourfeature.py |
Yes |
New scripts/*_engine.py |
yourfeature_engine.py |
Yes |
New file in scripts/formatters/ |
formatters/yourformat.py |
Yes |
New parser (non-fallback) in scripts/parsers/ |
parsers/yourlang_parser.py |
Yes |
| Fallback parser | parsers/fallback_yourlang.py |
No (regex shadow of existing parser) |
| Bug fix (modified file) | any existing file | No |
| Test addition | tests/test_*.py |
No |
| Documentation change | *.md |
No |
How to write a design doc:
- Copy
docs/design/template.mdtodocs/design/NNNN-feature-name.mdNNNNis the next available number (zero-padded to 4 digits)feature-nameis a short kebab-case slug
- Fill in the sections: Problem, Goal, Changes, Trade-offs, Open Questions, Migration / Rollout
- The Trade-offs section is the most important — document alternatives considered and why they were rejected. This prevents future contributors from re-litigating decisions without context.
- See
docs/design/0001-taint-engine.mdthrough0004-graph-model.mdfor retroactive examples documenting existing features.
Bypassing the check:
If a feature is genuinely trivial (e.g., a one-line command alias) and a
design doc would be pure overhead, add the skip-design-doc label to the
PR. Use this sparingly — the check exists to ensure design decisions are
recorded for future contributors.
See docs/README.md for full details on the design doc and implementation
plan convention.
feat: add Python parser— New featurefix: handle empty CSS files— Bug fixdocs: update README— Documentationrefactor: simplify edge resolver— Refactoringtest: add Rust parser tests— Testschore: update dependencies— Maintenance
Maintainers follow this process:
- Update version in
scripts/utils.py(CODELENS_VERSIONconstant),skill.json, andpyproject.toml - Update
CHANGELOG.md(top-level) andreferences/changelog.md(per-version highlights) - Update
SKILL.md,SKILL-QUICK.md, andREADME.mdversion numbers - Tag release:
git tag v8.x.x - Push tag:
git push origin v8.x.x
Feel free to open a GitHub issue with the question label, or start a discussion in the Discussions tab.