renma 0.18.1 → 0.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +126 -1
- package/README.md +60 -2
- package/architecture.md +4 -0
- package/dist/agent-skills.d.ts +5 -6
- package/dist/agent-skills.d.ts.map +1 -1
- package/dist/agent-skills.js +2 -10
- package/dist/agent-skills.js.map +1 -1
- package/dist/catalog.d.ts +28 -2
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +65 -16
- package/dist/catalog.js.map +1 -1
- package/dist/cli-help.d.ts +4 -4
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +5 -3
- package/dist/cli-help.js.map +1 -1
- package/dist/command-invocation.d.ts +4 -0
- package/dist/command-invocation.d.ts.map +1 -0
- package/dist/command-invocation.js +14 -0
- package/dist/command-invocation.js.map +1 -0
- package/dist/commands/inspect.d.ts +2 -61
- package/dist/commands/inspect.d.ts.map +1 -1
- package/dist/commands/inspect.js +51 -149
- package/dist/commands/inspect.js.map +1 -1
- package/dist/commands/readiness.d.ts +3 -0
- package/dist/commands/readiness.d.ts.map +1 -1
- package/dist/commands/readiness.js +9 -6
- package/dist/commands/readiness.js.map +1 -1
- package/dist/commands/suggest-metadata.d.ts +4 -17
- package/dist/commands/suggest-metadata.d.ts.map +1 -1
- package/dist/commands/suggest-metadata.js +214 -219
- package/dist/commands/suggest-metadata.js.map +1 -1
- package/dist/decisions/metadata-suggestion.d.ts +60 -0
- package/dist/decisions/metadata-suggestion.d.ts.map +1 -0
- package/dist/decisions/metadata-suggestion.js +176 -0
- package/dist/decisions/metadata-suggestion.js.map +1 -0
- package/dist/discovery.d.ts +33 -1
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +365 -51
- package/dist/discovery.js.map +1 -1
- package/dist/evidence/classification.d.ts +4 -0
- package/dist/evidence/classification.d.ts.map +1 -0
- package/dist/evidence/classification.js +15 -0
- package/dist/evidence/classification.js.map +1 -0
- package/dist/evidence/inspect.d.ts +68 -0
- package/dist/evidence/inspect.d.ts.map +1 -0
- package/dist/evidence/inspect.js +2 -0
- package/dist/evidence/inspect.js.map +1 -0
- package/dist/evidence/target.d.ts +51 -0
- package/dist/evidence/target.d.ts.map +1 -0
- package/dist/evidence/target.js +161 -0
- package/dist/evidence/target.js.map +1 -0
- package/dist/model.d.ts +2 -10
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js.map +1 -1
- package/dist/renderers/inspect.d.ts +3 -0
- package/dist/renderers/inspect.d.ts.map +1 -0
- package/dist/renderers/inspect.js +159 -0
- package/dist/renderers/inspect.js.map +1 -0
- package/dist/renderers/metadata-suggestion.d.ts +3 -0
- package/dist/renderers/metadata-suggestion.d.ts.map +1 -0
- package/dist/renderers/metadata-suggestion.js +320 -0
- package/dist/renderers/metadata-suggestion.js.map +1 -0
- package/dist/repository-evidence.d.ts +7 -1
- package/dist/repository-evidence.d.ts.map +1 -1
- package/dist/repository-evidence.js +10 -2
- package/dist/repository-evidence.js.map +1 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +58 -4
- package/dist/scanner.js.map +1 -1
- package/dist/skill-migration.d.ts.map +1 -1
- package/dist/skill-migration.js +6 -1
- package/dist/skill-migration.js.map +1 -1
- package/dist/types.d.ts +72 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +50 -1
- package/dist/types.js.map +1 -1
- package/docs/README.md +2 -0
- package/docs/agent-skills-compatibility.md +8 -1
- package/docs/authoring-guide.md +62 -0
- package/docs/diagnostics.md +382 -2
- package/docs/internal-architecture.md +296 -0
- package/docs/user-manual.md +122 -12
- package/package.json +1 -1
- package/scripts/verify-package.mjs +154 -9
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# Renma Internal Architecture
|
|
2
|
+
|
|
3
|
+
This document describes the implemented internal architecture for the 0.18.3
|
|
4
|
+
maintainability release. It is contributor guidance, not a new CLI or JSON
|
|
5
|
+
contract. Renma 0.18.2 remains the behavioral baseline: internal types and
|
|
6
|
+
module boundaries may become clearer, but public fields, classifications,
|
|
7
|
+
diagnostics, severities, exit behavior, and migration direction must not change
|
|
8
|
+
as a side effect.
|
|
9
|
+
|
|
10
|
+
The high-level product boundary remains in [Architecture](../architecture.md).
|
|
11
|
+
Stable classification and decision fields are documented in the
|
|
12
|
+
[Diagnostics Reference](diagnostics.md), and the versioned BOM contract is in
|
|
13
|
+
[Repository Context BOM](repository-context-bom.md).
|
|
14
|
+
|
|
15
|
+
## Dependency Flow
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
repository files + config
|
|
19
|
+
|
|
|
20
|
+
v
|
|
21
|
+
discovery + parsing + repository resolution
|
|
22
|
+
|
|
|
23
|
+
v
|
|
24
|
+
RepositorySnapshot (facts and snapshot-scoped indexes)
|
|
25
|
+
|
|
|
26
|
+
+--> scan + graph --> Readiness --> BOM
|
|
27
|
+
|
|
|
28
|
+
v
|
|
29
|
+
target evidence --> governance evidence --> command decision --> renderer
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Dependencies should continue to point from low-level parsing and resolution to
|
|
33
|
+
evidence, then to decisions, renderers, and command orchestration. A lower-level
|
|
34
|
+
module must not import a command renderer. Commands coordinate these layers;
|
|
35
|
+
they should not independently reinterpret repository layout.
|
|
36
|
+
|
|
37
|
+
The dependency direction is checked in CI. Type-only imports are treated as
|
|
38
|
+
architectural dependencies, so lower layers must not import command or renderer
|
|
39
|
+
modules even when the import is erased at runtime.
|
|
40
|
+
|
|
41
|
+
## RepositorySnapshot Is the Repository Evidence Source
|
|
42
|
+
|
|
43
|
+
`collectRepositorySnapshot` in `src/repository-evidence.ts` performs one
|
|
44
|
+
repository collection and creates the shared in-memory source of repository
|
|
45
|
+
facts. The snapshot contains:
|
|
46
|
+
|
|
47
|
+
- resolved root, configuration, configuration path, and scan count;
|
|
48
|
+
- discovered artifacts and parsed documents;
|
|
49
|
+
- the normalized catalog, Context Lens summary, and diagnostic partitions;
|
|
50
|
+
- repository-relative paths and their captured filesystem states;
|
|
51
|
+
- structural classification evidence indexed by repository-relative path;
|
|
52
|
+
- a parent-Skill index used for exact parent resolution;
|
|
53
|
+
- effective security-policy evidence with its provenance.
|
|
54
|
+
|
|
55
|
+
The indexes belong to the snapshot. Consumers should reuse them instead of
|
|
56
|
+
reparsing files or rebuilding command-specific lookup tables. A new projection
|
|
57
|
+
should normally accept `RepositorySnapshot`, or the narrowest existing
|
|
58
|
+
projection of it, rather than perform another discovery pass.
|
|
59
|
+
|
|
60
|
+
`RepositorySnapshot` does not freeze the working tree. It records what one
|
|
61
|
+
collection read, after which downstream projections operate on that collected
|
|
62
|
+
state. In particular, Readiness builds its graph and scan from one snapshot,
|
|
63
|
+
and BOM builds its graph, scan, Readiness evidence, policy inventory, and
|
|
64
|
+
diagnostics from one snapshot. This prevents one command result from combining
|
|
65
|
+
independently recollected repository states.
|
|
66
|
+
|
|
67
|
+
`collectRepositoryEvidence` is a narrower compatibility projection for
|
|
68
|
+
consumers such as catalog and graph. It deliberately omits parsed documents,
|
|
69
|
+
sets, maps, and indexes that are implementation details.
|
|
70
|
+
|
|
71
|
+
## Structural And Repository-Backed Resolution
|
|
72
|
+
|
|
73
|
+
Resolution stages answer different questions and must remain separate.
|
|
74
|
+
|
|
75
|
+
### Repository boundary
|
|
76
|
+
|
|
77
|
+
`repositoryClassificationPath` determines whether a target can be expressed
|
|
78
|
+
relative to one safe repository root. Evidence is considered in this order:
|
|
79
|
+
|
|
80
|
+
1. an explicit repository root;
|
|
81
|
+
2. the nearest valid `.git`, `renma.config.json`, or `.renma.json` marker;
|
|
82
|
+
3. an unambiguous strong structural boundary such as `skills`, `.agents`,
|
|
83
|
+
`contexts`, `context`, `lenses`, or `tools`, plus recognized root files such
|
|
84
|
+
as `AGENTS.md`;
|
|
85
|
+
4. an unresolved or ambiguous result.
|
|
86
|
+
|
|
87
|
+
Current-working-directory containment is not proof of a repository boundary.
|
|
88
|
+
Renma may be invoked from a parent workspace, and a target may be absolute or
|
|
89
|
+
belong to a neighboring repository. Traversal outside an explicit root is
|
|
90
|
+
rejected instead of being normalized into that root.
|
|
91
|
+
|
|
92
|
+
The names `profiles`, `references`, `examples`, `scripts`, and `assets` are
|
|
93
|
+
negative guard evidence only. They can make a later structural interpretation
|
|
94
|
+
ambiguous, but they never establish a repository root by themselves. Once an
|
|
95
|
+
outer strong boundary has a recognized interpretation, nested boundary-like
|
|
96
|
+
names do not replace it.
|
|
97
|
+
|
|
98
|
+
### Structural classification
|
|
99
|
+
|
|
100
|
+
`classifyAssetPath` consumes only a normalized repository-relative path and,
|
|
101
|
+
where relevant, parsed metadata type. It produces path interpretation such as
|
|
102
|
+
`kind`, `scope`, `matchedRule`, `reasonCode`, `recognizedRoot`, competing rules,
|
|
103
|
+
ignored nested segments, and a possible parent-Skill path.
|
|
104
|
+
|
|
105
|
+
For Skill-local support, structural placement yields
|
|
106
|
+
`parentResolution: "structural-candidate"`. This means only that the path has a
|
|
107
|
+
canonical Skill-local shape. It does not prove that the candidate file exists,
|
|
108
|
+
is unique, owns the support file, or supplies policy.
|
|
109
|
+
|
|
110
|
+
### Repository-backed enrichment
|
|
111
|
+
|
|
112
|
+
`buildSkillParentIndex` records all discovered Skill entrypoint candidates by
|
|
113
|
+
logical Skill directory. `resolveSkillSupportParent` then returns `resolved`
|
|
114
|
+
only when exactly one candidate exists; zero candidates are `missing`, and
|
|
115
|
+
multiple candidates are `ambiguous`. `withResolvedSkillParent` attaches that
|
|
116
|
+
result without changing the original structural kind or scope.
|
|
117
|
+
|
|
118
|
+
Snapshot construction creates this parent index before catalog construction and
|
|
119
|
+
passes the same instance into `buildCatalog`. Catalog ownership, target parent
|
|
120
|
+
resolution, and governance enrichment therefore share one snapshot-scoped
|
|
121
|
+
source rather than reconstructing equivalent indexes independently. The public
|
|
122
|
+
`buildCatalog(documents, repositoryPaths)` call remains compatible and creates
|
|
123
|
+
an index for standalone callers.
|
|
124
|
+
|
|
125
|
+
Ownership, policy, catalog membership, and relationships also require
|
|
126
|
+
repository evidence. None of them may be manufactured from path shape alone.
|
|
127
|
+
|
|
128
|
+
## Shared Target Evidence
|
|
129
|
+
|
|
130
|
+
`inspect` and `suggest-metadata` share the target-evidence pipeline in
|
|
131
|
+
`src/evidence/target.ts`:
|
|
132
|
+
|
|
133
|
+
- `collectTargetDocumentEvidence` reads one target, resolves its repository
|
|
134
|
+
boundary, parses it, and builds structural classification evidence.
|
|
135
|
+
- `collectTargetRepositoryEvidence` collects the resolved repository snapshot
|
|
136
|
+
and enriches the target with catalog membership, parent resolution, policy,
|
|
137
|
+
and governance evidence.
|
|
138
|
+
|
|
139
|
+
The two stages remain separate because a readable file does not guarantee a
|
|
140
|
+
resolvable repository. When repository collection is unavailable, the target
|
|
141
|
+
retains structural evidence but does not fall back to guessed catalog identity,
|
|
142
|
+
parentage, ownership, or policy.
|
|
143
|
+
|
|
144
|
+
Unavailable evidence preserves the exact boundary result:
|
|
145
|
+
`repository-boundary-unresolved` and `repository-boundary-ambiguous` remain
|
|
146
|
+
distinct, while a failure after a root resolves is `snapshot-unavailable`.
|
|
147
|
+
|
|
148
|
+
## Classification, Governance, And Decisions
|
|
149
|
+
|
|
150
|
+
These evidence layers are related, but none is a substitute for another.
|
|
151
|
+
|
|
152
|
+
| Layer | Answers | Does not prove |
|
|
153
|
+
| --- | --- | --- |
|
|
154
|
+
| Classification | What repository path rule matched, what kind and scope result, and whether a structural or resolved parent is known | Ownership, policy, authority, or human intent |
|
|
155
|
+
| Governance | Whether ownership and policy are declared, inherited, or missing, including provenance | That a proposed edit is applicable |
|
|
156
|
+
| Decision | Whether a command result is deterministic, requires confirmation, is blocked, or recommends no change | A different path classification or permission to discard evidence |
|
|
157
|
+
|
|
158
|
+
Ownership is explicit governance evidence. A declared local owner remains
|
|
159
|
+
declared. A Skill-local file may inherit an effective owner only from exactly
|
|
160
|
+
one resolved parent Skill that declares an owner. Missing or ambiguous parents
|
|
161
|
+
remain unowned. Renma never derives ownership from directory names, prose, Git
|
|
162
|
+
authors, or modification history.
|
|
163
|
+
|
|
164
|
+
Policy provenance is tracked separately from ownership provenance. A local
|
|
165
|
+
policy must not be relabeled as inherited, and an absent effective policy stays
|
|
166
|
+
missing. Likewise, Renma does not infer that local support should be promoted,
|
|
167
|
+
that an independent asset should be created, or that a maintainer intended an
|
|
168
|
+
owner or lifecycle value. Those are human repository-design decisions.
|
|
169
|
+
|
|
170
|
+
## Decisions, Renderers, And Commands
|
|
171
|
+
|
|
172
|
+
Decision construction belongs in `src/decisions/`. A decision object carries
|
|
173
|
+
the authoritative `decisionStatus`, stable reason code, summary, and any
|
|
174
|
+
remaining human question. Candidate construction must honor that status before
|
|
175
|
+
anything is presented as an applicable edit.
|
|
176
|
+
|
|
177
|
+
Metadata suggestion uses pure builders in
|
|
178
|
+
`src/decisions/metadata-suggestion.ts` for Skill migrations, Skill-local parent
|
|
179
|
+
and governance states, unsupported targets, owner conflicts, and independent
|
|
180
|
+
metadata candidates. The command retains filesystem collision checks,
|
|
181
|
+
candidate assembly, next-action construction, and orchestration.
|
|
182
|
+
|
|
183
|
+
Renderers in `src/renderers/` turn an already-decided result into human text.
|
|
184
|
+
They may improve wording and layout, but they must not rediscover a parent,
|
|
185
|
+
infer governance, change applicability, or create candidate data. JSON output
|
|
186
|
+
serializes the command result directly; it is not reconstructed from rendered
|
|
187
|
+
text.
|
|
188
|
+
|
|
189
|
+
Command modules should stay orchestration-oriented:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
collect context -> build evidence -> decide -> render or serialize
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
A `no-change-recommended` decision is a successful result. It means Renma
|
|
196
|
+
completed the analysis and found no supported change. The command must not
|
|
197
|
+
manufacture metadata, a migration, or verification work merely to return an
|
|
198
|
+
edit-shaped response.
|
|
199
|
+
|
|
200
|
+
## Public JSON And Internal Working Types
|
|
201
|
+
|
|
202
|
+
Public machine-readable output is protected at the serialized command boundary.
|
|
203
|
+
Fields such as classification evidence, governance provenance,
|
|
204
|
+
`decisionStatus`, command invocation `command` and `args`, and established
|
|
205
|
+
diagnostic fields must remain compatible with 0.18.2.
|
|
206
|
+
|
|
207
|
+
Internal working types have a different role. `RepositorySnapshot`, parsed
|
|
208
|
+
documents, `ReadonlyMap` indexes, `ReadonlySet` repository paths, and
|
|
209
|
+
intermediate target-resolution unions exist to keep implementation states
|
|
210
|
+
explicit. They are not public JSON merely because they are TypeScript types.
|
|
211
|
+
They may be narrowed or reorganized when behavior-focused tests prove that the
|
|
212
|
+
serialized contract is unchanged.
|
|
213
|
+
|
|
214
|
+
Inspect renderer DTOs live in `src/evidence/inspect.ts`, so renderers do not
|
|
215
|
+
depend on command modules. `src/commands/inspect.ts` re-exports the established
|
|
216
|
+
types to preserve existing TypeScript deep imports.
|
|
217
|
+
|
|
218
|
+
Human-readable reasons and prompts may evolve unless a test intentionally
|
|
219
|
+
protects exact wording. Stable branching must use typed fields such as
|
|
220
|
+
`matchedRule`, `reasonCode`, `parentResolution`, ownership provenance, and
|
|
221
|
+
`decisionStatus`, not prose parsing.
|
|
222
|
+
|
|
223
|
+
## Intentional 0.18.2 Compatibility Seams
|
|
224
|
+
|
|
225
|
+
Two parallel-looking paths remain intentional in 0.18.3.
|
|
226
|
+
|
|
227
|
+
### Scan keeps structural parent evidence
|
|
228
|
+
|
|
229
|
+
The snapshot classification index used to annotate scan findings and
|
|
230
|
+
diagnostics is structural. A Skill-local scan detail may therefore retain
|
|
231
|
+
`parentResolution: "structural-candidate"`. Target-oriented commands such as
|
|
232
|
+
`inspect` and `suggest-metadata` enrich the same structural classification with
|
|
233
|
+
snapshot-backed `resolved`, `missing`, or `ambiguous` parent evidence.
|
|
234
|
+
|
|
235
|
+
Do not silently make scan annotations repository-enriched merely to make the
|
|
236
|
+
implementations look uniform. The distinction preserves the 0.18.2 public
|
|
237
|
+
diagnostic shape; changing it requires an explicit contract decision and
|
|
238
|
+
characterization tests.
|
|
239
|
+
|
|
240
|
+
### Blocked migrations retain partial diagnostic maps
|
|
241
|
+
|
|
242
|
+
A blocked Agent Skills migration may retain partial
|
|
243
|
+
`candidateAgentSkillsFields` and `candidateRenmaMetadata` maps. These fields are
|
|
244
|
+
diagnostic evidence retained for 0.18.2 JSON compatibility, not an applicable
|
|
245
|
+
patch.
|
|
246
|
+
|
|
247
|
+
`decisionStatus` is authoritative. A frontmatter migration is applicable only
|
|
248
|
+
when the decision is not blocked and `canonicalFrontmatter` is present.
|
|
249
|
+
Blocked results must not expose canonical frontmatter or renderer patch
|
|
250
|
+
instructions, and consumers must never treat the partial candidate maps as an
|
|
251
|
+
override of the gate.
|
|
252
|
+
|
|
253
|
+
## Fail-Closed Boundaries
|
|
254
|
+
|
|
255
|
+
The following constraints are safety and compatibility invariants:
|
|
256
|
+
|
|
257
|
+
- An unresolved or ambiguous repository boundary produces no guessed root,
|
|
258
|
+
catalog identity, inherited governance, or executable repository action.
|
|
259
|
+
- Guard directory names are never positive repository-root evidence.
|
|
260
|
+
- Repository discovery does not follow symbolic links, and a symbolic-link
|
|
261
|
+
marker does not establish a boundary.
|
|
262
|
+
- Structural Skill-local placement never establishes inheritance by itself.
|
|
263
|
+
- A missing or ambiguous parent supplies neither inherited ownership nor
|
|
264
|
+
inherited policy.
|
|
265
|
+
- Explicit local governance is preserved as local governance.
|
|
266
|
+
- A blocked decision suppresses applicable candidate metadata and canonical
|
|
267
|
+
frontmatter; renderers cannot reopen the decision.
|
|
268
|
+
- A no-change decision produces no synthetic work.
|
|
269
|
+
|
|
270
|
+
When one of these states looks inconvenient, preserve it and improve the
|
|
271
|
+
evidence presented to the maintainer. Do not replace uncertainty with a guess.
|
|
272
|
+
|
|
273
|
+
## Runtime Boundary
|
|
274
|
+
|
|
275
|
+
Renma analyzes declared repository state. It does not execute Skills, select a
|
|
276
|
+
Skill for a live task, assemble prompts, invoke Skill tools, observe model runs,
|
|
277
|
+
or collect runtime telemetry. Static instructions and policies are evidence
|
|
278
|
+
about repository content; they are not proof of runtime behavior.
|
|
279
|
+
|
|
280
|
+
Future runtime signals may be imported as a separate, explicitly versioned
|
|
281
|
+
evidence artifact linked to a repository snapshot or BOM. Signal production,
|
|
282
|
+
collection, storage, and Skill execution remain outside this architecture.
|
|
283
|
+
|
|
284
|
+
## Contributor Checklist
|
|
285
|
+
|
|
286
|
+
For an internal change:
|
|
287
|
+
|
|
288
|
+
1. Add or confirm a behavior-focused test for the 0.18.2 result.
|
|
289
|
+
2. Reuse the snapshot and shared resolution paths before adding another
|
|
290
|
+
collector or index.
|
|
291
|
+
3. Keep structural facts, repository-backed governance, decisions, and
|
|
292
|
+
rendering in their respective layers.
|
|
293
|
+
4. Verify stable JSON fields and fail-closed states, not only human text.
|
|
294
|
+
5. For Readiness or BOM changes, prove all derived sections use one snapshot.
|
|
295
|
+
6. Run targeted tests, type checking, linting, the full test suite, build, and
|
|
296
|
+
package verification before release.
|
package/docs/user-manual.md
CHANGED
|
@@ -73,17 +73,20 @@ support paths:
|
|
|
73
73
|
|
|
74
74
|
The same reserved names apply under `.agents/skills/**`.
|
|
75
75
|
|
|
76
|
-
These
|
|
77
|
-
specific to one Skill. Promote reusable source-of-truth knowledge to an
|
|
78
|
-
Context Asset, or a helper shared across workflows to `tools/**`, only
|
|
79
|
-
repository evidence supports that change; Renma does not move files
|
|
76
|
+
These valid support paths are structurally Skill-local. Keep material local when
|
|
77
|
+
it is specific to one Skill. Promote reusable source-of-truth knowledge to an
|
|
78
|
+
owned Context Asset, or a helper shared across workflows to `tools/**`, only
|
|
79
|
+
when repository evidence supports that change; Renma does not move files
|
|
80
80
|
automatically.
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
support artifact does not declare an owner,
|
|
84
|
-
Graph, and BOM reporting use the
|
|
85
|
-
effective ownership and mark it as inherited.
|
|
86
|
-
|
|
82
|
+
Renma claims a parent only after repository evidence resolves exactly one Skill
|
|
83
|
+
entrypoint. When that resolved local support artifact does not declare an owner,
|
|
84
|
+
ownership, Readiness, graph, Trust Graph, and BOM reporting may use the parent
|
|
85
|
+
Skill's owner as deterministic effective ownership and mark it as inherited.
|
|
86
|
+
Missing or ambiguous parents never inherit. See
|
|
87
|
+
[classification evidence](diagnostics.md#how-to-read-classification-evidence)
|
|
88
|
+
for the detailed contract. This does not invent ownership for shared Context
|
|
89
|
+
Assets or unrelated repository files.
|
|
87
90
|
|
|
88
91
|
Only files marked Markdown-parser eligible contribute frontmatter metadata,
|
|
89
92
|
headings, links, code fences, and repeated-context evidence. Text scripts and
|
|
@@ -162,6 +165,61 @@ Review the Skill with this platform's standard Skill authoring guidance, then us
|
|
|
162
165
|
Start by running `renma --help` and use command-specific help to choose the appropriate workflow. Make only evidence-backed changes. Do not invent owners, references, product rules, or source-of-truth claims. Preserve existing semantics unless a diagnostic or explicit requirement supports a change. Run `renma scan . --fail-on high` after editing, fix relevant diagnostics, rerun it, and summarize both resolved and remaining findings.
|
|
163
166
|
```
|
|
164
167
|
|
|
168
|
+
Recommended evidence-first preflight:
|
|
169
|
+
|
|
170
|
+
1. Run `renma scan . --fail-on high --format json`.
|
|
171
|
+
2. Run `renma inspect <SKILL.md> --format json`.
|
|
172
|
+
3. Inspect relevant local resources and referenced Context Assets.
|
|
173
|
+
4. Use `renma suggest-metadata` only when retrofit or migration evidence exists.
|
|
174
|
+
5. Prepare the smallest intended patch.
|
|
175
|
+
6. Rerun `renma scan . --fail-on high --format json`.
|
|
176
|
+
7. Stop without manufacturing work when `suggest-metadata` reports
|
|
177
|
+
`decisionStatus: "no-change-recommended"`; this currently uses
|
|
178
|
+
`suggestedMode: "no-proposal"`.
|
|
179
|
+
8. Report unresolved human decisions.
|
|
180
|
+
|
|
181
|
+
For one classification question, `renma inspect <target> --format json` may be
|
|
182
|
+
the initial preflight. Repository-wide work should normally start with `scan`.
|
|
183
|
+
|
|
184
|
+
## Context Asset Discovery Boundary
|
|
185
|
+
|
|
186
|
+
`contexts/**` is the preferred independent Context Asset root and `context/**`
|
|
187
|
+
remains supported. Nested directory names never override a recognized root.
|
|
188
|
+
Files under canonical Skill `references/`, `profiles/`, `examples/`, `scripts/`,
|
|
189
|
+
and `assets/` directories are structurally Skill-local. Renma claims one parent
|
|
190
|
+
and possible inherited governance only after repository evidence resolves
|
|
191
|
+
exactly one Skill under `skills/**` or `.agents/skills/**`. Supported explicit
|
|
192
|
+
local metadata remains valid but is not required. See
|
|
193
|
+
[classification evidence](diagnostics.md#how-to-read-classification-evidence)
|
|
194
|
+
for the detailed contract.
|
|
195
|
+
|
|
196
|
+
Top-level `references/**` is not a Context root. `tools/**` contains shared
|
|
197
|
+
repository implementation, not Context knowledge, and `skills/**/tools/**` is
|
|
198
|
+
not a canonical local support directory. Skill-local executable support belongs
|
|
199
|
+
under `scripts/`.
|
|
200
|
+
|
|
201
|
+
```text
|
|
202
|
+
contexts/foo/references/policy.md
|
|
203
|
+
-> independent Context Asset
|
|
204
|
+
|
|
205
|
+
skills/foo/references/policy.md
|
|
206
|
+
-> Skill-local Reference
|
|
207
|
+
|
|
208
|
+
references/policy.md
|
|
209
|
+
-> outside the Context root
|
|
210
|
+
|
|
211
|
+
tools/helper.mjs
|
|
212
|
+
-> repository implementation
|
|
213
|
+
|
|
214
|
+
skills/foo/tools/helper.mjs
|
|
215
|
+
-> not canonical Skill-local support
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Placement as independent Context is a human decision about ownership,
|
|
219
|
+
lifecycle, reuse, and source of truth. Classification after placement is
|
|
220
|
+
deterministic. Renma never moves a file based on content. A successful
|
|
221
|
+
`no-proposal` result means no edit should be manufactured.
|
|
222
|
+
|
|
165
223
|
## User Story: Create A New Skill With Scaffold
|
|
166
224
|
|
|
167
225
|
Use this flow when adding a new agent-facing Skill. Platform-native guidance
|
|
@@ -640,7 +698,19 @@ renma inspect contexts/testing/boundary-value-analysis.md --format json
|
|
|
640
698
|
renma inspect skills/testing/spec-review/SKILL.md --lines L10-L42
|
|
641
699
|
```
|
|
642
700
|
|
|
643
|
-
Use this when editing one skill or context file and you want a deterministic outline without reading the whole repository catalog. Without `--lines`, output includes file size, line count, frontmatter range, headings, code fences, links, asset relationships, and a concise Context Lens governance summary when repository context can be inferred. Use `--lines <range>` for an exact source slice; ranges can look like `L10-L42` or `10-42`.
|
|
701
|
+
Use this when editing one skill or context file and you want a deterministic outline without reading the whole repository catalog. Without `--lines`, output includes file size, line count, frontmatter range, headings, code fences, links, asset relationships, and a concise Context Lens governance summary when repository context can be inferred. It also always includes `classification` with `kind`, `scope`, `matchedRule`, `reasonCode`, root or parent evidence, and concise competing rules. A Skill-local path exposes `parentAssetCandidatePath`; `parentAssetPath` appears only when `parentResolution` is `resolved`, while `missing` and `ambiguous` remain explicit fail-closed states. `governance` is separate and reports ownership, policy, and metadata provenance only from repository evidence. Unknown files and repository tools still receive classification. Use `--lines <range>` for an exact source slice; ranges can look like `L10-L42` or `10-42`. `--lines` output itself is unchanged.
|
|
702
|
+
|
|
703
|
+
JSON also includes `repositoryBoundary`. Resolved results record the root,
|
|
704
|
+
repository-relative path, and resolution source. Unresolved results retain a
|
|
705
|
+
stable reason code and `candidateRoots`; structural ambiguity uses
|
|
706
|
+
`repository-boundary-ambiguous` instead of selecting a broad ancestor.
|
|
707
|
+
|
|
708
|
+
For a file target, Renma resolves a repository root from an explicit caller root,
|
|
709
|
+
the nearest safe `.git` file/directory or Renma config marker, or an unambiguous
|
|
710
|
+
structural boundary, in that order. Current-working-directory containment alone
|
|
711
|
+
does not establish a repository. This keeps nested repositories and absolute
|
|
712
|
+
targets outside the current directory deterministic without scanning an
|
|
713
|
+
unrelated parent tree.
|
|
644
714
|
|
|
645
715
|
### `readiness`
|
|
646
716
|
|
|
@@ -763,7 +833,17 @@ workflow, constraints, and completion criteria with platform-native guidance;
|
|
|
763
833
|
apply only intended metadata or migration changes; run
|
|
764
834
|
`renma scan . --fail-on high`; fix relevant diagnostics; and rerun the scan.
|
|
765
835
|
Context Asset output does not receive this Skill-specific authoring guidance.
|
|
766
|
-
JSON
|
|
836
|
+
JSON adds `classification`, `decisionStatus`, structured `decision` evidence,
|
|
837
|
+
and safe `nextActions` to the existing suggestion fields. Each action has
|
|
838
|
+
`kind` and `invocation`; execute `invocation.command` with the exact
|
|
839
|
+
`invocation.args` array. `invocation.display` is for people and must not be
|
|
840
|
+
parsed as the machine contract, including on paths with spaces, quotes, or
|
|
841
|
+
Windows separators.
|
|
842
|
+
|
|
843
|
+
When no repository root resolves, `decisionStatus` is `blocked` and Renma does
|
|
844
|
+
not emit an executable `scan .` action. Establish the repository root with an
|
|
845
|
+
explicit root or repository marker before verification; the caller's current
|
|
846
|
+
directory is not assumed to contain the target.
|
|
767
847
|
|
|
768
848
|
For Skill targets using the pre-0.16 Renma Skill format, the 0.16.0 metadata
|
|
769
849
|
migration path is one-way: recognized governance and security frontmatter
|
|
@@ -771,6 +851,8 @@ becomes Agent Skills identity plus `metadata.renma.*`. Separately, `skill.md` an
|
|
|
771
851
|
report any required entrypoint rename or move, even when their frontmatter
|
|
772
852
|
already uses Agent Skills fields. For a canonical Agent Skill, `--owner` may
|
|
773
853
|
instead propose an owner metadata retrofit; it never causes reverse migration.
|
|
854
|
+
Skill migration `sourcePath` and `targetPath` values are repository-relative,
|
|
855
|
+
including when the user invokes Renma from the parent of a nested repository.
|
|
774
856
|
The normative behavior is documented in
|
|
775
857
|
[Agent Skills Compatibility and Migration](agent-skills-compatibility.md).
|
|
776
858
|
|
|
@@ -785,7 +867,35 @@ invalid evidence, confirm the Skill's intent with platform-native authoring
|
|
|
785
867
|
guidance, correct the source evidence, rerun `suggest-metadata`, then validate
|
|
786
868
|
intended corrections with `renma scan . --fail-on high`.
|
|
787
869
|
|
|
788
|
-
Owner metadata remains recommended but not required. Without `--owner`,
|
|
870
|
+
Owner metadata remains recommended but not required. Without `--owner`, Renma
|
|
871
|
+
does not invent an owner. With `--owner <owner>`, the command may include that
|
|
872
|
+
owner because it was explicitly provided. If an existing asset already
|
|
873
|
+
declares an owner, `suggest-metadata` preserves it; a different `--owner` value
|
|
874
|
+
is treated as conflicting evidence and blocks a candidate. Renma does not infer
|
|
875
|
+
owners from Git history, file paths, prose, or authors.
|
|
876
|
+
If the explicit owner equals the existing canonical `metadata.renma.owner`, the
|
|
877
|
+
result is `suggestedMode: "no-proposal"` with
|
|
878
|
+
`decisionStatus: "no-change-recommended"`; no candidate metadata, canonical
|
|
879
|
+
frontmatter, or patch instruction is emitted.
|
|
880
|
+
|
|
881
|
+
Ordinary Skill-local support returns `suggestedMode: "no-proposal"` and
|
|
882
|
+
`decisionStatus: "no-change-recommended"` when it can inherit governance from
|
|
883
|
+
one resolved parent Skill. Its `candidateMetadata` is empty. A missing or
|
|
884
|
+
ambiguous parent returns `decisionStatus: "blocked"`, leaves governance
|
|
885
|
+
unowned or unresolved, and provides a scan/layout action instead of claiming
|
|
886
|
+
inheritance. Existing explicit local owner or policy metadata is preserved
|
|
887
|
+
under `skill-local-existing-metadata-preserved`; an explicit `--owner` can still
|
|
888
|
+
request a supported intentional override after the parent resolves. Prompt and
|
|
889
|
+
JSON output both distinguish the observed path fact, deterministic
|
|
890
|
+
interpretation, recommendation, and remaining human decision. Repository tools
|
|
891
|
+
and unknown paths never receive fabricated Context metadata candidates.
|
|
892
|
+
|
|
893
|
+
`decisionStatus` is authoritative: `blocked` never authorizes a patch,
|
|
894
|
+
`no-change-recommended` stops without a patch, `human-confirmation-required`
|
|
895
|
+
identifies what must be confirmed before applying only the candidate fields,
|
|
896
|
+
and `deterministic` permits the reviewed candidate. Consumers should include a
|
|
897
|
+
conservative default for unknown future `suggestedMode` values rather than
|
|
898
|
+
assuming every non-`no-proposal` value is applicable.
|
|
789
899
|
|
|
790
900
|
### `suggest-semantic-split`
|
|
791
901
|
|
package/package.json
CHANGED
|
@@ -1,25 +1,53 @@
|
|
|
1
|
-
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
1
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
+
const temporaryRoot = await mkdtemp(
|
|
8
|
+
path.join(os.tmpdir(), "renma package verification-"),
|
|
9
|
+
);
|
|
10
|
+
const packDirectory = path.join(temporaryRoot, "packed artifact");
|
|
11
|
+
const consumerDirectory = path.join(temporaryRoot, "clean consumer");
|
|
12
|
+
const cacheDirectory = path.join(temporaryRoot, "npm cache");
|
|
7
13
|
|
|
8
14
|
try {
|
|
15
|
+
await mkdir(packDirectory, { recursive: true });
|
|
16
|
+
await mkdir(consumerDirectory, { recursive: true });
|
|
17
|
+
await mkdir(cacheDirectory, { recursive: true });
|
|
9
18
|
const packed = spawnSync(
|
|
10
19
|
"npm",
|
|
11
|
-
[
|
|
20
|
+
[
|
|
21
|
+
"pack",
|
|
22
|
+
"--json",
|
|
23
|
+
"--cache",
|
|
24
|
+
cacheDirectory,
|
|
25
|
+
"--pack-destination",
|
|
26
|
+
packDirectory,
|
|
27
|
+
],
|
|
12
28
|
{ cwd: process.cwd(), encoding: "utf8" },
|
|
13
29
|
);
|
|
14
|
-
if (packed.error)
|
|
30
|
+
if (packed.error) {
|
|
31
|
+
throw new Error(`npm pack failed: ${packed.error.message}`);
|
|
32
|
+
}
|
|
15
33
|
if (packed.status !== 0) {
|
|
16
|
-
throw new Error(
|
|
34
|
+
throw new Error(
|
|
35
|
+
`npm pack failed: ${packed.stderr.trim() || `exit code ${packed.status}`}`,
|
|
36
|
+
);
|
|
17
37
|
}
|
|
18
38
|
|
|
19
|
-
|
|
39
|
+
let reports;
|
|
40
|
+
try {
|
|
41
|
+
reports = JSON.parse(packed.stdout);
|
|
42
|
+
} catch {
|
|
43
|
+
throw new Error("npm pack failed: npm returned invalid JSON output.");
|
|
44
|
+
}
|
|
20
45
|
const report = reports[0];
|
|
21
46
|
if (!report || !Array.isArray(report.files)) {
|
|
22
|
-
throw new Error("npm pack
|
|
47
|
+
throw new Error("npm pack returned no package file list.");
|
|
48
|
+
}
|
|
49
|
+
if (typeof report.filename !== "string" || report.filename.length === 0) {
|
|
50
|
+
throw new Error("npm pack returned no tarball filename.");
|
|
23
51
|
}
|
|
24
52
|
const files = new Set(report.files.map((file) => file.path));
|
|
25
53
|
|
|
@@ -27,6 +55,17 @@ try {
|
|
|
27
55
|
"package.json",
|
|
28
56
|
"README.md",
|
|
29
57
|
"dist/index.js",
|
|
58
|
+
"dist/types.js",
|
|
59
|
+
"dist/types.d.ts",
|
|
60
|
+
"dist/discovery.js",
|
|
61
|
+
"dist/discovery.d.ts",
|
|
62
|
+
"dist/commands/inspect.js",
|
|
63
|
+
"dist/commands/inspect.d.ts",
|
|
64
|
+
"dist/commands/suggest-metadata.js",
|
|
65
|
+
"dist/commands/suggest-metadata.d.ts",
|
|
66
|
+
"dist/skill-migration.js",
|
|
67
|
+
"dist/skill-migration.d.ts",
|
|
68
|
+
"docs/internal-architecture.md",
|
|
30
69
|
"docs/trust-graph.md",
|
|
31
70
|
"docs/schemas/repository-context-bom-v2.schema.json",
|
|
32
71
|
"docs/schemas/trust-graph-v2.schema.json",
|
|
@@ -62,11 +101,117 @@ try {
|
|
|
62
101
|
}
|
|
63
102
|
}
|
|
64
103
|
|
|
104
|
+
const tarballPath = path.resolve(packDirectory, report.filename);
|
|
105
|
+
const packageRoot = await installInTemporaryConsumer(
|
|
106
|
+
consumerDirectory,
|
|
107
|
+
tarballPath,
|
|
108
|
+
cacheDirectory,
|
|
109
|
+
);
|
|
110
|
+
await verifyInspectDeclarationCompatibility(packageRoot);
|
|
111
|
+
for (const modulePath of [
|
|
112
|
+
"dist/commands/inspect.js",
|
|
113
|
+
"dist/commands/suggest-metadata.js",
|
|
114
|
+
"dist/discovery.js",
|
|
115
|
+
"dist/skill-migration.js",
|
|
116
|
+
]) {
|
|
117
|
+
try {
|
|
118
|
+
await import(pathToFileURL(path.join(packageRoot, modulePath)).href);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`Deep import failed for ${modulePath}: ${errorMessage(error)}`,
|
|
122
|
+
{ cause: error },
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
65
127
|
process.stdout.write(
|
|
66
|
-
`Verified ${files.size} packaged files and every README-relative target.\n`,
|
|
128
|
+
`Verified ${files.size} packaged files, deep imports, inspect declarations, and every README-relative target.\n`,
|
|
67
129
|
);
|
|
68
130
|
} finally {
|
|
69
|
-
await rm(
|
|
131
|
+
await rm(temporaryRoot, { recursive: true, force: true });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function installInTemporaryConsumer(
|
|
135
|
+
consumerDirectory,
|
|
136
|
+
tarballPath,
|
|
137
|
+
cacheDirectory,
|
|
138
|
+
) {
|
|
139
|
+
await writeFile(
|
|
140
|
+
path.join(consumerDirectory, "package.json"),
|
|
141
|
+
`${JSON.stringify(
|
|
142
|
+
{
|
|
143
|
+
name: "renma-package-verification",
|
|
144
|
+
private: true,
|
|
145
|
+
type: "module",
|
|
146
|
+
},
|
|
147
|
+
null,
|
|
148
|
+
2,
|
|
149
|
+
)}\n`,
|
|
150
|
+
);
|
|
151
|
+
const installed = spawnSync(
|
|
152
|
+
"npm",
|
|
153
|
+
[
|
|
154
|
+
"install",
|
|
155
|
+
"--ignore-scripts",
|
|
156
|
+
"--no-audit",
|
|
157
|
+
"--no-fund",
|
|
158
|
+
"--package-lock=false",
|
|
159
|
+
"--cache",
|
|
160
|
+
cacheDirectory,
|
|
161
|
+
tarballPath,
|
|
162
|
+
],
|
|
163
|
+
{ cwd: consumerDirectory, encoding: "utf8" },
|
|
164
|
+
);
|
|
165
|
+
if (installed.error) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
`Temporary consumer installation failed: ${installed.error.message}`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
if (installed.status !== 0) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
`Temporary consumer installation failed: ${installed.stderr.trim() || `npm exited with code ${installed.status}`}`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
const packageRoot = path.join(consumerDirectory, "node_modules", "renma");
|
|
176
|
+
try {
|
|
177
|
+
await readFile(path.join(packageRoot, "package.json"), "utf8");
|
|
178
|
+
} catch (error) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
`Temporary consumer installation failed: installed renma package is missing (${errorMessage(error)}).`,
|
|
181
|
+
{ cause: error },
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return packageRoot;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function verifyInspectDeclarationCompatibility(packageRoot) {
|
|
188
|
+
const declarations = await readFile(
|
|
189
|
+
path.join(packageRoot, "dist/commands/inspect.d.ts"),
|
|
190
|
+
"utf8",
|
|
191
|
+
);
|
|
192
|
+
for (const typeName of [
|
|
193
|
+
"InspectOutline",
|
|
194
|
+
"InspectAssetSummary",
|
|
195
|
+
"InspectRelationship",
|
|
196
|
+
"InspectRelationshipChain",
|
|
197
|
+
"InspectSlice",
|
|
198
|
+
]) {
|
|
199
|
+
const declared = new RegExp(
|
|
200
|
+
`export\\s+(?:interface|type)\\s+${typeName}\\b`,
|
|
201
|
+
).test(declarations);
|
|
202
|
+
const reexported = new RegExp(
|
|
203
|
+
`export\\s+type\\s*\\{[\\s\\S]*?\\b${typeName}\\b[\\s\\S]*?\\}\\s*from`,
|
|
204
|
+
).test(declarations);
|
|
205
|
+
if (!declared && !reexported) {
|
|
206
|
+
throw new Error(
|
|
207
|
+
`dist/commands/inspect.d.ts no longer exports ${typeName}.`,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function errorMessage(error) {
|
|
214
|
+
return error instanceof Error ? error.message : String(error);
|
|
70
215
|
}
|
|
71
216
|
|
|
72
217
|
function requirePackagedPath(files, target) {
|