wendkeep 0.66.4 → 0.67.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 +50 -0
- package/README.en.md +78 -5
- package/README.md +78 -5
- package/docs/en/commands/costs-and-observability.md +21 -7
- package/docs/en/commands/maintenance-and-diagnostics.md +13 -1
- package/docs/en/commands/operating-profiles.md +65 -10
- package/docs/en/commands/sessions-and-import.md +22 -1
- package/docs/en/commands/verify.md +5 -3
- package/docs/pt-BR/commands/costs-and-observability.md +21 -7
- package/docs/pt-BR/commands/maintenance-and-diagnostics.md +12 -1
- package/docs/pt-BR/commands/operating-profiles.md +66 -11
- package/docs/pt-BR/commands/sessions-and-import.md +20 -0
- package/docs/pt-BR/commands/verify.md +6 -3
- package/hooks/change-nag.mjs +8 -0
- package/hooks/codex-rollout-meta.mjs +112 -0
- package/hooks/codex-subagent-graph.mjs +903 -0
- package/hooks/harness-doctor.mjs +82 -1
- package/hooks/import-sessions.mjs +185 -50
- package/hooks/operating-profile-runtime.mjs +36 -2
- package/hooks/operating-profile-task-store.mjs +77 -0
- package/hooks/session-identity.mjs +40 -5
- package/hooks/session-observability-lifecycle.mjs +129 -0
- package/hooks/session-observability-state.mjs +241 -0
- package/hooks/session-observability-store.mjs +436 -0
- package/hooks/session-observability.mjs +647 -21
- package/hooks/session-stop.mjs +339 -11
- package/hooks/subagent-stop.mjs +266 -12
- package/hooks/subagent-usage.mjs +65 -0
- package/hooks/token-usage.mjs +81 -4
- package/package.json +3 -3
- package/packages/harness/src/operating-profile.mjs +127 -0
- package/packages/harness/src/sensors-core.mjs +41 -1
- package/packages/integrations/src/prompt-content.mjs +123 -0
- package/packages/integrations/src/transcripts.mjs +16 -10
- package/src/cost.mjs +40 -6
- package/src/doctor.mjs +4 -1
- package/src/profile.mjs +95 -17
- package/src/rebuild-costs.mjs +220 -34
- package/src/skills-seed.mjs +38 -2
- package/src/sync-defs.mjs +6 -1
package/src/rebuild-costs.mjs
CHANGED
|
@@ -1,45 +1,231 @@
|
|
|
1
|
-
// Deterministic
|
|
2
|
-
//
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
// Deterministic, causal reconstruction for historical session observability.
|
|
2
|
+
// Dry-run is a pure composition pass; apply delegates all note mutation to the CAS publisher.
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
5
6
|
import { readSessionRegistry } from '../hooks/obsidian-common.mjs';
|
|
6
|
-
import
|
|
7
|
+
import * as sessionObservability from '../hooks/session-observability.mjs';
|
|
8
|
+
import {
|
|
9
|
+
mutateObservabilityStore,
|
|
10
|
+
readObservabilityStore,
|
|
11
|
+
} from '../hooks/session-observability-store.mjs';
|
|
12
|
+
import { sanitizeObservabilityDiagnostics } from '../hooks/session-observability-state.mjs';
|
|
7
13
|
import { assertVaultPathSafe } from '../hooks/vault-path-safety.mjs';
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.filter((
|
|
14
|
-
.
|
|
15
|
-
|
|
15
|
+
function sortedEntries(registry, target) {
|
|
16
|
+
return Object.entries(registry?.sessions || {})
|
|
17
|
+
.map(([sessionId, value]) => ({ sessionId, ...value }))
|
|
18
|
+
.filter((entry) => entry.session_file)
|
|
19
|
+
.filter((entry) => !target || entry.sessionId === target || entry.session_file === target)
|
|
20
|
+
.sort((a, b) => a.sessionId.localeCompare(b.sessionId));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function transcriptCandidates(entry) {
|
|
24
|
+
const paths = new Set();
|
|
25
|
+
if (entry.transcript_path) paths.add(entry.transcript_path);
|
|
26
|
+
for (const path of entry.transcript_paths || []) if (path) paths.add(path);
|
|
27
|
+
const activations = Array.isArray(entry.activations)
|
|
28
|
+
? entry.activations
|
|
29
|
+
: Object.values(entry.activations || {});
|
|
30
|
+
for (const activation of activations) {
|
|
31
|
+
if (activation?.transcript_path) paths.add(activation.transcript_path);
|
|
32
|
+
for (const path of activation?.transcript_paths || []) if (path) paths.add(path);
|
|
33
|
+
}
|
|
34
|
+
return [...paths];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function candidateContent(candidate, fallback) {
|
|
38
|
+
return typeof candidate?.content === 'string' ? candidate.content : fallback;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function candidateHash(candidate, fallback) {
|
|
42
|
+
return createHash('sha256').update(candidateContent(candidate, fallback)).digest('hex');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function safeDiagnostics(input, fallback = []) {
|
|
46
|
+
try {
|
|
47
|
+
return sanitizeObservabilityDiagnostics(input || fallback);
|
|
48
|
+
} catch {
|
|
49
|
+
return sanitizeObservabilityDiagnostics(fallback);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function semanticRebuildReport(report) {
|
|
54
|
+
const {
|
|
55
|
+
generatedAt: _generatedAt,
|
|
56
|
+
changed = 0,
|
|
57
|
+
unchanged = 0,
|
|
58
|
+
sessions = [],
|
|
59
|
+
...semantic
|
|
60
|
+
} = report || {};
|
|
61
|
+
return {
|
|
62
|
+
...semantic,
|
|
63
|
+
converged: Number(changed || 0) + Number(unchanged || 0),
|
|
64
|
+
sessions: sessions.map((entry) => ({
|
|
65
|
+
...entry,
|
|
66
|
+
status: entry.status === 'published' || entry.status === 'unchanged'
|
|
67
|
+
? 'converged'
|
|
68
|
+
: entry.status,
|
|
69
|
+
})),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function writeRebuildReportIfChanged(reportPath, report) {
|
|
74
|
+
if (existsSync(reportPath)) {
|
|
75
|
+
try {
|
|
76
|
+
const previous = JSON.parse(readFileSync(reportPath, 'utf8'));
|
|
77
|
+
if (JSON.stringify(semanticRebuildReport(previous))
|
|
78
|
+
=== JSON.stringify(semanticRebuildReport(report))) return false;
|
|
79
|
+
} catch {
|
|
80
|
+
// Invalid prior reports are replaced by the sanitized current schema.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
mkdirSync(dirname(reportPath), { recursive: true });
|
|
84
|
+
writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function markDirtyDefault(vaultBase, sessionId, diagnostics) {
|
|
89
|
+
mutateObservabilityStore(vaultBase, sessionId, (state) => ({
|
|
90
|
+
...state,
|
|
91
|
+
observability_dirty: true,
|
|
92
|
+
diagnostics: safeDiagnostics(diagnostics, [{ code: 'STALE_FRONTIER', count: 1 }]),
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function rebuildSessionCosts(
|
|
97
|
+
vaultBase,
|
|
98
|
+
{
|
|
99
|
+
apply = false,
|
|
100
|
+
session = '',
|
|
101
|
+
limit = 0,
|
|
102
|
+
limits = {},
|
|
103
|
+
overrides = {},
|
|
104
|
+
} = {},
|
|
105
|
+
effects = {},
|
|
106
|
+
) {
|
|
107
|
+
const readRegistry = effects.readRegistry || readSessionRegistry;
|
|
108
|
+
const compose = effects.compose || sessionObservability.composeSessionObservability;
|
|
109
|
+
const publish = effects.publish || sessionObservability.publishSessionObservability;
|
|
110
|
+
const readStore = effects.readStore || readObservabilityStore;
|
|
111
|
+
const markDirty = effects.markDirty || markDirtyDefault;
|
|
112
|
+
const writeReport = effects.writeReport || writeRebuildReportIfChanged;
|
|
113
|
+
const now = effects.now || (() => new Date().toISOString());
|
|
114
|
+
if (typeof compose !== 'function') throw new TypeError('composeSessionObservability indisponível');
|
|
115
|
+
if (apply && typeof publish !== 'function') throw new TypeError('publishSessionObservability indisponível');
|
|
116
|
+
|
|
117
|
+
const registry = readRegistry(vaultBase);
|
|
118
|
+
const report = {
|
|
119
|
+
version: 2,
|
|
120
|
+
generatedAt: now(),
|
|
121
|
+
mode: apply ? 'apply' : 'dry-run',
|
|
122
|
+
targeted: Boolean(session),
|
|
123
|
+
overrides: { ...overrides },
|
|
124
|
+
scanned: 0,
|
|
125
|
+
changed: 0,
|
|
126
|
+
unchanged: 0,
|
|
127
|
+
degraded: 0,
|
|
128
|
+
stale: 0,
|
|
129
|
+
missing: 0,
|
|
130
|
+
errors: 0,
|
|
131
|
+
ok: true,
|
|
132
|
+
sessions: [],
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
for (const entry of sortedEntries(registry, session)) {
|
|
16
136
|
if (limit && report.scanned >= limit) break;
|
|
17
137
|
report.scanned += 1;
|
|
18
|
-
|
|
19
|
-
expectedType: 'file', label: 'nota de sessão do rebuild de custos',
|
|
20
|
-
});
|
|
21
|
-
const note = checkedNote.target;
|
|
22
|
-
if (!entry.transcript_path || !checkedNote.exists || !existsSync(entry.transcript_path)) {
|
|
23
|
-
report.missing.push({ sessionId: entry.sessionId, session: entry.session_file, note: checkedNote.exists, transcript: !!entry.transcript_path && existsSync(entry.transcript_path), transcriptPath: entry.transcript_path || '' });
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
const before = readFileSync(note, 'utf8');
|
|
138
|
+
let note;
|
|
27
139
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
caller: 'cost-rebuild', canonicalConversationId: entry.sessionId,
|
|
140
|
+
const checked = assertVaultPathSafe(vaultBase, join(vaultBase, entry.session_file), {
|
|
141
|
+
expectedType: 'file', label: 'nota de sessão do rebuild de custos',
|
|
31
142
|
});
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
143
|
+
const hasTranscript = transcriptCandidates(entry).some((path) => existsSync(path));
|
|
144
|
+
if (!checked.exists || !hasTranscript) {
|
|
145
|
+
report.missing += 1;
|
|
146
|
+
report.sessions.push({
|
|
147
|
+
sessionId: entry.sessionId, status: 'missing', diagnostics: [],
|
|
148
|
+
});
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
note = checked.target;
|
|
152
|
+
const before = readFileSync(note, 'utf8');
|
|
153
|
+
const runtimeState = readStore(vaultBase, entry.sessionId);
|
|
154
|
+
const candidate = compose({
|
|
155
|
+
vaultBase,
|
|
156
|
+
sessionContent: before,
|
|
157
|
+
sessionEntry: entry,
|
|
158
|
+
canonicalConversationId: entry.sessionId,
|
|
159
|
+
caller: 'cost-rebuild',
|
|
160
|
+
mode: 'offline',
|
|
161
|
+
limits,
|
|
162
|
+
runtimeState,
|
|
163
|
+
});
|
|
164
|
+
const diagnostics = safeDiagnostics(candidate?.diagnostics);
|
|
165
|
+
const contentHash = candidateHash(candidate, before);
|
|
166
|
+
if (candidate?.state === 'degraded') {
|
|
167
|
+
report.degraded += 1;
|
|
168
|
+
report.sessions.push({ sessionId: entry.sessionId, status: 'degraded', diagnostics });
|
|
169
|
+
if (apply) markDirty(vaultBase, entry.sessionId, diagnostics);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (candidate?.state !== 'complete' && candidate?.state !== 'none') {
|
|
173
|
+
report.degraded += 1;
|
|
174
|
+
const invalidDiagnostics = [{ code: 'PARENT_META_INVALID', count: 1 }];
|
|
175
|
+
report.sessions.push({
|
|
176
|
+
sessionId: entry.sessionId, status: 'degraded', diagnostics: invalidDiagnostics,
|
|
177
|
+
});
|
|
178
|
+
if (apply) markDirty(vaultBase, entry.sessionId, invalidDiagnostics);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (!apply) {
|
|
183
|
+
const changed = candidateContent(candidate, before) !== before;
|
|
184
|
+
if (changed) report.changed += 1;
|
|
185
|
+
else report.unchanged += 1;
|
|
186
|
+
report.sessions.push({
|
|
187
|
+
sessionId: entry.sessionId,
|
|
188
|
+
status: changed ? 'would-change' : 'unchanged',
|
|
189
|
+
candidateHash: contentHash,
|
|
190
|
+
diagnostics,
|
|
191
|
+
});
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const outcome = publish({
|
|
196
|
+
vaultBase,
|
|
197
|
+
sessionPath: note,
|
|
198
|
+
canonicalConversationId: entry.sessionId,
|
|
199
|
+
candidate,
|
|
200
|
+
caller: 'cost-rebuild',
|
|
201
|
+
mode: 'offline',
|
|
202
|
+
allowSourceRefresh: true,
|
|
203
|
+
}) || { status: 'degraded' };
|
|
204
|
+
if (outcome.status === 'published') report.changed += 1;
|
|
205
|
+
else if (outcome.status === 'unchanged') report.unchanged += 1;
|
|
206
|
+
else if (outcome.status === 'stale' || outcome.status === 'conflict') {
|
|
207
|
+
report.stale += 1;
|
|
208
|
+
markDirty(vaultBase, entry.sessionId, [{ code: 'STALE_FRONTIER', count: 1 }]);
|
|
209
|
+
} else {
|
|
210
|
+
report.degraded += 1;
|
|
211
|
+
markDirty(vaultBase, entry.sessionId, [{ code: 'PARENT_META_INVALID', count: 1 }]);
|
|
212
|
+
}
|
|
213
|
+
report.sessions.push({
|
|
214
|
+
sessionId: entry.sessionId,
|
|
215
|
+
status: outcome.status || 'degraded',
|
|
216
|
+
candidateHash: contentHash,
|
|
217
|
+
diagnostics: safeDiagnostics(outcome.diagnostics, diagnostics),
|
|
218
|
+
});
|
|
219
|
+
} catch {
|
|
220
|
+
report.errors += 1;
|
|
221
|
+
const diagnostics = [{ code: 'PARENT_META_INVALID', count: 1 }];
|
|
222
|
+
report.sessions.push({ sessionId: entry.sessionId, status: 'degraded', diagnostics });
|
|
223
|
+
if (apply) markDirty(vaultBase, entry.sessionId, diagnostics);
|
|
40
224
|
}
|
|
41
225
|
}
|
|
42
|
-
|
|
43
|
-
|
|
226
|
+
|
|
227
|
+
report.ok = report.degraded === 0 && report.stale === 0
|
|
228
|
+
&& report.missing === 0 && report.errors === 0;
|
|
229
|
+
if (apply) writeReport(join(vaultBase, '.brain', 'COST_REBUILD.json'), report);
|
|
44
230
|
return report;
|
|
45
231
|
}
|
package/src/skills-seed.mjs
CHANGED
|
@@ -17,6 +17,24 @@ Use ao começar implementação, correção ou refatoração. **Keep Core perman
|
|
|
17
17
|
em todos os perfis: Vault, sessão, identidade, memória, lessons e persistência. Na ausência de
|
|
18
18
|
configuração válida, **GOVERN é o padrão** compatível.
|
|
19
19
|
|
|
20
|
+
## Seleção temporária por solicitação
|
|
21
|
+
|
|
22
|
+
Antes de editar, classifique a implementação atual e registre a escolha auditável com
|
|
23
|
+
\`wendkeep profile route <FLOW|GUIDE|GOVERN|ASSURE> --session <id> --reason <texto>\`.
|
|
24
|
+
A lease vale somente para a solicitação atual; ao encerrá-la, o perfil persistente da
|
|
25
|
+
sessão/projeto volta a valer. **OFF nunca é uma escolha automática da LLM**: somente uma pessoa
|
|
26
|
+
pode persistir \`profile use OFF\` explicitamente.
|
|
27
|
+
|
|
28
|
+
- **FLOW:** ajuste local, reversível e de escopo fechado, sem contrato/spec, segurança,
|
|
29
|
+
dependência, CI/release ou policy.
|
|
30
|
+
- **GUIDE:** mudança compacta de comportamento que precisa de change/spec, sem revisão formal.
|
|
31
|
+
- **GOVERN:** escolha conservadora em caso de dúvida ou risco e para superfícies sensíveis.
|
|
32
|
+
- **ASSURE:** GOVERN quando confirmação explícita e handoff fazem parte do contrato.
|
|
33
|
+
|
|
34
|
+
O harness da LLM faz essa classificação semântica; o Wend Runtime valida e aplica a lease.
|
|
35
|
+
Se não houver uma sessão causal identificada ou o comando falhar, não fabrique estado: use o
|
|
36
|
+
perfil efetivo já injetado e trate \`GOVERN\` como fallback conservador quando ele for o padrão.
|
|
37
|
+
|
|
20
38
|
<HARD-GATE>
|
|
21
39
|
Antes de editar, leia o **perfil efetivo** injetado pelo WendKeep e siga somente sua rota:
|
|
22
40
|
- \`OFF\`: não imponha processo Wend; a governança pertence ao **harness nativo da LLM**.
|
|
@@ -268,6 +286,24 @@ Use this when starting an implementation, fix, or refactor. **Keep Core is alway
|
|
|
268
286
|
in every profile: Vault, session, identity, memory, lessons, and persistence. With no valid
|
|
269
287
|
configuration, **GOVERN is the default** for compatibility.
|
|
270
288
|
|
|
289
|
+
## Temporary selection per request
|
|
290
|
+
|
|
291
|
+
Before editing, classify the current implementation and record the auditable choice with
|
|
292
|
+
\`wendkeep profile route <FLOW|GUIDE|GOVERN|ASSURE> --session <id> --reason <text>\`.
|
|
293
|
+
The lease applies only to the current request; after it ends, the persistent session/project
|
|
294
|
+
profile becomes effective again. **OFF is never an automatic LLM choice**: only a human can
|
|
295
|
+
persist it explicitly through \`profile use OFF\`.
|
|
296
|
+
|
|
297
|
+
- **FLOW:** a local, reversible, bounded adjustment with no contract/spec, security, dependency,
|
|
298
|
+
CI/release, or policy impact.
|
|
299
|
+
- **GUIDE:** a compact behavior change that needs a change/spec but no formal review.
|
|
300
|
+
- **GOVERN:** the conservative choice when uncertain or risky, and for sensitive surfaces.
|
|
301
|
+
- **ASSURE:** GOVERN when explicit confirmation and handoff are part of the contract.
|
|
302
|
+
|
|
303
|
+
The LLM harness owns semantic classification; Wend Runtime validates and applies the lease. If
|
|
304
|
+
there is no causally identified session or the command fails, do not fabricate state: use the
|
|
305
|
+
already injected effective profile, with \`GOVERN\` as the conservative configured fallback.
|
|
306
|
+
|
|
271
307
|
<HARD-GATE>
|
|
272
308
|
Before editing, read the injected **effective profile** and follow only its route:
|
|
273
309
|
- \`OFF\`: impose no Wend process; governance belongs to the **native LLM harness**.
|
|
@@ -619,7 +655,7 @@ size of the problem>
|
|
|
619
655
|
// usuário ("implementa X", "corrige Y"), não com abstrações ("mudança não-trivial"). Gatilhos
|
|
620
656
|
// concretos + instrução imperativa = a skill dispara sozinha (paridade Superpowers).
|
|
621
657
|
const WK_SKILLS_PT = [
|
|
622
|
-
skill('wk-workflow', 'Use quando o usuário pedir para implementar, criar, corrigir, refatorar, adicionar ou alterar código:
|
|
658
|
+
skill('wk-workflow', 'Use quando o usuário pedir para implementar, criar, corrigir, refatorar, adicionar ou alterar código: classifique e registre a rota temporária FLOW/GUIDE/GOVERN/ASSURE ANTES de editar, então siga o perfil efetivo. Keep Core permanece ativo; OFF nunca é automático.', WORKFLOW),
|
|
623
659
|
skill('wk-tdd', 'Use ao implementar qualquer comportamento — Red/Green/Refactor com testes que discriminam (derivados do spec, litmus não-raso, adequação).', TDD),
|
|
624
660
|
skill('wk-debugging', 'Use quando algo falha, quebra, dá erro ou regride — depuração sistemática por hipótese antes de corrigir.', DEBUGGING),
|
|
625
661
|
skill('wk-brainstorming', 'Use quando a ideia ainda é vaga ou o usuário quer discutir/planejar uma feature (inclusive em plan mode) — vira design aprovado, com closure gate e tabela out-of-scope, antes de código.', BRAINSTORMING, [{ name: 'design-template.md', content: DESIGN_TEMPLATE_PT }]),
|
|
@@ -628,7 +664,7 @@ const WK_SKILLS_PT = [
|
|
|
628
664
|
];
|
|
629
665
|
|
|
630
666
|
const WK_SKILLS_EN = [
|
|
631
|
-
skill('wk-workflow', 'Use when the user asks to implement, create, fix, refactor, add, or change code:
|
|
667
|
+
skill('wk-workflow', 'Use when the user asks to implement, create, fix, refactor, add, or change code: classify and record the temporary FLOW/GUIDE/GOVERN/ASSURE route BEFORE editing, then follow the effective profile. Keep Core stays active; OFF is never automatic.', WORKFLOW_EN),
|
|
632
668
|
skill('wk-tdd', 'Use when implementing any behaviour — Red/Green/Refactor with tests that discriminate (spec-derived, non-shallow litmus, adequacy).', TDD_EN),
|
|
633
669
|
skill('wk-debugging', 'Use when something fails, breaks, errors or regresses — systematic hypothesis-driven debugging before fixing.', DEBUGGING_EN),
|
|
634
670
|
skill('wk-brainstorming', 'Use when the idea is still vague or the user wants to discuss/plan a feature (plan mode included) — turns it into an approved design, with a closure gate and out-of-scope table, before code.', BRAINSTORMING_EN, [{ name: 'design-template.md', content: DESIGN_TEMPLATE_EN }]),
|
package/src/sync-defs.mjs
CHANGED
|
@@ -62,7 +62,12 @@ function renderAgentsSection(skills, sourceHash = '') {
|
|
|
62
62
|
|
|
63
63
|
This project uses the [wendkeep](https://github.com/rogersialves/wendkeep) harness. **Keep Core is always active**
|
|
64
64
|
in every profile: Vault, session, identity, memory, lessons, and persistence integrations.
|
|
65
|
-
The
|
|
65
|
+
The persistent profile is selected explicitly; missing or invalid configuration uses **GOVERN as the default**.
|
|
66
|
+
|
|
67
|
+
Before an implementation, the native LLM harness classifies the current request and may create a
|
|
68
|
+
task-scoped lease with \`wendkeep profile route <FLOW|GUIDE|GOVERN|ASSURE> --session <id> --reason <text>\`.
|
|
69
|
+
The lease expires when that request ends and the persistent session/project profile becomes
|
|
70
|
+
effective again. **OFF is never selected adaptively**; only a human can persist \`profile use OFF\`.
|
|
66
71
|
|
|
67
72
|
Route work by the effective profile:
|
|
68
73
|
- **OFF** — Wend Runtime is disabled and governance belongs to the native LLM harness; Keep Core stays active.
|