feat: onboarding the agents#161
Conversation
…umer app can use those to learn about library more efficient
b30bf2e to
efb2570
Compare
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Consumers wire their AI agent to orio-ui by running `npx orio-ui agents`
(or pasting the 4-line snippet) — it appends a pointer to the shipped
dist/agents/ROUTING.md into their CLAUDE.md.
- add orio-ui bin: idempotent `agents` command, creates/appends CLAUDE.md
- single source of truth for all generated agent artifacts:
- routing renderers shared in scripts/lib/render-routing.mjs
- agent bodies in scripts/templates/bodies/ render both .claude/agents/
(repo paths) and dist/agents/ (consumer paths) via variant blocks
- onboarding snippet in scripts/templates/consumer-snippet.md, injected
into README and ROUTING.md at build
- fix marker semantics: every entry ships a USAGE.md; the marker now reads
"Read USAGE.md first" and flags non-trivial invariants only
- models: component-worker inherits the session model, component-finder
pins haiku — consistent in repo and dist
Co-Authored-By: Claude Fable 5 <[email protected]>
Adds a repo-only usage-auditor subagent (read-only, sonnet) plus a PostToolUse hook that fires whenever a component/composable source file under src/runtime/ is created or edited, instructing the session to dispatch the auditor against the related USAGE.md and apply reported fixes. Not shipped to consumers (npm packs only bin + dist). .claude/settings.json is now tracked so the hook ships with the repo. Co-Authored-By: Claude Fable 5 <[email protected]>
update-counts.mjs searched for "N unit tests" but the README text says "N test suites", so the count was frozen at 29. Pattern fixed; counts refreshed to the current 36 suites (README + docs/index.md). Co-Authored-By: Claude Fable 5 <[email protected]>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (13)
📝 Walkthroughfeat: onboarding the agents
WalkthroughAdds a generation pipeline and templates to build agent routing/onboarding artifacts, a consumer CLI, hook-driven usage-audit dispatch, and many new/updated USAGE.md docs for components and composables. ChangesAgent Documentation & Routing Generation
Estimated code review effort 🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 13
🧹 Nitpick comments (1)
tests/scripts/render-template.spec.ts (1)
5-66: ⚡ Quick winAdd a CRLF fixture test for block markers
Please add one regression case using
\r\n-joined templates to lock in cross-platform block parsing behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/scripts/render-template.spec.ts` around lines 5 - 66, Add a regression test to tests/scripts/render-template.spec.ts that verifies renderTemplate correctly handles CRLF line endings for variant block markers: create a new it("handles CRLF block markers", ...) which builds a template using ["shared line", "{{`#repo`}}", "repo-only line", "{{/repo}}", "tail line"].join("\r\n") and asserts that renderTemplate(template, { variant: "repo", vars: {} }) returns "shared line\nrepo-only line\ntail line" (or otherwise normalized lines as existing tests expect); this ensures the renderTemplate function correctly parses {{#...}} / {{/...}} blocks when input uses "\r\n".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.claude/agents/component-worker.md:
- Around line 19-21: The routing marker in .claude/agents/component-worker.md
must be produced by the generator with the exact text "**Read USAGE.md first.**"
(not "(read USAGE.md first)"); update the template/rendering in
scripts/generate-routing.mjs (or the template that it uses) so it emits the
exact required marker string for all generated routing blocks (including the
ranges noted 37-103) and regenerate the routing files—do not hand-edit
.claude/agents/component-worker.md directly.
In @.claude/agents/usage-auditor.md:
- Around line 47-54: The fenced code block in .claude/agents/usage-auditor.md
(the block showing "Component: <path to source> ... Findings:") is missing a
language identifier and triggers MD040; update that fence to include a language
(e.g., "text") so it starts with ```text rather than ```, ensuring the block
remains otherwise unchanged and linting passes.
In `@package.json`:
- Line 35: Replace the npm lifecycle script that installs git hooks from
postinstall to a contributor-facing hook to avoid running on consumer installs:
update the package.json scripts entry that currently reads "postinstall":
"simple-git-hooks" so it instead uses "prepare": "simple-git-hooks" (or remove
the script and add documentation for contributor-only setup), ensuring
references to simple-git-hooks are only executed during local
development/prepublish rather than on dependency installation.
In `@scripts/emit-consumer-agents.mjs`:
- Around line 96-101: The script currently checks DIST_RUNTIME with existsSync
and calls process.exit(0) on missing artifacts which masks failure; update the
branch in emit-consumer-agents.mjs so that when existsSync(DIST_RUNTIME) is
false you log an error (use console.error or processLogger/error equivalent) and
call process.exit(1) instead of process.exit(0) so CI and downstream callers
detect the missing build artifact; reference the existsSync(DIST_RUNTIME) check
and the process.exit call to locate and change the behavior.
- Line 86: The current replace call on ROOTS[entry.kind] assumes the value
starts with "src/" which is fragile; update the logic around targetRoot in
scripts/emit-consumer-agents.mjs so it only performs .replace(/^src\//, "dist/")
when ROOTS[entry.kind] is a string that starts with "src/", otherwise fall back
to a safe default (e.g., prepend "dist/" or use the original value) to avoid
producing incorrect paths; reference the targetRoot assignment, ROOTS, and
entry.kind to locate and update the code.
In `@scripts/lib/load-entries.mjs`:
- Around line 19-20: The frontmatter regex in the content.match call only
accepts LF (`\n`) delimiters so CRLF files are skipped; update the regex used
where content.match(...) is called (the frontmatter parsing in parseFrontmatter
/ the match variable) to accept optional CR before newlines (use `\r?\n` for the
opening, capture group boundary, and closing delimiter) so `---\r\n... \r\n---`
is correctly detected; keep the same capture group and null-return behavior if
no frontmatter is found.
In `@scripts/lib/render-routing.mjs`:
- Around line 45-47: The fenceMarkdown function currently uses a fixed
triple-backtick fence which breaks if snippet contains ```; update fenceMarkdown
to emit a safer fence by computing the longest run of backticks inside snippet
and using a fence one backtick longer (or at minimum use a 4-backtick fence,
e.g. ````md ... ````) so nested triple-backtick blocks won’t close the outer
fence; locate and modify the fenceMarkdown function to implement this change.
In `@scripts/lib/render-template.mjs`:
- Around line 22-24: The block RegExp that strips variant blocks (created as
`new RegExp(..., "gm")` using the `blockVariant` template) only matches LF
(`\n`) line endings; update the pattern to accept optional CR before newline by
replacing each `\\n` in the template literal with `\\r?\\n` so both LF and CRLF
templates (`{{`#repo`}}...{{/repo}}`, `{{`#consumer`}}...{{/consumer}}`) are matched
and removed correctly while leaving flags (`"gm"`) unchanged.
In `@src/runtime/components/Button.USAGE.md`:
- Line 51: Fix the mismatched bold markers in the sentence containing "Loading
hides the icon and the icon-right slot." by replacing the stray four asterisks
around the first "Loading" with a proper pair so the bold formatting is balanced
(i.e., ensure the whole phrase you intend bolding is wrapped in exactly two
asterisks on each side); update the text near the phrase "Loading hides the icon
**and** the icon-right slot." and verify the closing bold marker remains
present.
In `@src/runtime/components/gallery/CarouselPreview.USAGE.md`:
- Line 6: The frontmatter key "invariants: false" in CarouselPreview.USAGE.md
may be incorrect given several non-trivial behaviors (ARIA state management via
aria-pressed, differing default fit value "cover" vs parent Carousel "contain",
lack of auto-scroll on external active-image changes, and specific
opacity/styling rules); review each behavior and either (a) if they are indeed
invariant guarantees of CarouselPreview, set invariants: true in the frontmatter
so the routing index marks "Read USAGE.md first" and ensure the USAGE text
explicitly lists those invariants (mentioning aria-pressed behavior, default
fit="cover", auto-scroll not triggered by external active-image changes, and
opacity/styling rules), or (b) if any are not strict invariants, update the
documentation to clarify they are implementation details/optional and keep
invariants: false — make the decision and update the frontmatter and
corresponding text accordingly.
In `@src/runtime/components/Selector.USAGE.md`:
- Around line 28-30: Update the wording in Selector.USAGE.md to correctly
describe the readonly v-model failure mode: replace the phrase that says
mutating a readonly v-model will "throw silently in dev or warn in prod" with a
statement that Selector.vue mutates the bound multi-select array in place via
modelValue.value.splice(...) / modelValue.value.push(...), and when the bound
v-model is a deep readonly value Vue blocks those mutations — logging a warning
in dev (e.g., "Set operation on key … failed: target is readonly") and
suppressing the warning in production (silent failure), so selection won’t
update; remove the incorrect "throw silently" claim and use the exact “warn in
dev / silent in prod” wording.
In `@src/runtime/composables/useApi.USAGE.md`:
- Around line 1-7: The frontmatter flag `invariants: false` contradicts the
presence of a "## Invariants" section; update the frontmatter to `invariants:
true` so it accurately reflects the document content (look for the YAML block at
top of src/runtime/composables/useApi.USAGE.md and change the `invariants`
value), ensuring consistency between the frontmatter and the "## Invariants"
section.
In `@src/runtime/composables/useFuzzySearch.USAGE.md`:
- Around line 1-7: Update the frontmatter key "invariants" in the document to
match the presence of the "## Invariants" section: change invariants: false to
invariants: true so the metadata reflects documented invariants; ensure the "##
Invariants" heading remains accurate and consistent with that frontmatter
change.
---
Nitpick comments:
In `@tests/scripts/render-template.spec.ts`:
- Around line 5-66: Add a regression test to
tests/scripts/render-template.spec.ts that verifies renderTemplate correctly
handles CRLF line endings for variant block markers: create a new it("handles
CRLF block markers", ...) which builds a template using ["shared line",
"{{`#repo`}}", "repo-only line", "{{/repo}}", "tail line"].join("\r\n") and
asserts that renderTemplate(template, { variant: "repo", vars: {} }) returns
"shared line\nrepo-only line\ntail line" (or otherwise normalized lines as
existing tests expect); this ensures the renderTemplate function correctly
parses {{#...}} / {{/...}} blocks when input uses "\r\n".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6d8aadfe-26f5-46a2-a829-c4957dc23a73
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (79)
.claude/agents/component-finder.md.claude/agents/component-worker.md.claude/agents/usage-auditor.md.claude/settings.json.gitignoreCLAUDE.mdREADME.mdbin/orio-ui.mjsdocs/index.mdpackage.jsonscripts/emit-consumer-agents.mjsscripts/generate-routing.mjsscripts/hooks/usage-audit-reminder.mjsscripts/lib/load-entries.mjsscripts/lib/render-routing.mjsscripts/lib/render-template.mjsscripts/templates/bodies/component-finder.mdscripts/templates/bodies/component-worker.mdscripts/templates/consumer-routing.mdscripts/templates/consumer-snippet.mdscripts/update-counts.mjssrc/runtime/components/AnimatedContainer.USAGE.mdsrc/runtime/components/Badge.USAGE.mdsrc/runtime/components/Banner.USAGE.mdsrc/runtime/components/Button.USAGE.mdsrc/runtime/components/Calendar.USAGE.mdsrc/runtime/components/Canvas/USAGE.mdsrc/runtime/components/CheckBox.USAGE.mdsrc/runtime/components/CheckboxGroup.USAGE.mdsrc/runtime/components/ControlElement.USAGE.mdsrc/runtime/components/DashedContainer.USAGE.mdsrc/runtime/components/EmptyState.USAGE.mdsrc/runtime/components/Form.USAGE.mdsrc/runtime/components/Icon.USAGE.mdsrc/runtime/components/Input.USAGE.mdsrc/runtime/components/ListItem.USAGE.mdsrc/runtime/components/LoadingSpinner.USAGE.mdsrc/runtime/components/LocaleSwitcher.USAGE.mdsrc/runtime/components/Modal.USAGE.mdsrc/runtime/components/NavButton.USAGE.mdsrc/runtime/components/NumberInput/Horizontal.USAGE.mdsrc/runtime/components/NumberInput/USAGE.mdsrc/runtime/components/NumberInput/Vertical.USAGE.mdsrc/runtime/components/Popover.USAGE.mdsrc/runtime/components/RadioButton.USAGE.mdsrc/runtime/components/Selector.USAGE.mdsrc/runtime/components/SwitchButton.USAGE.mdsrc/runtime/components/Tag.USAGE.mdsrc/runtime/components/TaggableSelector.USAGE.mdsrc/runtime/components/Textarea.USAGE.mdsrc/runtime/components/Tooltip.USAGE.mdsrc/runtime/components/ZoomableContainer.USAGE.mdsrc/runtime/components/date/Picker.USAGE.mdsrc/runtime/components/date/PickerTrigger.USAGE.mdsrc/runtime/components/date/RangePicker.USAGE.mdsrc/runtime/components/gallery/Carousel.USAGE.mdsrc/runtime/components/gallery/CarouselPreview.USAGE.mdsrc/runtime/components/upload/USAGE.mdsrc/runtime/components/view/Dates.USAGE.mdsrc/runtime/components/view/KeyBinds.USAGE.mdsrc/runtime/components/view/Separator.USAGE.mdsrc/runtime/components/view/Text.USAGE.mdsrc/runtime/composables/useApi.USAGE.mdsrc/runtime/composables/useControlSize.USAGE.mdsrc/runtime/composables/useDecimalFormatter.USAGE.mdsrc/runtime/composables/useFilter.USAGE.mdsrc/runtime/composables/useFuzzySearch.USAGE.mdsrc/runtime/composables/useInertia.USAGE.mdsrc/runtime/composables/useListKeyboard.USAGE.mdsrc/runtime/composables/useModal.USAGE.mdsrc/runtime/composables/usePinchZoom.USAGE.mdsrc/runtime/composables/usePressAndHold.USAGE.mdsrc/runtime/composables/useRovingGrid.USAGE.mdsrc/runtime/composables/useSound.USAGE.mdsrc/runtime/composables/useTheme.USAGE.mdsrc/runtime/composables/useUrlSync.USAGE.mdsrc/runtime/composables/useValidation.USAGE.mdtests/scripts/orio-ui-bin.spec.tstests/scripts/render-template.spec.ts
| Match the user's request to one component here. Every entry ships a USAGE.md | ||
| file; the `(read USAGE.md first)` marker means it documents non-trivial | ||
| invariants/gotchas you **must read before writing integration code**. |
There was a problem hiding this comment.
Routing marker text does not match the required invariant marker contract.
The routing index uses (read USAGE.md first) but the required marker is **Read USAGE.md first.**. Because this file is generated, fix the marker emission in the template/rendering pipeline (not by editing this block directly).
As per coding guidelines, non-trivial invariants/gotchas in USAGE routes must be marked with the exact **Read USAGE.md first.** text in the routing index. Based on learnings, routing blocks should be generated via scripts/generate-routing.mjs, not hand-edited.
Also applies to: 37-103
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/agents/component-worker.md around lines 19 - 21, The routing marker
in .claude/agents/component-worker.md must be produced by the generator with the
exact text "**Read USAGE.md first.**" (not "(read USAGE.md first)"); update the
template/rendering in scripts/generate-routing.mjs (or the template that it
uses) so it emits the exact required marker string for all generated routing
blocks (including the ranges noted 37-103) and regenerate the routing files—do
not hand-edit .claude/agents/component-worker.md directly.
Sources: Coding guidelines, Learnings
| function copyUsageFiles(entries) { | ||
| let copied = 0; | ||
| entries.forEach((entry) => { | ||
| const targetRoot = ROOTS[entry.kind].replace(/^src\//, "dist/"); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check ROOTS definition and verify src/ prefix assumption
ast-grep --pattern 'export const ROOTS = { $$$ }'Repository: oriondor/orio-ui
Length of output: 296
Path replacement matches the current ROOTS contract.
scripts/lib/load-entries.mjs defines ROOTS.component = "src/runtime/components/" and ROOTS.composable = "src/runtime/composables/", which both start with "src/", so ROOTS[entry.kind].replace(/^src\//, "dist/") produces the expected dist/runtime/... paths under the current definition.
🛡️ Proposed guard (optional)
function copyUsageFiles(entries) {
let copied = 0;
entries.forEach((entry) => {
const targetRoot = ROOTS[entry.kind].replace(/^src\//, "dist/");
+ if (!targetRoot.startsWith("dist/")) {
+ throw new Error(
+ `Expected ROOTS[${entry.kind}] to start with "src/", got: ${ROOTS[entry.kind]}`
+ );
+ }
const out = join(targetRoot, entry.usagePath);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const targetRoot = ROOTS[entry.kind].replace(/^src\//, "dist/"); | |
| function copyUsageFiles(entries) { | |
| let copied = 0; | |
| entries.forEach((entry) => { | |
| const targetRoot = ROOTS[entry.kind].replace(/^src\//, "dist/"); | |
| if (!targetRoot.startsWith("dist/")) { | |
| throw new Error( | |
| `Expected ROOTS[${entry.kind}] to start with "src/", got: ${ROOTS[entry.kind]}` | |
| ); | |
| } | |
| const out = join(targetRoot, entry.usagePath); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/emit-consumer-agents.mjs` at line 86, The current replace call on
ROOTS[entry.kind] assumes the value starts with "src/" which is fragile; update
the logic around targetRoot in scripts/emit-consumer-agents.mjs so it only
performs .replace(/^src\//, "dist/") when ROOTS[entry.kind] is a string that
starts with "src/", otherwise fall back to a safe default (e.g., prepend "dist/"
or use the original value) to avoid producing incorrect paths; reference the
targetRoot assignment, ROOTS, and entry.kind to locate and update the code.
| --- | ||
| kind: composable | ||
| category: Composables | ||
| purpose: fetch, API client, HTTP request, JSON fetch | ||
| short: thin typed wrapper around ofetch's `$fetch` for GET/POST/PUT/DELETE/PATCH requests | ||
| invariants: false | ||
| --- |
There was a problem hiding this comment.
Frontmatter invariants: false contradicts the content.
The frontmatter declares invariants: false but the document includes a detailed "## Invariants" section (line 15). If this flag signals whether invariants exist or are non-trivial, it should be true.
📝 Proposed fix
---
kind: composable
category: Composables
purpose: fetch, API client, HTTP request, JSON fetch
short: thin typed wrapper around ofetch's `$fetch` for GET/POST/PUT/DELETE/PATCH requests
-invariants: false
+invariants: true
---📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| --- | |
| kind: composable | |
| category: Composables | |
| purpose: fetch, API client, HTTP request, JSON fetch | |
| short: thin typed wrapper around ofetch's `$fetch` for GET/POST/PUT/DELETE/PATCH requests | |
| invariants: false | |
| --- | |
| --- | |
| kind: composable | |
| category: Composables | |
| purpose: fetch, API client, HTTP request, JSON fetch | |
| short: thin typed wrapper around ofetch's `$fetch` for GET/POST/PUT/DELETE/PATCH requests | |
| invariants: true | |
| --- |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/runtime/composables/useApi.USAGE.md` around lines 1 - 7, The frontmatter
flag `invariants: false` contradicts the presence of a "## Invariants" section;
update the frontmatter to `invariants: true` so it accurately reflects the
document content (look for the YAML block at top of
src/runtime/composables/useApi.USAGE.md and change the `invariants` value),
ensuring consistency between the frontmatter and the "## Invariants" section.
| --- | ||
| kind: composable | ||
| category: Composables | ||
| purpose: fuzzy search, client-side filter, in-memory search, search-as-you-type | ||
| short: typed Fuse.js wrapper that returns a computed list of matched items (strings or objects) | ||
| invariants: false | ||
| --- |
There was a problem hiding this comment.
Frontmatter invariants: false contradicts the content.
The frontmatter declares invariants: false but the document includes an "## Invariants" section (line 16). If this flag signals whether invariants exist or are documented, it should be true.
📝 Proposed fix
---
kind: composable
category: Composables
purpose: fuzzy search, client-side filter, in-memory search, search-as-you-type
short: typed Fuse.js wrapper that returns a computed list of matched items (strings or objects)
-invariants: false
+invariants: true
---📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| --- | |
| kind: composable | |
| category: Composables | |
| purpose: fuzzy search, client-side filter, in-memory search, search-as-you-type | |
| short: typed Fuse.js wrapper that returns a computed list of matched items (strings or objects) | |
| invariants: false | |
| --- | |
| --- | |
| kind: composable | |
| category: Composables | |
| purpose: fuzzy search, client-side filter, in-memory search, search-as-you-type | |
| short: typed Fuse.js wrapper that returns a computed list of matched items (strings or objects) | |
| invariants: true | |
| --- |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/runtime/composables/useFuzzySearch.USAGE.md` around lines 1 - 7, Update
the frontmatter key "invariants" in the document to match the presence of the
"## Invariants" section: change invariants: false to invariants: true so the
metadata reflects documented invariants; ensure the "## Invariants" heading
remains accurate and consistent with that frontmatter change.
🤖 I have created a release *beep* *boop* --- ## [1.28.0](v1.27.0...v1.28.0) (2026-06-13) ### Features * onboarding the agents ([#161](#161)) ([f5b1bae](f5b1bae)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Adds a generation pipeline and templates to build agent routing/onboarding artifacts, a consumer CLI, hook-driven usage-audit dispatch, and many new/updated USAGE.md docs for components and composables.