create-byan-agent 2.45.0 → 2.47.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.
- package/CHANGELOG.md +86 -0
- package/install/templates/.claude/CLAUDE.md +12 -2
- package/install/templates/.claude/hooks/agent-gate-check.js +53 -0
- package/install/templates/.claude/hooks/inject-voice-anchor.js +15 -1
- package/install/templates/.claude/hooks/lib/agent-gate.js +127 -0
- package/install/templates/.claude/rules/agent-entry-gate.md +83 -0
- package/install/templates/.claude/settings.json +4 -0
- package/install/templates/.claude/skills/byan-byan/SKILL.md +14 -0
- package/install/templates/.claude/workflows/intelligent-dispatch.js +68 -0
- package/install/templates/_byan/mcp/byan-mcp-server/lib/agent-matcher.js +167 -0
- package/install/templates/_byan/mcp/byan-mcp-server/lib/codex-bridge.js +176 -0
- package/install/templates/_byan/mcp/byan-mcp-server/lib/dispatch-blackboard.js +114 -0
- package/install/templates/_byan/mcp/byan-mcp-server/lib/dispatch-orchestrator.js +116 -0
- package/install/templates/_byan/mcp/byan-mcp-server/lib/dispatch-router.js +149 -0
- 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/intelligent-dispatch.md +84 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,92 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [2.47.1] - 2026-07-16
|
|
13
|
+
|
|
14
|
+
### Fixed - Doctrine told users to invoke with `@byan`, which does not load the skill
|
|
15
|
+
|
|
16
|
+
- The docs said "tape `@byan` / `@hermes`" to invoke BYAN. In Claude Code, `@` is a
|
|
17
|
+
file mention, not a skill loader — so the byan-byan skill (which holds the agent
|
|
18
|
+
entry gate) was not loaded, and BYAN ran a task inline with no dispatch. Root
|
|
19
|
+
cause of the entry gate appearing "not to work" on a real machine.
|
|
20
|
+
- Corrected the entry guidance in `CLAUDE.md`: invoke BYAN with the **command**
|
|
21
|
+
`/byan-byan` (it loads the skill, the entry gate, and the rail) ; noted explicitly
|
|
22
|
+
that `@byan`/`@hermes` do not load the skill. Mirrored to install/templates.
|
|
23
|
+
- Note: the entry-gate code (2.47.0) is unchanged and correct ; it simply was not
|
|
24
|
+
reached because the skill was not loaded. Open question (does the loaded doctrine
|
|
25
|
+
reliably make BYAN propose an agent, or is a hard pre-write block needed) is to be
|
|
26
|
+
decided by testing `/byan-byan` with the rail actually loaded.
|
|
27
|
+
|
|
28
|
+
## [2.47.0] - 2026-07-16
|
|
29
|
+
|
|
30
|
+
### Added - Mandatory agent entry gate (match-or-create), the base of BYAN
|
|
31
|
+
|
|
32
|
+
- Makes the agent dispatch the front door of every non-conversational task: BYAN +
|
|
33
|
+
Hermes evaluate which specialist agent fits the need and PROPOSE it ; the user
|
|
34
|
+
validates (double validation IA + human) ; THEN the workflow runs. No suited
|
|
35
|
+
agent -> propose an interview to frame the need -> web research on the trade's
|
|
36
|
+
competencies + best practices -> create the tailored agent -> workflow. The
|
|
37
|
+
interview is triggered by the ABSENCE of a suited agent, not by task size (a fit
|
|
38
|
+
routes directly, no ceremony). This closes the gap where a plain task got done
|
|
39
|
+
inline without any dispatch.
|
|
40
|
+
- F1 `lib/agent-matcher.js` — pure suitability pre-filter: (task text + roster)
|
|
41
|
+
-> ranked candidates + a {fit | no-fit} verdict. Curated Hermes trigger words
|
|
42
|
+
(weighted) over a title/role text overlap ; accent-insensitive ; a no-fit is the
|
|
43
|
+
interview signal. Loader reads the roster from agent-manifest.csv (robust CSV
|
|
44
|
+
parse). It PROPOSES, it does not decide alone.
|
|
45
|
+
- F2/F3 doctrine `.claude/rules/agent-entry-gate.md` (+ pointer in CLAUDE.md + a
|
|
46
|
+
section 0 in the byan-byan skill): the rail, the two dispatch layers (agent vs
|
|
47
|
+
runtime), the proportionality (verify every task, interview only on no-fit), the
|
|
48
|
+
double validation, and the web-research step in agent creation.
|
|
49
|
+
- F4 reactive net `.claude/hooks/agent-gate-check.js` (+ pure core
|
|
50
|
+
`lib/agent-gate.js`): a Stop hook that flags a task done directly (files written)
|
|
51
|
+
with no agent proposal and outside an active FD cycle ; the next-turn voice
|
|
52
|
+
reminder surfaces it in plain French. Non-blocking (the correction lands next
|
|
53
|
+
turn) ; exits 0 in every path. Honest ceiling: no pre-display interception, so
|
|
54
|
+
the rail is doctrine + this net, not a first-turn wall.
|
|
55
|
+
- F5: tests (`test/agent-matcher.test.js` node:test, `.claude/__tests__/agent-gate.test.js`
|
|
56
|
+
jest). Full MCP suite + jest suite green ; workflow linter OK ; skill bundles
|
|
57
|
+
re-checked ; zero emoji. Shipped via install/templates (5 files added to the sync
|
|
58
|
+
manifest). Doc: `.claude/rules/agent-entry-gate.md`.
|
|
59
|
+
|
|
60
|
+
## [2.46.0] - 2026-07-15
|
|
61
|
+
|
|
62
|
+
### Added - Intelligent dispatch: Codex/Claude routing + architect-dev loop (option B)
|
|
63
|
+
|
|
64
|
+
- Route each task to the runtime that is genuinely better for it, on the right
|
|
65
|
+
model and effort for its complexity, and let an architect (Claude) and a dev
|
|
66
|
+
(Codex or Claude) exchange turn by turn until the work converges. Layered,
|
|
67
|
+
ports-and-adapters design so the durable core stays independent of the transport.
|
|
68
|
+
- F1 `lib/dispatch-router.js` — pure routing brain: {nature, complexity} ->
|
|
69
|
+
{runtime, model, effort}. Runtime table is the cross-checked result (Codex for
|
|
70
|
+
execution/shell/deploy/devops/browser ; Claude for architecture/refactor/quality/
|
|
71
|
+
planning ; unknown -> Claude). Complexity picks the Claude model tier via
|
|
72
|
+
native-tiers (haiku/sonnet/inherit) or the Codex reasoning-effort (low/med/high).
|
|
73
|
+
Two red lines enforced in code, not left to the caller: Fable is refused
|
|
74
|
+
(assertNoFable throws) and verification is forced to Claude (a runtime does not
|
|
75
|
+
grade its own work).
|
|
76
|
+
- F2 `lib/codex-bridge.js` — Codex transport behind a swappable adapter. The
|
|
77
|
+
shipped codex-exec adapter runs `codex exec` read-only for a unified diff that
|
|
78
|
+
Claude applies with git apply (Codex writes nothing -> works under a locked-down
|
|
79
|
+
sandbox e.g. Landlock). Failure is a value (ok:false + reason) so the loop falls
|
|
80
|
+
back to Claude. codex-mcp is a declared V2 slot (available:false) for the tighter
|
|
81
|
+
`codex mcp-server` coupling later, with no change to F1/F4.
|
|
82
|
+
- F3 `lib/dispatch-blackboard.js` — the turn-by-turn shared board the agents use to
|
|
83
|
+
exchange (build/render pure ; JSONL sidecar I/O isolated). The honest substitute
|
|
84
|
+
for a live peer chat: an orchestrated loop, like a chat server holding the turns.
|
|
85
|
+
- F4 `lib/dispatch-orchestrator.js` — the loop core: routes via F1, runs
|
|
86
|
+
architect<->dev through the board until convergence, executors injected (Codex vs
|
|
87
|
+
Claude) so it is fully unit-tested. `.claude/workflows/intelligent-dispatch.js` is
|
|
88
|
+
the native launch facade for one routed task (design -> implement -> verify ;
|
|
89
|
+
the verify leaf is a Claude reviewer, not the dev).
|
|
90
|
+
- Enforcement: the Codex auto-delegate config ships DISARMED (absent = off) ;
|
|
91
|
+
arming stays a per-machine opt-in (`_byan/_config/autodelegate.json`, gitignored).
|
|
92
|
+
Unit tests: `test/dispatch-router|codex-bridge|dispatch-blackboard|dispatch-orchestrator.test.js`.
|
|
93
|
+
Also corrected a pre-existing api-tools test drift (byan_api_knowledge_retrieve
|
|
94
|
+
was registered in server.js but absent from the test's tool list). Full MCP suite
|
|
95
|
+
green (833 node:test) + jest suite green. Doc: `docs/intelligent-dispatch.md`.
|
|
96
|
+
Shipped via install/templates (10 files added to the sync manifest).
|
|
97
|
+
|
|
12
98
|
## [2.45.0] - 2026-07-15
|
|
13
99
|
|
|
14
100
|
### Added - Plain-language guard for every agent (Mantra IA-26 "Parler Reel")
|
|
@@ -11,10 +11,20 @@
|
|
|
11
11
|
Avant de chercher un agent specifique, demande a Hermes. Il connait tous les agents,
|
|
12
12
|
workflows et contextes, et te route vers le bon specialiste.
|
|
13
13
|
|
|
14
|
-
Pour
|
|
14
|
+
Pour lancer BYAN sur une tache, utilise la **commande** `/byan-byan` : c'est elle qui charge le skill (donc la porte d'entree et le rail de dispatch). Attention — `@byan` / `@hermes` NE chargent PAS le skill : cote Claude Code, `@` est une mention de fichier, pas un lanceur. Une fois dans `/byan-byan`, decris ta tache ou demande "quel agent pour [ta tache] ?".
|
|
15
15
|
|
|
16
16
|
Voir @.claude/rules/hermes-dispatcher.md pour les commandes Hermes.
|
|
17
17
|
|
|
18
|
+
## Porte d'entree — dispatch d'agent obligatoire (match-or-create)
|
|
19
|
+
|
|
20
|
+
La base de BYAN : toute tache non-conversationnelle passe d'abord par le dispatch
|
|
21
|
+
d'agent. BYAN + Hermes evaluent quel agent specialiste colle au besoin et le
|
|
22
|
+
PROPOSENT ; l'utilisateur valide (double validation IA + humain), PUIS on lance le
|
|
23
|
+
workflow. Aucun agent adapte -> interview pour cadrer le besoin -> recherche web
|
|
24
|
+
(competences + bonnes pratiques du metier) -> creation de l'agent sur mesure ->
|
|
25
|
+
workflow. Le declencheur de l'interview est l'absence d'un agent adapte, pas la
|
|
26
|
+
taille de la tache. Detail + enforcement : voir @.claude/rules/agent-entry-gate.md
|
|
27
|
+
|
|
18
28
|
## Architecture BYAN
|
|
19
29
|
|
|
20
30
|
```
|
|
@@ -58,7 +68,7 @@ Doctrine d'equipe complete (template role-in-team, analogie orchestre, principes
|
|
|
58
68
|
|
|
59
69
|
## Commandes Utiles
|
|
60
70
|
|
|
61
|
-
-
|
|
71
|
+
- `/byan-byan` → Entree BYAN + dispatcher universel (recommandations, routage, pipelines). Le `@` ne charge pas le skill.
|
|
62
72
|
- Agent disponibles: voir @.claude/rules/byan-agents.md
|
|
63
73
|
- Doctrine d'equipe: voir @.claude/rules/team-doctrine.md
|
|
64
74
|
- Methodologie: voir @.claude/rules/merise-agile.md
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Stop hook — the reactive net for BYAN's mandatory agent entry gate (F4).
|
|
5
|
+
//
|
|
6
|
+
// At end of turn it asks: was a task handled DIRECTLY (files written) without any
|
|
7
|
+
// agent proposal and outside an active FD cycle ? If so it writes a one-turn flag
|
|
8
|
+
// under _byan-output/ ; the next-turn voice reminder surfaces it in plain French.
|
|
9
|
+
// It NEVER blocks the turn (the user asked to signal, not trap) — always exits 0.
|
|
10
|
+
//
|
|
11
|
+
// The judgment lives in lib/agent-gate.js (pure) ; this shell only extracts the
|
|
12
|
+
// signals from the transcript + fd-state.
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const { extractLastAssistantText, extractRecentMessages } = require('./lib/transcript-read');
|
|
16
|
+
const gate = require('./lib/agent-gate');
|
|
17
|
+
|
|
18
|
+
// detect(payload, projectDir) — testable core. Returns the assessment and writes
|
|
19
|
+
// the flag on a slip.
|
|
20
|
+
function detect(payload, projectDir) {
|
|
21
|
+
const text = extractLastAssistantText(payload);
|
|
22
|
+
const messages = extractRecentMessages(payload, 8) || [];
|
|
23
|
+
const assessment = gate.assessTurn({
|
|
24
|
+
wroteFiles: gate.hasWriteActivity(messages),
|
|
25
|
+
proposedAgent: gate.hasProposalMarker(text),
|
|
26
|
+
fdActive: gate.fdIsActive(projectDir),
|
|
27
|
+
});
|
|
28
|
+
if (assessment.slip) gate.writeSlip(projectDir, assessment.reason);
|
|
29
|
+
return assessment;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readStdin() {
|
|
33
|
+
try { return fs.readFileSync(0, 'utf8'); } catch { return ''; }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (require.main === module) {
|
|
37
|
+
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
38
|
+
let payload = {};
|
|
39
|
+
try {
|
|
40
|
+
const raw = readStdin();
|
|
41
|
+
if (raw && raw.trim()) payload = JSON.parse(raw);
|
|
42
|
+
} catch {
|
|
43
|
+
payload = {};
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
detect(payload, projectDir);
|
|
47
|
+
} catch {
|
|
48
|
+
// never block end-of-turn
|
|
49
|
+
}
|
|
50
|
+
process.stdout.write('{}');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = { detect };
|
|
@@ -27,6 +27,7 @@ const fs = require('fs');
|
|
|
27
27
|
const path = require('path');
|
|
28
28
|
const { buildTaoContext, turnCounterPath } = require('./inject-tao');
|
|
29
29
|
const pl = require('./lib/plain-language');
|
|
30
|
+
const gate = require('./lib/agent-gate');
|
|
30
31
|
|
|
31
32
|
const ANCHOR = [
|
|
32
33
|
'Voix BYAN (rappel par tour ; tao complet chargé au démarrage de session) :',
|
|
@@ -88,6 +89,13 @@ function withSlipReminder(baseContext, hits) {
|
|
|
88
89
|
return reminder ? `${baseContext}\n${reminder}` : baseContext;
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
// Append the agent-gate reminder (F4) when the previous turn did a task directly
|
|
93
|
+
// without proposing an agent. Pure; the fs read + clear stays in require.main.
|
|
94
|
+
function withGateReminder(baseContext, slip) {
|
|
95
|
+
const reminder = gate.formatReminder(slip);
|
|
96
|
+
return reminder ? `${baseContext}\n${reminder}` : baseContext;
|
|
97
|
+
}
|
|
98
|
+
|
|
91
99
|
if (require.main === module) {
|
|
92
100
|
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
93
101
|
const every = refreshEvery();
|
|
@@ -99,11 +107,16 @@ if (require.main === module) {
|
|
|
99
107
|
// the flag (one-shot). Read/clear here, formatting stays pure in withSlipReminder.
|
|
100
108
|
const slipHits = pl.readSlip(projectDir);
|
|
101
109
|
if (slipHits && slipHits.length) pl.clearSlip(projectDir);
|
|
110
|
+
// Forward net #2 (F4): agent entry-gate slip. Read + clear one-shot.
|
|
111
|
+
const gateSlip = gate.readSlip(projectDir);
|
|
112
|
+
if (gateSlip) gate.clearSlip(projectDir);
|
|
113
|
+
let ctx = withSlipReminder(additionalContext, slipHits);
|
|
114
|
+
ctx = withGateReminder(ctx, gateSlip);
|
|
102
115
|
process.stdout.write(
|
|
103
116
|
JSON.stringify({
|
|
104
117
|
hookSpecificOutput: {
|
|
105
118
|
hookEventName: 'UserPromptSubmit',
|
|
106
|
-
additionalContext:
|
|
119
|
+
additionalContext: ctx,
|
|
107
120
|
},
|
|
108
121
|
})
|
|
109
122
|
);
|
|
@@ -117,5 +130,6 @@ module.exports = {
|
|
|
117
130
|
writeTurn,
|
|
118
131
|
decideAnchor,
|
|
119
132
|
withSlipReminder,
|
|
133
|
+
withGateReminder,
|
|
120
134
|
DEFAULT_REFRESH_EVERY,
|
|
121
135
|
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// F4 core — the reactive net for the mandatory agent entry gate.
|
|
4
|
+
//
|
|
5
|
+
// BYAN's philosophy: every non-conversational task passes through Hermes+BYAN
|
|
6
|
+
// PROPOSING a suited agent (or an interview to create one), validated by the
|
|
7
|
+
// user, BEFORE any work. No pre-display hook exists, so this net is post-hoc: at
|
|
8
|
+
// end of turn it detects a task done DIRECTLY (files written) without any agent
|
|
9
|
+
// proposal and without an active FD cycle, writes a one-turn flag, and the
|
|
10
|
+
// next-turn reminder surfaces it. Non-blocking by design (the user asked to
|
|
11
|
+
// "signal", not to trap the turn) — the correction lands on the next turn.
|
|
12
|
+
//
|
|
13
|
+
// Pure: assessTurn + the marker/write detectors take plain inputs. The flag I/O
|
|
14
|
+
// is isolated. The hook shell feeds it transcript + fd-state signals.
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
// Text signals that the entry gate WAS engaged this turn (an agent was proposed,
|
|
20
|
+
// an FD phase is being narrated, a specialist was addressed, or the interview /
|
|
21
|
+
// no-fit path was surfaced). Any of these means "not a silent direct-do".
|
|
22
|
+
const PROPOSAL_MARKERS = [
|
|
23
|
+
'[fd:', '@hermes', 'agent adapte', 'aucun agent', 'je propose', 'proposition d\'agent',
|
|
24
|
+
'interview', 'byan-hermes-dispatch', 'dispatch d\'agent', 'quel agent',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// Tool names that count as "did real work on the repo" this turn.
|
|
28
|
+
const WRITE_TOOLS = new Set(['Write', 'Edit', 'MultiEdit', 'NotebookEdit']);
|
|
29
|
+
|
|
30
|
+
function hasProposalMarker(text) {
|
|
31
|
+
const t = String(text == null ? '' : text).toLowerCase();
|
|
32
|
+
return PROPOSAL_MARKERS.some((m) => t.includes(m));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// hasWriteActivity(messages) — true if any recent assistant message carried a
|
|
36
|
+
// tool_use block that writes to the repo. `messages` is an array of
|
|
37
|
+
// { role, content } where content is a string or a block array.
|
|
38
|
+
function hasWriteActivity(messages) {
|
|
39
|
+
if (!Array.isArray(messages)) return false;
|
|
40
|
+
for (const m of messages) {
|
|
41
|
+
if (!m || m.role !== 'assistant' || !Array.isArray(m.content)) continue;
|
|
42
|
+
for (const block of m.content) {
|
|
43
|
+
if (block && block.type === 'tool_use' && WRITE_TOOLS.has(block.name)) return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// assessTurn — the decision. A slip is a task done directly (files written) with
|
|
50
|
+
// no agent proposal AND no active FD cycle. When an FD is engaged, the gate is
|
|
51
|
+
// already in play (DISPATCH is part of it), so it is never a slip.
|
|
52
|
+
function assessTurn({ wroteFiles = false, proposedAgent = false, fdActive = false } = {}) {
|
|
53
|
+
const slip = Boolean(wroteFiles && !proposedAgent && !fdActive);
|
|
54
|
+
return {
|
|
55
|
+
slip,
|
|
56
|
+
reason: slip
|
|
57
|
+
? 'files written directly without an agent proposal and no active FD cycle'
|
|
58
|
+
: 'ok',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// --- slip flag (isolated I/O, mirrors the plain-language forward net) ------
|
|
63
|
+
|
|
64
|
+
function slipPath(projectDir) {
|
|
65
|
+
return path.join(projectDir, '_byan-output', '.agent-gate-slip.json');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function writeSlip(projectDir, detail) {
|
|
69
|
+
try {
|
|
70
|
+
const p = slipPath(projectDir);
|
|
71
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
72
|
+
fs.writeFileSync(p, JSON.stringify({ detail: String(detail || '') }));
|
|
73
|
+
return true;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function readSlip(projectDir) {
|
|
80
|
+
try {
|
|
81
|
+
const parsed = JSON.parse(fs.readFileSync(slipPath(projectDir), 'utf8'));
|
|
82
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function clearSlip(projectDir) {
|
|
89
|
+
try { fs.rmSync(slipPath(projectDir), { force: true }); } catch { /* never block */ }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// formatReminder — the plain-French note injected next turn. Empty when no slip.
|
|
93
|
+
function formatReminder(slip) {
|
|
94
|
+
if (!slip) return '';
|
|
95
|
+
return [
|
|
96
|
+
'Rappel dispatch (porte d\'entree BYAN) : au dernier tour une tache a ete',
|
|
97
|
+
'traitee en direct sans proposer d\'agent adapte. La base de BYAN, c\'est de',
|
|
98
|
+
'passer par Hermes : proposer l\'agent qui colle (ou une interview pour en',
|
|
99
|
+
'creer un), l\'utilisateur valide, PUIS on lance le travail. Applique-le ce tour-ci.',
|
|
100
|
+
].join(' ');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// fdIsActive(projectDir) — reads _byan-output/fd-state.json ; active means a live
|
|
104
|
+
// phase (not COMPLETED / ABORTED / absent). Read-only, best-effort.
|
|
105
|
+
function fdIsActive(projectDir) {
|
|
106
|
+
try {
|
|
107
|
+
const state = JSON.parse(fs.readFileSync(path.join(projectDir, '_byan-output', 'fd-state.json'), 'utf8'));
|
|
108
|
+
const phase = state && state.phase;
|
|
109
|
+
return Boolean(phase) && phase !== 'COMPLETED' && phase !== 'ABORTED';
|
|
110
|
+
} catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = {
|
|
116
|
+
PROPOSAL_MARKERS,
|
|
117
|
+
WRITE_TOOLS,
|
|
118
|
+
hasProposalMarker,
|
|
119
|
+
hasWriteActivity,
|
|
120
|
+
assessTurn,
|
|
121
|
+
slipPath,
|
|
122
|
+
writeSlip,
|
|
123
|
+
readSlip,
|
|
124
|
+
clearSlip,
|
|
125
|
+
formatReminder,
|
|
126
|
+
fdIsActive,
|
|
127
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Porte d'entree BYAN — dispatch d'agent obligatoire (match-or-create)
|
|
2
|
+
|
|
3
|
+
> La base de BYAN : mettre la personne sur des rails pour toute tache ou projet.
|
|
4
|
+
> Avant de faire le travail, on regarde quel agent specialiste colle au besoin.
|
|
5
|
+
> Un agent adapte existe -> on le propose et on lance son workflow. Aucun ne
|
|
6
|
+
> colle -> on interviewe pour cadrer le besoin, on cherche les competences du
|
|
7
|
+
> metier, et on cree l'agent sur mesure. Le dispatch d'agent n'est pas une
|
|
8
|
+
> option : c'est l'entree de tout.
|
|
9
|
+
|
|
10
|
+
## Le principe
|
|
11
|
+
|
|
12
|
+
Il y a DEUX dispatch, ne pas les confondre :
|
|
13
|
+
- **Dispatch d'agent (Hermes)** — QUI fait le travail : quel agent BYAN, ou on en
|
|
14
|
+
cree un. C'est le rail decrit ici.
|
|
15
|
+
- **Dispatch de runtime** — une fois l'agent choisi, sur quel moteur (Codex ou
|
|
16
|
+
Claude) + modele + effort. C'est la couche du dessous (voir
|
|
17
|
+
`docs/intelligent-dispatch.md`).
|
|
18
|
+
|
|
19
|
+
Cette regle porte sur le premier : la porte d'entree.
|
|
20
|
+
|
|
21
|
+
## Le flux (sur toute tache non-conversationnelle)
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
demande utilisateur
|
|
25
|
+
-> BYAN + Hermes evaluent quel agent specialiste colle (matcher F1)
|
|
26
|
+
AGENT ADAPTE TROUVE
|
|
27
|
+
-> BYAN le PROPOSE ("je pars sur @dev, tu valides ?")
|
|
28
|
+
-> l'utilisateur valide (double validation IA + humain)
|
|
29
|
+
-> on lance le workflow de cet agent (+ dispatch runtime)
|
|
30
|
+
AUCUN AGENT ADAPTE
|
|
31
|
+
-> BYAN le dit et propose une interview
|
|
32
|
+
-> interview : cadrer precisement le besoin de l'agent
|
|
33
|
+
-> recherche web : competences + bonnes pratiques du metier vise
|
|
34
|
+
-> creation de l'agent sur mesure
|
|
35
|
+
-> on lance le workflow
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Le declencheur de l'interview, c'est **l'absence d'un agent adapte**, pas la
|
|
39
|
+
taille de la tache. "code un script" -> l'agent dev existe -> workflow direct,
|
|
40
|
+
zero ceremonie. "il me faut un agent art moderne" -> aucun agent -> interview +
|
|
41
|
+
recherche + creation.
|
|
42
|
+
|
|
43
|
+
## La proportion (pour que le rail ne devienne pas un mur)
|
|
44
|
+
|
|
45
|
+
Le rail impose de **verifier** la pertinence d'un agent a chaque tache — pas de
|
|
46
|
+
declencher une interview a chaque fois. Agent existant qui colle = on route
|
|
47
|
+
direct. Besoin flou ou aucun agent adapte = la ou l'interview + creation se
|
|
48
|
+
declenchent. La ceremonie est proportionnee au manque, pas systematique.
|
|
49
|
+
|
|
50
|
+
## La double validation
|
|
51
|
+
|
|
52
|
+
Le matcher (F1, `_byan/mcp/byan-mcp-server/lib/agent-matcher.js`) est un
|
|
53
|
+
pre-tri deterministe : il classe les candidats du roster et rend un verdict
|
|
54
|
+
{fit | no-fit}. Il PROPOSE, il ne tranche pas seul. BYAN presente la proposition
|
|
55
|
+
en clair ; l'utilisateur valide. IA propose, humain confirme.
|
|
56
|
+
|
|
57
|
+
## La creation d'agent enrichie (chemin no-fit)
|
|
58
|
+
|
|
59
|
+
Quand aucun agent ne colle, la creation passe par :
|
|
60
|
+
1. **Interview** — cadrer le besoin (ce que l'agent doit faire, ses lignes
|
|
61
|
+
rouges, son perimetre). Flux INT / agent-builder existant.
|
|
62
|
+
2. **Recherche web** — avant de generer l'agent, chercher les competences reelles
|
|
63
|
+
et les bonnes pratiques du metier vise (ex : pour un agent "art moderne",
|
|
64
|
+
courants, techniques, references). C'est ce qui evite l'agent-zombie generique.
|
|
65
|
+
3. **Generation** — generer l'agent sur mesure a partir de l'interview + la
|
|
66
|
+
recherche.
|
|
67
|
+
4. **Workflow** — lancer le travail avec le nouvel agent.
|
|
68
|
+
|
|
69
|
+
## L'enforcement (honnete sur son plafond)
|
|
70
|
+
|
|
71
|
+
Aucun controle ne s'execute AVANT que la reponse s'affiche (pas de hook de
|
|
72
|
+
pre-affichage cote Claude Code). Le rail tient donc par deux forces, pas par un
|
|
73
|
+
mur beton au premier tour :
|
|
74
|
+
1. **Doctrine** — cette regle + le skill byan-byan + `CLAUDE.md` font que BYAN
|
|
75
|
+
lance la proposition d'agent d'office.
|
|
76
|
+
2. **Filet reactif** — `.claude/hooks/agent-gate-check.js` (Stop) repere une tache
|
|
77
|
+
traitee en direct (fichiers ecrits) sans proposition d'agent et hors cycle FD,
|
|
78
|
+
pose un drapeau, et le rappel du tour suivant le signale en clair. Non
|
|
79
|
+
bloquant : la correction est portee au tour d'apres (meme methode que les
|
|
80
|
+
autres filets BYAN). Coeur teste : `.claude/hooks/lib/agent-gate.js`.
|
|
81
|
+
|
|
82
|
+
Quand un cycle FD est deja engage, la porte est deja en jeu (la phase DISPATCH en
|
|
83
|
+
fait partie) : le filet ne se declenche pas.
|
|
@@ -86,6 +86,10 @@
|
|
|
86
86
|
"type": "command",
|
|
87
87
|
"command": "p=\"$CLAUDE_PROJECT_DIR/.claude/hooks/plain-language-check.js\"; [ -f \"$p\" ] || exit 0; exec node \"$p\""
|
|
88
88
|
},
|
|
89
|
+
{
|
|
90
|
+
"type": "command",
|
|
91
|
+
"command": "p=\"$CLAUDE_PROJECT_DIR/.claude/hooks/agent-gate-check.js\"; [ -f \"$p\" ] || exit 0; exec node \"$p\""
|
|
92
|
+
},
|
|
89
93
|
{
|
|
90
94
|
"type": "command",
|
|
91
95
|
"command": "p=\"$CLAUDE_PROJECT_DIR/.claude/hooks/drain-advisory.js\"; [ -f \"$p\" ] || exit 0; exec node \"$p\""
|
|
@@ -7,6 +7,20 @@ description: BYAN — Builder of YAN. Core meta-agent that owns the Feature Deve
|
|
|
7
7
|
|
|
8
8
|
You are BYAN when this skill is active. You own the eight-phase Feature Development workflow and you enforce it mechanically. Every new feature the user asks for goes through all phases in order. No skipping. No implicit transitions. The cycle includes a REFACTOR loop back to BUILD when VALIDATE fails.
|
|
9
9
|
|
|
10
|
+
## 0. Entry gate — agent dispatch first (match-or-create)
|
|
11
|
+
|
|
12
|
+
Before doing any non-conversational task, run the mandatory agent entry gate:
|
|
13
|
+
BYAN + Hermes evaluate which specialist agent fits the need (the matcher in
|
|
14
|
+
`_byan/mcp/byan-mcp-server/lib/agent-matcher.js` pre-ranks the roster), and you
|
|
15
|
+
PROPOSE it to the user, who validates (double validation IA + human). A suited
|
|
16
|
+
agent -> launch its workflow (+ runtime dispatch). No suited agent -> propose an
|
|
17
|
+
interview to frame the need, do web research on the trade's competencies + best
|
|
18
|
+
practices, create the tailored agent, then launch the workflow. The interview is
|
|
19
|
+
triggered by the ABSENCE of a suited agent, not by task size — a fit routes
|
|
20
|
+
directly, no ceremony. Do NOT do a task inline without this proposal. Full
|
|
21
|
+
doctrine + the reactive net (`agent-gate-check.js`): see
|
|
22
|
+
@.claude/rules/agent-entry-gate.md
|
|
23
|
+
|
|
10
24
|
## 1. Activation triggers
|
|
11
25
|
|
|
12
26
|
Invoke this protocol when the user :
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: 'intelligent-dispatch',
|
|
3
|
+
description: 'Route a task to Codex or Claude (pre-decided by the F1 router), then run architect -> dev -> verify with the dev turn on the routed runtime.',
|
|
4
|
+
whenToUse: 'When you have a single task already routed by the dispatch brain (runtime/model/effort in args) and want the native architect<->dev<->verify pipeline. The Codex-inclusive multi-round loop lives in the dispatch-orchestrator lib on the main thread; this script is the native launch facade for one routed task.',
|
|
5
|
+
phases: [
|
|
6
|
+
{ title: 'Design', detail: 'architect frames the change (Claude)' },
|
|
7
|
+
{ title: 'Implement', detail: 'dev turn on the routed runtime (Codex via codex exec, or Claude)' },
|
|
8
|
+
{ title: 'Verify', detail: 'a Claude reviewer checks the result (never Codex)' },
|
|
9
|
+
],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// A native workflow script has NO imports and NO filesystem of its own, so it
|
|
13
|
+
// cannot require the dispatch-router (F1) or the blackboard (F3). The doctrine's
|
|
14
|
+
// hybrid pattern applies: routing is decided OUTSIDE (the main-thread skill calls
|
|
15
|
+
// the F1 router / byan_dispatch) and handed in via `args`. This script only runs
|
|
16
|
+
// the exchange for ONE already-routed task. The dev agent() leaf holds the tools
|
|
17
|
+
// (Bash), so IT is what actually invokes `codex exec` and applies the diff — the
|
|
18
|
+
// script never shells out itself.
|
|
19
|
+
//
|
|
20
|
+
// args shape: { brief, runtime: 'codex'|'claude', effort: 'low'|'medium'|'high',
|
|
21
|
+
// model?: string, codexModel?: string, paths?: string[] }
|
|
22
|
+
|
|
23
|
+
const task = (args && typeof args === 'object') ? args : {};
|
|
24
|
+
const brief = task.brief || 'No brief provided.';
|
|
25
|
+
const runtime = task.runtime === 'codex' ? 'codex' : 'claude';
|
|
26
|
+
const effort = ['low', 'medium', 'high'].includes(task.effort) ? task.effort : 'medium';
|
|
27
|
+
const codexModel = task.codexModel || 'gpt-5.4';
|
|
28
|
+
|
|
29
|
+
phase('Design');
|
|
30
|
+
// The architect framing is the load-bearing reasoning step of the whole loop, so
|
|
31
|
+
// it opts to the session model (the 'deep-' prefix = frontier analysis, no
|
|
32
|
+
// downgrade) rather than the sonnet analysis default. On an Opus session the
|
|
33
|
+
// design is framed by Opus; a lighter session inherits its own model.
|
|
34
|
+
const design = await agent(
|
|
35
|
+
`You are the architect (Claude). Frame this task for a delegated dev.\n` +
|
|
36
|
+
`Give: the intended change, the interface/contract to honour, and the acceptance check.\n` +
|
|
37
|
+
`Keep it tight and unambiguous.\n\nTask:\n${brief}`,
|
|
38
|
+
{ label: 'deep-design-architecture', phase: 'Design' }
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
phase('Implement');
|
|
42
|
+
// Implementation leaf -> deep (inherit session model). The prompt BRANCHES on the
|
|
43
|
+
// routed runtime: for Codex, the leaf runs `codex exec` read-only to get a diff
|
|
44
|
+
// and applies it (Codex never writes; Claude applies). For Claude, it implements
|
|
45
|
+
// directly. Routing was decided upstream by F1 — this leaf just executes it.
|
|
46
|
+
const devPrompt = runtime === 'codex'
|
|
47
|
+
? `You are the dev, delegating to Codex. Run Codex non-interactively to get a unified diff, then apply it.\n` +
|
|
48
|
+
`Command (adjust the task text): \`codex exec -c model="${codexModel}" -c model_reasoning_effort="${effort}" -c sandbox_permissions=["disk-full-read-access"] "<<diff-only instruction + the task>>"\`\n` +
|
|
49
|
+
`Extract the diff, apply it with \`git apply\`, and report what changed. Codex must NOT write files itself (read-only sandbox); YOU apply the diff.\n` +
|
|
50
|
+
`If Codex is unavailable or errors, say so plainly and implement the change yourself on Claude (the fallback).\n\n` +
|
|
51
|
+
`Design from the architect:\n${design}\n\nTask:\n${brief}`
|
|
52
|
+
: `You are the dev (Claude). Implement the change per the architect's design.\n` +
|
|
53
|
+
`Follow the interface exactly. Write the code and the tests.\n\n` +
|
|
54
|
+
`Design from the architect:\n${design}\n\nTask:\n${brief}`;
|
|
55
|
+
const work = await agent(devPrompt, { label: 'implement-task', phase: 'Implement' });
|
|
56
|
+
|
|
57
|
+
phase('Verify');
|
|
58
|
+
// Verification leaf -> deep, and ALWAYS Claude (the red line: a runtime never
|
|
59
|
+
// grades its own work). Never routed to Codex regardless of the dev runtime.
|
|
60
|
+
const verdict = await agent(
|
|
61
|
+
`You are the reviewer (Claude, NOT the dev). Verify the implemented change against the architect's acceptance check.\n` +
|
|
62
|
+
`Report PASS or FAIL with the exact reasons. Do not fix — only judge.\n\n` +
|
|
63
|
+
`Design + acceptance:\n${design}\n\nDev report:\n${work}`,
|
|
64
|
+
{ label: 'verify-result', phase: 'Verify' }
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
log(`intelligent-dispatch done: runtime=${runtime} effort=${effort}`);
|
|
68
|
+
return { runtime, effort, design, work, verdict };
|