oh-my-claudecode
Splits a complex task across several specialized Claude Code agents working in parallel, then keeps going until the result is checked. You describe what you want in plain language instead of memorizing commands.
What navigator runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
Claude Code
> /plugin marketplace add qf-studio/navigator> /plugin install navigator@navigator-marketplace
Cursor
Cursor also runs Claude Code hooks from .claude/settings.json, so copy these hooks there to use them in Cursor.
Where it lives
#!/usr/bin/env python3
"""nav_dispatch — single dispatcher entrypoint for every Navigator hook event (TASK-60).
plugin.json routes the seven v6 surfaces here: python3 nav_dispatch.py <EventName>.
Thin shim: read stdin once, delegate to nav_hook_lib.runtime.dispatch(), relay the
single JSON doc + stderr (sentinels.emit_stderr, mem-034) + exit code. Fail-open:
ANY failure — bad argv/stdin, missing runtime, escaping SystemExit, broken stdout
pipe — exits 0 (BaseException catch-all: hooks are non-interactive). stdout flushes
INSIDE the guard so a closed pipe cannot become exit 120 at interpreter shutdown.
"""
import os
import sys
def main() -> int:
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from nav_hook_lib import hio, runtime, sentinels
event = sys.argv[1]
payload = hio.read_stdin_payload()
result = runtime.dispatch(event, payload)
if result.stdout is not None:
print(result.stdout)
sys.stdout.flush() # broken pipe raises HERE, inside the catch-all
if result.stderr is not None:
sentinels.emit_stderr(result.stderr)
return result.exit_code
if __name__ == "__main__":
try:
exit_code = main()
except BaseException:
exit_code = 0 # fail-open: Navigator must never brick the harness
try:
sys.stdout.flush()
except BaseException:
os._exit(exit_code) # dead stdout: bypass shutdown flush (exit-120 guard)
sys.exit(exit_code)
#!/usr/bin/env python3
"""Subprocess contract harness for hooks/nav_dispatch.py (TASK-60 Phase 5).
Template: hooks/test_workflow_enforcer.py (TASK-45 precedent) — each test
builds a throwaway project dir and drives the dispatcher as a subprocess
(`python3 hooks/nav_dispatch.py <event>`) with a JSON payload on stdin,
asserting on stdout/exit code only. stdlib unittest (pytest not installed).
Mandatory cases from the TASK-60 acceptance list covered here:
- Pristine v6.18.1 config fixture -> exit 0 on every v6 event surface,
with at most ONE JSON document on stdout.
- Project with NO .agent/ -> exit 0 AND empty stdout on every event, and
the dispatcher never CREATES .agent/ (silent degradation).
- PILOT_EXECUTOR=1 -> no blocking output on any event. NOTE: TASK-61 ops
do not exist yet, so this is the dispatch-level synthetic check (clean
exit, no block/deny/continue:false emissions); op-level bypass cases
(e.g. read_guard deny suppressed under Pilot) land with the TASK-61
ports that plug into this harness.
- Per-behavior off-switch: a config with every v6 toggle block disabled
(read_guard_hook.enabled=false etc.) -> exit 0 everywhere, and the
config gate skips ops BEFORE import (no missing-module op_errors notes
for gated-off ops).
- Malformed stdin fails open (exit 0); missing/unknown event arg -> exit
0, no output.
- Crash-injection: NOT feasible at the subprocess level right now — the
real op modules land in TASK-61, so there is nothing on the live
registry to crash. Instead a tmp-dir driver script imports
nav_hook_lib.runtime directly and dispatches a SYNTHETIC registry
(contract: the `registry` param overrides EVENT_OPS for testability)
with fake op modules: crash isolation, sentinel stderr hygiene
(mem-034: no payload echo), meta.op_errors, health-file write +
SessionStart surfacing, and gate short-circuit of rightward phases.
- Timing: UserPromptSubmit dispatched 20x against
nav_hook_lib/fixtures/timing_prompt.json; p95 <= 200ms * NAV_TIMING_MULT
(env, default 1 — set >1 on slow CI runners).
Out of scope here (other TASK-60 groups): mem-036 three-env-variant manifest
command tests (need .claude-plugin/plugin.json — integrator), state
read-once/write-once unit verification (runtime builder's colocated tests).
"""
import json
import math
import os
import subprocess
import sys
import tempfile
import time
import unittest
from pathlib import Path
HOOKS_DIR = Path(__file__).resolve().parent
HOOK = str(HOOKS_DIR / "nav_dispatch.py")
FIXTURES = HOOKS_DIR / "nav_hook_lib" / "fixtures"
PRISTINE_CONFIG = (FIXTURES / "nav-config-v6.18.1.json").read_text()
TIMING_FIXTURE = FIXTURES / "timing_prompt.json"
# The seven v6 manifest event surfaces (registry.EVENT_OPS keys — TASK-60
# registers ONLY these; new routing-matrix events belong to TASK-62).
EVENTS = (
"SessionStart",
"UserPromptSubmit",
"PreToolUse",
"PostToolUse",
"Stop",
"PreCompact",
"PostCompact",
)
# Realistic per-event payload shapes (tool_name chosen to HIT the coarse
# registry matchers: 'Read' and 'Edit|Write|MultiEdit|NotebookEdit').
EVENT_PAYLOAD_EXTRAS = {
"SessionStart": {"source": "startup"},
"UserPromptSubmit": {"prompt": "hello there"},
"PreToolUse": {"tool_name": "Read", "tool_input": {"file_path": "/tmp/x.md"}},
"PostToolUse": {
"tool_name": "Edit",
"tool_input": {"file_path": "/tmp/x.py"},
"tool_response": {},
},
"Stop": {"stop_hook_active": False},
"PreCompact": {"trigger": "manual"},
"PostCompact": {},
}
# v6 toggle block names (from fixtures/nav-config-v6.18.1.json) -> the op
# names the registry gates on them. Used by the off-switch tests.
TOGGLE_BLOCKS = (
"session_start_hook",
"workflow_enforcer_hook",
"brief_hook",
"read_guard_hook",
"task_graph_sync_hook",
"profile_sync_hook",
"workflow_state_hook",
"compact_hook",
)
GATED_OPS = (
"session_start",
"prompt_gate",
"prompt_brief",
"read_guard",
"graph_sync",
"profile_sync",
"stop_state",
"compact_marker",
)
ALL_TOGGLES_OFF = json.dumps({block: {"enabled": False} for block in TOGGLE_BLOCKS})
_ISOLATED_CONFIG_HOME = tempfile.TemporaryDirectory()
def clean_env(extra=None):
"""Subprocess env with the escape hatches / project redirects removed.
CLAUDE_PROJECT_DIR must go: with malformed stdin the payload is {}, and
an inherited value would redirect hio.resolve_cwd() at the REAL repo.
"""
env = os.environ.copy()
for var in ("PILOT_EXECUTOR", "CLAUDE_PROJECT_DIR", "CLAUDE_USER_MESSAGE"):
env.pop(var, None)
# TASK-82: per-person settings (ADHD switch) live outside the repo; point
# them at an empty dir so the developer's own switch never shapes a test.
env["NAVIGATOR_CONFIG_HOME"] = _ISOLATED_CONFIG_HOME.name
if extra:
env.update(extra)
return env
def run_dispatch(project_dir, event=None, payload=None, raw_stdin=None, env_extra=None):
"""Invoke `python3 nav_dispatch.py [<event>]` rooted at project_dir.
payload: sent as JSON on stdin ({} when None).
raw_stdin: sent verbatim (overrides payload) — malformed-input cases.
event: omitted from argv entirely when None (missing-arg case).
"""
argv = [sys.executable, HOOK]
if event is not None:
argv.append(event)
if raw_stdin is None:
raw_stdin = json.dumps(payload if payload is not None else {})
return subprocess.run(
argv,
input=raw_stdin,
capture_output=True,
text=True,
cwd=project_dir,
env=clean_env(env_extra),
)
def event_payload(project, event, session_id="s1"):
payload = {"cwd": project, "session_id": session_id}
payload.update(EVENT_PAYLOAD_EXTRAS.get(event, {}))
return payload
def parse_single_doc(testcase, stdout):
"""Contract: EXACTLY ONE JSON doc on stdout, or nothing. Returns doc/None.
js#!/usr/bin/env python3
"""Manifest + shim contract tests for nav_dispatch (TASK-60, shim-manifest group).
stdlib unittest only, subprocess-driven per the test_workflow_enforcer.py
template. Three concerns:
1. Manifest shape — .claude-plugin/plugin.json references ONLY
hooks/nav_dispatch.py, registers exactly the seven v6 event surfaces
plus the six TASK-62 events that survived the validate-or-drop gate
(SubagentStart, PostToolUseFailure, TaskCreated, TaskCompleted,
ConfigChange, Setup — all accepted by `claude plugin validate` on CC
2.1.205), with the contract matchers (PreToolUse: Read|Write|Edit|Bash|Skill; PostToolUse:
Edit|Write|MultiEdit|NotebookEdit; no matcher on any TASK-62 event) and
timeouts (SessionStart 10, PostToolUse 10, PreCompact 30, PostCompact 10
— the v6 allowances — all others 5, including every TASK-62 event).
Each command is the fail-OPEN shell guard: the dispatcher
file is [ -f ]-checked before exec, so a resolution miss exits 0
silently instead of python3's loud exit 2 (which the harness treats as
a block on every event).
2. mem-036 env variants — every event's LITERAL manifest command runs as a
subprocess (sh -c, so ${VAR:-fallback} expands exactly as the harness
would) under three CLAUDE_PLUGIN_ROOT variants:
* set-to-repo: resolves to this checkout; the dispatcher must exit 0 on
an empty payload (fail-open), and a seeded health file proves the
guard actually DISPATCHES (not silently skips) when the file exists.
* unset: sh substitutes the $HOME fallback. HOME is pointed at a temp
dir carrying a STALE marketplace clone (pre-v7: no nav_dispatch.py) —
the realistic fallback state. The guard must exit 0 silently: the old
loud-exit-2 behavior fails CLOSED and blocks every event.
* empty string: the :- operator treats empty like unset, so behavior
must match the unset variant (same fallback resolution).
3. Shim contract — hooks/nav_dispatch.py stays under 40 lines and exits 0
with no output on: empty JSON stdin, garbage stdin, missing event arg,
unknown event (fail-open; must hold with or without nav_hook_lib.runtime).
"""
import json
import os
import re
import subprocess
import tempfile
import unittest
from pathlib import Path
HOOKS_DIR = Path(__file__).resolve().parent
REPO_ROOT = HOOKS_DIR.parent
SHIM = HOOKS_DIR / "nav_dispatch.py"
PLUGIN_JSON = REPO_ROOT / ".claude-plugin" / "plugin.json"
EVENTS = (
"SessionStart",
"UserPromptSubmit",
"PreToolUse",
"PostToolUse",
"Stop",
"PreCompact",
"PostCompact",
# TASK-62 event surfaces (validate-or-drop survivors, CC 2.1.205):
"SubagentStart",
"PostToolUseFailure",
"TaskCreated",
"TaskCompleted",
"ConfigChange",
"Setup",
)
# v6 allowances: PostToolUse hooks had 10s EACH, PostCompact 10s — the shared
# dispatcher must not regress them to the 5s default.
EXPECTED_TIMEOUTS = {
"SessionStart": 10, "PostToolUse": 10, "PreCompact": 30, "PostCompact": 10,
}
DEFAULT_TIMEOUT = 5
EXPECTED_MATCHERS = {
"PreToolUse": "Read|Write|Edit|Bash|Skill",
"PostToolUse": "Edit|Write|MultiEdit|NotebookEdit",
}
# Fail-OPEN shell guard: missing dispatcher file -> exit 0 silently (stdin
# passes through the exec). %s is the event name.
COMMAND_GUARD = (
"sh -c 'f=\"${CLAUDE_PLUGIN_ROOT:-"
"$HOME/.claude/plugins/marketplaces/navigator-marketplace}"
"/hooks/nav_dispatch.py\"; "
"if [ -f \"$f\" ]; then exec python3 \"$f\" %s; fi'"
)
FALLBACK_RELPATH = ".claude/plugins/marketplaces/navigator-marketplace"
# Wedge guard: generous vs the 5-30s manifest timeouts; TimeoutExpired = fail.
SUBPROCESS_TIMEOUT = 20
def load_manifest():
return json.loads(PLUGIN_JSON.read_text(encoding="utf-8"))
def single_hook_entry(testcase, manifest, event):
"""Assert the event has exactly one matcher group with one hook; return both."""
groups = manifest["hooks"][event]
testcase.assertEqual(len(groups), 1, f"{event}: expected exactly one matcher group")
hooks = groups[0]["hooks"]
testcase.assertEqual(len(hooks), 1, f"{event}: expected exactly one hook entry")
return groups[0], hooks[0]
_ISOLATED_CONFIG_HOME = tempfile.TemporaryDirectory()
def clean_env(extra=None, drop=()):
env = os.environ.copy()
for key in ("PILOT_EXECUTOR", "CLAUDE_PROJECT_DIR", "CLAUDE_USER_MESSAGE"):
env.pop(key, None)
env["NAVIGATOR_CONFIG_HOME"] = _ISOLATED_CONFIG_HOME.name # TASK-82
for key in drop:
env.pop(key, None)
if extra:
env.update(extra)
return env
def run_shim(args, stdin="", env=None, cwd=None):
return subprocess.run(
["python3", str(SHIM), *args],
input=stdin,
capture_output=True,
text=True,
cwd=cwd or REPO_ROOT,
env=env or clean_env(),
timeout=SUBPROCESS_TIMEOUT,
)
def run_manifest_command(command, env, cwd, stdin="{}"):
"""Run the literal manifest command through sh -c, as the harness does."""
return subprocess.run(
["/bin/sh", "-c", command],
input=stdin,
capture_output=True,
text=True,
cwd=cwd,
env=env,
timeout=SUBPROCESS_TIMEOUT,
)
class ManifestShapeTest(unittest.TestCase):
"""plugin.json routes every event through nav_dispatch.py, nothing else."""
def setUp(self):
self.manifest = load_manifest()
def test_only_nav_dispatch_referenced(self):
raw = PLUGIN_JSON.read_text(encoding="utf-8")
scripts = set(re.findall(r"hooks/[A-Za-z0-9_]+\.py", raw))
self.assertEqual(scripts, {"hooks/nav_dispatch.py"})
def test_exactly_the_registered_event_surfaces(self):
# Seven v6 surfaces + six TASK-62 validate-or-drop survivors; every
# registration maps to a committed dispatcher (v5.1.0 lesson) and to
# a registry EVENT_OPS row (asserted in nav_hook_lib/test_registry).
self.assertEqual(set(self.manifest["hooks"].Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.
Splits a complex task across several specialized Claude Code agents working in parallel, then keeps going until the result is checked. You describe what you want in plain language instead of memorizing commands.
Turns a rough feature idea into a written spec through guided questions, then has the agent build it and checks the result against that spec. Instead of hand-checking whether the work is finished, you get an automatic evaluation gate that runs in your coding agent.
A plugin that runs coding tasks through multiple AI backends (Codex, Claude, Gemini, OpenCode) with a structured development workflow, parallel execution, browser automation and multi-session task checkpointing.
Coordinates AI agents with mechanical protocol enforcement, a workflow gate, memory validation and a session hook. Includes a catalog of specialist agents and has no runtime dependencies.
Bernstein is a Claude Code plugin for orchestrating AI agents. It adds skills to list and inspect agents, review and approve tasks, create tasks, track costs and budgets, and show alerts for failed or stalled work.
A Claude Code plugin that enforces finishing multi-step tasks with evidence and verification at each stage. It works as a procedure for Opus or any Claude model, not as chance.
Adjusts how third-party models behave inside Claude Code so they run closer to a native Opus session, covering subagent lifecycle, session hooks and tool interception. It does not replace your gateway, provider mapping or account setup.
Runs a PDCA workflow with phase gating, spec checks, and delegation to sub-agents for planning, QA, and deployment. Fires at session start and on prompts, edits, task creation, and phase transitions.