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
2 changes: 1 addition & 1 deletion .cursor/rules/agent-workflow.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ When you're given a per-PR task prompt from `plans/CURSOR-PROMPTS-*.md`:
- Schema changes that affect the Lance index or Kuzu graph need a
matching update to the README "Re-index required" callout. Bump
`ontology_version` when enrichment semantics change. The current
version is **8**.
version is **10**.
- Brownfield is a first-class surface: any new auto-detection
(route, role, capability, http client, async producer) must
compose with the matching `BrownfieldOverrides` layer. Last writer
Expand Down
9 changes: 4 additions & 5 deletions .cursor/rules/project-overview.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ when needed.

- `README.md` — feature surface, env vars, ranking, capabilities,
tool list, "Re-index required" callouts. The current
`ontology_version` is **8** (HTTP_CALLS / ASYNC_CALLS caller
edges + brownfield client/producer composition + cross-service
resolution mode on GraphMeta). Earlier
ontology bumps are described inline in the README's
callouts list.
`ontology_version` is **10** (adds `Client` nodes, `DECLARES_CLIENT`,
`list_clients`, plus HTTP_CALLS / ASYNC_CALLS caller edges and
brownfield composition from earlier bumps). Earlier ontology bumps
are described inline in the README's callouts list.
- `CODEBASE_REQUIREMENTS.md` — Java-repo assumptions and per-file
map of what to edit when a target tree doesn't match defaults.
- `tests/README.md` — testing philosophy.
Expand Down
2 changes: 1 addition & 1 deletion .cursor/skills/plan/reference.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Plan Style Reference (Repo-grounded)

This reference distills what made recent plan PRs strong:
- `#39` (`plans/PLAN-LIST-CLIENTS-MCP-TOOL.md`)
- `#39` (`plans/completed/PLAN-LIST-CLIENTS-MCP-TOOL.md`)
- `#11` (`plans/PLAN-TIER1B-COMPLETION.md` + prompts file)
- `#2` (`plans/PLAN-TIER1-COMPLETION.md`)

Expand Down
2 changes: 1 addition & 1 deletion .cursor/skills/pr-open/pr-input.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"title": "feat: retarget pass6 hint recovery to Client declarations (PR-LC2)",
"base": "master",
"draft": false,
"scope": "Implements PR-LC2 from `plans/PLAN-LIST-CLIENTS-MCP-TOOL.md` by retargeting pass6 hint recovery to caller-side `Client` declarations.",
"scope": "Implements PR-LC2 from `plans/completed/PLAN-LIST-CLIENTS-MCP-TOOL.md` by retargeting pass6 hint recovery to caller-side `Client` declarations.",
"what_changed": [
"Updated `build_ast_graph.py` pass6 fallback hint lookup to recover Feign hints from persisted `Client` rows.",
"Preserved existing `HTTP_CALLS(Symbol -> Route)` semantics and match outcomes.",
Expand Down
2 changes: 1 addition & 1 deletion .cursor/skills/propose/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Add a first-class outbound declaration surface:

## PR body (proposal-only) template
## What
Adds `propose/LIST-CLIENTS-MCP-TOOL-PROPOSE.md` describing outbound client declarations and a new `list_clients` MCP tool.
Adds `propose/completed/LIST-CLIENTS-MCP-TOOL-PROPOSE.md` describing outbound client declarations and a new `list_clients` MCP tool.

## Why now
Outbound declaration discovery needs a first-class tool after direction-honest annotation reshaping.
Expand Down
7 changes: 5 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ for tools that don't read `.cursor/rules/`.

- `README.md` — feature surface, env vars, ranking, capabilities,
tool list, "Re-index required" callouts. **`ontology_version` is
currently 8.**
currently 10** (`Client` nodes + `list_clients`; see README callouts).
- `CODEBASE_REQUIREMENTS.md` — Java-repo assumptions and tuning map.
- `propose/` and `plans/` (plus their `completed/` subdirs) —
in-flight scope and the rationale behind current design.
Expand All @@ -35,7 +35,10 @@ for tools that don't read `.cursor/rules/`.
`plans/completed/PLAN-BROWNFIELD-ROLE-OVERRIDES-design-fixes.md`,
`plans/completed/PLAN-COCOINDEX-SYMLINK-FIX.md`,
`plans/completed/PLAN-ENUM-ANNOTATION-FIXES.md`,
`plans/completed/PLAN-REMOTE-PROJECT-INDEXING.md`. Read these
`plans/completed/PLAN-REMOTE-PROJECT-INDEXING.md`,
`propose/completed/LIST-CLIENTS-MCP-TOOL-PROPOSE.md`,
`plans/completed/PLAN-LIST-CLIENTS-MCP-TOOL.md`,
`plans/completed/CURSOR-PROMPTS-LIST-CLIENTS-MCP-TOOL.md`. Read these
when you need the *why* behind current code.
- `tests/README.md` — testing philosophy.

Expand Down
5 changes: 5 additions & 0 deletions CODEBASE_REQUIREMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ root (`role_overrides:`, `route_overrides:`, `http_client_overrides:`,
`@CodebaseProducers` (method-level outbound HTTP / messaging) — see
README §3c.

**MCP discovery:** after indexing, use `list_routes` for inbound HTTP and async
routes and `list_clients` for outbound HTTP `Client` declarations (Feign
methods plus annotated imperative clients). `list_clients` requires
`graph_meta.ontology_version` **10** or newer.

See **Brownfield overrides** in `README.md` for the full schema, usage
examples, and execution order.

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The product vision for this tooling is proposed in [`propose/PRODUCT-VISION.md`]
> **Driving this MCP from an agent:**
> - [`docs/AGENT-GUIDE.md`](./docs/AGENT-GUIDE.md) — copy-paste-into-`QWEN.md` /
> `CLAUDE.md` block. Forced reasoning preamble, decision tree, full
> reference for all 22 tools, ontology glossary (v10), recovery playbook,
> reference for all 23 tools, ontology glossary (v10), recovery playbook,
> slash-style aliases. Engineered for weak / mid models that otherwise
> pick the wrong tool.
> - [`docs/MANUAL-VERIFICATION-CHECKLIST.md`](./docs/MANUAL-VERIFICATION-CHECKLIST.md)
Expand Down Expand Up @@ -167,12 +167,14 @@ The DB is dropped and rebuilt from scratch on each run (Phase 1 is a full rebuil
| `diagnose_ignore` | Explain whether a path is excluded for indexing / graph walks and which rule layer won (`builtin_default`, `project_root`, `nested`, `gitignore`). |
| `graph_meta` | Counts, ontology version, build timestamp, parse errors; route totals / `routes_by_framework` / `routes_resolved_pct` (v5+); `routes_from_brownfield_pct` / `routes_by_layer` (v6+). |
| `list_routes` | Filterable listing of `Route` nodes (`microservice`, `framework`, `path_prefix`, `method`). |
| `list_clients` | Filterable listing of outbound `Client` nodes (`microservice`, `client_kind`, `target_service`, `path_prefix`, `method`). |
| `find_route_handlers` | Endpoint symbols that `EXPOSES` a route id (confidence + resolution strategy on the edge); Feign consumer routes return empty. |
| `get_route_by_path` | Lookup one `Route` by `microservice` + normalised `path_template` + optional HTTP method. |
| `find_route_callers` | Callers that reach a route via `HTTP_CALLS` / `ASYNC_CALLS` (by route id or exact route tuple). |
| `trace_request_flow` | Inbound caller + outbound handler flow around one route entrypoint. |

HTTP mappings from literals are fully resolved (non-empty `path_template` / `path_regex`). Values containing Spring ``${…}`` SpEL, or non-string annotation arguments (constant references), are still stored as routes with lower confidence and empty template fields. Caller-side edges are now shipped via `HTTP_CALLS` / `ASYNC_CALLS` and exposed through `find_route_callers` and `trace_request_flow`.
Use `list_routes` for inbound service exposures and `list_clients` for outbound HTTP declarations (Feign methods and annotated imperative clients). `list_clients` rows include `source_layer` so brownfield-vs-builtin provenance is visible to callers. `list_clients` requires graphs rebuilt with `ontology_version` 10+.

**Example — `analyze_pr`:** pass the same unified diff text you would feed to `patch` (e.g. `git diff` output). Paths in the diff should match project-relative `Symbol.filename` values in the graph (e.g. `chat-assign/src/main/java/.../ChatManagementService.java`). A one-line edit inside `assign` returns JSON shaped like:

Expand Down
6 changes: 5 additions & 1 deletion build_ast_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
symbol_id,
)
from path_filtering import LayeredIgnore, iter_java_source_files
from java_ontology import VALID_HTTP_CALL_MATCHES
from java_ontology import VALID_CLIENT_KINDS, VALID_HTTP_CALL_MATCHES

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -1310,6 +1310,10 @@ def _client_id(
def _client_source_layer(strategy: str) -> str:
if strategy in {"layer_a_meta", "layer_b_ann", "layer_b_fqn", "layer_c_source"}:
return strategy
# Some caller extraction paths emit client kind as strategy; treat those
# as builtin-source declarations instead of warning on every row.
if strategy in VALID_CLIENT_KINDS:
return "builtin"
if strategy != "builtin":
log.warning("unknown client source strategy %r, falling back to builtin", strategy)
return "builtin"
Expand Down
35 changes: 28 additions & 7 deletions docs/AGENT-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
> **How to use this file.** Copy the block between the `<!-- BEGIN/END
> user-rag MCP guide -->` markers below into your project's `QWEN.md`,
> `CLAUDE.md`, `AGENTS.md`, or equivalent. The block is self-contained:
> all 22 MCP tools, the ontology glossary (v9), a forced reasoning
> all 23 MCP tools, the ontology glossary (v10), a forced reasoning
> preamble, a decision tree, a recovery playbook, and slash-style prompt
> aliases. Update by re-pulling from this repo when the ontology bumps.
>
Expand All @@ -12,7 +12,8 @@
> graph already knows exactly. This guide is engineered to keep them on
> the rails.
>
> Calibrated against ontology version **9** (see `java_ontology.py`).
> Calibrated against ontology version **10** (see `ast_java.ONTOLOGY_VERSION` /
> `java_ontology.py` valid sets).

---

Expand Down Expand Up @@ -178,6 +179,7 @@ the `path` field from a result.
| "What does method M call" | `find_callees` | `graph_neighbors` for type wiring |
| "Show me the handler for HTTP path /foo/bar" | `get_route_by_path` then `find_route_handlers` | `trace_request_flow` |
| "List all HTTP endpoints / Kafka topics" | `list_routes` (filter by `framework`) | `find_route_handlers` per id |
| "List outbound HTTP clients / Feign methods for this service" | `list_clients` (filter by `client_kind`, `target_service`, `path_prefix`) | `find_route_callers` for resolved call edges |
| "Who calls route /foo/bar" | `find_route_callers` | `trace_request_flow` |
| "All controllers / services / repositories in service X" | `list_by_role` | `list_by_role` + `capability=` filter |
| "Everything annotated `@Transactional`" | `list_by_annotation` | `find_callers` per result |
Expand All @@ -199,7 +201,7 @@ the `path` field from a result.
work" should start with `codebase_search` (or `trace_flow`); the
graph alone won't surface the right entry point.

### Tool reference — all 22 tools
### Tool reference — all 23 tools

Grouped by purpose. Required arguments are **bold**; common mistakes are
flagged with ⚠.
Expand Down Expand Up @@ -273,6 +275,18 @@ flagged with ⚠.
classify — usually annotation-only Kafka topic constants. If you
expected an HTTP route here, check brownfield overrides.

##### `list_clients` — list outbound `Client` nodes (Feign, imperative HTTP)

- **Args:** none required. Optionals: `microservice`, `client_kind`
(`feign_method`|`rest_template`|`web_client`), `target_service`,
`path_prefix`, `method`, `limit` (1–500).
- Returns rows with `path`, `path_template`, `member_fqn`, `source_layer`
(`builtin` vs brownfield layers), and other fields from the graph. Pair
with `find_route_callers` when you need **resolved** `HTTP_CALLS` edges,
not just declarations.
- ⚠ Requires a graph built with `ontology_version` **10+** — check
`graph_meta` first.

##### `find_route_handlers` — symbols that EXPOSES a Route id

- **Args:** **`route_id`** (e.g. `r:0a2bdd…`).
Expand Down Expand Up @@ -368,7 +382,7 @@ flagged with ⚠.
##### `graph_meta` — Kuzu metadata: counts, ontology version, build timestamp

- **Args:** none. First tool to run on a fresh index — confirms
`ontology_version=9` and surfaces build counts.
`ontology_version=10` and surfaces build counts.

##### `diagnose_ignore` — explain why a path is ignored

Expand All @@ -382,7 +396,7 @@ flagged with ⚠.
`LANCEDB_MCP_ALLOW_REFRESH=1`.
- ⚠ Always call `graph_meta` after to verify the rebuild succeeded.

### Ontology glossary (version 9)
### Ontology glossary (version 10)

Source of truth: `java_ontology.py`. Pass these strings verbatim
(case-sensitive).
Expand All @@ -393,7 +407,7 @@ Source of truth: `java_ontology.py`. Pass these strings verbatim
`CLIENT`, `MAPPER`, `DTO`, `OTHER`.

- `CLIENT` covers Feign clients (`@FeignClient`) and brownfield
`@CodebaseRole(CLIENT)`. As of ontology 9, plain `RestTemplate`
`@CodebaseRole(CLIENT)`. As of ontology 10, plain `RestTemplate`
wrappers stay in their natural stereotype role (typically `SERVICE`)
unless you explicitly tag them.
- `OTHER` = the inference didn't recognise the type. Treat as a
Expand Down Expand Up @@ -421,6 +435,11 @@ Source of truth: `java_ontology.py`. Pass these strings verbatim
`http_endpoint`, `kafka_topic`, `rabbit_queue`,
`jms_destination`, `stream_binding`.

#### Client node kind (`Client` rows / `list_clients`)

`feign_method`, `rest_template`, `web_client` (`VALID_CLIENT_KINDS` in
`java_ontology.py`).

#### Client kind (on `HTTP_CALLS` / `ASYNC_CALLS` edges)

`feign_method`, `rest_template`, `web_client`, `kafka_send`,
Expand All @@ -447,6 +466,7 @@ Source of truth: `java_ontology.py`. Pass these strings verbatim
| `path_template` filter returns nothing | Passed the raw annotation value, but the graph stores the concatenated servlet form | Run `list_routes({"path_prefix":"/your/prefix"})` and copy the exact `path` field, then retry |
| Tool says "graph unavailable" | Index not built or `LANCEDB_MCP_PROJECT_ROOT` not set | Run `graph_meta` to confirm; `refresh_code_index({"confirm":true})` if needed |
| Expected route is missing from `list_routes` | Framework not recognised by built-in extractor | Add `@CodebaseHttpRoute(path=…, method=…)` or `@CodebaseAsyncRoute(topic=…)` per README §3b, then `refresh_code_index` |
| `list_clients` returns no rows / errors | Stale graph (ontology below 10) or no outbound clients in index | Run `graph_meta`; rebuild with `refresh_code_index` if needed; tag call sites with `@CodebaseClient` per README §3c |
| `list_by_role` shows a `*Controller` class as `OTHER` | Non-Spring web stack (JAX-RS, custom) | Add `@CodebaseRole(CodebaseRoleKind.CONTROLLER)` per README §3a, or `role_overrides.fqn` in YAML |
| `cross_service_calls_total = 0` but you know there are inter-service calls | Resolution mode is `brownfield_only` and call sites have no brownfield tag, OR target services unindexed | Switch to `cross_service_resolution: auto` in YAML, or tag with `@CodebaseClient` |
| `codebase_search` returns DTOs / config classes instead of behaviour | Default ranking; no role filter | Add `exclude_roles=["DTO","ENTITY","CONFIG","OTHER"]` |
Expand All @@ -465,6 +485,7 @@ shorthand for the right tool + args.
- `/who-calls <fqn-with-sig>` → `find_callers({"fqn_or_signature":"<fqn>","depth":1,"min_confidence":0.9})`. **Pass the full signed FQN** (e.g. `com.foo.Bar#baz(String,int)`) — see *Argument shapes §B* for format. If you only have the simple name, query that first and re-issue with the exact FQN.
- `/calls-from <fqn-with-sig>` → `find_callees({"fqn_or_signature":"<fqn>","depth":1})`. Same FQN-with-signature rule — simple name will match all overloads but not let you target one.
- `/route <method> <path> [microservice]` → `list_routes({"path_prefix":"<path>","method":"<method>","microservice":"<ms>"})`
- `/clients [microservice]` → `list_clients({"microservice":"<ms>","limit":100})` — add `client_kind` / `path_prefix` when narrowing Feign vs imperative HTTP
- `/handler <route_id>` → `find_route_handlers({"route_id":"<route_id>"})`
- `/who-hits <microservice> <path>` → `find_route_callers({"microservice":"<ms>","path_template":"<path>"})`
- `/why-no-route <fqn>` → 1) `list_by_role({"role":"OTHER"})` to confirm the type wasn't classified, 2) `list_by_annotation` for any custom annotation, 3) suggest brownfield `@CodebaseHttpRoute` / `@CodebaseAsyncRoute`
Expand All @@ -489,7 +510,7 @@ shorthand for the right tool + args.
## Maintenance notes (for the repo, not the agent)

- Bump the **ontology version** sentence at the top of the BEGIN block
whenever `ONTOLOGY_VERSION` changes in `kuzu_queries.py`.
whenever `ONTOLOGY_VERSION` changes in `ast_java.py`.
- When a new MCP tool is added in `server.py`, add it to (a) the
decision tree, (b) the tool reference, (c) a slash alias if the use
case is common.
Expand Down
28 changes: 23 additions & 5 deletions docs/MANUAL-VERIFICATION-CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,11 @@ stubs. No `*Service` / `*Repository` classes in OTHER.
0 `@FeignClient` classes (it uses RestTemplate); on real projects,
counts should match exactly.

**If failing → fix:** as of ontology 9 (PR-H1), `@FeignClient` →
**If failing → fix:** as of ontology 9+ (PR-H1), `@FeignClient` →
`role=CLIENT` + `capability=HTTP_CLIENT`. If you see drift, run
`graph_meta` and confirm `ontology_version=9`. If yes and still
broken, re-index — may be a stale graph.
`graph_meta` and confirm `ontology_version` is current (10 as of the
`Client` / `list_clients` work). If yes and still broken, re-index — may
be a stale graph.

### 2.4 ☐ Message listeners and producers are detected

Expand Down Expand Up @@ -254,7 +255,7 @@ your custom stereotypes.

---

## Phase 3 — Routes (4 items)
## Phase 3 — Routes and outbound clients (5 items)

### 3.1 ☐ Route count and framework distribution

Expand Down Expand Up @@ -328,14 +329,31 @@ literal name of, use brownfield route override:
`@CodebaseAsyncRoute(topic="my.topic")`
on the listener method (README §3b).

### 3.5 ☐ Outbound HTTP clients surface via `list_clients`

**Verification prompt:**

> Call `graph_meta()` and note `ontology_version` and `clients_total`.
> Then `list_clients({"limit":200})`. Every row should include
> `client_kind`, `target_service`, `path`, `method`, and `source_layer`.

**Expected (calibration):** `ontology_version=10`, `clients_total=2`, and
both clients are `client_kind=rest_template` (imperative HTTP in the
fixture — no Feign interfaces).

**If failing → fix:** `ontology_version` below 10 → full rebuild. Zero
clients on a project you know has Feign or tagged `@CodebaseClient` →
check brownfield stubs (README §3c) and that those sources are indexed.

### Red flags for Phase 3

- `routes_total = 0` → no controllers were classified or framework not
recognised
- HTTP routes with empty `method` → annotation extractor didn't see
`@GetMapping` / `@PostMapping`
- `routes_from_brownfield_pct` jumped after a refactor → you broke a
built-in extraction; check that ontology version is still 9
built-in extraction; check that `ontology_version` in `graph_meta`
matches the bundle you expect (10 as of `Client` / `list_clients`)

---

Expand Down
Loading