Migrate existing untested code into the Grove test suite. Use when the user asks to "migrate this code", "convert to Grove", "make this testable", "move this example to the test suite", "add tests for this existing code", "migrate the code on this page", or wants to convert documentation code examples that currently live outside of Grove into properly tested, snippeted examples. Supports both page-level migration (scan an RST page for all code) and snippet-level migration (convert a single code block).
68
81%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Passed
No known issues
Begin your first response with: [grove-migrate-d12bc5c1]
Convert existing untested code examples from documentation source files into properly tested, snippeted Grove examples. This skill preserves the original code's semantics while adapting it to Grove conventions.
Do NOT use when:
/grove-create/grove-test/grove-run/grove-maintainBefore Step 1, check whether the Grove VS Code extension has dropped a
handoff file at .claude/grove-handoff.json in the workspace root. If the
file exists and skill equals grove-migrate:
Delete the handoff file immediately after reading it. The file is single-use; leaving it in place causes the next invocation to re-trigger on stale context.
Check the payload. If a check fails, tell the writer what's wrong (e.g. "version 2 isn't recognized" or "missing context.absolutePath"), recommend they file an issue for the Grove VS Code extension, and ask whether to proceed without the handoff. If they confirm, fall through to Step 1.
version must equal 1. Higher means the extension
is ahead of the skill.version, skill,
trigger, context. The context object must contain the
trigger-specific fields shown in the schemas in
references/extension-handoff.md.Branch on trigger. See references/extension-handoff.md for both
trigger schemas (rst-literalinclude and rst-code-block) and
their per-trigger handling instructions, including the JSON
code-block ambiguity (JavaScript vs. mongosh). Both branches skip
Step 1 and Step 2, then proceed from Step 3 with the language
already known.
If the handoff file is absent or skill doesn't match,
proceed normally from Step 1.
Examine what the user provided to determine the migration mode:
The user provided a path to an RST/TXT documentation page (a file under
content/). This is the primary workflow — scan the page for all code and
produce a migration plan.
→ Continue to Step 2: Scan Page for Code.
The user provided one of:
source/code-examples/
or source/includes/code-examples/)→ Skip to Step 3: Determine Language and Topic (one item to migrate).
Read the reference file references/page-scanning.md for the full directive
classification table and literalinclude path resolution process.
In summary: scan the RST/TXT file for all literalinclude, code-block, and
io-code-block directives. Classify each as already-tested (skip), untested
file, inline code, or external test repo. Present a migration plan table and
let the user select which items to migrate.
After the user selects items, process each one through Steps 3-11 below. For multiple items, process them sequentially and run the reviewer after each.
Grove currently supports these languages:
| Language | Suite directory |
|---|---|
| C# | csharp/driver/ |
| Go | go/driver/ |
| Java | java/driver-sync/ |
| JavaScript (Node.js) | javascript/driver/ |
| Mongosh | command-line/mongosh/ |
| Python | python/pymongo/ |
If the detected language is not in this list, flag it to the user and
ask them to review it manually — it is not eligible for Grove migration.
Language values in existing docs are sometimes incorrect (e.g., shell
used for JavaScript, javascript used for mongosh), so do not blindly
follow the :language: value.
If not specified by the user:
literalinclude
:language: option / code-block language argument. Verify it against the
supported list above.insertOne, propose crud/insert). Check the existing directory structure
under the language's examples/ dir — prefer placing the file in an
existing topic directory when a suitable one exists, rather than creating
a new directory for every migration.Confirm with the user if either is ambiguous.
Read these files in order to learn the target language's patterns:
code-example-tests/CLAUDE.md — cross-language patterns (Bluehawk tags,
Expect API, ellipsis patterns, sample data utilities)code-example-tests/javascript/driver/CLAUDE.md) — file naming, import
patterns, test framework, formatting rules.claude/skills/grove-create/references/conventions-{language}.md — the
conventions file for the target language, including Expect API method
signatures, import paths, and ellipsis patternsIf no CLAUDE.md exists for the target language, read 2-3 existing example and test files (sorted by most recent git modification date) to learn conventions by example.
Before creating new files, search for existing related examples:
examples/{topic}/**/*insertOne, aggregate) or
collection names in the examples directoryIf a related example exists, present options to the user:
Analyze the source code's data dependencies and classify:
| Source code pattern | Strategy | Next step |
|---|---|---|
Queries existing data (e.g., find on movies) | Sample data — propose the matching sample database (e.g., movies → sample_mflix) and confirm | Proceed normally |
| Uses placeholder data but user wants sample data | Sample data with adaptation — suggest a sample database from the list below and confirm | Proceed to Step 6a |
| Inserts its own data, then operates on it | Custom data — record database/collection names for teardown | Proceed normally |
| Ambiguous (generic collection name) | Ask the user to clarify | — |
Available sample databases: Read the sample data table in
code-example-tests/CLAUDE.md for the full list of databases, their
collections, and recommended use cases. When proposing a sample database,
suggest the one whose collections and data shape best match the operations
in the source code.
This decision affects the example code (database/collection names), the test
wrapper (describeWithSampleData vs. standard describe), and the teardown
strategy (do NOT drop sample databases).
Skip this step if the source code already uses the target sample dataset, or if the user chose custom data.
Read references/data-adaptation.md for the full data adaptation workflow.
It covers schema discovery, field mapping, operation-pattern preservation, and
expected output generation.
In summary: adapt the code's collection names, filter fields, projections, and sort keys to match real sample data fields. Keep the same operation types (a filtered find stays a filtered find). Record each change as a "Data adaptation" discrepancy so the user can verify the mappings.
Identify all changes needed to convert the source code to a Grove example. Track each change as a discrepancy to report later. Discrepancies fall into two categories:
Infrastructure changes (hidden from docs reader via :remove:, :replace:,
or :uncomment: tags — anything test-only or internal-only must be hidden):
process.env.CONNECTION_STRING, hidden
via :replace: terms (e.g., "process.env.CONNECTION_STRING": "\"<connection string URI>\"")export
keyword via :replace: terms if the suite convention does so:remove: lineclient.close() in finally/defer:uncomment: for the console.log (commented out
in test, uncommented in snippet) and :remove: for the return value that
replaces it. Use :uncomment: sparingly — it means the snippet differs
slightly from what was tested.literalinclude used :start-after: /
:end-before:, replace those markers with Bluehawk :snippet-start: /
:snippet-end: tags. The full file is migrated (the function must be
complete), but only the relevant section is within snippet tags. Do not
carry forward :start-after: / :end-before: — Bluehawk snippet
extraction replaces that mechanism. Also do not use :dedent: —
Bluehawk already handles indentation during extraction.Data adaptations (visible in the docs snippet — from Step 6a):
For each change, record:
Apply all identified transformations. Read 2-3 existing example files in the
target language (sorted by most recent git modification date) to see the
exact Bluehawk tag patterns before writing yours — especially the
:replace-start: block at the top of the file and the :uncomment: /
:remove: patterns used throughout.
:snippet-start: / :snippet-end:):replace-start: block at the top matching the suite's existing
pattern (substitutes env vars, export keywords, and other internal details
with reader-friendly values in the extracted snippet):remove: tags — anything internal-only or
test-only must be in a :remove: line or block:uncomment: for code that should appear in the docs snippet but would
break the test if executed (e.g., console.log replaced by a :remove:'d
return, or run().catch(console.dir) as an entry point). Use sparingly.dropDatabase(). For sample data, do NOT drop the sample
database.Preserve the original code's intent. The snippet that appears in docs after
Bluehawk processing should look as close to the original code as possible.
Preserve the data types used in the original code — if the original uses
typed models or specific BSON types, the migrated code should too. If a type
change is unavoidable (e.g., switching from a typed model to BsonDocument
because no equivalent model exists in the test suite), record it as a
discrepancy and call it out explicitly to the user.
Output files are not required. Create one when the original code shows output
in documentation (e.g., an .. output:: block in an io-code-block) or the
test validates structured results that benefit from a file-based baseline.
If you create an output file:
"..." for _id, timestamps, etc.)Check existing test files in tests/{topic}/:
it blocksit blocks, or the
example demonstrates a different operation category (e.g., aggregation vs.
CRUD)describeWithSampleData /
itWithSampleData for JS)afterEach to drop the test database (for custom data) — do NOT drop
sample databasesit block: call the example function, capture the return value,
validate with the appropriate Expect method (shouldMatch for file-based
comparison, shouldResemble().withSchema() for variable output)Launch a subagent with the Agent tool using this prompt (fill in the paths).
Use test commands from /grove-run Step 3:
Validate a migrated Grove code example. Perform these steps in order:
1. Run the test:
cd {language-driver-dir} && {test-command} {test-file-path}
2. If the test FAILS: Report the full error output. Do NOT attempt to fix it.
3. If the test PASSES: Run it a second time to verify idempotency.
4. Run the snip command:
cd {language-driver-dir} && {snip-command}
(This validates Bluehawk markup — unbalanced tags will cause errors.)
5. Report:
- Test result (pass/fail, both runs)
- Snip result (success/failure, output paths)If the reviewer reports a failure, fix the issue and re-launch (max 3 attempts). After 3 failed attempts, stop and report the remaining error to the user with the full error output, what you tried, and what you suspect the root cause is. Do not continue trying.
After verification passes, provide a report headed with Skill: grove-migrate:
| Change | Category | Reason |
|--------|----------|--------|
| Wrapped in `deleteDocuments()` function | Infrastructure | Grove requires exported functions |
| Replaced hardcoded URI with env var | Infrastructure | Security, portability |
| Added `return result` | Infrastructure | Required for test validation |
| `myCollection` → `movies` | Data adaptation | User chose sample_mflix |
| `{ status: 'active' }` → `{ year: { $gt: 2000 } }` | Data adaptation | Adapted filter to sample data schema |:remove: tags). Data adaptation changes will
appear in the snippet — call these out explicitly so the user can verify
the adapted code still illustrates the intended conceptliteralinclude path for the new tested snippetliteralinclude directive that replaces
the old one. Always include :category: — the value is almost always
usage example for Grove-migrated code. Other valid categories are
non-mongodb command, syntax example, example return object,
configuration object (all subtypes of snippet), and
sample application (complete runnable programs). For example:
.. was: .. literalinclude:: /includes/code-examples/insert-one.js
.. literalinclude:: /code-examples/tested/javascript/driver/crud/insert/insert-one.snippet.insert-one.js
:language: javascript
:copyable: true
:category: usage examplecontent/) for references to the old untested file path.
List every page that references it so the user knows which pages need
updating. If surrounding text on those pages refers to specific variable
names, collection names, or values from the old example that changed
during migration, flag those for the user to review.When migrating multiple items from a single page, provide a summary table after all items are processed:
## Migration Summary: content/node/current/source/crud/insert.txt
| # | Original Source | Grove Example | Test | Status |
|---|----------------|---------------|------|--------|
| 1 | /includes/code-examples/insert-one.js | examples/crud/insert/insert-one.js | tests/crud/insert.test.js | Migrated |
| 2 | /includes/code-examples/insert-many.js | examples/crud/insert/insert-many.js | tests/crud/insert.test.js | Migrated |
| 3 | Inline (lines 45-62) | examples/crud/insert/bulk-write.js | tests/crud/insert.test.js | Migrated |
All tests pass (2/2 runs each). Run `npm run snip` to generate snippets.literalinclude uses :start-after: and
:end-before:, replace those markers with Bluehawk :snippet-start: /
:snippet-end: tags. The full file is migrated (the function must be
complete), but only the relevant section is within snippet tags.5985af5
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.