Skip to content
This repository was archived by the owner on Aug 4, 2026. It is now read-only.

Latest commit

 

History

History
128 lines (87 loc) · 8.28 KB

File metadata and controls

128 lines (87 loc) · 8.28 KB

Contributing

How to add a skill, the conventions every skill follows, and how to refresh a skill after the docs change.

Repo layout

skills/
└── avo-fields/
    ├── SKILL.md
    └── scripts/        # optional — only if the skill runs one

Each skill lives in skills/{slug}/SKILL.md. Add a skill by creating that directory, then add a row to the table in README.md.

Skill conventions

Organize by vertical, not by task

A skill covers a whole feature area — creating, configuring, and troubleshooting its slice of Avo. avo-fields covers every "add/change a field" job; there is no separate "add a select field" skill. Task-shaped skills multiply fast and collide with each other on triggering.

Frontmatter

---
name: avo-fields
description: <one sentence on what it does, then "Use when the user wants to …">
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch
metadata:
  requires-gem: none — Community
---

metadata.requires-gem is required — it marks which paid gem (if any) the user's app needs for this skill's feature. none — Community when the free avo gem covers everything; otherwise the exact gem name(s) plus a short qualifier, e.g. avo-custom_controls — paid add-on or avo-advanced_search — only for searchable associations; the rest is Community. Gem names come from avohq.io/gems; add-on-to-bundle mapping is on avohq.io/pricing. The body must also name the gem in its license line so the agent surfaces it to the user (frontmatter isn't loaded into context when the skill runs).

The description is the trigger — it's the whole ballgame. It must carry both:

  • Explicit phrasings that name Avo: "add a field to the Avo resource", "set format_using".
  • Implicit phrasings a developer actually uses, which never name Avo: "add a status field to the Project model", "make the email field required", "let admins bulk-approve these orders".

A skill that only lists Avo vocabulary won't fire on a real request, because real requests are phrased in Rails and product terms. Be generous and concrete here.

One exception: avo-aware is the only skill allowed to trigger on requests that never mention Avo at all. It's a dispatcher — it notices a Rails change has an admin dimension, asks, then routes to the right vertical skill. Every other skill's description stays Avo-anchored so they don't all fire at once on "add a column to Project".

Body structure

Follow this order — it's what avo-menu-icons and all the vertical skills use:

  1. # Title + a short orientation paragraph — the mental model, and which file(s) the developer edits (e.g. def fields in app/avo/resources/<model>.rb).
  2. A Docs line — see below.
  3. ## When this applies — explicit and implicit triggers, plus what's explicitly not this skill.
  4. ## Workflow — ordered steps with real DSL and the generator commands.
  5. ## Key options / patterns — the common options with small examples.
  6. ## Gotchas — the footguns, as a checklist.
  7. ## Report — what to tell the user when done.

Add-on skills also get an ## Install section (gem, generator, migration) near the top.

Rules

  • Link the docs, don't inline them. Anchor on https://docs.avohq.io/4.0/docs-map.md, then link the specific pages the skill needs and instruct the agent to fetch them on demand. Inline only the common-path DSL and the gotchas. This is Avo's house style and it keeps skills from going stale on every doc edit.

  • Use raw-markdown doc URLs: https://docs.avohq.io/4.0/<page>.md. Both .md and .html resolve, but .md gives an agent clean markdown instead of a rendered page.

  • State the license whenever it isn't plain Community — paid add-on or Enterprise — and name any companion gem the feature needs (e.g. :money needs avo-money_field + money-rails; :location needs mapkick-rb, not mapkick). Emitting DSL for a gem the app doesn't have is the most common way a generated resource breaks.

  • Cross-link sibling skills instead of duplicating them. If a topic is owned by another skill, point at it.

  • Verify against the source, not memory. Check the DSL against the docs and the gem source before writing. Option names changed a lot in v4.

  • Never paste VitePress artifacts. Doc snippets contain [!code ++] / [!code highlight] markers, :::info / :::warning / :::code-group containers, and components like <Option>, <Image>, <FieldTypesList/>. Strip all of it — it renders as noise in a skill. Quick check before committing:

    grep -rnE "\[!code|:::|<Option|<Image|<CustomCode|<FieldTypesList" skills/

Where a skill came from

The Docs line is the provenance record. Every skill lists the pages it was built from, so you can always recover its sources. To list them for every skill:

for d in skills/*/; do
  printf "%-26s %s\n" "$(basename "$d")" \
    "$(grep -ohE 'docs\.avohq\.io/4\.0/[A-Za-z0-9_/-]+\.md' "$d/SKILL.md" \
       | sed 's#docs.avohq.io/4.0/##' | sort -u | grep -v '^docs-map.md$' | tr '\n' ' ')"
done

Note this lists both the pages a skill was generated from and the ones it merely cross-links. Shared pages like authorization.md show up under many skills; a change there doesn't necessarily mean all of them need work.

Regenerating a skill after the docs change

You don't need the original authoring prompt. The curation — triggers, gotchas, cross-links, license flags — already lives in the SKILL.md. So a refresh is a diff, not a rewrite, which also means it preserves any hand edits made since.

The procedure:

  1. Find the sources for the skill with the snippet above.
  2. Fetch the current pages (https://docs.avohq.io/4.0/<page>.md) — or read them from a local docs checkout.
  3. Compare against the skill — has any DSL, option name, default, generator flag, license, or gotcha drifted? Has a new option appeared that belongs in ## Key options?
  4. Edit in place. Preserve the structure, the section order, and the voice. Only change what actually drifted — a docs rewording with no API change usually needs no edit at all.
  5. Re-run the VitePress-artifact check above, since new snippets get pasted in during a refresh.
  6. Sanity-check the description — if the feature gained a capability, the trigger list probably needs a new phrase.

This works today with no tooling: point an agent at the skill and its source pages and ask it to reconcile the two.

Finding what changed since the last index

docs-index.json records the docs commit these skills were last generated from. The docs repo already hashes every page, so its git history is the lock file — we only have to remember one commit.

ruby bin/docs_drift.rb                        # finds a docs checkout near this repo
ruby bin/docs_drift.rb ~/code/docs.avohq.io   # or point it at one (also: AVO_DOCS_PATH)

It looks for a git checkout containing docs/4.0 next to or above the skills repo, so it works from whatever layout you (or a CI runner) happen to use. Ruby only — no gems.

It prints every page added/modified/deleted under docs/4.0 since that commit, the skills citing each one, and the git log command for the actual commits. Then work the refresh procedure above on the listed skills and record the new baseline:

bin/docs_drift.rb --update

Commit docs-index.json together with the skill edits, so the marker always means "the skills in this commit reflect the docs at that commit".

Two caveats. Citations come from the Docs lines, which mix generated-from with cross-linked pages — a change to authorization.md flags eleven skills and usually means nothing for most of them. And a change is "someone should look", not "must regenerate": typo-fix commits show up too, and step 4 above will often correctly conclude nothing needs editing.

If we want more later: a sources: frontmatter key to separate generated-from pages from cross-links, and CI running this on a schedule or on a repository_dispatch from the docs repo at release.

Skill references