diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e14a3e8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,15 @@ +# COCOA — dev guide + +Static system-graph engine. Package manager: `uv` (`uv sync --all-groups`). + +- Tests: `uv run pytest` (unit; integration/e2e/docker markers deselected by + default). `-m integration` runs a real cldk analyzer; `-m e2e` runs the Online + Boutique demo (network + analyzers; strict launch gate); `-m docker` builds and + smokes the image. +- Module map: `cocoa/system/` = engine (detect → driver → facts → stitch → + datastore → build → blast → topology → report/htmlmap); `cocoa/cli.py` = typer + CLI; `cocoa/server.py` + `cocoa/tools/` = MCP; `skills//commands/` = plugin + content (validated by `test/test_plugin_assets.py`). +- Provenance discipline is the product: never emit an edge without + `DERIVED-STATIC`/`INFERRED` tagging; skips are recorded, never silent. +- Conventional commits, no trailers. Branch-per-issue `feat/issue-NNN-`. diff --git a/README.md b/README.md index 0e492c1..0881ac7 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,72 @@ # COCOA — Code Context Agent -Precise static system graphs of polyglot, k8s-native codebases — code + RPC -topology + data access — for AI agents. Powered by [CLDK](https://github.com/codellm-devkit/python-sdk). +**Precise static system graphs of polyglot, k8s-native codebases — for AI agents.** -Status: v1 under construction. See issue #1 (epic). +Point COCOA at a repo and it derives one queryable graph of the whole system: +per-service call graphs, cross-service RPC edges (stitched from protos, call sites, +and k8s wiring), and datastore access — every edge tagged `DERIVED-STATIC` (real +static analysis, via [CLDK](https://github.com/codellm-devkit/python-sdk)) or +`INFERRED` (labeled fallback). Never guessed. + +> **Graphify indexes files. COCOA understands systems.** +> See the head-to-head: [docs/COMPARISON.md](docs/COMPARISON.md) + +## The hero query: blast radius + +```bash +cocoa blast -p . --target hipstershop.Money.units --kind proto-field +``` + +…returns exactly which functions in which services break — across languages, across +RPC boundaries, through the database — with call sites and provenance per hop. +On Google's Online Boutique (11 services, 5 languages), the answer costs ~1/25,000th +of the tokens an agent would burn reading every service (estimated; `cocoa demo` +prints the measurement). ## Quick start ```bash -uv run cocoa map -p /path/to/your/polyglot/repo # build .cocoa/ artifacts -uv run cocoa blast -p /path/to/repo --target hipstershop.Money.units --kind proto-field -uv run cocoa serve -p /path/to/repo # MCP server (5 system tools) -uv run cocoa demo # Online Boutique flagship demo +# no install (uv required): +uvx --from git+https://github.com/codellm-devkit/cocoa cocoa map -p /path/to/repo +uvx --from git+https://github.com/codellm-devkit/cocoa cocoa blast -p /path/to/repo \ + --target --kind + +# flagship demo (clones Online Boutique, maps it, blasts a proto field): +uvx --from git+https://github.com/codellm-devkit/cocoa cocoa demo + +# docker (all analyzers baked in, incl. the unreleased Go analyzer): +docker run --rm -v "$PWD:/work" ghcr.io/codellm-devkit/cocoa map -p /work ``` -Requires Docker-less local analyzers today: Java/Python/TypeScript run via CLDK -automatically; Go needs `codeanalyzer-go` on PATH (or pointed to via -`CODEANALYZER_GO_BIN`); C# is recorded as skipped until `codeanalyzer-dotnet` ships. +Agent setups (Claude Code plugin with skills + slash commands + MCP, Codex, Cursor, +plain MCP): [docs/INSTALL.md](docs/INSTALL.md). + +## What you get + +| Artifact | What it is | +|---|---| +| `.cocoa/system-graph.json` | the full graph — query it forever without re-reading source | +| `.cocoa/system-map.html` | self-contained interactive map, provenance-colored | +| `.cocoa/SYSTEM_REPORT.md` | services, topology, data access, dead-RPC candidates, and **every skipped service with its reason** | + +## Language & analyzer status (honest) + +| Language | Analyzer | Status | +|---|---|---| +| Java | codeanalyzer-java (via cldk) | works; clean pip installs need the jar workaround ([python-sdk#236](https://github.com/codellm-devkit/python-sdk/issues/236)) — the Docker image includes it | +| Python | codeanalyzer-python (via cldk) | works | +| JS/TS | codeanalyzer-typescript (via cldk) | works | +| Go | codeanalyzer-go | unreleased ([codeanalyzer-go#5](https://github.com/codellm-devkit/codeanalyzer-go/issues/5)); Docker image builds it from source; host installs need `codeanalyzer-go` on PATH or `$CODEANALYZER_GO_BIN` | +| C# | codeanalyzer-dotnet | pending ([codeanalyzer-dotnet#1](https://github.com/codellm-devkit/codeanalyzer-dotnet/issues/1)) — services are recorded as skipped, never silently dropped | + +## Skills (the agent discipline layer) + +The plugin ships four skills modeled on the +[obra/superpowers](https://github.com/obra/superpowers) paradigm: `using-cocoa` +(answer system questions from the graph, not file reads), `mapping-a-system`, +`blast-radius`, and `grounding-claims` — whose HARD-GATE is the product promise: +*never present an `INFERRED` edge as fact.* + +## License + +MIT. Built on [CodeLLM-DevKit](https://codellm-devkit.info). diff --git a/demo.tape b/demo.tape new file mode 100644 index 0000000..103f509 --- /dev/null +++ b/demo.tape @@ -0,0 +1,19 @@ +# Render with: vhs demo.tape → demo.gif +# +# RECORDING PROTOCOL: run `cocoa demo` once BEFORE recording so the fixture +# clone and per-service analysis caches are warm — the recorded run then +# completes in seconds instead of minutes and the GIF stays tight. Do NOT +# record a cold run: analysis time varies with toolchain availability and +# a fixed Sleep will truncate it. +Output demo.gif +Set FontSize 15 +Set Width 1200 +Set Height 640 +Set Theme "Catppuccin Mocha" + +Type "cocoa demo" +Enter +Sleep 25s +Type "cocoa blast -p ~/.cocoa/demo/microservices-demo-v0.10.5 --target hipstershop.Money.units --kind proto-field" +Enter +Sleep 10s diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md new file mode 100644 index 0000000..f3e7ca2 --- /dev/null +++ b/docs/COMPARISON.md @@ -0,0 +1,26 @@ +# COCOA vs. graphify + +[graphify](https://github.com/Graphify-Labs/graphify) popularized the "index your +repo into a queryable graph" workflow for AI agents — one-command setup, three +artifacts, token-efficient queries. COCOA adopts that exact UX and changes one +thing: **where the edges come from.** + +| | graphify | COCOA | +|---|---|---| +| Unit of understanding | a folder of files | a distributed system | +| Edge derivation | tree-sitter AST for code (deterministic); LLM inference for docs/PDFs/images | real analyzers (WALA, Jedi, ts-morph, go/types via CLDK) + proto/k8s stitching | +| Edge provenance | `EXTRACTED` / `INFERRED` / `AMBIGUOUS` | `DERIVED-STATIC` / `INFERRED` (labeled fallback only) | +| Cross-language links | inferred by the model | derived: proto stubs ↔ handlers ↔ k8s wiring, with anchor-exclusivity and boundary-matching to prevent false edges | +| Databases | absent | first-class: Redis ops, SQL tables, ORM mappings as graph nodes/edges | +| k8s manifests | more files in the graph | a topology source (raw YAML + `helm template` + `kustomize build`) | +| Impact queries | neighborhood lookups | cross-service blast radius with strongest-path provenance semantics | +| Coverage honesty | n/a | every unanalyzed service recorded with a reason; truncation always labeled | +| Artifacts | `graph.json` / `graph.html` / `GRAPH_REPORT.md` | `system-graph.json` / `system-map.html` / `SYSTEM_REPORT.md` | +| Token efficiency | ~1.7k/query vs ~123k naive (their number) | same persisted-graph mechanism; `cocoa demo` measures ~25,000× on Online Boutique (estimate, printed per run) | + +The trade: graphify covers 36 grammars and multi-modal inputs (docs, PDFs, images) +today; COCOA covers the languages with real analyzers (Java/Python/JS/TS shipped, +Go built-from-source in Docker, C# pending) and only code + configs. If you need +breadth-first repo Q&A, graphify is excellent. If an agent is about to *change* a +distributed system and needs to know what breaks — edges that are derived, labeled, +and complete-or-disclosed matter. That's COCOA. diff --git a/docs/INSTALL.md b/docs/INSTALL.md new file mode 100644 index 0000000..9796753 --- /dev/null +++ b/docs/INSTALL.md @@ -0,0 +1,54 @@ +# Installing COCOA + +COCOA is one Python package (`cocoa` CLI + MCP server) plus a skillset plugin. +Until the PyPI name is freed (tracked in cocoa-mcp#3), install from git via uv. + +## Claude Code (full experience: skills + commands + MCP) + +``` +/plugin marketplace add codellm-devkit/cocoa +/plugin install cocoa@cocoa +``` + +This registers the four skills, `/cocoa:map`, `/cocoa:blast`, `/cocoa:demo`, and an +MCP server entry that launches `uvx --from git+https://github.com/codellm-devkit/cocoa +cocoa serve -p .` in your project. + +## Codex / Cursor / other SKILL.md-compatible agents + +Copy the `skills/` directories into your agent's skills location (e.g. +`~/.codex/skills/` or your Cursor rules directory) — each `SKILL.md` is +self-contained and includes the CLI fallback, so no MCP setup is required. +Install the CLI once: `uv tool install git+https://github.com/codellm-devkit/cocoa`. + +## Plain MCP (any MCP client) + +```json +{ + "mcpServers": { + "cocoa": { + "command": "uvx", + "args": ["--from", "git+https://github.com/codellm-devkit/cocoa", + "cocoa", "serve", "-p", "."] + } + } +} +``` + +## Docker (all analyzers, zero host toolchains) + +```bash +docker run --rm -v "$PWD:/work" ghcr.io/codellm-devkit/cocoa map -p /work +``` + +Includes the unreleased Go analyzer (built from source) and the Java jar workaround. +Note: first Java analysis downloads a JDK into the project's `.cocoa/cache` +(network required once per project). + +## Host toolchain notes + +- Java: cldk auto-manages the JDK; clean pip installs currently need the jar + workaround (python-sdk#236) — copy `codeanalyzer-2.4.1.jar` from the + codeanalyzer-java releases into cldk's `analysis/java/codeanalyzer/jar/` dir. +- Go: put `codeanalyzer-go` on PATH or set `$CODEANALYZER_GO_BIN`. +- helm/kubectl: optional; enable static rendering of charts/kustomize wiring. diff --git a/test/test_plugin_assets.py b/test/test_plugin_assets.py index e846d30..0e88d32 100644 --- a/test/test_plugin_assets.py +++ b/test/test_plugin_assets.py @@ -132,3 +132,30 @@ def test_docker_smoke_builds_and_maps(): capture_output=True, text=True, timeout=1800, ) assert res.returncode == 0, f"smoke failed:\n{res.stdout}\n{res.stderr}" + + +def test_readme_carries_the_positioning_and_honest_status(): + text = (ROOT / "README.md").read_text() + assert "Graphify indexes files" in text # the pitch + assert "DERIVED-STATIC" in text and "INFERRED" in text + assert "docs/INSTALL.md" in text and "docs/COMPARISON.md" in text + assert "codeanalyzer-go" in text # honest prereq status + + +def test_install_doc_covers_platforms_and_pypi_caveat(): + text = (ROOT / "docs" / "INSTALL.md").read_text() + for platform in ("Claude Code", "Codex", "Cursor", "Docker"): + assert platform in text + assert "uvx --from git+" in text # pre-PyPI install path + + +def test_comparison_is_provenance_led(): + text = (ROOT / "docs" / "COMPARISON.md").read_text() + assert "graphify" in text.lower() + assert "AMBIGUOUS" in text and "DERIVED-STATIC" in text + + +def test_demo_tape_mandates_warm_cache_protocol(): + text = (ROOT / "demo.tape").read_text() + assert "RECORDING PROTOCOL" in text + assert "cold run" in text