a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
1676 lines
108 KiB
Plaintext
1676 lines
108 KiB
Plaintext
=== home/.hermes/config.yaml ===
|
||
mcp_servers:
|
||
gortex:
|
||
command: gortex
|
||
args: [mcp]
|
||
connect_timeout: 60
|
||
timeout: 120
|
||
platform_toolsets:
|
||
cli: true
|
||
=== home/.hermes/skills/analysis/gortex-architecture-review/SKILL.md ===
|
||
---
|
||
name: gortex-architecture-review
|
||
description: "Graph-grounded architectural read of a repo."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, architecture-review]
|
||
category: analysis
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Architecture Review with Gortex
|
||
|
||
Use this when the user wants a graph-grounded architectural read of a repo / system — "what does the architecture actually look like, where is the design under stress, what should we refactor before it breaks." Distinct from `/gortex-quality-audit` (which produces a punch list) — this produces a *narrative* with diagrams.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. graph_stats -> Orient
|
||
2. get_repo_outline -> Narrative single-call overview
|
||
3. get_communities -> Functional clusters via Louvain — the de facto module boundaries
|
||
4. get_processes -> Discovered execution flows — the de facto use cases
|
||
5. analyze({kind: "components"}) -> UI component tree (when applicable) — render hierarchy fan-in/out
|
||
6. analyze({kind: "routes"}) -> The API surface (HTTP / gRPC / GraphQL / WS / topic)
|
||
7. analyze({kind: "models"}) -> ORM models → tables — the data surface
|
||
8. analyze({kind: "k8s_resources"}) + analyze({kind: "images"}) -> Deployment topology (when applicable)
|
||
9. analyze({kind: "hotspots", top: 20}) -> Symbols under coupling stress
|
||
10. analyze({kind: "cycles"}) -> Architectural cycles (Tarjan SCC with severity)
|
||
11. analyze({kind: "would_create_cycle", from: "<A>", to: "<B>"}) -> Pre-flight before proposing a new dep in the review
|
||
12. analyze({kind: "cross_repo", base_kind: "calls"}) -> Inter-repo coupling (when multi-repo)
|
||
13. contracts({action: "list"}) -> Provider-side wire surface
|
||
14. contracts({action: "check"}) -> Provider ↔ consumer match across repos
|
||
15. get_class_hierarchy({id: "<key interface>"}) -> Inheritance / implementation depth on load-bearing interfaces
|
||
16. get_dependencies / get_dependents at the community / file level -> Layering walk — does the dependency direction match the intent?
|
||
17. analyze({kind: "pubsub"}) + analyze({kind: "channel_ops"}) -> Async + concurrency topology
|
||
18. analyze({kind: "field_writers"}) + analyze({kind: "race_writes"}) -> Shared-state hotspots — the architecture's hidden mutable surface
|
||
19. analyze({kind: "stale_code", older_than: 365}) -> Strata that haven't moved in a year — likely the "stable core"
|
||
20. analyze({kind: "ownership"}) -> Per-author footprint per community — Conway's law check
|
||
21. export_context({format: "markdown", -> The review deliverable
|
||
sections: ["overview", "modules", "processes",
|
||
"wire_surface", "data_surface", "concurrency",
|
||
"cross_repo", "stress_points", "recommendations"]})
|
||
```
|
||
|
||
## What the architecture review answers
|
||
|
||
| Question | Tool |
|
||
| -------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
||
| **What are the de facto modules?** (not what's claimed) | `get_communities` — Louvain finds the actual cluster structure |
|
||
| **What are the de facto use cases?** | `get_processes` — discovered execution flows |
|
||
| **Where is the design under coupling stress?** | `analyze kind=hotspots top=20` — fan-in + fan-out + community crossings |
|
||
| **Are there cycles?** | `analyze kind=cycles` — Tarjan SCC with severity classification |
|
||
| **Does the dependency direction match the intent?** | Walk `get_dependencies` / `get_dependents` at the community / file level |
|
||
| **What is the wire surface?** | `analyze kind=routes` + `contracts({action: list})` |
|
||
| **What is the data surface?** | `analyze kind=models` + `analyze kind=orphan_tables` / `unreferenced_tables` |
|
||
| **What is the deployment topology?** | `analyze kind=k8s_resources` + `analyze kind=images` |
|
||
| **Where does shared state live?** | `analyze kind=field_writers` + `race_writes` — the mutable-state surface |
|
||
| **Where does the async + pub/sub topology lead?** | `analyze kind=pubsub` + `channel_ops` + `goroutine_spawns` + `unclosed_channels` |
|
||
| **Does the team's structure match the code's structure? (Conway)** | `analyze kind=ownership` projected onto `get_communities` — author overlap per community |
|
||
| **Where is the stable core?** | `analyze kind=stale_code older_than=365` — strata that haven't moved in a year |
|
||
| **Where would adding a new edge create a cycle?** | `analyze kind=would_create_cycle from=A to=B` — pre-flight for proposed deps |
|
||
|
||
## Stress points
|
||
|
||
Stress points are graph signals that the design is fighting itself. Surface them explicitly in the review:
|
||
|
||
- **Cyclic dependency in the load-bearing layer** — `analyze kind=cycles severity=severe` ∩ a community with high `hotspots` rank
|
||
- **Architecture-spanning hotspot** — a symbol whose `community_crossings` is > 50% of its fan-in (the symbol "is" the integration layer, often by accident)
|
||
- **Mutable shared field reachable from a goroutine without a lock** — `analyze kind=race_writes` on a high-fan-in field
|
||
- **Contract orphan** — `contracts({action: check})` returns a provider with no consumer or a consumer with no provider, especially cross-repo
|
||
- **Inverted dependency** — a "lower" layer importing a "higher" one. Walk `get_dependencies` from each community to confirm directionality
|
||
- **Deployment ↔ code drift** — `analyze kind=images role=base ref=latest` (unpinned), `k8s_resources k8s_kind=ConfigMap` orphans
|
||
|
||
## Multi-repo architecture
|
||
|
||
When `get_active_project` shows >1 member:
|
||
|
||
- `analyze kind=cross_repo base_kind=calls` — typed cross-repo edges; the count is the *contract surface* the architecture must hold stable
|
||
- `contracts({action: check})` partitioned by repo pair — orphan providers / consumers across the boundary
|
||
- For each cross-repo edge, `get_test_targets` returns the cross-repo tests that exercise it; the absence of those tests is itself an architecture finding
|
||
|
||
## Review deliverable
|
||
|
||
The output of an architecture review is a markdown narrative with embedded diagrams (Mermaid / DOT) generated from the graph:
|
||
|
||
```
|
||
export_context({
|
||
task: "architecture review of <repo / project>",
|
||
format: "markdown",
|
||
sections: [...]
|
||
})
|
||
```
|
||
|
||
The packet rides the same surface as `/gortex-quality-audit` but is structured as a *narrative* (modules, processes, surfaces, stress, recommendations) rather than a flat punch list.
|
||
|
||
## Checklist
|
||
|
||
- `graph_stats` + `get_active_project` before any analyzer
|
||
- `get_repo_outline` for the narrative skeleton
|
||
- `get_communities` + `get_processes` are the architectural primitives — pin the review on these
|
||
- `analyze kind=hotspots` + `cycles` for stress points
|
||
- Wire surface = `analyze kind=routes` + `contracts list`; data surface = `analyze kind=models` + `orphan_tables`; deployment = `k8s_resources` + `images`
|
||
- Concurrency / async = `pubsub` + `channel_ops` + `goroutine_spawns` + `race_writes` + `unclosed_channels`
|
||
- Multi-repo: `cross_repo` + `contracts check` partitioned by repo pair
|
||
- `ownership` ∩ `communities` for Conway's law alignment
|
||
- `export_context format=markdown` for the narrative
|
||
- `store_memory({kind: "decision"})` for every architectural decision the review surfaces — the next agent inherits the rationale
|
||
=== home/.hermes/skills/analysis/gortex-co-change/SKILL.md ===
|
||
---
|
||
name: gortex-co-change
|
||
description: "Find what changes together and hidden coupling."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, co-change]
|
||
category: analysis
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Co-change Analysis with Gortex
|
||
|
||
Use this when the user asks "what tends to change together with this?" — for refactor planning, ownership decisions, ADR rationale, or to find hidden coupling the graph's static edges don't capture (two files that always co-modify but have no import / call edge between them). Built on git blame + history + the symbol-churn surface `get_symbol_history` + the existing graph dependents view.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. graph_stats -> Orient
|
||
2. gortex enrich blame all (CLI; once per session) -> Stamp last_authored / last_commit_at on every node
|
||
3. search_symbols({query: "<target symbol or file>"}) -> Resolve the anchor
|
||
4. get_recent_changes({since_ts: <N months ago>}) -> Per-file change frequency baseline
|
||
5. get_symbol_history -> Symbol-level churn this session (live hotspot signal)
|
||
6. analyze({kind: "blame", path_prefix: "<dir>/"}) -> Per-symbol last-author rollup; cross-ref with churn
|
||
7. analyze({kind: "ownership", path_prefix: "<dir>/"}) -> Per-author symbol / file counts — proxy for who-touches-it-most
|
||
8. analyze({kind: "hotspots", path_prefix: "<dir>/"}) -> Coupling-by-fan-in/out — graph-level vs git-level coupling
|
||
9. get_dependents({id: "<anchor>", depth: 2}) -> Static dependent set (graph coupling)
|
||
10. find_clones({path_prefix: "<dir>/", dead_only: false}) -> Near-duplicate functions — copy-paste co-evolution signal
|
||
11. detect_changes({scope: "all"}) -> If a diff already exists, project it onto the graph
|
||
12. diff_context({scope: "all"}) -> Per-file risk + per-symbol callers/callees overlay
|
||
```
|
||
|
||
## Co-change vs graph coupling
|
||
|
||
The two signals are complementary:
|
||
|
||
| Signal | What it tells you | Tool |
|
||
| --------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
|
||
| **Graph coupling** | Static structure: who imports / calls / extends / implements whom | `get_dependents` / `get_dependencies` / `analyze kind=hotspots` |
|
||
| **Co-change coupling** | Historical / temporal: who tends to co-modify even without a static edge | `get_recent_changes` + `analyze kind=blame` + `get_symbol_history` |
|
||
| **Both align** | Healthy module — the structure reflects how the team edits it | Use either; co-change adds confidence |
|
||
| **Co-change > graph** | **Hidden coupling** — two files always co-modify but have no graph edge. Smell: missing abstraction, parallel hierarchies, copy-paste | `find_clones` is the corroborating evidence |
|
||
| **Graph > co-change** | Dead coupling — graph edge exists but the files don't co-evolve. Often safe to break | `analyze kind=dead_code` may flag the dependent |
|
||
|
||
## Driving a refactor with co-change
|
||
|
||
1. Pick the anchor (file / symbol the user wants to refactor)
|
||
2. Compute co-change set: symbols whose `meta.last_authored` clusters with the anchor's, AND whose churn (`get_symbol_history` + `get_recent_changes`) overlaps the anchor's
|
||
3. Compute graph-coupling set: `get_dependents` + `get_dependencies` (depth 2)
|
||
4. Diff the two sets — the **co-change ∖ graph** delta is the hidden-coupling list and the highest ROI for "extract a shared abstraction"
|
||
5. Pair with `find_clones` on the co-change set — clone clusters that span the boundary are the copy-paste hidden coupling
|
||
6. `store_memory({kind: "convention", body: "X always changes with Y because Z"})` so the next agent inherits the invariant rather than re-discovering it
|
||
|
||
## Ownership signal
|
||
|
||
`analyze kind=ownership` projected onto the co-change set tells you who-pings-who for review. Two files that co-modify under different primary authors is a *coordination* signal — the team is implicitly maintaining a contract neither file's CODEOWNERS captures.
|
||
|
||
## Crossing the repo boundary
|
||
|
||
When the anchor lives in a multi-repo project (`get_active_project` shows >1 member):
|
||
|
||
- `analyze kind=cross_repo base_kind=calls repo=<anchor's repo>` gives the static cross-repo coupling
|
||
- For the temporal signal across repos, run `analyze kind=blame` per repo and look for authors who appear in both — that's the implicit cross-repo co-change channel
|
||
|
||
## Checklist
|
||
|
||
- `gortex enrich blame all` (CLI) at least once per session — the temporal analyzers need `meta.last_authored`
|
||
- `get_recent_changes` + `get_symbol_history` for the live churn signal
|
||
- `analyze kind=blame` + `ownership` for the per-symbol / per-author rollup
|
||
- `get_dependents` (graph coupling) **and** the churn surface (temporal coupling) — diff them; the delta is the hidden coupling
|
||
- `find_clones` to corroborate copy-paste-style hidden coupling
|
||
- `analyze kind=hotspots` for the graph-side coupling-by-fan-in/out view
|
||
- For multi-repo work: `analyze kind=cross_repo` on the static side + per-repo blame on the temporal side
|
||
- `store_memory({kind: "convention"})` when you discover a stable co-change relationship — saves the next agent from re-deriving it
|
||
=== home/.hermes/skills/analysis/gortex-episode-replay/SKILL.md ===
|
||
---
|
||
name: gortex-episode-replay
|
||
description: "Reconstruct what changed in a window (postmortem, release, PR)."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, episode-replay]
|
||
category: analysis
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Episode Replay with Gortex (timeline reconstruction)
|
||
|
||
Use this when the user wants to reconstruct what happened in a specific window — for a postmortem, a "what shipped between v1.2 and v1.3", a "what did Alice touch last week", or "walk me through what this PR actually changed". Pairs git history with the graph so the replay shows blast radius alongside the diff, not just the file list.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. graph_stats -> Orient
|
||
2. gortex enrich blame all (CLI; once per session) -> Stamp meta.last_authored / meta.last_commit_at / meta.added_in
|
||
3. analyze({kind: "releases"}) -> Tag boundaries → maps a tag to the symbols added in it
|
||
4. analyze({kind: "blame", path_prefix: "<scope>/"}) -> Per-symbol last-author rollup
|
||
5. get_recent_changes({since_ts: <window-start>}) -> Symbols touched in the window
|
||
6. analyze({kind: "ownership", path_prefix: "<scope>/"}) -> Per-author symbol/file counts in the window
|
||
7. detect_changes({scope: "<all|staged|since-tag>"}) -> The change-set's graph projection
|
||
8. diff_context({scope: "<same>"}) -> Graph-enriched diff: callers, callees, communities, per-file risk
|
||
9. For each material symbol in the window:
|
||
get_symbol_history({id: "<id>"}) -> Per-session edit count (regression hotspot)
|
||
explain_change_impact({ids: "<id>"}) -> Blast radius of that one change
|
||
10. query_notes({since: <window-start>}) -> Session decisions / bug notes recorded in the window
|
||
11. query_memories({tag: "decision", since: <window-start>}) -> Cross-session decisions in the window
|
||
12. export_context({format: "markdown", -> Hand the replay packet to PR / Slack / wiki
|
||
sections: ["changes", "impact", "decisions"]})
|
||
```
|
||
|
||
## Replay shapes
|
||
|
||
| Goal | Driver query |
|
||
| ----------------------------------------------------- | ------------------------------------------------------------------------ |
|
||
| "What shipped in v1.3?" | `analyze kind=releases` → symbols where `meta.added_in == "v1.3"`; then `diff_context` between v1.2..v1.3 tags |
|
||
| "What did Alice change last week?" | `analyze kind=ownership` filtered to Alice → cross-ref with `get_recent_changes since_ts=now-7d` |
|
||
| "What did this incident touch?" | Start with `/gortex-incident-investigation` → use its root-cause symbol set as the seed; replay walks `explain_change_impact` on each |
|
||
| "Postmortem narrative for a one-day window" | Full chain above + `query_notes` + `query_memories` so commentary rides next to code in the markdown |
|
||
| "What did this PR actually change beyond the diff?" | `detect_changes scope=staged` + `diff_context` + `explain_change_impact` per symbol → second-order blast that the literal diff hides |
|
||
|
||
## Reading the replay output
|
||
|
||
- `detect_changes` is the change-set's *graph* projection — every node a touched file owns, plus every directly-affected dependent. It is broader than `git diff --stat` because it captures symbols whose *meaning* changed, not just files whose *bytes* changed.
|
||
- `diff_context` adds the callers / callees / community / processes / per-file risk overlay. This is the artifact you embed in the PR description or postmortem.
|
||
- Per-symbol `explain_change_impact` surfaces the *second-order* blast (what depends on the things that changed). The replay is incomplete without this for any change touching a fan-in-heavy symbol.
|
||
|
||
## Crossing the merge boundary
|
||
|
||
For replays that span a merge or rebase, prefer `detect_changes scope=since-tag` over a literal commit-range diff. The graph projection survives rebases that the literal diff doesn't.
|
||
|
||
When the replay is across a release boundary, `analyze kind=releases` is the bridge: it stamps `meta.added_in` from git tags onto file nodes, so "symbols introduced in v1.3" is one filter away.
|
||
|
||
## Annotating the replay with prior context
|
||
|
||
`query_notes` and `query_memories` are how prior session decisions and cross-session invariants enter the timeline:
|
||
|
||
- `query_notes({since: <window-start>})` — every session note authored in the window; tag-filterable (`decision` / `bug` / `gotcha` / `follow-up`).
|
||
- `query_memories({tag: "decision", since: <window-start>})` — durable cross-session decisions stamped in the window.
|
||
|
||
These two surfaces are how a postmortem reads as a story rather than a list of file paths.
|
||
|
||
## Checklist
|
||
|
||
- `gortex enrich blame all` (CLI) at least once per session — the blame / releases / ownership analyzers need `meta.last_authored` to be populated
|
||
- `analyze kind=releases` for release-boundary replays
|
||
- `get_recent_changes` + `analyze kind=ownership` for the window-scoped change set
|
||
- `detect_changes` + `diff_context` to project the diff onto the graph
|
||
- `explain_change_impact` on every material symbol — second-order blast or it didn't happen
|
||
- `query_notes` + `query_memories` to ride commentary alongside the code timeline
|
||
- `export_context format=markdown` so the replay leaves the session as a shareable artifact
|
||
=== home/.hermes/skills/analysis/gortex-impact/SKILL.md ===
|
||
---
|
||
name: gortex-impact
|
||
description: "Assess what breaks if you change X before editing it."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, impact]
|
||
category: analysis
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Impact Analysis with Gortex
|
||
|
||
## Workflow
|
||
|
||
```
|
||
1. search_symbols({query: "X"}) -> Find the symbol ID
|
||
2. explain_change_impact({ids: "<id1>, <id2>"}) -> Risk-tiered blast radius
|
||
3. get_dependents({id: "<symbol-id>", depth: 3}) -> Detailed dependent tree
|
||
4. analyze({kind: "ownership", path_prefix: "<dir>/"}) -> Who owns this area (review pinging)
|
||
5. verify_change({id: "<id>", new_signature: "..."}) -> Check callers + interface implementors for signature-level breaks
|
||
6. contracts({action: "check"}) -> Cross-repo API breakage (HTTP/gRPC/GraphQL/topics)
|
||
7. analyze({kind: "would_create_cycle", from: "<a>", to: "<b>"}) -> Before adding a new dep
|
||
8. analyze({kind: "error_surface", path_prefix: "<dir>/"}) -> What error surface does this area produce — widening risk
|
||
9. get_test_targets({ids: ["<id1>", "<id2>"]}) -> Tests to re-run (includes cross-repo)
|
||
10. analyze({kind: "coverage_gaps", path_prefix: "<dir>/"}) -> Undertested code in the change area — extra-risky refactor zones
|
||
11. check_guards({ids: ["<id1>"]}) -> Project guard rules from .gortex.yaml
|
||
12. flow_between({source_id, sink_id}) -> Ranked dataflow paths between two symbols — catches consumers reached through helpers that get_dependents misses
|
||
13. taint_paths({source_pattern, sink_pattern}) -> Pattern-driven dataflow sweep — every flow from a matching source to a matching sink
|
||
14. detect_changes({scope: "staged"}) -> Pre-commit scope check
|
||
15. diff_context({scope: "staged"}) -> Graph-enriched diff for review
|
||
```
|
||
|
||
## Understanding Output
|
||
|
||
| Depth | Risk Level | Meaning |
|
||
| ----- | ---------------- | ------------------------ |
|
||
| d=1 | **WILL BREAK** | Direct callers/importers |
|
||
| d=2 | LIKELY AFFECTED | Indirect dependencies |
|
||
| d=3 | MAY NEED TESTING | Transitive effects |
|
||
|
||
## Checklist
|
||
|
||
- search_symbols to find exact symbol IDs
|
||
- explain_change_impact with all symbols you plan to change
|
||
- Review risk level (LOW/MEDIUM/HIGH/CRITICAL)
|
||
- Check by_depth: d=1 items WILL BREAK
|
||
- Note affected_processes and affected_communities
|
||
- analyze kind=ownership path_prefix=<dir>/ — who should review (pinging policy without CODEOWNERS)
|
||
- verify_change for every signature change (catches contract violations across repos)
|
||
- contracts action=check when changing HTTP routes, gRPC methods, topics, env contracts
|
||
- analyze kind=error_surface path_prefix=<dir>/ — confirm the change does not widen the error surface
|
||
- analyze kind=coverage_gaps path_prefix=<dir>/ — areas with weak coverage need extra scrutiny
|
||
- check_guards so team conventions from .gortex.yaml block bad changes early
|
||
- get_test_targets to see which test files need re-running
|
||
- Before commit: detect_changes to verify scope, diff_context for graph-enriched review
|
||
=== home/.hermes/skills/analysis/gortex-pr-review-agent/SKILL.md ===
|
||
---
|
||
name: gortex-pr-review-agent
|
||
description: "Coding-agent review verdict via the gortex review verb."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, pr-review-agent]
|
||
category: analysis
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# PR Review as a sub-agent (shell the review verb)
|
||
|
||
Use this when you are a coding agent (Codex / Claude Code / any CLI agent) and need a graph-grounded review verdict on a pending change **without** hand-walking the ten review gates yourself. Instead of orchestrating `detect_changes` / `diff_context` / `verify_change` / … one call at a time, shell the `gortex review` verb once and act on its terse, machine-first output.
|
||
|
||
The review engine runs the deterministic correctness rulepack, grounds every finding to an exact `file:line`, optionally folds in LLM findings, gates by confidence / severity, and prints a verdict — all server-side. You consume the result.
|
||
|
||
## Run the verb
|
||
|
||
```bash
|
||
# Terse, prose-free summary an agent can parse (one-line verdict + compact findings + cost):
|
||
gortex review --audience agent
|
||
|
||
# The same review as structured JSON when you want to branch on fields programmatically:
|
||
gortex review --audience agent --format json
|
||
```
|
||
|
||
Select the changeset the same way a human would:
|
||
|
||
- `--scope unstaged|staged|all|compare` — which working-tree changes to review (default `unstaged`)
|
||
- `--base <ref>` — review everything since a base ref (shorthand for compare)
|
||
- `--diff <file>` (or `--diff -` for stdin) — review a pasted unified diff instead of git
|
||
- `--use-llm` — additionally fold in LLM-found findings (needs a configured provider)
|
||
- `--repo <path>` — the repo the daemon tracks (default: current directory)
|
||
|
||
A daemon that tracks the repo must be running (`gortex daemon status`). The verb relays to the daemon; you never start the engine yourself.
|
||
|
||
## Read the terse output
|
||
|
||
`--audience agent` prints exactly three things, no narrative:
|
||
|
||
```
|
||
VERDICT: block (1 critical, 2 error)
|
||
findings:
|
||
internal/svc/handler.go:7 error go-inverted-err-check — inverted error check
|
||
internal/svc/loop.go:12 warning go-loop-query-call — query in loop
|
||
cost: in=1234 out=456 cache_r=2000 cache_w=0 usd=0.012000 elapsed=4.2s
|
||
```
|
||
|
||
- **Line 1** is the verdict — `block` / `review` / `approve` — with the kept-finding severity histogram in parentheses.
|
||
- The **findings** block has one compact line per finding: `file:line severity rule — message`. Each is anchored to a real new-side line, so you can open the file at that line directly.
|
||
- The **cost** line is the per-review token + USD accounting.
|
||
|
||
## Act on the verdict
|
||
|
||
| Verdict | What to do |
|
||
| ------- | ---------- |
|
||
| `block` | Do **not** merge / proceed. Fix every `critical` / `error` finding at its `file:line`, then re-run `gortex review --audience agent` until the verdict clears. |
|
||
| `review` | Address the `warning` findings or justify each one in the PR thread before merging. |
|
||
| `approve` | No blocking findings — proceed. |
|
||
|
||
When you want the full reasoning behind a verdict (per-file risk, contracts, guards, coverage), drop the `--audience agent` flag for the readable human packet, or use the `/gortex-pr-review` playbook to walk the ten gates by hand.
|
||
|
||
## Checklist
|
||
|
||
- `gortex daemon status` first — the verb needs a daemon tracking the repo
|
||
- `gortex review --audience agent` for the terse, parseable summary; add `--format json` to branch on fields
|
||
- Open each finding at its printed `file:line` — the anchor is exact, not approximate
|
||
- On `block`, fix and **re-run the verb** until it clears; do not merge a blocking verdict
|
||
- Escalate to the human packet (drop `--audience agent`) or `/gortex-pr-review` when you need the full gate-by-gate reasoning
|
||
=== home/.hermes/skills/analysis/gortex-pr-review/SKILL.md ===
|
||
---
|
||
name: gortex-pr-review
|
||
description: "Graph-grounded review of a pending change or PR."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, pr-review]
|
||
category: analysis
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# PR Review with Gortex (graph-grounded change review)
|
||
|
||
Use this when the user wants a code-review pass on a pending change — local staged diff, a branch about to merge, or a PR they're reading. The review walks the diff through the graph so the comments are grounded in real callers / contracts / coverage / guards, not surface-level style nitpicks.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. graph_stats -> Orient
|
||
2. detect_changes({scope: "staged"}) -> The change-set's graph projection (use "all" / "since-tag" as needed)
|
||
3. diff_context({scope: "staged"}) -> Graph-enriched diff: callers, callees, communities, processes, per-file risk
|
||
4. For each changed symbol:
|
||
explain_change_impact({ids: "<id>"}) -> Risk-tiered blast radius
|
||
verify_change({id: "<id>", new_signature: "<post-change sig>"}) -> Catch interface / contract breaks
|
||
5. contracts({action: "check"}) -> Provider ↔ consumer match across repos (HTTP / gRPC / topics / env / OpenAPI)
|
||
6. check_guards({ids: [<changed-ids>]}) -> Team conventions from .gortex.yaml
|
||
7. analyze({kind: "would_create_cycle", from: "<from>", to: "<to>"}) -> If the diff adds a new import edge, pre-flight it
|
||
8. analyze({kind: "coverage_gaps", path_prefix: "<changed dir>/", -> Did the change touch undertested code?
|
||
min_pct: 0, max_pct: 50})
|
||
9. get_untested_symbols({path_prefix: "<changed dir>/"}) -> Symbols still uncovered after the change
|
||
10. get_test_targets({ids: [<changed-ids>]}) -> Tests to re-run (cross-repo aware)
|
||
11. find_clones({path_prefix: "<changed dir>/", dead_only: true}) -> Did the change leave dead duplicates behind?
|
||
12. analyze({kind: "error_surface", path_prefix: "<changed dir>/"}) -> Did the change widen what gets thrown?
|
||
13. analyze({kind: "cross_repo", base_kind: "calls"}) -> Cross-repo blast (when multi-repo)
|
||
14. For high-risk changed symbols (d=1 in explain_change_impact):
|
||
preview_edit({edit: <the diff as a WorkspaceEdit>}) -> Speculative apply on the shadow graph; reports broken_callers / broken_implementors
|
||
15. surface_memories({task: "review <PR title>", symbol_ids: [...]}) -> Cross-session invariants on the touched symbols
|
||
16. export_context({format: "markdown", -> Review packet for the PR thread
|
||
sections: ["scope", "impact", "contracts",
|
||
"guards", "coverage", "tests",
|
||
"recommendations"]})
|
||
```
|
||
|
||
## Review priorities
|
||
|
||
Walk every PR through these gates, in order. A failure at gate N is a blocker — do not move to gate N+1 until N is addressed:
|
||
|
||
| Gate | Tool | Blocker if … |
|
||
| ---- | ----------------------------------------------- | ------------ |
|
||
| **1. Scope** | `detect_changes` | Touches files / symbols the PR description doesn't mention |
|
||
| **2. Signature safety** | `verify_change` per signature change | Callers / implementors break |
|
||
| **3. Contract safety** | `contracts({action: check})` | Orphan providers / consumers; cross-repo wire drift |
|
||
| **4. Convention compliance** | `check_guards` | Project rules from `.gortex.yaml` violated |
|
||
| **5. Coupling sanity** | `analyze kind=would_create_cycle` | New import edge introduces a cycle |
|
||
| **6. Coverage hygiene** | `analyze kind=coverage_gaps` + `get_untested_symbols` | Changed code is uncovered or under-covered |
|
||
| **7. Test discoverability** | `get_test_targets` | The PR adds a symbol with no covering test target |
|
||
| **8. Dead duplication** | `find_clones dead_only=true` | Refactor left a dead duplicate of live code |
|
||
| **9. Blast verification** | `preview_edit` on high-risk changes | Speculative apply reports `broken_callers` or `broken_implementors` that the diff doesn't address |
|
||
| **10. Memory check** | `surface_memories` on touched symbols | Diff contradicts a pinned invariant / decision / gotcha |
|
||
|
||
## Cross-repo PRs
|
||
|
||
When the PR touches a multi-repo project:
|
||
|
||
- `detect_changes` only sees the local repo's changes; also run `contracts({action: check})` to flag wire-side breakage in consumer repos
|
||
- `analyze kind=cross_repo base_kind=calls repo=<changed repo>` lists every consumer call that crosses out of the changed repo
|
||
- `get_test_targets` returns the cross-repo tests that exercise the affected wire path — those tests must be on the reviewer's run list
|
||
|
||
## Review deliverable
|
||
|
||
Hand the PR author a structured comment block, not a stream-of-consciousness comment:
|
||
|
||
```markdown
|
||
## Review — <PR title>
|
||
|
||
### Scope
|
||
- ✅ / ⚠ — `detect_changes` matches the PR description
|
||
- Touched: N files, M symbols, K cross-repo edges
|
||
|
||
### Impact
|
||
- High-risk: <id> · d=1 blast — see `explain_change_impact`
|
||
- Medium: …
|
||
|
||
### Contracts
|
||
- ✅ / ❌ — `contracts({action: check})` summary
|
||
|
||
### Guards
|
||
- ✅ / ❌ — `check_guards` summary
|
||
|
||
### Coverage
|
||
- Uncovered after this PR: <symbol ids> (`get_untested_symbols`)
|
||
- Coverage gap deltas: …
|
||
|
||
### Tests
|
||
- `get_test_targets` recommends: …
|
||
|
||
### Speculative apply (for high-risk changes)
|
||
- `preview_edit` flagged: broken_callers=…, broken_implementors=…
|
||
|
||
### Recommendations
|
||
1. …
|
||
2. …
|
||
```
|
||
|
||
`export_context format=markdown sections=[...]` produces this skeleton automatically.
|
||
|
||
## When the diff is already on disk
|
||
|
||
If the diff is in the working tree (or a feature branch checked out), `detect_changes` + `diff_context` see it directly. If the user pasted in a unified diff or a GitHub URL, parse it into a synthetic `WorkspaceEdit` and drive `preview_edit` to get the speculative report — same blast / broken-callers / broken-implementors signal without touching disk.
|
||
|
||
## Checklist
|
||
|
||
- `index_health` — confirm Gortex sees the working tree (`graph_stats` for counts)
|
||
- `detect_changes` + `diff_context` produce the graph-grounded scope + per-file risk
|
||
- Walk the **10 gates** above in order; do not skip ahead on a blocker
|
||
- `contracts({action: check})` is **mandatory** for any PR that touches a provider symbol — the orphan check catches wire drift the diff doesn't
|
||
- `check_guards` runs the team's `.gortex.yaml` rules — these encode conventions a reviewer would otherwise have to remember
|
||
- For high-risk changes, `preview_edit` the diff as a `WorkspaceEdit` and read `broken_callers` / `broken_implementors`; the speculative report is the highest-confidence signal in the review
|
||
- `surface_memories` on the touched symbols before finalising the review — a diff that contradicts a pinned invariant is a blocker, not a nit
|
||
- `export_context format=markdown` for the structured review block; never hand the user a stream-of-consciousness comment
|
||
- Cross-repo PRs: `contracts({action: check})` + `analyze kind=cross_repo` + `get_test_targets` (cross-repo aware)
|
||
=== home/.hermes/skills/analysis/gortex-quality-audit/SKILL.md ===
|
||
---
|
||
name: gortex-quality-audit
|
||
description: "Repo-scale quality scan — dead code, hotspots, clones."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, quality-audit]
|
||
category: analysis
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Quality Audit with Gortex (repo health scan)
|
||
|
||
Use this when the user wants a structured pass over a repo / directory looking for code-quality issues at scale — dead code, hotspots, cycles, churn, todos, coverage gaps, clones, anti-pattern smells, configuration drift. The output is a prioritised punch list, not a verdict; each finding is grounded in a graph query the user can re-run.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. graph_stats -> Orient
|
||
2. gortex enrich blame coverage releases all (CLI; once) -> Stamp the metadata the temporal + coverage analyzers need
|
||
3. analyze({kind: "dead_code", path_prefix: "<dir>/"}) -> Symbols with zero incoming edges (excludes entry points + tests)
|
||
4. find_clones({path_prefix: "<dir>/", dead_only: true}) -> Dead duplicates of live code — the segment-unique diagnostic
|
||
5. analyze({kind: "hotspots", path_prefix: "<dir>/"}) -> Over-coupled symbols by fan-in / fan-out / community crossings
|
||
6. analyze({kind: "cycles", path_prefix: "<dir>/"}) -> Tarjan SCCs with severity
|
||
7. analyze({kind: "todos", path_prefix: "<dir>/"}) -> TODO / FIXME / HACK nodes
|
||
8. analyze({kind: "stale_code", older_than: 365, path_prefix: "<dir>/"}) -> Code untouched 1y+ — refactor / delete candidates
|
||
9. analyze({kind: "stale_flags", older_than: 180}) -> Feature flags whose every toggler is older than 6mo
|
||
10. analyze({kind: "coverage_summary", path_prefix: "<dir>/"}) -> Per-directory coverage rollup
|
||
11. analyze({kind: "coverage_gaps", path_prefix: "<dir>/", -> Undertested symbols
|
||
min_pct: 0, max_pct: 50})
|
||
12. get_untested_symbols({path_prefix: "<dir>/"}) -> Symbols with zero covering tests
|
||
13. analyze({kind: "error_surface", path_prefix: "<dir>/"}) -> Functions and what they throw — risk concentration
|
||
14. analyze({kind: "field_writers"}) -> Mutability hotspots — fields ranked by write count
|
||
15. analyze({kind: "race_writes"}) -> Cross-language goroutine-reachable writes w/o lock
|
||
16. analyze({kind: "unclosed_channels"}) -> Channels with sends but no close()
|
||
17. analyze({kind: "orphan_tables"}) -> Tables queried but missing a migration
|
||
18. analyze({kind: "unreferenced_tables"}) -> Tables provided by a migration with zero readers
|
||
19. analyze({kind: "stale_flags"}) -> Dead-rollout flag candidates (rerun with smaller window if noisy)
|
||
20. analyze({kind: "sast", path_prefix: "<dir>/", severity: "high"}) -> CWE/OWASP-tagged security scan — 190+ rules across 8 languages
|
||
21. analyze({kind: "named", name: "<bundle>"}) -> Named query bundles — sql-injection, hardcoded-secrets, ssrf, xxe, weak-crypto, …
|
||
22. analyze({kind: "unsafe_patterns", path_prefix: "<dir>/"}) -> Panic-prone / undefined-behavior primitives across all languages
|
||
23. search_ast({detector: "<lang-specific detector>"}) -> Targeted structural anti-pattern sweep (see list_inspections for the menu)
|
||
24. analyze({kind: "health_score", path_prefix: "<dir>/", -> Composite per-file health grade — ranks the worst files first
|
||
roll_up: "file"})
|
||
25. audit_agent_config -> Stale references in CLAUDE.md / AGENTS.md / .cursor/rules — config drift
|
||
26. contracts({action: "check"}) -> Orphan providers / consumers; HTTP / gRPC / topics / env drift
|
||
27. analyze({kind: "ownership", path_prefix: "<dir>/"}) -> Per-author rollup — who to ping per finding
|
||
28. export_context({format: "markdown", -> Hand the audit packet to PR / Slack / wiki
|
||
sections: ["findings", "ownership", "priorities"]})
|
||
```
|
||
|
||
## Prioritising findings
|
||
|
||
Findings are not equal. Rank by:
|
||
|
||
| Tier | Filter | Why this matters first |
|
||
| ---- | ---------------------------------------------------------------------------------------- | ---------------------- |
|
||
| **P0** | `analyze kind=sast severity=high` / `analyze kind=named` / `race_writes` / `unclosed_channels` / `weak-crypto` / `hardcoded-secret` / `http-client-no-timeout` | Correctness / security |
|
||
| **P1** | `cycles severity=severe` / `orphan_tables` / `contracts({action: check})` orphans / `audit_agent_config` stale refs | Real bugs latent in the graph |
|
||
| **P2** | `dead_code` ∩ `find_clones dead_only=true` / `stale_flags` / `stale_code` | Deletion candidates — easy ROI |
|
||
| **P3** | `hotspots top=20` / `coverage_gaps min_pct=0 max_pct=20` / `error_surface` widening | Refactor targets |
|
||
| **P4** | `todos` / `field_writers` heavy churn | Backlog signal |
|
||
|
||
Always pair every P0 / P1 finding with `analyze kind=ownership` on its path so the audit packet pings the right reviewer.
|
||
|
||
## Security & anti-pattern sweep
|
||
|
||
`analyze kind=sast` is the comprehensive pass — 190+ CWE/OWASP-tagged rules across 8 languages, filterable by `severity` / `cwe` / `tag`. `analyze kind=named` runs focused query bundles (sql-injection, hardcoded-secrets, ssrf, xxe, …). `search_ast` then targets specific structural smells — a representative subset of its bundled detectors:
|
||
|
||
| Detector | Languages |
|
||
| --------------------------------- | ------------------------------------ |
|
||
| `error-not-wrapped` | Go |
|
||
| `sql-string-concat` | Go / Python / JS / TS / Ruby |
|
||
| `weak-crypto` | Go / Python |
|
||
| `panic-in-library` | Go |
|
||
| `goroutine-without-recover` | Go |
|
||
| `http-client-no-timeout` | Go |
|
||
| `hardcoded-secret` | Go / Python / JS / TS / Ruby |
|
||
| `empty-catch` | Java / JS / TS / Python |
|
||
| `java-string-equality` | Java |
|
||
| `python-mutable-default-arg` | Python |
|
||
|
||
Run each `search_ast detector=<name>` once; the per-match `symbol_id` chains directly into `find_usages` / `apply_code_action` for follow-up.
|
||
|
||
## Audit deliverable
|
||
|
||
The output of a quality audit is a prioritised markdown packet, not a one-line "score":
|
||
|
||
```
|
||
# <Repo / dir> audit — <date>
|
||
|
||
## P0 — Correctness / security
|
||
- <finding> · <symbol id> · owner: <author> · evidence: <analyze kind=… ran>
|
||
|
||
## P1 — Real bugs latent in the graph
|
||
…
|
||
|
||
## P2 — Deletion candidates
|
||
…
|
||
|
||
## P3 — Refactor targets
|
||
…
|
||
|
||
## P4 — Backlog signal
|
||
…
|
||
```
|
||
|
||
`export_context format=markdown` is the producer.
|
||
|
||
## Checklist
|
||
|
||
- `gortex enrich blame coverage releases all` (CLI) before the audit — temporal + coverage analyzers need `meta.last_authored` / `meta.coverage_pct` / `meta.added_in`
|
||
- Walk the analyzers in the order above — earlier ones surface highest-priority findings
|
||
- Pair every finding with `analyze kind=ownership` so the audit packet has a routing column
|
||
- `analyze kind=sast` is the security backbone; add `search_ast` detectors for the language-specific smells it doesn't cover
|
||
- `audit_agent_config` catches stale references in the team's CLAUDE.md / AGENTS.md / IDE config — config drift is a real-world finding
|
||
- Rank by the P0..P4 tiers; do not hand the user a flat list
|
||
- `export_context format=markdown` for the packet
|
||
- `store_memory({kind: "reference", title: "<repo> audit YYYY-MM", body: "..."})` so the next audit can diff against this baseline
|
||
=== home/.hermes/skills/code-intelligence/gortex-cli/SKILL.md ===
|
||
---
|
||
name: gortex-cli
|
||
description: "Drive Gortex from the shell via the gortex CLI, no MCP surface."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, cli]
|
||
category: code-intelligence
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
|
||
# Gortex from the CLI (no MCP surface)
|
||
|
||
Every Gortex capability is reachable from the `gortex` command, so you can work the graph from a plain shell — no MCP server mounted, no extra tools in your context. Reach for this when the MCP surface is unavailable or impractical (a CI job, a low-context budget, a shell-only agent), or when you simply prefer the command line.
|
||
|
||
This is a **toolkit, not a mandate**: pick the verbs your task needs. The sequence below is a reference safety workflow for changing code — run the steps that apply and skip the rest. Most verbs accept `--format json` for machine-readable output and `--repo <path>` to target a tracked repo other than the cwd. They all talk to a running daemon, so `gortex daemon status` first if anything errors.
|
||
|
||
## Orient
|
||
|
||
```bash
|
||
gortex query stats
|
||
```
|
||
|
||
Confirms the daemon is up and prints node / edge counts for the active repo — the CLI analogue of a session-start orientation.
|
||
|
||
## Assemble the working set
|
||
|
||
```bash
|
||
gortex explore "make the indexer skip vendored files"
|
||
```
|
||
|
||
Shells smart_context: one call returns the minimal relevant symbols, sources, and an edit plan for a task description. Start here instead of reading files one at a time. Note the symbol IDs it surfaces — later verbs take them as `--ids` / `--symbols`.
|
||
|
||
## Pick up prior knowledge
|
||
|
||
```bash
|
||
gortex memory surface --task "make the indexer skip vendored files" --symbols internal/indexer/indexer.go::IndexFile,internal/indexer/skip.go::shouldSkip
|
||
```
|
||
|
||
Surfaces cross-session invariants, decisions, and gotchas anchored to your working set, ranked by overlap. If it returns nothing, move on — don't probe further.
|
||
|
||
## Before editing a file
|
||
|
||
```bash
|
||
gortex edit context internal/indexer/indexer.go
|
||
```
|
||
|
||
Shows the file's symbols, signatures, callers, and callees so you edit with the blast radius in view.
|
||
|
||
## Before a signature change
|
||
|
||
```bash
|
||
gortex edit verify --change 'internal/indexer/indexer.go::IndexFile=func(path string, opts Opts) error'
|
||
```
|
||
|
||
Checks every caller and interface implementor against the proposed signature and reports what would break. `--change` is repeatable (`id=new_signature`); pass a raw JSON array via `--changes` / `--changes-file` for bulk edits.
|
||
|
||
## Plan a multi-symbol refactor
|
||
|
||
```bash
|
||
gortex edit plan --ids internal/indexer/indexer.go::IndexFile,internal/indexer/skip.go::shouldSkip
|
||
```
|
||
|
||
Returns a dependency-ordered list of files and symbols to touch, so a multi-file change goes in the right order.
|
||
|
||
## Apply edits atomically
|
||
|
||
```bash
|
||
gortex edit batch --edits-file edits.json
|
||
```
|
||
|
||
Applies multiple edits in one atomic, dependency-ordered pass. Build `edits.json` as the edits array (or pass it inline with `--edits`, or on stdin with `--edits -`); add `--dry-run` to preview the unified diff first.
|
||
|
||
## After editing
|
||
|
||
```bash
|
||
gortex edit guards --ids internal/indexer/indexer.go::IndexFile
|
||
gortex edit tests --ids internal/indexer/indexer.go::IndexFile
|
||
```
|
||
|
||
`guards` evaluates team rules against the changed symbols; `tests` enumerates the test files and functions that exercise them so you know what to run.
|
||
|
||
## Close the loop
|
||
|
||
```bash
|
||
gortex feedback record --task "make the indexer skip vendored files" --useful internal/indexer/skip.go::shouldSkip
|
||
gortex memory store --kind decision --body "skip lives in shouldSkip; IndexFile stays signature-stable for the daemon hot path" --symbols internal/indexer/skip.go::shouldSkip
|
||
```
|
||
|
||
`feedback record` scores which `explore` suggestions were useful / not needed / missing, improving future context quality. `memory store` persists a durable invariant / decision / gotcha so the next agent inherits the lesson — set `--kind` honestly and anchor it with `--symbols`.
|
||
|
||
## When you need more
|
||
|
||
These verbs cover the dev-cycle workhorses. For the long tail of the catalog, discover and invoke any tool directly:
|
||
|
||
```bash
|
||
gortex tools list # the whole surface, by category + read/write class
|
||
gortex tools search "dataflow taint" # find a tool by keyword
|
||
gortex call analyze --arg kind=dead_code --arg path=internal/indexer
|
||
```
|
||
|
||
`gortex call <tool> --arg key=value` is the generic escape hatch — it invokes any registered tool by name, so nothing in the MCP surface is out of reach from the shell. There are also dedicated verb groups worth knowing: `gortex analyze`, `gortex flow` / `gortex taint`, `gortex clones`, and the rest of the `gortex edit` and `gortex memory` families.
|
||
=== home/.hermes/skills/code-intelligence/gortex/SKILL.md ===
|
||
---
|
||
name: gortex
|
||
description: "Use for any task on a codebase indexed by the gortex daemon — searching symbols, finding usages/callers, reading code, tracing impact, refactoring, and multi-repo navigation. Prefer these graph tools over raw file reads or text search."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, code-search, navigation, refactoring, mcp]
|
||
category: code-intelligence
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex-add-test, gortex-architecture-review, gortex-cli, gortex-co-change, gortex-cross-repo-usage, gortex-dataflow-trace, gortex-debug, gortex-episode-replay, gortex-explore, gortex-extract-function, gortex-fix-all, gortex-impact, gortex-incident-investigation, gortex-onboarding, gortex-pr-review, gortex-pr-review-agent, gortex-quality-audit, gortex-refactor, gortex-rename, gortex-safe-edit]
|
||
---
|
||
|
||
# Gortex Code Intelligence
|
||
|
||
Gortex indexes repositories into an in-memory knowledge graph and serves it over MCP. On any indexed codebase its graph tools are faster, cheaper, and more accurate than reading whole files or grepping — they return exactly the symbol, caller set, or blast radius you asked for, with zero false positives.
|
||
|
||
## When to Use
|
||
|
||
- Searching for a symbol, function, type, or where something is referenced.
|
||
- Reading a single function/method without pulling its whole file.
|
||
- Understanding architecture, tracing call chains, or checking what a change breaks.
|
||
- Refactoring: renames, extractions, and multi-file edits that must stay consistent.
|
||
- Working across more than one repository from a single session.
|
||
|
||
## Prerequisites
|
||
|
||
- The `gortex` MCP server is registered in `~/.hermes/config.yaml` under `mcp_servers.gortex` (gortex's installer wires this for you).
|
||
- The gortex daemon is running and tracking the repo: check with `gortex daemon status` in a terminal, start it with `gortex daemon start --detach`, and track a repo with `gortex init` (or `gortex track <path>`).
|
||
- Confirm the graph is live at the start of a task by calling the `graph_stats` tool. If `total_nodes` is 0, call `index_repository` with `path: "."` first.
|
||
|
||
## How to Run
|
||
|
||
Call the gortex MCP tools directly. Translate the instinct to read or grep into the matching graph query. If you only have the terminal (no MCP tools), every tool below is reachable as `gortex call <tool> --arg k=v` (e.g. `gortex call read_file --arg path=<file>`) — there is no bare `gortex <tool>` verb.
|
||
|
||
### Search and navigation
|
||
|
||
| Instead of... | Use the gortex tool... |
|
||
|------------------------------------------|----------------------------------------------|
|
||
| Grepping for a symbol | `search_symbols` (BM25 + camelCase-aware) |
|
||
| Grepping for references | `find_usages` (zero false positives) |
|
||
| Hunting for callers | `get_callers` / `get_call_chain` |
|
||
| Globbing source files (`**/*.go`) | `get_repo_outline` / `search_symbols` |
|
||
| Many file reads to orient on a task | `smart_context` (one call assembles the working set) |
|
||
| Literal / regex text the symbol index misses | `search_text` (trigram-accelerated grep) |
|
||
|
||
### Reading source
|
||
|
||
| Instead of... | Use the gortex tool... |
|
||
|------------------------------------------|----------------------------------------------|
|
||
| Reading a whole file for one function | `get_symbol_source` (≈80% fewer tokens) |
|
||
| Reading a file to understand it | `get_file_summary` / `get_editing_context` |
|
||
| Reading a file to check a signature | `get_symbol` (signature in `meta.signature`) |
|
||
| Reading a non-indexed / raw file | `read_file` (atomic, overlay-aware) |
|
||
|
||
### Editing and refactoring
|
||
|
||
| Instead of... | Use the gortex tool... |
|
||
|------------------------------------------|----------------------------------------------|
|
||
| A whole-file string-match edit | `edit_file` (no pre-read; atomic; auto-reindex) |
|
||
| A read→edit roundtrip for one symbol | `edit_symbol` (edit by ID) |
|
||
| Manual find-and-replace for a rename | `rename_symbol` (updates cross-file references) |
|
||
| Sequencing multi-file edits by hand | `batch_edit` (dependency-ordered, atomic) |
|
||
| Guessing what a change breaks | `verify_change` / `get_dependents` (blast radius) |
|
||
|
||
### Analysis
|
||
|
||
`analyze` is a unified dispatcher — pass `kind` for one of `dead_code`, `hotspots`, `cycles`, `coverage_gaps`, `todos`, `sast`, `impact`, `cross_repo`, and ~50 more. `get_architecture` gives a one-call architectural snapshot.
|
||
|
||
## Multi-repo scoping
|
||
|
||
The daemon can track several repositories at once. Scope your queries so results come from the right project:
|
||
|
||
- Call `get_active_project` to see the current scope and `set_active_project` to switch the session default.
|
||
- Most list/search tools accept a `repo` or `project` argument to target one repository for a single call without changing the session default.
|
||
- `list_repos` enumerates everything the daemon tracks; `track_repository` adds a new one.
|
||
- `analyze kind: "cross_repo"` and a `find_usages` partitioned by repo answer "who consumes this across all our services?".
|
||
|
||
## Quick Reference
|
||
|
||
1. `index_health` — confirm the daemon is up and oriented (`graph_stats` for node/edge counts).
|
||
2. `smart_context` with the task description — assemble the minimal working set.
|
||
3. `search_symbols` / `find_usages` / `get_symbol_source` — navigate and read.
|
||
4. `get_editing_context` then `edit_symbol` / `edit_file` / `rename_symbol` / `batch_edit` — edit safely.
|
||
5. `verify_change` / `get_test_targets` — check the blast radius before and after.
|
||
|
||
## Token economy
|
||
|
||
For list-shaped responses (`search_symbols`, `find_usages`, `analyze`, `get_callers`, `get_editing_context`, `smart_context`, …) pass `format: "gcx"` for the GCX1 compact wire format — round-trippable, ~27% fewer tokens. For reading source, pass `compress_bodies: true` to `read_file` / `get_symbol_source` / `get_editing_context` to elide function bodies to signatures (~30–40% of original tokens).
|
||
|
||
## Pitfalls
|
||
|
||
- Don't fall back to raw file reads / shell grep on an indexed repo "just to be quick" — the graph tools are both faster and more precise, and they keep your context budget intact.
|
||
- An empty result from `search_symbols` usually means the daemon hasn't finished warming or isn't tracking this repo — check `graph_stats` / `index_health` rather than assuming the symbol is absent.
|
||
- In a multi-repo session, an unexpected result set is often a scoping issue — verify `get_active_project` or pass an explicit `repo` argument.
|
||
|
||
## Verification
|
||
|
||
After edits, call `verify_change` (broken callers + interface implementors, cross-repo) and `get_test_targets` (the tests that cover what you touched) before declaring the task done.
|
||
|
||
## Task playbooks (slash commands)
|
||
|
||
`gortex install` also registers these per-task playbooks as Hermes slash commands. Reach for the one that matches your task:
|
||
|
||
- `/gortex-add-test`
|
||
- `/gortex-architecture-review`
|
||
- `/gortex-cli`
|
||
- `/gortex-co-change`
|
||
- `/gortex-cross-repo-usage`
|
||
- `/gortex-dataflow-trace`
|
||
- `/gortex-debug`
|
||
- `/gortex-episode-replay`
|
||
- `/gortex-explore`
|
||
- `/gortex-extract-function`
|
||
- `/gortex-fix-all`
|
||
- `/gortex-impact`
|
||
- `/gortex-incident-investigation`
|
||
- `/gortex-onboarding`
|
||
- `/gortex-pr-review`
|
||
- `/gortex-pr-review-agent`
|
||
- `/gortex-quality-audit`
|
||
- `/gortex-refactor`
|
||
- `/gortex-rename`
|
||
- `/gortex-safe-edit`
|
||
=== home/.hermes/skills/debugging/gortex-debug/SKILL.md ===
|
||
---
|
||
name: gortex-debug
|
||
description: "Debug a bug, trace an error, or find why something fails."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, debug]
|
||
category: debugging
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Debugging with Gortex
|
||
|
||
## Workflow
|
||
|
||
```
|
||
1. search_symbols({query: "<error or suspect>"}) -> Find related symbols
|
||
2. get_callers({id: "<suspect>"}) -> Who calls it?
|
||
3. get_call_chain({id: "<suspect>"}) -> What does it call?
|
||
4. get_editing_context({path: "<file>"}) -> Full file context
|
||
5. get_processes({id: "<process>"}) -> Trace execution flow
|
||
6. get_symbol_history -> Symbols churning this session (regression hotspot)
|
||
7. explain_change_impact({ids: "<fix target>"}) -> Who else will feel the fix
|
||
```
|
||
|
||
## Debugging Patterns
|
||
|
||
| Symptom | Gortex Approach |
|
||
| ----------------------- | --------------- |
|
||
| Error message | search_symbols for error-related names -> get_callers on throw sites; analyze kind=error_surface to map who throws what |
|
||
| Wrong return value | get_call_chain on the function -> trace callees for data flow; flow_between({source_id, sink_id}) when you suspect the wrong value flows through helpers |
|
||
| Trace bad value to its origin | flow_between({source_id: producer, sink_id: consumer}) — ranked dataflow paths over value_flow / arg_of / returns_to. Faster than reading source for "where did this value come from?" |
|
||
| Find every taint into a sink | taint_paths({source_pattern: "name:Source", sink_pattern: "name:Sink"}) — every flow from any matching source to any matching sink (functions auto-expand to their params on the sink side) |
|
||
| Intermittent failure | get_editing_context -> look for external calls, async deps; analyze kind=goroutine_spawns to find unowned background work |
|
||
| Channel deadlock | analyze kind=channel_ops -> channels with sends but no receivers (or vice versa) |
|
||
| Performance issue | find_usages -> find symbols with many callers (hot paths) |
|
||
| Recent regression | detect_changes -> see what your changes affect. get_symbol_history flags symbols edited 3+ times this session |
|
||
| Flaky test | get_untested_symbols near the suspect -> find coverage gaps the flake may hide |
|
||
| Stale index suspect | index_health -> parse failures and stale files can mask the real bug |
|
||
| Stale-flag suspect | analyze kind=stale_flags -> flags with every caller untouched for `older_than` days are dead-rollout candidates |
|
||
| Config drift | analyze kind=config_readers -> who reads this env/viper key? Surfaces forgotten readers |
|
||
| Event/log volume spike | analyze kind=event_emitters with level=error -> find every site that logs an error |
|
||
| Mutation race suspicion | analyze kind=field_writers id=<field> -> every function that writes the contended field |
|
||
| Annotation drift | analyze kind=annotation_users name=Deprecated -> every site still using a deprecated API |
|
||
| Env var read/write mismatch | find_usages on cfg::env::<NAME> -> Resources/Dockerfile stages declaring it (EdgeUsesEnv) plus code-side os.Getenv consumers via the shared config_key node |
|
||
| K8s manifest blast radius | analyze kind=k8s_resources k8s_kind=ConfigMap -> orphan ConfigMaps. find_usages on a ConfigMap Resource ID surfaces every workload that envFroms or mounts it |
|
||
| Container image audit | analyze kind=images role=base -> every external image and how many Dockerfile stages / K8s Resources pull it. Filter by tag=latest to find the unpinned ones |
|
||
=== home/.hermes/skills/debugging/gortex-incident-investigation/SKILL.md ===
|
||
---
|
||
name: gortex-incident-investigation
|
||
description: "Walk a production symptom back to its root cause."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, incident-investigation]
|
||
category: debugging
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Incident Investigation with Gortex
|
||
|
||
Use this when an alert fired, a deploy regressed, or production is misbehaving and the user needs to walk back from the symptom (log line, error message, broken endpoint, failing test in CI) to the root cause. Wraps the debug + impact + recent-changes paths into one ordered drill so the investigator never loses the thread.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. graph_stats -> Confirm index + orient
|
||
2. surface_memories({task: "<symptom>"}) -> Prior incidents / invariants on the same area
|
||
3. search_symbols({query: "<error string or symbol name from the alert>"}) -> Resolve the suspect symbol
|
||
4. get_recent_changes({since_ts: <alert_time - 24h>}) -> Files/symbols changed in the suspect window
|
||
5. get_symbol_history -> Symbols churning this session (regression hotspot)
|
||
6. analyze({kind: "error_surface", path_prefix: "<suspect dir>/"}) -> Throw sites that match the symptom
|
||
7. analyze({kind: "event_emitters", level: "error", -> Every log/metric site that could have produced the alert
|
||
path_prefix: "<suspect dir>/", name: "<event token>"})
|
||
8. get_callers({id: "<suspect symbol>"}) -> Who calls the suspect — narrow blast
|
||
9. get_call_chain({id: "<suspect symbol>"}) -> What the suspect calls — downstream contributors
|
||
10. flow_between({source_id: "<input>", sink_id: "<suspect>"}) -> Trace the bad value's path (when applicable)
|
||
11. taint_paths({source_pattern: "name:<external input>", -> Every flow from a kind of source to the suspect
|
||
sink_pattern: "name:<suspect>"})
|
||
12. analyze({kind: "field_writers", id: "<contended field>"}) -> Race / mutation suspects
|
||
13. analyze({kind: "channel_ops"}) -> Channel deadlock / orphan recv (Go)
|
||
14. analyze({kind: "goroutine_spawns"}) -> Unowned background work
|
||
15. explain_change_impact({ids: "<root-cause id>"}) -> Blast radius of the proposed fix
|
||
16. get_test_targets({ids: ["<root-cause id>"]}) -> Tests to add / re-run as regression coverage
|
||
17. store_memory({kind: "incident", title: "<incident slug>", -> Persist root cause + fix + affected symbols
|
||
body: "...", symbol_ids: ["<id>"], importance: 5})
|
||
```
|
||
|
||
## Triage by symptom
|
||
|
||
| Symptom | First-stop tools |
|
||
| -------------------------------------------------------- | ------------------------------------------------------------ |
|
||
| New 5xx / panic / crash log | `search_symbols` on the error → `analyze kind=error_surface` → `get_callers` on throw sites |
|
||
| Latency spike on one endpoint | `analyze kind=routes path=<route>` → `get_call_chain` on the handler → `analyze kind=external_calls` for hot stdlib / module hops |
|
||
| Background worker silently broken | `analyze kind=goroutine_spawns` / `channel_ops` → `get_callers` on the spawned target |
|
||
| Pub/sub event missing | `analyze kind=pubsub name=<topic>` → publisher + subscriber sides; `taint_paths` from publisher to subscriber handler |
|
||
| Config-driven misbehavior after a deploy | `analyze kind=config_readers name=<KEY>` → callers; `analyze kind=stale_flags` if it's a feature flag |
|
||
| Data corruption / wrong value at a sink | `flow_between` from suspected source to sink; `taint_paths` when multiple sources are plausible |
|
||
| Cross-service / contract drift | `contracts({action: check})` → orphan providers/consumers; pair with `/gortex-cross-repo-usage` |
|
||
| Test regression after a refactor | `detect_changes` over the merge → `diff_context` for graph-enriched view → `get_test_targets` for the missing test signal |
|
||
|
||
## Walking the timeline
|
||
|
||
When the symptom appears tied to a window (between two deploys, between two commits, since N hours ago):
|
||
|
||
1. `analyze kind=blame` to stamp `meta.last_authored` on every blame-eligible symbol (one-time per session; cheap thereafter)
|
||
2. `get_recent_changes since_ts=<window-start>` to enumerate files / symbols touched
|
||
3. `detect_changes scope=all` to project the diff onto blast radius
|
||
4. Pair each touched symbol with `explain_change_impact` — anything in the d=1/d=2 buckets that overlaps the symptom area is your root-cause candidate
|
||
5. `get_symbol_history` flags symbols edited 3+ times *in this session*; combine with blame for "edited 3+ times in the suspect window"
|
||
|
||
## Closing the loop (mandatory)
|
||
|
||
After root-cause is found and the fix is shipped:
|
||
- `store_memory({kind: "incident", ...})` so the next on-call sees this pattern surfaced via `surface_memories`
|
||
- If the incident exposed an invariant the code lacked guard for (lock missing, contract unenforced), also `store_memory({kind: "invariant", importance: 5, pinned: true})`
|
||
- `save_note({tags: "incident", body: ...})` for the session-local timeline before context compacts
|
||
|
||
## Checklist
|
||
|
||
- `graph_stats` + `surface_memories` before any search — prior incident memories are the highest-value signal
|
||
- `search_symbols` on the actual error string / symbol from the alert — do not paraphrase
|
||
- `get_recent_changes` + `get_symbol_history` to scope the window
|
||
- `analyze kind=error_surface` + `event_emitters` to find the production sites of the symptom
|
||
- `get_callers` / `get_call_chain` / `flow_between` / `taint_paths` to walk from symptom toward root cause
|
||
- Concurrency-shape symptoms → `channel_ops` / `goroutine_spawns` / `field_writers` / `race_writes` / `unclosed_channels`
|
||
- `explain_change_impact` on the candidate fix; `get_test_targets` for regression coverage
|
||
- `store_memory({kind: "incident"})` is **mandatory** before declaring the investigation closed
|
||
=== home/.hermes/skills/navigation/gortex-cross-repo-usage/SKILL.md ===
|
||
---
|
||
name: gortex-cross-repo-usage
|
||
description: "Find who uses a symbol across all consumer repos."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, cross-repo-usage]
|
||
category: navigation
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Cross-Repo Usage with Gortex
|
||
|
||
Use this when the user needs to see who uses a symbol **across every consumer repo**, not just the one they happen to be in. Wraps `find_usages` + the cross-repo edge layer (`cross_repo_calls` / `cross_repo_implements` / `cross_repo_extends`) so the answer is partitioned by repo and includes contract-level consumers (HTTP / gRPC / topics) that wouldn't show up as a direct call edge.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. get_active_project -> See current scope (single repo or multi-repo project)
|
||
2. list_repos -> See which repos are tracked
|
||
3. For each consumer repo not yet tracked:
|
||
track_repository({path: "<consumer repo path>"}) -> Index immediately, persist to config
|
||
4. set_active_project({name: "<multi-repo project>"}) -> Switch scope so subsequent queries span repos
|
||
5. search_symbols({query: "X"}) -> Resolve the symbol ID in the providing repo
|
||
6. find_usages({id: "<id>"}) -> All references; group by repo prefix
|
||
7. analyze({kind: "cross_repo", -> Repo-boundary-crossing edges with relation
|
||
base_kind: "calls|implements|extends",
|
||
repo: "<providing repo>"})
|
||
8. contracts({action: "check"}) -> Contract-level consumers (HTTP routes, gRPC methods, topics, env, OpenAPI)
|
||
9. get_test_targets({ids: [<id>]}) -> Cross-repo tests that exercise this symbol
|
||
10. export_context({format: "markdown"}) -> Per-repo report for PR / Slack / docs
|
||
```
|
||
|
||
## Partitioning `find_usages` by repo
|
||
|
||
The graph stores repo as a prefix on each node ID. Group results by the leading path segment so the user sees one section per consumer:
|
||
|
||
| Repo | References |
|
||
| ------------------------- | ---------- |
|
||
| my-org/api-gateway | 7 sites |
|
||
| my-org/billing | 3 sites |
|
||
| my-org/notifications | 1 site |
|
||
|
||
`analyze kind=cross_repo` complements this — it reports the typed edges (calls / implements / extends) that physically cross the boundary, which is the count that matters for "is this safe to change without coordinating with consumer teams."
|
||
|
||
## Contract-level consumers
|
||
|
||
For published API surfaces, `find_usages` won't show consumers that go through the wire. `contracts({action: check})` catches:
|
||
- HTTP route consumers (client-side `fetch` / `http.Get` / generated SDK methods)
|
||
- gRPC method consumers (generated client stubs across repos)
|
||
- Pub/sub subscribers (NATS / Kafka / RabbitMQ / Redis / EventEmitter / Socket.IO)
|
||
- Env-var consumers (one process writes, another reads)
|
||
- OpenAPI / GraphQL schema consumers
|
||
|
||
## Onboarding a consumer repo
|
||
|
||
If a known consumer is missing from the tracked-repo list:
|
||
1. `track_repository` with its path — indexes immediately, persists to config
|
||
2. Re-run `find_usages` and `analyze kind=cross_repo` — the new edges materialise
|
||
3. `untrack_repository` only when you're done; leaving it tracked keeps subsequent cross-repo queries cheap
|
||
|
||
## Checklist
|
||
|
||
- `get_active_project` first — you may already be in multi-repo scope
|
||
- `track_repository` every consumer repo you care about; `find_usages` only sees what's indexed
|
||
- Partition the `find_usages` rows by repo prefix; the per-repo breakdown is the deliverable
|
||
- `analyze kind=cross_repo` for the typed-edge view (calls / implements / extends)
|
||
- `contracts({action: check})` for wire-level consumers that `find_usages` cannot see
|
||
- `get_test_targets` returns cross-repo tests too — run them, not just the local ones
|
||
- Hand the per-repo report to the user via `export_context` for PR descriptions / Slack
|
||
=== home/.hermes/skills/navigation/gortex-dataflow-trace/SKILL.md ===
|
||
---
|
||
name: gortex-dataflow-trace
|
||
description: "Trace where a value flows through the code."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, dataflow-trace]
|
||
category: navigation
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Dataflow Trace with Gortex (CPG-lite)
|
||
|
||
Use this when the user asks where a value flows — through assignments, function args, returns, channels, event buses, or pub/sub topics. Built on the CPG-lite edge layer (`value_flow` ∪ `arg_of` ∪ `returns_to`) plus the pub/sub + channel + emit layers, so flows survive crossing function and process boundaries that a plain caller-graph walk would lose.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. smart_context({task: "<the flow you want to understand>"}) -> Working-set bundle
|
||
2. search_symbols({query: "<source>"}) -> Resolve the producing symbol ID
|
||
3. search_symbols({query: "<sink>"}) -> Resolve the consuming symbol ID
|
||
4. flow_between({source_id: "<src>", sink_id: "<sink>", -> Ranked paths over value_flow ∪ arg_of ∪ returns_to
|
||
max_depth: 8, max_paths: 10})
|
||
5. taint_paths({source_pattern: "<pattern>", -> Every flow from any matching source to any matching sink
|
||
sink_pattern: "<pattern>",
|
||
max_depth: 8})
|
||
6. analyze({kind: "channel_ops"}) -> Channel producer/consumer mismatch (Go)
|
||
7. analyze({kind: "pubsub", -> Pub/sub topics with publishers + subscribers
|
||
transport: "nats|kafka|rabbitmq|redis|eventemitter|socketio",
|
||
name: "<topic>",
|
||
role: "publish|subscribe"})
|
||
8. analyze({kind: "event_emitters", level: "error"}) -> Log/metric/span emit sites
|
||
9. get_call_chain({id: "<sink>"}) + get_callers({id: "<source>"}) -> Caller-graph cross-check for any path flow_between missed
|
||
10. export_context({format: "markdown"}) -> Hand the trace to a PR / Slack / doc
|
||
```
|
||
|
||
## Pattern syntax for `taint_paths`
|
||
|
||
Each pattern is one or more clauses combined with AND:
|
||
|
||
| Clause | Meaning | Example |
|
||
| ------------------ | ------------------------------------------------ | ----------------------------- |
|
||
| `<bare token>` | Substring match on the symbol name | `Decode` |
|
||
| `exact:<name>` | Exact name match | `exact:HandleRequest` |
|
||
| `path:<prefix>` | Path prefix on the file the symbol lives in | `path:internal/http/` |
|
||
| `kind:<kind>` | Restrict to `function` / `method` / `field` / etc. | `kind:method` |
|
||
|
||
Functions auto-expand to their params on the sink side, so `taint_paths` with a function-shaped sink pattern reports flows into any of its parameters.
|
||
|
||
## Crossing process / transport boundaries
|
||
|
||
`flow_between` walks intra-process edges. To follow a value across a wire:
|
||
|
||
| Boundary | Tool |
|
||
| --------------------------------- | ---------------------------------------------------- |
|
||
| Channel (Go) | `analyze kind=channel_ops` — find the matching `recv` site, then `flow_between` from there |
|
||
| Pub/sub topic | `analyze kind=pubsub name=<topic>` — get every subscriber; `flow_between` from each |
|
||
| HTTP / gRPC / GraphQL contract | `contracts({action: check})` — match providers to consumers; the contract ID is your bridge node |
|
||
| Env var (one process writes, another reads) | `analyze kind=config_readers name=<KEY>` -> consumers; `find_usages` on `cfg::env::<KEY>` |
|
||
| Cross-repo call | `analyze kind=cross_repo base_kind=calls` — typed boundary-crossing edges |
|
||
|
||
## Reading a ranked path
|
||
|
||
Each row from `flow_between` is a sequence of edges with the kind annotated (`value_flow` / `arg_of` / `returns_to`). The rank reflects path length + edge confidence. Treat the top-3 paths as the load-bearing ones; the long tail tends to be incidental cross-references.
|
||
|
||
## Checklist
|
||
|
||
- `smart_context` first — pick up the working set before asking flow_between for a path
|
||
- Resolve **both** source and sink to symbol IDs before calling `flow_between` (path search needs anchors)
|
||
- Use `taint_paths` when "every flow from a kind of source to a kind of sink" matters more than one specific pair
|
||
- Cross process boundaries with the right analyzer (`channel_ops` / `pubsub` / `config_readers` / `contracts`) — `flow_between` alone won't follow a value across the wire
|
||
- Cross-check with `get_call_chain` / `get_callers` when `flow_between` returns zero paths for a flow you're sure exists — the producer or consumer may not yet be in the dataflow layer
|
||
- `export_context` to hand the trace to a PR / Slack / doc without losing the structure
|
||
=== home/.hermes/skills/navigation/gortex-explore/SKILL.md ===
|
||
---
|
||
name: gortex-explore
|
||
description: "Understand how code works or trace an execution flow."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, explore]
|
||
category: navigation
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Exploring Codebases with Gortex
|
||
|
||
## Workflow
|
||
|
||
```
|
||
1. graph_stats -> Confirm index, get node/edge counts
|
||
2. smart_context({task: "<what you want to understand>"}) -> One-call exploration bundle (start here)
|
||
3. get_communities -> See functional clusters (architecture overview)
|
||
4. search_symbols({query: "<concept>"}) -> Find symbols related to a concept
|
||
5. get_processes -> Discover execution flows
|
||
6. get_processes({id: "<process-id>"}) -> Trace a specific flow step by step
|
||
7. get_file_summary({path: "<file>"}) -> Symbols + imports for one file
|
||
8. get_editing_context({path: "<file>"}) -> Deep dive on a file (callers + callees)
|
||
9. export_context({...}) -> Share findings as markdown/JSON (PRs, Slack, docs)
|
||
```
|
||
|
||
## Checklist
|
||
|
||
- Call index_health to confirm Gortex is running (graph_stats only when you need node/edge counts)
|
||
- Call smart_context first — one call replaces 5-10 exploration calls
|
||
- Call get_communities for architecture overview when smart_context is not enough
|
||
- Call search_symbols for the concept you want to understand
|
||
- Call get_processes to discover execution flows
|
||
- Call get_processes with id on relevant flows for step-by-step traces
|
||
- Call get_editing_context on key files for full symbol context
|
||
- Call export_context to hand a findings packet outside the session
|
||
- Read source files only for implementation details you actually need to edit
|
||
=== home/.hermes/skills/navigation/gortex-onboarding/SKILL.md ===
|
||
---
|
||
name: gortex-onboarding
|
||
description: "Structured tour of an unfamiliar repo."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, onboarding]
|
||
category: navigation
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Onboarding with Gortex (30-minute repo tour)
|
||
|
||
Use this when the user is new to a repo (or returning to one cold) and wants a structured tour: where to read first, what the architecture looks like, who owns what, what's load-bearing, and where to safely make a first edit. Composes the discovery-tier tools into a single ordered walk so the agent doesn't waste the user's first hour on undirected `Read` calls.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. graph_stats -> Confirm Gortex is indexed; per-language / per-kind counts
|
||
2. get_active_project -> Is this single-repo or part of a multi-repo project?
|
||
3. list_repos (when multi-repo) -> See sibling repos in the project
|
||
4. get_repo_outline -> Narrative single-call codebase overview (entry points, top communities, hot paths)
|
||
5. surface_memories({task: "onboarding <repo>"}) -> Cross-session invariants / conventions already captured
|
||
6. distill_session -> Prior session digest for this workspace (decisions, pinned notes)
|
||
7. get_communities -> Functional clusters via Louvain — the implicit "modules"
|
||
8. get_processes -> Discovered execution flows (the implicit "use cases")
|
||
9. analyze({kind: "hotspots"}) -> Over-coupled symbols — where most edits should be careful
|
||
10. analyze({kind: "components"}) -> Component fan-in/out (UI projects)
|
||
11. analyze({kind: "routes"}) -> HTTP / gRPC / GraphQL / WS endpoints — the API surface
|
||
12. analyze({kind: "models"}) -> ORM models → tables — the data surface
|
||
13. analyze({kind: "ownership", path_prefix: "<dir>/"}) -> Per-author rollup — who to ping for what
|
||
14. contracts({action: "list"}) -> Detected API contracts (provider side)
|
||
15. audit_agent_config -> Project CLAUDE.md / AGENTS.md / .cursor/rules — read what the team told the agent
|
||
16. ask({question: "What does this repo do and how is it organised?"}) -> LLM summary grounded in the working set (only when llm provider configured)
|
||
```
|
||
|
||
## The five-minute version (when the user is in a hurry)
|
||
|
||
```
|
||
1. graph_stats
|
||
2. get_repo_outline
|
||
3. get_communities (top 5)
|
||
4. surface_memories({task: "onboarding"})
|
||
5. audit_agent_config
|
||
```
|
||
|
||
Stop here unless the user asks for more depth. The outline + communities + memories triple covers "what is this repo / how is it carved up / what should I know before editing."
|
||
|
||
## The full tour (when the user wants 30 minutes)
|
||
|
||
The full `Workflow` above, plus per-community drilldowns:
|
||
|
||
1. From `get_communities`, pick the top 3 by node count
|
||
2. For each, `get_communities({id: <community-id>})` returns its members
|
||
3. `get_file_summary` on the community's central file (highest fan-in by symbol count)
|
||
4. `get_processes` on a process that crosses the community
|
||
5. `get_callers` / `get_call_chain` on the community's entry-point symbol
|
||
|
||
Result: the user has a concrete mental model of one community per drilldown.
|
||
|
||
## Where to make a first edit safely
|
||
|
||
After the tour, the user usually asks "where can I make my first change without breaking things?" Answer with:
|
||
|
||
1. `analyze kind=todos` — every TODO / FIXME node, filterable by author / tag — pick a small one in a low-fan-in symbol
|
||
2. `analyze kind=coverage_gaps min_pct=0 max_pct=50 path_prefix=<community dir>/` — undertested code where a test addition is a safe first PR
|
||
3. `analyze kind=stale_code older_than=180` — code untouched for 6+ months in a community the user just explored — usually safe to add a small clarifying refactor
|
||
|
||
Either path: hand off to `/gortex-safe-edit` (or `/gortex-add-test` for the coverage-gap path) for the actual change.
|
||
|
||
## Multi-repo onboarding
|
||
|
||
When `get_active_project` shows multiple members:
|
||
|
||
- `list_repos` first; pick the *primary* repo for the tour (usually the largest by node count or the one with the most `KindContract` provider nodes)
|
||
- `analyze kind=cross_repo base_kind=calls` shows the cross-repo coupling — onboarding must cover *who calls into* + *who is called from* the primary
|
||
- `contracts({action: list})` partitioned by repo shows the wire surface each repo exposes
|
||
|
||
## Onboarding artefact
|
||
|
||
The deliverable for an onboarding session is a markdown packet the user can keep:
|
||
|
||
```
|
||
export_context({
|
||
task: "onboarding tour of <repo>",
|
||
format: "markdown",
|
||
sections: ["outline", "communities", "processes", "hotspots", "routes", "models", "memories"]
|
||
})
|
||
```
|
||
|
||
Hand that to the user; they can paste it into their notes / wiki / agent memory.
|
||
|
||
## Checklist
|
||
|
||
- `graph_stats` + `get_active_project` before any tool that reads the graph — confirm scope first
|
||
- `get_repo_outline` is the single-call narrative; if it's missing fields the user needs, fall back to the per-analyzer walks
|
||
- `surface_memories` + `distill_session` — prior agents may have left invariants / conventions / decisions that shape the tour
|
||
- `get_communities` + `get_processes` for the architectural skeleton
|
||
- `audit_agent_config` reads the team's own CLAUDE.md / AGENTS.md so the tour respects whatever conventions the team wrote down
|
||
- For multi-repo: pick the primary, then `analyze kind=cross_repo` for the boundary view
|
||
- End with `export_context format=markdown` so the user keeps the tour
|
||
- Suggest a safe first edit via `analyze kind=todos` / `coverage_gaps` / `stale_code` and hand off to `/gortex-safe-edit` or `/gortex-add-test`
|
||
=== home/.hermes/skills/refactoring/gortex-extract-function/SKILL.md ===
|
||
---
|
||
name: gortex-extract-function
|
||
description: "Extract code into a function or method via LSP refactor."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, extract-function]
|
||
category: refactoring
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Extract Function with Gortex (LSP refactor path)
|
||
|
||
Use this when the user wants to extract code into a new function / method / variable / constant via the **language server's refactor actions**, not by hand-editing braces. Maps onto LSP `refactor.extract.*` code actions; works wherever the underlying server supports them (gopls / tsserver / pyright / rust-analyzer / jdtls / kotlin-language-server / omnisharp / and others).
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. get_editing_context({path: "<file>"}) -> See enclosing symbol, callers, callees
|
||
2. (optional) find_usages({id: "<enclosing-fn>"}) -> Who calls the function you are about to split
|
||
3. get_code_actions({path: "<file>", range: {start, end}, -> Menu filtered to refactor.extract.* actions
|
||
only: ["refactor.extract.function",
|
||
"refactor.extract.method",
|
||
"refactor.extract.variable",
|
||
"refactor.extract.constant"]})
|
||
4. preview_edit({edit: <chosen action.workspaceEdit>}) -> Speculative apply
|
||
-> Inspect: touched / added / renamed / broken_callers / broken_implementors / impact
|
||
5. If the extraction crosses files (e.g. moving the helper to a sibling file):
|
||
simulate_chain({steps: [...]}) -> Ordered chain with broken-caller carry-over
|
||
6. apply_code_action({path: "<file>", action_id: "<id>"}) -> Atomic temp+rename, UTF-16 column math
|
||
7. check_guards({ids: [<changed-ids>]}) + verify_change -> Convention + signature gate
|
||
8. get_test_targets({ids: [<old-id>, <new-id>]}) -> Run tests for both the caller and the extract
|
||
9. detect_changes + diff_context -> Final scope check
|
||
```
|
||
|
||
## Choosing the right extract action
|
||
|
||
| User intent | Code-action kind | Notes |
|
||
| ------------------------------------------ | --------------------------------- | ----- |
|
||
| Pull a block of statements into a helper | `refactor.extract.function` | Most servers infer params + return type from the selection. |
|
||
| Move statements into a method on a type | `refactor.extract.method` | Receiver / this binding chosen by the server. |
|
||
| Extract a sub-expression to a local | `refactor.extract.variable` | Best for naming repeated sub-expressions. |
|
||
| Extract a literal to a package-level const | `refactor.extract.constant` | gopls and tsserver expose this; rust-analyzer uses `refactor.extract.module` for similar moves. |
|
||
|
||
If you don't know which kinds the server offers, call `get_code_actions` **without** `only` and inspect the menu first.
|
||
|
||
## Range selection
|
||
|
||
LSP positions are line + UTF-16 character offsets. The `apply_code_action` mapper handles this correctly, but when you compose the range yourself:
|
||
1. Get the file body via `get_symbol_source` (compress_bodies:false) or `get_file_summary`
|
||
2. Use the symbol's line numbers as anchors; expand to the precise statement boundaries
|
||
3. Pass `range: {start: {line, character}, end: {line, character}}` to `get_code_actions`
|
||
|
||
## When the server has no extract action
|
||
|
||
Some servers (yaml-language-server, json-language-server, bash-language-server) don't ship refactor actions. Fall back to `/gortex-safe-edit` and author the extract by hand — but still `preview_edit` first.
|
||
|
||
## Checklist
|
||
|
||
- `get_editing_context` to understand the enclosing symbol before selecting a range
|
||
- `get_code_actions` with `only: refactor.extract.*` — pick from the menu, don't invent
|
||
- `preview_edit` before `apply_code_action` (broken callers / blast radius)
|
||
- `simulate_chain` if the extract moves the helper to a new file with follow-on rename of call sites
|
||
- `check_guards`, `verify_change`, `get_test_targets` after the apply
|
||
- `get_symbol` on the new symbol to confirm Gortex indexed it under the expected ID
|
||
=== home/.hermes/skills/refactoring/gortex-fix-all/SKILL.md ===
|
||
---
|
||
name: gortex-fix-all
|
||
description: "Clear LSP diagnostics — one error, a file, or source.fixAll."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, fix-all]
|
||
category: refactoring
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Fix LSP Diagnostics with Gortex (LSP code-actions path)
|
||
|
||
Use this when the user wants errors / warnings cleared — for one symbol, one file, or the whole project. Bridges Gortex to the 18-language LSP coverage (gopls / tsserver / pyright / rust-analyzer / clangd / jdtls / kotlin-language-server / omnisharp / ruby-lsp / phpactor / lua-language-server / sourcekit-lsp / haskell-language-server / elixir-ls / ocamllsp / zls / terraform-ls / yaml-language-server / json-language-server / bash-language-server). No manual `Edit` of error messages.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. subscribe_diagnostics({min_severity: 1, path_prefix: "<dir>/"}) -> Push notifications, replays initial state once
|
||
2. get_diagnostics({path: "<file>", wait: true, timeout_ms: 2000}) -> Poll form when you need a synchronous snapshot
|
||
3. get_code_actions({path: "<file>", range: {...}}) -> Menu of fixes / refactors / source actions
|
||
4. For each chosen action:
|
||
preview_edit({edit: <action.workspaceEdit>}) -> Speculative apply on the shadow graph
|
||
apply_code_action({path, action_id}) -> Atomic on-disk apply (UTF-16 column math)
|
||
5. fix_all_in_file({path: "<file>"}) -> One-shot source.fixAll over an entire file
|
||
6. get_diagnostics({path: "<file>"}) -> Confirm the file is now clean
|
||
7. check_guards({ids: [<changed-ids>]}) + get_test_targets({ids}) -> Post-fix guardrails
|
||
8. unsubscribe_diagnostics -> Only when narrowing scope; auto-fires on disconnect
|
||
```
|
||
|
||
## Diagnostic-fix patterns
|
||
|
||
| Situation | Tool ordering | Notes |
|
||
| ------------------------------------------------------ | ------------- | ----- |
|
||
| One specific error | `get_code_actions` at the diagnostic range -> pick one -> `apply_code_action` | Smallest possible edit. |
|
||
| Every error in a file | `fix_all_in_file` | Bundles every server-suggested fix in a single round-trip. |
|
||
| Refactor offered as a code action (`refactor.*`) | `get_code_actions` -> pick by `kind` (e.g. `refactor.extract`) -> `preview_edit` first | See `/gortex-extract-function`. |
|
||
| Source action (`source.organizeImports`, `source.fixAll`) | `get_code_actions` with the right `only` kind, or `fix_all_in_file` | Whole-file scope. |
|
||
| Watching diagnostics during a long edit session | `subscribe_diagnostics` with `min_severity` + `path_prefix` filters | SHA-suppressed delta payloads; only changed files reach you. |
|
||
|
||
## Reading the diagnostic stream
|
||
|
||
- `initial_replay: true` on the first push — that's the synchronous snapshot of the current LSP state, not a new event.
|
||
- Every subsequent push carries only files whose `publishDiagnostics` SHA changed.
|
||
- `min_severity` 1 = error, 2 = warning, 3 = info, 4 = hint. Default to 1 unless you specifically need warnings.
|
||
- `path_prefix` is your scope filter — pin it to the area you're working on so the rest of the project doesn't drown the stream.
|
||
|
||
## When LSP cannot fix it
|
||
|
||
If `get_code_actions` returns an empty menu, the server doesn't know how to fix this diagnostic. Fall back to:
|
||
1. `search_symbols` for the symbol the diagnostic references
|
||
2. `get_editing_context` on the file
|
||
3. `/gortex-safe-edit` to author the edit by hand, with `preview_edit` to verify
|
||
|
||
## Checklist
|
||
|
||
- `subscribe_diagnostics` once per session, with `min_severity` + `path_prefix` scoped to the area you're touching
|
||
- `get_code_actions` is the menu — never invent fixes
|
||
- `preview_edit` (or `apply_code_action` directly when the action is small and well-known) before any disk write
|
||
- `fix_all_in_file` for whole-file source.fixAll — one round-trip beats N targeted fixes
|
||
- Re-run `get_diagnostics` after the fix; assume nothing
|
||
- `check_guards` and `get_test_targets` after the diagnostics are clean — fixing the LSP error is not the same as fixing the test
|
||
=== home/.hermes/skills/refactoring/gortex-refactor/SKILL.md ===
|
||
---
|
||
name: gortex-refactor
|
||
description: "Rename, extract, split, or restructure code safely."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, refactor]
|
||
category: refactoring
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Refactoring with Gortex
|
||
|
||
## Workflow
|
||
|
||
```
|
||
1. search_symbols({query: "X"}) -> Find the symbol ID
|
||
2. explain_change_impact({ids: "<id>"}) -> Map blast radius
|
||
3. analyze({kind: "ownership", path_prefix: "<dir>/"}) -> Who should review (pinging policy)
|
||
4. analyze({kind: "coverage_gaps", path_prefix: "<dir>/"}) -> Where is the refactor risky (poor coverage)
|
||
5. verify_change({id: "<id>", new_signature: "..."}) -> Catch contract violations in callers + implementors
|
||
6. get_editing_context({path: "<file>"}) -> See all symbols and relationships
|
||
7. find_usages({id: "<id>"}) -> Every reference to change
|
||
8. get_edit_plan({ids: ["<id1>", "<id2>"]}) -> Dependency-ordered file list
|
||
9. batch_edit({edits: [...]}) -> Apply edits in order, re-indexing between steps
|
||
10. check_guards({ids: [...]}) -> Post-edit: team conventions from .gortex.yaml
|
||
11. get_test_targets({ids: [...]}) -> Tests to re-run (cross-repo aware)
|
||
12. detect_changes({scope: "all"}) -> Verify scope; diff_context for review
|
||
```
|
||
|
||
## Rename Symbol
|
||
|
||
- search_symbols to find the symbol ID
|
||
- explain_change_impact to assess blast radius
|
||
- verify_change before signature-changing renames — fails fast on interface breaks
|
||
- rename_symbol({id: "<id>", new_name: "<name>"}) — generates edits for definition + all references
|
||
- Review the generated edits, apply via batch_edit or edit_symbol (no Read→Edit roundtrip)
|
||
- check_guards, then detect_changes to verify only expected files changed
|
||
|
||
## Extract Module
|
||
|
||
- get_editing_context on the source file — see all symbols
|
||
- get_dependents on symbols to extract — find external callers
|
||
- explain_change_impact on symbols being moved
|
||
- analyze({kind: "would_create_cycle", from: "<new module>", to: "<old module>"}) before wiring imports
|
||
- suggest_pattern + scaffold from a comparable existing module — generates code, wiring, test stubs
|
||
- Extract code, update imports (find_import_path for correct paths)
|
||
- get_edit_plan + batch_edit for dependency-ordered atomic application
|
||
- check_guards, detect_changes to verify affected scope
|
||
|
||
## Split Function/Service
|
||
|
||
- get_call_chain on the function — understand all callees
|
||
- Group callees by responsibility
|
||
- get_callers to map all call sites that need updating
|
||
- find_implementations when splitting along an interface
|
||
- explain_change_impact for full blast radius
|
||
- Create new functions/services (scaffold from a similar example)
|
||
- Update callers (find_usages for precise locations, batch_edit to apply in order)
|
||
- check_guards, detect_changes to verify affected scope
|
||
|
||
## API Contract Changes
|
||
|
||
- Before changing an HTTP route, gRPC method, topic, env, or OpenAPI contract: contracts({action: "check"}) to find cross-repo consumers
|
||
- verify_change on the provider signature
|
||
- Coordinate consumer-side edits in the same batch_edit when repos are tracked together
|
||
=== home/.hermes/skills/refactoring/gortex-rename/SKILL.md ===
|
||
---
|
||
name: gortex-rename
|
||
description: "Rename a symbol and update every reference atomically."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, rename]
|
||
category: refactoring
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Rename Symbol with Gortex (cross-file coordinated rename)
|
||
|
||
Use this when the user wants to rename a function / method / type / variable / package and have every reference (definition, callers, tests, cross-repo consumers, doc-comments where applicable) updated atomically. Picks the right tool for the job — graph-coordinated `rename_symbol` for Gortex-known symbols, LSP `textDocument/rename` (surfaced as a `refactor.rename` code action where supported) for server-driven cases.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. search_symbols({query: "<old name>"}) -> Resolve the symbol ID(s)
|
||
2. winnow_symbols({...}) -> Disambiguate if multiple matches survive
|
||
3. explain_change_impact({ids: "<id>"}) -> Blast radius (callers, implementors, processes)
|
||
4. find_usages({id: "<id>"}) -> Every reference (BM25-free; zero false positives)
|
||
5. verify_change({id: "<id>", new_signature: "<old sig with new name>"}) -> Catches interface breaks early
|
||
6. rename_symbol({id: "<id>", new_name: "<new>"}) -> Generates dependency-ordered WorkspaceEdit (Gortex path)
|
||
OR get_code_actions({path, range, only: ["refactor.rename"]}) -> LSP-driven path (when you want server-side rename semantics)
|
||
7. preview_edit({edit: <generated WorkspaceEdit>}) -> Speculative apply; check broken_callers / broken_implementors
|
||
8. batch_edit({edits: [...]}) -> Atomic on-disk apply, re-index between steps
|
||
OR apply_code_action({...}) -> If you went the LSP route
|
||
9. check_guards({ids: [<old, new>]}) -> Naming conventions, banned terms from .gortex.yaml
|
||
10. get_test_targets({ids: [<new-id>]}) -> Tests to re-run; cross-repo aware
|
||
11. detect_changes + diff_context -> Confirm no stray reference survived
|
||
```
|
||
|
||
## Choosing the right rename tool
|
||
|
||
| Situation | Tool | Why |
|
||
| ---------------------------------------------------------- | ----------------------------- | --- |
|
||
| Symbol is in the graph and rename is mechanical | `rename_symbol` | Generates the WorkspaceEdit from edges; deterministic, fast, no LSP round-trip. |
|
||
| Symbol semantics depend on the server (TS shadowed locals, Java generics, Rust trait resolution) | `get_code_actions` + `apply_code_action` with `refactor.rename` | Server resolves identifier scoping the parser can't fully replicate. |
|
||
| Cross-repo rename (consumer repos tracked together) | `rename_symbol` + `contracts({action: check})` | Graph carries cross-repo edges; `contracts` flags HTTP / gRPC / topic-side breakage. |
|
||
| Rename of a published API surface | `rename_symbol` **plus** `contracts({action: check})` and a deprecation shim | Pair with `/gortex-cross-repo-usage` to find consumer repos. |
|
||
|
||
## Cross-repo renames
|
||
|
||
`rename_symbol` covers every repo the graph knows about — track consumer repos first (`track_repository`) and switch `set_active_project` to the multi-repo scope, then run the rename. `/gortex-cross-repo-usage` is the partition view that confirms every consumer repo was touched.
|
||
|
||
## Renaming through interfaces
|
||
|
||
If the renamed symbol is part of an interface contract:
|
||
1. `find_implementations` on the interface — every implementor must be renamed in the same chain
|
||
2. `verify_change` against the interface's signature with the new name
|
||
3. `simulate_chain` with one step per implementor file so `broken_implementors` carries forward correctly
|
||
4. Apply via `batch_edit` (or `apply_code_action` if you went the LSP route per-implementor)
|
||
|
||
## Checklist
|
||
|
||
- `search_symbols` + `winnow_symbols` until exactly one ID resolves to the symbol you mean
|
||
- `explain_change_impact` + `find_usages` before authoring any edit
|
||
- `verify_change` on the new signature — catches interface breaks before anything is written
|
||
- Pick `rename_symbol` (graph path) or LSP `refactor.rename` (server path); never hand-author cross-file renames
|
||
- `preview_edit` / `simulate_chain` on the generated edits before disk
|
||
- `batch_edit` is dependency-ordered + re-indexes between steps — atomic in the sense that matters for the graph
|
||
- `check_guards`, `get_test_targets`, `diff_context` after the apply
|
||
=== home/.hermes/skills/refactoring/gortex-safe-edit/SKILL.md ===
|
||
---
|
||
name: gortex-safe-edit
|
||
description: "Preview an edit's blast radius on the shadow graph before writing."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, safe-edit]
|
||
category: refactoring
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Safe Edit with Gortex (speculative-execution path)
|
||
|
||
Use this **before** you touch `edit_file` / `edit_symbol` / `batch_edit` / `Edit` / `Write`. It runs the edit against the in-memory shadow graph first, reports broken callers + broken interface implementors + blast-radius rollup + suggested tests, and only promotes to disk once those signals are clean.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. smart_context({task: "<what you intend to change>"}) -> Working-set bundle
|
||
2. surface_memories({task, symbol_ids}) -> Cross-session invariants on the same symbols
|
||
3. get_editing_context({path: "<file>"}) -> Pre-edit signature + caller map
|
||
4. preview_edit({edit: <LSP WorkspaceEdit>}) -> Single-shot speculative apply on the shadow graph
|
||
-> Inspect: touched / added / removed / renamed / broken_callers / broken_implementors / impact / suggested_tests
|
||
5. simulate_chain({steps: [{edit: <e1>}, {edit: <e2>}, ...], -> Multi-step ordered simulation
|
||
inherit_overlay: true, stop_on_error: true,
|
||
keep: false})
|
||
-> Use when the change is more than one WorkspaceEdit (cross-file refactor, signature + every caller, etc.)
|
||
6. If broken_callers or broken_implementors is non-empty -> Fix the chain first, re-run preview_edit / simulate_chain
|
||
7. check_guards({ids: [<changed-ids>]}) -> Team conventions from .gortex.yaml
|
||
8. verify_change({id: <id>, new_signature: "..."}) -> Final signature check before disk write
|
||
9. batch_edit({edits: [...]}) -> Apply the same edits on disk in dependency order
|
||
10. detect_changes({scope: "all"}) + diff_context({scope: "all"}) -> Confirm the on-disk diff matches the simulated one
|
||
11. get_test_targets({ids: [<changed-ids>]}) -> Tests to re-run (cross-repo aware)
|
||
```
|
||
|
||
## When to use `preview_edit` vs `simulate_chain`
|
||
|
||
| Situation | Tool | Why |
|
||
| ------------------------------------------------------ | ---------------- | --- |
|
||
| One self-contained `WorkspaceEdit` (e.g. one rename) | preview_edit | Single round-trip, simplest. |
|
||
| Several dependent edits that must be applied in order | simulate_chain | First-failing-step semantics; `inherit_overlay` carries state forward. |
|
||
| You want the simulated state to become the live overlay so subsequent queries see it | simulate_chain with `keep: true` | Promotes the final shadow state into a real overlay session — graph queries see post-edit reality without writing disk. |
|
||
| Optional LSP diagnostics on the simulated content | Either, with `with_diagnostics: true` | Drives `didChange(simulated) → wait → didChange(original)` round-trip; concurrent sessions never observe simulated state as authoritative. |
|
||
|
||
## Reading the speculative report
|
||
|
||
- **broken_callers** — callers whose call sites won't type-check against the new signature. Fix or update every one before disk.
|
||
- **broken_implementors** — interface implementors that no longer satisfy the interface contract. Either widen the contract, update implementors, or revert.
|
||
- **impact** — `analysis.AnalyzeImpact` blast-radius rollup. The same risk tiers `/gortex-impact` reports.
|
||
- **suggested_tests** — what to feed to `get_test_targets` after the apply.
|
||
- **added / removed / renamed** — non-trivial-signature unambiguous-candidate heuristic; bare `func ()` voids reject as ambiguous, so you may see fewer "renamed" entries than you expect — that is correct behaviour.
|
||
|
||
## Checklist
|
||
|
||
- `smart_context` to orient a non-trivial task (skip for a single known symbol — use `search_symbols` / `get_symbol_source`)
|
||
- `surface_memories` on the same working set — pick up cross-session decisions / gotchas
|
||
- `preview_edit` (single edit) or `simulate_chain` (ordered chain) **before** any on-disk write
|
||
- Treat `broken_callers` / `broken_implementors` as blockers, not warnings
|
||
- `check_guards` + `verify_change` after the simulated diff is clean, before `batch_edit`
|
||
- `batch_edit` (dependency-ordered, atomic re-index between steps) over manual sequencing
|
||
- `detect_changes` + `diff_context` to confirm the on-disk diff matches the simulation
|
||
- `get_test_targets` to run the right tests, cross-repo aware
|
||
- If the edit is durable knowledge ("X must hold the lock", "this package never uses gob"), `store_memory` so the next agent inherits the lesson
|
||
=== home/.hermes/skills/testing/gortex-add-test/SKILL.md ===
|
||
---
|
||
name: gortex-add-test
|
||
description: "Add tests for under-tested code and coverage gaps."
|
||
version: 1.0.0
|
||
metadata:
|
||
hermes:
|
||
tags: [code-intelligence, mcp, add-test]
|
||
category: testing
|
||
platforms: [linux, macos, windows]
|
||
related_skills: [gortex]
|
||
---
|
||
# Add Tests with Gortex (coverage-led)
|
||
|
||
Use this when the user wants tests added for under-covered code, untested symbols, or a specific regression. Walks the coverage analyzers first so the new test goes where it matters; uses `suggest_pattern` + `scaffold` to author the new test in the style of an existing one rather than from scratch.
|
||
|
||
## Workflow (do not skip steps)
|
||
|
||
```
|
||
1. gortex enrich coverage (CLI) -> Stamp meta.coverage_pct on executable symbols from cover.out
|
||
2. analyze({kind: "coverage_summary", path_prefix: "<dir>/"}) -> Per-directory rollup (avg / covered / partial / uncovered)
|
||
3. analyze({kind: "coverage_gaps", -> Symbols inside [min_pct, max_pct) — the candidate list
|
||
path_prefix: "<dir>/",
|
||
min_pct: 0, max_pct: 50})
|
||
4. get_untested_symbols({path_prefix: "<dir>/"}) -> Symbols with no covering test
|
||
5. For the chosen target symbol:
|
||
get_editing_context({path: "<file>"}) -> Signature, callers, callees
|
||
get_callers({id: "<id>"}) -> How the symbol is invoked in real code (drives test inputs)
|
||
6. suggest_pattern({example_id: "<similar tested symbol>"}) -> Extracts the test-authoring pattern (source + registration + tests)
|
||
7. scaffold({kind: "test", from: "<example>", target: "<new test>"}) -> Generate test stub + wiring
|
||
8. preview_edit({edit: <generated WorkspaceEdit>}) -> apply / batch_edit -> Speculative apply, then on-disk
|
||
9. get_test_targets({ids: [<symbol-under-test>]}) -> Confirms the new test file is discovered + maps to a run command
|
||
10. Run the test command; if green, re-check `analyze kind=coverage_gaps` to confirm the gap closed
|
||
11. check_guards + detect_changes + diff_context -> Standard post-edit gates
|
||
```
|
||
|
||
## Picking the right target
|
||
|
||
| Source of priority | Tool | Use when |
|
||
| ----------------------------------- | ----------------------------------------------------------- | -------- |
|
||
| User named the symbol | `search_symbols` -> `get_untested_symbols` (confirm gap) | Direct request. |
|
||
| Recent regression | `detect_changes` -> `analyze kind=coverage_gaps` on the change set | "Add a test for what just broke." |
|
||
| Hot path with weak coverage | `analyze kind=hotspots` -> filter by `coverage_pct` < 50 | High-impact gaps. |
|
||
| Whole directory | `analyze kind=coverage_summary` -> walk lowest-coverage subdirs | "Cover this package." |
|
||
| Mutation hotspot without tests | `analyze kind=field_writers` + `get_untested_symbols` | Race / state-mutation risk. |
|
||
|
||
## Authoring the test
|
||
|
||
`suggest_pattern` returns the **shape** of a comparable test in the project (table-driven, parallel, golden-file, etc.) so the new test feels native. `scaffold` then materialises the file with the right imports, package, and registration. Hand-edit only the bits `scaffold` couldn't infer (inputs, expected values, edge cases).
|
||
|
||
When the target is interface-implementing or LSP-driven, also run `find_implementations` and ensure each implementor has at least one test in the new file (table-driven test with one row per implementor is idiomatic in this repo).
|
||
|
||
## Closing the loop
|
||
|
||
After the new test runs green:
|
||
1. `gortex enrich coverage` (CLI) to refresh `meta.coverage_pct`
|
||
2. Re-run `analyze kind=coverage_gaps` over the same scope
|
||
3. Confirm the symbol is no longer in the gap list; if it still is, the test exercises a different branch — add another row
|
||
|
||
## Checklist
|
||
|
||
- Run `gortex enrich coverage` (CLI) at least once per session so the coverage analyzers have data to work with
|
||
- `analyze kind=coverage_summary` for the per-directory rollup; `analyze kind=coverage_gaps` for the per-symbol list
|
||
- `get_untested_symbols` is the truth for "zero covering tests" — coverage_pct=0 ≠ "no test"; some tests register but don't execute
|
||
- `suggest_pattern` + `scaffold` for the test body — author in the project's style, not from scratch
|
||
- `preview_edit` even for new files; the speculative report flags broken_callers if you accidentally add a name that collides
|
||
- `get_test_targets` after the apply — the test must be discoverable + mapped to a run command
|
||
- Re-run `analyze kind=coverage_gaps` once the test is green; confirm the gap actually closed (a passing test that doesn't exercise the gap is theatre)
|
||
- If the test encodes a project-wide invariant ("Bar must hold the lock"), `store_memory kind:invariant` so the next agent inherits the constraint
|