reviewer-harness 0.0.0-stage → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Edsiel Ursal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,263 @@
1
- # Temporary Holding Version
1
+ # reviewer-harness
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ```
4
+ Four runtimes in the editor, each with files of its own,
5
+ Scattered rules in every corner, never quite in sync,
6
+ An AI that means well — but breaks what already works,
7
+ And forgets your whole project the moment the session ends:
8
+
9
+ One config to guard them all,
10
+ One harness to remind them,
11
+ One sync to bind them all,
12
+ and in your codebase, protect them.
13
+ ```
14
+
15
+ ![version](https://img.shields.io/badge/version-1.0.0-blue)
16
+ ![License](https://img.shields.io/badge/License-MIT-yellowgreen)
17
+ ![node](https://img.shields.io/badge/node-%3E%3D18-brightgreen)
18
+ ![dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)
19
+ ![runtimes](https://img.shields.io/badge/runtimes-4-purple)
20
+ ![status](https://img.shields.io/badge/status-Free%20%26%20Open%20Source-green)
21
+
22
+ **reviewer-harness** is a personal AI agent harness: one master config that syncs guardrail rules, reusable skills, and a local project memory to **Claude Code, OpenCode, Gemini CLI, and Cline** — so the AI that codes for you stops breaking what already works. No API key. No dependencies. Just Node.js and your rules.
23
+
24
+ ## Overview
25
+
26
+ AI coding assistants are powerful, but anyone who vibe-codes with them daily runs into the same crises:
27
+
28
+ 1. **The "you broke my code" crisis.** You ask the AI to add one feature, and it rewrites a file that was already working — deleting or altering parts you never asked it to touch. The fix becomes the bug.
29
+
30
+ 2. **The hallucination crisis.** The AI confidently imports packages that don't exist, calls functions it invented, and presents output that only *looks* correct — until you run it.
31
+
32
+ 3. **The fragmentation crisis.** Every AI runtime wants its own instruction file (`CLAUDE.md`, `.opencode/instructions.md`, `GEMINI.md`, `.clinerules`). Keeping the same rules in sync across all of them by hand is tedious and error-prone.
33
+
34
+ 4. **The amnesia crisis.** Every new session, the AI forgets your project: the decisions you made, the files that must never be touched, the gotchas you already paid for once.
35
+
36
+ **reviewer-harness solves this with One Master Config.** You define your rules, your problem statement, and your skills once — in a single `harness.config.json` — and the harness validates them (including scanning for leaked secrets) and syncs them deterministically to every runtime. A local, graph-style memory gives the AI something to read before it codes, and to write to when it learns.
37
+
38
+ ## The problem (why this harness exists)
39
+
40
+ **An AI with no guardrails.** You cannot control the model — but you *can* control **the rules it must follow**. That is the harness. The problem statement lives in `harness.config.json` (the `problem` field) and is synced along with everything else — it appears in every runtime file, so every AI knows not just the rules, but *why* they exist.
41
+
42
+ ## What is this?
43
+
44
+ The harness is **not the AI model** — it is what prepares everything the AI reads before it starts coding:
45
+
46
+ ```
47
+ harness.config.json ← your master spec (ONE file)
48
+ │ validate() ← quality checks + secret scanning
49
+ ▼
50
+ lib/adapters/*.js ← adapters: opencode, claude, gemini, cline
51
+ │ renderInstructions()
52
+ ▼
53
+ .opencode/instructions.md ← OpenCode
54
+ CLAUDE.md ← Claude Code
55
+ GEMINI.md ← Gemini CLI
56
+ .clinerules ← Cline
57
+ ```
58
+
59
+ Change the rules in **one** place (`harness.config.json`), and `sync` propagates them to every runtime.
60
+
61
+ ## Quickstart
62
+
63
+ You can use reviewer-harness in two ways: **Modular Mode** (zero-install: add individual skills to any project, no setup) or **Full Harness Mode** (one master config synced across all 4 runtimes).
64
+
65
+ ### 1. Modular Skills (zero-install via npx)
66
+
67
+ Copy a single skill straight into your current project — no install, no config needed. The skill lands in `./skills/` as a playbook your AI can follow:
68
+
69
+ ```bash
70
+ # Browse the bundled skills first
71
+ npx reviewer-harness skills list
72
+
73
+ # Add individual skills to this project
74
+ npx reviewer-harness skills add safe-editing
75
+ npx reviewer-harness skills add no-hallucination
76
+ ```
77
+
78
+ > Prefer a global CLI? Install once with `npm install -g reviewer-harness` and run `reviewer-harness skills add <name>` anywhere.
79
+
80
+ ### 2. Full Harness Synchronization (4 runtimes)
81
+
82
+ `init` creates your master config, `validate` checks it (including secret scanning), and `sync` generates the native instruction file for every runtime you enable: `.opencode/instructions.md`, `CLAUDE.md`, `GEMINI.md`, and `.clinerules`.
83
+
84
+ ```bash
85
+ # Using npx (zero-install, recommended)
86
+ npx reviewer-harness init
87
+ npx reviewer-harness sync --dry-run # preview: writes nothing
88
+ npx reviewer-harness sync # writes, with .bak backups
89
+
90
+ # Using pnpm (zero-install)
91
+ pnpm dlx reviewer-harness init
92
+
93
+ # Or install globally
94
+ npm install -g reviewer-harness
95
+ reviewer-harness init
96
+
97
+ # Direct git clone
98
+ git clone https://github.com/xcell321/reviewer-harness.git
99
+ cd reviewer-harness && node bin/cli.js init --target ../my-project
100
+ ```
101
+
102
+ ### 3. Standalone one-liner installers
103
+
104
+ ```bash
105
+ # Linux / macOS
106
+ curl -fsSL https://raw.githubusercontent.com/xcell321/reviewer-harness/main/bin/install.sh | bash
107
+
108
+ # Windows PowerShell
109
+ irm https://raw.githubusercontent.com/xcell321/reviewer-harness/main/bin/install.ps1 | iex
110
+ ```
111
+
112
+ ### 4. Running via Docker (zero local Node.js required)
113
+
114
+ For zero-dependency execution without installing Node.js on your machine:
115
+
116
+ ```bash
117
+ git clone https://github.com/xcell321/reviewer-harness.git
118
+ cd reviewer-harness
119
+
120
+ # Check status / start the harness in the mounted workspace
121
+ docker compose run --rm reviewer-harness status
122
+ docker compose run --rm reviewer-harness init
123
+ docker compose run --rm reviewer-harness sync
124
+ ```
125
+
126
+ ## Sandboxing and security notice
127
+
128
+ reviewer-harness executes locally and is fully transparent:
129
+
130
+ - **Zero telemetry, zero network.** The tool reads and writes files in your project only. It sends no code or prompts to external servers, and it never needs an API key.
131
+ - **Non-destructive backups.** Before modifying any existing instruction file, sync creates a `.bak` copy; files that would not change are skipped.
132
+ - **Inspect before applying.** Run `sync --dry-run` to see exactly what would change — it writes nothing.
133
+ - **Secrets are blocked, not leaked.** `validate` (and sync itself) scans the config for API keys and tokens and refuses to sync if one is found.
134
+ - **Prefer a hard sandbox?** Run it in the Docker container above.
135
+
136
+ ## The Sync Engine (safe by design)
137
+
138
+ Guardrails that run before any file is written:
139
+
140
+ 1. **VALIDATE GATE** — if the spec is broken or contains a secret, sync refuses to run
141
+ 2. **DRY-RUN** — `sync --dry-run`: preview only, writes nothing
142
+ 3. **BACKUP** — before overwriting an existing file, write a `.bak` copy first
143
+ 4. **IDEMPOTENT** — if nothing changed, touch nothing (safe to run repeatedly)
144
+
145
+ ## Validate + Secret Scanning
146
+
147
+ `validate` inspects the config before it becomes instructions:
148
+
149
+ - No empty rules, no duplicates
150
+ - Secret scanning — API keys and tokens must never be synced (they would leak into Git!)
151
+ - `sync` itself refuses to proceed when validation reports errors
152
+
153
+ ## This repo governs itself
154
+
155
+ reviewer-harness eats its own cooking: the instruction files at this repo's root — `.opencode/instructions.md`, `CLAUDE.md`, `GEMINI.md`, `.clinerules` — plus the agents and commands in `.opencode/` and `.claude/` are **generated by reviewer-harness itself** from its own `harness.config.json`. Open this repo in any AI coding tool and the tool follows the harness's own rules while working on the harness. To refresh them after editing the config, just run `node bin/cli.js sync` here.
156
+
157
+ ## Local Memory (graph-style, Obsidian-ready)
158
+
159
+ AI models have no memory — every session, they forget your project. The harness keeps a `memory/` folder (inspired by Graphify's knowledge graph and Obsidian's vault, but lightweight and fully local):
160
+
161
+ ```
162
+ memory/
163
+ project.md — notes (plain markdown, Obsidian-style)
164
+ decisions.md — [[wiki links]] connect the notes
165
+ INDEX.md — generated: the AI reads this first
166
+ graph.json — generated: nodes = notes, edges = links
167
+ ```
168
+
169
+ One of the rules orders the AI to read the memory first, and to write what it learns as a note with [[links]]. `sync` also refreshes the index. Open `memory/` in Obsidian to see the graph view.
170
+
171
+ ## Skills
172
+
173
+ Reusable playbooks, enabled per project:
174
+
175
+ - `skills list` — see the bundled skills
176
+ - `skills add <name>` — install into the project and enable it in the config
177
+ - `skills remove <name>` — disable it
178
+
179
+ Bundled: `safe-editing`, `no-hallucination`, `debug-first`, `explain-bisaya`. Enabled skills render below the rules in every instruction file — and sync also generates a **slash command** for each one (`.opencode/commands/<name>.md` and `.claude/commands/<name>.md`), so every enabled skill appears in the `/` menu of OpenCode and Claude, ready to invoke on a specific task: `/safe-editing`, `/no-hallucination`, and so on.
180
+
181
+ **Every project, instantly:** want the skills in the `/` menu of *every* project, with no per-project setup? Run `reviewer-harness global` once — it installs all bundled skills as slash commands into the global OpenCode (`~/.config/opencode/commands`) and Claude (`~/.claude/commands`) folders. From then on, they are in the `/` menu of any project you open. (Project rules still come from `sync` inside a project.)
182
+
183
+ ## Sub-agents and Slash Commands
184
+
185
+ One master definition in the harness, generated into each runtime's format:
186
+
187
+ - `agents add planner|reviewer|debugger` → `.opencode/agents/` + `.claude/agents/`
188
+ - **planner** (Tigplano) — plans before coding
189
+ - **reviewer** (Bantay) — hunts breakage and hallucinated code in diffs
190
+ - **debugger** (Tig-ayo) — root-cause debugging, never symptom-patching
191
+ - `commands add review|explain` → `.opencode/commands/` + `.claude/commands/` (type `/review` or `/explain` in your runtime)
192
+
193
+ ## Command reference
194
+
195
+ Requires Node.js 18+ (no dependencies). Run these inside your project — every command works on the current directory unless you add `--target <dir>`.
196
+
197
+ **Start & everyday**
198
+
199
+ ```bash
200
+ reviewer-harness init # one-time: create the master config
201
+ reviewer-harness validate # check the config (quality + secret scan)
202
+ reviewer-harness sync --dry-run # preview the changes, writes nothing
203
+ reviewer-harness sync # apply the rules to every runtime
204
+ reviewer-harness status # show the config + target files
205
+ ```
206
+
207
+ **Skills, agents, commands**
208
+
209
+ ```bash
210
+ reviewer-harness skills list
211
+ reviewer-harness skills add safe-editing
212
+ reviewer-harness skills remove safe-editing
213
+ reviewer-harness agents add reviewer
214
+ reviewer-harness commands add review
215
+ ```
216
+
217
+ **Local memory**
218
+
219
+ ```bash
220
+ reviewer-harness memory init # start the memory/ vault
221
+ reviewer-harness memory list # list notes + their links
222
+ reviewer-harness memory index # rebuild INDEX.md + graph.json
223
+ ```
224
+
225
+ Running from a source checkout instead? The same commands work as `node bin/cli.js <command>`.
226
+
227
+ ## File map
228
+
229
+ - `bin/cli.js` — commands: `status`, `sync`, `init`, `validate`, `memory`, `skills`, `agents`, `commands`
230
+ - `bin/install.sh` / `bin/install.ps1` — one-liner installers (Linux/macOS, Windows)
231
+ - `Dockerfile` / `docker-compose.yml` — run the harness with zero local Node.js
232
+ - `lib/config.js` — loads and validates the structure of the master spec
233
+ - `lib/validate.js` — rule quality checks + secret scanning
234
+ - `lib/sync.js` — THE SYNC ENGINE: validate gate, dry-run, backup, idempotent writes
235
+ - `lib/init.js` — creates the harness.config.json template in a new project
236
+ - `lib/memory.js` — local memory: notes vault, graph builder, index generator
237
+ - `lib/skills.js` — skills system: bundled store, install/enable, section rendering
238
+ - `lib/agents.js` / `lib/commands.js` — one source → OpenCode + Claude formats
239
+ - `lib/adapters/` — registry + one adapter per runtime (opencode, claude, gemini, cline)
240
+ - `skills/` — bundled skills · `agents/` — bundled sub-agents · `commands/` — bundled slash commands
241
+
242
+ ## How it was built (the lessons)
243
+
244
+ 1. ✅ Scaffold — CLI + master config + adapter pattern
245
+ 2. ✅ Sync engine — dry-run, .bak backup, idempotent
246
+ 3. ✅ Guardrails — `validate` command + secret scanning + sync gate
247
+ 4. ✅ Skills system — `skills add/list/remove`
248
+ 5. ✅ Sub-agents and slash commands — `agents add`, `commands add`
249
+ 6. ✅ Polish and publish — v1.0.0, LICENSE, publish-ready for GitHub/npx
250
+ 7. ✅ v1.1.0 — all-English repo, validate-and-report rule, self-governing repo, modular skills, one-liner installers, Docker
251
+
252
+ ## Contributing & Security
253
+
254
+ - Contributions welcome — see [CONTRIBUTING.md](CONTRIBUTING.md)
255
+ - Found a security issue? See [SECURITY.md](SECURITY.md)
256
+
257
+ ## Author & credits
258
+
259
+ Created and maintained by **Edsiel Ursal** ([@xcell321](https://github.com/xcell321)) — designed and built together with **Muse**, Meta's AI assistant, as pair programmer and mentor. Every feature in this repo was planned, coded, tested, and documented in that collaboration: Edsiel directed the vision and made every call; Muse helped write and verify the code.
260
+
261
+ ## License
262
+
263
+ MIT — see [LICENSE](LICENSE)
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: debugger
3
+ description: The Fixer — root-cause debugging specialist, never patches over symptoms.
4
+ ---
5
+
6
+ You are the Fixer, the debugging specialist.
7
+
8
+ 1. Reproduce the error first — capture the exact command and the full error message.
9
+ 2. Read the stack trace down to the first line that is yours (not the library's).
10
+ 3. Form a hypothesis, then prove it with logs or a small test — never guess at a fix.
11
+ 4. Fix the cause with the smallest change possible.
12
+ 5. Verify: re-run the reproduction — is the error really gone? Did anything else break?
13
+ 6. If the bug is worth remembering, write it as a note in memory/ with [[links]].
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: planner
3
+ description: The Planner — breaks a task into small steps before any code is written.
4
+ ---
5
+
6
+ You are the Planner. Before a single line of code is written:
7
+
8
+ 1. Read memory/INDEX.md and the related notes — what does the project already know?
9
+ 2. Break the task into small steps, in the right order.
10
+ 3. Identify the risky files (heavily connected ones, or anything listed under "do not touch" in the memory).
11
+ 4. State how each step will be verified (test, run, check).
12
+ 5. Present the plan and wait for approval before coding.
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: reviewer
3
+ description: Bantay, the Watcher — reviews changes against the rules, hunting breakage and invented code.
4
+ ---
5
+
6
+ You are Bantay, the reviewer. Your job: catch breakage before it gets committed.
7
+
8
+ 1. Look at the diff of the latest changes.
9
+ 2. Check it against the project's rules: was anything changed that was never asked for? Was a file rewritten instead of edited?
10
+ 3. Hunt for hallucination: imports that are not in package.json, functions or APIs that appear nowhere in the codebase or docs.
11
+ 4. Check the memory was respected: was anything under "do not touch" violated?
12
+ 5. Report as a list: **VIOLATION** (must fix) and **WARNING** (worth a look). If it is clean, say clearly that it is clean — never invent a problem.
package/bin/cli.js ADDED
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env node
2
+ // reviewer-harness — CLI: sync engine, guardrail validation, local memory,
3
+ // skills, sub-agents, and slash commands.
4
+ // Commands: status | sync | init | validate | memory | skills | agents | commands | global
5
+
6
+ import { parseArgs } from "node:util";
7
+ import { existsSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { homedir } from "node:os";
10
+ import { loadConfig } from "../lib/config.js";
11
+ import { adapters, supportedRuntimes } from "../lib/adapters/index.js";
12
+ import { sync, writeSafe } from "../lib/sync.js";
13
+ import { initProject } from "../lib/init.js";
14
+ import { initMemory, buildIndex, readNotes, memoryDir } from "../lib/memory.js";
15
+ import { validateConfig } from "../lib/validate.js";
16
+ import { listBundledSkills, addSkill, removeSkill, loadBundledSkills, skillCommandContent } from "../lib/skills.js";
17
+ import { listBundledAgents, addAgent } from "../lib/agents.js";
18
+ import { listBundledCommands, addCommand } from "../lib/commands.js";
19
+
20
+ const { values, positionals } = parseArgs({
21
+ allowPositionals: true,
22
+ options: {
23
+ "dry-run": { type: "boolean", default: false },
24
+ target: { type: "string", default: process.cwd() },
25
+ },
26
+ });
27
+ const [command, sub, arg] = positionals;
28
+ const targetDir = values.target;
29
+ const dryRun = values["dry-run"];
30
+
31
+ function help() {
32
+ console.log(`reviewer-harness — your own AI harness
33
+
34
+ Usage (run inside your project):
35
+ reviewer-harness init Create harness.config.json (one-time setup)
36
+ reviewer-harness validate Check the config: quality + secret scanning
37
+ reviewer-harness sync [--dry-run] Sync the rules to every runtime (--dry-run = preview only)
38
+ reviewer-harness status Show the config + target files
39
+
40
+ reviewer-harness skills list List bundled skills (+ which are enabled)
41
+ reviewer-harness skills add <name> Install + enable a skill in the project
42
+ reviewer-harness skills remove <name> Disable + remove a skill
43
+ reviewer-harness agents list List bundled sub-agents
44
+ reviewer-harness agents add <name> Install a sub-agent (OpenCode + Claude)
45
+ reviewer-harness commands list List bundled slash commands
46
+ reviewer-harness commands add <name> Install a slash command (OpenCode + Claude)
47
+
48
+ reviewer-harness global [--dry-run] Install EVERY bundled skill as a slash command for ALL projects (global OpenCode + Claude "/" menus)
49
+
50
+ reviewer-harness memory init Start the local memory (memory/ folder)
51
+ reviewer-harness memory index Rebuild the memory INDEX.md + graph.json
52
+ reviewer-harness memory list List memory notes + their links
53
+
54
+ Every command accepts --target <dir> (default: the current directory).
55
+ `);
56
+ }
57
+
58
+ function cmdStatus() {
59
+ const config = loadConfig(targetDir);
60
+ console.log(`Harness : ${config.name} v${config.version}`);
61
+ console.log(`Target : ${targetDir}`);
62
+ console.log(`Runtimes:`);
63
+ for (const name of config.runtimes) {
64
+ const adapter = adapters[name];
65
+ console.log(` - ${name} → ${adapter ? adapter.targetFile() : "(no adapter!)"}`);
66
+ }
67
+ console.log(`Skills : ${config.skills?.length ? config.skills.join(", ") : "(none)"}`);
68
+ }
69
+
70
+ function cmdSync() {
71
+ const results = sync({ targetDir, dryRun });
72
+ if (dryRun) console.log("(dry-run: nothing was written)\n");
73
+ for (const r of results) {
74
+ if (r.skillCommands) {
75
+ const written = r.skillCommands.filter((f) => f.written).length;
76
+ const pending = r.skillCommands.filter((f) => f.dryRun && f.changed).length;
77
+ const unchanged = r.skillCommands.filter((f) => f.unchanged || (f.dryRun && !f.changed)).length;
78
+ if (dryRun) {
79
+ console.log(`- skill commands: ${pending} would be written/updated, ${unchanged} unchanged (they appear in the "/" menu of OpenCode and Claude)`);
80
+ } else {
81
+ console.log(`- skill commands: ${written} written ✓, ${unchanged} unchanged (one per skill, in the "/" menu of OpenCode and Claude)`);
82
+ }
83
+ } else if (r.skipped) {
84
+ console.log(`- ${r.runtime}: SKIP — ${r.skipped}`);
85
+ } else if (r.dryRun) {
86
+ console.log(`- ${r.runtime} → ${r.file}: ${r.changed ? "WOULD WRITE (changes pending)" : "no changes"}`);
87
+ } else if (r.unchanged) {
88
+ console.log(`- ${r.runtime} → ${r.file}: no changes, skipped ✓`);
89
+ } else {
90
+ console.log(`- ${r.runtime} → ${r.file}: WRITTEN ✓${r.backup ? " (.bak backup made)" : ""}`);
91
+ }
92
+ }
93
+ // If the project has a local memory, refresh its index as part of
94
+ // sync — so the graph the AI reads is always current.
95
+ if (!dryRun && existsSync(memoryDir(targetDir))) {
96
+ const stats = buildIndex(targetDir);
97
+ console.log(`- memory: index refreshed (${stats.notes} notes, ${stats.edges} links) ✓`);
98
+ }
99
+ }
100
+
101
+ function cmdMemory() {
102
+ if (sub === "init") {
103
+ const r = initMemory(targetDir);
104
+ console.log(
105
+ r.created.length
106
+ ? `Local memory created: ${r.dir} (${r.created.join(", ")})`
107
+ : `Local memory already exists: ${r.dir} (nothing overwritten)`
108
+ );
109
+ console.log(`Index: ${r.notes} notes, ${r.edges} links. Open the folder in Obsidian for the graph view.`);
110
+ } else if (sub === "index") {
111
+ if (!existsSync(memoryDir(targetDir)))
112
+ throw new Error(`No memory/ in ${targetDir} — run "memory init" first.`);
113
+ const stats = buildIndex(targetDir);
114
+ console.log(`Index rebuilt: ${stats.notes} notes, ${stats.edges} links, ${stats.dangling} dangling links.`);
115
+ } else if (sub === "list") {
116
+ const notes = readNotes(targetDir);
117
+ if (!notes.length) {
118
+ console.log(`No memory notes in ${join(targetDir, "memory")} — run "memory init" first.`);
119
+ return;
120
+ }
121
+ for (const n of notes) {
122
+ console.log(`- [[${n.id}]] ${n.title}${n.links.length ? ` → ${n.links.join(", ")}` : ""}`);
123
+ }
124
+ } else {
125
+ console.log(`Usage: memory <init|index|list> [--target <dir>]`);
126
+ }
127
+ }
128
+
129
+ function cmdInit() {
130
+ const { created, file } = initProject(targetDir);
131
+ console.log(created ? `Config created: ${file}` : `Already exists: ${file} (not overwritten)`);
132
+ }
133
+
134
+ function cmdValidate() {
135
+ const config = loadConfig(targetDir);
136
+ const { errors, warnings, ok } = validateConfig(config, {
137
+ knownRuntimes: supportedRuntimes,
138
+ });
139
+ for (const e of errors) console.log(`✗ ${e}`);
140
+ for (const w of warnings) console.log(`⚠ ${w}`);
141
+ if (ok && !warnings.length) console.log(`✓ Config is clean — no problems, no secrets.`);
142
+ else if (ok) console.log(`✓ No errors (${warnings.length} warning(s)).`);
143
+ else {
144
+ console.log(`\n✗ ${errors.length} error(s) — fix them before syncing.`);
145
+ process.exitCode = 1;
146
+ }
147
+ }
148
+
149
+ function cmdSkills() {
150
+ if (sub === "list") {
151
+ let enabled = [];
152
+ try {
153
+ enabled = loadConfig(targetDir).skills ?? [];
154
+ } catch {
155
+ /* no config in the target — just list the bundled skills */
156
+ }
157
+ for (const s of listBundledSkills()) {
158
+ console.log(`- ${s.name}${enabled.includes(s.name) ? " ✓ enabled" : ""} — ${s.description}`);
159
+ }
160
+ } else if (sub === "add" && arg) {
161
+ const r = addSkill(arg, targetDir);
162
+ if (r.noConfig) {
163
+ console.log(
164
+ `Skill "${arg}" copied → ${r.file}\n` +
165
+ `(No harness.config.json here, so it is not enabled in a harness — it is yours as a standalone playbook.\n` +
166
+ `Run "init" in this project if you want the full harness to sync it to every runtime.)`
167
+ );
168
+ } else {
169
+ console.log(
170
+ r.alreadyEnabled
171
+ ? `Skill "${arg}" is already enabled (file refreshed). Run "sync" to apply.`
172
+ : `Skill "${arg}" installed → ${r.file}\nEnabled in the config. Run "sync" to apply it to the runtimes.`
173
+ );
174
+ }
175
+ } else if (sub === "remove" && arg) {
176
+ const r = removeSkill(arg, targetDir);
177
+ console.log(
178
+ r.wasEnabled
179
+ ? `Skill "${arg}" disabled${r.removedFile ? " and its file removed" : ""}. Run "sync" to update the runtimes.`
180
+ : `Skill "${arg}" was not enabled.`
181
+ );
182
+ } else {
183
+ console.log(`Usage: skills <list|add <name>|remove <name>> [--target <dir>]`);
184
+ }
185
+ }
186
+
187
+ function cmdAgents() {
188
+ if (sub === "list") {
189
+ for (const a of listBundledAgents()) console.log(`- ${a.name} — ${a.description}`);
190
+ } else if (sub === "add" && arg) {
191
+ const r = addAgent(arg, targetDir);
192
+ console.log(`Agent "${arg}" installed:`);
193
+ for (const f of r.written) console.log(` → ${f}`);
194
+ } else {
195
+ console.log(`Usage: agents <list|add <name>> [--target <dir>]`);
196
+ }
197
+ }
198
+
199
+ function cmdCommands() {
200
+ if (sub === "list") {
201
+ for (const c of listBundledCommands()) console.log(`- /${c.name} — ${c.description}`);
202
+ } else if (sub === "add" && arg) {
203
+ const r = addCommand(arg, targetDir);
204
+ console.log(`Command "/${arg}" installed:`);
205
+ for (const f of r.written) console.log(` → ${f}`);
206
+ } else {
207
+ console.log(`Usage: commands <list|add <name>> [--target <dir>]`);
208
+ }
209
+ }
210
+
211
+ function cmdGlobal() {
212
+ const skills = loadBundledSkills();
213
+ const targets = [
214
+ { runtime: "OpenCode", dir: join(homedir(), ".config", "opencode", "commands") },
215
+ { runtime: "Claude", dir: join(homedir(), ".claude", "commands") },
216
+ ];
217
+ if (dryRun) console.log("(dry-run: nothing was written)\n");
218
+ for (const { runtime, dir } of targets) {
219
+ let written = 0, unchanged = 0, pending = 0;
220
+ for (const skill of skills) {
221
+ const outcome = writeSafe(join(dir, `${skill.name}.md`), skillCommandContent(skill), dryRun);
222
+ if (outcome.written) written++;
223
+ else if (outcome.dryRun && outcome.changed) pending++;
224
+ else unchanged++;
225
+ }
226
+ if (dryRun) console.log(`- ${runtime} (global): ${pending} would be written/updated, ${unchanged} unchanged → ${dir}`);
227
+ else console.log(`- ${runtime} (global): ${written} written ✓, ${unchanged} unchanged → ${dir}`);
228
+ }
229
+ console.log(
230
+ `\nDone: ${skills.map((s) => "/" + s.name).join(", ")} are now in the "/" menu of EVERY project.` +
231
+ `\n(Per-project rules still come from "sync" inside a project.)`
232
+ );
233
+ }
234
+
235
+ async function main() {
236
+ if (!command || command === "status") cmdStatus();
237
+ else if (command === "sync") cmdSync();
238
+ else if (command === "init") cmdInit();
239
+ else if (command === "validate") cmdValidate();
240
+ else if (command === "memory") cmdMemory();
241
+ else if (command === "skills") cmdSkills();
242
+ else if (command === "agents") cmdAgents();
243
+ else if (command === "commands") cmdCommands();
244
+ else if (command === "global") cmdGlobal();
245
+ else help();
246
+ }
247
+
248
+ main().catch((err) => {
249
+ console.error("Error:", err.message);
250
+ process.exit(1);
251
+ });
@@ -0,0 +1,30 @@
1
+ # reviewer-harness installer (Windows PowerShell)
2
+ #
3
+ # Installs the reviewer-harness CLI globally from GitHub, so you can
4
+ # run `reviewer-harness` in any project. The only requirement is
5
+ # Node.js 18+ (the harness itself has zero dependencies).
6
+ #
7
+ # Usage:
8
+ # irm https://raw.githubusercontent.com/xcell321/reviewer-harness/main/bin/install.ps1 | iex
9
+
10
+ $ErrorActionPreference = "Stop"
11
+
12
+ if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
13
+ Write-Host "reviewer-harness needs Node.js 18 or newer."
14
+ Write-Host "Install it first: https://nodejs.org"
15
+ exit 1
16
+ }
17
+
18
+ $major = [int](node -p "process.versions.node.split('.')[0]")
19
+ if ($major -lt 18) {
20
+ Write-Host "reviewer-harness needs Node.js 18 or newer (you have $(node -v))."
21
+ exit 1
22
+ }
23
+
24
+ Write-Host "Installing reviewer-harness globally from GitHub..."
25
+ npm install -g reviewer-harness
26
+
27
+ Write-Host ""
28
+ Write-Host "Done. Try it in any project:"
29
+ Write-Host " reviewer-harness init # create a master config"
30
+ Write-Host " reviewer-harness sync # sync the rules to every runtime"
package/bin/install.sh ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env bash
2
+ # reviewer-harness installer (Linux / macOS)
3
+ #
4
+ # Installs the reviewer-harness CLI globally from GitHub, so you can
5
+ # run `reviewer-harness` in any project. The only requirement is
6
+ # Node.js 18+ (the harness itself has zero dependencies).
7
+ #
8
+ # Usage:
9
+ # curl -fsSL https://raw.githubusercontent.com/xcell321/reviewer-harness/main/bin/install.sh | bash
10
+
11
+ set -euo pipefail
12
+
13
+ if ! command -v node >/dev/null 2>&1; then
14
+ echo "reviewer-harness needs Node.js 18 or newer."
15
+ echo "Install it first: https://nodejs.org"
16
+ exit 1
17
+ fi
18
+
19
+ NODE_MAJOR="$(node -p "process.versions.node.split('.')[0]")"
20
+ if [ "$NODE_MAJOR" -lt 18 ]; then
21
+ echo "reviewer-harness needs Node.js 18 or newer (you have $(node -v))."
22
+ exit 1
23
+ fi
24
+
25
+ echo "Installing reviewer-harness globally from GitHub..."
26
+ npm install -g reviewer-harness
27
+
28
+ echo ""
29
+ echo "Done. Try it in any project:"
30
+ echo " reviewer-harness init # create a master config"
31
+ echo " reviewer-harness sync # sync the rules to every runtime"
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: explain
3
+ description: Explain code or a change in simple Bisaya (Cebuano).
4
+ ---
5
+
6
+ Explain the following in simple Bisaya (Cebuano): $ARGUMENTS
7
+
8
+ Rules for the explanation:
9
+ - One sentence per idea; avoid heavy jargon.
10
+ - If you use an English technical term, define it first in one sentence.
11
+ - If it is code: what it does, its inputs, its outputs, and where it is used in the project.
12
+ - If it is a change (diff): what changed, in which files, and why.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: review
3
+ description: Review the latest changes against the harness rules and the memory.
4
+ ---
5
+
6
+ Review the latest changes in this project (git diff, or the files most recently edited).
7
+
8
+ Check:
9
+ 1. Was anything changed that was never asked for, or a file rewritten instead of edited?
10
+ 2. Is there an import, function, or API that exists nowhere in the codebase or package.json (hallucination)?
11
+ 3. Was anything in memory/ violated (decisions, or "do not touch" areas)?
12
+ 4. Were the tests/lint run after the change?
13
+
14
+ Focus: $ARGUMENTS
15
+
16
+ Report as VIOLATION / WARNING. If it is clean, say it is clean.