Skip to content
Merged
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
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

> **Before an AI writes a new class/id/function, CodeLens must be checked. This is not optional.**

CodeLens is an AI-native code intelligence platform that gives AI agents **full visibility** into a codebase before they write any code. It prevents collision, overwrite of existing logic, security vulnerabilities, and dead code through 73 CLI commands, an MCP server with 71 tools (55 static + 16 dynamic), AST-based taint analysis, live CVE/OSV scanning, a plugin system with OWASP Top 10 + Compliance rule packs, a true graph data model (nodes + edges) for structural code queries, and token-efficient `--format compact` output for high-volume agent workflows (issue #17).
CodeLens is an AI-native code intelligence platform that gives AI agents **full visibility** into a codebase before they write any code. It prevents collision, overwrite of existing logic, security vulnerabilities, and dead code through 70 CLI commands, an MCP server with 68 tools (55 static + 13 dynamic), AST-based taint analysis, live CVE/OSV scanning, a plugin system with OWASP Top 10 + Compliance rule packs, a true graph data model (nodes + edges) for structural code queries, and token-efficient `--format compact` output for high-volume agent workflows (issue #17).

## Features

- **73 CLI Commands** — From basic scan/query to AST taint analysis, CVE scanning, plugin management, auto-fix, dashboards, CI/CD quality gates, and `graph-schema` for cheap graph-shape introspection
- **MCP Server (71 Tools)** — Native AI agent integration via Model Context Protocol (JSON-RPC over stdio), 55 statically-defined tools + 16 dynamically discovered, every tool accepts a `format` parameter (`json`/`markdown`/`ai`/`sarif`/`compact`)
- **70 CLI Commands** — From basic scan/query to AST taint analysis, CVE scanning, plugin management, auto-fix, dashboards, CI/CD quality gates, and `graph-schema` for cheap graph-shape introspection
- **MCP Server (68 Tools)** — Native AI agent integration via Model Context Protocol (JSON-RPC over stdio), 55 statically-defined tools + 13 dynamically discovered, every tool accepts a `format` parameter (`json`/`markdown`/`ai`/`sarif`/`compact`)
- **Token-Efficient Compact Output (v8.2, issue #17)** — `--format compact` produces single-char-key JSON with abbreviated types, omitted null fields, and relative paths — ~50% smaller than `json` on real trace output. Combined with `--limit`/`--offset` pagination, 5 structural queries now cost <5k tokens (down from 30-80k)
- **AST Taint Engine** — Tree-sitter based taint analysis with return-value propagation, scope hierarchy, and branch condition refinement
- **Live CVE/OSV Scanning** — Real-time vulnerability data from OSV.dev API with SQLite cache, 9 ecosystems (PyPI, npm, crates.io, Go, Maven, NuGet, RubyGems, Pub, Hex)
Expand Down Expand Up @@ -225,8 +225,8 @@ codelens/
│ ├── changelog.md # Older changelog (per-version highlights)
│ └── agent-integration.md # AI agent integration guide
├── scripts/
│ ├── codelens.py # CLI entry point (73 commands registered)
│ ├── mcp_server.py # MCP JSON-RPC server (71 tools)
│ ├── codelens.py # CLI entry point (70 commands registered)
│ ├── mcp_server.py # MCP JSON-RPC server (68 tools)
│ ├── registry.py # Registry read/write/build
│ ├── persistent_registry.py # SQLite persistent storage (WAL mode)
│ ├── base_parser.py # Base tree-sitter parser
Expand Down
10 changes: 5 additions & 5 deletions SKILL-QUICK.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ $CLI list --limit 5 --offset 10 --format compact # → paginated + co
| "Cross-file taint" | `dataflow` | `taint` (taint is single-file, AST-deep) |
| "Auto-fix issues" | `fix` | `check` (check just gates, doesn't fix) |

## All 73 Commands
## All 70 Commands

### Setup & Lifecycle (8+)
`init` · `scan [--incremental] [--max-files N] [--full]` · `registry-validate` · `detect` · `watch [--debounce SECS] [--git-mode] [--interval SECS]` · `git-status` · `migrate` · `serve` · `lsp-status` (issue #33: `codelens --lsp-status` top-level flag is an alias of `codelens lsp-status` — both delegate to `hybrid_engine.get_lsp_status()` and return the identical payload)
Expand Down Expand Up @@ -147,19 +147,19 @@ $CLI list --limit 5 --offset 10 --format compact # → paginated + co
### Tooling (1)
`plugin <install|list|search|update|info|validate>`

**Total: 73 commands** (auto-registered via `commands/__init__.py`; rerun `python3 scripts/sync_command_count.py --apply` after adding/removing a command)
**Total: 70 commands** (auto-registered via `commands/__init__.py`; rerun `python3 scripts/sync_command_count.py --apply` after adding/removing a command)

## MCP Server (71 Tools)
## MCP Server (68 Tools)

Start the MCP server for AI agent integration:

```bash
python3 scripts/codelens.py serve
```

Exposes 71 tools as `codelens_<command>` (e.g., `codelens_query`, `codelens_taint`, `codelens_graph_schema`, `codelens_architecture`, `codelens_resolve_types`, `codelens_git_status`):
Exposes 68 tools as `codelens_<command>` (e.g., `codelens_query`, `codelens_taint`, `codelens_graph_schema`, `codelens_architecture`, `codelens_resolve_types`, `codelens_git_status`):
- 50 statically-defined tools (full JSON schemas in `mcp_server.py`)
- 16 dynamically-discovered tools (auto-discovered from `COMMAND_REGISTRY`; long-running `watch` and `serve` are excluded)
- 13 dynamically-discovered tools (auto-discovered from `COMMAND_REGISTRY`; long-running `watch` and `serve` are excluded)
- Every tool accepts a `format` parameter (`json`/`markdown`/`ai`/`sarif`/`compact`). Use `format: "compact"` for token-efficient responses (~50% smaller than `json`).
- `watch` and `serve` itself are excluded (long-running)

Expand Down
4 changes: 2 additions & 2 deletions SKILL.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
name: codelens
description: >
CodeLens — AI-Native Code Intelligence. 73 commands for AI-powered code analysis,
CodeLens — AI-Native Code Intelligence. 70 commands for AI-powered code analysis,
security auditing, quality scoring, AST-based taint analysis, live CVE scanning,
and pre-write safety checks. Supports 28+ languages with tree-sitter + regex
fallback parsing. MCP server exposes 71 tools for AI agent integration.
fallback parsing. MCP server exposes 68 tools for AI agent integration.
For quick command reference with validated output schemas, see SKILL-QUICK.md.
For version history, see CHANGELOG.md.
---
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "codelens"
version = "8.2.0"
description = "Live Codebase Reference Intelligence — 73 commands for AI-powered code analysis, security auditing, and quality scoring"
description = "Live Codebase Reference Intelligence — 70 commands for AI-powered code analysis, security auditing, and quality scoring"
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.8"
Expand Down
85 changes: 85 additions & 0 deletions scripts/commands/query_graph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# @WHO: scripts/commands/query_graph.py
# @WHAT: Cypher-subset graph query CLI command (issue #9)
# @PART: commands
# @ENTRY: execute()
"""query-graph command — Cypher-subset graph query (issue #9).

Agents currently must chain multiple MCP tools (trace → impact → context) to
answer structural questions. This command accepts an openCypher-subset query
and returns matching nodes/edges in one call — replacing 3-5 tool calls.

Supported subset (MVP):
MATCH (var:Label)-[:EDGE_TYPE]->(var2)
WHERE var.property = 'value'
WHERE var.name CONTAINS 'substr'
WHERE var.file IS NULL
WHERE NOT EXISTS { ()-[:CALLS]->(var) } -- dead code
RETURN var.name, var2.file
LIMIT 10

Usage::

codelens query-graph "MATCH (f:Function)-[:CALLS]->(g) WHERE f.name = 'handleRequest' RETURN g.name, g.file"
codelens query-graph "MATCH (f:Function) WHERE NOT EXISTS { ()-[:CALLS]->(f) } RETURN f.name" --limit 50
codelens query-graph "MATCH (c:Class)-[:INHERITS]->(p:Class) RETURN c.name, p.name"

The query language is read-only (no CREATE/DELETE/MERGE). See
:mod:`query_graph_engine` for the grammar and supported clauses.
"""

from __future__ import annotations

from typing import Any, Dict

from commands import register_command


def add_args(parser):
"""Add query-graph arguments to the parser."""
parser.add_argument(
"query",
help=(
"Cypher-subset query. Must start with MATCH. "
"Example: \"MATCH (f:Function)-[:CALLS]->(g) WHERE f.name = 'handleRequest' RETURN g.name\""
),
)
parser.add_argument("workspace", nargs="?", default=None,
help="Path to workspace root (auto-detected if omitted)")
parser.add_argument("--db-path", default=None,
help="Custom path for SQLite database file")
parser.add_argument("--limit", type=int, default=None,
help="Max results to return (overrides LIMIT in query if set)")
parser.add_argument("--validate", action="store_true",
help="Validate query syntax without executing it")


def execute(args, workspace):
"""Execute the query-graph command."""
db_path = getattr(args, "db_path", None)
query = args.query

# If --limit is passed on CLI, append it to the query (CLI limit overrides
# query LIMIT for convenience — agents can use either).
cli_limit = getattr(args, "limit", None)
if cli_limit is not None:
# Strip any existing LIMIT from the query, then append CLI limit.
# This is a simple approach — the parser will handle the final LIMIT.
import re
query = re.sub(r"\s+LIMIT\s+\d+\s*$", "", query, flags=re.IGNORECASE)
query = f"{query.rstrip()} LIMIT {cli_limit}"

# --validate: check syntax only, don't touch the DB
if getattr(args, "validate", False):
from query_graph_engine import validate_query
return validate_query(query)

from query_graph_engine import execute_query
return execute_query(query, workspace, db_path=db_path)


register_command(
"query-graph",
"Query the code graph with a Cypher-subset query (MATCH/WHERE/RETURN/LIMIT)",
add_args,
execute,
)
2 changes: 1 addition & 1 deletion scripts/graph_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
- New tables `graph_nodes` and `graph_edges` are additive (prefixed `graph_`
to avoid colliding with any existing table name).
- The flat registry tables and JSON files are untouched.
- All 73 existing CLI commands continue to work unchanged.
- All 70 existing CLI commands continue to work unchanged.

Schema:
graph_nodes(
Expand Down
67 changes: 25 additions & 42 deletions scripts/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1133,18 +1133,20 @@
"required": ["workspace"]
}
},
"manage-adr": {
"query-graph": {
"description": (
"Architecture Decision Records (ADR) manager — persistent memory "
"of *why* the codebase is structured the way it is, so agents "
"don't propose refactors that violate intentional constraints. "
"Backed by SQLite at .codelens/adrs.db. Actions: "
"create <title> [context] [decision] [status], "
"list [status_filter], get <id>, "
"update <id> [title] [context] [decision] [status], "
"deprecate <id> [superseded_by], delete <id>. "
"Statuses: proposed (default), accepted, deprecated, rejected. "
"Prefer 'deprecate' over 'delete' to preserve history."
"Query the code graph with a Cypher-subset query (issue #9). "
"Replaces 3-5 chained trace/impact/context calls with one "
"expressive query. Read-only — safe for CI. "
"Supported: MATCH (var:Label)-[:EDGE_TYPE]->(var2), "
"WHERE var.prop = 'val' / CONTAINS / IS NULL / NOT EXISTS { pattern }, "
"RETURN var.prop, LIMIT n. "
"Labels: function, class, file, module, route, type, interface. "
"Edge types: CALLS, IMPORTS, DEFINES, INHERITS, IMPLEMENTS, USES_TYPE. "
"Examples: "
"\"MATCH (f:Function)-[:CALLS]->(g) WHERE f.name = 'handleRequest' RETURN g.name, g.file\"; "
"\"MATCH (f:Function) WHERE NOT EXISTS { ()-[:CALLS]->(f) } RETURN f.name\" (dead code); "
"\"MATCH (c:Class)-[:INHERITS]->(p:Class) RETURN c.name, p.name\"."
),
"parameters": {
"type": "object",
Expand All @@ -1153,43 +1155,24 @@
"type": "string",
"description": "Path to workspace root directory"
},
"action": {
"query": {
"type": "string",
"enum": ["create", "list", "get", "update", "deprecate", "delete"],
"description": "ADR action to perform"
"description": (
"Cypher-subset query. Must start with MATCH. "
"Example: \"MATCH (f:Function)-[:CALLS]->(g) WHERE f.name = 'handleRequest' RETURN g.name, g.file\""
),
},
"id": {
"limit": {
"type": "integer",
"description": "ADR id (required for get/update/deprecate/delete). Positive integer."
},
"title": {
"type": "string",
"description": "Short title (required for create, optional for update). E.g. 'Use SQLite over PostgreSQL'."
},
"context": {
"type": "string",
"description": "Background and constraints driving the decision (optional for create/update)."
"description": "Max results to return (overrides LIMIT in query if set). Default: no limit.",
},
"decision": {
"type": "string",
"description": "The decision itself — what was chosen and why (optional for create/update)."
},
"status": {
"type": "string",
"enum": ["proposed", "accepted", "deprecated", "rejected"],
"description": "ADR status. Default for create is 'proposed'."
},
"superseded_by": {
"type": "integer",
"description": "Id of the replacement ADR (optional, for deprecate action). Must exist and differ from id."
"validate": {
"type": "boolean",
"description": "Validate query syntax without executing it (default: False).",
"default": False,
},
"status_filter": {
"type": "string",
"enum": ["proposed", "accepted", "deprecated", "rejected"],
"description": "Filter list action by status (optional)."
}
},
"required": ["workspace", "action"]
"required": ["workspace", "query"]
}
},
}
Expand Down
Loading
Loading