.agents/skills/editor-test-harvester/SKILL.md
Use this skill when mining another editor repository for tests worth harvesting:
Lexical, ProseMirror, CodeMirror, Tiptap, Monaco, Quill, or any local clone under
...
The job is not to clone their framework. The job is to extract portable editor behavior proof and route it to the right owner: raw Slate v2 substrate or Plate packages, kits, examples, and docs.
This follows the ClawSweeper method and the goal-plan confidence model: source-first, exhaustive inventory, explicit skip reasons, evidence rows, scored passes, narrow claims, license-aware invariant extraction, then implementation only when asked.
Read these first:
LICENSE, LICENCE, COPYING, NOTICE,
package metadata, or workspace metadata.../lexical..tmp/slate-v2 current test files and package scripts.docs/solutions/ for prior browser, IME, selection, and mobile proof lessons..agents/skills/clawsweeper/SKILL.md for issue/PR provenance discipline
when a test exists because of a known upstream bug.Never browse GitHub files. If the target is owner/repo and the checkout is
missing, clone it to ../repo-name.
Before harvesting behavior, classify the target repo license from local source
files only: LICENSE, LICENCE, COPYING, NOTICE, package metadata, or
workspace metadata.
Use one of these modes:
permissive: MIT, BSD-2-Clause, BSD-3-Clause, Apache-2.0, ISC, CC0, or
clearly equivalent permissive licensing.behavior-only: GPL, LGPL, AGPL, MPL, EPL, CDDL, proprietary, commercial,
source-available, mixed/unclear licensing, missing license evidence, or any
repo whose tests are not clearly permissively reusable.Output location:
permissive: write harvest artifacts under
docs/editor-test-harvester/<repo>/.behavior-only: write harvest artifacts under
.tmp/editor-test-harvester/<repo>/..tmp/editor-test-harvester/<repo>/ is unversioned scratch space. It may contain
source-adjacent notes, detailed provenance, raw local observations, and working
material needed to understand the source repo.
The strict invariant-only rule applies when producing versioned or durable
project output from a behavior-only source:
behavior-only.Rule of thumb: study the wound, don’t transplant the skin.
behavior-only does not block learning from non-permissive, source-available,
or unclear-license projects. It blocks copying into versioned Plate/Slate output.
The local proof should show that the implementation was independently expressed
from the invariant, not pasted or mechanically ported from upstream source.
docs/editor-test-harvester/<repo>/.behavior-only targets, write unversioned scratch artifacts under
.tmp/editor-test-harvester/<repo>/.behavior-only targets, copying source material inside .tmp is allowed
as scratch provenance, but copying it into versioned Plate, Slate, docs,
examples, commits, or PRs is forbidden.behavior-only targets, every versioned behavior row, implementation,
docs note, and test must be rewritten as a fresh invariant in local language,
with only source path/line provenance.behavior-only repo into
versioned output. The valid versioned actions are invariant extraction, fresh
local proof, defer, or skip.docs/editor-test-harvester/<repo>/ for permissive targets, or
.tmp/editor-test-harvester/<repo>/ for behavior-only targets.behavior-only targets, inventory.md and test-index.md also stay
under .tmp/editor-test-harvester/<repo>/. Never create or refresh
docs/editor-test-harvester/<repo>/inventory.md.docs/plans/ for normal harvest output.behavior-only targets, do not paste, mechanically translate, or preserve
upstream fixture/helper shape in versioned output. Write the strongest fresh
local proof for the invariant, with source path references only.plate-owned when the useful behavior should fit Plate, not raw Slate.
Examples: link/autolink grammar, list/checklist policy, markdown transformer
UX, mention/hashtag/emoji/date-time plugins, media/product decorators,
toolbar/menu state, React plugin hosts, NodeView/PluginView-style authoring,
and rich product examples..tmp/slate-v2. Split substrate proof from
plugin policy: raw Slate owns editor primitives; Plate owns opinionated
features, integration ergonomics, and product-facing behavior..tmp/slate-v2 unless the user asks for apply/copy/fix execution.pending while more autonomous harvest/review passes remain. Use done
only after the closure score passes or when the user explicitly asked for a
quick/first-pass report and the report says so in the verdict.Use an agent-native goal for comprehensive harvests, long-running reruns, and
apply runs. Always call get_goal first. Call create_goal only when no active
matching goal exists. There can be only one active goal per thread.
Create the harvest goal plan from the project template:
node .agents/rules/autogoal/scripts/create-goal-scratchpad.mjs \
--template editor-test-harvester \
--title "<Repo> Editor Test Harvest"
The generated docs/plans file is the durable pass-state ledger, scratch log,
decision record, verification ledger, and completion checklist. Do not create
hook state.
The harvest report itself still lives in the license-selected report directory:
permissive: docs/editor-test-harvester/<repo>/report.mdbehavior-only: .tmp/editor-test-harvester/<repo>/report.mdRecord this state in the active goal plan:
target_repo: <path>
repo_key: <repo>
license_mode: permissive|behavior-only
output_mode: durable|scratch
report_path: <docs/.../report.md or .tmp/.../report.md>
inventory_path: <report_dir>/inventory.md
test_index_path: <report_dir>/test-index.md
current_pass: <pass-name>
current_pass_status: in_progress
current_pass_skill: .agents/skills/editor-test-harvester/SKILL.md
next_pass: <next-pass>
Set done only when:
>= 0.92;0.85;covered, refactor-existing, create-new, copy-now, defer, and
plate-owned action has a raw Slate owner, Plate owner, or explicit gap;If any gate fails but more work is possible, keep pending and write the active
goal plan with the next harvest pass. Use blocked only when the target repo,
Slate v2 checkout, required browser/device tooling, or a user decision is
missing and no useful autonomous pass remains.
Score each harvest pass from 0.00 to 1.00.
| Dimension | Weight |
|---|---|
| Inventory completeness | 0.20 |
| Behavior extraction depth | 0.20 |
| Skip precision and negative controls | 0.15 |
| Slate/Plate coverage mapping accuracy | 0.20 |
| Actionability of copy/refactor/create plan | 0.15 |
| Provenance and reproducibility | 0.10 |
Score caps:
0.75 unless the report records the
exact inventory command, total count, classified count, and unresolved count.0.90 unless every test file path appears
in a full inventory appendix or linked inventory file.0.75 if portable files were routed
only by file name.0.85 unless all portable and
portable-mixed runnable files have test-name extraction with line pointers.0.85 for behavior-only targets
unless the report separates scratch provenance from versioned-output
invariants.0.80 unless every skipped file or skip family
has a concrete reason and at least one negative-control example was read.0.80 unless the report records
the .tmp/slate-v2 search commands for raw rows and the current Plate owner or
explicit Plate gap for plate-owned rows.0.80 unless every create/refactor/copy row names
a target test file, proof kind, and focused verification command, and every
plate-owned row names the likely Plate package, kit, example, docs, or
backlog owner.0.80 when issue/PR-linked upstream regression tests
are used without ClawSweeper-style exact thread or local source rationale.0.80 for behavior-only targets unless the report
records license evidence, output directory, and versioned-output copy policy.0.88 if the report has no pass-state ledger.0.90 if the full inventory appendix is absent.Completion threshold:
>= 0.92;0.85;uncertain test files remain;behavior-only targets, no versioned report, test, docs, fixture,
snapshot, or implementation output contains copied or mechanically translated
upstream source material.Below threshold, the report can still be useful, but it must say first-pass,
partial, or pending and name the next owner.
Run harvests as passes, not one giant skim:
describe / it / test names for every runnable portable,
portable-mixed, and uncertain file;behavior-only targets, record raw/source-adjacent extraction only in
.tmp; convert anything that leaves .tmp into short paraphrased
provenance.behavior-only targets, scratch extraction may live in .tmp, but any
versioned row or implementation must be rewritten as a fresh local
invariant..tmp/slate-v2 by behavior keywords and adjacent concepts;covered, refactor-existing, create-new, copy-now, defer,
plate-owned, or skip;behavior-only targets, copy-now means "write a fresh local proof
from the invariant" when producing versioned output.done only if gates pass.Pass-state ledger rows must include:
pending, in_progress, or complete;Resolve the target repo:
test -d ../lexical || git clone https://github.com/facebook/lexical.git ../lexical
Classify license mode before creating report artifacts:
target="../lexical"
mapfile -t license_files < <(
{
find "$target" -maxdepth 2 -type f \
\( -iname 'LICENSE*' -o -iname 'LICENCE*' -o -iname 'COPYING*' -o -iname 'NOTICE*' \)
find "$target" -maxdepth 3 -type f \
\( -name 'package.json' -o -name 'pnpm-workspace.yaml' -o -name 'package.yaml' \)
} | sort -u
)
mkdir -p .tmp/editor-test-harvest-license
printf '%s\n' "${license_files[@]}" > .tmp/editor-test-harvest-license/files.txt
if [ "${#license_files[@]}" -gt 0 ] && \
rg -i 'MIT License|Apache License|BSD 2-Clause|BSD 3-Clause|ISC License|CC0|SPDX-License-Identifier:\s*(MIT|Apache-2.0|BSD-2-Clause|BSD-3-Clause|ISC|CC0-1.0)|"license"\s*:\s*"(MIT|Apache-2.0|BSD-2-Clause|BSD-3-Clause|ISC|CC0-1.0)"' \
"${license_files[@]}" >/dev/null && \
! rg -i 'GPL|AGPL|LGPL|MPL|EPL|CDDL|commercial|proprietary|source-available|Business Source|Elastic License|Server Side Public License|SSPL' \
"${license_files[@]}" >/dev/null; then
license_mode="permissive"
else
license_mode="behavior-only"
fi
echo "license_mode=$license_mode"
cat .tmp/editor-test-harvest-license/files.txt
If license evidence is missing, mixed, or unclear, use behavior-only.
Resolve the stable harvest directory:
repo_key="$(basename "$target" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9._-' '-')"
if [ "$license_mode" = "behavior-only" ]; then
report_dir=".tmp/editor-test-harvester/${repo_key}"
else
report_dir="docs/editor-test-harvester/${repo_key}"
fi
mkdir -p "$report_dir"
For owner/repo targets, use the cloned repo basename as <repo>. If
report.md, inventory.md, or test-index.md already exists in the chosen
license-mode report directory, read them before inventory and treat the run
as an update. The rerun must look for new and removed test files in the target
checkout, then rewrite the same stable files.
Capture repo basics without starting with git state:
rg --files "$target" | rg '(^|/)(package.json|bun.lock|pnpm-lock.yaml|yarn.lock|vitest|jest|playwright|wdio|cypress)'
Build the exhaustive test inventory:
rg --files "$target" \
| rg '(^|/)(__tests__|test|tests|spec|e2e|integration|playwright|cypress|wdio|fixtures)(/|$)|\.(test|spec)\.[cm]?[jt]sx?$' \
| rg -v '(^|/)(dist|build|coverage|node_modules|vendor|fixtures/generated|__snapshots__)(/|$)'
Classify every inventory row and record it in the appendix:
portable: proves framework-agnostic editor behavior.portable-mixed: contains raw editor behavior plus framework/product
policy that must be split before action.plate-owned: useful behavior, but the right owner is Plate, not raw
Slate v2.skip: framework internals, command registry, node-class mechanics,
product UI, build tooling, or test harness only.harness: reusable testing technique, but no product behavior assertion.product-shell: app/demo behavior outside raw editor substrate.uncertain: needs a read before routing.Extract test names for all runnable portable, portable-mixed, and uncertain files:
rg -n "(describe|it|test)\\(" <target-test-files>
Read all portable and uncertain files. For huge files, index test names first, then read the relevant ranges.
Extract behavior rows. Use behavior words, not upstream class names.
Search .tmp/slate-v2 for equivalent coverage using behavior keywords and
adjacent concepts. Do not stop at exact upstream names.
Search Plate packages, kits, examples, and docs when behavior belongs to product/plugin policy rather than raw Slate substrate.
Assign one owner action per portable row:
covered: current Slate v2 or Plate test fully proves the invariant.refactor-existing: related coverage exists but needs split, rename,
stronger assertions, or browser proof.create-new: no adequate coverage; propose the target test location.copy-now: user asked to apply, the invariant is safe to implement now,
and the target is permissive. For behavior-only targets, this means
"write a fresh local proof from the invariant" for versioned output, never
copy upstream code, fixtures, snapshots, helpers, or expressive prose into
Plate, Slate, docs, examples, commits, or PRs.defer: requires unavailable raw device/browser/tooling proof.plate-owned: route to Plate package, kit, example, docs, or backlog owner.skip: after reading, it is not portable enough.Use these tags consistently:
ime-compositionbeforeinput-inputcomposition-selection-repairselection-dom-mappingclipboard-pastedrag-drophistory-undo-redonormalization-schemadelete-backspaceinsert-fragmentmarks-inlinevoid-atomtables-griddecorations-overlayscollaboration-remoteperformance-large-docaccessibility-keyboardserialization-parsingbrowser-enginemobile-devicefocus-blurshadow-dompagination-layoutstructured-blocksmarkdown-richtext-roundtripPortable examples:
Skip examples:
behavior-only repos that cannot be reduced
to a fresh invariant without preserving expressive source material.Plate-owned examples:
For report-only runs, choose the output directory by license mode:
# permissive
docs/editor-test-harvester/<repo>/report.md
# behavior-only
.tmp/editor-test-harvester/<repo>/report.md
behavior-only reports are unversioned scratch artifacts. They may contain
detailed local research notes. They must not be copied into durable project docs
without rewriting into fresh invariant language.
Use stable companion files in the same directory:
<report_dir>/inventory.md
<report_dir>/test-index.md
For behavior-only targets, <report_dir> means
.tmp/editor-test-harvester/<repo>. Do not write inventory or test-index files
to docs/editor-test-harvester/<repo>/.
Do not include the date in file names. Put run dates, inventory commands, source checkout path, source revision/provenance, license mode, and license evidence inside the report instead.
If a previous harvest exists in the chosen license-mode report directory, rewrite these files in place and add a rerun/update note that names newly discovered and removed target test files.
Use this shape:
# Editor Test Harvest: <repo>
status: pending|first-pass done|done
score: 0.xx
license_mode: permissive|behavior-only
license_evidence: `<path/to/LICENSE or package metadata>`
output_mode: durable|scratch
versioned_copy_policy: normal|fresh-invariant-only
## Inventory
- target: `<path>`
- test files found: N
- portable: N
- portable-mixed: N
- plate-owned: N
- skipped: N
- harness/product/uncertain: N
## License Gate
| Field | Value |
| --------------------- | ---------------------------------- |
| License mode | `permissive` or `behavior-only` |
| Evidence files | `<local paths>` |
| Output directory | `docs/...` or `.tmp/...` |
| Output mode | `durable` or `scratch` |
| Versioned copy policy | `normal` or `fresh-invariant-only` |
For `behavior-only` targets, this report is scratch material. Anything promoted
from it into versioned Plate/Slate output must be rewritten as a fresh invariant
and local proof.
## Confidence Score
| Dimension | Score | Evidence | Cap hit |
| --------- | ----: | -------- | ------- |
## Pass-State Ledger
| Pass | Status | Evidence added | Report delta | Open issues | Next owner |
| ---- | ------ | -------------- | ------------ | ----------- | ---------- |
## Matrix
| Source ref | Test ref | Tag | Behavior invariant | Proof kind | Owner coverage | Action |
| ---------------- | ---------- | ----------------- | ------------------ | ----------------------- | ----------------------------------------- | ------------------------------------------------------ |
| `../lexical/...` | `test ref` | `ime-composition` | ... | browser/unit/raw-device | `.tmp/slate-v2/...`, Plate owner, or none | covered/refactor-existing/create-new/defer/plate-owned |
For `behavior-only` targets, `Source ref` and `Test ref` are scratch provenance.
Any versioned output derived from `Behavior invariant` must be rewritten locally.
## Skips
| Source | Reason |
| ---------------- | ------------------------------------------------------------ |
| `../lexical/...` | Framework node-class invariant, no portable editor behavior. |
## Next Slice
1. Refactor existing ...
2. Create new ...
3. Defer raw-device ...
## Full Inventory Appendix
| Source | Runnable | Category | Reason | Test-name extraction |
| ------ | -------- | -------- | ------ | -------------------- |
If the inventory appendix is too large, write it to:
<report_dir>/inventory.md
Then link it from the main report. Do not omit it.
Write the extracted portable/portable-mixed test-name index to:
<report_dir>/test-index.md
For apply runs, edit .tmp/slate-v2 or Plate tests only after the matrix exists.
Keep the implementation slice small enough to verify.
Source comments are useful only when they explain the behavior being protected.
Do not make tests read like upstream changelogs. For behavior-only targets,
source comments in versioned output must not quote or closely paraphrase
upstream test bodies, fixtures, snapshots, expected output blobs, or expressive
prose.
Report-only verification:
# Set this from the license gate.
# permissive:
report_dir="docs/editor-test-harvester/<repo>"
# behavior-only:
report_dir=".tmp/editor-test-harvester/<repo>"
rg --files <target> | rg '<test inventory pattern>' | wc -l
rg -n "License Gate|Confidence Score|Pass-State Ledger|Matrix|Skips|Next Slice|Full Inventory Appendix" "$report_dir/report.md"
test -f "$report_dir/inventory.md"
test -f "$report_dir/test-index.md"
node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/<goal-plan>.md
Versioned-output hygiene check for behavior-only sources:
test ! -f "docs/editor-test-harvester/<repo>/inventory.md"
test ! -f "docs/editor-test-harvester/<repo>/test-index.md"
rg -n "copied from|verbatim|fixture copied|ported from" \
docs .tmp/slate-v2 packages apps examples 2>/dev/null && \
echo "Review versioned output for unsafe behavior-only wording" || true
Implementation verification in .tmp/slate-v2 or Plate:
bun check before claiming the applied slice is closed.bun check:full.behavior-only sources, verify that versioned local tests use local
fixtures, helpers, names, and assertions, not upstream test code or
mechanically ported fixture shape.Use ClawSweeper as the model for provenance work. If a test points at an upstream issue, PR, browser bug, or closed-thread rationale, apply the ClawSweeper bar: exact thread, exact behavior, no speculative closure claim, and no broad claim without current source proof.
When local issue archaeology is useful, use the gitcrawl command surface through that ClawSweeper discipline:
gitcrawl doctor --json
gitcrawl search issues "<behavior phrase>" -R <owner/repo> --state all --json number,title,state,url --limit 20
gitcrawl sync <owner/repo> --numbers <issue-or-pr-number> --include-comments --with pr-details --json
Treat gitcrawl as provenance and candidate generation only. The target repo test inventory still owns coverage accounting.
For behavior-only targets, issue/PR provenance may identify why a behavior
matters, but it still must not justify copying upstream code, fixtures,
snapshots, expected output blobs, or expressive test prose into versioned output.
Extract the invariant. Write the local proof fresh.