t1k:opencode-harness
| Field | Value |
|---|---|
| Module | t1k-harness |
| Version | 1.2.1 |
| Effort | low |
| Tools | — |
Keywords: AGENTS.md, convert, cross-harness, harness, migrate, multi-harness, opencode, opencode.json, plugin, portable, zen
How to invoke
Section titled “How to invoke”/t1k:opencode-harness[paths | plugins | mapping | drift]OpenCode Harness — T1K’s Second Target
Section titled “OpenCode Harness — T1K’s Second Target”T1K is authored for Claude Code and shipped to more than one harness. This skill is the standing reference for the OpenCode target, so nobody re-researches it.
The facts are not in this file. They live in a pinned fixture with a companion check, because a reference doc that nobody re-verifies is a doc that quietly goes wrong:
| You need | Read |
|---|---|
| Scan paths, per asset class, per scope | data/opencode-paths.json (the fixture — SSOT) |
| The same, in prose, with the upstream citation | references/paths-and-formats.md |
| Plugin API — events, signatures, what has no Claude equivalent | references/plugin-api.md |
| Claude asset → OpenCode asset, field by field | references/claude-mapping.md |
Never quote a path from memory or from opencode.ai docs. Quote the fixture.
The four things that catch people
Section titled “The four things that catch people”1. Skills need no conversion. OpenCode scans Claude’s skill directories directly. A T1K skill works in OpenCode unchanged. Converting them is not just wasted work — it creates a second copy that drifts from the first.
2. That native fallback hides broken conversions. Because OpenCode also reads
.claude/skills/ and CLAUDE.md, a converter writing skills to the wrong
directory still appears to work. The feature is being served by the fallback,
not by the code under test. Verify a conversion by asking OpenCode what it
loaded, never by checking that a file exists. This happened for real:
.opencode/skill shipped singular against a harness that scans skills/, in two
separate registries, with no test pinning either form and no CI gate running the
suite that would have noticed — invisible precisely because the native fallback
served the same content anyway.
3. Frontmatter does not survive a copy. Claude and OpenCode accept different
field sets on an agent. A byte-for-byte copy is not a conversion; it is a file the
target parses under different rules. See references/claude-mapping.md for the
field-by-field table and the fields that have no counterpart.
4. Hooks are the real boundary. Claude’s hooks are subprocesses with a
stdin-JSON / exit-code contract. OpenCode’s plugins are in-process JS/TS modules
on a different event set. Tool events map cleanly. Prompt-time injection has
plausible candidates that nobody has yet run. SubagentStop and the
model-router’s PreToolUse: Task interception have no identified counterpart at
all. references/plugin-api.md holds the current mapping and names each gap by
name — read it before promising any hook-dependent behavior on OpenCode.
Workflows
Section titled “Workflows”Converting T1K assets to OpenCode
Section titled “Converting T1K assets to OpenCode”- Read the fixture for the target paths. Do not hardcode them.
- Skip skills — they are already portable. Converting them is a defect.
- Convert agent and command frontmatter per
references/claude-mapping.md; a straight copy is not acceptable. - Rules and
CLAUDE.mdmerge intoAGENTS.md. Content naming Claude-only machinery (hooks, Claude-specific tool names, slash commands) must be rewritten or dropped — not silently carried across. - Verify by discovery, not by presence: launch OpenCode against the output and confirm it lists the asset.
An asset OpenCode won’t load
Section titled “An asset OpenCode won’t load”Check in this order: (a) is it in a directory the fixture says is scanned, at the
right scope? (b) does the frontmatter validate against OpenCode’s schema, not
Claude’s? (c) is a native Claude-path fallback silently serving an older copy of
the same asset from .claude/? (d) has upstream moved — run the drift check.
Re-pinning after upstream drift
Section titled “Re-pinning after upstream drift”node "$CLAUDE_DIR/scripts/harness-drift-check.cjs" --harness opencodeOn failure, per pinned-baseline-test-companion.md, determine the direction
before touching the fixture:
- Upstream moved — read the upstream diff, update the fixture AND every converter that depended on the old value, in the same commit.
- Our pin was always wrong — this is a defect that has been shipping. Find what it broke, and check whether a native fallback was masking it.
- Unreachable — a network failure is not a drift. Do not re-pin.
Never set the fixture to whatever the run just reported. That converts a finding into a baseline.
Constraints
Section titled “Constraints”- The fixture is the single source of truth for paths. A path string anywhere else in T1K is a duplicate to be removed.
- Every pinned value records the upstream file and commit it came from. A value without a citation is unverified and must be marked as such.
- Assets that cannot port declare themselves by name in the fixture’s
unmappablelist. Omitting them reads as full support.
Related
Section titled “Related”wired-not-just-present.md·green-that-proves-nothing.md— why “the file is there” is not evidence.pinned-baseline-test-companion.md— the fixture’s companion obligation.