@polderlabs/bizar 6.1.0 → 6.2.1

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.
Files changed (42) hide show
  1. package/bizar-dash/DESIGN.md +18 -23
  2. package/bizar-dash/critique.json +6 -6
  3. package/cli/bin.mjs +19 -1
  4. package/cli/commands/validate.mjs +480 -0
  5. package/cli/commands/validate.test.mjs +281 -0
  6. package/cli/post-install-smoke.mjs +96 -3
  7. package/cli/post-install-smoke.test.mjs +3 -5
  8. package/cli/provision.mjs +137 -16
  9. package/config/cline.json.template +15 -0
  10. package/config/commands/team.md +124 -0
  11. package/config/commands/test.md +60 -0
  12. package/config/commands/validate.md +66 -0
  13. package/config/hooks/PostToolUse +66 -0
  14. package/config/hooks/PreToolUse +82 -0
  15. package/config/hooks/README.md +60 -21
  16. package/config/hooks/TaskResume +48 -0
  17. package/config/hooks/TaskStart +47 -0
  18. package/config/hooks/UserPromptSubmit +55 -0
  19. package/package.json +5 -4
  20. package/plugins/bizar/package.json +1 -1
  21. package/plugins/bizar/src/clineruntime.ts +1 -1
  22. package/plugins/bizar/tests/clineruntime-config.test.ts +44 -0
  23. package/scripts/bh-full-e2e.mjs +422 -0
  24. package/scripts/check-arch.sh +80 -0
  25. package/scripts/check-deps.mjs +510 -0
  26. package/scripts/clean-state-check.sh +81 -0
  27. package/scripts/git-hooks/pre-commit +59 -0
  28. package/scripts/git-hooks/pre-push +54 -0
  29. package/scripts/install-hooks.sh +29 -0
  30. package/scripts/install-service.mjs +190 -0
  31. package/scripts/session-trace.sh +52 -0
  32. package/scripts/verify-feature.sh +102 -0
  33. package/bizar-dash/image-1.png +0 -0
  34. package/bizar-dash/image-2.png +0 -0
  35. package/bizar-dash/image-3.png +0 -0
  36. package/bizar-dash/image-4.png +0 -0
  37. package/bizar-dash/image-5.png +0 -0
  38. package/bizar-dash/image-6.png +0 -0
  39. package/bizar-dash/image-7.png +0 -0
  40. package/bizar-dash/image.png +0 -0
  41. package/config/hooks/post-tool-use.md +0 -16
  42. package/config/hooks/pre-tool-use.md +0 -16
@@ -0,0 +1,124 @@
1
+ ---
2
+ description: Spawn a Cline agent team — coordinate Thor (M2.7), Tyr (M3), Mimir (research), and Hermod (git) to complete a complex mission end-to-end.
3
+ agent: odin
4
+ ---
5
+ # Team — Spawn a Cline Agent Team
6
+
7
+ The `/team` command spawns a **coordinated agent team** for a complex,
8
+ multi-step mission. The lead agent coordinates teammates; each teammate
9
+ owns a disjoint scope; results are synthesized and committed.
10
+
11
+ ## When to Use `/team`
12
+
13
+ Use `/team` for any non-trivial mission that benefits from **parallel
14
+ work + explicit coordination**. Examples:
15
+
16
+ - **Refactor** — split a module across Thor (M2.7) and Tyr (M3) in parallel.
17
+ - **Multi-feature build** — new feature A (Thor) + new feature B (Tyr) + tests (Heimdall).
18
+ - **Research + implementation** — Mimir researches, Thor implements, Forseti audits.
19
+ - **Migration / upgrade** — Hermod handles the git/PR lifecycle while Thor/Tyr write code.
20
+ - **Bug hunt** — Mimir traces the data flow while Tyr writes the fix and tests.
21
+
22
+ Do NOT use `/team` for trivial single-file edits or single-question
23
+ clarifications. Use `@heimdall` directly for those.
24
+
25
+ ## Default Team Composition
26
+
27
+ If the user does not specify a team composition, spawn this default:
28
+
29
+ | Role | Agent | Model | Job |
30
+ |---------------|---------|-------------------|---------------------------------------|
31
+ | Lead | @odin | minimax/MiniMax-M3 | Coordinate, synthesize, gate quality |
32
+ | Implementer 1 | @thor | minimax/MiniMax-M2.7 | Moderate-complexity implementation |
33
+ | Implementer 2 | @tyr | minimax/MiniMax-M3 | Complex / cross-cutting work |
34
+ | Researcher | @mimir | 9router/kr/auto | Codebase research, pattern discovery |
35
+ | Git ops | @hermod | minimax/MiniMax-M2.7 | Branch, commit, push, PR |
36
+ | Reviewer | @forseti| minimax/MiniMax-M3 | Audit plan + final output |
37
+
38
+ You can swap or remove any of these — but always keep at least one
39
+ implementer and a reviewer.
40
+
41
+ ## Protocol (How Odin Runs a `/team` Invocation)
42
+
43
+ 1. **Read `.bizar/PROJECT.md`** if it exists. Factor the project
44
+ description into the team mission.
45
+ 2. **Read `bizar memory status`**. If the vault is reachable, run
46
+ `bizar memory search "<topic>"` for prior context on the mission.
47
+ 3. **Decompose** the mission into disjoint work items. Each item
48
+ names:
49
+ - The agent that owns it
50
+ - The file scope (paths/globs)
51
+ - The deliverable (a function, a test, a commit, a doc)
52
+ - The exit signal ("done when X is committed")
53
+ 4. **Launch in parallel** — use `bizar_spawn_team` with the mission
54
+ string. Or, if you prefer synchronous control, launch 2+ `task`
55
+ calls in a **single message** to drive Thor and Tyr directly.
56
+ 5. **Monitor** — while the team runs, return control to the user.
57
+ The team runs asynchronously. Use `bizar_status` to check progress
58
+ only when the user asks.
59
+ 6. **Synthesize** — when teammates report back, gate through @forseti
60
+ (audit) and @hermod (commit/push). Then report the final outcome
61
+ to the user with file:line references.
62
+
63
+ ## Pre-Dispatch Checklist (MANDATORY)
64
+
65
+ - [ ] Each teammate has a **disjoint file scope** — no two agents
66
+ edit the same file or directory
67
+ - [ ] Lockfiles, `package.json`, root configs, `tsconfig.json`,
68
+ `vite.config.*`, `Dockerfile`, CI configs are assigned to ONE
69
+ agent or marked READ-ONLY for everyone else
70
+ - [ ] No subagent has both `bash: allow` AND a write-level git task
71
+ in the same batch — Hermod is the only git writer
72
+ - [ ] Each teammate's scope is named in plain English
73
+ - [ ] You have prepended the **Sibling-Awareness Block** to every
74
+ prompt — see Odin baseline, "Parallel Dispatch Coordination"
75
+ - [ ] You have called `bizar memory status` and confirmed the vault
76
+ is reachable
77
+
78
+ ## Example Mission Strings
79
+
80
+ **Refactor a module:**
81
+ ```
82
+ Refactor src/api/auth.ts into a clean module: extract JWT validation
83
+ into src/auth/jwt.ts, rate-limiting into src/auth/rate-limit.ts, and
84
+ keep the public surface stable. Add tests for each new module. Update
85
+ docs/architecture.md with the new module map. Do not change the HTTP
86
+ route handlers.
87
+ ```
88
+
89
+ **Multi-feature build:**
90
+ ```
91
+ Add a kanban board: (1) Thor — backend API at /api/tasks with CRUD
92
+ endpoints and SQLite persistence. (2) Tyr — frontend React component
93
+ in src/components/Kanban.tsx with 5 columns. (3) Heimdall — write
94
+ the OpenAPI spec at docs/api/tasks.yaml. (4) Hermod — open a PR
95
+ named feat/kanban-board.
96
+ ```
97
+
98
+ **Bug hunt:**
99
+ ```
100
+ Mimir — trace the data flow from POST /api/checkout through to the
101
+ Stripe webhook handler; find any place where the order status is
102
+ written before the payment is confirmed. Tyr — write a regression
103
+ test that reproduces the race. Thor — fix the bug. Forseti —
104
+ audit the fix for completeness. Hermod — commit + push.
105
+ ```
106
+
107
+ ## Tool Reference
108
+
109
+ - `bizar_spawn_team` — spawn a full team in one call (lead + mission)
110
+ - `bizar_spawn_background` — spawn a single background agent
111
+ - `bizar_status` — list all running background instances
112
+ - `bizar_collect` — block until an instance completes (use sparingly)
113
+ - `bizar_kill` — terminate an instance
114
+
115
+ ## Failure Modes
116
+
117
+ - **Two agents write the same file** — STOP, revert one branch, reassign.
118
+ - **One agent stalls** — call `bizar_kill`, route the remaining scope
119
+ to another agent.
120
+ - **Tests fail after team work** — dispatch @thor to investigate; do
121
+ not paper over the failure.
122
+ - **Git conflict** — route to @hermod for `git rebase` / merge resolution.
123
+ - **A teammate goes silent** — call `bizar_status` for a status report;
124
+ if dead, kill and re-spawn with a fresh prompt.
@@ -0,0 +1,60 @@
1
+ ---
2
+ description: Run the project's test suite via the Bizar test gate. Auto-detects jest/vitest/bun/pytest/cargo/go. Exits non-zero on failure.
3
+ agent: thor
4
+ ---
5
+ # /test — Run the Project's Test Suite
6
+
7
+ The `/test` command is a thin wrapper around `bizar test-gate`. It
8
+ auto-detects the project's test runner and runs the full suite.
9
+
10
+ ## What It Does
11
+
12
+ 1. Detects the project stack (one of: npm, pytest, cargo, go).
13
+ 2. Runs the matching test command:
14
+ - `package.json` present → `npm test`
15
+ - `pyproject.toml` present → `pytest`
16
+ - `Cargo.toml` present → `cargo test`
17
+ - `go.mod` present → `go test ./...`
18
+ 3. Streams the test output to the user.
19
+ 4. Exits non-zero on test failures.
20
+
21
+ ## Exit Codes
22
+
23
+ | Code | Meaning |
24
+ |------|----------------------------------|
25
+ | 0 | All tests passed |
26
+ | 1 | Tests failed |
27
+ | 2 | No test runner detected |
28
+
29
+ ## How to Use
30
+
31
+ Invoke `/test` (no arguments) from the project root. The test gate
32
+ inspects the current directory and picks the right runner.
33
+
34
+ To run a specific Bizar test scope instead, you can pass arguments
35
+ to `/test`. The arguments are forwarded to the underlying runner:
36
+
37
+ - `/test plugins/bizar` — run only the Bizar plugin tests (bun)
38
+ - `/test --testPathPattern=auth` — pass a flag to the runner
39
+
40
+ ## When to Use
41
+
42
+ - After any non-trivial code change
43
+ - Before committing (`@hermod` should always run `/test` first)
44
+ - As the final step of a `/team` mission — gate quality with tests
45
+
46
+ ## Common Patterns
47
+
48
+ - **Post-implementation gate** — after Thor and Tyr finish their
49
+ parallel work, dispatch `@thor` to run `/test`. If failures, fix
50
+ and re-run.
51
+ - **PR check** — run `/test` in CI before merging.
52
+ - **Debug a flaky test** — run `/test` twice; if the second run
53
+ passes, the test is order-dependent (fix or quarantine).
54
+
55
+ ## Related
56
+
57
+ - `bizar test-gate` — the underlying CLI command
58
+ - `bizar doctor` — checks the Bizar install itself (not project tests)
59
+ - `make check` — typecheck + tests (full pipeline, dev only)
60
+ - `make e2e` — Bizar plugin end-to-end (dev only)
@@ -0,0 +1,66 @@
1
+ ---
2
+ description: Validate the Bizar install end-to-end — cline.json parses, plugin entry resolves, all 14 agent files are installed, all skills/rules/hooks/commands are in place, provider config is sane, and the 9router gateway is reachable.
3
+ agent: heimdall
4
+ ---
5
+ # /validate — Validate the Bizar Install
6
+
7
+ The `/validate` command runs `bizar doctor` with the full check
8
+ battery. It is the fastest way to confirm the install is healthy
9
+ and Cline will see every Bizar component on the next session start.
10
+
11
+ ## What It Checks
12
+
13
+ 1. **cline-reachable** — `cline --version` exits 0.
14
+ 2. **cline-config-valid** — `~/.cline/cline.json` parses as JSON.
15
+ 3. **plugin-entry-present** — `cline.json` has a Bizar plugin entry.
16
+ 4. **plugin-path-resolves** — the plugin path on disk actually exists.
17
+ 5. **agent-files-installed** — all 14 agent files in `~/.cline/agents/`
18
+ (odin, vor, frigg, quick, mimir, heimdall, hermod, thor, baldr,
19
+ tyr, vidarr, forseti, semble-search, agent-browser).
20
+ 6. **tools-available** — at least one of `headroom`, `semble`, `skills`
21
+ is on PATH.
22
+ 7. **provider-config-sanity** — `provider.9router` (preferred) or
23
+ `provider.minimax` (legacy) has at least one sane model entry.
24
+ 8. **9router-reachable** — 9Router gateway responds at
25
+ `http://localhost:20128/api/health` (lenient — warn, don't fail).
26
+ 9. **slash-commands-installed** — all Bizar slash commands
27
+ (`/audit`, `/explain`, `/init`, `/learn`, `/plan`, `/plow-through`,
28
+ `/pr-review`, `/tailscale-serve`, `/visual-plan`, `/bizar`,
29
+ `/team`, `/test`, `/validate`) are present in `~/.cline/commands/`.
30
+ 10. **skills-installed** — every subdir of `config/skills/` is
31
+ mirrored to `~/.cline/skills/`.
32
+ 11. **rules-installed** — every `.md` in `config/rules/` is mirrored
33
+ to `~/.cline/rules/`.
34
+ 12. **hooks-installed** — `config/hooks/` is mirrored to
35
+ `~/.cline/hooks/`.
36
+
37
+ ## How to Use
38
+
39
+ Invoke `/validate` (no arguments) from anywhere. It is read-only and
40
+ never modifies the system.
41
+
42
+ If any check fails, the user should run `bizar update` to refresh the
43
+ install, or `bizar repair` to fix common issues.
44
+
45
+ ## Output
46
+
47
+ Each check prints ✓ or ✗ with a one-line message. The summary line
48
+ shows the total pass/fail count. Exits non-zero if any check fails.
49
+
50
+ For machine-readable output, the user can run `bizar doctor --json`
51
+ directly.
52
+
53
+ ## When to Use
54
+
55
+ - After a manual config edit — confirm nothing broke.
56
+ - Before a `/team` mission — confirm the install is healthy so the
57
+ team has all the tools it needs.
58
+ - After `bizar install` or `bizar update` — the install already
59
+ calls doctor, but a manual re-run is cheap.
60
+ - When a user asks "why is cline misbehaving?" — start here.
61
+
62
+ ## Related
63
+
64
+ - `bizar doctor` — the underlying CLI command
65
+ - `bizar update` — refreshes the install (re-runs syncConfigExtras)
66
+ - `bizar repair` — fixes common issues (stale symlinks, version drift)
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ // PostToolUse — Bizar harness hook.
3
+ //
4
+ // Runs AFTER a tool completes. Reads JSON from stdin, outputs JSON to
5
+ // stdout. This hook does NOT block (post-tool actions can't undo the
6
+ // call); it just adds context for the AI's next decision.
7
+ //
8
+ // Responsibilities:
9
+ // 1. Log tool latency for performance observability (append-only JSONL).
10
+ // 2. Surface any pre-tool warnings (e.g. console.log detected) AFTER
11
+ // the tool ran, so the model gets a second chance to fix it.
12
+ // 3. Remind the AI to run /test before claiming "done".
13
+
14
+ 'use strict';
15
+
16
+ const fs = require('fs');
17
+ const os = require('os');
18
+ const path = require('path');
19
+
20
+ let raw = '';
21
+ process.stdin.setEncoding('utf8');
22
+ process.stdin.on('data', (chunk) => { raw += chunk; });
23
+ process.stdin.on('end', () => {
24
+ let input = {};
25
+ try { input = JSON.parse(raw); } catch { input = {}; }
26
+ const post = input.postToolUse || {};
27
+ const toolName = String(post.toolName || '');
28
+ const success = post.success !== false;
29
+ const executionTimeMs = Number(post.executionTimeMs) || 0;
30
+ const params = (post.parameters && typeof post.parameters === 'object') ? post.parameters : {};
31
+
32
+ // 1. Append-only JSONL log under ~/.config/bizar/hook-logs/
33
+ try {
34
+ const logDir = path.join(os.homedir(), '.config', 'bizar', 'hook-logs');
35
+ fs.mkdirSync(logDir, { recursive: true });
36
+ const today = new Date().toISOString().slice(0, 10);
37
+ const logFile = path.join(logDir, `post-tool-use-${today}.jsonl`);
38
+ const line = JSON.stringify({
39
+ ts: new Date().toISOString(),
40
+ tool: toolName,
41
+ success,
42
+ executionTimeMs,
43
+ sessionId: input.taskId || null,
44
+ });
45
+ fs.appendFileSync(logFile, line + '\n');
46
+ } catch { /* best-effort */ }
47
+
48
+ const out = { cancel: false, contextModification: '' };
49
+ const notes = [];
50
+
51
+ if (!success) {
52
+ notes.push(`Bizar PostToolUse: tool '${toolName}' failed. Investigate the error before proceeding.`);
53
+ } else if (executionTimeMs > 5000) {
54
+ notes.push(`Bizar PostToolUse: tool '${toolName}' took ${executionTimeMs}ms — consider whether this is worth the cost.`);
55
+ }
56
+
57
+ // Surface a reminder for write_to_file / apply_patch to src/.
58
+ const path = params.path || params.file_path || params.filePath || params.target_file || '';
59
+ if (/^write_to_file$|^apply_patch$|^replace_in_file$|^edit$/i.test(toolName) &&
60
+ /\/src\/|\/plugins\/|\/packages\//.test(String(path))) {
61
+ notes.push("Bizar PostToolUse: if you're done editing, run `/test` to gate the change with tests before claiming complete.");
62
+ }
63
+
64
+ out.contextModification = notes.join(' ');
65
+ process.stdout.write(JSON.stringify(out) + '\n');
66
+ });
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ // PreToolUse — Bizar harness hook.
3
+ //
4
+ // Cline hook script (https://docs.cline.bot/customization/hooks).
5
+ // Runs BEFORE any tool call. Reads JSON from stdin, outputs JSON to
6
+ // stdout. Returns `{ cancel: true, errorMessage: "..." }` to block
7
+ // the tool call, or `{ cancel: false, contextModification: "..." }`
8
+ // to add context for the next AI decision.
9
+ //
10
+ // This hook enforces three Bizar harness invariants:
11
+ // 1. Block writes to .env, secrets, .lock files, node_modules.
12
+ // 2. Warn (don't block) on console.log / debugger / .only() in src/.
13
+ // 3. Always return a small context line for the next AI decision.
14
+
15
+ 'use strict';
16
+
17
+ let raw = '';
18
+ process.stdin.setEncoding('utf8');
19
+ process.stdin.on('data', (chunk) => { raw += chunk; });
20
+ process.stdin.on('end', () => {
21
+ let input = {};
22
+ try { input = JSON.parse(raw); } catch { input = {}; }
23
+ const pre = input.preToolUse || {};
24
+ const toolName = String(pre.toolName || '');
25
+ const params = (pre.parameters && typeof pre.parameters === 'object') ? pre.parameters : {};
26
+
27
+ const out = { cancel: false, contextModification: '' };
28
+ const notes = [];
29
+
30
+ // Extract the most common "path" parameter (varies by tool name).
31
+ const path =
32
+ params.path ||
33
+ params.file_path ||
34
+ params.filePath ||
35
+ params.target_file ||
36
+ params.targetFile ||
37
+ params.notebook_path ||
38
+ '';
39
+
40
+ const lower = String(path).toLowerCase();
41
+
42
+ // 1. Hard block — secrets + protected paths.
43
+ const blocked = [
44
+ /\/\.env(\.|$|\/)/,
45
+ /\/\.envrc$/,
46
+ /\/secrets?\//,
47
+ /\/credentials?/,
48
+ /\/node_modules\//,
49
+ /\.(lock|lockb)$/,
50
+ /\/package-lock\.json$/,
51
+ /\/bun\.lockb?$/,
52
+ /\/yarn\.lock$/,
53
+ ];
54
+ if (path && blocked.some((re) => re.test(lower))) {
55
+ out.cancel = true;
56
+ out.errorMessage = `PreToolUse: refusing to write to protected path '${path}' (Bizar harness policy).`;
57
+ process.stdout.write(JSON.stringify(out) + '\n');
58
+ return;
59
+ }
60
+
61
+ // 2. Warn — debug artifacts in src/.
62
+ if (path && /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(lower)) {
63
+ if (/\/src\//.test(lower) || /\/plugins\//.test(lower) || /\/packages\//.test(lower)) {
64
+ const text = JSON.stringify(params);
65
+ if (/\bconsole\.(log|debug|warn)\b/.test(text) && !/\bconsole\.(error|info)\b/.test(text)) {
66
+ notes.push('Heads up: console.log detected in src — `make clean-check` will fail.');
67
+ }
68
+ if (/\bdebugger\b/.test(text)) {
69
+ notes.push('Heads up: debugger statement detected — remove before committing.');
70
+ }
71
+ if (/\.only\s*\(/.test(text) && !/^[\s\S]*\.skip\s*\(/m.test(text)) {
72
+ notes.push('Heads up: .only() detected — `make clean-check` will fail.');
73
+ }
74
+ }
75
+ }
76
+
77
+ // 3. Always add a small context line for the AI's next decision.
78
+ notes.push(`Bizar PreToolUse: tool=${toolName || 'unknown'} path=${path || '(no path)'}`);
79
+
80
+ out.contextModification = notes.join(' ');
81
+ process.stdout.write(JSON.stringify(out) + '\n');
82
+ });
@@ -1,29 +1,68 @@
1
- # Hook System
1
+ # Bizar Harness — Cline Hooks
2
2
 
3
- BizarHarness uses **behavioral hooks** — agent-level instructions that simulate hook behavior. Since cline doesn't have a native hook runtime, all hooks are implemented as agent behavioral patterns.
3
+ This directory contains Cline-native hook scripts. They are NOT markdown
4
+ behavioral patterns — they are real Cline hook executables that run at
5
+ specific lifecycle events.
4
6
 
5
- ## Available Hooks
7
+ ## Format
6
8
 
7
- | Hook | Type | Trigger | Behavior |
8
- |------|------|---------|----------|
9
- | `pre-tool-use` | Behavioral | Before any edit/write | Check for secrets, verify permissions |
10
- | `post-tool-use` | Behavioral | After any edit/write | Auto-lint, auto-format, auto-test |
11
- | `session-start` | Behavioral | On session start | Read .bizar/, Hindsight recall, stack detection |
12
- | `session-end` | Behavioral | On task completion | Append to AGENTS_SELF_IMPROVEMENT.md |
13
- | `pre-commit` | Behavioral | Before git commit | Check for console.log, .env leaks, lint |
14
- | `post-implement` | Behavioral | After parallel implementation | Run test gate, verify both agents' outputs |
9
+ Cline hooks are executable scripts (no extension) with a shebang line:
15
10
 
16
- ## How It Works
11
+ ```bash
12
+ #!/usr/bin/env node
13
+ ```
17
14
 
18
- Each hook is enforced by agent instructions in the agent `.md` files:
15
+ They live in two locations:
16
+ - **Global**: `~/Documents/Cline/Hooks/` (applies to all workspaces)
17
+ - **Workspace**: `.clinerules/hooks/` (applies to one project)
19
18
 
20
- - **Pre-tool-use**: All implementation agents check for exposed secrets before any `write` or `edit` call
21
- - **Post-tool-use**: After file modifications, agents auto-run the linter and formatter
22
- - **Session-start**: Odin reads `.bizar/PROJECT.md` and Hindsight; Heimdall runs `bizar init` if missing
23
- - **Session-end**: Odin dispatches Heimdall to auto-extract self-improvement entries
24
- - **Pre-commit**: Hermod checks for console.log and .env before allowing git commits
25
- - **Post-implement**: After Thor+Tyr complete, Odin routes to Thor for test gate
19
+ The `bizar install` / `bizar update` commands install these scripts to
20
+ **both** locations with `chmod +x` so Cline picks them up.
26
21
 
27
- ## Customization
22
+ ## What each hook does
28
23
 
29
- To disable a hook, remove its instruction from the relevant agent `.md` file(s) in `~/.config/cline/agents/`.
24
+ | Hook | Stage | Job |
25
+ |------|-------|-----|
26
+ | `TaskStart` | New task | Prime the AI with `.bizar/PROJECT.md` + memory-vault search |
27
+ | `TaskResume` | Existing task resumed | Re-read project state, check `git log` since last run |
28
+ | `UserPromptSubmit` | User submits prompt | Tag the prompt for routing (`/team`, `/plow-through`, etc.) |
29
+ | `PreToolUse` | Before every tool | Block writes to `.env`, `secrets/`, `node_modules/`, lockfiles; warn on `console.log`/`debugger`/`.only()` in `src/` |
30
+ | `PostToolUse` | After every tool | Log latency to `~/.config/bizar/hook-logs/`, remind to run `/test` after edits |
31
+
32
+ ## I/O contract
33
+
34
+ Cline invokes each hook with **JSON on stdin** and reads **JSON on stdout**.
35
+
36
+ Input shape (Cline → hook):
37
+
38
+ ```json
39
+ {
40
+ "clineVersion": "3.0.39",
41
+ "hookName": "PreToolUse",
42
+ "taskId": "...",
43
+ "preToolUse": { "toolName": "write_to_file", "parameters": { "path": "src/foo.ts", ... } }
44
+ }
45
+ ```
46
+
47
+ Output shape (hook → Cline):
48
+
49
+ ```json
50
+ {
51
+ "cancel": false,
52
+ "contextModification": "small note for the next AI decision"
53
+ }
54
+ ```
55
+
56
+ Set `cancel: true` to block the tool call. The optional `errorMessage`
57
+ is shown to the user.
58
+
59
+ ## Disabling a hook
60
+
61
+ Rename the file to add a `.disabled` suffix (e.g. `PreToolUse.disabled`)
62
+ or remove the executable bit (`chmod -x PreToolUse`). Cline silently
63
+ skips hooks it can't execute.
64
+
65
+ ## See also
66
+
67
+ - [Cline hooks documentation](https://docs.cline.bot/customization/hooks)
68
+ - `cli/commands/validate.mjs` — `bizar validate` includes a `hooks-installed` check
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ // TaskResume — Bizar harness hook.
3
+ //
4
+ // Runs when an existing task is resumed. Reads JSON from stdin, outputs
5
+ // JSON to stdout. Used to remind the model of previous progress and to
6
+ // detect scope drift since the last run.
7
+
8
+ 'use strict';
9
+
10
+ const fs = require('fs');
11
+ const os = require('os');
12
+ const path = require('path');
13
+
14
+ let raw = '';
15
+ process.stdin.setEncoding('utf8');
16
+ process.stdin.on('data', (chunk) => { raw += chunk; });
17
+ process.stdin.on('end', () => {
18
+ let input = {};
19
+ try { input = JSON.parse(raw); } catch { input = {}; }
20
+ const task = input.taskResume || {};
21
+ const previous = task.previousState || {};
22
+
23
+ try {
24
+ const logDir = path.join(os.homedir(), '.config', 'bizar', 'hook-logs');
25
+ fs.mkdirSync(logDir, { recursive: true });
26
+ const today = new Date().toISOString().slice(0, 10);
27
+ const logFile = path.join(logDir, `task-resume-${today}.jsonl`);
28
+ fs.appendFileSync(logFile, JSON.stringify({
29
+ ts: new Date().toISOString(),
30
+ taskId: input.taskId || null,
31
+ lastMessageTs: previous.lastMessageTs || null,
32
+ messageCount: previous.messageCount || null,
33
+ }) + '\n');
34
+ } catch { /* best-effort */ }
35
+
36
+ const notes = [
37
+ 'Bizar TaskResume: re-read `.bizar/PROJECT.md` and `PROGRESS.md` before continuing.',
38
+ 'Bizar TaskResume: check `git log --oneline -10` to see what changed since the last run.',
39
+ ];
40
+ if (previous.conversationHistoryDeleted) {
41
+ notes.push('Bizar TaskResume: WARNING — conversation history was deleted. Context from previous run is gone; verify scope before continuing.');
42
+ }
43
+
44
+ process.stdout.write(JSON.stringify({
45
+ cancel: false,
46
+ contextModification: notes.join(' '),
47
+ }) + '\n');
48
+ });
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ // TaskStart — Bizar harness hook.
3
+ //
4
+ // Runs when a NEW task is started (not when resuming). Reads JSON from
5
+ // stdin, outputs JSON to stdout. Used to prime the AI with project
6
+ // context and to record the start of a session.
7
+
8
+ 'use strict';
9
+
10
+ const fs = require('fs');
11
+ const os = require('os');
12
+ const path = require('path');
13
+
14
+ let raw = '';
15
+ process.stdin.setEncoding('utf8');
16
+ process.stdin.on('data', (chunk) => { raw += chunk; });
17
+ process.stdin.on('end', () => {
18
+ let input = {};
19
+ try { input = JSON.parse(raw); } catch { input = {}; }
20
+ const task = input.taskStart || {};
21
+ const initial = String(task.taskMetadata?.initialTask || '').slice(0, 500);
22
+
23
+ // Log task start to ~/.config/bizar/hook-logs/
24
+ try {
25
+ const logDir = path.join(os.homedir(), '.config', 'bizar', 'hook-logs');
26
+ fs.mkdirSync(logDir, { recursive: true });
27
+ const today = new Date().toISOString().slice(0, 10);
28
+ const logFile = path.join(logDir, `task-start-${today}.jsonl`);
29
+ fs.appendFileSync(logFile, JSON.stringify({
30
+ ts: new Date().toISOString(),
31
+ taskId: input.taskId || null,
32
+ clineVersion: input.clineVersion || null,
33
+ initial: initial,
34
+ }) + '\n');
35
+ } catch { /* best-effort */ }
36
+
37
+ const notes = [
38
+ 'Bizar TaskStart: read `.bizar/PROJECT.md` (if present) before any routing decision.',
39
+ 'Bizar TaskStart: if memory vault exists, run `bizar memory search "<topic>"` first.',
40
+ 'Bizar TaskStart: Odin dispatches to subagents via `task` (sync) or `bizar_spawn_background` (async).',
41
+ ];
42
+
43
+ process.stdout.write(JSON.stringify({
44
+ cancel: false,
45
+ contextModification: notes.join(' '),
46
+ }) + '\n');
47
+ });
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ // UserPromptSubmit — Bizar harness hook.
3
+ //
4
+ // Runs when the user submits a prompt. Reads JSON from stdin, outputs
5
+ // JSON to stdout. Used to lightly tag user prompts for routing and to
6
+ // add a "Plow Through" prompt hint when ambiguity is detected.
7
+
8
+ 'use strict';
9
+
10
+ const fs = require('fs');
11
+ const os = require('os');
12
+ const path = require('path');
13
+
14
+ let raw = '';
15
+ process.stdin.setEncoding('utf8');
16
+ process.stdin.on('data', (chunk) => { raw += chunk; });
17
+ process.stdin.on('end', () => {
18
+ let input = {};
19
+ try { input = JSON.parse(raw); } catch { input = {}; }
20
+ const submit = input.userPromptSubmit || {};
21
+ const prompt = String(submit.prompt || '').trim();
22
+
23
+ // Always log (no PII redaction needed — the prompt is the user's).
24
+ try {
25
+ const logDir = path.join(os.homedir(), '.config', 'bizar', 'hook-logs');
26
+ fs.mkdirSync(logDir, { recursive: true });
27
+ const today = new Date().toISOString().slice(0, 10);
28
+ const logFile = path.join(logDir, `user-prompt-${today}.jsonl`);
29
+ fs.appendFileSync(logFile, JSON.stringify({
30
+ ts: new Date().toISOString(),
31
+ taskId: input.taskId || null,
32
+ promptLength: prompt.length,
33
+ }) + '\n');
34
+ } catch { /* best-effort */ }
35
+
36
+ const notes = [];
37
+ if (prompt.length === 0) {
38
+ notes.push('Bizar UserPromptSubmit: empty prompt — wait for actual user input.');
39
+ } else if (prompt.startsWith('/team')) {
40
+ notes.push('Bizar UserPromptSubmit: /team — Odin will spawn a coordinated agent team. Confirm disjoint file scopes before dispatching.');
41
+ } else if (prompt.startsWith('/plow-through')) {
42
+ notes.push('Bizar UserPromptSubmit: /plow-through — autonomous mode. Dispatch 2+ parallel agents when possible. Run /test before claiming done.');
43
+ } else if (prompt.startsWith('/test')) {
44
+ notes.push('Bizar UserPromptSubmit: /test — auto-detects runner (jest/vitest/bun/pytest/cargo/go). Streams output to the user.');
45
+ } else if (prompt.startsWith('/validate')) {
46
+ notes.push('Bizar UserPromptSubmit: /validate — runs 21-point health check on the Bizar install.');
47
+ } else {
48
+ notes.push('Bizar UserPromptSubmit: if the request is complex, decompose into 2+ parallel subagent tasks (Odin) or spawn a /team.');
49
+ }
50
+
51
+ process.stdout.write(JSON.stringify({
52
+ cancel: false,
53
+ contextModification: notes.join(' '),
54
+ }) + '\n');
55
+ });