Add and ship OpenCode support for one Claude Code plugin at a time. Includes core migration to a reviewable `opencode-plugin/` adapter, maintainer-facing docs, and follow-up CI/versioning setup for package publishing or skill-copy drift checks.
92
92%
Does it follow best practices?
Impact
97%
1.25xAverage score across 2 eval scenarios
Passed
No known issues
The caveman project is a popular Claude plugin that gives Claude Code users a persistent terse communication mode, command shortcuts, and small hook scripts that keep mode state synchronized. OpenCode users want equivalent local support they can review before the maintainer decides whether to publish anything.
Work against the upstream source at https://github.com/JuliusBrussee/caveman pinned to commit 84cc3c14fa1e10182adaced856e003406ccd250d. If network access is available, fetch that exact commit and use it as the source. If network access is unavailable, reconstruct the compact pinned fixture from the files below and proceed from that source instead. Do not use an unpinned latest branch as the migration source.
Create or update files in the working repository so the maintainer has reviewable OpenCode support and tests. Include a concise migration note at OPENCODE_SUPPORT.md that records the source commit, the surfaces you found, the support decisions, and how to run the verification you added.
Leave the completed migrated repository in the workspace. If you downloaded an archive or clone, keep only the migrated source tree and remove large temporary downloads before finishing.
The following files are provided as an offline fixture. Extract them into a source repository if you cannot fetch the pinned upstream commit.
=============== FILE: README.md ===============
Ultra-compressed communication mode for Claude Code. Cuts token usage while keeping technical accuracy by speaking like a caveman.
Upstream: https://github.com/JuliusBrussee/caveman
Pinned commit: 84cc3c14fa1e10182adaced856e003406ccd250d
=============== FILE: .claude-plugin/plugin.json ===============
{
"name": "caveman",
"description": "Ultra-compressed communication mode. Cuts ~75% of tokens while keeping full technical accuracy by speaking like a caveman.",
"author": {
"name": "Julius Brussee",
"url": "https://github.com/JuliusBrussee"
},
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/caveman-activate.js\"",
"timeout": 5,
"statusMessage": "Loading caveman mode..."
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/caveman-mode-tracker.js\"",
"timeout": 5,
"statusMessage": "Tracking caveman mode..."
}
]
}
]
}
}=============== FILE: .claude-plugin/marketplace.json ===============
{
"name": "caveman",
"plugins": [
{
"name": "caveman",
"path": ".claude-plugin/plugin.json"
}
]
}=============== FILE: .agents/plugins/marketplace.json ===============
{
"plugins": [
{
"name": "caveman",
"path": "plugins/caveman/.codex-plugin/plugin.json"
}
]
}=============== FILE: hooks/package.json ===============
{
"type": "commonjs",
"private": true
}=============== FILE: hooks/caveman-config.js ===============
const fs = require("fs");
const path = require("path");
const VALID_MODES = new Set(["lite", "full", "ultra", "wenyan", "wenyan-lite", "wenyan-ultra", "commit", "review", "compress", "off"]);
function getDefaultMode() {
return process.env.CAVEMAN_MODE || "full";
}
function safeWriteFlag(flagPath, mode) {
if (!VALID_MODES.has(mode)) return;
fs.mkdirSync(path.dirname(flagPath), { recursive: true });
fs.writeFileSync(flagPath, mode, "utf8");
}
function readFlag(flagPath) {
try {
const value = fs.readFileSync(flagPath, "utf8").trim();
return VALID_MODES.has(value) ? value : null;
} catch (e) {
return null;
}
}
module.exports = { getDefaultMode, safeWriteFlag, readFlag };=============== FILE: hooks/caveman-activate.js ===============
#!/usr/bin/env node
// caveman - Claude Code SessionStart activation hook
// Writes active mode state and emits model-visible startup context.
const fs = require("fs");
const path = require("path");
const os = require("os");
const { getDefaultMode, safeWriteFlag } = require("./caveman-config");
const claudeDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
const flagPath = path.join(claudeDir, ".caveman-active");
const mode = getDefaultMode();
if (mode === "off") {
try { fs.unlinkSync(flagPath); } catch (e) {}
process.stdout.write("OK");
process.exit(0);
}
safeWriteFlag(flagPath, mode);
let skillContent = "";
try {
skillContent = fs.readFileSync(path.join(__dirname, "..", "skills", "caveman", "SKILL.md"), "utf8");
} catch (e) {}
process.stdout.write("CAVEMAN MODE ACTIVE - level: " + mode + "\n\n" + (skillContent || "Respond terse like smart caveman. Technical substance stay."));=============== FILE: hooks/caveman-mode-tracker.js ===============
#!/usr/bin/env node
// caveman - UserPromptSubmit hook to track which caveman mode is active.
const fs = require("fs");
const path = require("path");
const os = require("os");
const { getDefaultMode, safeWriteFlag, readFlag } = require("./caveman-config");
const claudeDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
const flagPath = path.join(claudeDir, ".caveman-active");
let input = "";
process.stdin.on("data", chunk => { input += chunk; });
process.stdin.on("end", () => {
try {
const data = JSON.parse(input);
const prompt = (data.prompt || "").trim().toLowerCase();
if (prompt.startsWith("/caveman")) {
const parts = prompt.split(/\s+/);
const arg = parts[1] || "";
const mode = arg || getDefaultMode();
if (mode !== "off") safeWriteFlag(flagPath, mode);
else try { fs.unlinkSync(flagPath); } catch (e) {}
}
if (/\b(stop|disable|deactivate|turn off)\b.*\bcaveman\b/i.test(prompt) || /\bnormal mode\b/i.test(prompt)) {
try { fs.unlinkSync(flagPath); } catch (e) {}
}
const activeMode = readFlag(flagPath);
if (activeMode && !new Set(["commit", "review", "compress"]).has(activeMode)) {
process.stdout.write(JSON.stringify({
hookSpecificOutput: {
hookEventName: "UserPromptSubmit",
additionalContext: "CAVEMAN MODE ACTIVE (" + activeMode + "). Drop articles/filler/pleasantries/hedging. Code/commits/security: write normal."
}
}));
}
} catch (e) {}
});=============== FILE: hooks/caveman-statusline.sh ===============
#!/usr/bin/env bash
set -euo pipefail
flag="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/.caveman-active"
if [ -f "$flag" ]; then
mode="$(cat "$flag")"
printf '[CAVEMAN:%s]' "$mode"
fi=============== FILE: commands/caveman.toml ===============
description = "Switch caveman intensity level (lite/full/ultra/wenyan)"
prompt = "Switch to caveman {{args}} mode. If no level specified, use full. Respond terse like smart caveman - drop articles, filler, pleasantries. Fragments OK. Technical terms exact. Code unchanged. Pattern: [thing] [action] [reason]. [next step]."=============== FILE: commands/caveman-commit.toml ===============
description = "Generate a caveman-style conventional commit message"
prompt = "Write a concise conventional commit message for current changes. Keep subject under 50 chars. Body only when why not obvious."=============== FILE: commands/caveman-review.toml ===============
description = "Review code with terse actionable feedback"
prompt = "Review this diff. Findings first. Each comment one line: location, problem, fix."=============== FILE: skills/caveman/SKILL.md ===============
---
name: caveman
description: >
Ultra-compressed communication mode. Cuts token usage ~75% by speaking like caveman
while keeping full technical accuracy. Supports intensity levels: lite, full (default), ultra,
wenyan-lite, wenyan-full, wenyan-ultra.
Use when user says "caveman mode", "talk like caveman", "use caveman", "less tokens",
"be brief", or invokes /caveman. Also auto-triggers when token efficiency is requested.
---
Respond terse like smart caveman. All technical substance stay. Only fluff die.
## Persistence
ACTIVE EVERY RESPONSE. No revert after many turns. No filler drift. Still active if unsure. Off only: "stop caveman" / "normal mode".
Default: **full**. Switch: `/caveman lite|full|ultra`.
## Rules
Drop: articles, filler, pleasantries, hedging. Fragments OK. Short synonyms. Technical terms exact. Code blocks unchanged. Errors quoted exact.
Pattern: `[thing] [action] [reason]. [next step].`
## Boundaries
Code/commits/PRs: write normal. Security warnings and irreversible action confirmations: write normal, then resume caveman.=============== FILE: skills/caveman-commit/SKILL.md ===============
---
name: caveman-commit
description: Ultra-compressed commit message generator. Conventional Commits format. Subject <=50 chars, body only when why is not obvious. Use when user asks for commit message.
---
# Caveman Commit
Write concise Conventional Commit messages. Preserve intent and reasoning. Do not include noise.=============== FILE: skills/caveman-review/SKILL.md ===============
---
name: caveman-review
description: Ultra-compressed code review comments. Use when user asks for code review, PR review, or review the diff.
---
# Caveman Review
Findings first. Order by severity. Each comment one line: location, problem, fix.=============== FILE: skills/caveman-help/SKILL.md ===============
---
name: caveman-help
description: Quick-reference card for all caveman modes, skills, and commands. Trigger on caveman help.
---
# Caveman Help
Show available caveman modes and commands in a compact reference.=============== FILE: skills/compress/SKILL.md ===============
---
name: compress
description: >
Compress natural language memory files (CLAUDE.md, todos, preferences) into caveman format
to save input tokens. Preserves all technical substance, code, URLs, and structure.
Compressed version overwrites the original file. Human-readable backup saved as FILE.original.md.
Trigger: /caveman:compress <filepath> or "compress memory file"
---
# Caveman Compress
Compress natural language files into caveman-speak to reduce input tokens. Preserve technical substance, code, URLs, and structure.
## Process
Run `python3 -m scripts <absolute_filepath>` from this skill directory.
## Boundaries
- ONLY compress natural language files.
- NEVER modify code files, JSON, YAML, TOML, env files, lockfiles, CSS, HTML, XML, SQL, or shell scripts.
- Back up the original file as FILE.original.md before overwriting.=============== FILE: skills/compress/scripts/main.py ===============
from .cli import main
if __name__ == "__main__":
raise SystemExit(main())=============== FILE: skills/compress/scripts/cli.py ===============
def main() -> int:
print("compress fixture placeholder")
return 0