Agent skill

Qv Docs Update

by tetherto in tetherto/qvac

Updates the docs website after a change to the SDK or CLI. An agent skill from tetherto/qvac.

Apache-2.0Auto-check passedAI & LLM Engineering

Install Qv Docs Update

skills CLI
$ npx skills add tetherto/qvac --skill qv-docs-update -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install tetherto/qvac qv-docs-update --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/tetherto/qvac.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/qv-docs-update .claude/skills/qv-docs-update && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
qv-docs-update
GitHub stars
681
Token cost
~11k tokens
SKILL.md length
4,983 words
Files
10 (incl. scripts, references)
Skills in repo
50
Repo updated
First seen
Licence
Apache-2.0

At a glance

Updates the docs website after a change to the SDK or CLI. An agent skill from tetherto/qvac.

  • Works in 6 steps: Collect the source change → Build SOURCE_CHANGE_SET → Build DOCS_IMPACT → …
  • Invoking /qv-docs-update
  • SKILL.md covers What this skill reads and writes, Pipeline objects, States and Decision flow, plus 11 more sections
  • Runs TypeScript and Shell scripts from its folder; calls git, bun and bash

What it does

Qv Docs Update is an agent skill from tetherto/qvac. Updates the docs website after a change to the SDK or CLI. Finds the pages your change made out of date and proposes the smallest edit that fixes them. Use when invoking /qv-docs-update.

Its SKILL.md is about 11k tokens, which your agent loads only when the skill is triggered. The skill folder holds 12 other files, including scripts and reference files (for example `agents/openai.yaml`, `references/docs-impact-policy.md` and `references/docs-scope.md`).

It sits in AI & LLM Engineering. The repository describes itself as: Open-source local AI SDK - run AI on-device with no cloud, no API keys. Supports GGUF, RAG, image, music, and video generation, speech-to-text, P2P inference, and more… The licence is Apache-2.0.

When your agent uses it

  • Invoking /qv-docs-update

Example prompts

  • “Use the qv-docs-update skill to update the docs website after a change to the SDK or CLI. An agent skill from tetherto/qvac”
  • “/qv-docs-update”

Requirements

  • Node.js
  • A Bash shell

Workflow steps

6 steps, taken from the step headings in SKILL.md.

  1. Collect the source change
  2. Build SOURCE_CHANGE_SET
  3. Build DOCS_IMPACT
  4. Route to DOCS_TARGETS
  5. Write and apply DOCS_PATCH
  6. Validate

What it can do on your machine

Read from SKILL.md and the folder at commit c3a6030. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships 3 files in scripts/ (TypeScript and Shell), which the agent can run.

    Shell commands in SKILL.md call:

    • git
    • bun
    • bash
    • gh

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use git and gh, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Qv Docs Update loads about 11k tokens when it runs, and up to ~20k if it reads all its reference files. Until then it costs about 50 tokens; SKILL.md has 4,983 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~50
When it runs · the whole SKILL.md, loaded when a task matches
~11k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~20k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.

SKILL.md

The full file from tetherto/qvac at commit c3a6030, republished under its Apache-2.0 licence (© tetherto). 4,983 words, ~10,640 tokens.

Download SKILL.mdSave it as .claude/skills/qv-docs-update/SKILL.md (or your agent's skills folder). This skill also uses 9 other files; get the full folder from GitHub.
name
qv-docs-update
description
Updates the docs website after a change to the SDK or CLI. Finds the pages your change made out of date and proposes the smallest edit that fixes them. Use when invoking /qv-docs-update.
disable-model-invocation
true

Docs Update

Whenever a developer finishes implementing a feature in the SDK or the CLI, they invoke this skill to update the docs website, adding or updating the content. That way, every new feature PR opens with its documentation already in place.

Route a source change to the documentation pages it invalidated. Propose the smallest patch that makes them correct again.

Everything you write is read by a developer building a local AI application on QVAC, an open-source ecosystem. docs/website is their developer portal: it teaches how to use the SDK and the CLI, never how the codebase works internally. Write for that reader in Phase 3 and Phase 5.

Run this skill only when the developer asks for it. The source API must be stable. Do not run it mid-implementation: developers iterate on an API several times before it settles, and prose written against a moving surface is the waste this skill exists to avoid.

What this skill reads and writes

There are three observed source packages: packages/sdk, packages/sdk-python, packages/cli. They are read-only.

Never edit anything under packages/**. If a source file is wrong, report it and stop. Fixing source is the developer's job.

The writable surface is defined in references/docs-scope.md. Read that file before writing anything. A write outside the allowlist aborts the run and reverts every patch already applied.

One constraint from that file shapes every phase, so it is repeated here. The SDK and the CLI are each cut into one documentation line per published version, and this skill writes to the current line only — the folder written in parentheses, sdk/(v0.20) and cli/(v0.14). It documents the working tree, which is the release not yet cut; a line already cut documents a release already shipped. Resolve the folder each run, never from memory:

bash
ls docs/website/content/docs/sdk | grep '^(v'
ls docs/website/content/docs/cli | grep '^(v'

The two scripts that read the docs — the Phase 4 router and the Phase 6 parity gate — resolve it the same way and exit 2 if a collection has anything other than exactly one current line. Page paths below are written sdk/<line>/…, and the routing map uses the same placeholder.

Pipeline objects

The skill builds four objects, in order. Each one appears as a block in the final report.

ObjectQuestion it answersBuilt in
SOURCE_CHANGE_SETWhat changed in the code?Phase 2
DOCS_IMPACTWhat does that mean for a user?Phase 3
DOCS_TARGETSWhich pages and sections became wrong, and why?Phase 4
DOCS_PATCHWhat is the smallest change that fixes them?Phase 5

Cardinality:

text
1 SOURCE_CHANGE_SET  ->  1 DOCS_IMPACT   (always one, never split)
1 DOCS_IMPACT        ->  N pages         (routing is a union of hits)
1 page               ->  N targets       (distinct sections of that page)
1 target             ->  1 reason + 1 patch

DOCS_IMPACT is always a single report. Never split it. Never estimate how many pages it will touch. The router produces the page grouping, deterministically.

You have exactly two jobs in this pipeline, and both are verifiable: describe the change (Phase 3), and judge a concrete page you have in front of you (Phase 4). Nothing here asks you how many independent impacts a change contains. That question has no ground truth, and nothing downstream needs the answer.

States

A state classifies the documentary impact of a change, and decides what the skill does next: proceed to routing, stop and report, or ask the developer a question.

There are eight. Six classify one source file. Two describe the whole run.

StateScopeMeaning
NO_SOURCE_CHANGErunNothing changed in the three packages against the merge base.
NO_DOCS_IMPACTfileCode changed. Nothing user-facing went stale.
GENERATED_DOCS_ONLYfileUser-facing impact, fully covered by a generated surface.
DOCS_UPDATE_REQUIREDfileEditable prose must change. Proceed to routing.
NEW_CAPABILITY_PAGEfileNew AI capability with no page. The skill creates it.
NEW_MODELS_PAGEfileNew model-lifecycle topic with no page. The skill creates it.
HUMAN_INPUT_REQUIREDfileAn ambiguity the repo does not resolve. Ask the developer.
DONErunEvery patch applied and validated.

The two page-creation states are the same operation on different subtrees, and they are mutually exclusive. Separate them by what the symbol is about, not by where its source file sits. A symbol that performs inference — it takes a prompt, audio, or an image and returns a generated result — is an AI capability. A symbol that acquires, inspects, or prepares a model without performing inference is a model-lifecycle topic. completion and transcribe are the first. downloadAsset and assessModelFit are the second.

Assign the file-scoped states one source file at a time. If one file is unresolved, keep the patches already proposed for the files that routed cleanly.

Both scripts report a single run-level state field, and it is advisory. You own the state machine, not the scripts.

The collector decides only the two states it can prove alone, NO_SOURCE_CHANGE and NO_DOCS_IMPACT, and reports CONTINUE for everything else. CONTINUE is not one of the seven states: it means the script reached no verdict and Phase 3 must judge. The router reports its best guess from the routing signals it can see. Treat either field as a starting point, then refine per file as you work.

The final report carries one state in its header. Choose it this way. If any file is HUMAN_INPUT_REQUIRED, then report HUMAN_INPUT_REQUIRED, and list the resolved patches alongside the pending question. Else if every patch was applied and validated, then report DONE. Else report the state that every file shares.

Decision flow

This is every path through the skill, and every point where it stops. The phases below implement this flow.

text
Developer finishes the feature
        │
        ▼
  /qv-docs-update
        │
        ▼
Phase 1 — resolve the merge base; collect committed, staged,
          unstaged and untracked changes
        │
        ├── nothing changed ──────────────► NO_SOURCE_CHANGE      STOP
        ├── every changed file `internal` ─► NO_DOCS_IMPACT       STOP
        ▼
Phase 1 — export diff, TSDoc diff, auxiliary context
        │
        ▼
Phase 2 — build SOURCE_CHANGE_SET
        │
        ▼
Phase 3 — classify against the impact policy
        │
        ├── nothing user-facing ──────────► NO_DOCS_IMPACT        STOP
        ├── a generated surface covers it ─► GENERATED_DOCS_ONLY  STOP
        ├── is the behaviour supported? ──► HUMAN_INPUT_REQUIRED  STOP
        │   the repo does not say
        ▼
      DOCS_UPDATE_REQUIRED
        │
        ▼
Phase 4 — run the router
        │
        ├── new_capability_symbols ───────► NEW_CAPABILITY_PAGE
        │   symbol performs inference       four append-only edits,
        │                                   then Phase 6
        │
        ├── new_capability_symbols ───────► NEW_MODELS_PAGE
        │   symbol is model lifecycle       three append-only edits,
        │                                   then Phase 6
        │
        ├── unrouted and user-facing ─────► HUMAN_INPUT_REQUIRED
        │                                   for that source only;
        │                                   routed pages continue
        ▼
Phase 4 — filter each candidate; write one reason for each
        │
        ▼
Phase 5 — write the patch; present the diff
        │
        ├── developer rejects ────────────► revise, present again
        ▼
Apply to disk
        │
        ▼
Phase 6 — five gates
        │
        ├── any gate fails ───────────────► report the error, leave
        │                                   the patches on disk,
        │                                   do not declare DONE    STOP
        ▼
      DONE

Phase 1 — Collect the source change

  • Inputs: the current git working tree.
  • Outputs: /tmp/qv-docs-scs.json (written by the script), plus three records you gather by hand: export diff, TSDoc diff, auxiliary context.
  • Expected result: every changed path in the three packages is accounted for and carries a bucket, across all four git states. A file missed here is invisible to every later phase.

Start with the script. It resolves the merge base, collects changes across all four git states (committed on the branch, staged, unstaged, untracked), and classifies every path into a bucket.

  1. Run the collector.
bash
bash .agents/skills/qv-docs-update/scripts/collect-source-changes.sh > /tmp/qv-docs-scs.json

The output has this shape:

json
{
  "state": "CONTINUE",
  "base": { "ref": "tether/main", "sha": "3f2a91c…", "short": "3f2a91c", "via": "url" },
  "strong_evidence": true,
  "buckets": ["api", "examples"],
  "file_count": 2,
  "files": [{ "path": "packages/sdk/src/client/api/completion-stream.ts", "bucket": "api", "status": "M" }]
}

Each file carries a bucket. The bucket decides which router runs in Phase 4.

BucketPaths
examplespackages/{sdk,sdk-python}/examples/**
apipackages/sdk/src/client/api/**
client-otherpackages/sdk/src/client/** outside api/
surfacebarrels, src/types/**, src/schemas/**
cli-commandpackages/cli/src/{bundle-sdk,serve,configure,openai,doctor,verify}/**
cli-infrapackages/cli/src/cli/**, src/{config,errors,logger,index}.ts
python-surfacepackages/sdk-python/** outside examples/
areapackages/sdk/src/{logging,models,server,worker}/**
internaleverything else

The script decides two states on its own. It reports NO_SOURCE_CHANGE when nothing changed, and NO_DOCS_IMPACT when every changed file is internal. Every other run reports CONTINUE: changes exist, and their documentary impact is Phase 3's to judge.

  1. If state is NO_SOURCE_CHANGE or NO_DOCS_IMPACT, then stop and emit the no-update report. Else continue.

strong_evidence is true when any of examples, api, or cli-command was touched. Treat it as weight in Phase 3, not as a verdict. Do not put it in the report.

base.via records how the base was chosen: url when a remote points at tetherto/qvac, explicit when the developer passed --base, single-remote when neither applied and the clone has exactly one remote. Report the base with its via. A single-remote base plus an implausible file_count means the base is wrong, so stop and say so rather than routing hundreds of files.

The script cannot read the public export surface. Get it from the barrel, comparing the base against the working tree.

  1. If no changed file is in the api or surface bucket, then skip to step 5. Else read the barrel at the base and in the working tree, and record added, removed, and renamed exports.
bash
git show <base-sha>:packages/sdk/src/client/api/index.ts

Compare it against the current packages/sdk/src/client/api/index.ts. The barrel is the authority on what is public.

  1. Read the diff of every file in the api and surface buckets, then record each changed function signature and each changed TSDoc block.
bash
git diff <base-sha> -- <file-path>

For an untracked file, read the file directly. There is no diff to read.

  1. Gather auxiliary context.

Collect three things: the branch commit messages (git log <base-sha>..HEAD --format=%s), the PR title and body (gh pr view --json title,body, only when a PR exists), and any changed test that exercises an affected symbol. A new test often states new behaviour more plainly than the diff does.

Phase 2 — Build SOURCE_CHANGE_SET

  • Inputs: everything collected in Phase 1.
  • Outputs: one SOURCE_CHANGE_SET text block.
  • Expected result: the block carries every fact the later phases need, so nothing downstream has to reopen the raw diff.

This object is what you read from here on. Do not go back to the raw diff after this phase.

  1. Write the SOURCE_CHANGE_SET block in this exact shape.
text
SOURCE_CHANGE_SET

Base: tether/main @ 3f2a91c (via url)
Packages: packages/sdk

Buckets:
- api:       packages/sdk/src/client/api/completion-stream.ts
- examples:  packages/sdk/examples/completion-events.ts
- surface:   packages/sdk/src/types/generation.ts

Exports:
- changed:   completion() — new optional parameter `maxTokens?: number`
- unchanged: all others

TSDoc:
- completion(): @param maxTokens added

Tests:
- packages/sdk/test/completion-max-tokens.test.ts (new)

Phase 3 — Build DOCS_IMPACT

  • Inputs: the SOURCE_CHANGE_SET block, and references/docs-impact-policy.md.
  • Outputs: one DOCS_IMPACT text block, and a state.
  • Expected result: the block states the change in the user's terms, not the code's, and every later claim in a patch traces back to something written here.

The question here is not "did the code change?". Phase 1 already answered that. Ask two questions instead, and answer both.

First: did a claim the docs make stop being true, or become incomplete?

Second: with the docs exactly as they stand today, can a user use the feature that changed?

The two catch different failures. The first catches a page that went stale. The second catches a page that is still entirely correct and yet leaves the user unable to reach the new capability. A new optional parameter usually makes no existing sentence false, and still leaves the user with no way to learn that the parameter exists. If the answer to either question is bad, the change has documentary impact.

  1. Read references/docs-impact-policy.md.

  2. Write the DOCS_IMPACT block in this exact shape.

text
DOCS_IMPACT

User-facing change:
completion() accepts an optional maxTokens parameter.

Public surface affected:
- completion()
- GenerateTextOptions.maxTokens

Behaviour:
- maxTokens caps the total tokens generated in the response.
- Omitted, current behaviour is unchanged.

Generated coverage:
- The API summary will list completion() with the new signature.
- The API summary will NOT describe what maxTokens means. It omits parameter descriptions by design.

Documentary implication:
maxTokens is essential to controlling output, so it belongs on the capability page, per the policy on essential parameters.
  1. If the repo does not settle whether the changed behaviour is public and supported, then emit HUMAN_INPUT_REQUIRED, put that exact question to the developer, and stop.

This is the impact ambiguity, not the routing one. It appears when an observable behaviour changed and no barrel export, no TSDoc, no test and no page says whether that behaviour is part of the contract or an accident of the implementation. Documenting an accident is worse than documenting nothing, because the next change silently breaks a promise the docs made. Ask instead of inferring. Phase 4 raises the same state for a different reason: there the behaviour is known and the page is not.

  1. If the state is NO_DOCS_IMPACT or GENERATED_DOCS_ONLY, then stop and emit the no-update report. Else continue.

When you claim GENERATED_DOCS_ONLY, name the covering surface in the report. An unnamed claim is not checkable.

Phase 4 — Route to DOCS_TARGETS

  • Inputs: /tmp/qv-docs-scs.json, and the DOCS_IMPACT block.
  • Outputs: one DOCS_TARGETS block, grouped by page, with a written reason per candidate.
  • Expected result: every candidate the router produced is either kept with a reason, or dismissed with a reason. None is silently dropped.

The router reads the JSON from Phase 1, not the SOURCE_CHANGE_SET.

  1. Run the router.
bash
bun run .agents/skills/qv-docs-update/scripts/route-docs-targets.ts --input /tmp/qv-docs-scs.json

The output has this shape:

json
{
  "state": "DOCS_UPDATE_REQUIRED",
  "base": { "ref": "tether/main", "sha": "3f2a91c…", "short": "3f2a91c", "via": "url" },
  "r3_used": false,
  "high_page_count": false,
  "new_capability_symbols": [],
  "pages": [
    {
      "page": "sdk/(v0.20)/ai-capabilities/text-generation.mdx",
      "targets": [
        {
          "page": "sdk/(v0.20)/ai-capabilities/text-generation.mdx",
          "section": "Examples › Usage",
          "sectionLevel": 3,
          "via": "R1",
          "source": "packages/sdk/examples/completion-events.ts",
          "evidence": "file=<rootDir>/packages/sdk/examples/completion-events.ts",
          "line": 185
        }
      ]
    }
  ],
  "unrouted": [{ "source": "…", "bucket": "…", "status": "M", "reason": "…" }],
  "discarded": [{ "page": "…", "source": "…", "via": "R4", "reason": "…" }]
}

Read the fields as follows:

  • pages[].targets[] are the candidates. Each one is a page section to judge in step 3.
  • evidence is the authored binding the router matched. It is a fact about the repo, not a guess.
  • line is where that binding sits in the page. Use it to find the section fast.
  • section is null on a page-level hit: every R3 hit, and the cli/<line>/http-server/** subtree of R4. The router bound the page, not a section, because the map and the subtree rule name pages only.
  • unrouted[] are source files no router could place. Handle them in step 5.
  • discarded[] are hits that fell outside the allowlist or hit a path declared undocumented. Copy them into the report. Never re-add them.
  • new_capability_symbols[] are new exported symbols in client/api/ with no page. Each one means NEW_CAPABILITY_PAGE.
  • r3_used is true only when every hit came from the area map. It is run-level, so a run with one R1 hit and one R3 hit reports false. To weigh a single candidate, read its via field instead: R3 is the declared fallback, so treat an R3 candidate with more suspicion than an R1, R2 or R4 hit.
  • high_page_count is true when the router produced more than four pages. It is counted before your filtering, so recount after step 3.

There are four routers, and their hits are unioned. R1, R2 and R4 are exact: each resolves a binding that already exists in the content. R3 is the declared fallback and labels itself as such.

RouterBinding it resolvesBuckets it covers
R1the literal file=<rootDir>/… directive in a fenceexamples
R2the /sdk/reference/api#<symbol> anchorapi, export diff
R4the ### `qvac <command>` headingcli-command
R3references/routing-map.yamleverything else

Four router behaviours affect how you read the output:

  • R1 has no false-positive mode. No page inlines a full example. A TS example also routes the page that shows its transpiled dist/**.js counterpart.
  • R2 takes symbols from the barrel, not the filename. completion-stream.ts exports completion, so the anchor is #completion and never #completionstream. rag.ts exports nine functions and transcribe.ts exports two. Use the same rule when you write a link in a patch.
  • R2 also has a secondary pass for a symbol linked somewhere other than its anchor, reported as the weaker binding. text-generation.mdx links the text `batchCompletion()` to the batch-processing page instead of to its API anchor, and carries a paragraph on how that function shares parallel slots. That page is a real target even though the anchor is absent. A symbol mentioned in prose with no link at all is routed by nothing.
  • R4 also routes the narrative sections that describe a command outside ## Reference, and for serve/ it adds the whole cli/<line>/http-server/** subtree. That subtree is in the CLI's line, not the SDK's: the HTTP server ships in the SDK and is documented under qvac serve, and the two collections are versioned independently.
  • R3 runs per file, not per run. It picks up only the files the exact routers could not resolve. A commit that touches an example and a config module gets an R1 hit for the example, and R3 still runs for the config module. One file's exact hit never suppresses the fallback for another file.

A pages: [] entry in the routing map is a positive declaration that a path is intentionally not documented. It is why a file can be unrouted without becoming a question.

  1. Read each candidate section in the page it belongs to.

Judge the page itself, not the diff. Read the section with DOCS_IMPACT in hand.

If section is null, then read the whole page and choose the section yourself, then state that choice and its justification in the candidate's Reason. This is the one place where you pick a target the router did not name, so make the choice auditable rather than silent. If no section on the page fits, dismiss the candidate — do not invent a section for it.

  1. For each candidate, answer this question in writing: did this section become incorrect, incomplete, misleading, or materially insufficient after the change described in DOCS_IMPACT?

Keep the candidate if the answer is yes. Dismiss it if the answer is no. Either way, write the reason. A page that routed by accident has no answer to "which claim here went stale?", and that is what removes it.

The Reason field is the contract for the patch. Phase 5 is bound to it, so write it precisely.

  1. Write the DOCS_TARGETS block, grouped by page, in this exact shape.
text
DOCS_TARGETS — 2 pages, 3 targets

sdk/(v0.20)/ai-capabilities/text-generation.mdx
  1. Section: "Features"
     Via:     R2 (completion -> /sdk/reference/api#completion)
     Reason:  the list of generation controls is complete today and would
              become incomplete by omitting maxTokens.
     Action:  list maxTokens among the controls.

  2. Section: "Examples › Usage"
     Via:     R1 (packages/sdk/examples/completion-events.ts)
     Reason:  the introductory sentence describes what the script does, and the
              script now demonstrates the new parameter.
     Action:  update the introductory sentence.

sdk/(v0.20)/configuration/index.mdx
  3. Section: "Reference"
     Via:     R3 (packages/sdk/src/client/config-loader/**)
     Reason:  R3 bound the page and named no section; "Reference" is the only
              section that enumerates config keys, and its key table lacks the
              new one.
     Action:  add the key, its accepted values, and its default.

Dismissed:
- sdk/(v0.20)/ai-capabilities/batch-processing.mdx
  Reason: links completion() only by comparison; no claim went stale.

There is no page limit, and multi-page is a normal result.

The team rule "1 change == 1 scope" describes the scope of the change in the source. It says nothing about how many pages document that change, and the two are different quantities. A new CLI command that reads a new config key is perfectly scoped, and it needs both cli/<line>/index.mdx and the configuration page. Do not drop a target to keep the page count down. The gate against wide routing is the written reason, not a count.

  1. If more than four pages survived filtering, then emit this note and continue. It never blocks.
text
Routing produced 6 pages after filtering. That is allowed but uncommon. Worth
checking whether routing went wide (candidates that should have been dismissed)
or the source change mixes scopes. The patches stand.
  1. For each entry in new_capability_symbols[], classify the symbol by the rule in States, then run the matching subprocedure, below. If the symbol performs inference, run NEW_CAPABILITY_PAGE. Else run NEW_MODELS_PAGE.

Both subprocedures also apply to a symbol the router could not place because no page links its anchor yet. R2 binds a page by the /sdk/reference/api#<symbol> link it already contains, so a public symbol that no prose page mentions routes to nothing and reaches unrouted[] whether or not it is new in this run. A symbol in that position, exported from the barrel and listed in the API summary, needs the page the routers found missing rather than a question to the developer. Confirm the absence before creating the page: search the current line, docs/website/content/docs/sdk/<line>/, for the symbol name and for its anchor, and treat a hit under reference/ as no coverage, since the API summary and the release notes are both generated there. Search that line alone — a hit in a line already cut says the symbol was documented for a shipped release, not that the current one covers it.

  1. For each entry in unrouted[] that is user-facing and carries no newSymbol, emit HUMAN_INPUT_REQUIRED for that source and ask which page covers the topic.

new_capability_symbols[] is derived from unrouted[], so a new symbol appears in both lists. Step 6 already handled it. Asking about it here would create the page and then ask which page covers the topic.

The answer becomes a new routing-map.yaml entry. That is how the map grows. A source file that is not user-facing needs no question: ignore it.

Show full SKILL.md (2,077 more words)Show less

Phase 5 — Write and apply DOCS_PATCH

  • Inputs: the DOCS_TARGETS block, and references/editorial-guidelines.md.
  • Outputs: one patch per target, applied to disk after approval.
  • Expected result: each patch settles exactly one target's Reason, and changes nothing else.

Work page by page. Close every target on one page before opening the next, so the developer reviews one file at a time.

  1. Read references/editorial-guidelines.md.

  2. Read the whole target page, then locate the target section by its heading.

  3. Write the smallest change that settles that target's Reason, and nothing beyond it.

If the new text asserts something the Reason does not support, it is scope creep or hallucination. Delete it and write it again.

Match the patch to the change type:

Change in the sourcePatch to write
Existing example modifiedUpdate the script's introductory sentence. Take it from the example's own top-of-file comment.
New example using existing functionsAdd a ### subsection under Examples: one introductory sentence, then a complete <Tabs> block for the language files that exist.
New essential parameter on an existing functionDocument it on the capability page, as a Features bullet or as prose in the relevant section. Follow text-generation.mdx.
Observable behaviour changedCorrect the stale statement in place. Do not rewrite the section.
New function in an existing capabilityAdd it to the Functions list with a /sdk/reference/api#<symbol> link.
New flag on an existing CLI commandDocument it inside that command's own ### block in cli/<line>/index.mdx, following how the neighbouring flags are shown.
New CLI commandAdd a ### `qvac <command>` heading under ## Reference in cli/<line>/index.mdx, matching the shape of the commands already there. Never a new page.
New function that institutes a new capabilityRun the NEW_CAPABILITY_PAGE subprocedure, below.
New function that institutes a new model-lifecycle topicRun the NEW_MODELS_PAGE subprocedure, below.
  1. Present the diff to the developer before writing to disk.

  2. If the developer approves, then apply the patch and preserve the rest of the page byte for byte. Else revise the patch and present it again.

Phase 6 — Validate

  • Inputs: the applied patches.
  • Outputs: a pass or fail per gate, reported in the Validation: block.
  • Expected result: all five gates pass, and the state becomes DONE.

There are five gates. Run them in order. If any gate fails, report the error, leave the patches on disk for the developer to fix, and do not declare DONE.

  1. List the files this run wrote — the targets patched in Phase 5, plus the registration points when a page-creation subprocedure ran (four for NEW_CAPABILITY_PAGE, three for NEW_MODELS_PAGE) — and check each one against the allowlist in references/docs-scope.md.

Check the files this run wrote, never the dirty working tree. The tree legitimately holds the developer's own changes under packages/**, which Phase 1 collected on purpose. Treating those as scope violations would abort every run. To confirm nothing else in the website was touched, run git status --short -- docs/website/ and verify that every path it lists is one you wrote.

A file outside the allowlist aborts the run. Revert everything already applied. The three restricted files pass only when the diff is an append inside the one block their row names — the AI-capabilities grid in ecosystem/index.mdx and the pages array of ai-capabilities/meta.json under NEW_CAPABILITY_PAGE, the pages array of models/meta.json under NEW_MODELS_PAGE. src/lib/custom-tree.ts is not among them: it declares the sidebars of the two unversioned collections, and this skill adds a page to neither.

  1. Run git diff and review the full diff.

Check three things: which files and sections were touched, whether the patch is proportional to the source change, and whether any editorial edit unrelated to the source change slipped in. Remove anything unrelated.

This review is the only gate that catches a well-formed but false sentence. Every other gate catches a broken patch: invalid MDX, a file= pointing at nothing, a dead route. A sentence claiming a default is 512 when it is 1024 compiles, renders, and passes all of them. Do not skip this gate.

The skill relies on the developer here, and that works because the reviewer is the person who just wrote the feature. If this skill is ever run where the reviewer is not the feature's author — a CI companion, a sweep over someone else's branch, a batch over old commits — that premise no longer holds. Say so in the report instead of declaring DONE.

  1. Check that every symbol cited in a patch exists in packages/sdk/src/client/api/index.ts, and that every file= directive introduced resolves to a real file on disk.

  2. If the run created a capability page, then run the parity script.

bash
bun run .agents/skills/qv-docs-update/scripts/check-capability-parity.ts

It cross-checks all four registration points, verifies the card's icon is imported and matches the sidebar's, and catches registrations pointing at pages that do not exist. Three of the four points fail silently without it: omit the card, the bullet, or the sidebar entry and the build still succeeds, the tests still pass, and the capability is missing everywhere a user would look.

If the run created a models page instead, then check its three registration points by hand: the page file exists and declares an icon:, sdk/<line>/index.mdx carries a bullet linking its URL under ### Utilities, and sdk/<line>/models/meta.json lists its slug. The script does not cover models/. The silent failure is the same one — omit the bullet or the slug and every other gate still passes — so do not skip this because no command reports it.

  1. Run the website suites from docs/website/.
bash
bun run test:examples   # file refs, example type-check, transpilation, inline blocks, Python
bun run test            # website suite (link integrity, open graph, …)
bun run build           # static build; catches broken MDX and broken routes

Subprocedure — NEW_CAPABILITY_PAGE

This is not a phase. It is a conditional subprocedure, and it runs only when a change institutes a new AI capability. Two places call it: Phase 4, for each entry in new_capability_symbols[], and Phase 5, for the last row of the patch-shape table. When it finishes, go to Phase 6. Gate 4 exists to validate it.

  • Inputs: the new symbol, its example file, and its model family.
  • Outputs: four edits: one new page, three appends.
  • Expected result: the parity script in Phase 6 passes.

A new capability is not "create an MDX". It is one operation with four points, every time. All four are appends. Nothing else is touched.

#FileOperation
1content/docs/sdk/<line>/ai-capabilities/<slug>.mdxcreate, from references/capability-page-template.mdx
2content/docs/sdk/<line>/ai-capabilities/meta.jsonappend 1 slug at the end of the pages array
3content/docs/ecosystem/index.mdxappend 1 <Card> at the end of the ## AI capabilities grid, and 1 identifier to the lucide-react import
4content/docs/sdk/<line>/index.mdxappend 1 bullet at the end of the ### AI tasks list

The capability belongs to the release being documented, so all of this happens in the current line and in no other. A line already cut shipped without the capability.

  1. If the change requires touching any file outside those four, then stop and emit HUMAN_INPUT_REQUIRED. The case is not a new capability.

  2. Create the page from the template, and declare its icon in the frontmatter.

A versioned collection composes its navigation from the content, so a page carries its own icon rather than a hand-written tree carrying it. The icon is not derivable from the source: propose a Lucide name, use the same one in the card at step 3, and flag it in the report as needing editorial confirmation.

  1. Append the slug to content/docs/sdk/<line>/ai-capabilities/meta.json.

The pages array is explicit and ordered, with no catch-all, so it is the whole of the sidebar for that folder. Without this entry the page is reachable by URL and invisible in navigation.

json
{
  "title": "AI capabilities",
  "pages": ["text-generation", "…", "image-classification"]
}
  1. Append the card and its icon import to content/docs/ecosystem/index.mdx.

The grid lives on the Ecosystem overview — the page the old site index became — and its cards point at the version-less capability URLs, which the current line answers. Both edits are required. Without the import, the build breaks.

mdx
import { MessagesSquare, /* … */, Shapes, Eye, Brain, /* … */ } from 'lucide-react'
mdx
  <Card href="/sdk/ai-capabilities/image-classification" title={<span className="inline-flex items-center gap-2"><Shapes className="size-4 text-[var(--color-fd-primary)]" />Image classification</span>}>
    Classify images into labels with confidence scores via a customized GGML backend.
  </Card>

If the icon name collides in MDX scope, then alias it. Image is imported as Image as ImageIcon for that reason. The page's frontmatter declares the Lucide export itself, so it reads icon: Image where the card reads <ImageIcon>, and the parity gate resolves the alias before comparing them.

  1. Append the bullet to content/docs/sdk/<line>/index.mdx, under ### AI tasks.

That page is the SDK collection overview, the one the old introduction.mdx became.

mdx
* [**Image classification:**](/sdk/ai-capabilities/image-classification) assigning class labels with confidence scores to images, via [a customized GGML backend](https://github.com/tetherto/qvac/tree/main/packages/classification-ggml).
  1. Use the same icon in the page's frontmatter (step 2) and the card (step 4).

  2. Write the card and bullet descriptions from this formula, which is already present as an MDX comment in both files.

mdx
{/* <Task name>: <what computation is performed> for <what the developer achieves> via <engine> */}

Base all three strings — frontmatter description, card, bullet — on the same sentence. They describe the same thing at different lengths and must agree.

Subprocedure — NEW_MODELS_PAGE

This is not a phase. It is a conditional subprocedure, and it runs only when a change institutes a new model-lifecycle topic — acquiring, inspecting, or preparing a model, with no inference performed. Two places call it: Phase 4 step 6, and the patch-shape table in Phase 5. When it finishes, go to Phase 6.

  • Inputs: the symbol, its example file, and the question the topic answers for a user.
  • Outputs: three edits: one new page, two appends.
  • Expected result: the page, its slug in models/meta.json, and the bullet all exist and agree.

It is the NEW_CAPABILITY_PAGE operation on the models/ subtree, with one point fewer. There is no card, because the Ecosystem overview's only grid is ## AI capabilities and this topic is not one.

#FileOperation
1content/docs/sdk/<line>/models/<slug>.mdxcreate, following models/download-lifecycle.mdx and models/sharded-models.mdx
2content/docs/sdk/<line>/models/meta.jsonappend 1 slug at the end of the pages array
3content/docs/sdk/<line>/index.mdxappend 1 bullet at the end of the ### Utilities list

Like a capability, the topic belongs to the release being documented, so every edit lands in the current line.

  1. If the change requires touching any file outside those three, then stop and emit HUMAN_INPUT_REQUIRED. The case is not a model-lifecycle topic.

  2. Create the page, following the shape both existing models/ pages share.

text
frontmatter:  title, icon, description, schemaType: HowTo
## Overview
## Functions
<topic sections>
## Example
<Callout type="success"> footer tip

It is close to the capability skeleton and differs in two ways. There is no ## Models section: the topic is about handling models, not about which ones a task supports. And the topic sections carry the page, so they are the bulk of it rather than an optional extra — download-lifecycle.mdx has five, sharded-models.mdx two.

Open ## Overview by naming the function and the question it answers for the user, then link the function to its API anchor. Do not open by naming an inference engine: that opening belongs to capability pages, which have one, and this topic does not.

  1. Append the slug to content/docs/sdk/<line>/models/meta.json.
json
{
  "title": "Models",
  "pages": ["download-lifecycle", "sharded-models", "assess-model-fit"]
}
  1. Append the bullet to content/docs/sdk/<line>/index.mdx, under ### Utilities.

Model-lifecycle topics go in ### Utilities, not ### AI tasks. All three existing pages are already there.

mdx
* [**Sharded models:**](/sdk/models/sharded-models) download a model that is sharded into multiple parts.
  1. Declare a Lucide icon in the page's frontmatter and flag it in the report as needing editorial confirmation.

The icon is not derivable from the source. Unlike a capability, this page has only one icon to choose, since there is no card to keep in agreement.

  1. Base the frontmatter description and the bullet on the same sentence. Both describe the topic, at different lengths, and must agree. Keep the description to one line, as both existing pages do.

Report formats

Emit one of these three at the end of the run.

Run with updates:

text
qv-docs-update — DONE

Source impact:
completion() accepts an optional maxTokens parameter.

Routing:
- sdk/(v0.20)/ai-capabilities/text-generation.mdx  via R2 (symbol)  -> section "Features"
- sdk/(v0.20)/ai-capabilities/text-generation.mdx  via R1 (example) -> section "Examples › Usage"

Generated coverage:
- The API summary covers the signature. It does not cover the parameter's meaning.

Documentation updated:
- sdk/(v0.20)/ai-capabilities/text-generation.mdx (2 sections, +7 −2)

Validation:
- scope ok
- diff reviewed
- grounding ok
- test:examples ok
- test ok
- build ok

Run with no update:

text
qv-docs-update — NO_DOCS_IMPACT

Changes detected in packages/sdk (buckets: internal, client-other).
No public surface changed; no documentary claim became incorrect or incomplete.

Run partially blocked. The resolved patch survives:

text
qv-docs-update — HUMAN_INPUT_REQUIRED

Source impact:
completion() accepts an optional maxTokens parameter.

Resolved:
- sdk/(v0.20)/ai-capabilities/text-generation.mdx  "Features"  via R2  +4 −0
  (patch proposed, awaiting approval)

Pending:
- The change in src/types/streaming.ts is user-facing and no router hit. Which
  page covers this topic? The answer becomes a new routing-map.yaml entry.

The proposed patch stands — answering the pending question does not invalidate it.

Out of scope

Do not do any of the following:

  • Route by anything other than the four bindings and the declared area map. There is no covers frontmatter, no embeddings, no semantic search.
  • Add managed markers inside MDX. The allowlist is path-level only.
  • Ground a patch beyond symbol existence and file= resolution. Broad factual validation is v2. The developer reviewing the diff wrote the feature, so they catch a false claim.
  • Judge the style guide with a second model pass.
  • Trigger this skill automatically. Hook-based auto-detection belongs to a CI companion outside this skill.
  • Create a page for anything other than a new AI capability or a new model-lifecycle topic. Those two are derivable from a source change, because a public symbol with no page is a fact the routers report. A new page from an information-architecture decision is permanently out of scope: reorganising pages that already cover their subject is not derivable from a source change. A new CLI command is a new section of cli/<line>/index.mdx. A new Python example is a tab on an existing page, or a section of sdk/<line>/python-sdk.mdx.

Files

© tetherto, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 9 other files (scripts, references) in .agents/skills/qv-docs-update of tetherto/qvac.

  • SKILL.md
  • agents/openai.yaml
  • references/capability-page-template.mdx
  • references/docs-impact-policy.md
  • references/docs-scope.md
  • references/editorial-guidelines.md
  • references/routing-map.yaml
  • scripts/check-capability-parity.ts
  • scripts/collect-source-changes.sh
  • scripts/route-docs-targets.ts

Open the folder on GitHubat commit c3a6030

Compare with similar skills

Qv Docs Update next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Qv Docs Update compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Qv Docs Update this skilltetherto/qvac681—~11kAutomated safety check: PassApache-2.0
Agent BuildershareAI-lab/learn-claude-code78k6 repos~1.2kAutomated safety check: PassMIT
Add Uint Supportpytorch/pytorch104k2 repos~2.3kAutomated safety check: PassCustom licence
Peft Fine TuningOrchestra-Research/AI-Research-SKILLs13k9 repos~3.1kAutomated safety check: PassMIT
Segment Anything Model GuideOrchestra-Research/AI-Research-SKILLs13k9 repos~3.3kAutomated safety check: PassMIT
1passwordtrpc-group/trpc-agent-go1.8k15 repos~656Automated safety check: PassApache-2.0

Similar skills

  • Agent Builder

    shareAI-lab/learn-claude-code

    Design and build AI agents for any domain. An agent skill from shareAI-lab/learn-claude-code.

    78k GitHub starsUsed in 6 repos~1.2k tokens
    AI & LLM EngineeringAuto-check passed
  • Add Uint Support

    pytorch/pytorch

    Add unsigned integer (uint) type support to PyTorch operators by updating ATDISPATCH macros.

    104k GitHub starsUsed in 2 repos~2.3k tokens
    AI & LLM EngineeringAuto-check passed
  • Peft Fine Tuning

    Orchestra-Research/AI-Research-SKILLs

    Parameter-efficient fine-tuning for LLMs using LoRA, QLoRA, and 25+ methods.

    13k GitHub starsUsed in 9 repos~3.1k tokens
    AI & LLM EngineeringAuto-check passed
  • Segment Anything Model Guide

    Orchestra-Research/AI-Research-SKILLs

    Guide to using Meta's Segment Anything Model for zero-shot image segmentation with point, box or mask prompts, or automatic mask generation.

    13k GitHub starsUsed in 9 repos~3.3k tokens
    AI & LLM EngineeringAuto-check passed
  • 1password

    trpc-group/trpc-agent-go

    Set up and use 1Password CLI (op). An agent skill from trpc-group/trpc-agent-go.

    1.8k GitHub starsUsed in 15 repos~656 tokens
    AI & LLM EngineeringAuto-check passed
  • Chroma Vector Database

    Orchestra-Research/AI-Research-SKILLs

    Shows how to store documents and embeddings in Chroma, query them by similarity with metadata filters, and persist them to disk for RAG and semantic search projects.

    13k GitHub starsUsed in 8 repos~2.3k tokens
    AI & LLM EngineeringAuto-check passed

More from tetherto/qvac

All 50 skills in this repo
  • Creates a Solutions page in the QVAC documentation website from a real use case, generalizing the case into reusable guidance and registering the page in the site navigation.

    681 GitHub stars~2.8k tokensUpdated today
    Auto-check passed
  • Qv Agent Stack Sync

    tetherto/qvac

    Plan and prepare the QVAC agent-stack release cascade across @qvac/inference, @qvac/sdk, @qvac/cli, @qvac/ai-sdk-provider, @qvac/opencode-plugin, and @qvac/openclaw-plugin.

    681 GitHub stars~2k tokensUpdated today
    Auto-check passed
  • Run the deterministic code-quality audit, turn related findings into contextual remediation groups, prepare approval-gated Asana proposals, reconcile recurring runs, or configure twice-monthly…

    681 GitHub stars~1.6k tokensUpdated today
    Auto-check passed
  • Review C++ changes for string parameter and call-site efficiency conventions (std::stringview, std::string&&, const std::string&, const char, and TransparentStringMap lookup).

    681 GitHub stars~702 tokensUpdated today
    Auto-check passed
  • Qv Addon Changelog

    tetherto/qvac

    Generate changelog entries for a target add-on package. An agent skill from tetherto/qvac.

    681 GitHub stars~1.7k tokensUpdated today
    Auto-check passed
  • Generate release notes for addon packages (non-SDK inference addons, decoder, OCR).

    681 GitHub stars~1.2k tokensUpdated today
    Auto-check passed

Questions about Qv Docs Update

What does Qv Docs Update do?

Updates the docs website after a change to the SDK or CLI. An agent skill from tetherto/qvac. Qv Docs Update is an agent skill from tetherto/qvac. Updates the docs website after a change to the SDK or CLI.

When should I use Qv Docs Update?

Qv Docs Update fits situations like: invoking /qv-docs-update.

How do I install Qv Docs Update in Claude Code?

Run `npx skills add tetherto/qvac --skill qv-docs-update -a claude-code`. Or copy the skill folder (.agents/skills/qv-docs-update in tetherto/qvac) into .claude/skills/qv-docs-update in your project. Claude Code loads it when a task matches its description.

How do I install Qv Docs Update in Codex?

Run `npx skills add tetherto/qvac --skill qv-docs-update -a codex`. Or copy the skill folder (.agents/skills/qv-docs-update in tetherto/qvac) into .agents/skills/qv-docs-update in your project. Codex loads it when a task matches its description.

Can I use Qv Docs Update in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add tetherto/qvac --skill qv-docs-update -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/qv-docs-update, .gemini/skills/qv-docs-update, .github/skills/qv-docs-update and .opencode/skills/qv-docs-update in your project.

What does Qv Docs Update need to run?

Going by SKILL.md and its folder, Qv Docs Update needs TypeScript and a shell for the scripts in its folder and the command-line tools its instructions call (git, bun, bash and gh). Our summary lists: Node.js; A Bash shell.

Does Qv Docs Update access the network?

SKILL.md contains no URLs. Its commands use git and gh, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Qv Docs Update safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.

What licence does Qv Docs Update use?

Qv Docs Update is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Qv Docs Update use?

About 11k tokens (SKILL.md is roughly 43k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 9.4k tokens, read only when the agent opens those files.

What are the alternatives to Qv Docs Update?

Skills that share tags, products or a category with Qv Docs Update: Agent Builder (shareAI-lab/learn-claude-code, 78k stars), Add Uint Support (pytorch/pytorch, 104k stars), Peft Fine Tuning (Orchestra-Research/AI-Research-SKILLs, 13k stars) and Segment Anything Model Guide (Orchestra-Research/AI-Research-SKILLs, 13k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Qv Docs Update?

tetherto (a GitHub organization) maintains it in tetherto/qvac, which has 681 GitHub stars. The repository holds 50 skills in this directory. The repository was last updated on October 7, 2026.

Source: tetherto/qvac on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.