create-byan-agent 2.50.0 → 2.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -0
- package/install/package.json +1 -1
- package/install/templates/.claude/hooks/codex-delegate-guard.js +66 -74
- package/install/templates/.claude/hooks/inject-voice-anchor.js +2 -1
- package/install/templates/.claude/hooks/lib/autodelegate-decision.js +11 -13
- package/install/templates/.claude/hooks/lib/codex-delegate-gate.js +0 -0
- package/install/templates/.claude/hooks/lib/plain-language.js +18 -0
- package/install/templates/.claude/rules/native-workflows.md +17 -7
- package/install/templates/.claude/rules/plain-language.md +18 -0
- package/install/templates/.claude/skills/byan-byan/SKILL.md +44 -10
- package/install/templates/.claude/workflows/byan-auto-dispatch.js +210 -0
- package/install/templates/_byan/agent/byan/byan-tao.md +8 -0
- package/install/templates/_byan/mcp/byan-mcp-server/lib/dispatch-router.js +48 -30
- package/install/templates/_byan/mcp/byan-mcp-server/lib/native-tiers.js +25 -6
- package/install/templates/_byan/mcp/byan-mcp-server/lib/tier-script.js +8 -4
- package/install/templates/_byan/mcp/byan-mcp-server/lib/workflows-lint.js +6 -2
- package/install/templates/_byan/mcp/byan-mcp-server/skill-bundles-manifest.json +1 -1
- package/install/templates/dist/skill-bundles/byan-byan.zip +0 -0
- package/install/templates/docs/codex-auto-delegation.md +51 -25
- package/install/templates/docs/intelligent-dispatch.md +9 -5
- package/install/templates/docs/native-workflows-contract.md +9 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,99 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [2.53.0] - 2026-07-21
|
|
13
|
+
|
|
14
|
+
### Added — Rail automatique : workflow natif byan-auto-dispatch (F2)
|
|
15
|
+
- Nouveau workflow Claude natif `.claude/workflows/byan-auto-dispatch.js` : il
|
|
16
|
+
decoupe une tache en etapes typees (nature + complexite 0-100) via un agent
|
|
17
|
+
d'analyse (sonnet, schema JSON force), route chaque etape sur le bon modele
|
|
18
|
+
par l'echelle v3 (haiku < 34, sonnet < 67, opus < 90, fable >= 90), route les
|
|
19
|
+
etapes shell/deploiement/navigation vers Codex (repli Claude annonce si Codex
|
|
20
|
+
n'est pas disponible ; la verification reste sur le modele de session, non
|
|
21
|
+
deleguee), ecrit `_byan-output/plan.md` (table etape x nature x complexite x
|
|
22
|
+
moteur x modele + consignes), execute chaque etape en sequence sur le modele
|
|
23
|
+
route, et verifie le livrable en fin.
|
|
24
|
+
- Cablage skill `byan-byan` (section 0.5) : a CHAQUE tache non-conversationnelle
|
|
25
|
+
recue par `/byan-byan`, ce workflow est invoque AUTOMATIQUEMENT (scriptPath +
|
|
26
|
+
args {task, stamp}), sans demande a l'utilisateur. Exceptions nommees :
|
|
27
|
+
question simple, action destructive (confirmation d'abord), FD multi-feature
|
|
28
|
+
deja engage (sa phase DISPATCH peut invoquer le meme workflow par feature),
|
|
29
|
+
demande explicite d'execution directe. Le gate utilisateur reste en fin, sur
|
|
30
|
+
le livrable.
|
|
31
|
+
- Livraison npm : le script est ajoute au miroir `template-sync.js`.
|
|
32
|
+
|
|
33
|
+
### Changed — Langage precis, zero dialecte interne (F1, Mantra IA-26)
|
|
34
|
+
- Le filet plain-language s'etend : `nudge`, `up-tier`, `ladder`, `rung`,
|
|
35
|
+
`runtime` rejoignent les mots a remplacer en prose ; nouvelle detection de
|
|
36
|
+
l'anthropomorphisme d'outil (un MCP/serveur/hook dit "vivant" ou "mort") avec
|
|
37
|
+
le remplacement exige : le fait observe, outil nomme ("byan_ping a repondu en
|
|
38
|
+
0.3s", "le serveur ne repond pas, timeout 8s").
|
|
39
|
+
- Nouvelle clause de precision factuelle dans `.claude/rules/plain-language.md` :
|
|
40
|
+
tout etat d'outil = l'outil nomme + l'appel + le resultat exact ; pas de
|
|
41
|
+
resume flou ("ca marche") ; "non verifie" quand l'appel n'a pas ete fait.
|
|
42
|
+
- L'ancre de voix par tour et le tao (Section 4, Vocabulaire Interdit) portent
|
|
43
|
+
les deux nouveaux interdits. Tests jest etendus (26 verts sur la suite
|
|
44
|
+
plain-language).
|
|
45
|
+
|
|
46
|
+
## [2.52.0] - 2026-07-20
|
|
47
|
+
|
|
48
|
+
### Changed — Delegation Codex v3 : pression-only + obeissance au routeur (F1, F2)
|
|
49
|
+
- **F1 — la delegation ne se declenche plus que sous PRESSION budget.** La nature
|
|
50
|
+
d'une tache (code / mecanique) n'est plus un declencheur d'auto-delegation a elle
|
|
51
|
+
seule. Deleguer au Codex de l'abonnement (qui reste en dessous de Claude en
|
|
52
|
+
qualite) vaut le coup pour epargner le budget Claude, pas par tache de code. Hors
|
|
53
|
+
pression, le code tourne sur Claude sans rappel. Le seuil par defaut passe a 75 %
|
|
54
|
+
(`autodelegate-decision.js` + `codex-delegate-guard.js` alignes sur un seul
|
|
55
|
+
nombre). Sans jauge `budget`, la pression n'est pas calculee et rien n'est
|
|
56
|
+
propose (documente, non bloquant).
|
|
57
|
+
- **F2 — le garde `codex-delegate-guard` obeit au routeur.** Le blocage ne mord
|
|
58
|
+
que pour une tache que le `dispatch-router` route lui-meme vers Codex (nature
|
|
59
|
+
execution / shell / deploiement / devops / navigateur). Une tache
|
|
60
|
+
architecture / refactor / qualite / planif — et toute verification — route vers
|
|
61
|
+
Claude, donc le garde reste silencieux. Le garde recalcule router + pression
|
|
62
|
+
uniquement dans la branche ou un blocage est encore possible (les chemins
|
|
63
|
+
d'autorisation courants ne paient rien) ; les deux signaux echouent en mode
|
|
64
|
+
ouvert (signal irresolu -> on autorise, sans blocage a tort).
|
|
65
|
+
|
|
66
|
+
### Changed — Echelle de modele par complexite + Fable dernier recours (F3)
|
|
67
|
+
- **Cote routeur (`dispatch-router.claudeModelForComplexity`)** : echelle a quatre
|
|
68
|
+
rungs — `haiku` (bas) -> `sonnet` (moyen) -> `opus` (haut) -> `fable` (extreme,
|
|
69
|
+
dernier recours, ~2x le prix d'Opus). C'est une RECOMMANDATION par tache, pas un
|
|
70
|
+
changement du modele de session en cours (Claude Code n'expose pas ce levier).
|
|
71
|
+
- **Cote leaves de workflow (`native-tiers` + linter)** : un up-tier explicite
|
|
72
|
+
(`opus` / `fable`) devient un choix d'auteur AUTORISE sur n'importe quel leaf,
|
|
73
|
+
miroir de l'echelle du routeur. Le plancher anti-downgrade est conserve (haiku /
|
|
74
|
+
sonnet interdits sur un leaf protege) ; seul le plafond est ouvert (le pin-up
|
|
75
|
+
n'est plus une violation). Nouveaux : `UP_TIER_MODELS`, `isUpTierModel`.
|
|
76
|
+
- **Revirement d'invariant assume** : l'ancienne ligne rouge "pas de Fable /
|
|
77
|
+
pas de pin-up" est levee cote Claude. Cote Codex elle tient (Codex ne peut pas
|
|
78
|
+
lancer un modele Claude) : `assertNoFable` garde le chemin Codex + `codex-bridge`.
|
|
79
|
+
- Doctrine alignee : `native-workflows.md`, `native-workflows-contract.md`,
|
|
80
|
+
`intelligent-dispatch.md`, `codex-auto-delegation.md`, skill `byan-byan`.
|
|
81
|
+
|
|
82
|
+
## [2.51.0] - 2026-07-20
|
|
83
|
+
|
|
84
|
+
### Changed — Delegation Codex : fermeture de l'auto-esquive (option B)
|
|
85
|
+
- Le blocage `codex-delegate-guard` ne peut plus etre contourne par BYAN lui-meme.
|
|
86
|
+
Retire : la marque de contenu auto-ecrite (`// BYAN-DELEGATE: reviewed`) et
|
|
87
|
+
l'auto-passe par re-soumission/fenetre de grace — les deux permettaient a Claude
|
|
88
|
+
de s'auto-accorder la sortie. Les seules sorties valides sont desormais : une
|
|
89
|
+
delegation Codex reelle ce tour, Codex indisponible (detecte via `codex --version`),
|
|
90
|
+
ou un opt-out HUMAIN ("reste sur claude" / "sans codex" dans la demande, ou le
|
|
91
|
+
fichier `.byan-codex-autodelegate/off`). Le motif "script court / latence / je
|
|
92
|
+
verifie" n'est plus une raison valide. Coeur pur `lib/codex-delegate-gate.js`
|
|
93
|
+
(`humanOptOutFromText`, `decideDelegateGate` durci) + `codex-delegate-guard.js`
|
|
94
|
+
(probe Codex, opt-out depuis la demande). Le rendu injecte (`autodelegate-decision`
|
|
95
|
+
renderNudge), le skill `byan-byan` et `docs/codex-auto-delegation.md` sont alignes.
|
|
96
|
+
|
|
97
|
+
### Notes
|
|
98
|
+
- Constat de session : le CLI Codex de l'abo ChatGPT est plafonne a gpt-5.5 (5.6
|
|
99
|
+
refuse). Recherche croisee : gpt-5.5 est sous le meilleur Claude sur tous les
|
|
100
|
+
domaines mesures. Donc la delegation Codex vaut pour economiser le budget Claude,
|
|
101
|
+
pas pour la qualite. Prochain chantier (FD dedie) : delegation declenchee par la
|
|
102
|
+
PRESSION budget (~75%) au lieu de par-nature ; le blocage obeit au routeur ;
|
|
103
|
+
echelle modele Claude par complexite (haiku/sonnet/opus) + Fable en dernier recours.
|
|
104
|
+
|
|
12
105
|
## [2.50.0] - 2026-07-17
|
|
13
106
|
|
|
14
107
|
### Added — BYAN souverainete (les concepts BYAN pilotent Claude, ne se font plus doubler)
|
package/install/package.json
CHANGED
|
@@ -1,35 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
// PreToolUse hook —
|
|
4
|
+
// PreToolUse hook — the armed Codex-delegation guard (v3 : router-obedient +
|
|
5
|
+
// pressure-gated). See lib/codex-delegate-gate.js for the policy.
|
|
5
6
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
7
|
+
// It DENIES a code Write/Edit only when ALL hold : the lane is armed (yanstaller
|
|
8
|
+
// option on AND Codex linked), the ROUTER routes the task to Codex, we are under
|
|
9
|
+
// Claude budget PRESSURE, Codex is available, and no delegation happened this turn
|
|
10
|
+
// — and the human has not opted out. Otherwise it allows. Never traps a turn on an
|
|
11
|
+
// internal error (fails open), always exits 0.
|
|
11
12
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// - `// BYAN-DELEGATE: reviewed` in the file acknowledges a deliberate
|
|
16
|
-
// Claude-lane choice (Codex unavailable, judgment/verify) and passes.
|
|
17
|
-
// - deny-once : an identical resubmission passes, and a grace window after a
|
|
18
|
-
// deny lets a multi-file build proceed without nagging on every file.
|
|
19
|
-
//
|
|
20
|
-
// Never traps a turn, always exits 0. Pure decision in lib/codex-delegate-gate.js;
|
|
21
|
-
// armed/linked detection reused from codex-autodelegate.js; delegability from
|
|
22
|
-
// autodelegate-decision.js; the turn transcript via transcript-read.js.
|
|
13
|
+
// The two computed signals (router decision, budget pressure) are only evaluated
|
|
14
|
+
// in the would-deny branch, so the common allow paths pay nothing. Both fail open
|
|
15
|
+
// (an unresolvable signal -> allow, never a wrong block).
|
|
23
16
|
|
|
24
17
|
const fs = require('fs');
|
|
25
18
|
const path = require('path');
|
|
19
|
+
const { spawnSync } = require('child_process');
|
|
20
|
+
const { pathToFileURL } = require('url');
|
|
26
21
|
const gate = require('./lib/codex-delegate-gate');
|
|
27
22
|
const { loadConfig, codexLinked, toggledOff } = require('./codex-autodelegate');
|
|
28
|
-
const {
|
|
29
|
-
const { extractRecentMessages,
|
|
23
|
+
const { estimateClaudeUsage } = require('./lib/usage-estimator');
|
|
24
|
+
const { extractRecentMessages, contentToText } = require('./lib/transcript-read');
|
|
30
25
|
|
|
31
26
|
const ROOT = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
32
|
-
const
|
|
27
|
+
const ROUTER_PATH = path.resolve(__dirname, '../../_byan/mcp/byan-mcp-server/lib/dispatch-router.js');
|
|
28
|
+
const DEFAULT_PRESSURE_THRESHOLD = 75; // % of the Claude budget window
|
|
33
29
|
|
|
34
30
|
function readStdin() {
|
|
35
31
|
return new Promise((resolve) => {
|
|
@@ -40,44 +36,47 @@ function readStdin() {
|
|
|
40
36
|
});
|
|
41
37
|
}
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function deny(reason) {
|
|
48
|
-
return {
|
|
49
|
-
hookSpecificOutput: {
|
|
50
|
-
hookEventName: 'PreToolUse',
|
|
51
|
-
permissionDecision: 'deny',
|
|
52
|
-
permissionDecisionReason: reason,
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
}
|
|
39
|
+
const allow = () => ({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'allow' } });
|
|
40
|
+
const deny = (reason) => ({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason } });
|
|
56
41
|
|
|
57
|
-
|
|
58
|
-
|
|
42
|
+
// Codex availability probe : `codex --version` exits 0. Absent/broken -> false ->
|
|
43
|
+
// the guard must NOT deny (staying on Claude is the legit fallback).
|
|
44
|
+
function probeCodexAvailable(runner = spawnSync) {
|
|
45
|
+
try {
|
|
46
|
+
const res = runner('codex', ['--version'], { timeout: 8000, encoding: 'utf8' });
|
|
47
|
+
return res && res.status === 0;
|
|
48
|
+
} catch (_e) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
59
51
|
}
|
|
60
52
|
|
|
61
|
-
|
|
53
|
+
// routerSaysCodex(text) : does dispatch-router route this task's text to Codex?
|
|
54
|
+
// The router keyword-matches on the text (execution/shell/deploy/script...). ESM
|
|
55
|
+
// module dynamically imported from this CJS hook. Fails open (false = don't block)
|
|
56
|
+
// if the router cannot be loaded.
|
|
57
|
+
async function defaultRouteProbe(text) {
|
|
62
58
|
try {
|
|
63
|
-
const
|
|
64
|
-
return
|
|
59
|
+
const mod = await import(pathToFileURL(ROUTER_PATH).href);
|
|
60
|
+
return mod.routeRuntime(String(text || '')) === 'codex';
|
|
65
61
|
} catch (_e) {
|
|
66
|
-
return
|
|
62
|
+
return false;
|
|
67
63
|
}
|
|
68
64
|
}
|
|
69
65
|
|
|
70
|
-
|
|
66
|
+
// underPressure : Claude budget usage >= threshold. Needs a budget in the config
|
|
67
|
+
// (no budget -> pct null -> not under pressure -> no delegation, documented).
|
|
68
|
+
function computeUnderPressure(config) {
|
|
71
69
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
const budget = config && config.budget ? config.budget : null;
|
|
71
|
+
if (!budget) return false;
|
|
72
|
+
const threshold = typeof config.threshold === 'number' ? config.threshold : DEFAULT_PRESSURE_THRESHOLD;
|
|
73
|
+
const usage = estimateClaudeUsage({ budget });
|
|
74
|
+
return typeof usage.pct === 'number' && usage.pct >= threshold;
|
|
74
75
|
} catch (_e) {
|
|
75
|
-
|
|
76
|
+
return false;
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
// The last user message text this turn, for the delegability signal (a code
|
|
80
|
-
// target already suffices, this only broadens it).
|
|
81
80
|
function lastUserText(payload) {
|
|
82
81
|
const msgs = extractRecentMessages(payload, 12);
|
|
83
82
|
if (!Array.isArray(msgs)) return '';
|
|
@@ -87,45 +86,38 @@ function lastUserText(payload) {
|
|
|
87
86
|
return '';
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
// runGuard — async (the router import is async). opts inject the probes for tests.
|
|
90
|
+
async function runGuard(payload, {
|
|
91
|
+
root = ROOT,
|
|
92
|
+
codexProbe = probeCodexAvailable,
|
|
93
|
+
routeProbe = defaultRouteProbe,
|
|
94
|
+
pressureProbe = computeUnderPressure,
|
|
95
|
+
} = {}) {
|
|
93
96
|
const toolName = payload.tool_name || payload.toolName || '';
|
|
94
97
|
if (toolName !== 'Write' && toolName !== 'Edit') return allow();
|
|
95
98
|
|
|
96
99
|
const config = loadConfig(root);
|
|
97
100
|
const armed = config.enabled === true && codexLinked();
|
|
98
|
-
|
|
101
|
+
if (!armed) return allow(); // fast path, no transcript/probe work when off
|
|
99
102
|
|
|
103
|
+
const escaped = toggledOff(root);
|
|
100
104
|
const input = payload.tool_input || payload.toolInput || {};
|
|
101
105
|
const filePath = input.file_path || input.filePath || '';
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
: String(input.content || '');
|
|
105
|
-
|
|
106
|
-
const userText = lastUserText(payload);
|
|
107
|
-
const delegable = gate.targetIsCode(filePath) || looksDelegable(userText);
|
|
108
|
-
const reviewedMarker = gate.hasReviewedMarker(content) || gate.hasReviewedMarker(extractLastAssistantText(payload));
|
|
106
|
+
const isCode = gate.targetIsCode(filePath);
|
|
107
|
+
const humanOptOut = gate.humanOptOutFromText(lastUserText(payload));
|
|
109
108
|
const delegationSeen = gate.delegationSeenThisTurn(extractRecentMessages(payload, 12) || []);
|
|
110
|
-
|
|
109
|
+
|
|
110
|
+
// Only compute the two expensive signals when a deny is otherwise possible.
|
|
111
|
+
const maybeDeny = !escaped && !humanOptOut && isCode && !delegationSeen;
|
|
112
|
+
const routerSaysCodex = maybeDeny ? await routeProbe(lastUserText(payload)) : false;
|
|
113
|
+
const underPressure = (maybeDeny && routerSaysCodex) ? pressureProbe(config) : false;
|
|
114
|
+
const codexAvailable = (maybeDeny && routerSaysCodex && underPressure) ? codexProbe() : true;
|
|
111
115
|
|
|
112
116
|
const decision = gate.decideDelegateGate({
|
|
113
|
-
armed,
|
|
114
|
-
|
|
115
|
-
delegationSeen,
|
|
116
|
-
escaped,
|
|
117
|
-
reviewedMarker,
|
|
118
|
-
priorDeny: readPriorDeny(root),
|
|
119
|
-
turnHash,
|
|
120
|
-
now,
|
|
121
|
-
graceMs: GRACE_MS,
|
|
117
|
+
armed, routerSaysCodex, targetIsCode: isCode, underPressure,
|
|
118
|
+
delegationSeen, escaped, humanOptOut, codexAvailable,
|
|
122
119
|
});
|
|
123
|
-
|
|
124
|
-
if (decision.decision === 'deny') {
|
|
125
|
-
writePriorDeny(root, { hash: turnHash, ts: now });
|
|
126
|
-
return deny(decision.reason);
|
|
127
|
-
}
|
|
128
|
-
return allow();
|
|
120
|
+
return decision.decision === 'deny' ? deny(decision.reason) : allow();
|
|
129
121
|
}
|
|
130
122
|
|
|
131
123
|
if (require.main === module) {
|
|
@@ -133,7 +125,7 @@ if (require.main === module) {
|
|
|
133
125
|
let out;
|
|
134
126
|
try {
|
|
135
127
|
const payload = JSON.parse((await readStdin()) || '{}');
|
|
136
|
-
out = runGuard(payload);
|
|
128
|
+
out = await runGuard(payload);
|
|
137
129
|
} catch (_e) {
|
|
138
130
|
out = allow();
|
|
139
131
|
}
|
|
@@ -142,4 +134,4 @@ if (require.main === module) {
|
|
|
142
134
|
})();
|
|
143
135
|
}
|
|
144
136
|
|
|
145
|
-
module.exports = { runGuard,
|
|
137
|
+
module.exports = { runGuard, probeCodexAvailable, defaultRouteProbe, computeUnderPressure, lastUserText };
|
|
@@ -36,7 +36,8 @@ const ANCHOR = [
|
|
|
36
36
|
'- Challenge avant de confirmer ; questionne les absolus (Mantra IA-16).',
|
|
37
37
|
'- Signatures : "Attends — pourquoi ?", "OK. On construit.", "Ça, c\'est du générique.".',
|
|
38
38
|
'- Zéro emoji. Orienté solution : on cherche la meilleure option, pas le mur.',
|
|
39
|
-
'- Français réel et cohérent (Mantra IA-26) : pas d\'anglais gratuit (dis "redémarrer le conteneur", pas "cutoff"), pas de jargon interne brut, pas de métaphore collée de travers ("forger" un token).',
|
|
39
|
+
'- Français réel et cohérent (Mantra IA-26) : pas d\'anglais gratuit (dis "redémarrer le conteneur", pas "cutoff"), pas de jargon interne brut ("nudge", "up-tier", "ladder", "runtime"), pas de métaphore collée de travers ("forger" un token).',
|
|
40
|
+
'- Précision factuelle : nomme l\'outil et le résultat observé ("byan_ping a répondu", pas "le MCP est vivant") ; un état = un fait mesuré, pas une image.',
|
|
40
41
|
].join('\n');
|
|
41
42
|
|
|
42
43
|
const DEFAULT_REFRESH_EVERY = 12;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
const { perfFavors } = require('./perf-routing');
|
|
24
24
|
|
|
25
|
-
const DEFAULT_THRESHOLD =
|
|
25
|
+
const DEFAULT_THRESHOLD = 75;
|
|
26
26
|
const DEFAULT_INVOCATION = 'codex:codex-rescue --model gpt-5.4';
|
|
27
27
|
const RED_LINE = 'delegable work only (code / mechanical) — judgment, analysis, soul and verification stay on Claude';
|
|
28
28
|
|
|
@@ -71,16 +71,12 @@ function decideAutodelegation({ requestText = '', usage = null, config = {} } =
|
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
redLine: RED_LINE,
|
|
81
|
-
invocation,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
74
|
+
// v3 : NATURE alone is no longer an auto-delegate trigger. The user's decision
|
|
75
|
+
// is PRESSURE-only — delegating to the subscription Codex (which trails Claude
|
|
76
|
+
// on quality) is worth it to spare the Claude budget, not per coding task. So a
|
|
77
|
+
// delegable task off-pressure does NOT propose Codex. `delegable` is kept only as
|
|
78
|
+
// a signal the perf-routing opt-in below can still use.
|
|
79
|
+
void delegable;
|
|
84
80
|
|
|
85
81
|
// PERF (opt-in): the forces table (user-populated) may favor Codex for this
|
|
86
82
|
// kind of task even at low pressure. Off by default; always heuristic.
|
|
@@ -141,8 +137,10 @@ function renderNudge(decision) {
|
|
|
141
137
|
`[BYAN auto-delegate]${gauge}: ${scope} via \`${invocation}\` `
|
|
142
138
|
+ '(runs on the ChatGPT subscription, no API credit).',
|
|
143
139
|
`Red line: ${decision.redLine}. The lane is ARMED (option on AND Codex linked), so this is a `
|
|
144
|
-
+ 'DIRECTIVE, not a
|
|
145
|
-
+
|
|
140
|
+
+ 'DIRECTIVE, not a suggestion: delegate the delegable part. The ONLY valid reasons to stay on '
|
|
141
|
+
+ 'Claude are (1) Codex unavailable, or (2) the user asked to stay on Claude. "Small script / '
|
|
142
|
+
+ 'latency / I verify anyway" is NOT a valid reason — the codex-delegate-guard denies a delegable '
|
|
143
|
+
+ "code write that skips Codex. Verify Codex's output before commit.",
|
|
146
144
|
].join(' ');
|
|
147
145
|
}
|
|
148
146
|
|
|
Binary file
|
|
@@ -32,6 +32,11 @@ const OFFENDERS = Object.freeze([
|
|
|
32
32
|
{ term: 'gate', good: 'point de controle / porte' },
|
|
33
33
|
{ term: 'leaf', good: 'etape / tache' },
|
|
34
34
|
{ term: 'tier', good: 'niveau / gamme' },
|
|
35
|
+
{ term: 'nudge', good: 'rappel / conseil injecte' },
|
|
36
|
+
{ term: 'up-tier', good: 'monter en gamme' },
|
|
37
|
+
{ term: 'ladder', good: 'echelle' },
|
|
38
|
+
{ term: 'rung', good: 'palier' },
|
|
39
|
+
{ term: 'runtime', good: "moteur d'execution" },
|
|
35
40
|
]);
|
|
36
41
|
|
|
37
42
|
// A metaphor misuse, not a single word: "forger" applied to a token/jeton.
|
|
@@ -43,6 +48,19 @@ const METAPHOR_OFFENDERS = Object.freeze([
|
|
|
43
48
|
label: 'forger un token',
|
|
44
49
|
good: 'generer / creer un token',
|
|
45
50
|
},
|
|
51
|
+
{
|
|
52
|
+
// Anthropomorphism applied to a tool: an MCP/serveur/hook is not "vivant" or
|
|
53
|
+
// "mort" — the precise statement is the observed fact ("byan_ping a repondu",
|
|
54
|
+
// "le serveur ne repond pas, timeout 8s"). The predicate must be COPULA-bound
|
|
55
|
+
// to the tool word ("le serveur est mort", "l'API semble morte") : bare
|
|
56
|
+
// proximity would misfire on fixed French idioms near a tool word ("point
|
|
57
|
+
// mort", "angle mort", "temps mort", "nature morte", "communaute vivante"),
|
|
58
|
+
// which carry no anthropomorphism at all.
|
|
59
|
+
id: 'outil-vivant-mort',
|
|
60
|
+
re: /\b(?:mcp|serveur|outil|hook|api|tool)s?\b[^.!?\n]{0,40}\b(?:est|sont|etait|était|etaient|étaient|semble|semblent|parait|paraît|paraissent|reste|restent)\s+(?:bien\s+|encore\s+|toujours\s+|deja\s+|déjà\s+)?(?:vivante?s?|morte?s?)\b/i,
|
|
61
|
+
label: 'outil "vivant/mort"',
|
|
62
|
+
good: 'le fait observe : "repond" / "ne repond pas" + le resultat exact',
|
|
63
|
+
},
|
|
46
64
|
]);
|
|
47
65
|
|
|
48
66
|
// A word boundary that treats accented letters as part of a word, so \btier\b
|
|
@@ -26,7 +26,8 @@ A native workflow script mutates FD/strict state only through the `byan_fd_*` /
|
|
|
26
26
|
|
|
27
27
|
Each `agent()` leaf runs on the session model unless the call sets `opts.model`.
|
|
28
28
|
The tiering decision lives in one place — `_byan/mcp/byan-mcp-server/lib/native-tiers.js`
|
|
29
|
-
(tier vocabulary, leaf classifier, model map). Three tiers
|
|
29
|
+
(tier vocabulary, leaf classifier, model map). Three AUTO-routed tiers, plus an
|
|
30
|
+
explicit UP-TIER an author may pin by complexity (v3):
|
|
30
31
|
|
|
31
32
|
- **cheap (`model: 'haiku'`)** — a pure EXPLORATION leaf (read/load/parse/detect).
|
|
32
33
|
- **balanced (`model: 'sonnet'`)** — two classes land here. (1) MECHANICAL
|
|
@@ -40,16 +41,25 @@ The tiering decision lives in one place — `_byan/mcp/byan-mcp-server/lib/nativ
|
|
|
40
41
|
leaf may carry `model: 'sonnet'` (its tier) but not `haiku` (`analysis-below-tier`).
|
|
41
42
|
Semantic/adversarial VERIFICATION is NOT analysis and stays deep.
|
|
42
43
|
- **deep (OMIT `opts.model`)** — implementation + verification leaves inherit the
|
|
43
|
-
session model (no pin-up
|
|
44
|
-
deep with the `deep-` label prefix
|
|
45
|
-
`mech-` opt-in.
|
|
44
|
+
session model (the cost-safe default: no AUTO pin-up). A genuinely frontier
|
|
45
|
+
ANALYSIS leaf opts back to deep with the `deep-` label prefix
|
|
46
|
+
(`deep-assess-architecture`), the mirror of the `mech-` opt-in.
|
|
47
|
+
- **up-tier (`model: 'opus'` / `model: 'fable'`)** — an EXPLICIT authoring choice
|
|
48
|
+
to raise a genuinely complex leaf ABOVE the inherited tier (v3). `opus` for a
|
|
49
|
+
hard leaf, `fable` as the last-resort top-reasoning model for extreme complexity
|
|
50
|
+
(~2x Opus price). This is the workflow-leaf mirror of the dispatch-router
|
|
51
|
+
complexity ladder (haiku -> sonnet -> opus -> fable). Auto-routing does not pick
|
|
52
|
+
it — the author writes it deliberately. The anti-downgrade floor does not apply
|
|
53
|
+
upward, so the linter allows an up-tier pin on any leaf (it costs more, it does
|
|
54
|
+
not regress quality). The old blanket "no pin-up / no Fable" ban is lifted.
|
|
46
55
|
|
|
47
56
|
The linter splits the two directions:
|
|
48
57
|
|
|
49
|
-
- **Floor (HARD, blocks the commit)** — a
|
|
50
|
-
|
|
58
|
+
- **Floor (HARD, blocks the commit)** — a DOWNGRADE model (haiku/sonnet) on a
|
|
59
|
+
PROTECTED leaf, or a half-applied `mech-` opt-in, is a contract violation
|
|
51
60
|
(`modelRoutingViolations` + `mechanicalLabelViolations`). This is the STRICT-2
|
|
52
|
-
No Downgrade net.
|
|
61
|
+
No Downgrade net. An UP-TIER pin (opus/fable) is not a violation — the floor
|
|
62
|
+
guards downward only.
|
|
53
63
|
- **Ceiling (ADVISORY, non-blocking)** — an exploration- OR analysis-labelled leaf
|
|
54
64
|
that runs deep is *reported* (`byan-lint-workflows.js --advise`:
|
|
55
65
|
`untiered-exploration` -> `model: 'haiku'`, `untiered-analysis` -> `model: 'sonnet'`),
|
|
@@ -41,7 +41,25 @@ rappel des récidivistes connus.
|
|
|
41
41
|
| gate | point de contrôle / porte |
|
|
42
42
|
| leaf | étape / tâche |
|
|
43
43
|
| tier | niveau / gamme |
|
|
44
|
+
| nudge | rappel / conseil injecté |
|
|
45
|
+
| up-tier | monter en gamme |
|
|
46
|
+
| ladder | échelle |
|
|
47
|
+
| rung | palier |
|
|
48
|
+
| runtime | moteur d'exécution |
|
|
44
49
|
| "forger" un token | générer / créer un token |
|
|
50
|
+
| un outil/MCP/serveur "vivant" ou "mort" | le fait observé : "répond" / "ne répond pas" + le résultat exact |
|
|
51
|
+
|
|
52
|
+
## Précision factuelle (le fond, pas seulement la forme)
|
|
53
|
+
|
|
54
|
+
Le langage clair ne suffit pas s'il reste vague. Deux obligations :
|
|
55
|
+
|
|
56
|
+
1. **Zéro anthropomorphisme d'outil.** Un MCP, un serveur, un hook n'est ni
|
|
57
|
+
"vivant", ni "mort", ni "content". Dis le fait observé : "`byan_ping` a
|
|
58
|
+
répondu en 0.3s", "le serveur ne répond pas (timeout 8s)".
|
|
59
|
+
2. **Un état = une observation nommée.** Toute affirmation sur l'état d'un outil
|
|
60
|
+
ou d'un résultat nomme l'outil, l'appel effectué et la valeur retournée —
|
|
61
|
+
pas un résumé flou ("ça marche", "il monte pas"). Si tu n'as pas fait
|
|
62
|
+
l'appel, dis-le : "non vérifié".
|
|
45
63
|
|
|
46
64
|
## Le mécanisme (comment c'est tenu, sans boucle de réécriture)
|
|
47
65
|
|
|
@@ -21,8 +21,10 @@ the user should not have to ask for it. Four moments:
|
|
|
21
21
|
(`_byan/mcp/byan-mcp-server/lib/agent-matcher.js`), the right model + effort
|
|
22
22
|
(`dispatch-router.js` / native-tiers), and the right runtime — Codex for
|
|
23
23
|
execution / shell / deploy / devops / browser ; Claude for architecture /
|
|
24
|
-
refactor / quality / planning ; verification stays on Claude
|
|
25
|
-
|
|
24
|
+
refactor / quality / planning ; verification stays on Claude. The Claude model
|
|
25
|
+
scales on a four-rung complexity ladder (haiku -> sonnet -> opus -> fable, fable
|
|
26
|
+
the extreme last resort) ; Fable is refused on the Codex path only. No user ask.
|
|
27
|
+
A suited agent -> use it. NO suited agent -> interview to
|
|
26
28
|
frame the need, web-research the trade's competencies + best practices, create
|
|
27
29
|
the tailored agent (the one place the human is required upstream).
|
|
28
30
|
3. **Execute in party-mode with a live visual.** The user SEES what happens, live:
|
|
@@ -30,13 +32,17 @@ the user should not have to ask for it. Four moments:
|
|
|
30
32
|
`TaskCreate` / `TaskUpdate`) plus the dispatch table shown at the top of BUILD.
|
|
31
33
|
- **Codex-lane** — when the lane is ARMED (yanstaller option on AND Codex
|
|
32
34
|
linked, i.e. `_byan/_config/autodelegate.json` present with `enabled:true`
|
|
33
|
-
AND `~/.codex/auth.json` or `CODEX_API_KEY`) and the task is delegable,
|
|
35
|
+
AND `~/.codex/auth.json` or `CODEX_API_KEY`) and the task is delegable code,
|
|
34
36
|
ACTUALLY delegate via `codex-bridge.js` (`codex exec` -> unified diff -> YOU
|
|
35
|
-
apply it)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
apply it) or the `codex:codex-rescue` agent. This is a DIRECTIVE, enforced by
|
|
38
|
+
the `codex-delegate-guard` PreToolUse tooth : it DENIES a delegable code
|
|
39
|
+
Write/Edit that skipped Codex. The ONLY valid reasons to stay on Claude are
|
|
40
|
+
(1) Codex unavailable (auto-detected), or (2) the USER asked to stay on Claude
|
|
41
|
+
("reste sur Claude" / "sans codex", or the `.byan-codex-autodelegate/off`
|
|
42
|
+
switch). "Small script / latency / I verify anyway" is NOT valid — that is
|
|
43
|
+
exactly the self-dodge the tooth closes (option B). You cannot self-grant a
|
|
44
|
+
bypass. When NOT armed (option off or Codex not linked), there is no
|
|
45
|
+
delegation — you run it on Claude.
|
|
40
46
|
- **Claude-lane** — run it on Claude at the chosen model.
|
|
41
47
|
4. **User gate at the END.** The user-validation gate lands at the end, once the
|
|
42
48
|
feature/task is done and there is a deliverable to review — not upstream. (In a
|
|
@@ -56,6 +62,33 @@ net (`agent-gate-check.js`) at turn end — not a guarantee enforced before disp
|
|
|
56
62
|
Full doctrine + runtime routing table: see @.claude/rules/agent-entry-gate.md and
|
|
57
63
|
@docs/intelligent-dispatch.md
|
|
58
64
|
|
|
65
|
+
## 0.5. Rail natif automatique — byan-auto-dispatch (OBLIGATOIRE)
|
|
66
|
+
|
|
67
|
+
A CHAQUE tache non-conversationnelle recue par /byan-byan, le dispatch et
|
|
68
|
+
l'execution passent par le workflow natif — SANS que l'utilisateur le demande :
|
|
69
|
+
|
|
70
|
+
1. Appelle l'outil **Workflow** avec
|
|
71
|
+
`{ scriptPath: '.claude/workflows/byan-auto-dispatch.js', args: { task: <la demande, verbatim>, stamp: <horodatage ISO courant> } }`.
|
|
72
|
+
Ne demande pas la permission de le lancer ; ne substitue pas une execution
|
|
73
|
+
directe main-thread au workflow.
|
|
74
|
+
2. Le workflow fait tout le rail : il decoupe la tache en etapes typees, route
|
|
75
|
+
chaque etape sur le bon modele (echelle par complexite : haiku < 34,
|
|
76
|
+
sonnet < 67, opus < 90, fable >= 90 ; moteur Codex pour shell/deploiement
|
|
77
|
+
avec repli Claude ; la verification reste sur le modele de session), ecrit
|
|
78
|
+
`_byan-output/plan.md`, execute chaque etape sur le modele route, verifie.
|
|
79
|
+
3. Au retour : montre la table etape x nature x complexite x moteur x modele,
|
|
80
|
+
le verdict de verification, et pointe `_byan-output/plan.md`. Le gate
|
|
81
|
+
utilisateur est EN FIN, sur le livrable.
|
|
82
|
+
4. **Exceptions** (les seules) : une question simple / de la conversation ->
|
|
83
|
+
reponds directement ; une action destructive -> confirme d'abord ; un FD
|
|
84
|
+
multi-feature deja engage -> la phase DISPATCH du FD prend le dessus (elle
|
|
85
|
+
peut invoquer ce meme workflow feature par feature) ; l'utilisateur demande
|
|
86
|
+
explicitement une execution directe sans workflow.
|
|
87
|
+
|
|
88
|
+
Note honnete : l'outil Workflow peut demander une autorisation a l'invocation
|
|
89
|
+
selon le mode de permissions de la session — c'est le harnais qui la pose, pas
|
|
90
|
+
toi ; ne la re-demande pas en plus.
|
|
91
|
+
|
|
59
92
|
## 1. Activation triggers
|
|
60
93
|
|
|
61
94
|
Invoke this protocol when the user :
|
|
@@ -129,13 +162,14 @@ Never call `byan_update_apply` without explicit user consent. That tool returns
|
|
|
129
162
|
- nature `exploration` (load/read/scan/list/parse/fetch...) → `haiku`
|
|
130
163
|
- nature `mechanical` (binary judgment-free checks : JSON parses, schema matches, lint passes — label prefix `mech-`, explicit opt-in only) → `sonnet`
|
|
131
164
|
- nature `implementation` / `verification` / `analysis` / unknown → deep = **inherit the session model**
|
|
132
|
-
- Keep protected work (verify/analysis/implement) off haiku/sonnet regardless of size
|
|
165
|
+
- Keep protected work (verify/analysis/implement) off haiku/sonnet regardless of size. Auto-routing does not pin up ; but an author MAY deliberately UP-TIER a genuinely complex leaf to `opus` (hard) or `fable` (extreme, last resort) — the linter allows it (the floor guards downward only). Pass an explicit `nature` to `byan_dispatch` when you know it.
|
|
133
166
|
- **Inside native workflow scripts** (`.claude/workflows/*.js` OR ad-hoc) the SAME tiering applies per `agent()` leaf via `opts.model`, enforced as a FLOOR not a ceiling on TWO nets :
|
|
134
|
-
- **Repo linter** (committed scripts, pre-commit) : `modelRoutingViolations` HARD-blocks a downgrade on a protected leaf,
|
|
167
|
+
- **Repo linter** (committed scripts, pre-commit) : `modelRoutingViolations` HARD-blocks a downgrade (haiku/sonnet) on a protected leaf, or a half-applied `mech-` opt-in (`mechanical-without-model` / `mechanical-below-tier`) ; an UP-TIER pin (opus/fable) is allowed, not blocked (the floor guards downward only) ; an exploration-labelled leaf left deep is a NON-blocking ADVISORY (`byan-lint-workflows.js --advise`), since many such leaves bear a gate/classification/exact-conversion and must stay deep — the human owns that call.
|
|
135
168
|
- **Tier gate hook** (EVERY Workflow invocation, inline or scriptPath) : `tier-script-guard.js` (PreToolUse) runs the same analysis (`lib/tier-script.js`) and DENIES ONCE when exploration/`mech-` leaves have no tier, with the exact leaf list to fix. Acknowledge deliberate deep choices with the `// BYAN-TIER: reviewed` comment marker ; an identical resubmission passes (deny-once by design, no trap). Every decision lands in `_byan-output/tier-ledger.jsonl` (the measurement basis for token gains). Escape hatch : `.byan-tier/off`.
|
|
136
169
|
- **Authoring aid** : BEFORE writing a script, call `byan_dispatch` with `{ leaves: [{ label, nature? }] }` (batch mode) to get the `opts.model` per leaf ; write `model:` only where non-null. Report with `node _byan/mcp/byan-mcp-server/bin/byan-tier-script.js <file> [--json]`.
|
|
137
170
|
- No per-leaf effort knob exists (the API exposes only `model`), so effort-by-complexity reduces to model-by-complexity.
|
|
138
171
|
- **Output** : a table `{ feature → specialist → model → strategy → estimated_tokens }`.
|
|
172
|
+
- **Execution engine per feature** : le workflow natif `byan-auto-dispatch` (section 0.5) prend la feature comme `task` — meme decoupage, meme echelle de modeles, meme plan.md. Repartition des roles : `byan-hermes-dispatch` reste l'ORCHESTRATEUR du BUILD (phase 5) ; `byan-auto-dispatch` est le MOTEUR qu'il peut invoquer par feature (une invocation Workflow = une feature). Pas deux pilotes : un orchestrateur, un moteur.
|
|
139
173
|
- **If no specialist matches** : halt. Ask user whether to run INT (agent recruitment) first. Do NOT fallback silently to general-purpose.
|
|
140
174
|
- **Exit gate** : user validates the mapping.
|
|
141
175
|
|