create-byan-agent 2.44.0 → 2.45.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 +25 -0
- package/install/templates/.claude/CLAUDE.md +1 -0
- package/install/templates/.claude/hooks/inject-voice-anchor.js +20 -1
- package/install/templates/.claude/hooks/lib/plain-language.js +155 -0
- package/install/templates/.claude/hooks/plain-language-check.js +53 -0
- package/install/templates/.claude/rules/plain-language.md +73 -0
- package/install/templates/.claude/settings.json +4 -0
- package/install/templates/_byan/agent/byan/byan-tao.md +12 -0
- package/install/templates/_byan/mcp/byan-mcp-server/server.js +37 -0
- package/install/templates/_byan/workflow/simple/byan/data/mantras.yaml +15 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [2.45.0] - 2026-07-15
|
|
13
|
+
|
|
14
|
+
### Added - Plain-language guard for every agent (Mantra IA-26 "Parler Reel")
|
|
15
|
+
|
|
16
|
+
- New team-wide rule: agents speak clear, coherent French to the user — no gratuitous
|
|
17
|
+
English when a French word exists ("redemarrer le conteneur", not "cutoff"), no raw
|
|
18
|
+
internal jargon (leaf/tier/downgrade/gate/inline/advisory), no misapplied metaphor
|
|
19
|
+
(you do not "forge" a token). A technical term with no French equivalent (commit,
|
|
20
|
+
cache, token) is kept but explained once. Test: the reader understands with no
|
|
21
|
+
dictionary. This is the sibling of IA-23 (no emoji) and applies to ALL agents.
|
|
22
|
+
- Mechanism, in three layers, none of which re-generates an already-shown reply:
|
|
23
|
+
1. The rule reaches every agent: mantra `IA-26` (`mantras.yaml` + `mantras-sources.md`),
|
|
24
|
+
`.claude/rules/plain-language.md`, and a pointer in `CLAUDE.md`.
|
|
25
|
+
2. BYAN's own voice stays fresh: a line in the per-turn reminder
|
|
26
|
+
(`inject-voice-anchor.js`) + entries in `tao.md` Section 4 (Vocabulaire Interdit).
|
|
27
|
+
3. A forward net (non-blocking): the Stop hook `plain-language-check.js` spots the
|
|
28
|
+
known repeat-offenders in the finished reply and writes a one-turn flag under
|
|
29
|
+
`_byan-output/`; the next-turn reminder reads it, signals it in plain French, and
|
|
30
|
+
clears it. No blocking, no re-answer — the correction is carried to the next turn
|
|
31
|
+
(a blocking guard would force a costly regen and the user has already read the slip).
|
|
32
|
+
- Core logic isolated in `.claude/hooks/lib/plain-language.js` (French-aware word
|
|
33
|
+
boundary so "metier"/"chantier" stay clear of the "tier" match; code spans stripped
|
|
34
|
+
before scanning). Tests: `.claude/__tests__/plain-language.test.js`. Full suite green
|
|
35
|
+
(2629 jest). Shipped via `install/templates/`.
|
|
36
|
+
|
|
12
37
|
## [2.44.0] - 2026-07-15
|
|
13
38
|
|
|
14
39
|
### Changed - Revived the Sonnet middle tier for native-workflow model routing
|
|
@@ -33,6 +33,7 @@ Voir @.claude/rules/hermes-dispatcher.md pour les commandes Hermes.
|
|
|
33
33
|
|
|
34
34
|
- Pas d'emojis dans le code, commits, ou specs techniques (Mantra IA-23)
|
|
35
35
|
- Code auto-documente, commentaires uniquement pour le POURQUOI (Mantra IA-24)
|
|
36
|
+
- Parler reel: francais clair et coherent avec l'utilisateur, zero jargon interne / anglais gratuit (Mantra IA-26, voir @.claude/rules/plain-language.md)
|
|
36
37
|
- Format commits: `type: description` (feat, fix, docs, refactor, test, chore)
|
|
37
38
|
- Simplicite d'abord - Rasoir d'Ockham (Mantra #37)
|
|
38
39
|
- Challenge Before Confirm - Valider avant d'accepter (Mantra IA-16)
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
const fs = require('fs');
|
|
27
27
|
const path = require('path');
|
|
28
28
|
const { buildTaoContext, turnCounterPath } = require('./inject-tao');
|
|
29
|
+
const pl = require('./lib/plain-language');
|
|
29
30
|
|
|
30
31
|
const ANCHOR = [
|
|
31
32
|
'Voix BYAN (rappel par tour ; tao complet chargé au démarrage de session) :',
|
|
@@ -33,6 +34,7 @@ const ANCHOR = [
|
|
|
33
34
|
'- Challenge avant de confirmer ; questionne les absolus (Mantra IA-16).',
|
|
34
35
|
'- Signatures : "Attends — pourquoi ?", "OK. On construit.", "Ça, c\'est du générique.".',
|
|
35
36
|
'- Zéro emoji. Orienté solution : on cherche la meilleure option, pas le mur.',
|
|
37
|
+
'- 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).',
|
|
36
38
|
].join('\n');
|
|
37
39
|
|
|
38
40
|
const DEFAULT_REFRESH_EVERY = 12;
|
|
@@ -77,6 +79,15 @@ function decideAnchor({ turn, every, fullTao }) {
|
|
|
77
79
|
return { mode: 'anchor', additionalContext: ANCHOR };
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
// Append a plain-language slip reminder (IA-25) to the injected context when the
|
|
83
|
+
// previous turn tripped the forward net. Pure so it is unit-testable; the fs read
|
|
84
|
+
// + clear stays in the require.main path below. A missing/empty hit list is a
|
|
85
|
+
// no-op, so this never changes the anchor on a clean turn.
|
|
86
|
+
function withSlipReminder(baseContext, hits) {
|
|
87
|
+
const reminder = pl.formatReminder(hits);
|
|
88
|
+
return reminder ? `${baseContext}\n${reminder}` : baseContext;
|
|
89
|
+
}
|
|
90
|
+
|
|
80
91
|
if (require.main === module) {
|
|
81
92
|
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
82
93
|
const every = refreshEvery();
|
|
@@ -84,9 +95,16 @@ if (require.main === module) {
|
|
|
84
95
|
writeTurn(projectDir, turn);
|
|
85
96
|
const fullTao = every > 0 && turn % every === 0 ? buildTaoContext(projectDir) : '';
|
|
86
97
|
const { additionalContext } = decideAnchor({ turn, every, fullTao });
|
|
98
|
+
// Forward net: if the previous turn slipped into jargon, remind now and clear
|
|
99
|
+
// the flag (one-shot). Read/clear here, formatting stays pure in withSlipReminder.
|
|
100
|
+
const slipHits = pl.readSlip(projectDir);
|
|
101
|
+
if (slipHits && slipHits.length) pl.clearSlip(projectDir);
|
|
87
102
|
process.stdout.write(
|
|
88
103
|
JSON.stringify({
|
|
89
|
-
hookSpecificOutput: {
|
|
104
|
+
hookSpecificOutput: {
|
|
105
|
+
hookEventName: 'UserPromptSubmit',
|
|
106
|
+
additionalContext: withSlipReminder(additionalContext, slipHits),
|
|
107
|
+
},
|
|
90
108
|
})
|
|
91
109
|
);
|
|
92
110
|
}
|
|
@@ -98,5 +116,6 @@ module.exports = {
|
|
|
98
116
|
readTurn,
|
|
99
117
|
writeTurn,
|
|
100
118
|
decideAnchor,
|
|
119
|
+
withSlipReminder,
|
|
101
120
|
DEFAULT_REFRESH_EVERY,
|
|
102
121
|
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Plain-language core — the shared, testable heart of the "parler reel" guard
|
|
4
|
+
// (Mantra IA-26). Two jobs, no I/O beyond the slip flag:
|
|
5
|
+
//
|
|
6
|
+
// 1. scanText: find the KNOWN repeat-offender words in an assistant reply and
|
|
7
|
+
// return each with its plain-French replacement. This is the mechanical net
|
|
8
|
+
// for words we already know we misuse; the generative rule (the principle in
|
|
9
|
+
// .claude/rules/plain-language.md + the voice anchor) handles the long tail.
|
|
10
|
+
// 2. slip flag: a tiny file under _byan-output/ that the Stop hook writes when a
|
|
11
|
+
// reply slipped, and the next-turn voice anchor reads + clears to remind the
|
|
12
|
+
// agent. NO re-answer, NO blocking — the correction is carried FORWARD to the
|
|
13
|
+
// next turn, which is the whole point (avoid the costly regen loop).
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
// Known repeat-offenders -> plain French. Deliberately conservative: only terms
|
|
19
|
+
// with a clean everyday equivalent and a low false-positive risk once code is
|
|
20
|
+
// stripped. Common technical borrowings that have no French equivalent (commit,
|
|
21
|
+
// cache, token) are NOT here — the rule keeps them, explained once.
|
|
22
|
+
const OFFENDERS = Object.freeze([
|
|
23
|
+
{ term: 'inline', good: 'directement (je le fais moi-meme)' },
|
|
24
|
+
{ term: 'cutoff', good: "l'action reelle (ex: redemarrer, couper)" },
|
|
25
|
+
{ term: 'housekeeping', good: 'rangement / menage du code' },
|
|
26
|
+
{ term: 'downgrade', good: 'retrograder / baisser en gamme' },
|
|
27
|
+
{ term: 'advisory', good: 'signalement non bloquant' },
|
|
28
|
+
{ term: 'wrapper', good: 'enveloppe / surcouche' },
|
|
29
|
+
{ term: 'fallback', good: 'repli / solution de secours' },
|
|
30
|
+
{ term: 'throughput', good: 'debit' },
|
|
31
|
+
{ term: 'overhead', good: 'surcout' },
|
|
32
|
+
{ term: 'gate', good: 'point de controle / porte' },
|
|
33
|
+
{ term: 'leaf', good: 'etape / tache' },
|
|
34
|
+
{ term: 'tier', good: 'niveau / gamme' },
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
// A metaphor misuse, not a single word: "forger" applied to a token/jeton.
|
|
38
|
+
// Matched separately so the replacement can name the real verb.
|
|
39
|
+
const METAPHOR_OFFENDERS = Object.freeze([
|
|
40
|
+
{
|
|
41
|
+
id: 'forger-token',
|
|
42
|
+
re: /forg\w*\s+(?:un |une |des |le |les |la )?(?:token|jeton)/i,
|
|
43
|
+
label: 'forger un token',
|
|
44
|
+
good: 'generer / creer un token',
|
|
45
|
+
},
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
// A word boundary that treats accented letters as part of a word, so \btier\b
|
|
49
|
+
// style matching does NOT fire inside "metier", "chantier", "quartier"... The
|
|
50
|
+
// native \b is wrong here because JS \w excludes accented chars, splitting French
|
|
51
|
+
// words. This lookbehind/lookahead pair is the correct French-aware boundary.
|
|
52
|
+
const LEFT = '(?<![A-Za-zÀ-ÿ0-9_])';
|
|
53
|
+
const RIGHT = '(?![A-Za-zÀ-ÿ0-9_])';
|
|
54
|
+
|
|
55
|
+
function escapeRegExp(s) {
|
|
56
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function termRegExp(term) {
|
|
60
|
+
return new RegExp(LEFT + escapeRegExp(term) + RIGHT, 'i');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Remove fenced code blocks and inline `code` spans before scanning, so quoting a
|
|
64
|
+
// file, flag, or function literally named "tier" / "gate" does not trip the net.
|
|
65
|
+
// Prose is what we police; quoted code is not prose.
|
|
66
|
+
function stripCode(text) {
|
|
67
|
+
if (typeof text !== 'string' || !text) return '';
|
|
68
|
+
return text
|
|
69
|
+
.replace(/```[\s\S]*?```/g, ' ')
|
|
70
|
+
.replace(/`[^`]*`/g, ' ');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Find every distinct offender present in the prose. Returns [{ bad, good }].
|
|
74
|
+
function scanText(text) {
|
|
75
|
+
const prose = stripCode(text);
|
|
76
|
+
if (!prose) return [];
|
|
77
|
+
const hits = [];
|
|
78
|
+
const seen = new Set();
|
|
79
|
+
for (const { term, good } of OFFENDERS) {
|
|
80
|
+
if (termRegExp(term).test(prose) && !seen.has(term)) {
|
|
81
|
+
seen.add(term);
|
|
82
|
+
hits.push({ bad: term, good });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (const m of METAPHOR_OFFENDERS) {
|
|
86
|
+
if (m.re.test(prose) && !seen.has(m.id)) {
|
|
87
|
+
seen.add(m.id);
|
|
88
|
+
hits.push({ bad: m.label, good: m.good });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return hits;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// A short French reminder, for injection at the NEXT turn. Bounded to a few
|
|
95
|
+
// offenders so the note stays tiny even if a reply slipped many times.
|
|
96
|
+
function formatReminder(hits) {
|
|
97
|
+
if (!Array.isArray(hits) || hits.length === 0) return '';
|
|
98
|
+
const shown = hits.slice(0, 6)
|
|
99
|
+
.map((h) => `"${h.bad}" -> ${h.good}`)
|
|
100
|
+
.join(' ; ');
|
|
101
|
+
return [
|
|
102
|
+
'Rappel langage (IA-26) : au dernier tour tu as glisse du jargon ou de',
|
|
103
|
+
`l'anglais gratuit -> ${shown}. Reformule en francais reel et coherent ce`,
|
|
104
|
+
'tour-ci, sans refaire la reponse precedente.',
|
|
105
|
+
].join(' ');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// The slip flag lives under _byan-output/ (gitignored), same family as the other
|
|
109
|
+
// hook sidecars. It is a transient one-turn signal, never source of truth.
|
|
110
|
+
function slipPath(projectDir) {
|
|
111
|
+
return path.join(projectDir, '_byan-output', '.jargon-slip.json');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function writeSlip(projectDir, hits) {
|
|
115
|
+
try {
|
|
116
|
+
const p = slipPath(projectDir);
|
|
117
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
118
|
+
fs.writeFileSync(p, JSON.stringify({ hits }));
|
|
119
|
+
return true;
|
|
120
|
+
} catch {
|
|
121
|
+
return false; // best-effort: a write failure must never block a turn
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function readSlip(projectDir) {
|
|
126
|
+
try {
|
|
127
|
+
const raw = fs.readFileSync(slipPath(projectDir), 'utf8');
|
|
128
|
+
const parsed = JSON.parse(raw);
|
|
129
|
+
return Array.isArray(parsed.hits) ? parsed.hits : [];
|
|
130
|
+
} catch {
|
|
131
|
+
return null; // no flag (or unreadable) -> nothing to remind
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function clearSlip(projectDir) {
|
|
136
|
+
try {
|
|
137
|
+
fs.rmSync(slipPath(projectDir), { force: true });
|
|
138
|
+
} catch {
|
|
139
|
+
// never block
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = {
|
|
144
|
+
OFFENDERS,
|
|
145
|
+
METAPHOR_OFFENDERS,
|
|
146
|
+
escapeRegExp,
|
|
147
|
+
termRegExp,
|
|
148
|
+
stripCode,
|
|
149
|
+
scanText,
|
|
150
|
+
formatReminder,
|
|
151
|
+
slipPath,
|
|
152
|
+
writeSlip,
|
|
153
|
+
readSlip,
|
|
154
|
+
clearSlip,
|
|
155
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Stop hook — the FORWARD net for the "parler reel" rule (Mantra IA-26).
|
|
5
|
+
//
|
|
6
|
+
// It reads the assistant reply that just finished, looks for the known
|
|
7
|
+
// jargon/anglais repeat-offenders, and — if it finds any — writes a one-turn
|
|
8
|
+
// slip flag under _byan-output/. It NEVER blocks the turn: there is no re-answer,
|
|
9
|
+
// no regen. The next-turn voice anchor (inject-voice-anchor.js) reads the flag,
|
|
10
|
+
// reminds the agent in plain French, and clears it. Carrying the correction
|
|
11
|
+
// FORWARD is deliberate: a blocking guard would force a costly regen AND the user
|
|
12
|
+
// has already read the slip anyway (no pre-display hook exists).
|
|
13
|
+
//
|
|
14
|
+
// Always exits 0. A read/scan/write failure degrades to a no-op.
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const { extractLastAssistantText } = require('./lib/transcript-read');
|
|
18
|
+
const pl = require('./lib/plain-language');
|
|
19
|
+
|
|
20
|
+
// Testable core: scan the finished reply, flag a slip if any. Returns the hits.
|
|
21
|
+
function detectAndFlag(payload, projectDir) {
|
|
22
|
+
const text = extractLastAssistantText(payload);
|
|
23
|
+
const hits = pl.scanText(text);
|
|
24
|
+
if (hits.length > 0) pl.writeSlip(projectDir, hits);
|
|
25
|
+
return hits;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function readStdin() {
|
|
29
|
+
try {
|
|
30
|
+
return fs.readFileSync(0, 'utf8');
|
|
31
|
+
} catch {
|
|
32
|
+
return '';
|
|
33
|
+
}
|
|
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
|
+
detectAndFlag(payload, projectDir);
|
|
47
|
+
} catch {
|
|
48
|
+
// never block end-of-turn
|
|
49
|
+
}
|
|
50
|
+
process.stdout.write('{}');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = { detectAndFlag };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Parler Reel — Langage clair, cohérent, sans jargon (Mantra IA-26)
|
|
2
|
+
|
|
3
|
+
> L'utilisateur doit te comprendre sans dictionnaire. Un agent qui parle en
|
|
4
|
+
> jargon interne, en anglais gratuit ou en métaphore collée de travers force
|
|
5
|
+
> l'utilisateur à traduire — c'est du travail qu'on lui refile. Cette règle
|
|
6
|
+
> s'applique à TOUS les agents BYAN, comme "zéro emoji" (IA-23).
|
|
7
|
+
|
|
8
|
+
## Le principe (ce qui fait le vrai travail)
|
|
9
|
+
|
|
10
|
+
Parle en français réel et cohérent — des mots qu'un humain dit vraiment,
|
|
11
|
+
technique ou pas.
|
|
12
|
+
|
|
13
|
+
- **Pas d'anglais quand le français existe.** "redémarrer le conteneur", pas
|
|
14
|
+
"faire un cutoff". "solution de secours", pas "fallback".
|
|
15
|
+
- **Pas de métaphore collée de travers.** On ne "forge" pas des tokens : on les
|
|
16
|
+
génère, on les crée.
|
|
17
|
+
- **Pas de jargon interne du projet balancé brut** (leaf, tier, downgrade, gate,
|
|
18
|
+
inline, advisory...) : dis ce que ça FAIT, en clair.
|
|
19
|
+
- **Un terme technique anglais sans équivalent** (commit, cache, token) : tu le
|
|
20
|
+
gardes, mais tu l'expliques une fois en clair à la première utilisation.
|
|
21
|
+
- **Test simple** : ton responsable technique doit tout comprendre sans
|
|
22
|
+
dictionnaire.
|
|
23
|
+
|
|
24
|
+
Le principe est génératif : il te fait CHOISIR le bon mot, y compris pour les
|
|
25
|
+
mots pourris qui ne sont pas dans la liste ci-dessous. La liste n'est qu'un
|
|
26
|
+
rappel des récidivistes connus.
|
|
27
|
+
|
|
28
|
+
## La liste (récidivistes connus -> mot normal)
|
|
29
|
+
|
|
30
|
+
| Mot pourri | Dis plutôt |
|
|
31
|
+
|------------|------------|
|
|
32
|
+
| inline | directement (je le fais moi-même) |
|
|
33
|
+
| cutoff | l'action réelle (redémarrer, couper) |
|
|
34
|
+
| housekeeping | rangement / ménage du code |
|
|
35
|
+
| downgrade | rétrograder / baisser en gamme |
|
|
36
|
+
| advisory | signalement non bloquant |
|
|
37
|
+
| wrapper | enveloppe / surcouche |
|
|
38
|
+
| fallback | repli / solution de secours |
|
|
39
|
+
| throughput | débit |
|
|
40
|
+
| overhead | surcoût |
|
|
41
|
+
| gate | point de contrôle / porte |
|
|
42
|
+
| leaf | étape / tâche |
|
|
43
|
+
| tier | niveau / gamme |
|
|
44
|
+
| "forger" un token | générer / créer un token |
|
|
45
|
+
|
|
46
|
+
## Le mécanisme (comment c'est tenu, sans boucle de réécriture)
|
|
47
|
+
|
|
48
|
+
Trois couches, aucune ne refait une réponse déjà affichée :
|
|
49
|
+
|
|
50
|
+
1. **La règle, partout.** Ce fichier + le mantra IA-26 (`mantras.yaml`,
|
|
51
|
+
`mantras-sources.md`) + un pointeur dans `CLAUDE.md`. Tous les agents en
|
|
52
|
+
héritent (comme IA-23).
|
|
53
|
+
2. **La voix de BYAN, gardée fraîche.** Une ligne dans le rappel par tour
|
|
54
|
+
(`.claude/hooks/inject-voice-anchor.js`) + des entrées dans
|
|
55
|
+
`_byan/agent/byan/tao.md` (Section 4, Vocabulaire Interdit).
|
|
56
|
+
3. **Le filet vers l'avant (sans blocage).** À la fin de chaque réponse, le
|
|
57
|
+
programme `.claude/hooks/plain-language-check.js` (Stop) repère les
|
|
58
|
+
récidivistes connus et écrit un drapeau sous `_byan-output/.jargon-slip.json`.
|
|
59
|
+
Le rappel du tour SUIVANT lit le drapeau, le signale en clair, et l'efface.
|
|
60
|
+
Pas de réécriture, pas de régénération : la correction est portée au tour
|
|
61
|
+
d'après. C'est volontaire — un blocage forcerait une régénération coûteuse et
|
|
62
|
+
l'utilisateur a déjà lu le dérapage de toute façon (aucun contrôle ne
|
|
63
|
+
s'exécute avant l'affichage).
|
|
64
|
+
|
|
65
|
+
Le cœur logique est isolé dans `.claude/hooks/lib/plain-language.js` (liste +
|
|
66
|
+
détection + drapeau), testé par `.claude/__tests__/plain-language.test.js`.
|
|
67
|
+
|
|
68
|
+
## Coût
|
|
69
|
+
|
|
70
|
+
Le filet ne coûte quasiment rien : le programme qui relit tourne en local, aucun
|
|
71
|
+
appel au modèle. Le rappel ajoute une poignée de mots par tour, du même ordre
|
|
72
|
+
que le rappel de voix déjà présent. Ce n'est PAS une économie de tokens — c'est
|
|
73
|
+
du confort de compréhension pour l'utilisateur, assumé comme tel.
|
|
@@ -82,6 +82,10 @@
|
|
|
82
82
|
"type": "command",
|
|
83
83
|
"command": "p=\"$CLAUDE_PROJECT_DIR/.claude/hooks/punt-guard.js\"; [ -f \"$p\" ] || exit 0; exec node \"$p\""
|
|
84
84
|
},
|
|
85
|
+
{
|
|
86
|
+
"type": "command",
|
|
87
|
+
"command": "p=\"$CLAUDE_PROJECT_DIR/.claude/hooks/plain-language-check.js\"; [ -f \"$p\" ] || exit 0; exec node \"$p\""
|
|
88
|
+
},
|
|
85
89
|
{
|
|
86
90
|
"type": "command",
|
|
87
91
|
"command": "p=\"$CLAUDE_PROJECT_DIR/.claude/hooks/drain-advisory.js\"; [ -f \"$p\" ] || exit 0; exec node \"$p\""
|
|
@@ -155,6 +155,18 @@ Exemple : "Attends. Ca touche au noyau. On est jamais assez parano. Qu'est-ce qu
|
|
|
155
155
|
**Pourquoi :** Faux enthousiasme. BYAN est sincere ou silencieux.
|
|
156
156
|
**Au lieu de ca :** "Oui." ou "C'est ca."
|
|
157
157
|
|
|
158
|
+
**Interdit :** l'anglais gratuit quand le francais existe ("cutoff", "fallback", "housekeeping", "wrapper", "throughput", "overhead")
|
|
159
|
+
**Pourquoi :** Mantra IA-26 Parler Reel. Le lecteur doit comprendre sans dictionnaire.
|
|
160
|
+
**Au lieu de ca :** le mot francais ("redemarrer le conteneur", "solution de secours", "menage du code", "surcouche", "debit", "surcout")
|
|
161
|
+
|
|
162
|
+
**Interdit :** le jargon interne du projet balance brut ("leaf", "tier", "downgrade", "gate", "inline", "advisory")
|
|
163
|
+
**Pourquoi :** Mantra IA-26. C'est le vocabulaire de la cuisine interne, pas celui de l'utilisateur.
|
|
164
|
+
**Au lieu de ca :** dis ce que ca FAIT en clair ("etape", "niveau", "baisser en gamme", "point de controle", "directement", "signalement non bloquant")
|
|
165
|
+
|
|
166
|
+
**Interdit :** la metaphore collee de travers ("forger un token")
|
|
167
|
+
**Pourquoi :** Mantra IA-26. On forge une ame, pas un token.
|
|
168
|
+
**Au lieu de ca :** le verbe reel ("generer un token", "creer un token")
|
|
169
|
+
|
|
158
170
|
---
|
|
159
171
|
|
|
160
172
|
### Section 5 — Non-dits
|
|
@@ -1004,6 +1004,27 @@ const tools = [
|
|
|
1004
1004
|
additionalProperties: false,
|
|
1005
1005
|
},
|
|
1006
1006
|
},
|
|
1007
|
+
// Selective RAG retrieval — returns the top-k most relevant knowledge bodies
|
|
1008
|
+
// VERBATIM (never truncated; negations/prohibitions are returned intact).
|
|
1009
|
+
// GET /api/projects/:projectId/knowledge/retrieve?q=...&k=10&tokenBudget=0
|
|
1010
|
+
// Backed by PG FTS (ts_rank) in prod, LIKE-degraded on SQLite (dev/tests).
|
|
1011
|
+
// Use this instead of knowledge_list when you only need a focused subset.
|
|
1012
|
+
{
|
|
1013
|
+
name: 'byan_api_knowledge_retrieve',
|
|
1014
|
+
description:
|
|
1015
|
+
'Retrieve the top-k most relevant knowledge entries for a query using full-text search (PG) or LIKE fallback (SQLite). Returns bodies VERBATIM — negations and prohibitions are never truncated. GET /api/projects/:projectId/knowledge/retrieve?q=...&k=10&tokenBudget=0. RBAC viewer required. projectId and q are required. Requires BYAN_API_TOKEN.',
|
|
1016
|
+
inputSchema: {
|
|
1017
|
+
type: 'object',
|
|
1018
|
+
properties: {
|
|
1019
|
+
projectId: { type: 'string', description: 'Project id (required — RBAC guard).' },
|
|
1020
|
+
q: { type: 'string', description: 'Search query (required).' },
|
|
1021
|
+
k: { type: 'number', description: 'Max number of results (default 10).' },
|
|
1022
|
+
tokenBudget: { type: 'number', description: 'Total token budget (0 = unlimited).' },
|
|
1023
|
+
},
|
|
1024
|
+
required: ['projectId', 'q'],
|
|
1025
|
+
additionalProperties: false,
|
|
1026
|
+
},
|
|
1027
|
+
},
|
|
1007
1028
|
|
|
1008
1029
|
// ─── Memory ───────────────────────────────────────────────────────────
|
|
1009
1030
|
// Route: GET /api/projects/:projectId/memory (RBAC viewer)
|
|
@@ -1437,6 +1458,7 @@ const REMOTE_SAFE_TOOLS = new Set([
|
|
|
1437
1458
|
'byan_api_workflow_runs_get',
|
|
1438
1459
|
'byan_api_knowledge_list',
|
|
1439
1460
|
'byan_api_knowledge_get',
|
|
1461
|
+
'byan_api_knowledge_retrieve',
|
|
1440
1462
|
'byan_api_memory_list',
|
|
1441
1463
|
'byan_api_memory_search',
|
|
1442
1464
|
'byan_api_custom_agents_list',
|
|
@@ -1982,6 +2004,21 @@ export function createByanServer({ token, remoteOnly = false } = {}) {
|
|
|
1982
2004
|
return { content: [{ type: 'text', text: JSON.stringify(body, null, 2) }] };
|
|
1983
2005
|
}
|
|
1984
2006
|
|
|
2007
|
+
if (name === 'byan_api_knowledge_retrieve') {
|
|
2008
|
+
requireToken();
|
|
2009
|
+
if (!args.projectId) throw new Error('projectId is required (RBAC: knowledge is project-scoped).');
|
|
2010
|
+
if (!args.q || String(args.q).trim() === '') throw new Error('q (query) is required.');
|
|
2011
|
+
const qs = buildQuery({
|
|
2012
|
+
q: args.q,
|
|
2013
|
+
k: args.k,
|
|
2014
|
+
tokenBudget: args.tokenBudget,
|
|
2015
|
+
});
|
|
2016
|
+
const body = await apiRequest(
|
|
2017
|
+
`/api/projects/${encodeURIComponent(args.projectId)}/knowledge/retrieve${qs}`
|
|
2018
|
+
);
|
|
2019
|
+
return { content: [{ type: 'text', text: JSON.stringify(body, null, 2) }] };
|
|
2020
|
+
}
|
|
2021
|
+
|
|
1985
2022
|
if (name === 'byan_api_memory_list') {
|
|
1986
2023
|
requireToken();
|
|
1987
2024
|
if (!args.projectId) throw new Error('projectId is required (RBAC: memory is project-scoped).');
|
|
@@ -262,11 +262,22 @@ agents_ia:
|
|
|
262
262
|
- "Contraintes légales/business"
|
|
263
263
|
- "TODOs avec ticket"
|
|
264
264
|
|
|
265
|
+
- id: "IA-26"
|
|
266
|
+
name: "Parler Réel"
|
|
267
|
+
category: "code_quality"
|
|
268
|
+
description: "Parler en français réel et cohérent à l'utilisateur : pas d'anglais gratuit, pas de jargon interne brut, pas de métaphore collée de travers. Un terme technique sans équivalent est gardé mais expliqué une fois. Le test : le lecteur comprend sans dictionnaire."
|
|
269
|
+
priority: "critique"
|
|
270
|
+
forbidden:
|
|
271
|
+
- "Anglais quand le français existe (cutoff, fallback, housekeeping)"
|
|
272
|
+
- "Jargon interne balancé brut (leaf, tier, downgrade, gate, inline, advisory)"
|
|
273
|
+
- "Métaphore collée de travers (forger un token)"
|
|
274
|
+
rule_file: ".claude/rules/plain-language.md"
|
|
275
|
+
|
|
265
276
|
metadata:
|
|
266
|
-
total_mantras:
|
|
277
|
+
total_mantras: 65
|
|
267
278
|
conception_count: 39
|
|
268
|
-
agents_ia_count:
|
|
269
|
-
version: "1.0.
|
|
270
|
-
last_updated: "2026-
|
|
279
|
+
agents_ia_count: 26
|
|
280
|
+
version: "1.0.1"
|
|
281
|
+
last_updated: "2026-07-15"
|
|
271
282
|
authors: ["Yan", "Carson"]
|
|
272
283
|
methodology: "Merise Agile + TDD"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-byan-agent",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.45.0",
|
|
4
4
|
"description": "BYAN v2.8 - Intelligent AI agent creator with ELO trust system + scientific fact-check + Hermes universal dispatcher + native Claude Code integration (hooks, skills, MCP server). Multi-platform (Claude Code, Codex). Merise Agile + TDD + 71 Mantras. ~54% LLM cost savings.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|