# Skill Discovery Graph and Index

Renma provides a static, declaration-driven Skill-to-Skill graph, a versioned
Skill Index, a compact repository-level Readiness projection, an
observation-only direct semantic diff, a CI report projection, and an opt-in
warn-only CI review policy. It does not interpret task text, select, rank, load,
invoke, or execute a Skill. Repository authors keep routing conditions in
source `SKILL.md` files; Renma exposes deterministic publication, adoption,
continuation, and structural evidence.

The current contract is intentionally layered:

```text
explicit continuations and publication
  -> exact route resolution and repository-wide adoption
  -> cycle-safe reachability, coverage, and route-cycle review
  -> renma.skill-index.v1 and the stdout-only skill-index command
  -> compact Readiness, semantic diff, and CI projections
  -> opt-in warn-only CI review policy
```

## Three separate facts

```text
structural root
  = a derived Skill graph fact

published entrypoint
  = an explicit valid Skill-local declaration

repository-wide adoption
  = an explicit repository configuration decision
```

A structural root is not automatically published. A published entrypoint does
not prove complete repository coverage. Neither fact causes Renma to select or
execute a Skill.

## Canonical declarations

The User Manual's
[authoritative metadata table](user-manual.md#renma-operational-metadata-table)
owns the complete Renma field inventory. This section intentionally covers
only the Discovery-specific `renma.published-entrypoint` and
`renma.continues-with` subset and its deeper routing semantics.

Only a specification-valid, directory-based Agent Skill named exactly
`SKILL.md` can contribute operational Discovery metadata:

```yaml
---
name: review-request
description: Classify a review request by workflow. Use when a request needs a reviewed next step; do not use for implementation or runtime Skill selection.
metadata:
  renma.id: skill.review-request
  renma.owner: developer-experience
  renma.status: stable
  renma.published-entrypoint: "true"
  renma.continues-with: '["skill.review-api","skills/review-ui/SKILL.md"]'
---
```

`metadata.renma.published-entrypoint` is a one-state marker. The only valid
value is the exact YAML string `"true"`; omission means not published. YAML
booleans, `"false"`, empty or whitespace-padded strings, alternate casing,
numbers, arrays, objects, null, duplicate declarations, and duplicate
top-level `metadata` mappings fail closed. Renma does not accept
`published_entrypoint`, `discovery_entrypoint`, `entrypoint`,
`renma.entrypoint`, or historical aliases, and does not fall back to legacy
metadata. Rejected markers retain exact field evidence.

`metadata.renma.continues-with` uses a JSON-array string contract.
Every member must be a non-empty string. An empty array string (`'[]'`) is valid
and declares no routes. Renma resolves one exact effective asset ID or one
exact repository-relative source path after the documented path normalization;
it does not match titles, tags, aliases, basenames, suffixes, prose, or ordinary
Markdown links.

## Publication eligibility

Publication intent and effective publication are separate. A visible Skill
exposes marker state and evidence, whether publication was requested and
accepted, stable rejection reasons, and linked existing diagnostics.

A Skill is an effective published entrypoint only when the marker is the exact
string `"true"` and the Skill is:

- a specification-valid canonical Agent Skill;
- lifecycle-usable: status is omitted, `experimental`, or `stable`; and
- unique in effective asset ID across the repository catalog.

Stable publication rejection reasons are `invalid-marker`,
`ambiguous-marker`, `invalid-skill`, `inactive-skill`, and
`duplicate-skill-id`. Existing `AS-SKILL-*` validity diagnostics and
`META-DUPLICATE-ASSET-ID` evidence remain authoritative; Discovery links them
instead of emitting competing validity or identity diagnostics.

A suspended Skill remains in the visible Skill inventory with its current
lifecycle reason and transition date, but it is not eligible for publication or
routing. A valid publication marker on a suspended Skill emits the blocking
`DISCOVERY-SUSPENDED-PUBLISHED-ENTRYPOINT` diagnostic. An active route that
resolves exactly to a suspended Skill remains resolved and auditable, but is
unusable and emits blocking `DISCOVERY-SUSPENDED-ROUTE-TARGET`. Suspended Skills
and routes are excluded from effective entrypoints, route eligibility,
reachability, coverage, and route-cycle analysis. Deprecated and archived
publication and route attempts keep their established warning behavior.

A revoked Skill is likewise retained with its current reason and transition
date but is unusable for publication and routing. Its valid publication marker
emits blocking `DISCOVERY-REVOKED-PUBLISHED-ENTRYPOINT`; an active route to it
emits blocking `DISCOVERY-REVOKED-ROUTE-TARGET`. These IDs remain distinct from
suspension because revocation records explicit withdrawal of trust or
authorization, not a temporary stop.

A published Skill may have an incoming route or no outgoing route. A Skill
with no outgoing route can itself be a complete first-hop workflow. Graph
position never determines publication.

## Repository-wide adoption

Repository-wide adoption is declared only in Renma JSONC or JSON configuration:

```jsonc
{
  "skill_discovery": {
    "adopted": true,
    // Keep warning-only while maintainers review migration results.
    "ci_policy": "warn"
  }
}
```

`skill_discovery` must be an object. Its supported keys are boolean `adopted`
and string `ci_policy`. Adoption omission defaults to `false`; explicit
`false` does not declare repository-wide adoption. `ci_policy` supports only
`off` and `warn`, defaults to `off`, and `warn` requires `adopted: true`.
Unknown keys, non-string modes, unsupported modes, and alternate spellings are
configuration errors. `renma init` continues to omit this field: initializing
Renma is not the same decision as adopting repository-wide Skill Discovery or
enabling CI review policy.

The prepared Discovery index reports one deterministic adoption state:

- `not-adopted`: no continuation or publication metadata is present and
  repository-wide adoption is not true;
- `partial`: valid, invalid, or rejected continuation/publication metadata is
  present and repository-wide adoption is not true;
- `incomplete`: repository-wide adoption is true but no effective published
  entrypoint exists; or
- `adopted`: repository-wide adoption is true and at least one effective
  published entrypoint exists.

## Reachability and coverage

Published entrypoints define where Discovery starts. Usable `continues-with`
routes define where Discovery can continue. Reachability reports what can be
found through those declarations. Renma still does not decide which Skill
matches a user request.

Traversal starts from every effective published entrypoint at depth `0` and
uses only routes that are usable representatives, resolve successfully, and
target a Skill. Resolution and usability are not reinterpreted during
traversal. Invalid, inactive, duplicate-ID, unresolved, ambiguous, wrong-kind,
and duplicate non-representative declarations therefore cannot create
reachability. Adjacency, entrypoint provenance, and result IDs are sorted;
per-entrypoint breadth-first traversal gives the true minimum route depth and
terminates safely through self-loops and larger cycles.

## Route-cycle review diagnostics

Renma detects maximal strongly connected components after route resolution and
usability are complete. The input is exactly the existing
authoritative continuation edge boundary:

```text
route.usable === true
route.representative === true
route.resolution === "resolved"
route.resolvedTarget.kind === "skill"
```

Invalid, inactive, duplicate-ID, unresolved, ambiguous, wrong-kind,
normalization-rejected, and duplicate non-representative declarations cannot
participate. Ordinary Markdown references, Context relationships,
reachability, structural-root state, and directory layout never create cycle
edges.

A singleton component emits `DISCOVERY-ROUTE-CYCLE` only when its one Skill has
an explicit self-loop. A component with two or more Skills emits one warning
for the complete maximal component, including every usable representative
internal route. Sorted adjacency, members, routes, and component sequences make
the result independent of document, declaration, Map, and Set insertion order.
The canonical first internal route supplies the warning's primary path and
exact `renma.continues-with` evidence.

A cycle is static continuation evidence. It does not prove that an agent will
recurse or execute the same Skills repeatedly. Renma traversal is cycle-safe. A
cycle may be intentional, but every internal continuation and the workflow's
stop, ask, retry, handoff, and completion conditions should be reviewed. An
intentional bounded cycle may remain after review; Renma does not choose an
edge to remove or change reachability.

Every visible Skill exposes one reachability object:

- `reachable`: an effective entrypoint or an eligible Skill reached through
  usable declarations, with every reaching entrypoint ID and minimum depth;
- `not-reached`: an eligible Skill with no usable path when coverage is being
  evaluated; or
- `not-evaluated`: repository coverage is not evaluated, or the Skill itself
  is not Discovery-eligible.

Coverage always has repository scope and uses one of three modes:

- `not-evaluated`: Discovery is `not-adopted`, `incomplete`, or `partial`
  without an effective published entrypoint. Reachable and not-reached arrays
  remain empty. Readiness reports this as unevaluated rather than presenting
  the empty arrays as `0 reachable` and `0 not-reached`. The check is neutral
  for `not-adopted`; it warns only when Discovery metadata or explicit
  repository-wide adoption makes the missing effective entrypoint actionable.
- `descriptive`: adoption is `partial` and at least one effective published
  entrypoint exists. Reachability is review evidence, not a repository-wide
  completeness claim, and not-reached Skills do not emit coverage warnings.
- `authoritative`: adoption is `adopted`. `complete` is true only when every
  Discovery-eligible Skill is reachable; otherwise it is false and each
  not-reached eligible Skill emits a warning.

The index exposes sorted `reachableDiscoveryEligibleSkillIds`,
`notReachedDiscoveryEligibleSkillIds`, and `unroutedSkillIds`. Unrouted means
exactly an eligible structural root that is not an effective published
entrypoint; it is not a synonym for not-reached. A disconnected child can be
not-reached while still having an incoming usable route and therefore not be
unrouted.

## Graph view

All Discovery formats use the same index prepared in the shared repository
snapshot:

```bash
renma graph . --view discovery --format json
renma graph . --view discovery --format markdown
renma graph . --view discovery --format mermaid
renma graph . --view discovery --focus skill.review-request --format json
```

JSON includes `adoption`, repository-scoped `coverage`, published, reachable,
not-reached, structural-root, standalone, and unrouted ID arrays in the
dedicated `discovery` object. Each visible Skill includes ownership provenance,
structural-root and standalone facts, marker evidence, publication request and
acceptance, rejection reasons, global reachability, unrouted state, and linked
diagnostics. Repository diagnostics remain at top-level `diagnostics`; Skill
Discovery diagnostics remain under `discovery.diagnostics`. Exit-code
evaluation considers errors in both collections, while current Discovery
diagnostics are warnings.

Markdown presents Summary, Adoption, Coverage, Published entrypoints,
authoritative coverage gaps when adopted, Structural roots, Unrouted Skills,
Declared routes, Discovery diagnostics, and then Repository diagnostics when
present. Descriptive mode shows counts without presenting not-reached Skills as
defects. Long structural and coverage lists are bounded; JSON retains the full
arrays.

Mermaid retains solid usable route edges and dotted unusable declaration edges.
Published entrypoints and structural roots receive separate deterministic
classes, including both facts when one Skill has both roles. Styling does not
change edge meaning or imply invocation. Deterministic comments record coverage
mode plus source-entrypoint, reachable, not-reached, and unrouted ID arrays.

Exact `--focus` retains the selected Skill's direct incoming and outgoing
declarations without transitive traversal. A focused projection preserves the
repository-wide adoption and coverage objects and every visible Skill's global
reachability. Published, reachable, not-reached, and unrouted ID arrays plus
summary counts are filtered to visible Skills. Focus never becomes a traversal
seed and never recomputes coverage or cycles from the subset. Repository-wide
cycle diagnostics remain visible whenever any recorded internal cycle route is
part of the focused direct-neighborhood route projection. Focusing an unrelated
Skill excludes the diagnostic; focus does not become transitive.

## Skill Index command

`renma skill-index` emits a compact static index over the same prepared
Discovery model:

```bash
renma skill-index .
renma skill-index . --format markdown
renma skill-index . --format json
renma skill-index . --json
renma skill-index . --focus skill.release-prep --format markdown
```

Markdown is the default. JSON uses the canonical schema identifier
`renma.skill-index.v1` and is the complete unfocused automation contract. The
report contains repository metadata, the existing adoption, coverage, summary,
visible Skill, route, publication, reachability, structural-root, standalone,
unrouted, and eligible-ID projections, plus explicitly separate
`diagnostics.repository` and `diagnostics.discovery` collections.

The command collects one `RepositorySnapshot` and wraps its already prepared
Discovery index. It does not scan twice or reimplement parsing, exact target
resolution, eligibility, publication, reachability, coverage, or focus.
Repository diagnostics remain repository-wide. Focused Discovery diagnostics
use the existing exact direct-neighborhood projection.

Focus accepts only an exact stable effective Skill ID or exact
repository-relative Skill source path. It does not match titles, descriptions,
tags, aliases, basenames, suffixes, letter-case variants, fuzzy phrases, or task
text. Focus does not perform transitive traversal and does not make the selected
Skill reachable. In focused reports:

```text
coverage is repository-scoped

summary and visible ID arrays are projection-scoped
```

Markdown shows the static-only boundary, summary, adoption and coverage,
focused Skill when present, effective published entrypoints and their direct
continuations, authoritative coverage gaps, structural candidates, separate
diagnostic sections, and instructions to open the referenced source
`SKILL.md`. Long presentation lists use the established deterministic cap;
JSON retains complete evidence.

The command writes only to stdout. It does not create `.renma/`, write a
generated index, modify configuration or Skill metadata, interpret a request,
select or rank a Skill, load Context, assemble a prompt, infer a route, call an
LLM, or execute a workflow. Exit `0` means the report was produced with no
error-severity diagnostic; warnings still exit `0`. Exit `1` means an error is
present in either diagnostic collection. Invalid CLI use, configuration, focus,
or report construction exits `2`.

## Diagnostics

Discovery publication uses these warning diagnostics:

- `DISCOVERY-INVALID-PUBLISHED-ENTRYPOINT` for an invalid or ambiguous marker,
  or an exact marker on a specification-valid inactive Skill; and
- `DISCOVERY-ENTRYPOINT-WITHOUT-USABLE-BOUNDARIES` when current deterministic
  Agent Skills checks establish that an effective entrypoint lacks a
  capability, positive usage boundary, or negative selection boundary.

The boundary warning reuses linked `RN-SKILL-*` evidence and is not proof of
semantic completeness. Its repair is to improve the bounded first-hop
responsibility, not to remove publication solely to silence the warning.

Both diagnostics flow through normal scan output, diagnostics v2, and review
bundles. They do not create a CI gate. Readiness may reference their
stable codes and messages as compact check evidence without copying them into
its diagnostic collection. The semantic diff and neutral CI projection compare
prepared topology facts but do not copy these diagnostics; Trust Graph and BOM
remain excluded.

`DISCOVERY-UNREACHABLE-ELIGIBLE-SKILL` appears only in authoritative adopted
mode, once
per not-reached eligible Skill. It states the exact negative graph fact: no
usable declared continuation path reaches the Skill from any effective
published entrypoint. It does not claim runtime non-use and does not recommend
a fake route or blanket publication. Repair requires human review of whether
the Skill is an independent first hop, belongs beneath a real source-owned
workflow, or falls outside the intended repository-wide policy. This warning
also flows through scan, diagnostics v2, and review bundles. Readiness uses it
as the authority for adopted-mode coverage check evidence without
duplicating the diagnostic or applying another score penalty. Its diagnostic
payload remains outside Trust Graph, semantic diff, CI, and BOM projections.

`DISCOVERY-ROUTE-CYCLE` does not require repository-wide adoption. It is emitted
whenever the prepared usable continuation graph
contains a cyclic strongly connected component, including a self-loop. In
normal repository states this means `partial`, `incomplete`, or `adopted`: a
truly `not-adopted` repository has no Discovery metadata and therefore cannot
contain a usable declared route cycle. Details contain
sorted `cycleSkillIds`, `cycleSkills`, `selfLoop`, `routeCount`, and complete
`cycleRoutes` evidence. Every member Skill and internal route links the
diagnostic. The warning asks a human to decide whether the component is an
intentional bounded workflow loop or an accidental circular continuation
contract; it does not require every intentional cycle to be removed.

Cycle warnings flow through scan, diagnostics v2, review bundles, Discovery
graph diagnostics, Skill Index Discovery diagnostics, and the compact
Readiness cycle-review check. They remain warnings, do not create a CI gate,
and do not by themselves make Readiness fail. Discovery JSON report schemas,
Markdown sections, and Mermaid edge semantics are unchanged; there is no
top-level cycle section or count in the Discovery graph or Skill Index.

## Readiness projection

Readiness exposes routine-review visibility under
`readiness.summary.skillDiscovery`. The summary is derived only from the
memoized prepared Discovery index in the shared `RepositorySnapshot` and
contains the existing adoption state plus compact publication, eligibility,
reachability, unrouted, route-usability, unresolved-route, and maximal
cycle-component counts. It contains no complete Skill array, route list, or
diagnostic payload.

The five Readiness checks use the established lower-case dotted ID style:

- `discovery.publication` reviews explicit effective publication only.
  `not-adopted` repositories pass because publication is not required and
  structural roots are never inferred as published. Partial or incomplete
  adoption without an effective published entrypoint warns, while valid
  effective publication and existing publication diagnostics remain
  authoritative;
- `discovery.route_validity` aggregates existing resolution and usability
  reasons;
- `discovery.coverage` is authoritative only for explicit repository-wide
  adoption, descriptive only for partial adoption with an effective
  entrypoint, and explicitly unevaluated when Discovery is not adopted or no
  effective entrypoint exists;
- `discovery.unrouted_skills` preserves the existing unpublished/no-incoming
  usable continuation definition and does not reject intentional standalone
  Skills automatically; and
- `discovery.cycle_review` counts maximal cyclic components as warning-level
  human review evidence.

This projection adds no scoring weight. Partial coverage never reduces the
score, cycle presence alone is not a hard failure, and existing Discovery
diagnostics are referenced rather than copied or penalized again. Use
`renma skill-index` for the complete static report and
`renma graph --view discovery` for topology and source evidence.

The direct Readiness command prepares the memoized Discovery projection once.
Semantic diff retains its Discovery-excluded Readiness subset, then uses the same
snapshot's prepared Discovery index for its dedicated versioned section.
CI calls that complete semantic diff once and projects its existing
`SkillDiscoveryDiff`; it therefore intentionally prepares one Discovery index
per ref without a second collection or comparison. BOM continues to build and
serialize its Discovery-excluded Readiness subset without preparing Discovery
for that subset.

## Semantic diff projection

Direct `renma diff` JSON and Markdown include an observation-only `discovery`
section. It reports exact from/to adoption and coverage
modes, count deltas, effective published entrypoint additions/removals,
newly-reachable and newly-not-reached Skills, newly/resolved unrouted Skills,
route additions/removals/state changes, and added/resolved maximal cyclic
components. Count deltas use `to - from`; identity lists remain present because
equal additions and removals can cancel numerically.

Skill identity is repository-relative path plus visible ID. Route identity is
normalized source Skill path plus normalized declared target. It deliberately
excludes declaration index, YAML array position, source line, discovery order,
resolved target, and object insertion order. Declarations with the same route
identity form one group whose `declarationCount` records duplicate changes.
Reordering declarations therefore produces no diff. A resolution, candidate,
resolved-target, lifecycle, usability, or reason change under the same
identity is one changed route; only identity presence determines route
addition or removal.

Cycle identity is the sorted maximal strongly connected component member-ID
set. Internal edge order does not create a resolved-plus-added cycle pair;
edge changes remain route changes. Reachability uses only the prepared
reachable/not-reached partitions, and empty sets stay empty when coverage is
not evaluated. Structural roots are never inferred as publication.

Each archived ref is collected once into one immutable `RepositorySnapshot`.
Graph, the Discovery-excluded Readiness subset, and `snapshot.skillDiscovery`
therefore share one parse, catalog preparation, Agent Skills validation, and
Discovery preparation per ref. The diff does not call `skill-index`, reconstruct
Discovery independently, or copy its complete report or diagnostics.

These facts have no improvement/regression label and do not change direct diff
exit behavior.

## CI report projection and review policy

Renma exposes the exact existing `SkillDiscoveryDiff` once as required
top-level `CiReport.skillDiscovery`. Its schema remains
`renma.skill-discovery-diff.v1`; CI does not construct a second Discovery
schema or comparison. The nested `CiCompatibleDiffReport` under `diff` omits
`discovery`, preserving the compact earlier contract and avoiding duplicate
JSON.

CI uses the internal semantic-diff execution exactly once. Each ref therefore
uses one immutable `RepositorySnapshot`, one discovery pass, one parse per
artifact, one catalog preparation, one Agent Skills validation, and one Skill
Discovery preparation. Graph, the Discovery-excluded Readiness subset,
Discovery facts, and that ref's effective `skillDiscovery.ciPolicy` reuse the
same snapshot. There is no second diff, config load, repository discovery, or
Discovery preparation.

Reports also contain one top-level `skillDiscoveryPolicy` value:

```text
schemaVersion: renma.skill-discovery-ci-policy.v1
configured: { from, to, effective }
outcome: pass | warn
matchCount
matches
```

The effective mode uses the stricter archived-ref value under `off < warn`.
Thus `off -> warn` and `warn -> off` both evaluate as `warn`; a pull request
cannot bypass review merely by disabling the policy in its target config.
When effective mode is `off`, evaluation returns `pass`, zero matches, and no
hypothetical results.

Enabled policy evaluation uses only these stable match IDs and conditions:

- `skill_discovery_ci.adoption_weakened`: adoption moves from `adopted` or
  `incomplete` to `partial` or `not-adopted`;
- `skill_discovery_ci.adoption_incomplete`: target adoption is `incomplete`;
- `skill_discovery_ci.newly_not_reached`: one match per existing
  `reachability.newlyNotReached` Skill, only with authoritative target coverage;
- `skill_discovery_ci.route_became_unusable`: one match per changed route whose
  usable state changes from `true` to `false`, only with authoritative target
  coverage; and
- `skill_discovery_ci.added_unusable_route`: one match per added route whose
  usable state is `false`, only with authoritative target coverage.

Removed entrypoints, newly unrouted Skills, removed routes,
declaration-count-only changes, newly reachable Skills, resolved not-reached
Skills, routes becoming usable, adoption becoming authoritative, cycles and
self-loops, partial/not-adopted coverage observations, and count deltas without
matching identities do not create policy matches. In particular, a cycle is
review evidence rather than an automatic defect.

CI Markdown places a bounded `## Skill Discovery Changes` section after the
semantic-diff summary. It reports policy configuration and outcome plus
adoption, coverage, publication, reachability, unrouted Skills, route changes,
cycle changes, and bounded policy matches. Detailed lists use the shared
top-summary cap and direct readers to JSON for omitted entries. It does not
render the complete graph, diagnostics, declaration indices, source lines, or
repair instructions.

`determineCiReportStatus()` remains typed only over the Discovery-free
compatible diff. A separate pure composition keeps `fail > warn > pass`: an
existing `FAIL` remains `FAIL`, an existing `WARN` remains `WARN`, and an
existing `PASS` becomes `WARN` only when policy outcome is `warn`. One concise
policy review note is appended for matches. Discovery policy cannot produce
`FAIL`, and its `WARN` exits `0`.

Serialized CI reports that predate both Discovery fields retain their prior JSON
and Markdown shape. A report with `skillDiscovery` but no
`skillDiscoveryPolicy` retains its observation-only section. Formatting does not
mutate either legacy generation.

Programmatic compatibility is preserved separately from the direct command
contract. `buildDiffReport()` accepts older snapshots without prepared
Discovery indexes and returns a stable neutral Discovery section rather than
inferring topology. `formatDiff()` accepts older serialized reports without
`discovery` and retains their previous non-Discovery Markdown shape.

## Compatibility and boundaries

Continuation and publication data remain separate from
`catalog.dependencies`. Existing full, summary, workflow, layered,
composition, and impact graph outputs remain route/publication-free. Catalog,
Trust Graph, BOM, ownership, init, scaffold, guide, and suggestion contracts
are unchanged. Readiness changes only through its additive summary and checks;
direct diff changes only through its additive observation section; CI adds the
neutral projection and explicit warn-only policy. A
repository without Discovery policy opt-in remains valid and policy-neutral.
Its
`not-adopted` Readiness summary is a neutral inventory
summary: route-eligible, unrouted, and route counts remain visible, while
publication is not required and coverage is not evaluated.

There is no `renma discovery` command. Hard-fail gating, per-rule configuration,
policy suppressions or allowlists, Trust Graph, BOM, ownership, observed
Markdown references, richer visualization, authoring assistance, scaffold,
init, guide, suggestion, and multi-repository federation are outside this
contract. BOM and Trust Graph output contracts contain no Discovery additions.
