@ngockhoale/ukit 1.5.1 → 1.5.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.
- package/CHANGELOG.md +24 -0
- package/README.md +3 -5
- package/manifests/platform.full.yaml +5 -20
- package/package.json +1 -1
- package/src/cli/commands/doctor.js +2 -4
- package/src/cli/commands/install.js +3 -3
- package/src/cli/commands/uninstall.js +1 -1
- package/src/core/ensureGitignore.js +0 -2
- package/src/core/runtimeConfig.js +1 -1
- package/src/index/taskRouting.js +23 -2
- package/templates/.claude/skills/next-step/SKILL.md +6 -5
- package/templates/.claude/ukit/index/post-edit-verify.mjs +11 -3
- package/templates/.claude/ukit/index/route-task.mjs +20 -2
- package/templates/docs/AI_HANDOFF.md +118 -0
- package/templates/docs/INSTALL.md +2 -4
- package/templates/docs/PROJECT.md +5 -6
- package/templates/docs/UKIT_USAGE_GUIDE.md +3 -4
- package/templates/ukit/storage/config.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to UKit are documented here.
|
|
4
4
|
|
|
5
|
+
## 1.5.2 - 2026-05-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- 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.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
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.
|
|
17
|
+
- Updated `route-task` mirror and hook behavior in both source and installed artifact so `ukit install` users get consistent handoff routing.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Handoff authoring is now advisory (exit 0) in Safe Patch, so large `docs/AI_HANDOFF.md` batches no longer block the handoff workflow.
|
|
22
|
+
- Hard runtime/shared-risk file broad rewrites still block by default unless `advisoryOnly=true` or `UKIT_SAFE_PATCH_ADVISORY=1` is set.
|
|
23
|
+
|
|
24
|
+
### Tests
|
|
25
|
+
|
|
26
|
+
- Added explicit handoff routing coverage in `tests/index/taskRouting.test.js`.
|
|
27
|
+
- Verified Safe Patch protocol still passes 12 tests including the new handoff advisory case.
|
|
28
|
+
|
|
5
29
|
## 1.5.0 - 2026-05-24
|
|
6
30
|
|
|
7
31
|
### Fixed
|
package/README.md
CHANGED
|
@@ -32,8 +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/
|
|
36
|
-
- `docs/TASKS.md`
|
|
35
|
+
- `docs/AI_HANDOFF.md`
|
|
37
36
|
- `docs/WORKLOG.md`
|
|
38
37
|
5. Open your AI tool and work in natural language.
|
|
39
38
|
|
|
@@ -66,7 +65,7 @@ If maintainers roll out a newer CLI build, the in-project workflow still stays t
|
|
|
66
65
|
**Project support files**
|
|
67
66
|
- `.claude/ukit/.ukit/` — installer manifests, metadata, backups
|
|
68
67
|
- `.ukit/` — hidden shared runtime storage for config, cache, and cross-agent memory
|
|
69
|
-
- `docs/` — PROJECT / MEMORY /
|
|
68
|
+
- `docs/` — PROJECT / MEMORY / AI_HANDOFF / WORKLOG baseline
|
|
70
69
|
|
|
71
70
|
## UKit v1.3.1 Runtime
|
|
72
71
|
|
|
@@ -91,8 +90,7 @@ UKit v1.3.1 keeps the same shared runtime contract while adding Safe Patch Proto
|
|
|
91
90
|
- install globally with `npm install -g @ngockhoale/ukit`
|
|
92
91
|
- keep using the exact same human workflow inside projects: `ukit install`
|
|
93
92
|
- preserve the same `ukit` binary, hooks, and install-first orchestration while standardizing the runtime root as hidden `.ukit/`
|
|
94
|
-
- install `docs/
|
|
95
|
-
- install gitignored `docs/TASKS.md` as a local AI task queue for deferred/ready work, with safe AI cleanup rules that remove duplicates and prune completed history without deleting unfinished human intent
|
|
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
|
|
96
94
|
- auto-route open-ended “what next?” / “continue” prompts to the `next-step` skill with a visible freshness cue when status may be stale
|
|
97
95
|
- auto-route explicit handoff/wrap-up requests to the `update-status` skill while skipping trivial/no-state-change tasks
|
|
98
96
|
- keep concrete debug/implementation/review prompts primary, so project status never replaces source/index-first task work
|
|
@@ -143,10 +143,10 @@ items:
|
|
|
143
143
|
packs:
|
|
144
144
|
- core
|
|
145
145
|
|
|
146
|
-
- id: docs-
|
|
146
|
+
- id: docs-ai-handoff
|
|
147
147
|
type: config
|
|
148
|
-
sourceTemplate: docs/
|
|
149
|
-
targetPath: docs/
|
|
148
|
+
sourceTemplate: docs/AI_HANDOFF.md
|
|
149
|
+
targetPath: docs/AI_HANDOFF.md
|
|
150
150
|
requires:
|
|
151
151
|
- docs-project
|
|
152
152
|
- docs-memory
|
|
@@ -159,19 +159,6 @@ items:
|
|
|
159
159
|
packs:
|
|
160
160
|
- core
|
|
161
161
|
|
|
162
|
-
- id: docs-tasks
|
|
163
|
-
type: config
|
|
164
|
-
sourceTemplate: docs/TASKS.md
|
|
165
|
-
targetPath: docs/TASKS.md
|
|
166
|
-
requires:
|
|
167
|
-
- docs-status
|
|
168
|
-
mergeStrategy: skip
|
|
169
|
-
variables:
|
|
170
|
-
- project.name
|
|
171
|
-
enabledByDefault: true
|
|
172
|
-
packs:
|
|
173
|
-
- core
|
|
174
|
-
|
|
175
162
|
- id: docs-bugfix
|
|
176
163
|
type: config
|
|
177
164
|
sourceTemplate: docs/BUGFIX.md
|
|
@@ -495,8 +482,7 @@ items:
|
|
|
495
482
|
targetPath: .claude/skills/next-step/SKILL.md
|
|
496
483
|
requires:
|
|
497
484
|
- docs-quality-skill
|
|
498
|
-
- docs-
|
|
499
|
-
- docs-tasks
|
|
485
|
+
- docs-ai-handoff
|
|
500
486
|
mergeStrategy: overwrite_with_backup
|
|
501
487
|
variables: []
|
|
502
488
|
enabledByDefault: true
|
|
@@ -509,8 +495,7 @@ items:
|
|
|
509
495
|
targetPath: .claude/skills/update-status/SKILL.md
|
|
510
496
|
requires:
|
|
511
497
|
- docs-quality-skill
|
|
512
|
-
- docs-
|
|
513
|
-
- docs-tasks
|
|
498
|
+
- docs-ai-handoff
|
|
514
499
|
mergeStrategy: overwrite_with_backup
|
|
515
500
|
variables: []
|
|
516
501
|
enabledByDefault: true
|
package/package.json
CHANGED
|
@@ -62,8 +62,7 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [] }) {
|
|
|
62
62
|
sessionMemoryDirExists: await pathExists(runtimePaths.sessionsDir),
|
|
63
63
|
docsProjectExists: await pathExists(path.join(projectRoot, 'docs', 'PROJECT.md')),
|
|
64
64
|
docsMemoryExists: await pathExists(path.join(projectRoot, 'docs', 'MEMORY.md')),
|
|
65
|
-
|
|
66
|
-
docsTasksExists: await pathExists(path.join(projectRoot, 'docs', 'TASKS.md')),
|
|
65
|
+
docsAiHandoffExists: await pathExists(path.join(projectRoot, 'docs', 'AI_HANDOFF.md')),
|
|
67
66
|
docsWorklogExists: await pathExists(path.join(projectRoot, 'docs', 'WORKLOG.md')),
|
|
68
67
|
allProvidersConfigured: providers.allSupported,
|
|
69
68
|
...(codexAdapterTracked
|
|
@@ -105,8 +104,7 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [] }) {
|
|
|
105
104
|
console.log(`[UKit] ${ok(checks.sessionMemoryDirExists)} .ukit/storage/memory/sessions/`);
|
|
106
105
|
console.log(`[UKit] ${ok(checks.docsProjectExists)} docs/PROJECT.md`);
|
|
107
106
|
console.log(`[UKit] ${ok(checks.docsMemoryExists)} docs/MEMORY.md`);
|
|
108
|
-
console.log(`[UKit] ${ok(checks.
|
|
109
|
-
console.log(`[UKit] ${ok(checks.docsTasksExists)} docs/TASKS.md`);
|
|
107
|
+
console.log(`[UKit] ${ok(checks.docsAiHandoffExists)} docs/AI_HANDOFF.md`);
|
|
110
108
|
console.log(`[UKit] ${ok(checks.docsWorklogExists)} docs/WORKLOG.md`);
|
|
111
109
|
if (codexAdapterTracked) {
|
|
112
110
|
console.log(`[UKit] ${ok(checks.codexReadmeExists)} .codex/README.md`);
|
|
@@ -239,10 +239,10 @@ export async function runInstall({ packageRoot, projectRoot, packageVersion, arg
|
|
|
239
239
|
const docsLabels = [
|
|
240
240
|
'docs/PROJECT.md',
|
|
241
241
|
'docs/MEMORY.md',
|
|
242
|
-
'docs/
|
|
243
|
-
'docs/TASKS.md',
|
|
242
|
+
'docs/AI_HANDOFF.md',
|
|
244
243
|
'docs/WORKLOG.md',
|
|
245
244
|
];
|
|
245
|
+
|
|
246
246
|
const docsPaths = docsLabels.map((label) => path.join(projectRoot, ...label.split('/')));
|
|
247
247
|
const missingDocs = [];
|
|
248
248
|
for (let i = 0; i < docsPaths.length; i++) {
|
|
@@ -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/
|
|
257
|
+
console.log('[UKit] Docs baseline ready: docs/PROJECT.md, docs/MEMORY.md, docs/AI_HANDOFF.md, 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/
|
|
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.');
|
|
51
51
|
}
|
package/src/index/taskRouting.js
CHANGED
|
@@ -243,8 +243,10 @@ export function buildRouteSummary({
|
|
|
243
243
|
),
|
|
244
244
|
);
|
|
245
245
|
const nextActionCommand = compactHelperLane ? null : nextAction?.command ?? null;
|
|
246
|
+
const handoffFile = routingContext.intentMode === 'handoff' ? 'docs/AI_HANDOFF.md' : null;
|
|
246
247
|
const summaryLine = [
|
|
247
248
|
routingContext.taskType ? `task=${routingContext.taskType}` : null,
|
|
249
|
+
handoffFile ? `handoff=${handoffFile}` : null,
|
|
248
250
|
formatCompactSegment('targets', primaryTargets),
|
|
249
251
|
formatCompactSegment('tests', relatedTests),
|
|
250
252
|
formatCompactSegment('styles', styleFiles),
|
|
@@ -267,6 +269,7 @@ export function buildRouteSummary({
|
|
|
267
269
|
completionState,
|
|
268
270
|
continuationState,
|
|
269
271
|
intentMode: routingContext.intentMode ?? null,
|
|
272
|
+
handoffFile,
|
|
270
273
|
delegateHint: delegationRecommendation?.hint ?? null,
|
|
271
274
|
nextActionType: nextAction?.type ?? null,
|
|
272
275
|
nextActionCommand,
|
|
@@ -783,11 +786,11 @@ async function selectActiveSkills({ rootDir, promptText, commandText, targetFile
|
|
|
783
786
|
}
|
|
784
787
|
|
|
785
788
|
function shouldKeepRouteEntryForIntent(entry, intentMode) {
|
|
786
|
-
if (entry.id === 'next-step' && ['scoped-advice', 'docs-specific'].includes(intentMode)) {
|
|
789
|
+
if (entry.id === 'next-step' && ['scoped-advice', 'docs-specific', 'handoff'].includes(intentMode)) {
|
|
787
790
|
return false;
|
|
788
791
|
}
|
|
789
792
|
|
|
790
|
-
if (entry.id === 'update-status' &&
|
|
793
|
+
if (entry.id === 'update-status' && ['docs-specific', 'handoff'].includes(intentMode)) {
|
|
791
794
|
return false;
|
|
792
795
|
}
|
|
793
796
|
|
|
@@ -896,6 +899,10 @@ function deriveIntentMode({ promptText = '', commandText = '', targetFile = null
|
|
|
896
899
|
const openEndedStatus = hasOpenEndedStatusSignal(lower, raw) || taskQueueNext;
|
|
897
900
|
const concreteTask = hasConcreteTaskSignal(lower, raw, targetFile, { taskQueueNext });
|
|
898
901
|
|
|
902
|
+
if (hasHandoffSignal(lower, raw)) {
|
|
903
|
+
return 'handoff';
|
|
904
|
+
}
|
|
905
|
+
|
|
899
906
|
if (docsSpecific) {
|
|
900
907
|
return 'docs-specific';
|
|
901
908
|
}
|
|
@@ -927,6 +934,20 @@ function deriveIntentMode({ promptText = '', commandText = '', targetFile = null
|
|
|
927
934
|
return null;
|
|
928
935
|
}
|
|
929
936
|
|
|
937
|
+
function hasHandoffSignal(lower, raw) {
|
|
938
|
+
return /\bukit:handoff\b/.test(raw)
|
|
939
|
+
|| /\b(ai handoff|handoff phase|handoff mode|clear handoff|update handoff|start handoff|handoff clear)\b/.test(lower)
|
|
940
|
+
|| /\b(brainstorm|idea dump|ideas?).{0,80}\b(handoff|tasks?|taskify|split|breakdown)\b/.test(lower)
|
|
941
|
+
|| /\b(handoff|tasks?|taskify|split|breakdown).{0,80}\b(brainstorm|idea dump|ideas?)\b/.test(lower)
|
|
942
|
+
|| /\b(gom|chia|tach|tách|lên|len|xóa|clear|dọn).{0,80}\b(idea|ý tưởng|y tuong|task|công việc|cong viec|handoff)\b/.test(raw)
|
|
943
|
+
|| /\b(bàn giao|ban giao).{0,80}\b(ai|task|công việc|cong viec)\b/.test(raw);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function hasHandoffClearSignal(lower, raw) {
|
|
947
|
+
return /\b(clear handoff|handoff clear|dọn handoff|xóa handoff|reset handoff|compact handoff)\b/.test(lower)
|
|
948
|
+
|| (/\bukit:handoff\b/.test(raw) && /\b(clear|dọn|xóa|reset|compact)\b/.test(lower));
|
|
949
|
+
}
|
|
950
|
+
|
|
930
951
|
function hasStatusUpdateSignal(lower, raw) {
|
|
931
952
|
return /\b(update|refresh|write|sync|record|capture|summarize|summarise).{0,64}\b(status\.md|project status|current state|next candidates|session state)\b/.test(lower)
|
|
932
953
|
|| /\b(status\.md|project status).{0,64}\b(update|refresh|write|sync|record|capture|summarize|summarise)\b/.test(lower)
|
|
@@ -44,11 +44,12 @@ 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/
|
|
48
|
-
2. `docs/
|
|
49
|
-
3. `docs/
|
|
50
|
-
4. `docs/
|
|
51
|
-
5.
|
|
47
|
+
1. `docs/AI_HANDOFF.md` first when the prompt explicitly names handoff / `ukit:handoff` / brainstorm-to-task flow
|
|
48
|
+
2. `docs/STATUS.md` (or existing root `STATUS.md` fallback) for normal status/continue prompts
|
|
49
|
+
3. `docs/TASKS.md` only for queued-task prompts, “continue” with no active status, or when status points at queued work
|
|
50
|
+
4. `docs/CODE_MAP.md` only when navigation is needed
|
|
51
|
+
5. `docs/MEMORY.md` only when constraints/decisions affect the suggestion
|
|
52
|
+
6. routed index/tree summary only if status/tasks are stale, missing, or contradicted
|
|
52
53
|
|
|
53
54
|
## Output Shape
|
|
54
55
|
|
|
@@ -17,6 +17,10 @@ function getFilePath(payload = {}) {
|
|
|
17
17
|
return payload.tool_input?.file_path || payload.file_path || '';
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function isHandoffAuthoringFile(relativePath) {
|
|
21
|
+
return relativePath === 'docs/AI_HANDOFF.md';
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
async function listManifestPaths(backupsRoot) {
|
|
21
25
|
const dates = await fs.readdir(backupsRoot, { withFileTypes: true }).catch(() => []);
|
|
22
26
|
return dates
|
|
@@ -152,7 +156,8 @@ export async function verifyPostEdit({ projectRoot = process.cwd(), payload = {}
|
|
|
152
156
|
|
|
153
157
|
const overChangedLines = delta.changedLines > Number(config.deltaMaxChangedLines || 120);
|
|
154
158
|
const overHunks = delta.hunkCount > Number(config.deltaMaxHunks || 3);
|
|
155
|
-
const
|
|
159
|
+
const handoffAdvisory = isHandoffAuthoringFile(resolved.relative) && risk.labels.every((label) => ['large-file', 'multilingual-text'].includes(label));
|
|
160
|
+
const status = risk.strict && (overChangedLines || overHunks) ? (handoffAdvisory ? 'advisory' : 'blocked') : 'ok';
|
|
156
161
|
const postEntry = {
|
|
157
162
|
event: 'post-edit',
|
|
158
163
|
file: resolved.relative,
|
|
@@ -169,8 +174,8 @@ export async function verifyPostEdit({ projectRoot = process.cwd(), payload = {}
|
|
|
169
174
|
|
|
170
175
|
return {
|
|
171
176
|
...postEntry,
|
|
172
|
-
message: status === 'blocked'
|
|
173
|
-
?
|
|
177
|
+
message: status === 'blocked' || status === 'advisory'
|
|
178
|
+
? `${status === 'advisory' ? 'ADVISORY' : 'BLOCKED'}: '${resolved.relative}' exceeded Safe Patch delta budget (changedLines=${delta.changedLines}/${config.deltaMaxChangedLines}, hunks=${delta.hunkCount}/${config.deltaMaxHunks}). Review diff or restore from ${latest.entry.rollbackPath}.`
|
|
174
179
|
: `OK: '${resolved.relative}' delta changedLines=${delta.changedLines}, hunks=${delta.hunkCount}.`,
|
|
175
180
|
};
|
|
176
181
|
}
|
|
@@ -193,6 +198,9 @@ async function main() {
|
|
|
193
198
|
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
194
199
|
} else if (result.status === 'ok') {
|
|
195
200
|
process.stdout.write(`[ukit-safe-patch] ${result.message}\n`);
|
|
201
|
+
} else if (result.status === 'advisory') {
|
|
202
|
+
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');
|
|
196
204
|
}
|
|
197
205
|
if (result.status === 'blocked') {
|
|
198
206
|
const advisory = isSafePatchAdvisoryOnly(runtimeConfig);
|
|
@@ -723,11 +723,11 @@ async function selectActiveSkills({ rootDir, promptText, commandText, targetFile
|
|
|
723
723
|
}
|
|
724
724
|
|
|
725
725
|
function shouldKeepRouteEntryForIntent(entry, intentMode) {
|
|
726
|
-
if (entry.id === 'next-step' && ['scoped-advice', 'docs-specific'].includes(intentMode)) {
|
|
726
|
+
if (entry.id === 'next-step' && ['scoped-advice', 'docs-specific', 'handoff'].includes(intentMode)) {
|
|
727
727
|
return false;
|
|
728
728
|
}
|
|
729
729
|
|
|
730
|
-
if (entry.id === 'update-status' &&
|
|
730
|
+
if (entry.id === 'update-status' && ['docs-specific', 'handoff'].includes(intentMode)) {
|
|
731
731
|
return false;
|
|
732
732
|
}
|
|
733
733
|
|
|
@@ -835,6 +835,10 @@ function deriveIntentMode({ promptText = '', commandText = '', targetFile = null
|
|
|
835
835
|
return 'docs-specific';
|
|
836
836
|
}
|
|
837
837
|
|
|
838
|
+
if (hasHandoffSignal(lower, raw)) {
|
|
839
|
+
return 'handoff';
|
|
840
|
+
}
|
|
841
|
+
|
|
838
842
|
if (statusUpdate) {
|
|
839
843
|
return 'status-update';
|
|
840
844
|
}
|
|
@@ -870,6 +874,20 @@ function hasStatusUpdateSignal(lower, raw) {
|
|
|
870
874
|
|| /\b(cập nhật|ghi lại|tổng kết|chốt session|bàn giao).{0,64}\b(status|trạng thái|việc tiếp theo)\b/.test(raw);
|
|
871
875
|
}
|
|
872
876
|
|
|
877
|
+
function hasHandoffSignal(lower, raw) {
|
|
878
|
+
return /\bukit:handoff\b/.test(raw)
|
|
879
|
+
|| /\b(ai handoff|handoff phase|handoff mode|clear handoff|update handoff|start handoff|handoff clear)\b/.test(lower)
|
|
880
|
+
|| /\b(brainstorm|idea dump|ideas?).{0,80}\b(handoff|tasks?|taskify|split|breakdown)\b/.test(lower)
|
|
881
|
+
|| /\b(handoff|tasks?|taskify|split|breakdown).{0,80}\b(brainstorm|idea dump|ideas?)\b/.test(lower)
|
|
882
|
+
|| /\b(gom|chia|tach|tách|lên|len|xóa|clear|dọn).{0,80}\b(idea|ý tưởng|y tuong|task|công việc|cong viec|handoff)\b/.test(raw)
|
|
883
|
+
|| /\b(bàn giao|ban giao).{0,80}\b(ai|task|công việc|cong viec)\b/.test(raw);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
function hasHandoffClearSignal(lower, raw) {
|
|
887
|
+
return /\b(clear handoff|handoff clear|dọn handoff|xóa handoff|reset handoff|compact handoff)\b/.test(lower)
|
|
888
|
+
|| (/\bukit:handoff\b/.test(raw) && /\b(clear|dọn|xóa|reset|compact)\b/.test(lower));
|
|
889
|
+
}
|
|
890
|
+
|
|
873
891
|
function hasOpenEndedStatusSignal(lower, raw) {
|
|
874
892
|
return /\b(what next|what is next|what's next|next step|next steps|project status|current status|where are we|continue|continue from last session|roadmap|status\.md|task queue|tasks\.md|next queued task|pick next task|work from tasks)\b/.test(lower)
|
|
875
893
|
|| /\b(lam gi tiep|buoc tiep theo|tiep theo lam gi|lam tiep|dang o dau|trang thai project|tinh trang project|task tiep theo|viec tiep theo trong tasks)\b/.test(lower)
|
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
-
|
|
@@ -47,8 +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/
|
|
51
|
-
- `docs/TASKS.md`
|
|
50
|
+
- `docs/AI_HANDOFF.md`
|
|
52
51
|
- `docs/WORKLOG.md`
|
|
53
52
|
|
|
54
53
|
### 4) Open your AI tool
|
|
@@ -98,8 +97,7 @@ ukit install
|
|
|
98
97
|
Check that the docs baseline files exist and are filled in:
|
|
99
98
|
- `docs/PROJECT.md`
|
|
100
99
|
- `docs/MEMORY.md`
|
|
101
|
-
- `docs/
|
|
102
|
-
- `docs/TASKS.md`
|
|
100
|
+
- `docs/AI_HANDOFF.md`
|
|
103
101
|
- `docs/WORKLOG.md`
|
|
104
102
|
|
|
105
103
|
---
|
|
@@ -44,9 +44,8 @@
|
|
|
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/
|
|
48
|
-
4. Read `docs/
|
|
49
|
-
5.
|
|
50
|
-
6.
|
|
51
|
-
7.
|
|
52
|
-
8. Verify understanding against source before acting — **docs orient, source is truth; keep the index-first workflow intact**
|
|
47
|
+
3. Read `docs/AI_HANDOFF.md` when continuing cross-AI planning, task breakdown, or task implementation handoff work
|
|
48
|
+
4. Read `docs/CODE_MAP.md` if it exists — structural navigation index
|
|
49
|
+
5. Use the installed source-code index / routed helpers to localize the smallest relevant file + test set first
|
|
50
|
+
6. Scan recent `docs/WORKLOG.md` entries if continuing prior work
|
|
51
|
+
7. Verify understanding against source before acting — **docs orient, source is truth; keep the index-first workflow intact**
|
|
@@ -138,11 +138,10 @@ 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/
|
|
142
|
-
3.
|
|
141
|
+
2. read `docs/AI_HANDOFF.md` when the team is passing planning, task breakdown, or implementation context between AIs
|
|
142
|
+
3. verify the handoff against source/index before treating it as authoritative
|
|
143
143
|
4. suggest only a few actionable next candidates
|
|
144
|
-
5. if
|
|
145
|
-
6. if the prompt names a concrete bug/feature/review target, keep the concrete workflow primary instead of producing a global roadmap
|
|
144
|
+
5. if the prompt names a concrete bug/feature/review target, keep the concrete workflow primary instead of producing a global roadmap
|
|
146
145
|
|
|
147
146
|
---
|
|
148
147
|
|