Project Graph Candidates Scan
Purpose
Scan the current project for potential Project Graph relationship candidates and maintain the candidate queue. This skill writes candidate facts only. It must not write confirmed edges, proposals, cross-ref pins, Base Graph files, or remote project files.
Use it when the user explicitly asks to scan project-graph/candidates.md, discover missing upstream/downstream relationships, refresh candidate findings, or run a Project Graph candidate scanner.
Initialization Gate
Run after resolving the current project root and before reading scan inputs or writing candidate state.
wiki_required: true
on_missing_wiki: route project-init
direct_invocation_missing_wiki: dispatch-project-init
- When directly invoked and no parent router is active, treat the bootstrap handoff as an internal routing message, not a terminal user-facing response.
- Unless an explicit no-write constraint or root-confidence check requires confirmation, continue through
project-init in the same turn, consume its return handoff, and resume only at a supported next gate.
pending_primary_stage: project-graph-candidates-scan
- Preserve the user's requested scan scope as
pending_intent.
- If
<project_root>/.llm-wiki/ is absent, stop and return a Context Handoff to project-init; resume only after the router receives initialization readiness and a supported next gate.
- Do not create a partial
.llm-wiki/, candidates file, scan report, scan state, or log inside this child as a substitute for initialization.
On the missing-wiki branch, emit this minimal handoff:
bootstrap_handoff:
project_root: <resolved project root>
pending_intent: <preserved scan request and scope>
pending_primary_stage: project-graph-candidates-scan
requested_stage_or_bridge: project-init
bootstrap_mode: automatic-minimal
current_gate: Initialization Gate
Required Reads
Read only as much as needed for the requested scan scope:
../references/project-graph.md
.llm-wiki/project-graph/candidates.md
.llm-wiki/project-graph/scan-report.md, when present
.llm-wiki/project-graph/scan-state.local.json, when present
.llm-wiki/log.md, when present
- local source/config/wiki files that can reveal relationship signals
../references/cross-project-refs.md only when candidate signals name another project or require registry/Base Graph interpretation
Allowed Writes
Current project only:
.llm-wiki/project-graph/candidates.md
.llm-wiki/project-graph/scan-report.md
.llm-wiki/project-graph/scan-state.local.json
.llm-wiki/log.md
Forbidden Writes
.llm-wiki/project-graph/edges.md
.llm-wiki/project-graph/proposals.md
.llm-wiki/cross-refs/index.md
- remote project wiki, source, config, Briefs, registry, or graph files
- Base Graph tracked files
If the scan finds enough evidence for an edge, stop at a pending candidate and tell the user to run project-graph-auto-edge for proposal generation.
Process
- Resolve the current project root, run the Initialization Gate, and then confirm
.llm-wiki exists.
- Read
project-graph.md for current schemas, status values, fingerprint rules, pending timeout, and write boundaries.
- Read existing
candidates.md and build a fingerprint set.
- Collect local relationship signals from:
- Feign clients and HTTP client interfaces
- hard-coded or configured HTTP URLs
- MQ topics, consumer groups, producer names, and queue bindings
- RPC client names, SDK package names, callback URLs, and webhook handlers
- shared DB/schema/table names when they imply cross-service ownership
- config keys naming another service, endpoint, topic, or project id
- existing wiki mentions of upstream/downstream systems
- Normalize
candidate_fingerprint with stable lowercase tokens: type:current_project:local_signal:remote_hint. Do not include absolute paths, line numbers, machine names, or local drive letters.
- Keep only candidates where one side is the current project. Put external-to-external findings in
scan-report.md, not current candidates.md.
- Add new rows with
status=pending, edge_id= empty, and source=scan.
- Preserve existing manual candidates. Never auto-expire
source=manual candidates.
- Archive stale
pending scan-origin candidates according to default_candidate_pending_days in project-graph.md by moving them to scan-report.md Archived Candidates; do not silently delete them.
- Append a concise
.llm-wiki/log.md entry unless the user explicitly requested dry-run.
Candidate Row Rules
remote_project may stay unknown when the scanner has only a hint.
relation must explain the suspected dependency in human-readable terms.
evidence should cite repo-relative files, config keys, class names, method names, endpoints, or topics.
first_seen is preserved for existing fingerprints.
last_seen is updated when a candidate is observed again.
edge_id remains empty until project-graph-human-edge promotes the candidate.
Example row shape:
| cand-YYYYMMDD-001 | http:smart-go-web:streamfeignapi:smarthub-mediakit | smarthub-mediakit | smart-go-web calls media stream change API | smart-go-device-mapping/.../ZLMediakitStreamSendServiceImpl.java#streamChange | pending | scan | 2026-06-23 | 2026-06-23 | |
Output
Report:
- scan scope and files inspected
- new candidates added
- duplicate fingerprints skipped
- stale scan candidates archived
- external-to-external findings kept out of current candidates
- validation result for candidate column counts, fingerprint uniqueness, statuses, sources, and promoted
edge_id resolution
- next recommended command, usually
project-graph-auto-edge <candidate_id> for candidates ready for proposal
1---2name: project-graph-candidates-scan3description: Use when scanning the current project-local .llm-wiki or source tree for potential Project Graph relationship candidates, including Chinese prompts like 扫描 candidates, project-graph candidates scan, 自动扫描候选关系, or 发现缺失跨项目关系.4---56# Project Graph Candidates Scan78## Purpose910Scan the current project for potential Project Graph relationship candidates and maintain the candidate queue. This skill writes candidate facts only. It must not write confirmed edges, proposals, cross-ref pins, Base Graph files, or remote project files.1112Use it when the user explicitly asks to scan `project-graph/candidates.md`, discover missing upstream/downstream relationships, refresh candidate findings, or run a Project Graph candidate scanner.1314## Initialization Gate1516Run after resolving the current project root and before reading scan inputs or writing candidate state.1718- `wiki_required: true`19- `on_missing_wiki: route project-init`20- `direct_invocation_missing_wiki: dispatch-project-init`21- When directly invoked and no parent router is active, treat the bootstrap handoff as an internal routing message, not a terminal user-facing response.22- Unless an explicit no-write constraint or root-confidence check requires confirmation, continue through `project-init` in the same turn, consume its return handoff, and resume only at a supported next gate.23- `pending_primary_stage: project-graph-candidates-scan`24- Preserve the user's requested scan scope as `pending_intent`.25- If `<project_root>/.llm-wiki/` is absent, stop and return a Context Handoff to `project-init`; resume only after the router receives initialization readiness and a supported next gate.26- Do not create a partial `.llm-wiki/`, candidates file, scan report, scan state, or log inside this child as a substitute for initialization.2728On the missing-wiki branch, emit this minimal handoff:2930```text31bootstrap_handoff:32 project_root: <resolved project root>33 pending_intent: <preserved scan request and scope>34 pending_primary_stage: project-graph-candidates-scan35 requested_stage_or_bridge: project-init36 bootstrap_mode: automatic-minimal37 current_gate: Initialization Gate38```3940## Required Reads4142Read only as much as needed for the requested scan scope:4344- `../references/project-graph.md`45- `.llm-wiki/project-graph/candidates.md`46- `.llm-wiki/project-graph/scan-report.md`, when present47- `.llm-wiki/project-graph/scan-state.local.json`, when present48- `.llm-wiki/log.md`, when present49- local source/config/wiki files that can reveal relationship signals50- `../references/cross-project-refs.md` only when candidate signals name another project or require registry/Base Graph interpretation5152## Allowed Writes5354Current project only:5556- `.llm-wiki/project-graph/candidates.md`57- `.llm-wiki/project-graph/scan-report.md`58- `.llm-wiki/project-graph/scan-state.local.json`59- `.llm-wiki/log.md`6061## Forbidden Writes6263- `.llm-wiki/project-graph/edges.md`64- `.llm-wiki/project-graph/proposals.md`65- `.llm-wiki/cross-refs/index.md`66- remote project wiki, source, config, Briefs, registry, or graph files67- Base Graph tracked files6869If the scan finds enough evidence for an edge, stop at a `pending` candidate and tell the user to run `project-graph-auto-edge` for proposal generation.7071## Process72731. Resolve the current project root, run the Initialization Gate, and then confirm `.llm-wiki` exists.742. Read `project-graph.md` for current schemas, status values, fingerprint rules, pending timeout, and write boundaries.753. Read existing `candidates.md` and build a fingerprint set.764. Collect local relationship signals from:77 - Feign clients and HTTP client interfaces78 - hard-coded or configured HTTP URLs79 - MQ topics, consumer groups, producer names, and queue bindings80 - RPC client names, SDK package names, callback URLs, and webhook handlers81 - shared DB/schema/table names when they imply cross-service ownership82 - config keys naming another service, endpoint, topic, or project id83 - existing wiki mentions of upstream/downstream systems845. Normalize `candidate_fingerprint` with stable lowercase tokens: `type:current_project:local_signal:remote_hint`. Do not include absolute paths, line numbers, machine names, or local drive letters.856. Keep only candidates where one side is the current project. Put external-to-external findings in `scan-report.md`, not current `candidates.md`.867. Add new rows with `status=pending`, `edge_id=` empty, and `source=scan`.878. Preserve existing manual candidates. Never auto-expire `source=manual` candidates.889. Archive stale `pending` scan-origin candidates according to `default_candidate_pending_days` in `project-graph.md` by moving them to `scan-report.md` `Archived Candidates`; do not silently delete them.8910. Append a concise `.llm-wiki/log.md` entry unless the user explicitly requested dry-run.9091## Candidate Row Rules9293- `remote_project` may stay `unknown` when the scanner has only a hint.94- `relation` must explain the suspected dependency in human-readable terms.95- `evidence` should cite repo-relative files, config keys, class names, method names, endpoints, or topics.96- `first_seen` is preserved for existing fingerprints.97- `last_seen` is updated when a candidate is observed again.98- `edge_id` remains empty until `project-graph-human-edge` promotes the candidate.99100Example row shape:101102```markdown103| cand-YYYYMMDD-001 | http:smart-go-web:streamfeignapi:smarthub-mediakit | smarthub-mediakit | smart-go-web calls media stream change API | smart-go-device-mapping/.../ZLMediakitStreamSendServiceImpl.java#streamChange | pending | scan | 2026-06-23 | 2026-06-23 | |104```105106## Output107108Report:109110- scan scope and files inspected111- new candidates added112- duplicate fingerprints skipped113- stale scan candidates archived114- external-to-external findings kept out of current candidates115- validation result for candidate column counts, fingerprint uniqueness, statuses, sources, and promoted `edge_id` resolution116- next recommended command, usually `project-graph-auto-edge <candidate_id>` for candidates ready for proposal