Skip to content
Back to skills

2974 Tasks 4 Validate Orchestrator Discipline 55f8f536

BSecurity

Fix and validate the orchestrator-discipline plugin — blocker, hook coverage, SKILL.md frontmatter, and full validation suite

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
testingjavascriptgojavabashnodegitdevopsdocumentation

Works with

  • claude code
  • cli
  • mcp

Security analysis

B88/100
  • criticalPipes output to a shell interpreter

Pro shows the line behind each finding and how to fix it

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 2974-tasks-4-validate-orchestrator-discipline_55f8f536 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2974 Tasks 4 Validate Orchestrator Discipline 55f8f536?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2974 Tasks 4 Validate Orchestrator Discipline 55f8f536
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2974-tasks-4-validate-orchestrator-discipline-55f8/badge)](https://www.skillsdirectory.com/skills/tools-only-2974-tasks-4-validate-orchestrator-discipline-55f8)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
---
description: "Fix and validate the orchestrator-discipline plugin — blocker, hook coverage, SKILL.md frontmatter, and full validation suite"
version: "1.0"
tasks:
  - T1: Fix plugin.json validation failure (BLOCKER)
  - T2: Fix Grep directory path coverage in hook
  - T3: Fix SKILL.md frontmatter and linting
  - T4: Full validation suite (depends on T1 + T2 + T3)
task_exports:
  enabled: false
  directory: "TASK"
---

# Task Plan: Validate and Fix orchestrator-discipline Plugin

## Context

The `orchestrator-discipline` plugin enforces delegation discipline via two PreToolUse hooks and a
rules file. It currently fails `claude plugin validate` due to an unrecognized `rules` field in
`plugin.json`. Three additional gaps exist: directory-targeted `Grep` bypasses the read-warning
hook, `rules/CLAUDE.md` loading is unverified, and `SKILL.md` is missing `user-invocable: true`.

Source documents:

- `plan/feature-context-validate-orchestrator-discipline.md`
- `plan/codebase/orchestrator-discipline-patterns.md`

Plugin root: `plugins/orchestrator-discipline/`

---

## Context Manifest

### Key Decisions Already Made (Do Not Re-Investigate)

The architecture spec (`plan/architect-validate-orchestrator-discipline.md`) resolved all four open questions from the feature context doc. These decisions are final — do not reopen them.

**Decision 1 — rules/CLAUDE.md delivery mechanism**: Move content verbatim to a new file at `plugins/orchestrator-discipline/CLAUDE.md` (plugin root). This is the same pattern used by `plugins/development-harness/CLAUDE.md` and `plugins/plugin-creator/CLAUDE.md`. The `rules/` directory and `rules/CLAUDE.md` are to be deleted after content is confirmed moved. Option B (merge into SKILL.md body) was rejected because SKILL.md content loads on demand rather than passively. Option C (references file) was also rejected.

**Decision 2 — Grep directory path coverage**: Add `isDirectory()` + `looksLikeDirectory()` to the Grep branch in `pre-tool-orchestrator-read-warning.cjs`. Fire the warning for ALL directory-targeted Grep calls — no allowlist, no pattern heuristic. The hook is non-blocking so the noise cost is acceptable.

**Decision 3 — SKILL.md `user-invocable` field**: Add `user-invocable: true` to SKILL.md frontmatter. Do NOT add a `name:` field. The absence of `name:` is intentional and correct — adding it would suppress slash command registration due to a confirmed Claude Code v2.1.23 bug (documented in `plugins/plugin-creator/CLAUDE.md`, "CRITICAL: Skill Name Field Bug" section).

**Decision 4 — Remove `commands` field from plugin.json**: The `commands` field is the legacy registration path. Both `skills` and `commands` currently point to `./skills/orchestrator-discipline`. Remove `commands`; keep only `skills`. After T1 completes, `plugin.json` should contain exactly: `name`, `skills`, `hooks`.

---

### Current State of Each File to Be Modified

**`plugins/orchestrator-discipline/.claude-plugin/plugin.json`** — current contents (13 lines):

```json
{
  "name": "orchestrator-discipline",
  "description": "Enforces orchestrator context window discipline...",
  "version": "1.3.2",
  "author": { "name": "Jamie Nelson", "url": "https://github.com/bitflight-devops" },
  "skills": ["./skills/orchestrator-discipline"],
  "hooks": "./hooks.json",
  "rules": ["./rules"],
  "commands": ["./skills/orchestrator-discipline"]
}
```

Target state after T1: remove `"rules"` and `"commands"` lines. Do NOT touch `version` — `auto_sync_manifests.py` pre-commit hook handles versioning automatically.

**`plugins/orchestrator-discipline/rules/CLAUDE.md`** — 143-line behavioral constraints file. Content covers: Context Window Read Constraints (permitted/prohibited), Delegation Constraints, Investigation Escalation Anti-Pattern (with mermaid diagram), Agent Output Polling Anti-Pattern (with mermaid diagram), Diagnostic Commands list, Epistemic Identity Scope. Key string that must survive in destination: `"no exemption categories"` (used in T1 and T4 verification).

**`plugins/orchestrator-discipline/CLAUDE.md`** — does NOT exist yet. T1 creates it by copying `rules/CLAUDE.md` content verbatim.

**`plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs`** — 86-line CommonJS Node.js hook. Current structure:

- Lines 15-16: `SOURCE_FILE_EXTENSIONS` regex and `TEST_PATH_PATTERN` regex constants.
- Lines 23-26: `isSourceOrConfigFile(filePath)` function — returns true if path matches extension regex OR test path pattern.
- Lines 28-58: stdin read loop, JSON parse, tool name dispatch. For `Read`, reads `toolInput.file_path`. For `Grep`, reads `toolInput.path`. Falls through to `isSourceOrConfigFile(targetPath)` check — this is the gap (directory paths like `"src/"` return false).
- Lines 60-84: Produces `{ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: "<orchestrator-read-warning>...</orchestrator-read-warning>" } }` and exits 0.
- No `require('node:fs')` import exists — must be added in T2.
- Uses CommonJS (`require()`), not ESM (`import`). Must stay CommonJS.

**`plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md`** — 83-line skill. Current frontmatter (lines 1-3):

```yaml
---
description: Orchestrator context window discipline enforcement. Prevents...
---
```

Target state after T3: add `user-invocable: true` on line 3, before closing `---`. No `name:` field. Body content unchanged.

**`plugins/orchestrator-discipline/hooks.json`** — does NOT need modification. It wires two PreToolUse hooks: `Read|Grep` matcher to `pre-tool-orchestrator-read-warning.cjs` and `Bash` matcher to `pre-tool-diagnostic-command-gate.cjs`, both invoked as `node "${CLAUDE_PLUGIN_ROOT}/hooks/..."`.

---

### Hook Architecture — How the Read Warning Hook Works

When Claude Code fires a PreToolUse event for `Read` or `Grep`, it pipes a JSON object to the hook's stdin in the form:

```json
{ "tool_name": "Grep", "tool_input": { "path": "src/", "pattern": "foo" } }
```

The hook reads all stdin, parses the JSON, checks `tool_name`, extracts `targetPath` (from `tool_input.file_path` for Read, from `tool_input.path` for Grep), then calls `isSourceOrConfigFile(targetPath)`. If that returns true, the hook writes a `hookSpecificOutput.additionalContext` JSON block. If false, it writes `{}`. Both paths call `process.exit(0)` — the hook is strictly non-blocking.

The gap: `isSourceOrConfigFile("src/")` returns false because neither the extension regex nor the test-path pattern match a bare directory string. The fix adds two new functions (`isDirectory` and `looksLikeDirectory`) and OR-extends the `shouldWarn` condition in the Grep branch only.

The exact logic change to implement (from architect spec):

```text
// Add at top of file alongside existing requires:
const fs = require('node:fs');

// Add two new helper functions after isSourceOrConfigFile():

function isDirectory(targetPath) {
  try { return fs.statSync(targetPath).isDirectory(); } catch { return false; }
}

function looksLikeDirectory(targetPath) {
  if (!targetPath) return false;
  if (targetPath.endsWith('/') || targetPath.endsWith('\\')) return true;
  const lastSegment = targetPath.split(/[\\/]/).filter(Boolean).pop() || '';
  return !lastSegment.includes('.');
}

// Change Grep branch from:
shouldWarn = isSourceOrConfigFile(targetPath) || isTestPath(targetPath)

// To:
shouldWarn = isSourceOrConfigFile(targetPath)
          || isTestPath(targetPath)
          || isDirectory(targetPath)
          || looksLikeDirectory(targetPath)
```

Note: `BACKLOG.md` has a `.md` extension — it does NOT match `SOURCE_FILE_EXTENSIONS`, is NOT a test path, `fs.statSync("BACKLOG.md").isDirectory()` returns false, and it does NOT pass `looksLikeDirectory` (it has `.` in the last segment). So `BACKLOG.md` will correctly produce `{}` output.

---

### `user-invocable: true` Syntax — Confirmed Pattern

From `plugins/plugin-creator/skills/skill-creator/SKILL.md` lines 1-5 (read directly):

```yaml
---
description: Guide for creating effective skills...
license: Complete terms in LICENSE.txt
user-invocable: true
---
```

The field name is `user-invocable` (hyphenated), value is YAML boolean `true` (not the string `"true"`). Place after `description:`, before the closing `---`.

---

### Plugin.json Schema — What Is and Is Not Allowed

Per `plugins/plugin-creator/skills/claude-plugins-reference-2026/SKILL.md:32-52` and confirmed in `plugins/plugin-creator/CLAUDE.md` "Plugin.json Requirements" section:

Valid component path fields: `commands`, `agents`, `skills`, `hooks`, `mcpServers`, `outputStyles`, `lspServers`.

The field `rules` is NOT in the schema — this is the direct cause of the `Unrecognized key: "rules"` validation error.

The `commands` field is the legacy registration path. Per the CLAUDE.md: "Skills and slash commands are now unified — they are the same system." The canonical registration after the fix is `skills` in plugin.json plus `user-invocable: true` in SKILL.md frontmatter.

---

### Plugin Root CLAUDE.md Pattern — Confirmed

Two existing plugins use root-level `CLAUDE.md` as the mechanism for delivering session-level behavioral context:

- `plugins/development-harness/CLAUDE.md` — confirmed present (directory listing shows it)
- `plugins/plugin-creator/CLAUDE.md` — confirmed present (read in full above)

`plugins/orchestrator-discipline/` currently has NO root-level `CLAUDE.md`. The `rules/CLAUDE.md` at `plugins/orchestrator-discipline/rules/CLAUDE.md` is the content to be moved.

---

### Validation Tools

Two validators are used in T4:

1. `claude plugin validate plugins/orchestrator-discipline/` — official Claude Code CLI validator. Checks: plugin.json schema compliance, `name` field present and kebab-case, all paths start with `./`, referenced files exist. Current failure: `✘ Found 1 error: root: Unrecognized key: "rules"`.

2. `./plugins/plugin-creator/scripts/plugin_validator.py plugins/orchestrator-discipline/` — repo-internal validator. Invoked as `uv run plugins/plugin-creator/scripts/plugin_validator.py plugins/orchestrator-discipline/`. Validates frontmatter, skill complexity (token-based), internal links, cross-references. Use `--verbose` for detail; `--fix` for auto-remediation of known issues (removes `name:` fields from plugin skills automatically).

Linting tool: `uv run prek run --files <path>` — runs all configured pre-commit hooks against specific files. Used to confirm markdown formatting compliance.

---

### Critical Constraints for All Tasks

- Do NOT manually edit `version` fields in `plugin.json` or `.claude-plugin/marketplace.json` — `auto_sync_manifests.py` pre-commit hook handles versioning on commit.
- Do NOT run `git commit` or `git add` — leave staging for human review.
- Do NOT use ESM `import` syntax in the JS hook — file uses CommonJS `require()`.
- Do NOT add external npm dependencies to the hook — use only `node:` stdlib modules.
- Do NOT add a `name:` field to SKILL.md — doing so suppresses slash command registration.
- Do NOT change the `additionalContext` XML content or tag name in the hook.
- Conventional commit scope for this plugin: `fix(orchestrator-discipline): ...`

---

### File Paths for Implementation

| File | Task | Action |
|------|------|--------|
| `plugins/orchestrator-discipline/.claude-plugin/plugin.json` | T1 | Remove `rules` and `commands` fields |
| `plugins/orchestrator-discipline/CLAUDE.md` | T1 | Create — copy verbatim content from `rules/CLAUDE.md` |
| `plugins/orchestrator-discipline/rules/CLAUDE.md` | T1 | Document for deletion (do not delete in T1 — leave for human) |
| `plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` | T2 | Add `fs` require + two helper functions + extend Grep shouldWarn |
| `plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md` | T3 | Add `user-invocable: true` to frontmatter only |

Reference files (read-only):

- `plugins/plugin-creator/skills/claude-plugins-reference-2026/SKILL.md` — lines 32-52 (schema), lines 148-153 (auto-loading table)
- `plugins/plugin-creator/CLAUDE.md` — skill name field bug, plugin.json requirements
- `plugins/orchestrator-discipline/hooks/pre-tool-diagnostic-command-gate.cjs` — do NOT modify (out of scope)
- `plugins/orchestrator-discipline/skills/orchestrator-discipline/references/investigation-escalation.md` — do NOT modify (out of scope)

---

### What NOT to Re-Investigate

The following questions were resolved by the architect doc and do NOT need re-investigation:

- Whether `rules` is a valid plugin.json field — it is NOT (confirmed schema gap).
- Which delivery mechanism for rules content — plugin root `CLAUDE.md` is chosen (Decision 1).
- Whether to keep `commands` field — remove it (Decision 4).
- Whether `user-invocable: true` is needed — yes (Decision 3).
- Whether `name:` should be added — NO, confirmed bug means omitting `name:` is correct.
- Whether `fs.statSync` is safe in CommonJS Node.js hooks — yes, with try/catch (confirmed pattern).
- Whether `BACKLOG.md` would trigger the new directory detection — confirmed NO (has `.md` extension, `isDirectory()` returns false, `looksLikeDirectory` returns false).

---

## Dependency Graph

```
T1 (plugin.json fix)    ─┐
T2 (Grep dir coverage)  ─┼─→ T4 (Full validation suite)
T3 (SKILL.md frontmatter)┘
```

T1, T2, and T3 are independent and can execute in parallel.
T4 depends on T1, T2, and T3 all completing successfully.

---

## Priority Ordering

| Task | Priority | Complexity | Depends On     | Parallelize With |
|------|----------|------------|----------------|------------------|
| T1   | High     | Low        | None           | T2, T3           |
| T2   | High     | Medium     | None           | T1, T3           |
| T3   | Medium   | Low        | None           | T1, T2           |
| T4   | High     | Medium     | T1 + T2 + T3   | None             |

---

## Tasks

---

### T1: Fix plugin.json Validation Failure

```yaml
---
task: T1
title: Fix plugin.json validation failure (BLOCKER)
status: not-started
agent: general-purpose
dependencies: []
priority: 1
complexity: low
accuracy-risk: medium
parallelize-with: [T2, T3]
reason: T1, T2, T3 touch different files — plugin.json, a JS hook, and SKILL.md respectively. No file conflicts.
handoff: "Report: final plugin.json contents, output of `claude plugin validate`, disposition of rules/CLAUDE.md content (merged/moved/kept), and whether `commands` field was removed."
---
```

#### Context

`plugins/orchestrator-discipline/.claude-plugin/plugin.json` currently contains a `"rules"` key
that is not in the Claude Code plugin.json schema. This causes:

```
✘ Found 1 error: root: Unrecognized key: "rules"
```

The schema (per `plugins/plugin-creator/skills/claude-plugins-reference-2026/SKILL.md:32-52`)
allows only: `commands`, `agents`, `skills`, `hooks`, `mcpServers`, `outputStyles`, `lspServers`.

The `rules` field points to `./rules`, which contains
`plugins/orchestrator-discipline/rules/CLAUDE.md` — a 143-line behavioral constraints file. The
plugin also declares both `"skills"` and `"commands"` pointing to the same
`./skills/orchestrator-discipline` path, which may cause a double-registration issue surfaced after
the `rules` field is removed.

No other plugin in this repository uses a `rules` field. Alternate patterns for surfacing rules
content: plugin root `CLAUDE.md`, inline in `SKILL.md`, or `skills/.../references/` file.

#### Objective

Remove the invalid `rules` field from `plugin.json`, preserve `rules/CLAUDE.md` content via a
verified loading mechanism, and make `claude plugin validate plugins/orchestrator-discipline/` exit
0 with no errors.

#### Required Inputs

- `plugins/orchestrator-discipline/.claude-plugin/plugin.json` — current manifest
- `plugins/plugin-creator/skills/claude-plugins-reference-2026/SKILL.md` — authoritative schema
  reference (lines 32-52 for component path fields, lines 148-153 for auto-loading table)
- `plugins/orchestrator-discipline/rules/CLAUDE.md` — content to be preserved
- `plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md` — may need update if
  content is merged here
- `plugins/plugin-creator/CLAUDE.md` — skill name field bug notes (affects whether `commands`
  field is needed)
- Assumption: `claude` CLI is available on PATH. Confirm with `which claude`.

#### Requirements

1. Remove `"rules": ["./rules"]` from `plugin.json`.
2. Move the content of `./rules/CLAUDE.md` to `plugins/orchestrator-discipline/CLAUDE.md` (plugin
   root). This is the confirmed pattern used by `plugins/development-harness/` and
   `plugins/plugin-creator/` — root-level `CLAUDE.md` is auto-loaded as plugin documentation
   context. Do not choose option B (SKILL.md body) or option C (references/rules.md); the
   architecture spec (Decision 1) has already evaluated and rejected those options.
3. Implement whichever option from requirement 2 is chosen. Do NOT delete `rules/CLAUDE.md`
   content without confirming it exists in the destination.
4. Assess whether `"commands": ["./skills/orchestrator-discipline"]` should be removed. Read
   `plugins/plugin-creator/CLAUDE.md` to confirm whether `commands` + `skills` pointing to the
   same path causes double-registration. Remove `commands` if it is redundant and the schema
   recommends `skills` alone.
5. Run `claude plugin validate plugins/orchestrator-discipline/` and verify exit code is 0.

#### Constraints

- Do NOT change the behavioral semantics of the hooks (what they warn about, what they allow).
- Do NOT modify `hooks/pre-tool-orchestrator-read-warning.cjs` or
  `hooks/pre-tool-diagnostic-command-gate.cjs` — those are T2's scope.
- Do NOT modify `skills/orchestrator-discipline/SKILL.md` frontmatter fields — that is T3's scope.
  You may append content to the body if merging rules, but do not touch frontmatter.
- Do NOT manually bump the version in `plugin.json` — the `auto_sync_manifests.py` pre-commit hook
  handles versioning automatically on commit.
- Do NOT run `git commit` — leave staging for the human to review.

#### Expected Outputs

- `plugins/orchestrator-discipline/.claude-plugin/plugin.json` — modified (no `rules` field, and
  possibly no `commands` field if determined redundant)
- One of:
  - `plugins/orchestrator-discipline/CLAUDE.md` created (if option A chosen), OR
  - `plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md` body updated (if
    option B chosen), OR
  - `plugins/orchestrator-discipline/skills/orchestrator-discipline/references/rules.md` created
    (if option C chosen)
- If `rules/CLAUDE.md` is superseded, document that it can be removed (but do NOT delete it in
  this task — leave deletion decision to human review).

#### Acceptance Criteria

1. `claude plugin validate plugins/orchestrator-discipline/` exits 0 with no errors printed.
2. `plugins/orchestrator-discipline/.claude-plugin/plugin.json` contains no `rules` key when
   inspected with `cat`.
3. The full text of the original `rules/CLAUDE.md` is reachable via one of the approved mechanisms
   (plugin root CLAUDE.md, SKILL.md body, or references/rules.md). Verify by reading the
   destination file and confirming the "no exemption categories" and "falsifiable test" language is
   present.
4. If `commands` field was removed: `plugin.json` contains no `commands` key. If kept: document
   why in handoff.
5. `node -e "JSON.parse(require('fs').readFileSync('plugins/orchestrator-discipline/.claude-plugin/plugin.json','utf8'))"` exits 0 (valid JSON).

#### Verification Steps

1. `claude plugin validate plugins/orchestrator-discipline/` — confirm output shows no errors and
   exit code is 0.
2. `cat plugins/orchestrator-discipline/.claude-plugin/plugin.json` — visually confirm no `rules`
   key present.
3. Read the destination file for `rules/CLAUDE.md` content. Grep for the string
   "no exemption categories" to confirm content survived.
4. `node -e "JSON.parse(require('fs').readFileSync('plugins/orchestrator-discipline/.claude-plugin/plugin.json','utf8'))"` — confirm valid JSON.

#### CoVe Checks

Key claims to verify:

- Claim: `rules` is not in the plugin.json schema.
- Claim: Plugin root `CLAUDE.md` is auto-loaded as plugin documentation context (per how other
  plugins deliver rule content).
- Claim: `commands` and `skills` pointing to the same path may cause double-registration.

Verification questions:

1. Does `plugins/plugin-creator/skills/claude-plugins-reference-2026/SKILL.md` lines 32-52 list
   `rules` as a valid component path field? (Expected: No.)
2. Does `plugins/plugin-creator/skills/claude-plugins-reference-2026/SKILL.md` lines 148-153
   (default directory auto-loading table) include a `rules/` or root `CLAUDE.md` row? (Determines
   which delivery mechanism is verified.)
3. Does `plugins/plugin-creator/CLAUDE.md` document whether `commands` + `skills` both pointing to
   the same directory path causes a schema error or harmless redundancy?

Evidence to collect:

- Read lines 32-52 and 148-153 of
  `plugins/plugin-creator/skills/claude-plugins-reference-2026/SKILL.md`.
- Read `plugins/plugin-creator/CLAUDE.md` for the skill name field bug and `commands` vs `skills`
  guidance.
- Read `plugins/development-harness/CLAUDE.md` or `plugins/agent-orchestration/CLAUDE.md` as an
  example of plugin root `CLAUDE.md` usage (confirm the pattern exists).

Revision rule:

If any CoVe check reveals the schema allows `rules`, or that root `CLAUDE.md` is NOT auto-loaded,
revise the delivery mechanism choice and state what changed in the handoff.

---

### T2: Fix Grep Directory Path Coverage in Hook

```yaml
---
task: T2
title: Fix Grep directory path coverage in pre-tool-orchestrator-read-warning.cjs
status: not-started
agent: general-purpose
dependencies: []
priority: 1
complexity: medium
accuracy-risk: medium
parallelize-with: [T1, T3]
reason: T2 modifies only the JS hook file. T1 touches plugin.json and potentially rules/CLAUDE.md. T3 touches SKILL.md. No overlap.
handoff: "Report: the exact code change made (diff or before/after), output of `node --check`, test evidence for all four Grep scenarios in acceptance criteria, and whether BACKLOG.md Grep calls were determined to trigger or not (with rationale documented)."
---
```

#### Context

`plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` (86 lines) fires a
`<orchestrator-read-warning>` advisory for `Read` and `Grep` tool calls when the target path has a
source file extension. The current gate function:

```javascript
const SOURCE_FILE_EXTENSIONS =
  /\.(py|toml|yaml|yml|js|ts|jsx|tsx|json|cfg|ini|env|sh|bash|go|rs|rb|java|c|cpp|h|hpp)$/i;

function isSourceOrConfigFile(filePath) {
  return SOURCE_FILE_EXTENSIONS.test(filePath) || TEST_PATH_PATTERN.test(filePath);
}
```

When an orchestrator calls `Grep(pattern="class.*Service", path="src/")`, `targetPath` is `"src/"`.
`isSourceOrConfigFile("src/")` returns false — no extension match, no test path match — and the
hook silently passes. This is the primary failure mode: directory-targeted Grep by an orchestrator
escapes the warning.

The codebase patterns doc (`plan/codebase/orchestrator-discipline-patterns.md`, section 5.2)
provides two detection approaches: `fs.statSync` (filesystem check) and pattern heuristics
(trailing slash or no dot in last segment).

The hook must NOT crash when `path` is absent from `tool_input` (current code already guards with
`toolInput.path || ''`).

#### Objective

Extend the hook so that `Grep` calls where `path` is a directory (detected via heuristic or
`fs.statSync`) also trigger the `<orchestrator-read-warning>` advisory, without introducing
crashes or false-positive noise on legitimate markdown/plan-file searches.

#### Required Inputs

- `plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` — full file to
  read before editing
- `plan/codebase/orchestrator-discipline-patterns.md` sections 4 and 5 — gap analysis and
  detection options
- `plan/feature-context-validate-orchestrator-discipline.md` Q3 (lines 183-194) — options A–D for
  directory detection scope

#### Requirements

1. Read the full current hook file before making any changes.
2. Add directory detection to the `Grep` path-checking logic. Implement **Option A from Q3** (fire
   for any directory path) combined with a heuristic guard: treat a path as a directory if
   `fs.statSync(path).isDirectory()` returns true, OR if the path ends with `/`, OR if the last
   segment of the path contains no `.` character. Wrap `fs.statSync` in a try/catch that returns
   false on any error (path does not exist or is inaccessible).
3. `BACKLOG.md` is a legitimate orchestrator read target (tracking file, not source code). Grep
   calls with `path: "BACKLOG.md"` must NOT trigger the hook. Confirm that `BACKLOG.md` does not
   match the new directory detection logic (it will not — it has a `.md` extension and
   `isDirectory()` will return false). Document in a code comment that `.md` files are excluded by
   the extension check already.
4. Do not alter the existing behavior for `Read` calls or for `Grep` calls with source file
   extension paths — only extend the `Grep` directory detection branch.
5. Preserve the existing error-safety pattern: if `path` is absent or empty, the hook passes
   through silently (return `{}`).

#### Constraints

- Do NOT change the `additionalContext` message content or XML tag name — only the trigger logic.
- Do NOT change how the hook handles `Read` tool calls.
- Do NOT add any `console.error` or `console.warn` calls — the hook writes only to stdout.
- Do NOT use ES module syntax (`import`) — the file uses CommonJS `require()`.
- Do NOT add external npm dependencies — use only `node:` stdlib modules (`node:fs`, `node:path`).
- The hook must still exit via `process.exit(0)` in all code paths.
- `node --check` must pass on the modified file.

#### Expected Outputs

- `plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` — modified with
  directory detection logic added to the Grep branch

#### Acceptance Criteria

1. `node --check plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs`
   exits 0 (no syntax errors).
2. A test script that simulates `Grep({ pattern: "foo", path: "src/" })` via stdin produces JSON
   output containing `"additionalContext"`. (Simulate by piping JSON to the script via
   `echo '{"tool_name":"Grep","tool_input":{"path":"src/","pattern":"foo"}}' | node
   plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs`.)
3. A test with `path: "plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs"` (an
   existing `.js` file) produces `"additionalContext"` (existing behavior preserved).
4. A test with `path: "BACKLOG.md"` produces `{}` (no warning — markdown file excluded by
   extension check; not a source file extension, not a directory).
5. A test with `path: ""` (empty string) produces `{}` without crashing.

#### Verification Steps

1. `node --check plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs`
2. `echo '{"tool_name":"Grep","tool_input":{"path":"src/","pattern":"foo"}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` — output must contain `additionalContext`.
3. `echo '{"tool_name":"Grep","tool_input":{"path":"plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs","pattern":"foo"}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` — output must contain `additionalContext`.
4. `echo '{"tool_name":"Grep","tool_input":{"path":"BACKLOG.md","pattern":"foo"}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` — output must be `{}`.
5. `echo '{"tool_name":"Grep","tool_input":{"path":"","pattern":"foo"}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` — output must be `{}` and script must not throw.

#### CoVe Checks

Key claims to verify:

- Claim: `tool_input.path` is the correct field name for the Grep path argument in the hook's
  stdin JSON.
- Claim: `fs.statSync(path).isDirectory()` with a try/catch is safe to call from a Node.js hook
  in the repo's CommonJS + `node:fs` convention.
- Claim: `BACKLOG.md` will not trigger the new directory detection logic.

Verification questions:

1. Does the current hook file read Grep path as `toolInput.path` (not `toolInput.file_path` or
   another field)? Read `plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs`
   lines 48-51 to confirm.
2. Does `BACKLOG.md` end with `/`? Does it have no `.` in the last segment? (Both are false — it
   ends in `.md`.) Confirm that neither heuristic matches it and `fs.statSync("BACKLOG.md").isDirectory()` returns false (it is a file).
3. Does any other hook in this repo use `fs.statSync` from `node:fs`? If not, is there a
   documented reason to avoid it? Check `plugins/*/hooks/*.js` for filesystem access patterns.

Evidence to collect:

- Read lines 42-60 of `plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs`
  to confirm field names.
- Run verification step 4 (BACKLOG.md test) and record the output.
- Search `plugins/*/hooks/*.js` for `statSync` to confirm or deny prior usage.

Revision rule:

If `tool_input.path` is not the correct field name, correct the field access in the implementation
and state the actual field name in the handoff. If `fs.statSync` is found to be inappropriate
(e.g., hook runs before the path exists on disk), fall back to the heuristic-only approach (Option
B from section 5.2) and document why.

---

### T3: Fix SKILL.md Frontmatter and Linting

```yaml
---
task: T3
title: Fix SKILL.md frontmatter user-invocable field and run linting
status: not-started
agent: general-purpose
dependencies: []
priority: 2
complexity: low
accuracy-risk: medium
parallelize-with: [T1, T2]
reason: T3 touches only SKILL.md frontmatter. T1 touches plugin.json and rules/CLAUDE.md. T2 touches the JS hook. No overlap.
handoff: "Report: final frontmatter of SKILL.md (full YAML block), output of `uv run prek run --files`, and rationale for the user-invocable value chosen."
---
```

#### Context

`plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md` (83 lines) has minimal
frontmatter:

```yaml
---
description: "..."
---
```

Two questions are unresolved per the feature context doc:

- Q2: Should `user-invocable: true` be added? (The `commands` field in `plugin.json` points to this
  skills directory, which may register it as a slash command. The `plugin-creator` CLAUDE.md notes
  that a `name:` field causes skills NOT to appear as slash commands — the current SKILL.md has no
  `name:` field, which is correct.)
- Q4: The `commands` field in `plugin.json` declares the same path as `skills`. After T1 resolves
  the `commands` redundancy question, T3 must ensure SKILL.md frontmatter is correct for whichever
  registration mechanism remains.

Per `plugins/plugin-creator/CLAUDE.md` (skill name field bug section, per feature context doc line
282): `user-invocable: true` must be set for the skill to appear in the slash command menu.

#### Objective

Determine the correct value for `user-invocable` in the SKILL.md frontmatter, add the field, and
confirm the file passes `uv run prek run --files`.

#### Required Inputs

- `plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md` — full file to read
  before editing
- `plugins/plugin-creator/CLAUDE.md` — skill name field bug section (determines whether
  `user-invocable: true` is needed and whether `name:` field must be absent)
- `plugins/plugin-creator/skills/claude-plugins-reference-2026/SKILL.md` — SKILL.md frontmatter
  field reference (what fields are valid)
- One working example SKILL.md from another plugin that uses `user-invocable: true` — confirm the
  field name and value format (true vs "true" vs boolean)
- T1 handoff (if available): whether `commands` field was removed from `plugin.json`. If `commands`
  was removed, `user-invocable: true` is the only registration mechanism — it becomes required, not
  optional.

#### Requirements

1. Read the full current SKILL.md before editing.
2. Read `plugins/plugin-creator/CLAUDE.md` to find the definitive answer on whether
   `user-invocable: true` is required for slash command registration when `name:` is absent.
3. Find one existing SKILL.md in this repo that uses `user-invocable: true` and confirm the exact
   YAML syntax (field name, value format).
4. Add `user-invocable: true` to the frontmatter if confirmed required. Place it after
   `description:` and before any other fields, consistent with the example found in requirement 3.
5. Do NOT add a `name:` field — the feature context doc (line 282) explicitly states the absence
   of `name:` is correct.
6. Run `uv run prek run --files plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md`
   and resolve any linting findings.

#### Constraints

- Do NOT change the body content of SKILL.md — only frontmatter.
- Do NOT add `name:` to the frontmatter.
- Do NOT change the `description:` value.
- If T1 has not completed, proceed with `user-invocable: true` as the default choice (the feature
  context doc states manual invocation is a desired use case per scenario 6, line 136-139).
- Do NOT run `git commit`.

#### Expected Outputs

- `plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md` — modified frontmatter
  with `user-invocable: true` added (and any linting fixes applied)

#### Acceptance Criteria

1. SKILL.md frontmatter contains `user-invocable: true` (exact YAML boolean, not string `"true"`).
2. SKILL.md frontmatter does NOT contain a `name:` field.
3. `uv run prek run --files plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md`
   exits 0 with no errors.
4. SKILL.md body content (lines after the closing `---`) is unchanged from the original.

#### Verification Steps

1. Read the modified SKILL.md and print the frontmatter block (lines 1 to closing `---`). Confirm
   `user-invocable: true` is present and `name:` is absent.
2. `uv run prek run --files plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md`
   — record full output; confirm exit 0.
3. `grep -n "user-invocable" plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md`
   — confirm line number and value.
4. `grep -n "^name:" plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md` —
   confirm no output (field absent).

#### CoVe Checks

Key claims to verify:

- Claim: `user-invocable: true` (YAML boolean) is the correct field name and value format for
  slash command registration in plugin SKILL.md files.
- Claim: The absence of a `name:` field is intentional and correct (not a missing required field).

Verification questions:

1. Does any existing SKILL.md in `plugins/*/skills/` use `user-invocable: true`? Find one and read
   its frontmatter to confirm exact syntax. (`Grep(pattern="user-invocable", path="plugins/")`)
2. Does `plugins/plugin-creator/CLAUDE.md` or the plugin-creator skill reference explicitly state
   that `name:` in SKILL.md frontmatter prevents slash command registration?
3. Does `plugins/plugin-creator/skills/claude-plugins-reference-2026/SKILL.md` list `user-invocable`
   as a valid frontmatter field for skills?

Evidence to collect:

- Run `Grep(pattern="user-invocable", path="plugins/")` and read one matching file to confirm
  field syntax.
- Read the relevant section of `plugins/plugin-creator/CLAUDE.md` and cite the exact line.

Revision rule:

If `user-invocable` is not found in any existing SKILL.md, the field name may be wrong. Check the
plugin-creator reference for the correct field name before writing. State the finding and actual
field name in the handoff.

---

## SYNC CHECKPOINT 1: T1 + T2 + T3 Convergence

Convergence point: All three of T1, T2, T3 must complete before T4 starts.

Quality gates:

- T1: `claude plugin validate plugins/orchestrator-discipline/` exits 0
- T1: `plugin.json` contains no `rules` key; `rules/CLAUDE.md` content preserved in verified
  destination
- T2: All 5 verification step commands for T2 produce expected outputs
- T2: `node --check` passes on the modified hook file
- T3: `user-invocable: true` present in SKILL.md frontmatter, `name:` absent
- T3: `uv run prek run --files` passes on SKILL.md

Reflection questions:

- Did T1 remove the `commands` field? If so, does T3's frontmatter still correctly register the
  skill?
- Did T2 introduce any new import (`require`) statements? If so, does T1's updated `plugin.json`
  need any adjustment?
- Are there any emergent conflicts between the three parallel fixes?

Proceed to T4 only after all T1 + T2 + T3 acceptance criteria are confirmed met.

---

### T4: Full Validation Suite

```yaml
---
task: T4
title: Full validation suite — end-to-end verification of all orchestrator-discipline fixes
status: not-started
agent: general-purpose
dependencies: [T1, T2, T3]
priority: 1
complexity: medium
accuracy-risk: low
parallelize-with: []
reason: T4 is the convergence task; it depends on all three prior tasks completing. No parallelism possible.
handoff: "Report: output of each validation command (copy-pasted, not summarized), pass/fail status for each acceptance criterion, any pre-existing issues found in plugin_validator.py output, and the documented test procedure for hook behavior."
---
```

#### Context

T1, T2, and T3 have each addressed one gap in the orchestrator-discipline plugin:

- T1: Removed invalid `rules` field from `plugin.json`
- T2: Extended Grep directory detection in `pre-tool-orchestrator-read-warning.cjs`
- T3: Added `user-invocable: true` to SKILL.md frontmatter

T4 runs the complete validation suite across all plugin files to confirm the fixes integrate
correctly and no regressions exist.

Two validators exist for this repo:

- `claude plugin validate plugins/orchestrator-discipline/` — official Claude Code CLI validator
- `./plugins/plugin-creator/scripts/plugin_validator.py plugins/orchestrator-discipline/` — repo
  internal validator script

Both must be run. Failures in `plugin_validator.py` must be documented; pre-existing failures
(present before T1/T2/T3 changes) should be noted as pre-existing and added to the backlog if not
fixed.

#### Objective

Confirm that all fixes from T1, T2, and T3 integrate correctly, both validators pass (or known
pre-existing failures are documented), all modified files pass `prek` linting, and the hook
behavior is verified end-to-end via the five test commands defined in T2's verification steps.

#### Required Inputs

- All modified plugin files (outputs from T1, T2, T3)
- T1, T2, T3 handoff reports (review before starting)
- `plugins/plugin-creator/scripts/plugin_validator.py` — internal validator
- `uv run prek run` — linting tool

#### Requirements

1. Verify T1, T2, and T3 handoff reports confirm all their acceptance criteria are met before
   proceeding.
2. Run `claude plugin validate plugins/orchestrator-discipline/` and capture full output.
3. Run `./plugins/plugin-creator/scripts/plugin_validator.py plugins/orchestrator-discipline/` and
   capture full output.
4. Collect the list of all files modified across T1, T2, T3 and run
   `uv run prek run --files <each-modified-file>` on each one.
5. Re-run the five hook behavior test commands from T2's verification steps to confirm hook
   behavior end-to-end (not just the modified logic in isolation).
6. Document the test procedure for hook behavior as a short code block that can be re-run by a
   human reviewer.
7. If `plugin_validator.py` reports errors not related to the T1/T2/T3 changes (pre-existing
   issues), document each one with file and line reference, and add a backlog item for each.

#### Constraints

- Do NOT fix issues discovered in step 7 in this task — document them only. Scope boundaries apply.
- Do NOT run `git commit` or `git add`.
- Do NOT modify any files unless a T1/T2/T3 fix was not correctly applied (in which case, apply
  only the missing part of the fix with a note in the handoff).

#### Expected Outputs

- A validation report (written to stdout / handoff) containing:
  - Full output of `claude plugin validate` (copy-pasted verbatim)
  - Full output of `plugin_validator.py` (copy-pasted verbatim)
  - Full output of `prek` linting for each modified file
  - Pass/fail result for each acceptance criterion
  - Hook behavior test results (all five commands and their outputs)
  - List of any pre-existing issues found (if any)

#### Acceptance Criteria

1. `claude plugin validate plugins/orchestrator-discipline/` exits 0 with 0 errors.
2. `plugin_validator.py plugins/orchestrator-discipline/` exits 0, OR any non-zero exit is
   explained by pre-existing issues documented with file:line citations.
3. `uv run prek run --files` passes (exit 0) for every file modified in T1, T2, and T3.
4. Hook test — directory path: `echo '{"tool_name":"Grep","tool_input":{"path":"src/","pattern":"foo"}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` produces JSON containing `"additionalContext"`.
5. Hook test — source file path: `echo '{"tool_name":"Grep","tool_input":{"path":"plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs","pattern":"foo"}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` produces JSON containing `"additionalContext"`.
6. Hook test — markdown path: `echo '{"tool_name":"Grep","tool_input":{"path":"BACKLOG.md","pattern":"foo"}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` produces `{}`.
7. Hook test — empty path: `echo '{"tool_name":"Grep","tool_input":{"path":"","pattern":"foo"}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` produces `{}` and exits without error.
8. SKILL.md frontmatter contains `user-invocable: true` and no `name:` field (confirmed by grep).
9. `plugin.json` contains no `rules` key (confirmed by grep or cat).
10. `rules/CLAUDE.md` content (the "no exemption categories" language) is present in the
    destination file chosen in T1.
11. Hook test — extensionless directory path: `echo '{"tool_name":"Grep","tool_input":{"path":"plugins/orchestrator-discipline/hooks","pattern":"def "}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` produces JSON containing `"additionalContext"` (tests the `looksLikeDirectory` heuristic for paths with no file extension and no trailing slash).

#### Verification Steps

1. `claude plugin validate plugins/orchestrator-discipline/` — copy full output to handoff.
2. `./plugins/plugin-creator/scripts/plugin_validator.py plugins/orchestrator-discipline/` — copy full output to handoff.
3. For each modified file path from T1/T2/T3 handoffs: `uv run prek run --files <path>` — copy output for each.
4. Run all five echo-pipe test commands from acceptance criteria 4–7 above and copy outputs.
5. `grep -n "rules" plugins/orchestrator-discipline/.claude-plugin/plugin.json` — confirm no output.
6. `grep -n "user-invocable" plugins/orchestrator-discipline/skills/orchestrator-discipline/SKILL.md` — confirm `user-invocable: true` on output.
7. `grep -n "no exemption categories" <destination-file-from-T1>` — confirm content present.
8. `echo '{"tool_name":"Grep","tool_input":{"path":"plugins/orchestrator-discipline/hooks","pattern":"def "}}' | node plugins/orchestrator-discipline/hooks/pre-tool-orchestrator-read-warning.cjs` — output must contain `additionalContext` (extensionless directory path coverage).

---

## SYNC CHECKPOINT 2: Final Review

Convergence point: T4 must complete and all acceptance criteria pass.

Quality gates:

- `claude plugin validate` exits 0
- `plugin_validator.py` exits 0 or pre-existing issues are fully documented
- All prek linting passes
- All five hook behavior tests produce expected outputs
- `rules/CLAUDE.md` content preserved in verified destination
- No unaddressed issues introduced by T1/T2/T3

If any quality gate fails, return the failing task to `not-started` and re-execute with the
specific failure mode documented.

Ready for human review and commit when all gates pass.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.