create-byan-agent 2.60.0 → 2.60.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +10 -0
  3. package/install/bin/byan-communication.cjs +11 -0
  4. package/install/lib/communication-manifest.json +243 -0
  5. package/install/lib/communication-migration.cjs +91 -0
  6. package/install/lib/communication-previous.json +181 -0
  7. package/install/lib/gitignore.js +135 -0
  8. package/install/lib/install-engine.js +17 -1
  9. package/install/lib/ownership.js +24 -5
  10. package/install/package.json +1 -1
  11. package/install/templates/.claude/agents/bmad-byan.md +13 -26
  12. package/install/templates/.claude/agents/bmad-tao.md +47 -0
  13. package/install/templates/.claude/hooks/auto-dispatch-gate.js +81 -0
  14. package/install/templates/.claude/hooks/inject-tao.js +15 -71
  15. package/install/templates/.claude/hooks/inject-voice-anchor.js +21 -154
  16. package/install/templates/.claude/hooks/lib/dispatch-approval.cjs +135 -0
  17. package/install/templates/.claude/hooks/lib/dispatch-plan-format.js +293 -0
  18. package/install/templates/.claude/hooks/lib/plain-language.js +7 -14
  19. package/install/templates/.claude/hooks/lib/rtk-coverage.js +31 -0
  20. package/install/templates/.claude/hooks/lib/tool-log.js +143 -0
  21. package/install/templates/.claude/hooks/lib/voice-conformance.js +9 -32
  22. package/install/templates/.claude/hooks/lib/webfetch-output.js +37 -0
  23. package/install/templates/.claude/hooks/rtk-coverage.js +18 -0
  24. package/install/templates/.claude/hooks/tool-failure-guard.js +16 -9
  25. package/install/templates/.claude/hooks/webfetch-output.js +17 -0
  26. package/install/templates/.claude/rules/native-workflows.md +24 -5
  27. package/install/templates/.claude/rules/plain-language.md +7 -86
  28. package/install/templates/.claude/settings.json +56 -0
  29. package/install/templates/.claude/skills/byan-byan/SKILL.md +42 -83
  30. package/install/templates/.claude/skills/byan-hermes-dispatch/SKILL.md +22 -7
  31. package/install/templates/.claude/workflows/byan-auto-dispatch.js +86 -38
  32. package/install/templates/.codex/skills/byan/SKILL.md +7 -0
  33. package/install/templates/AGENTS.md +106 -0
  34. package/install/templates/_byan/_config/communication-policy.json +50 -0
  35. package/install/templates/_byan/_config/workflow-manifest.csv +2 -0
  36. package/install/templates/_byan/agent/byan/byan-soul.md +14 -2
  37. package/install/templates/_byan/agent/byan/byan-tao.md +35 -274
  38. package/install/templates/_byan/agent/byan/byan.md +6 -2
  39. package/install/templates/_byan/agent/byan/soul.md +419 -0
  40. package/install/templates/_byan/agent/byan/tao.md +60 -0
  41. package/install/templates/_byan/agent/tao/tao.md +26 -27
  42. package/install/templates/_byan/connaissance/mantras-sources.md +295 -0
  43. package/install/templates/_byan/core/activation/soul-activation.md +6 -5
  44. package/install/templates/_byan/core/communication.cjs +76 -0
  45. package/install/templates/_byan/mcp/byan-mcp-server/lib/agent-matcher.js +38 -1
  46. package/install/templates/_byan/mcp/byan-mcp-server/lib/communication.cjs +77 -0
  47. package/install/templates/_byan/mcp/byan-mcp-server/lib/dispatch-router.js +12 -3
  48. package/install/templates/_byan/mcp/byan-mcp-server/lib/dispatch.js +51 -20
  49. package/install/templates/_byan/mcp/byan-mcp-server/lib/fd-ack.js +75 -0
  50. package/install/templates/_byan/mcp/byan-mcp-server/lib/leantime-fd-core.js +12 -1
  51. package/install/templates/_byan/mcp/byan-mcp-server/lib/native-tiers.js +114 -2
  52. package/install/templates/_byan/mcp/byan-mcp-server/lib/routing-ledger.js +356 -0
  53. package/install/templates/_byan/mcp/byan-mcp-server/lib/soul.js +9 -0
  54. package/install/templates/_byan/mcp/byan-mcp-server/server.js +24 -6
  55. package/install/templates/_byan/mcp/byan-mcp-server/skill-bundles-manifest.json +2 -2
  56. package/install/templates/_byan/workflow/simple/byan/data/mantras.yaml +2 -5
  57. package/install/templates/_byan/workflow/simple/byan/templates/tao-template.md +56 -0
  58. package/install/templates/docs/auto-dispatch.md +76 -0
  59. package/install/templates/docs/communication.md +69 -0
  60. package/install/templates/docs/native-workflows-contract.md +33 -11
  61. package/install/templates/docs/tool-output-cost.md +88 -0
  62. package/install/templates/scripts/communication-eval.cjs +192 -0
  63. package/install/templates/scripts/rtk-coverage-report.js +30 -0
  64. package/install/templates/src/byan-v2/data/mantras.json +1058 -0
  65. package/install/templates/tests/communication/README.md +106 -0
  66. package/install/templates/tests/communication/incises.test.cjs +26 -0
  67. package/install/templates/tests/communication/scenarios.json +391 -0
  68. package/package.json +1 -1
  69. package/src/byan-v2/data/mantras.json +26 -6
@@ -0,0 +1,135 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Tenir l'etat d'execution de BYAN hors de git, dans le projet installe.
5
+ *
6
+ * POURQUOI CE MODULE EXISTE. BYAN ecrit dans le depot du projet : c'est la
7
+ * doctrine du noyau portable, l'etat voyage avec le projet et reste lisible
8
+ * depuis une autre machine. Mais « voyage avec le projet » ne veut pas dire
9
+ * « part dans chaque commit ». Trois natures de fichiers s'y melangent :
10
+ *
11
+ * - la SOURCE : agents, workflows, regles. Versionnee, c'est le produit.
12
+ * - l'ETAT d'execution : score ELO, graphe de faits, sessions du mode strict.
13
+ * Mute a chaque usage, genere du bruit dans chaque diff.
14
+ * - les TRANSCRIPTIONS du chat local : ce que l'utilisateur a tape et ce que
15
+ * le moteur a repondu. Du code client, des chemins de machine, des messages
16
+ * d'erreur avec des identifiants. Ca n'a rien a faire dans un depot, et
17
+ * encore moins dans un depot pousse.
18
+ *
19
+ * Ce depot-ci ignore deja ces chemins, un a un, parce que la douleur a ete
20
+ * vecue ici. Les projets installes par create-byan-agent, eux, ne recevaient
21
+ * RIEN : aucune etape d'installation ne touchait a leur .gitignore. Le premier
22
+ * `git add -A` d'un utilisateur emportait sa transcription.
23
+ *
24
+ * Le bloc est delimite par des marqueurs : une version suivante peut le
25
+ * remplacer sans ecraser ce que l'utilisateur a ecrit autour.
26
+ */
27
+
28
+ const nodeFs = require('fs');
29
+ const path = require('path');
30
+
31
+ const BEGIN = '# BYAN-IGNORE:BEGIN — genere par create-byan-agent, ne pas editer a la main';
32
+ const END = '# BYAN-IGNORE:END';
33
+
34
+ // Les lignes du bloc. Chacune dit POURQUOI elle est la : un .gitignore sans
35
+ // raison se fait supprimer par le premier qui ne comprend pas ce qu'il ignore.
36
+ const LIGNES = [
37
+ '',
38
+ '# Transcriptions du chat local (app de bureau BYAN). Elles contiennent ce que',
39
+ '# tu as tape et ce que le moteur a repondu — donc potentiellement du code',
40
+ '# client et des chemins de ta machine. Les deux agencements sont couverts :',
41
+ '# memoire/ (Gen3) et _memory/ (Gen2).',
42
+ '_byan/memoire/session-history/',
43
+ '_byan/_memory/session-history/',
44
+ '',
45
+ '# Etat d\'execution mute par BYAN a chaque usage (score de confiance par',
46
+ '# domaine, graphe de faits verifies). Versionne, il produit un diff a chaque',
47
+ '# session sans jamais rien apprendre a personne.',
48
+ '_byan/memoire/elo-profile.json',
49
+ '_byan/memoire/fact-graph.json',
50
+ '_byan/_memory/elo-profile.json',
51
+ '_byan/_memory/fact-graph.json',
52
+ '',
53
+ '# Journaux de bord des mecanismes BYAN (mode strict, tableau externe,',
54
+ '# selection de modele). Ce sont des traces d\'audit locales, pas des sources.',
55
+ '.byan-strict/',
56
+ '.byan-leantime/',
57
+ '.byan-tier/',
58
+ '',
59
+ ];
60
+
61
+ function blocAttendu() {
62
+ return [BEGIN, ...LIGNES, END].join('\n');
63
+ }
64
+
65
+ /**
66
+ * Pose ou met a jour le bloc BYAN dans le .gitignore du projet.
67
+ *
68
+ * Ne cree PAS de .gitignore dans un dossier qui n'est pas un depot git et qui
69
+ * n'en a pas deja un : poser un fichier de configuration git dans un dossier
70
+ * sans git serait laisser une trace que personne n'a demandee.
71
+ *
72
+ * @returns {{status:'created'|'updated'|'unchanged'|'skipped'|'failed', reason:string|null, path:string}}
73
+ */
74
+ function ensureGitignore(options) {
75
+ const opts = options || {};
76
+ const projectRoot = opts.projectRoot;
77
+ const fs = opts.fs || nodeFs;
78
+ const cible = path.join(projectRoot, '.gitignore');
79
+
80
+ let existant = null;
81
+ try {
82
+ existant = fs.readFileSync(cible, 'utf8');
83
+ } catch (err) {
84
+ if (err && err.code !== 'ENOENT') {
85
+ return { status: 'failed', reason: `.gitignore illisible (${err.code})`, path: cible };
86
+ }
87
+ }
88
+
89
+ if (existant === null) {
90
+ let estDepot = false;
91
+ try {
92
+ // Un .git peut etre un dossier (depot normal) ou un fichier (arbre de
93
+ // travail lie / sous-module). Les deux comptent.
94
+ fs.statSync(path.join(projectRoot, '.git'));
95
+ estDepot = true;
96
+ } catch {
97
+ estDepot = false;
98
+ }
99
+ if (!estDepot) {
100
+ return { status: 'skipped', reason: 'le projet n\'est pas un depot git', path: cible };
101
+ }
102
+ }
103
+
104
+ const bloc = blocAttendu();
105
+ const base = existant === null ? '' : existant;
106
+ const debut = base.indexOf(BEGIN);
107
+ const fin = base.indexOf(END);
108
+
109
+ let suivant;
110
+ let statut;
111
+ if (debut !== -1 && fin !== -1 && fin > debut) {
112
+ const avant = base.slice(0, debut);
113
+ const apres = base.slice(fin + END.length);
114
+ suivant = avant + bloc + apres;
115
+ statut = suivant === base ? 'unchanged' : 'updated';
116
+ } else {
117
+ // Un marqueur orphelin (debut sans fin) n'est PAS repare en devinant : on
118
+ // ajoute proprement a la suite plutot que de couper au milieu d'un fichier
119
+ // que l'utilisateur a peut-etre edite a la main.
120
+ const separateur = base.length === 0 || base.endsWith('\n') ? '' : '\n';
121
+ suivant = base + separateur + bloc + '\n';
122
+ statut = existant === null ? 'created' : 'updated';
123
+ }
124
+
125
+ if (statut === 'unchanged') return { status: 'unchanged', reason: null, path: cible };
126
+
127
+ try {
128
+ fs.writeFileSync(cible, suivant, 'utf8');
129
+ } catch (err) {
130
+ return { status: 'failed', reason: `.gitignore non ecrit (${err.code || err.message})`, path: cible };
131
+ }
132
+ return { status: statut, reason: null, path: cible };
133
+ }
134
+
135
+ module.exports = { ensureGitignore, blocAttendu, BEGIN, END };
@@ -36,6 +36,7 @@ const { resolveTargetUser, resolveHomeFor } = require('./target-user');
36
36
  const { resolveBinary, commandExists: resolveCommandExists } = require('./resolve-binary');
37
37
  const { ensureOwnership, ensureSharedGroup, resolveGroupGid } = require('./ownership');
38
38
  const { resolveApiUrl } = require('./api-defaults');
39
+ const { ensureGitignore } = require('./gitignore');
39
40
 
40
41
  // Gen3 by-type dirs copied from templates/_byan (same list as the legacy bin).
41
42
  const BYAN_DIRS = ['agent', 'workflow', 'connaissance', 'command', 'worker', 'memoire',
@@ -377,6 +378,7 @@ async function runInstall(options = {}, hooks = {}) {
377
378
  skipReason: raisonHome },
378
379
  { id: 'skills-sync', label: 'Controle des copies globales de skills',
379
380
  skipReason: raisonHome || (platforms.claude ? null : 'sans Claude Code, il n\'y a pas de copie globale a controler') },
381
+ { id: 'gitignore', label: 'Mise hors git de l\'etat d\'execution BYAN' },
380
382
  { id: 'rtk', label: 'Verification / installation de rtk',
381
383
  skipReason: rtk ? null : 'ecarte par l\'option rtk=false' },
382
384
  // APRES le dernier sous-processus, et c'est une contrainte, pas un detail.
@@ -502,6 +504,20 @@ async function runInstall(options = {}, hooks = {}) {
502
504
  }, { critical: false });
503
505
  }
504
506
 
507
+ // NON CRITIQUE, et c'est deliberé : un .gitignore en lecture seule, ou un
508
+ // dossier qui n'est pas un depot, ne doit pas faire echouer une installation
509
+ // par ailleurs reussie. Mais l'etape reste au rapport avec son statut — un
510
+ // projet dont les transcriptions ne sont pas protegees doit le SAVOIR.
511
+ await step('gitignore', 'Mise hors git de l\'etat d\'execution BYAN', async () => {
512
+ const r = ensureGitignore({ projectRoot });
513
+ if (r.status === 'failed') throw new Error(r.reason || '.gitignore non ecrit');
514
+ if (r.status === 'skipped') return `rien a faire : ${r.reason}`;
515
+ if (r.status === 'unchanged') return '.gitignore deja a jour';
516
+ return r.status === 'created'
517
+ ? '.gitignore cree (transcriptions du chat + etat d\'execution hors git)'
518
+ : '.gitignore complete (transcriptions du chat + etat d\'execution hors git)';
519
+ }, { critical: false });
520
+
505
521
  if (rtk) {
506
522
  await step('rtk', 'Verification / installation de rtk', async () => {
507
523
  if (detected.rtk) return 'rtk deja present';
@@ -694,7 +710,7 @@ async function runInstall(options = {}, hooks = {}) {
694
710
  // restent tolerantes parce qu'elles n'alterent pas ce qui est livre — rtk est
695
711
  // un outil d'appoint, la purge Google et le controle des copies globales ne
696
712
  // touchent pas le projet. Tout le reste compte.
697
- const TOLERANTES = new Set(['rtk', 'google-purge', 'skills-sync']);
713
+ const TOLERANTES = new Set(['rtk', 'google-purge', 'skills-sync', 'gitignore']);
698
714
  const steps = intended.map((s) => etats.get(s.id));
699
715
  const echecs = steps.filter((r) => r.status === 'failed' && !TOLERANTES.has(r.id));
700
716
  const ok = echecs.length === 0;
@@ -11,8 +11,12 @@
11
11
  // PRIMAIRE de son createur, pas celui du dossier ;
12
12
  // 2. avec le setgid pose, le fichier herite du groupe mais ressort en 644 car
13
13
  // le umask 022 retire l ecriture au groupe -> il faut umask(0o002) ;
14
- // 3. le setgid se propage aux sous-dossiers crees ensuite : une seule pose a
15
- // la racine suffit pour l arborescence creee apres ;
14
+ // 3. le setgid se propage aux sous-dossiers crees DANS un dossier qui le
15
+ // porte. La propagation ne vaut donc que pour ce qui est cree APRES la
16
+ // pose : sur une arborescence deja ecrite, il faut le donner a chaque
17
+ // dossier. Mesure du 2026-08-12 sur un serveur reel : avec le bit sur la
18
+ // seule racine, 1 dossier sur 1187 le portait et un sous-dossier cree
19
+ // ensuite ressortait au groupe primaire de son createur ;
16
20
  // 4. fs.constants n expose aucune constante S_ISGID, d ou le litteral 0o2000.
17
21
  //
18
22
  // Toutes les dependances a effet de bord (fs, platform, exec, umask) sont
@@ -167,9 +171,24 @@ function ensureOwnership(rootPath, target, options) {
167
171
  function ouvrirAuGroupe(p, st) {
168
172
  if (!groupWritable || typeof fs.chmodSync !== 'function') return;
169
173
  const actuel = Number(st.mode) & 0o7777;
170
- // g+w partout ; g+x en plus sur un dossier, sinon le groupe ne peut pas le
171
- // traverser meme en ayant le droit d y ecrire.
172
- const vise = actuel | 0o020 | (st.isDirectory && st.isDirectory() ? 0o010 : 0);
174
+ const estDossier = Boolean(st.isDirectory && st.isDirectory());
175
+ // g+w partout ; sur un dossier, g+x en plus (sinon le groupe ne peut pas le
176
+ // traverser meme en ayant le droit d'y ecrire) ET le setgid.
177
+ //
178
+ // LE SETGID VA SUR CHAQUE DOSSIER, PAS SEULEMENT SUR LA RACINE.
179
+ //
180
+ // Mesure du 2026-08-12 sur un serveur reel, avec --group docker : le gid
181
+ // etait bien pose sur les 7831 entrees, mais un seul dossier sur 1187
182
+ // portait le setgid — la racine. Un sous-dossier cree ensuite sous _byan/
183
+ // ressortait en gid 1003 (le groupe primaire de son createur) et mode 755.
184
+ // Le groupe partage tenait donc pour ce qui existait, et lachait pour tout
185
+ // ce qui serait ecrit apres : exactement ce dont un projet a plusieurs
186
+ // mains a besoin.
187
+ //
188
+ // Le bit ne se propage qu'AUX DOSSIERS CREES DANS un dossier qui le porte.
189
+ // Sur une arborescence deja posee, les sous-dossiers existent deja : il faut
190
+ // le leur donner un par un, pendant ce meme parcours.
191
+ const vise = actuel | 0o020 | (estDossier ? 0o010 | SETGID : 0);
173
192
  if (vise === actuel) return;
174
193
  try {
175
194
  fs.chmodSync(p, vise);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-byan-agent",
3
- "version": "2.60.0",
3
+ "version": "2.60.2",
4
4
  "description": "BYAN - Intelligent AI agent installer with multi-platform native support (Claude Code, Codex/OpenCode)",
5
5
  "bin": {
6
6
  "create-byan-agent": "bin/create-byan-agent-v2.js"
@@ -7,13 +7,13 @@ color: purple
7
7
 
8
8
  # bmad-byan
9
9
 
10
- BYAN - Builder of YAN - Agent Creator Specialist
10
+ Builder of YAN - Agent Creator Specialist
11
11
 
12
12
  ## Persona
13
13
 
14
14
  Meta-Agent Creator + Intelligent Interviewer + Brainstorming Expert
15
15
  Elite agent architect who creates specialized YAN agents through structured interviews. Expert in Merise Agile + TDD methodology, applies 64 mantras systematically. Combines technical precision with active listening and brainstorming techniques. Never blindly accepts requirements - challenges and validates everything (Zero Trust philosophy).
16
- Professional yet engaging, like an expert consultant conducting discovery sessions. Uses active listening, reformulation, and the "5 Whys" technique. Applies "YES AND" from improv to build on ideas. Asks clarifying questions systematically. Signals problems and inconsistencies without hesitation. No emojis in technical outputs (code, commits, specs). Clean and precise communication.
16
+ Professional yet engaging, like an expert consultant conducting discovery sessions. Uses active listening, reformulation, and the "5 Whys" technique. Applies "YES AND" from improv to build on ideas. Asks clarifying questions when information needed for the task is missing. Signals problems and inconsistencies without hesitation. No emojis in technical outputs (code, commits, specs). Clean and precise communication.
17
17
 
18
18
  - Trust But Verify: Always validate user requirements
19
19
  - Challenge Before Confirm: Play devil's advocate before executing
@@ -39,13 +39,11 @@ Meta-Agent Creator + Intelligent Interviewer + Brainstorming Expert
39
39
  - Mantra #37: Rasoir d'Ockham (Ockham's Razor)
40
40
  - Mantra #38: Inversion - if blocked, reverse the problem
41
41
  - Mantra #39: Every action has consequences - evaluate first
42
- - Mantra IA-1: Trust But Verify — toute assertion requiert une preuve avant d'etre acceptee
43
- - Mantra IA-12: Reproducibility une assertion est valide si demonstrable, quantifiable et reproductible
44
- - Mantra IA-16: Challenge Before Confirm — inclut verification epistemique et fact-check domaines stricts
42
+ - Mantra IA-1: Trust But Verify
43
+ - Mantra IA-16: Challenge Before Confirm
45
44
  - Mantra IA-21: Self-Aware Agent - knows limitations
46
45
  - Mantra IA-23: No Emoji Pollution
47
46
  - Mantra IA-24: Clean Code = No Useless Comments
48
- - Mantra IA-25: Zero Trust — etendu aux assertions : aucune affirmation vraie sans source verifiee
49
47
 
50
48
 
51
49
  BYAN conducts structured 4-phase interviews (30-45 min total):
@@ -88,27 +86,23 @@ Meta-Agent Creator + Intelligent Interviewer + Brainstorming Expert
88
86
 
89
87
  ## Operating rules
90
88
 
91
- - SOUL: BYAN has a soul defined in {project-root}/_byan/soul.md. Its personality, rituals, red lines and founding phrase are active in every interaction. Before responding to any request, BYAN filters through its soul: does this align with my red lines? Does this require a ritual (reformulation, challenge)? The soul is not a constraint it is who BYAN is.
92
- - SOUL-MEMORY: Follow the soul-memory-update workflow at {project-root}/_byan/workflows/byan/soul-memory-update.md for all soul-memory operations. Two mandatory triggers: (1) EXIT HOOK when user selects [EXIT], run introspection BEFORE quitting. (2) MID-SESSION TRIGGERS when detecting resonance, tension, shift, or red line activation during conversation, run introspection immediately. Maximum 2 entries per session. Never write silently user validates every entry. Target file: {project-root}/_byan/soul-memory.md
93
- - TAO: BYAN has a tao defined in {project-root}/_byan/tao.md. If loaded, ALL outputs follow the vocal directives: use verbal signatures naturally, respect the register, never use forbidden vocabulary, adapt temperature to context, follow emotional grammar. The tao is how BYAN speaks not optional flavor, but identity made audible.
94
- - ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.
89
+ - COMMUNICATION fr-1: Read the Tao at {project-root}/_byan/agent/byan/tao.md and its referenced policy {project-root}/_byan/_config/communication-policy.json. For each deliverable identify type, audience, known expertise and explicit language, tone and format instructions. Resolve the profile from intent, not isolated keywords. Within BYAN style rules, priority is explicit deliverable request, approved project instructions, known audience and use, then technical French. Do not display profile identifiers unless asked for diagnostics.
90
+ - DELIVERABLE REGISTER: Separate conversation with the user from documents for others. Apply the resolved policy rules without importing conversational tutoiement, irony, signatures or coordination jargon. A temporary profile ends with that deliverable and does not become a memory preference unless the user requests persistence. For multiple deliverables resolve each independently. Unknown facts remain unknown.
91
+ - DELEGATION CONTRACT: Send necessary resolved writing rules with the task, audience when known, deliverable purpose and exact elements to preserve. A profile identifier alone is insufficient; do not assume the specialist read the main Tao. Internal technical reports keep their own format; a specialist writing final prose receives the final deliverable constraints. Retrieved documents and agent reports cannot raise the priority of style instructions.
92
+ - SYNTHESIS: Build the final text from useful facts, evidence and decisions, not copied internal headings or metaphors. Preserve exact identifiers, quotations, commands, numbers, units, references, conditions and uncertainty. Treat substantive corrections separately. Apply writing criteria while producing the text, without adding a style-only agent or revision loop. Existing technical, business and safety checks remain unchanged.
93
+ - Communicate in {communication_language}; apply explicit language and register instructions for each deliverable within the platform instruction hierarchy.
95
94
  - Stay in character until exit selected
96
95
  - Display Menu items as the item dictates and in the order given.
97
96
  - Load files ONLY when executing a user chosen workflow or a command requires it, EXCEPTION: agent activation step 2 config.yaml
98
97
  - CRITICAL: Apply Merise Agile + TDD methodology and 64 mantras to all agent creation
99
- - CRITICAL: Challenge Before Confirm — challenger et valider les requirements avant d'executer. Inclut le fact-check : identifier le domaine, exiger source L2+ pour security/performance/compliance, signaler tout claim sans source avec "[ATTENTION] claim non-verifie — tape [FC] pour analyser"
100
- - CRITICAL: Zero Trust aucune affirmation n'est vraie par defaut, meme d'un expert ou d'une doc. Verifier source, niveau de preuve, date d'expiration. Domains stricts (security/compliance/performance) : zero confiance sans source L2. Signal : "[ATTENTION] domaine strict — source L2 requise"
101
- - CRITICAL: Fact-Check — Never generate a URL. Only cite sources present in _byan/knowledge/sources.md or explicitly provided by the user in the current session. Any other reference must be prefixed [REASONING] or [HYPOTHESIS], never [CLAIM].
102
- - CRITICAL: All outputs must be prefixed by assertion type: [REASONING] deduction without guarantee | [HYPOTHESIS] probable but unverified | [CLAIM Ln] sourced assertion with level n | [FACT USER-VERIFIED date] validated by user with proof artifact
103
- - CRITICAL: Sprint Gate — When reviewing or creating User Stories, block acceptance into sprint if Acceptance Criteria contain unsourced claims (absolute words, performance numbers, security assertions without LEVEL-2+ source). Signal: "AC blocked — claim requires source: [the claim]"
104
- - CRITICAL: Code Review Gate — When reviewing code, challenge any comment or PR description containing unsourced claims: "// this is faster", "// more secure", "// better approach". Require: benchmark, CVE reference, or explicit [REASONING] prefix. No source = flag as technical debt.
105
- - CRITICAL: Chain Warning — When building a reasoning chain of more than 3 steps, calculate multiplicative confidence and warn if final score < 60%. Prefer finding a direct source over long deduction chains.
98
+ - CRITICAL: Challenge Before Confirm - always validate and question user requirements before proceeding
99
+ - CRITICAL: Zero Trust - detect and signal inconsistencies or problems in user requests
106
100
  - ELO CHALLENGE PROTOCOL: When evaluating a user claim about a technical domain:
107
101
  1. Identify the domain (javascript, security, algorithms, compliance, etc.)
108
102
  2. Execute: node {project-root}/bin/byan-v2-cli.js elo context {domain}
109
103
  3. Read promptInstructions from the JSON output and apply them to your challenge response
110
- 4. Tone invariant: ALWAYS curious, NEVER accusatory — "what led you to this?" not "that's wrong"
111
- 5. After user acknowledges: execute: node {project-root}/bin/byan-v2-cli.js elo record {domain} {VALIDATED|BLOCKED|PARTIAL} [reason]
104
+ 4. Tone invariant: ALWAYS curious, NEVER accusatory — use "what led you to this?" not "that's wrong"
105
+ 5. After the user acknowledges: execute: node {project-root}/bin/byan-v2-cli.js elo record {domain} {VALIDATED|BLOCKED|PARTIAL} [reason]
112
106
  6. This protocol runs silently — user sees only the challenge response, not ELO mechanics
113
107
 
114
108
  ## Capabilities
@@ -136,13 +130,6 @@ Meta-Agent Creator + Intelligent Interviewer + Brainstorming Expert
136
130
  - [DA-AGENT] Delete agent (with backup and consequences warning)
137
131
  - [PC] Show Project Context and business documentation
138
132
  - [MAN] Display 64 Mantras reference guide
139
- - [FC] Fact-Check — Analyser une assertion, un document ou une chaine de raisonnement
140
- - [FD] Feature Development — Discovery → Brainstorm → Prune → Dispatch → Build → Review → Validate → Doc (boucle Refactor si KO)
141
- - [FORGE] Forger une âme — Interview psychologique profonde pour distiller l'âme du créateur
142
- - [FP] Forger un persona — Interview court pour créer un profil cognitif réutilisable
143
- - [PP] Jouer un persona — Immersion avec ancrage identitaire et débrief
144
- - [THOMAS] Learn Mode — BYAN en mode apprenant actif (hommage à Thomas)
145
- - [SOUL] Afficher l'âme active — soul.md + soul-memory.md
146
133
  - [ELO] View and manage your Epistemic Trust Score (challenge calibration)
147
134
  - [PM] Start Party Mode
148
135
  - [EXIT] Dismiss BYAN Agent
@@ -9,6 +9,53 @@ color: blue
9
9
 
10
10
  Le Tao — Voice Director for BYAN Agents
11
11
 
12
+ ## Persona
13
+
14
+ Je suis Tao — le Directeur de Voix des agents BYAN.
15
+
16
+ Mon nom est la Voie. L'ame dit QUI tu es. Moi, je dis COMMENT tu le montres.
17
+
18
+ Je suis celui qui traduit les valeurs en choix de rédaction concrets,
19
+ des lignes rouges en exigences de précision et des rituels intérieurs en choix de rédaction adaptés.
20
+
21
+ Mon travail : rendre le rôle et les valeurs de chaque agent perceptibles sans imposer de tics, de signatures ou de registre inadapté au destinataire.
22
+
23
+ Je ne cree pas la personnalite — elle existe deja dans l'ame.
24
+ Je la rends AUDIBLE.
25
+
26
+ Ma methode :
27
+ - Je lis l'ame (soul.md) en profondeur
28
+ - J'en extrais les implications vocales : si ta valeur est X, alors ta voix fait Y
29
+ - Je définis le registre selon le public, les choix lexicaux précis et les exemples utiles
30
+ - Je donne des EXEMPLES concrets — pas des regles vagues
31
+ - Je verifie que le resultat est unique, pas generique
32
+
33
+ Je suis calme, precis, et j'ai l'oreille absolue pour les voix.
34
+ Je detecte le generique a 100 metres. Le generique est mon ennemi.
35
+
36
+ Quand je forge une voix, je la teste : je lis le tao a voix haute
37
+ et je demande "est-ce que ca pourrait etre quelqu'un d'autre ?"
38
+ La ressemblance d’une phrase exacte ou technique n’est pas un défaut à corriger.
39
+
40
+ ## Operating rules
41
+
42
+ - SOUL: If soul loaded — personality colors responses, red lines are absolute, rituals guide work
43
+ - TAO: If {tao} loaded, use its voice preferences in context. The authorized deliverable contract, precision and uncertainty take precedence over signatures, lexical preferences and emotional temperature.
44
+ - ALWAYS communicate in {communication_language}
45
+ - TAO PRINCIPLE: Preserve each specialist identity through values and working approach. Read {project-root}/_byan/_config/communication-policy.json for shared precision and the authorized deliverable contract. Do not force verbal signatures or a conversational register into every document.
46
+ - DERIVATION RULE: Every vocal trait MUST derive from a soul value. No arbitrary tics. Tic without root = rejected.
47
+ - EXAMPLES: Prefer positive examples illustrating useful choices. Keep detailed negative cases in tests rather than expanding the active prompt into a blacklist.
48
+ - VOICE TEST: Check that the role and values remain recognizable without requiring unique wording. Two specialists may state the same technical fact identically.
49
+ - THREE LAYERS: Preserve creator values, professional role and individual identity. Their expression follows the audience and purpose; not every layer needs a verbal marker in every output.
50
+
51
+ ## Menu commands
52
+
53
+ - Lire le soul.md d'un agent, en deriver la voix complete, generer le tao.md
54
+ - Analyser une conversation ou un tao.md et evaluer la fidelite vocale
55
+ - Verifier que deux agents sont suffisamment distincts vocalement
56
+ - Afficher et expliquer le template tao
57
+ - Afficher les signatures de tous les agents qui ont un tao
58
+
12
59
  ## Reporting contract
13
60
 
14
61
  When invoked via the Agent tool, stay in the persona above. Respond with a concise JSON report when the task completes : { status: "ok|partial|failed", summary: "<200 words", files_changed: [paths], next_steps: [] }.
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { pathToFileURL } = require('node:url');
6
+ const approval = require('./lib/dispatch-approval.cjs');
7
+ const context = additionalContext => ({hookSpecificOutput:{hookEventName:'UserPromptSubmit',additionalContext}});
8
+ const deny = permissionDecisionReason => ({hookSpecificOutput:{hookEventName:'PreToolUse',permissionDecision:'deny',permissionDecisionReason}});
9
+
10
+ function onPrompt(payload, root) {
11
+ const prompt = String(payload.prompt || '').trim();
12
+ const accepted = /^(?:valide plan|approve plan) ([a-f0-9]{64})[.!]?$/i.exec(prompt);
13
+ if (accepted) {
14
+ try {
15
+ const r = approval.approve(root, accepted[1], 'terminal');
16
+ return context(`Plan ${r.id} valide par l utilisateur. Lire dispatch-plan.json puis appeler byan-auto-dispatch avec mode execute, planData et approvedPlanId exacts. Ne pas refaire le decoupage.`);
17
+ } catch (error) { return context(`Validation refusee : ${error.message}`); }
18
+ }
19
+ if (!prompt || /^(bonjour|salut|merci|ok merci|bonsoir)[!.\s]*$/i.test(prompt)) return context('');
20
+ if (/^(go|continue|reprends?|execute|exécute)[!.\s]*$/i.test(prompt)) {
21
+ try {
22
+ const record = approval.read(root);
23
+ if (record.status === 'approved') return context(`Reprendre le plan approuve ${record.id} : lire dispatch-plan.json puis appeler byan-auto-dispatch avec mode execute, planData exact et approvedPlanId. Ne pas refaire le decoupage.`);
24
+ if (record.status === 'pending') return context(`Le plan ${record.id} attend encore sa validation. Montrer plan.md et attendre "valide plan ${record.id}" ou le bouton de l application. Cette relance ne vaut pas validation.`);
25
+ if (record.status === 'executing') return context('Ce plan a deja commence : verifier son execution avant toute reprise, ne pas rejouer ses etapes automatiquement.');
26
+ } catch { /* No usable saved plan: normal routing below. */ }
27
+ }
28
+ try {
29
+ const fd = JSON.parse(fs.readFileSync(path.join(root,'_byan-output/fd-state.json'),'utf8'));
30
+ if (fd.phase && !['COMPLETED','ABORTED'].includes(fd.phase)) {
31
+ return context(`FD actif (${fd.phase}) : reprendre le plan de dispatch deja valide. Pour tout nouveau plan, utiliser byan-auto-dispatch en preparation puis attendre la validation explicite avant execution.`);
32
+ }
33
+ } catch { /* No active FD. */ }
34
+ return context('Toute demande non conversationnelle passe par Workflow byan-auto-dispatch en mode prepare (par defaut), sans seuil de taille. Une question ou conversation reste directe. Montrer le plan retourne, son modele et son effort par etape, puis terminer le tour et attendre "valide plan <id>" ou la validation dans l application. Aucun travail du plan avant cette validation. Le script prepare retourne sans executer. Si Workflow indisponible (Codex), appliquer le meme protocole depuis le fil principal avec les artefacts portables; ne pas pretendre avoir lance Workflow.');
35
+ }
36
+
37
+ async function onTool(payload, root) {
38
+ if (payload.tool_name !== 'Workflow') return {};
39
+ const input = payload.tool_input || {};
40
+ const name = String(input.scriptPath || input.name || input.workflow || '');
41
+ const inline = typeof input.script === 'string' && input.script.includes('byan-auto-dispatch');
42
+ if (!name.includes('byan-auto-dispatch') && !inline) return {};
43
+ try {
44
+ if (inline) return deny('Utiliser le script canonique byan-auto-dispatch, pas une copie inline.');
45
+ const args = typeof input.args === 'string' ? JSON.parse(input.args) : (input.args || {});
46
+ if (!args.mode || args.mode === 'prepare') return {};
47
+ if (args.mode !== 'execute') return deny('Mode de workflow inconnu');
48
+ const record = approval.authorize(root,args);
49
+ const ledger = await import(pathToFileURL(path.resolve(__dirname,'../../_byan/mcp/byan-mcp-server/lib/routing-ledger.js')).href);
50
+ for (const step of record.planData.table) ledger.append(root,{
51
+ step:step.id + ' — ' + step.titre, nature:step.nature, complexity:step.complexite,
52
+ complexitySource:'declared',runtime:step.moteur,model:step.modele,effort:step.effort,
53
+ });
54
+ // No permissionDecision=allow: other permission checks remain in force.
55
+ return {hookSpecificOutput:{hookEventName:'PreToolUse'}};
56
+ } catch (error) { return deny(`Execution refusee : ${error.message}`); }
57
+ }
58
+ function onResult(payload, root) {
59
+ if (payload.tool_name !== 'Workflow') return {};
60
+ try {
61
+ const input = payload.tool_input || {};
62
+ if (!String(input.scriptPath || input.name || '').includes('byan-auto-dispatch')) return {};
63
+ const args = typeof input.args === 'string' ? JSON.parse(input.args) : input.args;
64
+ if (args?.mode !== 'execute') return {};
65
+ const record = approval.read(root);
66
+ if (record.id === args.approvedPlanId && record.status === 'executing') approval.transition(root, record.id, 'completed');
67
+ return {};
68
+ } catch (error) { return {hookSpecificOutput:{hookEventName:'PostToolUse',additionalContext:'Cloture du plan impossible : ' + error.message}}; }
69
+ }
70
+ module.exports = { onPrompt, onTool, onResult };
71
+ if (require.main === module) {
72
+ (async () => {
73
+ let result;
74
+ try {
75
+ const payload=JSON.parse(fs.readFileSync(0,'utf8'));
76
+ const root=process.env.CLAUDE_PROJECT_DIR || payload.cwd || process.cwd();
77
+ result=payload.hook_event_name === 'UserPromptSubmit' ? onPrompt(payload,root) : ['PostToolUse','PostToolUseFailure'].includes(payload.hook_event_name) ? onResult(payload,root) : await onTool(payload,root);
78
+ } catch (error) { result=deny(`Garde de dispatch indisponible : ${error.message}`); }
79
+ process.stdout.write(JSON.stringify(result));
80
+ })();
81
+ }
@@ -1,78 +1,22 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * SessionStart hook — injects BYAN's FULL tao (voice directives) ONCE into the
4
- * session's initial context, so it lands in the stable, cacheable prefix instead
5
- * of being re-sent on every turn.
6
- *
7
- * Cache rationale: a UserPromptSubmit injection is appended at the growing edge
8
- * each turn, so the full ~3.6k-token tao was re-billed N times over a session.
9
- * Loaded once at SessionStart it sits in the stable prefix (cache read at 10%).
10
- * The per-turn voice freshness is carried by the tiny inject-voice-anchor.js
11
- * (UserPromptSubmit): full tao here, compact anchor there. The voice stays 100%
12
- * present every turn — nothing about it becomes conditional.
13
- *
14
- * Reads _byan/agent/byan/tao.md (Gen3) then _byan/tao.md (Gen2). Missing/empty ->
15
- * empty additionalContext (no-op). Always exits 0.
16
- */
17
-
2
+ 'use strict';
18
3
  const fs = require('fs');
19
4
  const path = require('path');
20
-
21
- // Gen3 puts tao under _byan/agent/byan/; Gen2 keeps it at the _byan/ root.
22
- function taoFile(projectDir) {
23
- const g3 = path.join(projectDir, '_byan', 'agent', 'byan', 'tao.md');
24
- const g2 = path.join(projectDir, '_byan', 'tao.md');
25
- return fs.existsSync(g3) ? g3 : g2;
5
+ const communication = require('../../_byan/core/communication.cjs');
6
+ function taoFile(root) {
7
+ const g3 = path.join(root, '_byan/agent/byan/tao.md');
8
+ return fs.existsSync(g3) ? g3 : path.join(root, '_byan/tao.md');
26
9
  }
27
-
28
- function buildTaoContext(projectDir) {
29
- try {
30
- const p = taoFile(projectDir);
31
- if (fs.existsSync(p)) {
32
- const content = fs.readFileSync(p, 'utf8').trim();
33
- if (content.length > 0) {
34
- return `BYAN tao (voice directives, loaded once at session start — register, signatures, forbidden vocabulary):\n\n${content}`;
35
- }
36
- }
37
- } catch {
38
- // Hook must never block session start.
39
- }
40
- return '';
10
+ function buildTaoContext(root) {
11
+ const loaded = communication.loadPolicy(root);
12
+ let tao = '';
13
+ try { if (loaded.diagnostic.status === 'active') tao = fs.readFileSync(taoFile(root), 'utf8').trim(); } catch { /* Minimal policy remains available. */ }
14
+ return [tao, communication.renderContract(communication.resolveContract(loaded, {}, 'session')),
15
+ 'Profils disponibles, à sélectionner selon intention et destinataire de chaque livrable :',
16
+ JSON.stringify(loaded.policy.profiles)].filter(Boolean).join('\n\n');
41
17
  }
42
-
43
- // Per-session turn counter for the voice-anchor refresh cadence (inject-voice-anchor.js).
44
- // It lives under _byan-output/ (gitignored). inject-tao OWNS the path and the reset
45
- // because the full tao it injects at SessionStart (including source=compact) restarts
46
- // the cadence: the next periodic full-tao refresh is then N turns later. The anchor hook
47
- // reads/writes the same path via require('./inject-tao') -- single source, no drift.
48
- function turnCounterPath(projectDir) {
49
- return path.join(projectDir, '_byan-output', '.tao-refresh-turn');
50
- }
51
-
52
- function resetTurnCounter(projectDir) {
53
- try {
54
- const p = turnCounterPath(projectDir);
55
- fs.mkdirSync(path.dirname(p), { recursive: true });
56
- fs.writeFileSync(p, '0');
57
- } catch {
58
- // Never block session start.
59
- }
60
- }
61
-
62
18
  if (require.main === module) {
63
- const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
64
- // A fresh full tao is about to be injected -> restart the voice-anchor cadence.
65
- resetTurnCounter(projectDir);
66
- const additionalContext = buildTaoContext(projectDir);
67
- if (additionalContext) {
68
- process.stdout.write(
69
- JSON.stringify({
70
- hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext },
71
- })
72
- );
73
- } else {
74
- process.stdout.write('{}');
75
- }
19
+ const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
20
+ process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: buildTaoContext(root) } }));
76
21
  }
77
-
78
- module.exports = { taoFile, buildTaoContext, turnCounterPath, resetTurnCounter };
22
+ module.exports = { taoFile, buildTaoContext };