@linimin/pi-letscook 0.1.59 → 0.1.61
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/.agent/mission.md +1 -1
- package/CHANGELOG.md +4 -5
- package/README.md +26 -28
- package/extensions/completion/driver.ts +45 -26
- package/extensions/completion/index.ts +76 -63
- package/extensions/completion/prompt-surfaces.ts +15 -13
- package/extensions/completion/proposal.ts +28 -1
- package/package.json +1 -1
- package/scripts/context-proposal-test.sh +40 -112
- package/scripts/refocus-test.sh +4 -4
- package/scripts/release-check.sh +17 -23
- package/scripts/smoke-test.sh +9 -13
- package/skills/cook-handoff-boundary/SKILL.md +56 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linimin/pi-letscook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.61",
|
|
4
4
|
"description": "Pi package for long-running completion workflows with canonical .agent state, role-based subagents, continuity, and verification helpers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -147,30 +147,36 @@ mkdir -p "$ROOT"
|
|
|
147
147
|
cd "$ROOT"
|
|
148
148
|
git init -q
|
|
149
149
|
|
|
150
|
-
# No workflow yet: bare /cook should
|
|
151
|
-
# even when
|
|
150
|
+
# No workflow yet: bare /cook should synthesize a deferred startup brief from recent discussion,
|
|
151
|
+
# even when no explicit ordinary-chat handoff capsule exists.
|
|
152
152
|
SESSION_ZERO="$TMPDIR/session-zero.jsonl"
|
|
153
153
|
DISCUSSION_ZERO=$'Mission: Remove the completion status line while keeping the completion widget.\nScope:\n- Keep the non-running completion widget.\n- Suppress the widget while a completion role is active.\nConstraints:\n- Do not reintroduce any other completion status surface.\nAcceptance:\n- Update README to match the shipped behavior.\n- Keep observability regression coverage truthful.'
|
|
154
154
|
DISCUSSION_SNAPSHOT_ZERO="$TMPDIR/context-proposal-structured-fallback.json"
|
|
155
155
|
write_session "$SESSION_ZERO" "$ROOT" "$DISCUSSION_ZERO"
|
|
156
156
|
|
|
157
157
|
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
158
|
-
PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
|
|
159
158
|
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_ZERO" \
|
|
160
159
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
161
160
|
pi --session "$SESSION_ZERO" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-structured-fallback.out" 2>"$TMPDIR/pi-completion-context-proposal-structured-fallback.err"
|
|
162
161
|
|
|
163
162
|
python3 - "$TMPDIR/pi-completion-context-proposal-structured-fallback.out" "$TMPDIR/pi-completion-context-proposal-structured-fallback.err" "$DISCUSSION_SNAPSHOT_ZERO" <<'PY'
|
|
163
|
+
import json
|
|
164
164
|
import sys
|
|
165
165
|
from pathlib import Path
|
|
166
166
|
|
|
167
167
|
output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
168
168
|
snapshot = Path(sys.argv[3])
|
|
169
|
-
assert
|
|
170
|
-
assert
|
|
171
|
-
|
|
169
|
+
assert Path('.agent').exists(), 'bare /cook should scaffold canonical state from structured recent discussion'
|
|
170
|
+
assert snapshot.exists(), 'bare /cook should emit a startup proposal snapshot when recent discussion is concrete enough'
|
|
171
|
+
proposal = json.loads(snapshot.read_text())
|
|
172
|
+
brief = json.loads(Path('.agent/state.json').read_text())['advisory_startup_brief']
|
|
173
|
+
assert proposal['source'] == 'deferred_primary_agent_handoff', 'structured startup should snapshot the deferred primary-agent handoff source'
|
|
174
|
+
assert brief['source'] == 'deferred_primary_agent_handoff', 'structured startup should record the deferred primary-agent handoff source in advisory intake'
|
|
175
|
+
assert 'Initialized completion control plane' in output, 'structured startup should initialize canonical workflow state'
|
|
172
176
|
PY
|
|
173
177
|
|
|
178
|
+
rm -rf .agent
|
|
179
|
+
|
|
174
180
|
# No workflow yet: user-authored faux handoffs must not bootstrap canonical workflow state.
|
|
175
181
|
SESSION_ZERO_USER_AUTHORED="$TMPDIR/session-zero-user-authored.jsonl"
|
|
176
182
|
USER_AUTHORED_SNAPSHOT_ZERO="$TMPDIR/context-proposal-user-authored-handoff.json"
|
|
@@ -212,9 +218,9 @@ from pathlib import Path
|
|
|
212
218
|
|
|
213
219
|
output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
214
220
|
snapshot = Path(sys.argv[3])
|
|
215
|
-
assert not Path('.agent').exists(), 'user-authored faux handoff should fail closed without writing canonical state'
|
|
221
|
+
assert not Path('.agent').exists(), 'user-authored faux handoff without supporting discussion should still fail closed without writing canonical state'
|
|
216
222
|
assert not snapshot.exists(), 'user-authored faux handoff should not emit a startup proposal snapshot'
|
|
217
|
-
assert '
|
|
223
|
+
assert 'could not derive a concrete startup brief from recent discussion' in output, 'user-authored faux handoff should fall back to the deferred-synthesis fail-closed message'
|
|
218
224
|
PY
|
|
219
225
|
|
|
220
226
|
# No workflow yet: malformed or invalid assistant handoff capsules must also fail closed.
|
|
@@ -233,9 +239,9 @@ from pathlib import Path
|
|
|
233
239
|
|
|
234
240
|
output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
235
241
|
snapshot = Path(sys.argv[3])
|
|
236
|
-
assert not Path('.agent').exists(), 'invalid assistant handoff should fail closed without writing canonical state'
|
|
242
|
+
assert not Path('.agent').exists(), 'invalid assistant handoff without supporting discussion should fail closed without writing canonical state'
|
|
237
243
|
assert not snapshot.exists(), 'invalid assistant handoff should not emit a startup proposal snapshot'
|
|
238
|
-
assert '
|
|
244
|
+
assert 'could not derive a concrete startup brief from recent discussion' in output, 'invalid assistant handoff should explain the deferred-synthesis fail-closed contract'
|
|
239
245
|
PY
|
|
240
246
|
|
|
241
247
|
# No workflow yet: a fresh explicit primary-agent handoff should still bootstrap canonical startup state.
|
|
@@ -383,7 +389,7 @@ assert routing['mode'] == 'bare', 'active bare /cook resume regression should sn
|
|
|
383
389
|
assert 'explicitGoal' not in routing, 'active bare /cook resume routing should not expose removed explicit-goal shim fields'
|
|
384
390
|
assert 'explicitGoalProvided' not in routing, 'active bare /cook resume routing should not expose removed explicit-goal shim fields'
|
|
385
391
|
assert routing['action'] == 'continue', 'active bare /cook should resume when no fresh explicit handoff exists'
|
|
386
|
-
assert routing['reason'] == '
|
|
392
|
+
assert routing['reason'] == 'no_replacement_proposal', 'active bare /cook should explain that resume happened because no replacement mission was derived'
|
|
387
393
|
assert routing['currentMissionAnchor'] == mission, 'resume routing should preserve the current mission anchor'
|
|
388
394
|
assert routing['proposedMissionAnchor'] is None, 'resume routing should not derive a replacement mission from recent discussion'
|
|
389
395
|
assert 'Resume the completion workflow from canonical state.' in resume, 'active bare /cook resume should still use the canonical resume prompt'
|
|
@@ -428,7 +434,7 @@ active = json.loads(Path('.agent/active-slice.json').read_text())
|
|
|
428
434
|
|
|
429
435
|
assert routing['mode'] == 'bare', 'discussion-driven refocus removal should snapshot bare routing mode'
|
|
430
436
|
assert routing['action'] == 'continue', 'bare /cook should resume instead of deriving a replacement workflow from recent discussion'
|
|
431
|
-
assert routing['reason'] == '
|
|
437
|
+
assert routing['reason'] == 'no_replacement_proposal', 'discussion-driven refocus removal should explain that no replacement mission was derived'
|
|
432
438
|
assert routing['currentMissionAnchor'] == mission, 'discussion-driven refocus removal should preserve the current mission anchor'
|
|
433
439
|
assert routing['proposedMissionAnchor'] is None, 'discussion-driven refocus removal should not preserve a replacement mission from recent discussion'
|
|
434
440
|
assert 'Resume the completion workflow from canonical state.' in resume, 'discussion-driven refocus removal should still queue the canonical resume prompt'
|
|
@@ -502,7 +508,7 @@ active = json.loads(Path('.agent/active-slice.json').read_text())
|
|
|
502
508
|
|
|
503
509
|
assert routing['mode'] == 'bare', 'summary-only active bare /cook regression should snapshot bare routing mode'
|
|
504
510
|
assert routing['action'] == 'continue', 'summary-only active bare /cook should resume rather than derive replacement startup'
|
|
505
|
-
assert routing['reason'] == '
|
|
511
|
+
assert routing['reason'] == 'no_replacement_proposal', 'summary-only active bare /cook should explain that no replacement mission was derived'
|
|
506
512
|
assert routing['currentMissionAnchor'] == mission, 'summary-only active bare /cook should preserve the current mission anchor'
|
|
507
513
|
assert routing['proposedMissionAnchor'] is None, 'summary-only active bare /cook should not derive a replacement mission from summary artifacts alone'
|
|
508
514
|
assert 'Resume the completion workflow from canonical state.' in resume, 'summary-only active bare /cook should still resume the canonical workflow'
|
|
@@ -607,7 +613,7 @@ after = {
|
|
|
607
613
|
|
|
608
614
|
assert routing['mode'] == 'bare', 'fresh non-startable explicit handoff should snapshot bare routing mode'
|
|
609
615
|
assert routing['action'] == 'blocked', 'fresh non-startable explicit handoff should fail closed for active bare /cook'
|
|
610
|
-
assert routing['reason'] == '
|
|
616
|
+
assert routing['reason'] == 'replacement_not_startable', 'fresh non-startable explicit handoff should keep the dedicated replacement fail-closed reason'
|
|
611
617
|
assert 'fresh explicit primary-agent handoff exists' in routing['blockedFailureMessage'], 'fresh non-startable explicit handoff should surface the dedicated fail-closed message'
|
|
612
618
|
assert 'acceptance is not anchored to concrete repo changes or verification' in routing['blockedFailureMessage'], 'fresh non-startable explicit handoff should explain why the capsule is not startable'
|
|
613
619
|
assert not resume_path.exists(), 'fresh non-startable explicit handoff should not queue a resume prompt'
|
|
@@ -702,15 +708,14 @@ assert not snapshot.exists(), 'verification-evidence overlap suppression should
|
|
|
702
708
|
assert '/cook failed closed' in output, 'verification-evidence overlap suppression should fail closed when the latest discussion only repeats verified work'
|
|
703
709
|
PY
|
|
704
710
|
|
|
705
|
-
# Completed workflow: bare /cook should
|
|
706
|
-
# even when
|
|
711
|
+
# Completed workflow: bare /cook should synthesize the next round from discussion-only startup too,
|
|
712
|
+
# even when no explicit ordinary-chat handoff capsule exists.
|
|
707
713
|
SESSION_TWO_NORMALIZED="$TMPDIR/session-two-normalized.jsonl"
|
|
708
714
|
DISCUSSION_TWO_NORMALIZED=$'Mission: 開始實作這個方案\nScope:\n- Normalize bare /cook planning phrasing for the next workflow round.\n- Reset canonical state for the new implementation mission.\nConstraints:\n- Do not resume the completed workflow when the new round is clearly different.\nAcceptance:\n- Start a new round with the normalized mission anchor.'
|
|
709
715
|
DISCUSSION_SNAPSHOT_TWO_NORMALIZED="$TMPDIR/context-proposal-next-round-normalized.json"
|
|
710
716
|
write_session "$SESSION_TWO_NORMALIZED" "$ROOT" "$DISCUSSION_TWO_NORMALIZED"
|
|
711
717
|
|
|
712
718
|
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
713
|
-
PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
|
|
714
719
|
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_TWO_NORMALIZED" \
|
|
715
720
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
716
721
|
pi --session "$SESSION_TWO_NORMALIZED" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-next-round-normalized.out" 2>"$TMPDIR/pi-completion-context-proposal-next-round-normalized.err"
|
|
@@ -722,13 +727,15 @@ from pathlib import Path
|
|
|
722
727
|
|
|
723
728
|
output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
724
729
|
snapshot = Path(sys.argv[3])
|
|
725
|
-
|
|
730
|
+
previous = sys.argv[4]
|
|
726
731
|
state = json.loads(Path('.agent/state.json').read_text())
|
|
727
732
|
|
|
728
|
-
assert
|
|
729
|
-
|
|
730
|
-
assert state['
|
|
731
|
-
assert '
|
|
733
|
+
assert snapshot.exists(), 'done-workflow discussion-only startup should emit a proposal snapshot from deferred synthesis'
|
|
734
|
+
proposal = json.loads(snapshot.read_text())
|
|
735
|
+
assert state['mission_anchor'] != previous, 'done-workflow discussion-only startup should advance to the new mission anchor'
|
|
736
|
+
assert state['continuation_policy'] == 'continue', 'done-workflow discussion-only startup should reopen workflow state'
|
|
737
|
+
assert proposal['source'] == 'deferred_primary_agent_handoff', 'done-workflow discussion-only startup should snapshot the deferred handoff source'
|
|
738
|
+
assert 'Started a new completion workflow round from deferred primary-agent handoff' in output, 'done-workflow discussion-only startup should report deferred next-round startup'
|
|
732
739
|
PY
|
|
733
740
|
|
|
734
741
|
# Completed workflow: a fresh explicit primary-agent handoff should still start the next round.
|
|
@@ -947,8 +954,8 @@ after = {path.name: path.read_text() for path in tracked}
|
|
|
947
954
|
assert before == after, 'done /cook inline-args rejection should leave canonical files unchanged'
|
|
948
955
|
PY
|
|
949
956
|
|
|
950
|
-
# Completed workflow again: model-assisted discussion analysis alone should
|
|
951
|
-
#
|
|
957
|
+
# Completed workflow again: model-assisted discussion analysis alone should be able to
|
|
958
|
+
# synthesize the next round from explicit /cook entry.
|
|
952
959
|
mark_done
|
|
953
960
|
|
|
954
961
|
SESSION_FIVE="$TMPDIR/session-five.jsonl"
|
|
@@ -972,9 +979,9 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
|
972
979
|
snapshot = Path(sys.argv[3])
|
|
973
980
|
state = json.loads(Path('.agent/state.json').read_text())
|
|
974
981
|
|
|
975
|
-
assert
|
|
976
|
-
assert state['continuation_policy'] == '
|
|
977
|
-
assert '
|
|
982
|
+
assert snapshot.exists(), 'done-workflow analyst-only restart should emit a startup proposal snapshot'
|
|
983
|
+
assert state['continuation_policy'] == 'continue', 'done-workflow analyst-only restart should reopen the workflow'
|
|
984
|
+
assert 'deferred primary-agent handoff' in output, 'done-workflow analyst-only restart should report deferred startup'
|
|
978
985
|
PY
|
|
979
986
|
|
|
980
987
|
# Custom confirmation UI: start should render proposal content separately from approval-only Start/Cancel actions.
|
|
@@ -1200,85 +1207,6 @@ assert 'Why this slice first: The redirect callback bug is already bounded enoug
|
|
|
1200
1207
|
assert 'Primary-agent /cook handoff rationale: The implementation plan is concrete and ready for repo changes.' in state['advisory_startup_brief']['notes'], 'explicit handoff startup should preserve why_cook_now as notes'
|
|
1201
1208
|
PY
|
|
1202
1209
|
|
|
1203
|
-
# Fresh explicit handoff: later ordinary-chat follow-up before /cook should not invalidate startup.
|
|
1204
|
-
HANDOFF_ROOT_FOLLOWUP="$TMPDIR/handoff-root-followup"
|
|
1205
|
-
mkdir -p "$HANDOFF_ROOT_FOLLOWUP"
|
|
1206
|
-
cd "$HANDOFF_ROOT_FOLLOWUP"
|
|
1207
|
-
git init -q
|
|
1208
|
-
|
|
1209
|
-
HANDOFF_SESSION_FOLLOWUP="$TMPDIR/handoff-session-followup.jsonl"
|
|
1210
|
-
HANDOFF_SNAPSHOT_FOLLOWUP="$TMPDIR/handoff-proposal-followup.json"
|
|
1211
|
-
HANDOFF_MESSAGES_FOLLOWUP="$(python3 - <<'PY'
|
|
1212
|
-
import json
|
|
1213
|
-
capsule = {
|
|
1214
|
-
"kind": "cook_handoff",
|
|
1215
|
-
"source": "primary_agent",
|
|
1216
|
-
"captured_at": "2026-01-01T00:00:02.000Z",
|
|
1217
|
-
"source_turn_id": "m0002",
|
|
1218
|
-
"mission": "Fix login redirect callback behavior.",
|
|
1219
|
-
"scope": [
|
|
1220
|
-
"Update the callback redirect decision logic.",
|
|
1221
|
-
"Preserve the broader auth flow."
|
|
1222
|
-
],
|
|
1223
|
-
"constraints": [
|
|
1224
|
-
"Do not refactor the broader auth flow."
|
|
1225
|
-
],
|
|
1226
|
-
"acceptance": [
|
|
1227
|
-
"Add a regression test for returning to the requested page."
|
|
1228
|
-
],
|
|
1229
|
-
"risks": [
|
|
1230
|
-
"Late ordinary-chat clarifications should not force the user into a fresh handoff-only retry loop."
|
|
1231
|
-
],
|
|
1232
|
-
"notes": [
|
|
1233
|
-
"Keep the startup brief anchored to the explicit primary-agent handoff until a later assistant reply replaces it."
|
|
1234
|
-
],
|
|
1235
|
-
"handoff_kind": "implementation_workflow_handoff",
|
|
1236
|
-
"first_slice_goal": "Land the redirect callback fix and its regression coverage.",
|
|
1237
|
-
"first_slice_non_goals": [
|
|
1238
|
-
"Do not refactor the broader auth flow."
|
|
1239
|
-
],
|
|
1240
|
-
"implementation_surfaces": [
|
|
1241
|
-
"src/auth/redirect.ts",
|
|
1242
|
-
"tests/auth/redirect.spec.ts"
|
|
1243
|
-
],
|
|
1244
|
-
"verification_commands": [
|
|
1245
|
-
"npm test -- redirect.spec.ts"
|
|
1246
|
-
],
|
|
1247
|
-
"why_this_slice_first": "The redirect callback bug is already bounded enough to start implementation safely.",
|
|
1248
|
-
"task_type": "completion-workflow",
|
|
1249
|
-
"evaluation_profile": "completion-rubric-v1",
|
|
1250
|
-
"why_cook_now": "The implementation plan is concrete and ready for repo changes."
|
|
1251
|
-
}
|
|
1252
|
-
messages = [
|
|
1253
|
-
{"role": "user", "content": "Please think through the login redirect fix and tell me when it is ready for /cook."},
|
|
1254
|
-
{"role": "assistant", "content": "This task is now ready for /cook whenever you want to start implementation.\n\n```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```"},
|
|
1255
|
-
{"role": "user", "content": "Before I run /cook, one more clarification: keep the broader auth flow unchanged and keep the later verification focused on the redirect regression."},
|
|
1256
|
-
]
|
|
1257
|
-
print(json.dumps(messages, ensure_ascii=False))
|
|
1258
|
-
PY
|
|
1259
|
-
)"
|
|
1260
|
-
write_session_messages "$HANDOFF_SESSION_FOLLOWUP" "$HANDOFF_ROOT_FOLLOWUP" "$HANDOFF_MESSAGES_FOLLOWUP"
|
|
1261
|
-
|
|
1262
|
-
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
1263
|
-
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$HANDOFF_SNAPSHOT_FOLLOWUP" \
|
|
1264
|
-
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
1265
|
-
pi --session "$HANDOFF_SESSION_FOLLOWUP" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-handoff-followup.out" 2>"$TMPDIR/pi-completion-handoff-followup.err"
|
|
1266
|
-
|
|
1267
|
-
python3 - "$HANDOFF_SNAPSHOT_FOLLOWUP" <<'PY'
|
|
1268
|
-
import json
|
|
1269
|
-
import sys
|
|
1270
|
-
from pathlib import Path
|
|
1271
|
-
|
|
1272
|
-
snapshot = json.loads(Path(sys.argv[1]).read_text())
|
|
1273
|
-
state = json.loads(Path('.agent/state.json').read_text())
|
|
1274
|
-
|
|
1275
|
-
assert snapshot['source'] == 'handoff_capsule', 'later ordinary-chat follow-up should still use the explicit handoff capsule as startup source'
|
|
1276
|
-
assert snapshot['mission'] == 'Fix login redirect callback behavior.', 'later ordinary-chat follow-up should preserve the handoff mission'
|
|
1277
|
-
assert state['mission_anchor'] == 'Fix login redirect callback behavior.', 'later ordinary-chat follow-up should still start from the explicit handoff mission'
|
|
1278
|
-
assert state['advisory_startup_brief']['source'] == 'primary_agent_handoff', 'later ordinary-chat follow-up should keep the advisory intake source as the explicit handoff'
|
|
1279
|
-
assert 'Verification commands: npm test -- redirect.spec.ts' in state['advisory_startup_brief']['notes'], 'later ordinary-chat follow-up should preserve the handoff verification commands'
|
|
1280
|
-
PY
|
|
1281
|
-
|
|
1282
1210
|
# Fresh but non-startable explicit handoff: /cook should fail closed instead of falling back
|
|
1283
1211
|
# to a broad recent-discussion startup brief when the explicit capsule is still too vague.
|
|
1284
1212
|
HANDOFF_ROOT_VAGUE="$TMPDIR/handoff-root-vague"
|
|
@@ -1545,7 +1473,7 @@ assert 'First slice goal: Patch the callback edge case and cover it with a focus
|
|
|
1545
1473
|
assert 'Verification commands: npm test -- redirect-edge.spec.ts' in state['advisory_startup_brief']['notes'], 'done-workflow handoff should preserve verification_commands in advisory notes'
|
|
1546
1474
|
PY
|
|
1547
1475
|
|
|
1548
|
-
# Stale handoff:
|
|
1476
|
+
# Stale handoff: later discussion should invalidate the older handoff capsule and fail closed instead of falling back to newer discussion.
|
|
1549
1477
|
HANDOFF_ROOT_STALE="$TMPDIR/handoff-root-stale"
|
|
1550
1478
|
mkdir -p "$HANDOFF_ROOT_STALE"
|
|
1551
1479
|
cd "$HANDOFF_ROOT_STALE"
|
|
@@ -1558,7 +1486,7 @@ import json
|
|
|
1558
1486
|
capsule = {
|
|
1559
1487
|
"kind": "cook_handoff",
|
|
1560
1488
|
"source": "primary_agent",
|
|
1561
|
-
"captured_at": "
|
|
1489
|
+
"captured_at": "2026-01-01T00:00:02.000Z",
|
|
1562
1490
|
"source_turn_id": "m0002",
|
|
1563
1491
|
"mission": "Fix the original login redirect callback behavior.",
|
|
1564
1492
|
"scope": ["Update the original callback redirect logic."],
|
|
@@ -1571,7 +1499,7 @@ capsule = {
|
|
|
1571
1499
|
"first_slice_non_goals": ["Do not refactor the auth stack."],
|
|
1572
1500
|
"implementation_surfaces": ["src/auth/login-redirect.ts"],
|
|
1573
1501
|
"verification_commands": ["npm test -- login-redirect.spec.ts"],
|
|
1574
|
-
"why_this_slice_first": "The original callback follow-up was the first bounded implementation slice before
|
|
1502
|
+
"why_this_slice_first": "The original callback follow-up was the first bounded implementation slice before later discussion replaced it."
|
|
1575
1503
|
}
|
|
1576
1504
|
newer_discussion = "Mission: Ship logout redirect consistency instead.\nScope:\n- Update the logout redirect path.\nConstraints:\n- Leave the login callback flow unchanged.\nAcceptance:\n- Add a logout redirect regression test."
|
|
1577
1505
|
messages = [
|
|
@@ -1597,9 +1525,9 @@ from pathlib import Path
|
|
|
1597
1525
|
snapshot = Path(sys.argv[1])
|
|
1598
1526
|
output = Path(sys.argv[2]).read_text() + Path(sys.argv[3]).read_text()
|
|
1599
1527
|
|
|
1600
|
-
assert not snapshot.exists(), '
|
|
1601
|
-
assert not Path('.agent').exists(), '
|
|
1602
|
-
assert '
|
|
1528
|
+
assert not snapshot.exists(), 'stale handoff should not emit a startup proposal snapshot'
|
|
1529
|
+
assert not Path('.agent').exists(), 'stale handoff should fail closed without writing canonical state'
|
|
1530
|
+
assert 'could not derive a concrete startup brief from recent discussion' in output, 'stale handoff should explain that deferred startup synthesis failed closed'
|
|
1603
1531
|
PY
|
|
1604
1532
|
|
|
1605
1533
|
# Negative handoff rationale: a non-startable capsule must not become the startup mission.
|
package/scripts/refocus-test.sh
CHANGED
|
@@ -313,7 +313,7 @@ assert routing['mode'] == 'bare', 'supported refocus should use bare active-work
|
|
|
313
313
|
assert 'explicitGoal' not in routing, 'supported bare refocus should not expose removed explicit-goal shim fields'
|
|
314
314
|
assert 'explicitGoalProvided' not in routing, 'supported bare refocus should not expose removed explicit-goal shim fields'
|
|
315
315
|
assert routing['action'] == 'refocus', 'supported bare /cook should classify as refocus when a fresh explicit handoff proposes a different mission'
|
|
316
|
-
assert routing['reason'] == '
|
|
316
|
+
assert routing['reason'] == 'explicit_handoff_replacement', 'supported bare /cook should record the explicit-handoff replacement reason'
|
|
317
317
|
assert routing['proposedMissionAnchor'] == new_anchor, 'explicit handoff routing snapshot should expose the replacement mission anchor'
|
|
318
318
|
assert routing['proposalSource'] == 'handoff_capsule', 'explicit handoff routing snapshot should preserve the handoff source'
|
|
319
319
|
PY
|
|
@@ -411,7 +411,7 @@ assert routing['mode'] == 'bare', 'bare /cook should snapshot bare active-workfl
|
|
|
411
411
|
assert 'explicitGoal' not in routing, 'bare chooser routing should not expose removed explicit-goal shim fields'
|
|
412
412
|
assert 'explicitGoalProvided' not in routing, 'bare chooser routing should not expose removed explicit-goal shim fields'
|
|
413
413
|
assert routing['action'] == 'refocus', 'fresh explicit replacement handoff should classify active bare /cook as refocus'
|
|
414
|
-
assert routing['reason'] == '
|
|
414
|
+
assert routing['reason'] == 'explicit_handoff_replacement', 'fresh explicit replacement handoff should record the explicit-handoff reason'
|
|
415
415
|
assert routing['currentMissionAnchor'] == updated_mission, 'explicit-handoff routing should keep the current mission anchor until the user approves replacement'
|
|
416
416
|
assert routing['proposedMissionAnchor'] == replacement_mission, 'explicit-handoff routing should expose the proposed replacement mission'
|
|
417
417
|
assert routing['proposalSource'] == 'handoff_capsule', 'explicit-handoff routing should preserve the handoff source'
|
|
@@ -454,7 +454,7 @@ assert state['mission_anchor'] == updated_mission, 'final Start/Cancel cancel sh
|
|
|
454
454
|
assert plan['mission_anchor'] == updated_mission, 'final Start/Cancel cancel should keep plan.json unchanged'
|
|
455
455
|
assert active['mission_anchor'] == updated_mission, 'final Start/Cancel cancel should keep active-slice.json unchanged'
|
|
456
456
|
assert routing['action'] == 'refocus', 'final Start/Cancel cancel should still come from an explicit-handoff refocus classification'
|
|
457
|
-
assert routing['reason'] == '
|
|
457
|
+
assert routing['reason'] == 'explicit_handoff_replacement', 'final Start/Cancel cancel should preserve the explicit-handoff reason'
|
|
458
458
|
assert routing['currentMissionAnchor'] == updated_mission, 'final Start/Cancel cancel should keep the current mission anchor until the user approves replacement'
|
|
459
459
|
assert proposal['mission'] == replacement_mission, 'final Start/Cancel cancel should still prepare the replacement proposal before rewriting state'
|
|
460
460
|
assert proposal['source'] == 'handoff_capsule', 'final Start/Cancel cancel should preserve the explicit-handoff proposal source'
|
|
@@ -495,7 +495,7 @@ assert routing['mode'] == 'bare', 'accepted bare refocus should keep bare routin
|
|
|
495
495
|
assert 'explicitGoal' not in routing, 'accepted bare refocus should not expose removed explicit-goal shim fields'
|
|
496
496
|
assert 'explicitGoalProvided' not in routing, 'accepted bare refocus should not expose removed explicit-goal shim fields'
|
|
497
497
|
assert routing['action'] == 'refocus', 'accepted bare refocus should keep the explicit-handoff refocus classification'
|
|
498
|
-
assert routing['reason'] == '
|
|
498
|
+
assert routing['reason'] == 'explicit_handoff_replacement', 'accepted bare refocus should keep the explicit-handoff reason'
|
|
499
499
|
assert routing['currentMissionAnchor'] == 'Remove completion status line, keep widget.', 'accepted bare refocus should expose the original mission until Start is accepted'
|
|
500
500
|
assert routing['proposalSource'] == 'handoff_capsule', 'accepted bare refocus should preserve the explicit-handoff source'
|
|
501
501
|
assert new_anchor in mission_text, '.agent/mission.md did not update to the bare refocus mission anchor'
|
package/scripts/release-check.sh
CHANGED
|
@@ -17,45 +17,39 @@ checks = {
|
|
|
17
17
|
"README.md": [
|
|
18
18
|
"`/cook` is the explicit workflow boundary for starting, continuing, refocusing, or beginning the next round of long-running repo work.",
|
|
19
19
|
"Only explicit `/cook` enters the workflow. Ordinary prompts stay in the main chat and go straight to the primary agent.",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"`/cook` first looks for a fresh explicit primary-agent handoff capsule from recent ordinary-chat discussion. New-workflow entry and done-workflow next-round entry start only when that capsule is fresh, valid, and implementation-startable; otherwise `/cook` fails closed instead of deriving startup from recent discussion.",
|
|
26
|
-
"When a workflow is already active and no fresh valid explicit handoff is present, `/cook` resumes from canonical `.agent/**` state instead of deriving replacement startup from recent discussion.",
|
|
27
|
-
"Without one, `/cook` fails closed instead of deriving the next round from recent discussion.",
|
|
28
|
-
"when a fresh explicit handoff suggests replacing an active workflow, `/cook` shows a chooser before any canonical state rewrite",
|
|
20
|
+
"Ordinary chat remains advisory until you explicitly run `/cook`. At that point `/cook` synthesizes a startup brief from recent discussion using primary-agent-style context, then asks you to **Start** or **Cancel** before rewriting canonical workflow state.",
|
|
21
|
+
"- startup and next-round entry stay confirm-first, but they now derive startup from explicit user `/cook` entry plus recent discussion when needed",
|
|
22
|
+
"- active workflows resume from canonical `.agent/**` state unless `/cook` synthesizes or receives a concrete replacement mission",
|
|
23
|
+
"`/cook` first checks for a fresh explicit primary-agent handoff capsule as a compatibility intake path. If none is present, `/cook` synthesizes a startup brief from recent discussion using primary-agent-style context.",
|
|
24
|
+
"when a concrete replacement mission suggests replacing an active workflow, `/cook` shows a chooser before any canonical state rewrite",
|
|
29
25
|
],
|
|
30
26
|
"CHANGELOG.md": [
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
27
|
+
"removed proactive primary-agent `/cook` prompting and default ordinary-chat `cook_handoff` emission so main chat stays advisory until the user explicitly runs `/cook`",
|
|
28
|
+
"changed bare `/cook` startup and done-workflow next-round entry to synthesize a deferred primary-agent startup brief from recent discussion instead of requiring a pre-authored explicit handoff capsule",
|
|
29
|
+
"updated public parity and shipped package contents so the tracked `.agent` contract files are included in package tarballs and packaged smoke/release verification can scaffold canonical state truthfully",
|
|
34
30
|
],
|
|
35
31
|
"extensions/completion/prompt-surfaces.ts": [
|
|
36
32
|
'"/cook is the only explicit entrypoint into long-running completion workflow."',
|
|
37
|
-
'"
|
|
38
|
-
'"
|
|
39
|
-
'"The capsule is startup intake for /cook only: do not present it as canonical .agent state',
|
|
33
|
+
'"Do not proactively tell the user to run /cook just because a task looks workflow-worthy, and do not emit a ```cook_handoff``` capsule by default in ordinary chat."',
|
|
34
|
+
'"Only provide a preview startup brief or ```cook_handoff``` capsule in ordinary chat when the user explicitly asks for that preview behavior."',
|
|
40
35
|
],
|
|
41
36
|
"extensions/completion/index.ts": [
|
|
42
|
-
'"/cook failed closed because
|
|
43
|
-
'description: "/cook workflow:
|
|
37
|
+
'"/cook failed closed because it could not derive a concrete startup brief from recent discussion. Clarify the mission, first slice, or verification intent in the main chat, then rerun /cook."',
|
|
38
|
+
'description: "/cook workflow: synthesize a startup brief when the user explicitly enters /cook, resume the current workflow from canonical state, or confirm a replacement mission from explicit /cook entry"',
|
|
44
39
|
],
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
forbidden = {
|
|
48
43
|
"README.md": [
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"Without a fresh explicit handoff blocking startup, `/cook` can fall back to recent discussion.",
|
|
44
|
+
"wait for a fresh primary-agent handoff",
|
|
45
|
+
"require a fresh valid explicit primary-agent handoff",
|
|
52
46
|
],
|
|
53
47
|
"extensions/completion/prompt-surfaces.ts": [
|
|
54
|
-
'"When handing off, explain that /cook
|
|
48
|
+
'"When handing off, explain that /cook can start a new workflow or next round only from a fresh valid explicit primary-agent handoff capsule; otherwise it fails closed, while already-active workflows resume from canonical .agent state unless a fresh valid explicit handoff proposes replacement."',
|
|
55
49
|
],
|
|
56
50
|
"extensions/completion/index.ts": [
|
|
57
|
-
'description: "/cook workflow:
|
|
58
|
-
'"/cook failed closed because
|
|
51
|
+
'description: "/cook workflow: start a new workflow or next round only from a fresh explicit primary-agent handoff, resume the current workflow from canonical state, or confirm an explicit replacement from the explicit /cook command"',
|
|
52
|
+
'"/cook failed closed because new-workflow startup now requires a fresh valid explicit primary-agent handoff from the immediately preceding ordinary-chat turn; recent discussion alone no longer starts a workflow. Ask the primary agent to hand off explicitly in the main chat, then rerun /cook."',
|
|
59
53
|
],
|
|
60
54
|
}
|
|
61
55
|
|
package/scripts/smoke-test.sh
CHANGED
|
@@ -266,17 +266,13 @@ assert not reminder.exists(), 'ordinary non-/cook turn should not inject complet
|
|
|
266
266
|
assert handoff.exists(), 'ordinary non-/cook turn should inject the /cook handoff boundary reminder'
|
|
267
267
|
handoff_text = handoff.read_text()
|
|
268
268
|
assert '/cook is the only explicit entrypoint into long-running completion workflow.' in handoff_text, 'ordinary handoff reminder should preserve the explicit /cook workflow boundary'
|
|
269
|
-
assert '
|
|
270
|
-
assert '
|
|
271
|
-
assert '
|
|
272
|
-
assert '
|
|
273
|
-
assert '
|
|
274
|
-
assert '
|
|
275
|
-
assert '
|
|
276
|
-
assert 'fresh valid explicit primary-agent handoff capsule from recent ordinary-chat discussion' in handoff_text, 'ordinary handoff reminder should describe recent explicit-handoff startup truthfully'
|
|
277
|
-
assert 'fails closed' in handoff_text, 'ordinary handoff reminder should describe fail-closed startup when no fresh valid handoff exists'
|
|
278
|
-
assert 'resume from canonical .agent state' in handoff_text, 'ordinary handoff reminder should preserve active-workflow canonical resume wording'
|
|
279
|
-
assert 'fall back to recent discussion' not in handoff_text, 'ordinary handoff reminder should no longer promise recent-discussion startup fallback'
|
|
269
|
+
assert 'Do not proactively tell the user to run /cook' in handoff_text, 'ordinary handoff reminder should keep ordinary chat neutral until explicit /cook entry'
|
|
270
|
+
assert 'do not emit a ```cook_handoff``` capsule by default in ordinary chat' in handoff_text, 'ordinary handoff reminder should stop proactive capsule emission'
|
|
271
|
+
assert 'ordinary chat remains ordinary chat until the user explicitly runs /cook' in handoff_text, 'ordinary handoff reminder should preserve the explicit /cook boundary'
|
|
272
|
+
assert 'do not begin long-running product implementation in ordinary chat' in handoff_text, 'ordinary handoff reminder should still block workflow-level implementation before /cook'
|
|
273
|
+
assert 'Only provide a preview startup brief or ```cook_handoff``` capsule in ordinary chat when the user explicitly asks for that preview behavior.' in handoff_text, 'ordinary handoff reminder should restrict preview capsules to explicit preview requests'
|
|
274
|
+
assert 'startup brief from recent discussion using primary-agent-style context' in handoff_text, 'ordinary handoff reminder should describe deferred startup synthesis'
|
|
275
|
+
assert 'Start/Cancel confirmation before canonical workflow state is rewritten' in handoff_text, 'ordinary handoff reminder should preserve confirm-first startup'
|
|
280
276
|
assert not auto_resume.exists(), 'ordinary non-/cook turn should not queue auto-resume before /cook activation'
|
|
281
277
|
assert 'Skipped completion workflow auto-resume prompt (test mode)' not in output, 'ordinary non-/cook turn should not attempt auto-resume'
|
|
282
278
|
PY
|
|
@@ -304,8 +300,8 @@ assert 'Canonical routing profile:' in resume, 'resume prompt should expose cano
|
|
|
304
300
|
assert f'- task_type: {expected_task_type}' in resume, 'resume prompt missing canonical task_type'
|
|
305
301
|
assert f'- evaluation_profile: {expected_eval_profile}' in resume, 'resume prompt missing canonical evaluation_profile'
|
|
306
302
|
assert routing['mode'] == 'bare', 'active bare /cook should snapshot bare routing mode'
|
|
307
|
-
assert routing['action'] == 'continue', 'no-discussion active bare /cook should resume from canonical state without a
|
|
308
|
-
assert routing['reason'] == '
|
|
303
|
+
assert routing['action'] == 'continue', 'no-discussion active bare /cook should resume from canonical state without a concrete replacement mission'
|
|
304
|
+
assert routing['reason'] == 'no_replacement_proposal', 'no-discussion active bare /cook should explain that resume happened because no replacement mission was derived'
|
|
309
305
|
assert routing['currentMissionAnchor'] == state['mission_anchor'], 'resume routing snapshot should keep the current mission anchor'
|
|
310
306
|
assert routing['proposedMissionAnchor'] is None, 'no-discussion active bare /cook should not propose a replacement mission'
|
|
311
307
|
assert not chooser_path.exists(), 'active bare /cook resume should not open the chooser without a fresh explicit handoff'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cook-handoff-boundary
|
|
3
|
-
description: Ordinary-chat boundary contract for
|
|
3
|
+
description: Ordinary-chat boundary contract for keeping main chat advisory until the user explicitly enters `/cook`, while preventing long-running implementation from starting before that explicit workflow entry.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /cook Handoff Boundary
|
|
@@ -14,34 +14,66 @@ This skill governs the boundary between:
|
|
|
14
14
|
|
|
15
15
|
## Core Contract
|
|
16
16
|
|
|
17
|
-
- Ordinary chat may be used to clarify requirements, discuss tradeoffs, propose implementation approaches, and refine scope
|
|
17
|
+
- Ordinary chat may be used to clarify requirements, discuss tradeoffs, propose implementation approaches, and refine scope.
|
|
18
18
|
- `/cook` is the only explicit entrypoint into long-running completion workflow.
|
|
19
|
-
-
|
|
20
|
-
- Before
|
|
19
|
+
- Ordinary chat remains ordinary chat until the user explicitly runs `/cook`.
|
|
20
|
+
- Before that explicit `/cook` entry, the primary agent must stop short of long-running implementation for workflow-level tasks.
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## What Ordinary Chat May Do
|
|
23
23
|
|
|
24
|
-
The primary agent
|
|
24
|
+
The primary agent may:
|
|
25
|
+
|
|
26
|
+
- answer follow-up questions
|
|
27
|
+
- discuss tradeoffs
|
|
28
|
+
- refine scope and constraints
|
|
29
|
+
- summarize likely mission, acceptance, or risks
|
|
30
|
+
- help the user determine whether the work seems large enough for `/cook`
|
|
31
|
+
|
|
32
|
+
The primary agent should not:
|
|
33
|
+
|
|
34
|
+
- proactively tell the user to run `/cook`
|
|
35
|
+
- proactively emit a `cook_handoff` capsule by default
|
|
36
|
+
- act as though workflow has already started
|
|
37
|
+
- rewrite ordinary-chat discussion into canonical workflow state
|
|
38
|
+
|
|
39
|
+
## When Work Looks Workflow-Worthy
|
|
40
|
+
|
|
41
|
+
The primary agent should treat work as workflow-worthy when one or more of the following are true:
|
|
25
42
|
|
|
26
|
-
- the user has clearly shifted from exploration into implementation intent
|
|
27
|
-
- the agent has just produced a concrete plan or proposal whose natural next step would be implementation
|
|
28
43
|
- the task spans multiple files, steps, or verification surfaces
|
|
29
|
-
- the
|
|
44
|
+
- the next natural step would be bounded repo implementation rather than more explanation
|
|
45
|
+
- the work needs resumability, review, audit, or canonical workflow state
|
|
30
46
|
- the task is better treated as a long-running repo mission than a one-off answer or tiny fix
|
|
31
47
|
|
|
32
|
-
|
|
48
|
+
Even then, the boundary remains:
|
|
49
|
+
|
|
50
|
+
- ordinary chat can still keep refining the task
|
|
51
|
+
- only explicit `/cook` starts workflow
|
|
52
|
+
|
|
53
|
+
## Required Behavior Before Explicit `/cook`
|
|
33
54
|
|
|
34
|
-
When
|
|
55
|
+
When a task has matured into workflow-level work, the primary agent must:
|
|
35
56
|
|
|
36
57
|
- stop before long-running implementation
|
|
37
|
-
- not edit tracked product files
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
58
|
+
- not edit tracked product files for that workflow-level task in ordinary chat
|
|
59
|
+
- continue ordinary discussion naturally if the user keeps asking questions or refining scope
|
|
60
|
+
- wait for the user to explicitly run `/cook` before treating the conversation as workflow startup
|
|
61
|
+
|
|
62
|
+
## Deferred Handoff Model
|
|
63
|
+
|
|
64
|
+
When the user explicitly runs `/cook`:
|
|
65
|
+
|
|
66
|
+
- `/cook` will synthesize a startup brief from recent discussion using primary-agent-style context
|
|
67
|
+
- `/cook` will show Start / Cancel confirmation before canonical workflow state is rewritten
|
|
68
|
+
- that synthesized startup brief is advisory intake only, not canonical `.agent/**` state by itself
|
|
69
|
+
|
|
70
|
+
This means the primary agent does **not** need to proactively attach startup capsules during ordinary chat just because the task looks ready.
|
|
71
|
+
|
|
72
|
+
## Optional Preview Behavior
|
|
73
|
+
|
|
74
|
+
Only if the user explicitly asks for a preview startup brief or handoff capsule in ordinary chat may the primary agent provide one.
|
|
43
75
|
|
|
44
|
-
|
|
76
|
+
Optional preview capsule format:
|
|
45
77
|
|
|
46
78
|
````text
|
|
47
79
|
```cook_handoff
|
|
@@ -73,31 +105,28 @@ Required capsule format:
|
|
|
73
105
|
Notes:
|
|
74
106
|
|
|
75
107
|
- `constraints` may be replaced or supplemented by `non_goals` when clearer.
|
|
76
|
-
- `first_slice_goal`, `first_slice_non_goals`, `implementation_surfaces`, `verification_commands`, and `why_this_slice_first` are required only for implementation-ready
|
|
77
|
-
-
|
|
78
|
-
- If later ordinary-chat discussion materially changes the startup brief before `/cook` runs, update or replace the capsule in a later assistant reply.
|
|
79
|
-
- The mission must be positively startable implementation work; do not use rejection or suppression text as the mission.
|
|
80
|
-
- The capsule is startup intake for `/cook` only. It is not canonical `.agent/**` state, not active-slice state, and not a second repo contract source.
|
|
108
|
+
- `first_slice_goal`, `first_slice_non_goals`, `implementation_surfaces`, `verification_commands`, and `why_this_slice_first` are required only for an implementation-ready preview capsule.
|
|
109
|
+
- Any preview capsule is startup intake for `/cook` only. It is not canonical `.agent/**` state, not active-slice state, and not a second repo contract source.
|
|
81
110
|
|
|
82
111
|
Suggested wording:
|
|
83
112
|
|
|
84
|
-
>
|
|
113
|
+
> We are still in ordinary chat until you explicitly run `/cook`. If you want, we can keep refining the first slice here. When you do run `/cook`, it will synthesize a startup brief from our recent discussion and show Start / Cancel before workflow begins.
|
|
85
114
|
|
|
86
115
|
A short recap may include mission, scope, or acceptance, but that recap must not be presented as canonical plan state.
|
|
87
116
|
|
|
88
117
|
## Forbidden Behaviors
|
|
89
118
|
|
|
90
|
-
|
|
119
|
+
Before the user explicitly runs `/cook`, the primary agent must not:
|
|
91
120
|
|
|
92
121
|
- directly begin long-running implementation in ordinary chat
|
|
93
122
|
- modify tracked product files as part of that workflow-level task
|
|
94
123
|
- act as though `/cook` had already been invoked
|
|
95
124
|
- silently rewrite ordinary-chat discussion into active workflow state
|
|
96
|
-
- refuse ordinary-chat clarification
|
|
125
|
+
- refuse ordinary-chat clarification only because `/cook` would now be appropriate
|
|
97
126
|
|
|
98
127
|
## Relationship To `completion-protocol`
|
|
99
128
|
|
|
100
|
-
This skill is only about pre-`/cook` ordinary-chat
|
|
129
|
+
This skill is only about pre-`/cook` ordinary-chat boundary behavior.
|
|
101
130
|
|
|
102
131
|
After the user explicitly enters `/cook`, the separate `completion-protocol` skill governs:
|
|
103
132
|
|