plugins/lisa/skills/cross-pollinate/SKILL.md
Detect a host project's locally-authored coding-agent definitions (skills, subagents, rules, commands, hooks, MCP) and make each available in the formats of the OTHER agents the project supports, as declared in .lisa.config.json. Any-to-any, provenance-tracked, idempotent, never clobbers hand-edited output.
npx skillsauth add codyswanngt/lisa cross-pollinateInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A host project that installs Lisa may hand-author a definition for one coding
agent — a .claude/skills/foo, a .cursor/rules/bar.mdc, an MCP server only
Claude sees. /lisa:cross-pollinate detects those locally-authored definitions
and regenerates each in the formats of the other agents the project supports,
so the whole fleet stays in parity with what a developer wrote for any single one.
any agent's format -> Claude-format IR -> every OTHER configured agent
Claude format is the canonical intermediate representation (IR) because every Lisa generator already sources from it. So translation is always: normalize the detected definition up to Claude-format IR, then fan that IR out to each target agent using the documented mappings below. Never translate format A → B directly — that multiplies error and loses fidelity on every hop.
The agents a project supports come from .lisa.config.json harness
(claude | codex | cursor | agy | copilot | opencode | both | fleet;
all is an alias for fleet). Only emit to agents that harness includes.
.lisa/cross-pollination.lock.json (committed) is the source of truth for what
this skill generated. Location heuristics cannot work: a generated Cursor
rule sits in the same .cursor/rules/ directory as a hand-authored one. The
lockfile is the only reliable way to enforce the four invariants:
target is NEVER treated as a source on
the next run. Without this, today's output becomes tomorrow's input and
translations ping-pong forever.generatedHash, a human edited it. Stop and report;
do not overwrite. They may have intentionally diverged, or want to adopt the
edit as a new source.lisa apply.)Lockfile shape:
{
"version": 1,
"entries": {
"skill:security-review": {
"source": { "agent": "claude", "path": ".claude/skills/security-review", "hash": "…" },
"targets": [ { "agent": "codex", "path": ".claude/skills/security-review/agents/openai.yaml", "generatedHash": "…" } ]
}
}
}
The logicalId is <kind>:<name> — stable across formats. It links a source to
its targets and detects collisions: the same logicalId authored
independently in two agents (neither generated). On a collision, NEVER
auto-translate over either side — report it and let the human pick the source of
truth.
The deterministic core (scan, provenance, loop/GC/drift/conflict detection, and the skill + MCP emitters) is a bundled engine. Always run it first — it does the safe, mechanical work and tells you exactly what is left for you to translate by hand.
# dry-run (default): report only, writes nothing
node "${CLAUDE_PLUGIN_ROOT}/scripts/cross-pollinate.mjs" "$PROJECT_ROOT" --json
# apply the deterministic emits + update the lockfile
node "${CLAUDE_PLUGIN_ROOT}/scripts/cross-pollinate.mjs" "$PROJECT_ROOT" --write
In the Lisa source repo itself the path is
node plugins/lisa/scripts/cross-pollinate.mjs (built) or
node plugins/src/base/scripts/cross-pollinate.mjs (source).
The JSON report has four lists you act on:
emits — already handled by --write (skills, MCP). Verify, don't redo.conflicts — STOP. Report each to the user; do not translate.orphans — GC'd by --write. Confirm the removals look right.pending — your job. Definitions whose target format the engine does not
emit deterministically. Translate each per the mappings below, then record
provenance (see "Recording provenance").pending translation)Normalize the source to Claude-format IR first, then emit per target:
.claude/rules/<name>.md; Cursor reads .cursor/rules/<name>.mdc with YAML
frontmatter (description from the first H1, alwaysApply: true) and intra-rule
link extensions rewritten. You do not translate these — verify the engine's
emits.pending): project rules are delivered via
AGENTS.md, not a per-rule file. MERGE the rule content into AGENTS.md under a
stable marked section rather than writing a separate file (so re-runs replace,
not append). agy never gets a duplicate rule file (rules-once).pending): .github/copilot-instructions.md (inline). Merge into a
marked section, don't scatter.agents/<name>.md (or .claude/agents/).agents/<name>.agent.md (note the .agent.md suffix)..claude/commands/…).PreToolUse→preToolUse/beforeSubmitPrompt,
UserPromptSubmit→userPromptSubmitted, Stop→agentStop/stop, …).SessionStart/SubagentStart — only PreToolUse (e.g.
block-no-verify) is portable. Everything else: dropped — unsupported.codex exec — install into
~/.codex/hooks.json, not a bundled file.SubagentStart/empty-matcher
entry is present — drop that event wholesale..mcp.json. Cursor: .cursor/mcp.json (same JSON shape).mcpServers object in the plugin manifest (bundled
.mcp.json is ignored). Codex: TOML / .codex-plugin pointer.
agy/OpenCode: user-global installer / .opencode. The engine reports these
as pending; translate per the target's documented shape or report dropped.pending itemsAfter you write a target by hand, it MUST be recorded in
.lisa/cross-pollination.lock.json or the next run will treat it as a source
(loop) or fail to GC it. Re-run the engine after staging your translated files —
on its next pass it adopts and hashes any target already referenced — OR add the
entry yourself following the lockfile shape above (compute generatedHash as the
sha256 of the written file/dir). Prefer the engine; only hand-edit the lock if
the engine cannot infer the mapping.
Report, concisely:
.lisa/cross-pollination.lock.json was updated and the working tree
otherwise contains only intended changesharness includes.tools
--- name: harper-realtime description: This skill should be used when adding or troubleshooting Harper (HarperDB/Fabric) real-time behavior: MQTT topics, WebSocket resource subscriptions, resource publish/subscribe handlers, SSE-style streaming routes, and local subscriber verification. Pairs with harper-resources, harper-config-yaml, harper-schema-graphql, and harper-build-and-deploy. --- # Harper Realtime ## Overview Harper exposes live data through the same Resource model used for REST and
tools
--- name: harper-realtime description: This skill should be used when adding or troubleshooting Harper (HarperDB/Fabric) real-time behavior: MQTT topics, WebSocket resource subscriptions, resource publish/subscribe handlers, SSE-style streaming routes, and local subscriber verification. Pairs with harper-resources, harper-config-yaml, harper-schema-graphql, and harper-build-and-deploy. --- # Harper Realtime ## Overview Harper exposes live data through the same Resource model used for REST and
tools
--- name: harper-realtime description: This skill should be used when adding or troubleshooting Harper (HarperDB/Fabric) real-time behavior: MQTT topics, WebSocket resource subscriptions, resource publish/subscribe handlers, SSE-style streaming routes, and local subscriber verification. Pairs with harper-resources, harper-config-yaml, harper-schema-graphql, and harper-build-and-deploy. --- # Harper Realtime ## Overview Harper exposes live data through the same Resource model used for REST and
tools
--- name: harper-realtime description: This skill should be used when adding or troubleshooting Harper (HarperDB/Fabric) real-time behavior: MQTT topics, WebSocket resource subscriptions, resource publish/subscribe handlers, SSE-style streaming routes, and local subscriber verification. Pairs with harper-resources, harper-config-yaml, harper-schema-graphql, and harper-build-and-deploy. --- # Harper Realtime ## Overview Harper exposes live data through the same Resource model used for REST and