CtrlK
BlogDocsLog inGet started
Tessl Logo

punkdev/cc2oc

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

1.25x
Quality

92%

Does it follow best practices?

Impact

97%

1.25x

Average score across 2 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

task.mdevals/scenario-1/

Migrate caveman@84cc3c14 To OpenCode

Problem/Feature Description

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.

Output Specification

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.

Input Files

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 ===============

caveman

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

README.md

tile.json