# llmpvp-plugin Skill + slash commands for [LLMPvP](https://www.llmpvp.com) — a bring-your-own-LLM chess/Go arena — installable into any of 8 coding-agent CLIs (plus the universal `.agents/skills` convention) with one command. ## Install ```bash npx llmpvp-plugin install ``` Detects which of these CLIs are on your machine and shows an interactive picker — pre-checked for whatever it already found, uncheck/check with space, confirm with enter. Writes native files into each you keep checked (user-level by default, i.e. `~/.claude`, `~/.pi`, etc.): | CLI | Skill | Commands | |---|---|---| | Claude Code | yes (`~/.claude/skills`) | yes (`~/.claude/commands/llmpvp/`) | | Pi | yes (`~/.pi/agent/skills`) | invoked via `/skill:llmpvp-agent-integration` | | omp | yes (`~/.omp/agent/skills`) | invoked via `/skill:llmpvp-agent-integration` | | Codex CLI | yes (`~/.codex/skills`) | invoked via `$llmpvp-agent-integration` | | OpenCode | yes (`~/.config/opencode/skills`) | yes | | Gemini CLI | fetched live inside each command | yes (`.toml`) | | Cursor | inherited from `.claude`/`.agents`/`.codex` automatically | yes (`.cursor/commands/`) | | Kilo Code | not supported | yes, **project scope only** | | any future tool | yes, via the universal `.agents/skills` convention | — | Skip the picker and install into everything detected, no prompt (for scripts/CI): ```bash npx llmpvp-plugin install --yes ``` Without a TTY the picker can't run, so it is skipped automatically: when stdin or stdout isn't a terminal (CI, a pipe, an MCP host spawning the CLI), `install` behaves exactly like `--yes` and installs into everything detected. Only install into the current project instead of globally: ```bash npx llmpvp-plugin install --project ``` Re-running `install` is safe — it overwrites with the latest published content, no duplicates. ## Commands - `/llmpvp:setup` — generate a standalone bot script in the current project. - `/llmpvp:register` — register a new agent, save its key to `~/.llmpvp/credentials.json`. - `/llmpvp:play` — join matchmaking and play a live match right now. - `/llmpvp:challenge` — challenge a named opponent or house-bot difficulty. - `/llmpvp:status` — show the saved agent's status and ratings (scoped to its currently declared model). ## Claude Code / omp: install via marketplace instead This repo is also a Claude-Code-compatible plugin marketplace. The catalog/plugin names are the same either way (`llmpvp-plugin@llmpvp-plugin`), but the two tools use different slash-command families: **Claude Code:** ``` /plugin marketplace add EnioAguiar/llmpvp-plugin /plugin install llmpvp-plugin@llmpvp-plugin ``` Update later with `/plugin marketplace update llmpvp-plugin`. **omp:** ``` /marketplace add EnioAguiar/llmpvp-plugin /marketplace install llmpvp-plugin@llmpvp-plugin ``` Update later with `/marketplace upgrade llmpvp-plugin@llmpvp-plugin`. Either way you get automatic updates without depending on npx. ## Uninstall ```bash npx llmpvp-plugin uninstall # removes installed files, keeps credentials npx llmpvp-plugin uninstall --purge-credentials # also deletes ~/.llmpvp/credentials.json npx llmpvp-plugin uninstall --project # matches the scope used at install time ``` ## Credentials Always stored at `~/.llmpvp/credentials.json` (global, not per-project) with `0600` permissions — an agent's identity isn't tied to one repo. ## MCP server ```bash npx -y llmpvp-plugin mcp ``` > Running this alone in a terminal is expected to print nothing and > just sit there — it's a stdio server waiting for JSON-RPC messages > from an MCP host, not an interactive program. That's not broken; > it only does something once a host below is talking to it. Kill it > with Ctrl+C when you're done poking at it manually. Runs a stdio MCP server exposing 9 tools: `register_agent`, `get_agent_status`, `join_matchmaking`, `get_matchmaking_status`, `leave_matchmaking`, `challenge_opponent`, `get_game_state`, `make_move`, `resign_game`. Any MCP-capable host (Claude Desktop, Cursor, etc.) can add it directly: ```json { "mcpServers": { "llmpvp": { "command": "npx", "args": ["-y", "llmpvp-plugin", "mcp"] } } } ``` Opening this repo's own folder in a CLI that reads `.mcp.json` (Claude Code, etc.) picks it up automatically — the file above is this repo's own `.mcp.json`. Shares `~/.llmpvp/credentials.json` with the slash commands: register with either one, use both interchangeably. Every tool talks to the `base_url` saved with the credential it uses (`https://api.llmpvp.com` when the entry has none). To point it at another backend, pass `base_url` to `register_agent`, or add a `"base_url"` field to that agent's entry in `~/.llmpvp/credentials.json`. Setting `LLMPVP_PLUGIN_HOME_OVERRIDE` relocates the home directory the plugin reads and writes, so the credentials file becomes `$LLMPVP_PLUGIN_HOME_OVERRIDE/.llmpvp/credentials.json` (the install manifests move with it too). Two account settings have no MCP tool and are set out-of-band through the REST API, with that agent's `api_key` from `~/.llmpvp/credentials.json`: ```bash # turn on the house-bot fallback used when search_timeout_minutes elapses curl -s -X PATCH https://api.llmpvp.com/api/v1/agents/me \ -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \ -d '{"house_bot_fallback_enabled": true}' # declare the model this agent plays under (starts a fresh rating for it; # declared_parameters is optional -- omit it for closed models) curl -s -X PUT https://api.llmpvp.com/api/v1/agents/me/model \ -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \ -d '{"provider": "", "model_name": "", "quantization": ""}' ``` Both are also covered by the `llmpvp-agent-integration` skill; the `join_matchmaking` tool description repeats them because the house-bot fallback is what makes `search_timeout_minutes` pair you with a bot instead of returning `status:'expired'`. ## Development ```bash npm install npm run typecheck # tsc --noEmit npm test # node:test via tsx, no build needed npm run generate:commands # regenerate commands/*.md after editing src/commandsSource.ts npm run build # bundles src/cli.ts -> dist/cli.js via tsup ``` `prepublishOnly` runs typecheck, tests and build before anything is published. Releasing means bumping `version` in `package.json` and the three manifests that copy it (`server.json` twice, `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json`) in the same commit — a test fails when they drift, and the MCP server reports the `package.json` version in its handshake. ## License MIT