@polderlabs/bizar 10.23.7 → 10.23.9
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/AGENTS.md +20 -21
- package/cli/commands/models.mjs +23 -4
- package/cli/doctor.mjs +9 -0
- package/cli/provision.mjs +15 -5
- package/config/claude/CLAUDE.md +20 -21
- package/config/claude/agents/office-manager.md +37 -14
- package/config/claude/hooks/README.md +1 -1
- package/config/claude/hooks/agent-model-guard.mjs +16 -30
- package/config/claude/hooks/sessionstart-model-sync.mjs +11 -1
- package/config/claude/hooks/sessionstart-prime.mjs +4 -4
- package/config/claude/hooks/worker-suggest.mjs +6 -5
- package/config/claude/hooks/workflow-route-guard.mjs +23 -16
- package/config/claude/model-router.json +7 -28
- package/config/workflows/bizar-debug.js +39 -11
- package/config/workflows/bizar-implement.js +66 -7
- package/config/workflows/bizar-research.js +40 -24
- package/config/workflows/lib/dispatch.js +7 -10
- package/config/workflows/lib/native-contract.mjs +96 -0
- package/config/workflows/ultracode-research.js +40 -9
- package/config/workflows/ultracode-review.js +39 -6
- package/config/workflows/ultracode.js +39 -18
- package/package.json +3 -3
- package/packages/sdk/dist/version.d.ts +1 -1
- package/packages/sdk/dist/version.js +1 -1
- package/packages/sdk/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -58,21 +58,18 @@ still deny prohibited actions and escalate externally visible or irreversible
|
|
|
58
58
|
actions with `permissionDecision: "ask"`; that escalation list is the
|
|
59
59
|
authoritative floor, not a starting point.
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
change
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Do not add unnecessary phases or duplicate workers. For work that needs 3+
|
|
68
|
-
long-lived workers with bounded cross-talk,
|
|
69
|
-
Mike invokes a workflow that fans out as a native agent team; the team is
|
|
61
|
+
Mike selects the coordination mode after bounded read-only orientation and one
|
|
62
|
+
user clarification checkpoint: direct work only for an unmistakably tiny
|
|
63
|
+
single-target copy/style/format edit; one isolated Agent for a clear bounded
|
|
64
|
+
change; a native workflow for repeatable phased work; parallel Agents for
|
|
65
|
+
disjoint scopes; and an Agent team for 3+ sustained roles that genuinely need
|
|
66
|
+
cross-talk. Do not add unnecessary phases or duplicate workers. The team is
|
|
70
67
|
host-side state under `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`, and per
|
|
71
|
-
Anthropic's docs `team_name` is deprecated and ignored.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
Anthropic's docs `team_name` is deprecated and ignored. Every editing dispatch
|
|
69
|
+
uses an explicit configured model and call-level `isolation: "worktree"`.
|
|
70
|
+
When two or more subtasks have non-overlapping writable scopes and no data
|
|
71
|
+
dependency, dispatch them concurrently; serialize only dependencies and
|
|
72
|
+
integration.
|
|
76
73
|
|
|
77
74
|
Agent roles are model-agnostic. Mike selects the cheapest sufficient enabled
|
|
78
75
|
configured-tier model for each dispatch, with explicit user picks taking
|
|
@@ -136,11 +133,13 @@ The autonomy and approval policy above governs this execution model. The project
|
|
|
136
133
|
Every non-empty primary request enters Bizar through `office-manager` (`@mike`).
|
|
137
134
|
The installer sets Claude Code's global `agent` setting to Mike's frontmatter
|
|
138
135
|
name (`mike`),
|
|
139
|
-
and
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
136
|
+
and the routing hook supplies the adaptive coordination policy. For non-tiny
|
|
137
|
+
work, Mike first gathers only bounded read-only context, asks one concise
|
|
138
|
+
clarification question that names the inferred outcome and proposed mode, then
|
|
139
|
+
continues autonomously after the answer. A native workflow is one available
|
|
140
|
+
mode, not a universal gate; Mike may select an isolated Agent, parallel Agents,
|
|
141
|
+
or an Agent team when that better fits the work. Mike owns integration and
|
|
142
|
+
final verification.
|
|
144
143
|
A Bizar custom agent already executing its assigned role does not recursively
|
|
145
144
|
dispatch itself.
|
|
146
145
|
|
|
@@ -152,8 +151,8 @@ relevant page. Guess-and-try integration work is prohibited. When official
|
|
|
152
151
|
documentation is unavailable or ambiguous, inspect authoritative source code
|
|
153
152
|
and report the evidence gap.
|
|
154
153
|
|
|
155
|
-
For workflow
|
|
156
|
-
a known risk
|
|
154
|
+
For a workflow or team, `office-manager` uses only phases and members that
|
|
155
|
+
reduce a known risk:
|
|
157
156
|
|
|
158
157
|
1. Research: `greg` (`research-analyst.md`) plus an implementation-context specialist.
|
|
159
158
|
2. Plan: `planner` drafts; `qa-reviewer` challenges assumptions and test shape.
|
package/cli/commands/models.mjs
CHANGED
|
@@ -947,8 +947,9 @@ export function partitionStalePicks({ liveIds, pickedIds, disabledProviders }) {
|
|
|
947
947
|
*
|
|
948
948
|
* Behavior:
|
|
949
949
|
* - Reads `settings.json` if present; preserves every other field.
|
|
950
|
-
* -
|
|
951
|
-
*
|
|
950
|
+
* - Maps every recognized Claude alias into picked IDs that are also in
|
|
951
|
+
* `liveIds`, preventing internal alias normalization from reaching an
|
|
952
|
+
* unconfigured provider default.
|
|
952
953
|
* - Atomic replace via temp-file + rename (matches `applyModels`).
|
|
953
954
|
* - When `settingsJsonPath` is provided (tests), uses that instead of
|
|
954
955
|
* `~/.claude/settings.json`.
|
|
@@ -1007,6 +1008,12 @@ export function applyModelOverrides({ settingsJsonPath, pickedIds, liveIds = [],
|
|
|
1007
1008
|
// must be keys; configured gateway aliases are values. This also suppresses
|
|
1008
1009
|
// print-mode `[claude-code:unrecognized_model]` diagnostics for Agent SDK calls.
|
|
1009
1010
|
settings.modelOverrides = buildClaudeModelOverrides(synced);
|
|
1011
|
+
if (requiresGatewayModelDiscovery(synced)) {
|
|
1012
|
+
settings.env = {
|
|
1013
|
+
...(settings.env || {}),
|
|
1014
|
+
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: '1',
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1010
1017
|
const previousModel = typeof settings.model === 'string' ? settings.model : null;
|
|
1011
1018
|
const previousContext = profiles?.[previousModel]?.limits?.contextTokens;
|
|
1012
1019
|
const nextModel = synced[0] || null;
|
|
@@ -1068,8 +1075,20 @@ export function buildClaudeModelOverrides(modelIds) {
|
|
|
1068
1075
|
const unique = [...new Set((Array.isArray(modelIds) ? modelIds : [])
|
|
1069
1076
|
.filter((id) => typeof id === 'string' && id.trim())
|
|
1070
1077
|
.map((id) => id.trim()))];
|
|
1071
|
-
|
|
1072
|
-
|
|
1078
|
+
if (unique.length === 0) return {};
|
|
1079
|
+
// Cover every built-in alias: the workflow runtime may normalize an Agent
|
|
1080
|
+
// request through one of these names, and no alias may escape to an
|
|
1081
|
+
// unconfigured Anthropic default.
|
|
1082
|
+
return Object.fromEntries(CLAUDE_MODEL_OVERRIDE_KEYS
|
|
1083
|
+
.map((key, index) => [key, unique[index % unique.length]]));
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/** Custom gateway IDs must be discoverable to Claude's SDK/subagent path. */
|
|
1087
|
+
export function requiresGatewayModelDiscovery(modelIds) {
|
|
1088
|
+
return (Array.isArray(modelIds) ? modelIds : []).some((id) => {
|
|
1089
|
+
if (typeof id !== 'string' || !id.trim()) return false;
|
|
1090
|
+
return !/^(?:claude(?:-|$)|anthropic(?:[./-]|$))/i.test(id.trim());
|
|
1091
|
+
});
|
|
1073
1092
|
}
|
|
1074
1093
|
|
|
1075
1094
|
/**
|
package/cli/doctor.mjs
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
REQUIRED_HOOKS,
|
|
43
43
|
} from './commands/validate.mjs';
|
|
44
44
|
import { configuredEnabledModels, listModels, resolveEndpoint } from './commands/models.mjs';
|
|
45
|
+
import { validateNativeWorkflowDirectory } from '../config/workflows/lib/native-contract.mjs';
|
|
45
46
|
|
|
46
47
|
const REQUIRED_RULES = [
|
|
47
48
|
'general.md', 'git.md', 'javascript.md', 'python.md',
|
|
@@ -157,6 +158,13 @@ async function checkHookFilesInstalled() {
|
|
|
157
158
|
return `all ${REQUIRED_HOOKS.length} hook entrypoints installed`;
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
async function checkNativeWorkflowsInstalled() {
|
|
162
|
+
const dir = join(claudeDir(), 'workflows');
|
|
163
|
+
if (!existsSync(dir)) throw new Error(`workflows dir missing: ${dir} — run \`bizar update\``);
|
|
164
|
+
const result = validateNativeWorkflowDirectory(dir);
|
|
165
|
+
return `${result.count} native workflows parser-compatible and filename-addressable`;
|
|
166
|
+
}
|
|
167
|
+
|
|
160
168
|
/**
|
|
161
169
|
* Lenient: passes if at least one of semble/skills/claude is on PATH.
|
|
162
170
|
* These are informational — none of them are strictly required for
|
|
@@ -216,6 +224,7 @@ const CHECKS = [
|
|
|
216
224
|
{ name: 'skill-files-installed', run: checkSkillFilesInstalled },
|
|
217
225
|
{ name: 'rule-files-installed', run: checkRuleFilesInstalled },
|
|
218
226
|
{ name: 'hook-files-installed', run: checkHookFilesInstalled },
|
|
227
|
+
{ name: 'native-workflows-valid', run: checkNativeWorkflowsInstalled },
|
|
219
228
|
{ name: 'tools-on-path', run: checkToolsAvailable },
|
|
220
229
|
{ name: 'bizar-home', run: checkBizarHome },
|
|
221
230
|
{ name: 'provider-reachable', run: checkProviderReachable },
|
package/cli/provision.mjs
CHANGED
|
@@ -32,7 +32,12 @@ import { homedir } from 'node:os';
|
|
|
32
32
|
import { dirname, join, resolve, sep } from 'node:path';
|
|
33
33
|
import { fileURLToPath } from 'node:url';
|
|
34
34
|
import { resolveBizarHome } from './config-paths.mjs';
|
|
35
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
buildClaudeModelOverrides,
|
|
37
|
+
configuredEnabledModels,
|
|
38
|
+
requiresGatewayModelDiscovery,
|
|
39
|
+
} from './commands/models.mjs';
|
|
40
|
+
import { validateNativeWorkflowDirectory } from '../config/workflows/lib/native-contract.mjs';
|
|
36
41
|
|
|
37
42
|
const __filename = fileURLToPath(import.meta.url);
|
|
38
43
|
const __dirname = dirname(__filename);
|
|
@@ -921,7 +926,6 @@ export function writeClaudeSettings({ dryRun = false, force = false } = {}) {
|
|
|
921
926
|
pickEnv('CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS')
|
|
922
927
|
|| shipped.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS
|
|
923
928
|
|| '1',
|
|
924
|
-
...(pickEnv('ANTHROPIC_MODEL') ? { ANTHROPIC_MODEL: pickEnv('ANTHROPIC_MODEL') } : {}),
|
|
925
929
|
},
|
|
926
930
|
hooks: {
|
|
927
931
|
UserPromptSubmit: [{ hooks: [hook('user-prompt-submit', 10)] }],
|
|
@@ -968,6 +972,10 @@ export function writeClaudeSettings({ dryRun = false, force = false } = {}) {
|
|
|
968
972
|
if (installModel) {
|
|
969
973
|
bizarSettings.model = installModel;
|
|
970
974
|
bizarSettings.modelOverrides = buildClaudeModelOverrides(installModels);
|
|
975
|
+
bizarSettings.env.ANTHROPIC_MODEL = installModel;
|
|
976
|
+
if (operatorGatewayUrl && requiresGatewayModelDiscovery(installModels)) {
|
|
977
|
+
bizarSettings.env.CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY = '1';
|
|
978
|
+
}
|
|
971
979
|
const configuredContext = pickEnv('CLAUDE_CODE_MAX_CONTEXT_TOKENS') || installContextTokens;
|
|
972
980
|
if (configuredContext) bizarSettings.env.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(configuredContext);
|
|
973
981
|
} else {
|
|
@@ -1013,6 +1021,9 @@ export function writeClaudeSettings({ dryRun = false, force = false } = {}) {
|
|
|
1013
1021
|
if (installModel) {
|
|
1014
1022
|
merged.model = installModel;
|
|
1015
1023
|
merged.modelOverrides = bizarSettings.modelOverrides;
|
|
1024
|
+
merged.env = { ...(merged.env || {}), ANTHROPIC_MODEL: installModel };
|
|
1025
|
+
} else if (merged.env && typeof merged.env === 'object') {
|
|
1026
|
+
delete merged.env.ANTHROPIC_MODEL;
|
|
1016
1027
|
}
|
|
1017
1028
|
|
|
1018
1029
|
// Auto-compaction is part of the Bizar reliability contract. Remove legacy
|
|
@@ -1348,9 +1359,9 @@ export async function syncConfigExtras({ dryRun = false } = {}) {
|
|
|
1348
1359
|
const workflowsSrc = join(REPO_ROOT, 'config', 'workflows');
|
|
1349
1360
|
if (existsSync(workflowsSrc)) {
|
|
1350
1361
|
const workflowsDst = join(CLAUDE_DIR, 'workflows');
|
|
1362
|
+
validateNativeWorkflowDirectory(workflowsSrc);
|
|
1351
1363
|
await copyDirIfExists(workflowsSrc, workflowsDst);
|
|
1352
|
-
counts.workflows =
|
|
1353
|
-
.filter((entry) => entry.isFile() && entry.name.endsWith('.js')).length;
|
|
1364
|
+
counts.workflows = validateNativeWorkflowDirectory(workflowsDst).count;
|
|
1354
1365
|
}
|
|
1355
1366
|
|
|
1356
1367
|
return { ok: true, message: `synced (${counts.commands} commands, ${counts.skills} skills, ${counts.hooks} hooks, ${counts.rules} rules, ${counts.workflows} workflows)`, counts };
|
|
@@ -1374,7 +1385,6 @@ export const FORCE_CLEAN_PRESERVE_ENV_KEYS = Object.freeze([
|
|
|
1374
1385
|
'ANTHROPIC_AUTH_TOKEN',
|
|
1375
1386
|
'BIZAR_MODEL_ROUTER_URL',
|
|
1376
1387
|
'BIZAR_HOME',
|
|
1377
|
-
'ANTHROPIC_MODEL',
|
|
1378
1388
|
'CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY',
|
|
1379
1389
|
'CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS',
|
|
1380
1390
|
'CLAUDE_CODE_MAX_CONTEXT_TOKENS',
|
package/config/claude/CLAUDE.md
CHANGED
|
@@ -69,21 +69,18 @@ still deny prohibited actions and escalate externally visible or irreversible
|
|
|
69
69
|
actions with `permissionDecision: "ask"`; that escalation list is the
|
|
70
70
|
authoritative floor, not a starting point.
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
change
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
Do not add unnecessary phases or duplicate workers. For work that needs 3+
|
|
79
|
-
long-lived workers with bounded cross-talk,
|
|
80
|
-
Mike invokes a workflow that fans out as a native agent team; the team is
|
|
72
|
+
Mike selects the coordination mode after bounded read-only orientation and one
|
|
73
|
+
user clarification checkpoint: direct work only for an unmistakably tiny
|
|
74
|
+
single-target copy/style/format edit; one isolated Agent for a clear bounded
|
|
75
|
+
change; a native workflow for repeatable phased work; parallel Agents for
|
|
76
|
+
disjoint scopes; and an Agent team for 3+ sustained roles that genuinely need
|
|
77
|
+
cross-talk. Do not add unnecessary phases or duplicate workers. The team is
|
|
81
78
|
host-side state under `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`, and per
|
|
82
|
-
Anthropic's docs `team_name` is deprecated and ignored.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
Anthropic's docs `team_name` is deprecated and ignored. Every editing dispatch
|
|
80
|
+
uses an explicit configured model and call-level `isolation: "worktree"`.
|
|
81
|
+
When two or more subtasks have non-overlapping writable scopes and no data
|
|
82
|
+
dependency, dispatch them concurrently; serialize only dependencies and
|
|
83
|
+
integration.
|
|
87
84
|
|
|
88
85
|
Agent roles are model-agnostic. Mike selects the cheapest sufficient enabled
|
|
89
86
|
configured-tier model for each dispatch, with explicit user picks taking
|
|
@@ -147,11 +144,13 @@ The autonomy and approval policy above governs this execution model. The project
|
|
|
147
144
|
Every non-empty primary request enters Bizar through `office-manager` (`@mike`).
|
|
148
145
|
The installer sets Claude Code's global `agent` setting to Mike's frontmatter
|
|
149
146
|
name (`mike`),
|
|
150
|
-
and
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
147
|
+
and the routing hook supplies the adaptive coordination policy. For non-tiny
|
|
148
|
+
work, Mike first gathers only bounded read-only context, asks one concise
|
|
149
|
+
clarification question that names the inferred outcome and proposed mode, then
|
|
150
|
+
continues autonomously after the answer. A native workflow is one available
|
|
151
|
+
mode, not a universal gate; Mike may select an isolated Agent, parallel Agents,
|
|
152
|
+
or an Agent team when that better fits the work. Mike owns integration and
|
|
153
|
+
final verification.
|
|
155
154
|
A Bizar custom agent already executing its assigned role does not recursively
|
|
156
155
|
dispatch itself.
|
|
157
156
|
|
|
@@ -163,8 +162,8 @@ relevant page. Guess-and-try integration work is prohibited. When official
|
|
|
163
162
|
documentation is unavailable or ambiguous, inspect authoritative source code
|
|
164
163
|
and report the evidence gap.
|
|
165
164
|
|
|
166
|
-
For workflow
|
|
167
|
-
a known risk
|
|
165
|
+
For a workflow or team, `office-manager` uses only phases and members that
|
|
166
|
+
reduce a known risk:
|
|
168
167
|
|
|
169
168
|
1. Research: `greg` (`research-analyst.md`) plus an implementation-context specialist.
|
|
170
169
|
2. Plan: `planner` drafts; `qa-reviewer` challenges assumptions and test shape.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mike
|
|
3
|
-
description: Mike —
|
|
4
|
-
tools: Workflow, Agent, Read, Write, Edit, Bash, Grep, Glob, WebFetch, WebSearch, Skill
|
|
3
|
+
description: Mike — adaptive orchestrator that selects the lightest safe coordination mode.
|
|
4
|
+
tools: Workflow, Agent, Read, Write, Edit, Bash, Grep, Glob, WebFetch, WebSearch, Skill, AskUserQuestion
|
|
5
5
|
skills:
|
|
6
6
|
- i-have-adhd
|
|
7
7
|
---
|
|
@@ -12,23 +12,45 @@ Follow `_shared/AGENT_BASELINE.md`. You own the user outcome, integration, and
|
|
|
12
12
|
final verification. Direct execution is a narrow exception; workflows are the
|
|
13
13
|
default for meaningful work.
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Orient, clarify, then select the coordination mode
|
|
16
16
|
|
|
17
17
|
| Shape | Signals | Execution |
|
|
18
18
|
|---|---|---|
|
|
19
19
|
| Tiny direct | one obvious copy, typo, comment, whitespace, or single style-token edit; one target; no behavior or test change | inspect, make the micro-edit, run the smallest proving check yourself |
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
| Single isolated worker | one bounded implementation after scope is clear | dispatch one worktree-isolated Agent with an explicit Bizar model; integrate and verify |
|
|
21
|
+
| Native workflow | repeatable diagnosis, research, review, or an implementation needing visible phase barriers | invoke the matching Bizar workflow with explicit Bizar routing |
|
|
22
|
+
| Agent team | three or more sustained, independent roles need bounded cross-talk or coordinated handoff | use the native Agent-team capability; writers use worktrees and explicit Bizar models |
|
|
23
|
+
| Parallel agents | two disjoint writable scopes with no cross-talk needed | dispatch concurrently with explicit models and worktree isolation |
|
|
24
|
+
|
|
25
|
+
For every non-tiny request, first make only enough read-only inspection to
|
|
26
|
+
understand the repository boundary and current constraints. Then ask the user
|
|
27
|
+
one concise clarification checkpoint: state the inferred outcome, the material
|
|
28
|
+
choice or risk, and the proposed coordination mode. Wait for the answer before
|
|
29
|
+
writing, dispatching editors, creating branches, or running tests. If the user
|
|
30
|
+
explicitly says to proceed without questions, record that choice and continue.
|
|
31
|
+
After the answer, work autonomously until the requested outcome and verification
|
|
32
|
+
are complete. Research current official docs only for external or
|
|
28
33
|
version-sensitive claims. Inspect installed skills before hard or specialized
|
|
29
34
|
work; if stuck with no match, search skills.sh and review the candidate before
|
|
30
35
|
proposing installation.
|
|
31
36
|
|
|
37
|
+
Before every Workflow, Agent, or Agent-team call, read the global Bizar model router and construct a
|
|
38
|
+
small `args.routing` object whose `default`, `medium`, and `high` values are
|
|
39
|
+
explicit enabled configured model IDs (user picks win; otherwise use enabled
|
|
40
|
+
tier candidates). Include the user's task in the same args object under the
|
|
41
|
+
workflow's documented task field. Never pass only a string and never use
|
|
42
|
+
`inherit`, `sonnet`, `opus`, or another provider default. If no configured ID
|
|
43
|
+
exists, stop and ask the operator to run `bizar models`.
|
|
44
|
+
|
|
45
|
+
Invoke the selected workflow by `name` first. If Claude reports that the Bizar
|
|
46
|
+
name is unavailable, resolve the active Claude config directory and retry once
|
|
47
|
+
with the absolute installed `scriptPath` at
|
|
48
|
+
`<CLAUDE_CONFIG_DIR>/workflows/<name>.js` (normally
|
|
49
|
+
`~/.claude/workflows/<name>.js`). Never retry a bare filename or a repository
|
|
50
|
+
relative path. If that file is missing or invalid, stop with `bizar update`
|
|
51
|
+
and `bizar doctor` as the repair commands; do not improvise a primary-session
|
|
52
|
+
implementation around a broken workflow installation.
|
|
53
|
+
|
|
32
54
|
## Models
|
|
33
55
|
|
|
34
56
|
For every Agent call, select the cheapest sufficient enabled configured model
|
|
@@ -41,9 +63,10 @@ only when the router explicitly supplies it.
|
|
|
41
63
|
|
|
42
64
|
## Worktree Discipline and integration
|
|
43
65
|
|
|
44
|
-
Every editing subagent call uses call-level `isolation: "worktree"`.
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
Every editing subagent call uses call-level `isolation: "worktree"`. Use teams
|
|
67
|
+
only when collaboration changes the result; do not manufacture a team or a
|
|
68
|
+
workflow for a simple isolated task. Parallel writers receive disjoint file
|
|
69
|
+
ownership and sibling scopes. Read-only research stays foreground. When a writer finishes, merge its queued branch with
|
|
47
70
|
`bizar worktree-merge`; report conflicts instead of guessing. The integration
|
|
48
71
|
branch runs final tests once after all required results are incorporated.
|
|
49
72
|
Worktree branches use `wt/<agent_type>-<short-task-id>`.
|
|
@@ -11,7 +11,7 @@ All hooks read Claude Code JSON from stdin and emit either no decision, addition
|
|
|
11
11
|
| `simplify-guard.mjs` | PostToolUse Skill + PreToolUse Bash | require one `/simplify` per commit attempt |
|
|
12
12
|
| `posttooluse-editwrite.mjs` | PostToolUse writes | local telemetry and test reminder |
|
|
13
13
|
| `worker-suggest.mjs` | UserPromptSubmit | ranked skill/agent suggestions |
|
|
14
|
-
| `workflow-route-guard.mjs` | UserPromptSubmit, PreToolUse, PostToolUse |
|
|
14
|
+
| `workflow-route-guard.mjs` | UserPromptSubmit, PreToolUse, PostToolUse | records adaptive Bizar routing state without blocking Mike's selected coordination mode; workflow success clears the pending route record |
|
|
15
15
|
| `thinking-route.mjs` | UserPromptSubmit | slash and mental-model routing |
|
|
16
16
|
| `telemetry.mjs` | SessionStart/UserPromptSubmit | local correlation and rejection categories |
|
|
17
17
|
| `sessionstart-prime.mjs` | SessionStart | bounded project and handoff context |
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
* validated by `pickFailover` against the same registry.
|
|
37
37
|
* - The hard deny of out-of-pool models STILL APPLIES when
|
|
38
38
|
* `routingDecisionId` is absent — the contract is opt-in.
|
|
39
|
-
* - Registry load failures
|
|
40
|
-
*
|
|
39
|
+
* - Registry load failures fail closed: allowing the dispatch would hand
|
|
40
|
+
* model choice back to Claude Code's unconfigured provider default.
|
|
41
41
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
42
|
+
* Callers that pass only `model` are accepted only when that literal ID is in
|
|
43
|
+
* the enabled configured pool. Missing or inherited model selection is denied.
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
46
|
import { readFileSync } from 'node:fs';
|
|
@@ -48,16 +48,6 @@ import { pathToFileURL } from 'node:url';
|
|
|
48
48
|
|
|
49
49
|
import { loadModelRouter } from '../../../config/agents/model-assignment.mjs';
|
|
50
50
|
|
|
51
|
-
function advise(reason) {
|
|
52
|
-
return {
|
|
53
|
-
hookSpecificOutput: {
|
|
54
|
-
hookEventName: 'PreToolUse',
|
|
55
|
-
permissionDecision: 'allow',
|
|
56
|
-
additionalContext: `🟡 Model override guidance: ${reason} The dispatch will proceed regardless.`,
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
51
|
function deny(reason) {
|
|
62
52
|
return {
|
|
63
53
|
hookSpecificOutput: {
|
|
@@ -72,8 +62,6 @@ function deny(reason) {
|
|
|
72
62
|
* 10.22.0 / Phase 4: extract the operator's `disabledProviders` list from
|
|
73
63
|
* the loaded registry. Whitespace-trimmed + lowercased at read time.
|
|
74
64
|
* Returns `[]` for legacy configs that lack the key (no in-code default).
|
|
75
|
-
* The hook MUST fail open on parse errors — the orchestrator already
|
|
76
|
-
* chose a model; let Claude Code validate it once.
|
|
77
65
|
*/
|
|
78
66
|
function readDisabledProvidersFromRegistry(registry) {
|
|
79
67
|
if (!registry || typeof registry !== 'object') return [];
|
|
@@ -90,14 +78,15 @@ function readDisabledProvidersFromRegistry(registry) {
|
|
|
90
78
|
}
|
|
91
79
|
|
|
92
80
|
/**
|
|
93
|
-
* 10.22.0 / Phase 4: case-
|
|
94
|
-
* disabled list. Empty / missing prefix list is a no-op
|
|
81
|
+
* 10.22.0 / Phase 4: case-insensitive prefix filter against the normalized
|
|
82
|
+
* disabled list. Empty / missing prefix list is a no-op.
|
|
95
83
|
*/
|
|
96
84
|
function isDisabledId(id, prefixes) {
|
|
97
85
|
if (!Array.isArray(prefixes) || prefixes.length === 0) return false;
|
|
98
86
|
if (typeof id !== 'string' || !id) return false;
|
|
87
|
+
const normalized = id.toLowerCase();
|
|
99
88
|
for (const p of prefixes) {
|
|
100
|
-
if (typeof p === 'string' && p &&
|
|
89
|
+
if (typeof p === 'string' && p && normalized.startsWith(p)) return true;
|
|
101
90
|
}
|
|
102
91
|
return false;
|
|
103
92
|
}
|
|
@@ -171,18 +160,15 @@ export async function guardAgentModel(input, options = {}) {
|
|
|
171
160
|
const failoverBlock = readFailoverBlock(toolInput);
|
|
172
161
|
const hasFailoverContract = Boolean(failoverBlock.routingDecisionId) && Boolean(failoverBlock.fallback);
|
|
173
162
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (requested === 'inherit') return {};
|
|
163
|
+
if (!requested || requested === 'inherit') {
|
|
164
|
+
return deny('Bizar Agent dispatch blocked: every Agent call requires an explicit enabled model from `bizar models`; session/provider inheritance is prohibited.');
|
|
165
|
+
}
|
|
178
166
|
|
|
179
167
|
let registry;
|
|
180
168
|
try {
|
|
181
169
|
registry = options.registry || loadModelRouter(options.routerPath);
|
|
182
170
|
} catch {
|
|
183
|
-
|
|
184
|
-
// chose a model; let Claude Code/provider validate it once.
|
|
185
|
-
return {};
|
|
171
|
+
return deny('Bizar Agent dispatch blocked: the global model router is missing or invalid. Run `bizar models`, then retry.');
|
|
186
172
|
}
|
|
187
173
|
|
|
188
174
|
// Disabled is an enforceable operator boundary. Falling through here would
|
|
@@ -201,17 +187,17 @@ export async function guardAgentModel(input, options = {}) {
|
|
|
201
187
|
// already computed by `pickFailover` against this same registry.
|
|
202
188
|
if (hasFailoverContract) {
|
|
203
189
|
if (!userPicks.has(failoverBlock.fallback)) {
|
|
204
|
-
return
|
|
190
|
+
return deny(`Bizar Agent dispatch blocked: fallback ${failoverBlock.fallback} is outside the user-selected pool; select an enabled configured fallback.`);
|
|
205
191
|
}
|
|
206
192
|
if (!allowed.has(requested)) {
|
|
207
|
-
return
|
|
193
|
+
return deny(`Bizar Agent dispatch blocked: model override ${requested} is outside the configured dynamic tiers and the user-selected pool. Pick it via \`bizar models\`.`);
|
|
208
194
|
}
|
|
209
195
|
// Both IDs are user-selected. Accept without re-probing the gateway.
|
|
210
196
|
return {};
|
|
211
197
|
}
|
|
212
198
|
|
|
213
199
|
if (!allowed.has(requested)) {
|
|
214
|
-
return
|
|
200
|
+
return deny(`Bizar Agent dispatch blocked: model override ${requested} is outside the configured dynamic tiers and the user-selected pool. Pick it via \`bizar models\`.`);
|
|
215
201
|
}
|
|
216
202
|
|
|
217
203
|
// User-selected models bypass live-discovery validation. The picker is the
|
|
@@ -220,7 +206,7 @@ export async function guardAgentModel(input, options = {}) {
|
|
|
220
206
|
if (!fromUserPick && Array.isArray(options.availableModelIds)) {
|
|
221
207
|
const available = new Set(options.availableModelIds);
|
|
222
208
|
if (!available.has(requested)) {
|
|
223
|
-
return
|
|
209
|
+
return deny(`Bizar Agent dispatch blocked: ${requested} was not reported by live discovery. Select another enabled configured model; do not retry aliases.`);
|
|
224
210
|
}
|
|
225
211
|
}
|
|
226
212
|
|
|
@@ -122,6 +122,10 @@ function filterDisabled(ids, disabled) {
|
|
|
122
122
|
return kept;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
function requiresGatewayModelDiscovery(modelIds) {
|
|
126
|
+
return modelIds.some((id) => !/^(?:claude(?:-|$)|anthropic(?:[./-]|$))/i.test(id));
|
|
127
|
+
}
|
|
128
|
+
|
|
125
129
|
function readSettingsPath() {
|
|
126
130
|
return join(resolveClaudeConfigDir(), 'settings.json');
|
|
127
131
|
}
|
|
@@ -234,8 +238,14 @@ function syncOnce() {
|
|
|
234
238
|
];
|
|
235
239
|
settings.modelPicker = { options };
|
|
236
240
|
settings.modelOverrides = Object.fromEntries(
|
|
237
|
-
|
|
241
|
+
overrideKeys.map((key, index) => [key, liveIds[index % liveIds.length]]),
|
|
238
242
|
);
|
|
243
|
+
if (requiresGatewayModelDiscovery(liveIds)) {
|
|
244
|
+
settings.env = {
|
|
245
|
+
...(settings.env || {}),
|
|
246
|
+
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: '1',
|
|
247
|
+
};
|
|
248
|
+
}
|
|
239
249
|
|
|
240
250
|
let modelChanged = false;
|
|
241
251
|
if (typeof settings.model !== 'string' || !liveIds.includes(settings.model)) {
|
|
@@ -186,13 +186,13 @@ function startupBriefing(cwd, featureBrief, recentCommits, projectLine, progress
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
if (progressLast) lines.push(`- Progress: ${progressLast}.`);
|
|
189
|
-
lines.push('- You are @mike.
|
|
189
|
+
lines.push('- You are @mike. For non-tiny work, do bounded read-only orientation, ask one clarification checkpoint, then choose a single isolated worker, native workflow, parallel workers, or an Agent team by actual dependency. Use worktrees for editors and explicit Bizar models for every Agent.');
|
|
190
190
|
lines.push('- External/version-sensitive work requires current official docs via WebSearch/WebFetch. Use relevant installed skills; apply i-have-adhd to user output. WIP=1.');
|
|
191
191
|
lines.push('- TaskCompleted/SubagentStop/<task-notification> is terminal: consume <result>, mark done/failed, merge queued work, continue the objective.');
|
|
192
192
|
// Default-first-stop hint when nothing is active yet.
|
|
193
193
|
if (featureBrief && featureBrief.active.length === 0) {
|
|
194
194
|
lines.push(
|
|
195
|
-
'- First move: read PROGRESS.md and feature_list.json
|
|
195
|
+
'- First move: read PROGRESS.md and feature_list.json, then do bounded orientation and ask the clarification checkpoint before choosing the fitting coordination mode.',
|
|
196
196
|
);
|
|
197
197
|
}
|
|
198
198
|
return lines.join('\n');
|
|
@@ -203,14 +203,14 @@ function clearBriefing(cwd, recentCommits, progressLast) {
|
|
|
203
203
|
if (progressLast) lines.push(`- Progress: ${progressLast}.`);
|
|
204
204
|
if (recentCommits.length > 0) lines.push(`- Last commit: ${recentCommits[0]}.`);
|
|
205
205
|
lines.push('- Context preserved in same repo / cwd — only the model turn was reset.');
|
|
206
|
-
lines.push('- You are @mike: continue
|
|
206
|
+
lines.push('- You are @mike: continue the active coordination plan; adapt it when new evidence changes the fit.');
|
|
207
207
|
lines.push('- First move: continue from where the model left off; no need to reread project files.');
|
|
208
208
|
return lines.join('\n');
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
function resumeBriefing(cwd, state) {
|
|
212
212
|
const lines = ['Bizar SessionStart (resume):'];
|
|
213
|
-
lines.push('- You are @mike: restore state, then continue the active
|
|
213
|
+
lines.push('- You are @mike: restore state, then continue the active coordination plan and adapt it if the evidence changed.');
|
|
214
214
|
if (state) {
|
|
215
215
|
if (state.activeFeature) lines.push(`- Last active feature: ${state.activeFeature}.`);
|
|
216
216
|
if (state.reason) lines.push(`- Last session ended with: ${state.reason}.`);
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Runs on every user prompt. Only unmistakably tiny, single-scope edits take
|
|
8
8
|
* a cheap fast path. Every other request is routed into a native Bizar
|
|
9
|
-
*
|
|
9
|
+
* adaptive coordination mode selected by Mike after bounded orientation and a
|
|
10
|
+
* clarification checkpoint.
|
|
10
11
|
*
|
|
11
12
|
* Uses import.meta.url + dynamic import() to resolve the sibling CLI module so
|
|
12
13
|
* the hook works regardless of install path (fixes ERR_MODULE_NOT_FOUND after
|
|
@@ -56,10 +57,10 @@ const FAST_ROUTE_POLICY = [
|
|
|
56
57
|
].join('\n');
|
|
57
58
|
|
|
58
59
|
const ROUTE_POLICY = [
|
|
59
|
-
'
|
|
60
|
-
'- If this is the primary session, you ARE @mike.
|
|
61
|
-
'-
|
|
62
|
-
'-
|
|
60
|
+
'Adaptive Bizar routing policy:',
|
|
61
|
+
'- If this is the primary session, you ARE @mike. First do only bounded read-only orientation. Then ask one concise clarification question describing the inferred outcome, the material choice/risk, and your proposed coordination mode. Wait for the answer before edits, branches, tests, or editor dispatch. If the user explicitly waives questions, continue autonomously.',
|
|
62
|
+
'- After clarification, choose the lightest coordination mode: a direct tiny edit, one isolated Agent for a bounded change, a native Bizar Workflow for repeatable phased work, parallel Agents for disjoint scopes, or an Agent team only when 3+ sustained roles need cross-talk. Do not force a workflow or team when it adds no value.',
|
|
63
|
+
'- Every Agent or team member receives an explicit enabled configured Bizar model; use no provider alias, inheritance, or default. Every editing worker uses call-level `isolation: "worktree"`. For genuinely disjoint writable scopes, dispatch concurrently; otherwise use one owner.',
|
|
63
64
|
'- Consume terminal agent results, merge queued worktrees with bizar worktree-merge, and run integration checks in the primary session. A subagent may not recursively dispatch itself.',
|
|
64
65
|
'- Do NOT execute any tool you do not have. If a tool you need is missing from your tools list, dispatch to a subagent that has it — do not pretend you have it.',
|
|
65
66
|
'- If you are already running as a Bizar custom agent, follow your assigned role and do not recursively dispatch yourself.',
|