@ngockhoale/ukit 1.5.2 → 1.5.4

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 CHANGED
@@ -2,23 +2,48 @@
2
2
 
3
3
  All notable changes to UKit are documented here.
4
4
 
5
+ ## 1.5.4 - 2026-05-28
6
+
7
+ ### Fixed
8
+
9
+ - Fixed stale `docs/AI_HANDOFF.md` references in next-step skill, INSTALL.md, UKIT_USAGE_GUIDE.md, PROJECT.md (template + local).
10
+ - Fixed mirror `route-task.mjs` not showing `handoff=` in summary — wrong intent order (docsSpecific before handoff) + missing handoffFile field + missing display segment.
11
+ - Added `WORKLOG_ARCHIVE.md` to `.gitignore`.
12
+
13
+ ### Changed
14
+
15
+ - Compacted `docs/MEMORY.md` from 118KB/298 lines to 7.8KB/78 lines. Old entries archived to `docs/MEMORY_ARCHIVE.md`.
16
+ - Cleared handoff task queue after all cycle 002 tasks resolved.
17
+
18
+ ## 1.5.3 - 2026-05-28
19
+
20
+ ### Changed
21
+
22
+ - Restructured `docs/AI_HANDOFF.md` into `docs/AI_HANDOFF/` folder: ACTIVE.md (snapshot), RULES.md (flow + token budget), PLAN.md (brainstorm), INDEX.md (task index), tasks/ (per-task files), archive/ (completed cycles, max 3).
23
+ - Each task is now an isolated file in `tasks/TASK-xxx.md` — AI reads only the task it implements, not the entire backlog.
24
+ - Added token budget rule: combined handoff reads must stay under 200 lines per request.
25
+ - Added auto-compact rule: if any handoff file exceeds 80 lines, trigger `clear handoff`.
26
+ - Updated template mirror `templates/docs/AI_HANDOFF/` to match new folder structure.
27
+ - Updated `taskRouting.js` handoffFile target from `docs/AI_HANDOFF.md` to `docs/AI_HANDOFF/ACTIVE.md`.
28
+ - Updated `install.js`, `doctor.js`, `uninstall.js` to check for `docs/AI_HANDOFF/ACTIVE.md`.
29
+
5
30
  ## 1.5.2 - 2026-05-28
6
31
 
7
32
  ### Added
8
33
 
9
34
  - Added first-class `ukit:handoff` prompt detection and routing for explicit handoff/brainstorm-to-task flows.
10
- - Added `intentMode: handoff` to route summaries so hooks and helpers can prioritize `docs/AI_HANDOFF.md` automatically.
11
- - Added a reusable generic `docs/AI_HANDOFF.md` handoff template for installed projects.
35
+ - Added `intentMode: handoff` to route summaries so hooks and helpers can prioritize handoff file automatically.
36
+ - Added a reusable generic handoff template for installed projects.
12
37
 
13
38
  ### Changed
14
39
 
15
- - Handoff prompts now route through `docs-quality` skill instead of generic `update-status`, making `docs/AI_HANDOFF.md` the primary coordination artifact.
16
- - Updated installed `next-step` skill guidance to read `docs/AI_HANDOFF.md` first for explicit handoff prompts.
40
+ - Handoff prompts now route through `docs-quality` skill instead of generic `update-status`.
41
+ - Updated installed `next-step` skill guidance to read handoff file first for explicit handoff prompts.
17
42
  - Updated `route-task` mirror and hook behavior in both source and installed artifact so `ukit install` users get consistent handoff routing.
18
43
 
19
44
  ### Fixed
20
45
 
21
- - Handoff authoring is now advisory (exit 0) in Safe Patch, so large `docs/AI_HANDOFF.md` batches no longer block the handoff workflow.
46
+ - Handoff authoring is now advisory (exit 0) in Safe Patch, so large handoff batches no longer block the handoff workflow.
22
47
  - Hard runtime/shared-risk file broad rewrites still block by default unless `advisoryOnly=true` or `UKIT_SAFE_PATCH_ADVISORY=1` is set.
23
48
 
24
49
  ### Tests
package/README.md CHANGED
@@ -32,7 +32,7 @@ ukit install
32
32
  4. Fill in the generated docs baseline:
33
33
  - `docs/PROJECT.md`
34
34
  - `docs/MEMORY.md`
35
- - `docs/AI_HANDOFF.md`
35
+ - `docs/AI_HANDOFF/`
36
36
  - `docs/WORKLOG.md`
37
37
  5. Open your AI tool and work in natural language.
38
38
 
@@ -90,7 +90,7 @@ UKit v1.3.1 keeps the same shared runtime contract while adding Safe Patch Proto
90
90
  - install globally with `npm install -g @ngockhoale/ukit`
91
91
  - keep using the exact same human workflow inside projects: `ukit install`
92
92
  - preserve the same `ukit` binary, hooks, and install-first orchestration while standardizing the runtime root as hidden `.ukit/`
93
- - install `docs/AI_HANDOFF.md` as the default cross-AI handoff file for plan task breakdown implementation continuity, with explicit sections so one AI can plan, another can refine tasks, and another can implement them reliably
93
+ - install `docs/AI_HANDOFF/` as the cross-AI handoff folder with per-task isolation: ACTIVE.md (snapshot), INDEX.md (task index), tasks/ (one file per task) so each AI reads only the task it needs, with token budget rules in RULES.md
94
94
  - auto-route open-ended “what next?” / “continue” prompts to the `next-step` skill with a visible freshness cue when status may be stale
95
95
  - auto-route explicit handoff/wrap-up requests to the `update-status` skill while skipping trivial/no-state-change tasks
96
96
  - keep concrete debug/implementation/review prompts primary, so project status never replaces source/index-first task work
@@ -145,8 +145,8 @@ items:
145
145
 
146
146
  - id: docs-ai-handoff
147
147
  type: config
148
- sourceTemplate: docs/AI_HANDOFF.md
149
- targetPath: docs/AI_HANDOFF.md
148
+ sourceTemplate: docs/AI_HANDOFF
149
+ targetPath: docs/AI_HANDOFF
150
150
  requires:
151
151
  - docs-project
152
152
  - docs-memory
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ngockhoale/ukit",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "Install/update an index-first AI workspace for Claude Code, Antigravity, OpenAI Codex, and OpenCode.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,4 +1,5 @@
1
1
  import path from 'node:path';
2
+ import fs from 'node:fs/promises';
2
3
  import { pathExists, readJsonIfExists } from '../../core/fileOps.js';
3
4
  import { buildPathConfig } from '../../core/paths.js';
4
5
  import { buildRuntimePaths } from '../../core/runtimePaths.js';
@@ -45,6 +46,15 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [] }) {
45
46
  : [];
46
47
  const codexAdapterTracked = trackedPaths.some((entry) => entry.startsWith('.codex/'));
47
48
 
49
+ const WORKLOG_MAX_LINES = 600;
50
+ let worklogLineCount = 0;
51
+ try {
52
+ const content = await fs.readFile(path.join(projectRoot, 'docs', 'WORKLOG.md'), 'utf8');
53
+ worklogLineCount = content.split('\n').length;
54
+ } catch {
55
+ // file may not exist
56
+ }
57
+
48
58
  const checks = {
49
59
  manifestLoaded: Boolean(manifest?.name),
50
60
  templatesDirExists: await pathExists(pathConfig.templatesRoot),
@@ -62,8 +72,9 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [] }) {
62
72
  sessionMemoryDirExists: await pathExists(runtimePaths.sessionsDir),
63
73
  docsProjectExists: await pathExists(path.join(projectRoot, 'docs', 'PROJECT.md')),
64
74
  docsMemoryExists: await pathExists(path.join(projectRoot, 'docs', 'MEMORY.md')),
65
- docsAiHandoffExists: await pathExists(path.join(projectRoot, 'docs', 'AI_HANDOFF.md')),
75
+ docsAiHandoffExists: await pathExists(path.join(projectRoot, 'docs', 'AI_HANDOFF', 'ACTIVE.md')),
66
76
  docsWorklogExists: await pathExists(path.join(projectRoot, 'docs', 'WORKLOG.md')),
77
+ docsWorklogUnderBudget: worklogLineCount <= WORKLOG_MAX_LINES,
67
78
  allProvidersConfigured: providers.allSupported,
68
79
  ...(codexAdapterTracked
69
80
  ? {
@@ -104,8 +115,9 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [] }) {
104
115
  console.log(`[UKit] ${ok(checks.sessionMemoryDirExists)} .ukit/storage/memory/sessions/`);
105
116
  console.log(`[UKit] ${ok(checks.docsProjectExists)} docs/PROJECT.md`);
106
117
  console.log(`[UKit] ${ok(checks.docsMemoryExists)} docs/MEMORY.md`);
107
- console.log(`[UKit] ${ok(checks.docsAiHandoffExists)} docs/AI_HANDOFF.md`);
118
+ console.log(`[UKit] ${ok(checks.docsAiHandoffExists)} docs/AI_HANDOFF/`);
108
119
  console.log(`[UKit] ${ok(checks.docsWorklogExists)} docs/WORKLOG.md`);
120
+ console.log(`[UKit] ${ok(checks.docsWorklogUnderBudget)} docs/WORKLOG.md under budget (${worklogLineCount}/${WORKLOG_MAX_LINES} lines)`);
109
121
  if (codexAdapterTracked) {
110
122
  console.log(`[UKit] ${ok(checks.codexReadmeExists)} .codex/README.md`);
111
123
  console.log(`[UKit] ${ok(checks.codexSettingsExists)} .codex/settings.json`);
@@ -239,7 +239,7 @@ export async function runInstall({ packageRoot, projectRoot, packageVersion, arg
239
239
  const docsLabels = [
240
240
  'docs/PROJECT.md',
241
241
  'docs/MEMORY.md',
242
- 'docs/AI_HANDOFF.md',
242
+ 'docs/AI_HANDOFF/ACTIVE.md',
243
243
  'docs/WORKLOG.md',
244
244
  ];
245
245
 
@@ -254,7 +254,7 @@ export async function runInstall({ packageRoot, projectRoot, packageVersion, arg
254
254
  if (missingDocs.length > 0) {
255
255
  console.log(`[UKit] Missing docs — fill these in before first use: ${missingDocs.join(', ')}`);
256
256
  } else {
257
- console.log('[UKit] Docs baseline ready: docs/PROJECT.md, docs/MEMORY.md, docs/AI_HANDOFF.md, docs/WORKLOG.md');
257
+ console.log('[UKit] Docs baseline ready: docs/PROJECT.md, docs/MEMORY.md, docs/AI_HANDOFF/, docs/WORKLOG.md');
258
258
  console.log('[UKit] Fill them once with real project context for the best results.');
259
259
  }
260
260
 
@@ -47,5 +47,5 @@ export async function runUninstall({ projectRoot, argv = [] }) {
47
47
  }
48
48
 
49
49
  console.log(`[UKit] Uninstall complete. Removed ${result.removed}/${result.attempted} managed paths.`);
50
- console.log('[UKit] Note: docs/PROJECT.md, docs/MEMORY.md, docs/AI_HANDOFF.md, docs/WORKLOG.md contain user content and were preserved. Delete manually if needed.');
50
+ console.log('[UKit] Note: docs/PROJECT.md, docs/MEMORY.md, docs/AI_HANDOFF/, docs/WORKLOG.md contain user content and were preserved. Delete manually if needed.');
51
51
  }
@@ -139,6 +139,10 @@ export async function deriveTaskRoute({
139
139
  contextRecommendation,
140
140
  verificationRecommendation,
141
141
  });
142
+ const handoffBudget = intentMode === 'handoff'
143
+ ? await checkHandoffBudget(absoluteRoot)
144
+ : null;
145
+ const worklogBudget = await checkWorklogBudget(absoluteRoot);
142
146
  const routeSummary = buildRouteSummary({
143
147
  activeSkills,
144
148
  routingContext: {
@@ -157,6 +161,8 @@ export async function deriveTaskRoute({
157
161
  contextRecommendation,
158
162
  verificationRecommendation,
159
163
  nextAction,
164
+ handoffBudget,
165
+ worklogBudget,
160
166
  });
161
167
  const approachSelector = routeSummary?.approachSelector ?? null;
162
168
 
@@ -180,6 +186,8 @@ export async function deriveTaskRoute({
180
186
  verificationRecommendation,
181
187
  nextAction,
182
188
  routeSummary,
189
+ handoffBudget,
190
+ worklogBudget,
183
191
  ...(degradedWarnings.length > 0 ? { degradedWarnings } : {}),
184
192
  };
185
193
  }
@@ -190,6 +198,8 @@ export function buildRouteSummary({
190
198
  contextRecommendation = null,
191
199
  verificationRecommendation = null,
192
200
  nextAction = null,
201
+ handoffBudget = null,
202
+ worklogBudget = null,
193
203
  } = {}) {
194
204
  const autonomyLevel = routingContext.autonomyLevel ?? 'balanced';
195
205
  const delegationRecommendation = deriveDelegationRecommendation({
@@ -243,7 +253,7 @@ export function buildRouteSummary({
243
253
  ),
244
254
  );
245
255
  const nextActionCommand = compactHelperLane ? null : nextAction?.command ?? null;
246
- const handoffFile = routingContext.intentMode === 'handoff' ? 'docs/AI_HANDOFF.md' : null;
256
+ const handoffFile = routingContext.intentMode === 'handoff' ? 'docs/AI_HANDOFF/ACTIVE.md' : null;
247
257
  const summaryLine = [
248
258
  routingContext.taskType ? `task=${routingContext.taskType}` : null,
249
259
  handoffFile ? `handoff=${handoffFile}` : null,
@@ -253,6 +263,8 @@ export function buildRouteSummary({
253
263
  editGuardHint ? `editGuard=${editGuardHint}` : null,
254
264
  delegationRecommendation?.hint ? `delegate=${delegationRecommendation.hint}` : null,
255
265
  policyMode ? `policy=${policyMode}` : null,
266
+ handoffBudget?.warning ? `budget=${handoffBudget.warning}` : null,
267
+ worklogBudget?.warning ? `budget=${worklogBudget.warning}` : null,
256
268
  ].filter(Boolean).join(' | ');
257
269
 
258
270
  return {
@@ -270,6 +282,8 @@ export function buildRouteSummary({
270
282
  continuationState,
271
283
  intentMode: routingContext.intentMode ?? null,
272
284
  handoffFile,
285
+ handoffBudget,
286
+ worklogBudget,
273
287
  delegateHint: delegationRecommendation?.hint ?? null,
274
288
  nextActionType: nextAction?.type ?? null,
275
289
  nextActionCommand,
@@ -1480,6 +1494,108 @@ function unique(values) {
1480
1494
  return [...new Set(values.filter(Boolean))];
1481
1495
  }
1482
1496
 
1497
+ const HANDOFF_BUDGET_MAX_LINES = 200;
1498
+ const HANDOFF_FILE_MAX_LINES = 80;
1499
+ const WORKLOG_BUDGET_MAX_LINES = 600;
1500
+ const WORKLOG_BUDGET_MAX_ENTRIES = 30;
1501
+
1502
+ export async function checkHandoffBudget(rootDir) {
1503
+ const handoffDir = path.join(rootDir, 'docs', 'AI_HANDOFF');
1504
+ const checkFiles = ['ACTIVE.md', 'INDEX.md'];
1505
+ let totalLines = 0;
1506
+ const fileDetails = [];
1507
+
1508
+ for (const fileName of checkFiles) {
1509
+ const filePath = path.join(handoffDir, fileName);
1510
+ try {
1511
+ const content = await fs.readFile(filePath, 'utf8');
1512
+ const lines = content.split('\n').length;
1513
+ totalLines += lines;
1514
+ fileDetails.push({ file: fileName, lines });
1515
+ } catch {
1516
+ // File may not exist yet — not an error
1517
+ }
1518
+ }
1519
+
1520
+ // Also count task files
1521
+ const tasksDir = path.join(handoffDir, 'tasks');
1522
+ try {
1523
+ const taskFiles = await fs.readdir(tasksDir);
1524
+ for (const taskFile of taskFiles) {
1525
+ if (!taskFile.endsWith('.md')) continue;
1526
+ const content = await fs.readFile(path.join(tasksDir, taskFile), 'utf8');
1527
+ const lines = content.split('\n').length;
1528
+ totalLines += lines;
1529
+ fileDetails.push({ file: `tasks/${taskFile}`, lines });
1530
+ }
1531
+ } catch {
1532
+ // tasks dir may not exist
1533
+ }
1534
+
1535
+ const oversizedFiles = fileDetails.filter((f) => f.lines > HANDOFF_FILE_MAX_LINES);
1536
+ const overBudget = totalLines > HANDOFF_BUDGET_MAX_LINES;
1537
+
1538
+ let warning = null;
1539
+ if (overBudget) {
1540
+ warning = 'over-budget';
1541
+ } else if (oversizedFiles.length > 0) {
1542
+ warning = 'file-oversized';
1543
+ }
1544
+
1545
+ return {
1546
+ totalLines,
1547
+ maxLines: HANDOFF_BUDGET_MAX_LINES,
1548
+ fileDetails,
1549
+ oversizedFiles: oversizedFiles.map((f) => f.file),
1550
+ overBudget,
1551
+ warning,
1552
+ action: warning ? 'clear-handoff' : null,
1553
+ };
1554
+ }
1555
+
1556
+ export async function checkWorklogBudget(rootDir) {
1557
+ const worklogPath = path.join(rootDir, 'docs', 'WORKLOG.md');
1558
+ try {
1559
+ const content = await fs.readFile(worklogPath, 'utf8');
1560
+ const lines = content.split('\n').length;
1561
+ const entryMatches = content.match(/^## \d{4}-\d{2}-\d{2}/gm) ?? [];
1562
+ const entryCount = entryMatches.length;
1563
+
1564
+ const overLineBudget = lines > WORKLOG_BUDGET_MAX_LINES;
1565
+ const overEntryBudget = entryCount > WORKLOG_BUDGET_MAX_ENTRIES;
1566
+ const overBudget = overLineBudget || overEntryBudget;
1567
+
1568
+ let warning = null;
1569
+ if (overLineBudget && overEntryBudget) {
1570
+ warning = 'worklog-lines-and-entries-over';
1571
+ } else if (overLineBudget) {
1572
+ warning = 'worklog-lines-over';
1573
+ } else if (overEntryBudget) {
1574
+ warning = 'worklog-entries-over';
1575
+ }
1576
+
1577
+ return {
1578
+ lines,
1579
+ maxLines: WORKLOG_BUDGET_MAX_LINES,
1580
+ entryCount,
1581
+ maxEntries: WORKLOG_BUDGET_MAX_ENTRIES,
1582
+ overBudget,
1583
+ warning,
1584
+ action: warning ? 'compact-worklog' : null,
1585
+ };
1586
+ } catch {
1587
+ return {
1588
+ lines: 0,
1589
+ maxLines: WORKLOG_BUDGET_MAX_LINES,
1590
+ entryCount: 0,
1591
+ maxEntries: WORKLOG_BUDGET_MAX_ENTRIES,
1592
+ overBudget: false,
1593
+ warning: null,
1594
+ action: null,
1595
+ };
1596
+ }
1597
+ }
1598
+
1483
1599
  const DELEGATABLE_IMPLEMENTATION_SKILL_IDS = new Set([
1484
1600
  'delivery',
1485
1601
  'frontend',
@@ -3,7 +3,7 @@
3
3
  # Used from UserPromptSubmit and PreToolUse so end users do not need to name skills.
4
4
 
5
5
  INPUT=$(cat)
6
- PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
6
+ PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
7
7
  STATE_FILE="$PROJECT_ROOT/.claude/ukit/skill-router-state.json"
8
8
  HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
9
9
  THRESHOLD_SCRIPT="$HOOK_DIR/../ukit/runtime/compact-threshold.mjs"
@@ -3,7 +3,7 @@
3
3
  # and does not jump to blanket verification when targeted evidence already exists.
4
4
 
5
5
  INPUT=$(cat)
6
- PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$(pwd)}"
6
+ PROJECT_ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
7
7
  STATE_FILE="$PROJECT_ROOT/.claude/ukit/skill-router-state.json"
8
8
  ROUTE_CACHE_FILE="$PROJECT_ROOT/.claude/ukit/route-cache.json"
9
9
  PROGRESS_FILE="$PROJECT_ROOT/.claude/ukit/verification-progress.json"
@@ -44,7 +44,7 @@ If stale or missing, downgrade confidence and verify with the smallest current t
44
44
  ## Input Order
45
45
 
46
46
  Read only what is needed:
47
- 1. `docs/AI_HANDOFF.md` first when the prompt explicitly names handoff / `ukit:handoff` / brainstorm-to-task flow
47
+ 1. `docs/AI_HANDOFF/ACTIVE.md` first when the prompt explicitly names handoff / `ukit:handoff` / brainstorm-to-task flow
48
48
  2. `docs/STATUS.md` (or existing root `STATUS.md` fallback) for normal status/continue prompts
49
49
  3. `docs/TASKS.md` only for queued-task prompts, “continue” with no active status, or when status points at queued work
50
50
  4. `docs/CODE_MAP.md` only when navigation is needed
@@ -18,7 +18,8 @@ function getFilePath(payload = {}) {
18
18
  }
19
19
 
20
20
  function isHandoffAuthoringFile(relativePath) {
21
- return relativePath === 'docs/AI_HANDOFF.md';
21
+ return relativePath === 'docs/AI_HANDOFF.md'
22
+ || relativePath.startsWith('docs/AI_HANDOFF/');
22
23
  }
23
24
 
24
25
  async function listManifestPaths(backupsRoot) {
@@ -200,7 +201,7 @@ async function main() {
200
201
  process.stdout.write(`[ukit-safe-patch] ${result.message}\n`);
201
202
  } else if (result.status === 'advisory') {
202
203
  process.stderr.write(`[ukit-safe-patch] ${result.message}\n`);
203
- process.stderr.write('[ukit-safe-patch] handoff authoring advisory — change is already written; continue updating docs/AI_HANDOFF.md.\n');
204
+ process.stderr.write('[ukit-safe-patch] handoff authoring advisory — change is already written; continue updating docs/AI_HANDOFF/.\n');
204
205
  }
205
206
  if (result.status === 'blocked') {
206
207
  const advisory = isSafePatchAdvisoryOnly(runtimeConfig);
@@ -481,6 +481,7 @@ function formatDisplayRouteSummary(routeSummary = null, routingContext = {}) {
481
481
 
482
482
  const segments = [
483
483
  taskSegment,
484
+ extractRouteLineSegment(line, 'handoff'),
484
485
  extractRouteLineSegment(line, 'targets'),
485
486
  extractRouteLineSegment(line, 'tests'),
486
487
  extractRouteLineSegment(line, 'styles'),
@@ -831,14 +832,14 @@ function deriveIntentMode({ promptText = '', commandText = '', targetFile = null
831
832
  const openEndedStatus = hasOpenEndedStatusSignal(lower, raw) || taskQueueNext;
832
833
  const concreteTask = hasConcreteTaskSignal(lower, raw, targetFile, { taskQueueNext });
833
834
 
834
- if (docsSpecific) {
835
- return 'docs-specific';
836
- }
837
-
838
835
  if (hasHandoffSignal(lower, raw)) {
839
836
  return 'handoff';
840
837
  }
841
838
 
839
+ if (docsSpecific) {
840
+ return 'docs-specific';
841
+ }
842
+
842
843
  if (statusUpdate) {
843
844
  return 'status-update';
844
845
  }
@@ -1350,8 +1351,10 @@ function buildRouteSummary({
1350
1351
  ),
1351
1352
  );
1352
1353
  const nextActionCommand = compactHelperLane ? null : nextAction?.command ?? null;
1354
+ const handoffFile = routingContext.intentMode === 'handoff' ? 'docs/AI_HANDOFF/ACTIVE.md' : null;
1353
1355
  const line = [
1354
1356
  routingContext.taskType ? `task=${routingContext.taskType}` : null,
1357
+ handoffFile ? `handoff=${handoffFile}` : null,
1355
1358
  formatCompactSegment('targets', primaryTargets),
1356
1359
  formatCompactSegment('tests', relatedTests),
1357
1360
  formatCompactSegment('styles', styleFiles),
@@ -1374,6 +1377,7 @@ function buildRouteSummary({
1374
1377
  completionState,
1375
1378
  continuationState,
1376
1379
  intentMode: routingContext.intentMode ?? null,
1380
+ handoffFile,
1377
1381
  delegateHint: delegationRecommendation?.hint ?? null,
1378
1382
  nextActionType: nextAction?.type ?? null,
1379
1383
  nextActionCommand,
@@ -96,7 +96,7 @@ For clearly non-code specialist lanes (docs-only, status, task queue), skip the
96
96
  - **Non-trivial**: `docs/MEMORY.md` + `docs/PROJECT.md` + `docs/CODE_MAP.md`.
97
97
  - `docs/STATUS.md`: use for open-ended status/continue prompts or meaningful continuation context; stale status is orientation only.
98
98
  - `docs/TASKS.md`: use only for queued-task prompts or when status points at queued work; safely clean exact duplicates/completed overflow by default without deleting unfinished human-authored tasks.
99
- - `docs/WORKLOG.md`: only recent relevant entries.
99
+ - `docs/WORKLOG.md`: only recent relevant entries. Follow the Budget Rules at the top of the file; archive oldest entries to `docs/WORKLOG_ARCHIVE.md` when over limits.
100
100
  - Follow routed verification policy: targeted first, widen only when risk/shared scope justifies it, ask before blanket broad runs.
101
101
 
102
102
  ## Living Status Workflow
@@ -0,0 +1,9 @@
1
+ # Active Handoff Cycle
2
+
3
+ - Status: `ready_for_next_cycle`
4
+ - Phase: `cleared`
5
+ - Updated:
6
+ - Updated by:
7
+ - Human decision needed: `no`
8
+
9
+ <!-- Snapshot only. Rules in RULES.md. Tasks in tasks/. Plan brainstorm in PLAN.md. -->
@@ -0,0 +1,4 @@
1
+ # Handoff History
2
+
3
+ | Cycle | Date | Summary |
4
+ |-------|------|---------|
@@ -0,0 +1,6 @@
1
+ # Handoff Task Index
2
+
3
+ | ID | Title | Priority | Size | Status | File |
4
+ |----|-------|----------|------|--------|------|
5
+
6
+ Updated:
@@ -0,0 +1,5 @@
1
+ # Handoff Plan
2
+
3
+ Status: `empty`
4
+
5
+ <!-- AI ghi ý tưởng + phân tích ở đây. Sau khi tách thành tasks, clear phần dưới. -->
@@ -0,0 +1,47 @@
1
+ # Handoff Rules
2
+
3
+ ## Token Budget (MANDATORY)
4
+
5
+ - **Combined handoff reads must stay under 200 lines per request.**
6
+ - Read order: `ACTIVE.md` (if needed) → `INDEX.md` (scan tasks) → single `tasks/TASK-xxx.md` (implement one task).
7
+ - Do NOT read `RULES.md` every request — only when you need flow clarification.
8
+ - Do NOT read multiple task files in one request.
9
+ - If ACTIVE.md + INDEX.md + task file would exceed budget, read only the task file.
10
+ - Auto-compact: if any single handoff file exceeds 80 lines, trigger `clear handoff` immediately.
11
+
12
+ ## How Human Submits Ideas
13
+
14
+ - Natural language is enough: `ukit:handoff`, `gom ý tưởng`, `chia task`, `đưa vào handoff`.
15
+ - If request is already a concrete task (clear file/logic/output, small enough to do now), bypass handoff and execute directly.
16
+ - If request is broad/ambiguous/multi-step, use handoff.
17
+
18
+ ## Handoff Flow
19
+
20
+ 1. Human submits ideas → AI writes to `PLAN.md`.
21
+ 2. Human approves plan → AI splits into `tasks/TASK-xxx.md` + updates `INDEX.md`.
22
+ 3. AI implementer reads `INDEX.md` → picks task → reads `tasks/TASK-xxx.md` → implements.
23
+ 4. After implementation → update `INDEX.md` status, archive cycle if done.
24
+
25
+ ## Task Gate
26
+
27
+ A task is `ready` only when it has:
28
+ - Clear target files
29
+ - Clear action
30
+ - Dependencies stated
31
+ - Verification command
32
+ - Acceptance criteria
33
+
34
+ Missing any → `needs_breakdown`, `blocked`, or `needs_human`.
35
+
36
+ ## Clear Handoff
37
+
38
+ 1. Archive current cycle → `archive/cycle-NNN.md`.
39
+ 2. If archive > 3 files → delete oldest, append 1-line summary to `HISTORY.md`.
40
+ 3. Reset `ACTIVE.md` to empty template.
41
+ 4. Clear `INDEX.md`.
42
+ 5. Delete all files in `tasks/`.
43
+ 6. Clear `PLAN.md`.
44
+
45
+ ## Docs Sync
46
+
47
+ After cycle, update affected docs only: `WORKLOG.md`, `PROJECT.md`, `CODE_MAP.md`, `CHANGELOG.md`.
File without changes
File without changes
@@ -47,7 +47,7 @@ End users do not need to manage any of that manually.
47
47
  Complete these files before first serious use:
48
48
  - `docs/PROJECT.md`
49
49
  - `docs/MEMORY.md`
50
- - `docs/AI_HANDOFF.md`
50
+ - `docs/AI_HANDOFF/`
51
51
  - `docs/WORKLOG.md`
52
52
 
53
53
  ### 4) Open your AI tool
@@ -97,7 +97,7 @@ ukit install
97
97
  Check that the docs baseline files exist and are filled in:
98
98
  - `docs/PROJECT.md`
99
99
  - `docs/MEMORY.md`
100
- - `docs/AI_HANDOFF.md`
100
+ - `docs/AI_HANDOFF/`
101
101
  - `docs/WORKLOG.md`
102
102
 
103
103
  ---
@@ -44,7 +44,7 @@
44
44
 
45
45
  1. Run `ukit memory recall "<current task>"` for non-trivial work; reuse relevant `## Previous Context` before asking the user to restate prior decisions
46
46
  2. Read `docs/MEMORY.md` — architecture decisions, active constraints, known bugs
47
- 3. Read `docs/AI_HANDOFF.md` when continuing cross-AI planning, task breakdown, or task implementation handoff work
47
+ 3. Read `docs/AI_HANDOFF/ACTIVE.md` when continuing cross-AI planning, task breakdown, or task implementation handoff work
48
48
  4. Read `docs/CODE_MAP.md` if it exists — structural navigation index
49
49
  5. Use the installed source-code index / routed helpers to localize the smallest relevant file + test set first
50
50
  6. Scan recent `docs/WORKLOG.md` entries if continuing prior work
@@ -138,7 +138,7 @@ Project đang ở đâu, làm gì tiếp?
138
138
 
139
139
  Expected UKit behavior:
140
140
  1. auto-load the hidden next-step lane
141
- 2. read `docs/AI_HANDOFF.md` when the team is passing planning, task breakdown, or implementation context between AIs
141
+ 2. read `docs/AI_HANDOFF/ACTIVE.md` when the team is passing planning, task breakdown, or implementation context between AIs
142
142
  3. verify the handoff against source/index before treating it as authoritative
143
143
  4. suggest only a few actionable next candidates
144
144
  5. if the prompt names a concrete bug/feature/review target, keep the concrete workflow primary instead of producing a global roadmap
@@ -2,6 +2,17 @@
2
2
 
3
3
  Track session-level execution details.
4
4
 
5
+ ## Budget Rules
6
+
7
+ Keep this file compact to save AI context tokens:
8
+
9
+ - **Max 30 entries.** When over, archive the oldest entries to `docs/WORKLOG_ARCHIVE.md`.
10
+ - **Max ~600 lines.** If over, archive oldest entries until under budget.
11
+ - Each entry should be 10-20 lines max (summary, not transcript).
12
+ - On archive: move full entry block to `docs/WORKLOG_ARCHIVE.md` (create if missing).
13
+ - Keep a compaction marker as the last line: `<!-- Entries before YYYY-MM archived to docs/WORKLOG_ARCHIVE.md. Keep this file < 600 lines. -->`
14
+ - If the user says "compact worklog" or "clean worklog", perform the archive pass and report what moved.
15
+
5
16
  For each significant action, append:
6
17
  - Date/time
7
18
  - Action taken
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.5.2",
2
+ "version": "1.5.4",
3
3
  "agent": "claude-code",
4
4
  "autonomy": {
5
5
  "level": "balanced",
@@ -1,118 +0,0 @@
1
- # AI Handoff — {{project.name}}
2
-
3
- Dùng file này làm active handoff duy nhất cho project.
4
- Source code và test vẫn là sự thật cuối cùng.
5
-
6
- ---
7
-
8
- ## 1. Current Cycle Snapshot
9
-
10
- - Handoff status: `draft | ready_for_planning | ready_for_breakdown | ready_for_implementation | blocked | ready_for_next_cycle | done`
11
- - Current phase: `planning | breakdown | implementation | verification | wrap_up | cleared`
12
- - Updated at:
13
- - Updated by AI:
14
- - Human decision needed: `yes | no`
15
- - Human decision summary:
16
-
17
- ---
18
-
19
- ## 2. Handoff Rules
20
-
21
- ### How human should submit ideas
22
- - Có thể nói tự nhiên: `ukit:handoff`, `đưa vào handoff`, `gom các ý tưởng này thành task`, `chia việc cho AI làm tiếp`.
23
- - Nếu request đã là task cụ thể, rõ file/logic/đầu ra hoặc đủ nhỏ để làm ngay, bypass handoff và thực hiện trực tiếp.
24
- - Nếu request là ý tưởng rộng, nhiều tính năng, cải tiến mơ hồ, brainstorming, nhiều plan/task, hoặc cần chia cho AI kế tiếp, dùng handoff.
25
-
26
- ### Default handoff flow
27
- 1. Capture ideas/request.
28
- 2. Write a concrete plan.
29
- 3. Split the plan into ordered tasks.
30
- 4. Add target files, verification, dependencies, acceptance criteria, and stop conditions.
31
- 5. Resolve `ready` tasks in order.
32
- 6. Update this file with results.
33
- 7. Clear active handoff by keeping summary + carry-forward backlog only.
34
-
35
- ### Fast-AI task gate
36
- Một task chỉ được là `ready` khi có:
37
- - target file/folder rõ;
38
- - action cụ thể;
39
- - dependency/blocker rõ;
40
- - verification rõ;
41
- - acceptance criteria rõ;
42
- - stop condition rõ;
43
- - không cần đoán product decision.
44
-
45
- Nếu thiếu, để `needs_breakdown`, `blocked`, hoặc `needs_human`.
46
-
47
- ### Clear rule
48
- - `clear handoff` không bao giờ là wipe mù.
49
- - Trước khi clear, AI phải resolve hoặc triage task còn lại.
50
- - Completed work thành summary ngắn.
51
- - Unfinished work thành carry-forward backlog ngắn.
52
- - Sau clear, file phải ngắn, sẵn sàng cho cycle tiếp theo.
53
-
54
- ### Docs sync rule
55
- - Handoff không thay thế docs.
56
- - Sau khi xong cycle, update các file docs trực tiếp bị ảnh hưởng như `docs/WORKLOG.md`, `docs/PROJECT.md`, `docs/CODE_MAP.md`, `CHANGELOG.md` nếu có liên quan.
57
- - Không cần update toàn bộ `docs/` nếu không bị ảnh hưởng.
58
-
59
- ---
60
-
61
- ## 3. Completed Cycle Summary
62
-
63
- ### Cycle summary
64
- - completed:
65
- - verification:
66
- - important decisions:
67
- - carry-forward needed:
68
-
69
- ---
70
-
71
- ## 4. Carry-Forward Backlog
72
-
73
- ### TASK-001
74
- - Title:
75
- - Priority: `P0-now | P1-next | P2-later | blocked | needs_human`
76
- - Size: `S | M | L`
77
- - AI capability: `fast_ai_ok | needs_smart_ai | needs_human`
78
- - Goal:
79
- - Target files:
80
- - Dependencies:
81
- - Must do:
82
- - Must not do:
83
- - Acceptance criteria:
84
- - Verification:
85
- - Stop condition:
86
- - Status: `ready | blocked | in_progress | done | needs_breakdown | needs_human`
87
- - Owner AI:
88
-
89
- ### TASK-002
90
- - Title:
91
- - Priority: `P0-now | P1-next | P2-later | blocked | needs_human`
92
- - Size: `S | M | L`
93
- - AI capability: `fast_ai_ok | needs_smart_ai | needs_human`
94
- - Goal:
95
- - Target files:
96
- - Dependencies:
97
- - Must do:
98
- - Must not do:
99
- - Acceptance criteria:
100
- - Verification:
101
- - Stop condition:
102
- - Status: `ready | blocked | in_progress | done | needs_breakdown | needs_human`
103
- - Owner AI:
104
-
105
- ---
106
-
107
- ## 5. Decisions Made By Human
108
-
109
- -
110
- -
111
-
112
- ---
113
-
114
- ## 6. Do Not Lose This Context
115
-
116
- -
117
- -
118
- -