@veewo/claw 0.2.2 → 0.2.3

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/README.md CHANGED
@@ -1,83 +1,83 @@
1
- # @veewo/claw
2
-
3
- `@veewo/claw` is the CLI entrypoint for running the `.claw` workflow in a project.
4
-
5
- It gives agents and developers a concrete way to plan work, recall project knowledge, deposit truth and ADR notes, and close rounds out cleanly instead of leaving project state scattered across transient chats.
6
-
7
- ## What the CLI is for
8
-
9
- - initialize and normalize the `.claw` project surface
10
- - run project-scoped planning and task lifecycle commands
11
- - index and query project documentation recall
12
- - support truth ingestion and closeout flows
13
-
14
- ## Install
15
-
16
- ```bash
17
- npm install -g @veewo/claw
18
- ```
19
-
20
- After installing the CLI, project search still needs one-time setup inside each `.claw` project:
21
-
22
- 1. Run `claw context` so `.claw/project.json` is normalized and the default local embedding config is present.
23
- 2. Run `claw search index --refresh` once so the local embedding model can be downloaded or reused and the first vector index can be built.
24
-
25
- Then run:
26
-
27
- ```bash
28
- claw init
29
- claw search index --refresh
30
- claw search "existing truth or ADR topic"
31
- claw plan create --title "My task" --goal "Define the first task"
32
- claw plan create "My templated task" --template default --goal "Route through the default template"
33
- claw plan create "Ephemeral harness" --scope session --goal "Use plan and Goal workflows without project deposition"
34
- ```
35
-
36
- `claw plan create` uses explicit `--template` first, otherwise the project's configured `defaultPlanTemplate`, and finally falls back to the built-in `default` template. You can select a template explicitly with `claw plan create "<title>" --template <name>` or `claw plan create --template <name> --title "<title>"`.
37
-
38
- New project tasks are grouped under `.claw/tasks/YYYY-MM-DD/`. On the first `claw context` call of each local calendar day, claw performs a lock-protected maintenance pass: it clears `.claw/runtime/tmp/` (and removes legacy `.claw/tmp/`), moves date-scoped task folders from before yesterday into the archive even when old plans have no `completedAt`, archives legacy flat tasks by `plan.updatedAt` (falling back to the plan file timestamp), applies `maxTasksToKeep` to archived tasks, removes bindings to plans no longer under active tasks, and sweeps expired session workflows. This is lazy maintenance, not a background scheduler.
39
-
40
- `--scope session` stores the workflow in a user-level directory keyed by the platform session id, so it works without a project `.claw` directory and recovers across cwd changes. It preserves plan/task/subplan/Goal behavior while disabling project knowledge capture, memory/GitNexus refresh, and project retention. Use `claw session clean` for the current session or `claw session clean --expired` for the seven-day TTL sweep.
41
-
42
- Projects can add reusable templates directly under `.claw/templates` with `.json`, `.js`, `.mjs`, or `.cjs` files. Put `defaultPlanTemplate` in `.claw/project.json` for a shared team default, or in `.claw/project-override.json` for a local personal override.
43
-
44
- When `.claw/project.json` has `planning: true`, the default `default` template seeds one planning task in `process.discussing`. It loads the effective `externalPlanningSkill`, falling back to `claw-kit:planning`, and stays open while the requirements and proposed solution are discussed and confirmed with the user. Use `plan start` when execution tasks remain; when planning itself resolves the request, complete task 1 and close the plan.
45
-
46
- When `planning: false`, `claw plan create` seeds the smallest executable plan directly in `process.active`.
47
-
48
- ## Workflow shape
49
-
50
- In a typical round, the CLI helps land this loop in a project:
51
-
52
- `plan` -> `search and recall` -> `execute` -> `deposit truth / ADR` -> `close out`
53
-
54
- That project-level plan structure helps agents carry longer-running work more cleanly than leaving the task in loose chat state alone.
55
-
56
- Codex startup workflow should rely on the session hook or startup recovery path instead of treating any extra manual recovery step as required after plan creation.
57
-
58
- ## Search and recall
59
-
60
- `claw search` is the project recall command for `.claw` memory, truth, ADR, and declared markdown docs. Use it for retained project context rather than code search.
61
-
62
- When a task needs deeper code investigation or relationship tracing, GitNexus can complement this workflow, but it is optional rather than required for using `claw` itself.
63
-
64
- Typical setup:
65
-
66
- ```bash
67
- claw context
68
- claw search index --refresh
69
- ```
70
-
71
- If you need deeper backup detail on config or recall behavior, use the adapter reference notes in [packages/codex-adapter/references/project-config-reference.md](../codex-adapter/references/project-config-reference.md) or [packages/opencode-adapter/references/project-config-reference.md](../opencode-adapter/references/project-config-reference.md).
72
-
73
- ## Configuration
74
-
75
- If you need backup `.claw/project.json` detail, start with the adapter reference notes above and use [docs/project-json-reference.md](../../docs/project-json-reference.md) only for deeper canonical detail.
76
-
77
- `claw-kit` also stays usable alongside other harnesses or external skills, so the CLI does not assume a single host or investigation surface.
78
-
79
- The config model is team-friendly as well: `.claw/project.json` carries the shared canonical workflow, while `.claw/project-override.json` leaves room for personal runtime preferences.
80
-
81
- ## Repository
82
-
83
- - [claw-kit](https://github.com/chanyuenpang/claw-kit)
1
+ # @veewo/claw
2
+
3
+ `@veewo/claw` is the CLI entrypoint for running the `.claw` workflow in a project.
4
+
5
+ It gives agents and developers a concrete way to plan work, recall project knowledge, deposit truth and ADR notes, and close rounds out cleanly instead of leaving project state scattered across transient chats.
6
+
7
+ ## What the CLI is for
8
+
9
+ - initialize and normalize the `.claw` project surface
10
+ - run project-scoped planning and task lifecycle commands
11
+ - index and query project documentation recall
12
+ - support truth ingestion and closeout flows
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install -g @veewo/claw
18
+ ```
19
+
20
+ After installing the CLI, project search still needs one-time setup inside each `.claw` project:
21
+
22
+ 1. Run `claw context` so `.claw/project.json` is normalized and the default local embedding config is present.
23
+ 2. Run `claw search index --refresh` once so the local embedding model can be downloaded or reused and the first vector index can be built.
24
+
25
+ Then run:
26
+
27
+ ```bash
28
+ claw init
29
+ claw search index --refresh
30
+ claw search "existing truth or ADR topic"
31
+ claw plan create --title "My task" --goal "Define the first task"
32
+ claw plan create "My templated task" --template default --goal "Route through the default template"
33
+ claw plan create "Ephemeral harness" --scope session --goal "Use plan and Goal workflows without project deposition"
34
+ ```
35
+
36
+ `claw plan create` uses explicit `--template` first, otherwise the project's configured `defaultPlanTemplate`, and finally falls back to the built-in `default` template. You can select a template explicitly with `claw plan create "<title>" --template <name>` or `claw plan create --template <name> --title "<title>"`.
37
+
38
+ New project tasks are grouped under `.claw/tasks/YYYY-MM-DD/`. On the first `claw context` call of each local calendar day, claw performs a lock-protected maintenance pass: it removes expired entries from `.claw/runtime/tmp/`, removes workflow task directories that exceed the task TTL even when incomplete, moves eligible date-scoped task folders into the archive, applies `maxTasksToKeep` and archive TTL, removes expired or invalid bindings, and sweeps expired session workflows. This is lazy maintenance, not a background scheduler.
39
+
40
+ `--scope session` stores the workflow in a user-level directory keyed by the platform session id, so it works without a project `.claw` directory and recovers across cwd changes. It preserves plan/task/subplan/Goal behavior while disabling project knowledge capture, memory/GitNexus refresh, and project retention. Use `claw session clean` for the current session or `claw session clean --expired` for the seven-day TTL sweep.
41
+
42
+ Projects can add reusable templates directly under `.claw/templates` with `.json`, `.js`, `.mjs`, or `.cjs` files. Put `defaultPlanTemplate` in `.claw/project.json` for a shared team default, or in `.claw/project-override.json` for a local personal override.
43
+
44
+ When `.claw/project.json` has `planning: true`, the default `default` template seeds one planning task in `process.discussing`. It loads the effective `externalPlanningSkill`, falling back to `claw-kit:planning`, and stays open while the requirements and proposed solution are discussed and confirmed with the user. Use `plan start` when execution tasks remain; when planning itself resolves the request, complete task 1 and close the plan.
45
+
46
+ When `planning: false`, `claw plan create` seeds the smallest executable plan directly in `process.active`.
47
+
48
+ ## Workflow shape
49
+
50
+ In a typical round, the CLI helps land this loop in a project:
51
+
52
+ `plan` -> `search and recall` -> `execute` -> `deposit truth / ADR` -> `close out`
53
+
54
+ That project-level plan structure helps agents carry longer-running work more cleanly than leaving the task in loose chat state alone.
55
+
56
+ Codex startup workflow should rely on the session hook or startup recovery path instead of treating any extra manual recovery step as required after plan creation.
57
+
58
+ ## Search and recall
59
+
60
+ `claw search` is the project recall command for `.claw` memory, truth, ADR, and declared markdown docs. Use it for retained project context rather than code search.
61
+
62
+ When a task needs deeper code investigation or relationship tracing, GitNexus can complement this workflow, but it is optional rather than required for using `claw` itself.
63
+
64
+ Typical setup:
65
+
66
+ ```bash
67
+ claw context
68
+ claw search index --refresh
69
+ ```
70
+
71
+ If you need deeper backup detail on config or recall behavior, use the adapter reference notes in [packages/codex-adapter/references/project-config-reference.md](../codex-adapter/references/project-config-reference.md) or [packages/opencode-adapter/references/project-config-reference.md](../opencode-adapter/references/project-config-reference.md).
72
+
73
+ ## Configuration
74
+
75
+ If you need backup `.claw/project.json` detail, start with the adapter reference notes above and use [docs/project-json-reference.md](../../docs/project-json-reference.md) only for deeper canonical detail.
76
+
77
+ `claw-kit` also stays usable alongside other harnesses or external skills, so the CLI does not assume a single host or investigation surface.
78
+
79
+ The config model is team-friendly as well: `.claw/project.json` carries the shared canonical workflow, while `.claw/project-override.json` leaves room for personal runtime preferences.
80
+
81
+ ## Repository
82
+
83
+ - [claw-kit](https://github.com/chanyuenpang/claw-kit)
package/dist/cli.js CHANGED
@@ -394,6 +394,28 @@ const COMMAND_HELP = {
394
394
  description: "Internal: warms the configured local persistent embedding session after context recovery without delaying SessionStart.",
395
395
  options: [{ flag: "--cwd <dir>", detail: "(required) Project root." }],
396
396
  },
397
+ "internal-daily-maintenance": {
398
+ usage: ["{script} internal-daily-maintenance --cwd <dir> [--session-key <key>] [--session-only]"],
399
+ description: "Internal: runs the lock-protected daily cleanup asynchronously after context recovery.",
400
+ options: [
401
+ { flag: "--cwd <dir>", detail: "(required) Current workspace directory." },
402
+ { flag: "--session-key <key>", detail: "Optional owner session key used for session workflow maintenance." },
403
+ { flag: "--session-only", detail: "Only maintain the session workflow; do not touch project tasks." },
404
+ ],
405
+ },
406
+ "internal-knowledge-sweep": {
407
+ usage: ["{script} internal-knowledge-sweep --cwd <dir>"],
408
+ description: "Internal: discovers retryable knowledge jobs and launches their detached finalizers.",
409
+ options: [{ flag: "--cwd <dir>", detail: "(required) Project root." }],
410
+ },
411
+ "internal-background-maintenance": {
412
+ usage: ["{script} internal-background-maintenance --cwd <dir> [--session-key <key>]"],
413
+ description: "Internal: runs non-blocking cleanup, embedding warmup, and knowledge job discovery in one worker.",
414
+ options: [
415
+ { flag: "--cwd <dir>", detail: "(required) Current workspace directory." },
416
+ { flag: "--session-key <key>", detail: "Optional owner session key used for session workflow maintenance." },
417
+ ],
418
+ },
397
419
  };
398
420
  async function main() {
399
421
  const args = process.argv.slice(2);
@@ -527,6 +549,15 @@ async function main() {
527
549
  case "internal-embedding-warmup":
528
550
  await runInternalEmbeddingWarmup(args);
529
551
  return;
552
+ case "internal-daily-maintenance":
553
+ runInternalDailyMaintenance(args);
554
+ return;
555
+ case "internal-knowledge-sweep":
556
+ runInternalKnowledgeSweep(args);
557
+ return;
558
+ case "internal-background-maintenance":
559
+ await runInternalBackgroundMaintenance(args);
560
+ return;
530
561
  default:
531
562
  printTopLevelUsage();
532
563
  process.exitCode = 1;
@@ -717,8 +748,6 @@ async function runPlan(args, effectiveHost) {
717
748
  && effectiveWriter?.executionPolicy === "subagent"
718
749
  && result.knowledgeFinalizeId)
719
750
  ? buildKnowledgeDispatch({
720
- projectRoot: project.projectRoot,
721
- taskName: result.taskName,
722
751
  finalizeId: result.knowledgeFinalizeId,
723
752
  writer: effectiveWriter,
724
753
  })
@@ -820,8 +849,6 @@ async function runPlan(args, effectiveHost) {
820
849
  && effectiveWriter?.executionPolicy === "subagent"
821
850
  && result.knowledgeFinalizeId)
822
851
  ? buildKnowledgeDispatch({
823
- projectRoot: project.projectRoot,
824
- taskName: result.taskName,
825
852
  finalizeId: result.knowledgeFinalizeId,
826
853
  writer: effectiveWriter,
827
854
  })
@@ -1057,7 +1084,15 @@ async function runContextCommand(args, cwd = process.cwd(), ownerSessionKey = re
1057
1084
  let fixedPaths = [];
1058
1085
  const sessionProject = resolveSessionWorkflowContext(ownerSessionKey ?? undefined);
1059
1086
  if (sessionProject) {
1060
- const maintenance = runDailyMaintenance(sessionProject, { excludeSessionKey: ownerSessionKey ?? undefined, includeProject: false });
1087
+ const maintenance = effectiveHost
1088
+ ? null
1089
+ : runDailyMaintenance(sessionProject, {
1090
+ excludeSessionKey: ownerSessionKey ?? undefined,
1091
+ includeProject: false,
1092
+ });
1093
+ if (effectiveHost) {
1094
+ launchDailyMaintenance(cwd, ownerSessionKey, true);
1095
+ }
1061
1096
  const activeWorkflow = !taskName && ownerSessionKey
1062
1097
  ? await tryResolveActiveWorkflowSnapshot(cwd, ownerSessionKey, effectiveHost)
1063
1098
  : null;
@@ -1068,7 +1103,7 @@ async function runContextCommand(args, cwd = process.cwd(), ownerSessionKey = re
1068
1103
  return {
1069
1104
  project: sessionProject,
1070
1105
  ...(activeWorkflow ? { activeWorkflow } : {}),
1071
- ...(maintenance.ran ? { maintenance } : {}),
1106
+ ...(maintenance?.ran ? { maintenance } : {}),
1072
1107
  ...(codexRuntimeError ? { error: codexRuntimeError } : {}),
1073
1108
  };
1074
1109
  }
@@ -1084,7 +1119,13 @@ async function runContextCommand(args, cwd = process.cwd(), ownerSessionKey = re
1084
1119
  initProject({ cwd, version: CLI_VERSION });
1085
1120
  initialized = true;
1086
1121
  }
1087
- const maintenance = runDailyMaintenance(resolveProjectContext(cwd), { excludeSessionKey: ownerSessionKey ?? undefined });
1122
+ const project = resolveProjectContext(cwd);
1123
+ const maintenance = effectiveHost
1124
+ ? null
1125
+ : runDailyMaintenance(project, { excludeSessionKey: ownerSessionKey ?? undefined });
1126
+ if (effectiveHost) {
1127
+ launchDailyMaintenance(cwd, ownerSessionKey, false);
1128
+ }
1088
1129
  let resolved = resolveContext(cwd, taskName);
1089
1130
  const versionSync = syncProjectVersionWithCli(cwd, resolved.project);
1090
1131
  if (versionSync.projectVersionUpdated) {
@@ -1104,7 +1145,7 @@ async function runContextCommand(args, cwd = process.cwd(), ownerSessionKey = re
1104
1145
  launchProjectEmbeddingWarmup(resolved.project);
1105
1146
  return {
1106
1147
  ...resolved,
1107
- ...(maintenance.ran ? { maintenance } : {}),
1148
+ ...(maintenance?.ran ? { maintenance } : {}),
1108
1149
  ...(activeWorkflow ? { activeWorkflow } : {}),
1109
1150
  ...(codexRuntimeError ? { error: codexRuntimeError } : {}),
1110
1151
  protocolCheck: checkProjectProtocol(cwd),
@@ -1152,6 +1193,28 @@ function launchProjectEmbeddingWarmup(project) {
1152
1193
  // Context recovery is authoritative; embedding warmup is fail-open latency work.
1153
1194
  }
1154
1195
  }
1196
+ function launchDailyMaintenance(cwd, ownerSessionKey, sessionOnly) {
1197
+ const args = [resolveCliEntryPath(), "internal-daily-maintenance", "--cwd", cwd];
1198
+ if (ownerSessionKey) {
1199
+ args.push("--session-key", ownerSessionKey);
1200
+ }
1201
+ if (sessionOnly) {
1202
+ args.push("--session-only");
1203
+ }
1204
+ try {
1205
+ const child = spawn(process.execPath, args, {
1206
+ cwd,
1207
+ detached: true,
1208
+ stdio: "ignore",
1209
+ windowsHide: true,
1210
+ env: withoutInvocationHost(),
1211
+ });
1212
+ child.unref();
1213
+ }
1214
+ catch {
1215
+ // Context recovery is authoritative; daily cleanup is fail-open latency work.
1216
+ }
1217
+ }
1155
1218
  function buildPublicContextOutput(context) {
1156
1219
  const project = asJsonRecord(context.project);
1157
1220
  const output = {};
@@ -1441,6 +1504,7 @@ async function runInternalKnowledgeCapture(args, effectiveHost) {
1441
1504
  const sessionId = resolveOwnerSessionKey(payload);
1442
1505
  const turnId = readHookString(payload, "turn_id");
1443
1506
  const message = readHookString(payload, "message");
1507
+ const taskConclusions = readHookTaskConclusions(payload, turnId);
1444
1508
  if (!hookCwd || !sessionId || !turnId || !message || !containsClawDir(hookCwd)) {
1445
1509
  printJson({ ok: true, captured: false });
1446
1510
  return;
@@ -1453,6 +1517,7 @@ async function runInternalKnowledgeCapture(args, effectiveHost) {
1453
1517
  turnId,
1454
1518
  message,
1455
1519
  host: effectiveHost === "cindy" ? "cindy" : effectiveHost,
1520
+ taskConclusions,
1456
1521
  });
1457
1522
  printJson(result);
1458
1523
  }
@@ -1583,6 +1648,86 @@ async function runInternalEmbeddingWarmup(args) {
1583
1648
  ...await warmProjectMemoryEmbedding({ cwd }),
1584
1649
  });
1585
1650
  }
1651
+ function runInternalDailyMaintenance(args) {
1652
+ const cwd = readRequiredFlag(args, "--cwd");
1653
+ const sessionKey = readOptionalFlag(args, "--session-key");
1654
+ const sessionOnly = readBooleanFlag(args, "--session-only");
1655
+ assertNoRemainingArgs(args, "internal-daily-maintenance");
1656
+ const project = sessionOnly
1657
+ ? (sessionKey ? resolveSessionWorkflowContext(sessionKey) : null)
1658
+ : resolveProjectContext(cwd);
1659
+ if (!project) {
1660
+ printJson({ command: "internal-daily-maintenance", ok: true, ran: false, skipped: true });
1661
+ return;
1662
+ }
1663
+ printJson({
1664
+ command: "internal-daily-maintenance",
1665
+ ok: true,
1666
+ ...runDailyMaintenance(project, {
1667
+ excludeSessionKey: sessionKey ?? undefined,
1668
+ includeProject: !sessionOnly,
1669
+ }),
1670
+ });
1671
+ }
1672
+ function runInternalKnowledgeSweep(args) {
1673
+ const cwd = readRequiredFlag(args, "--cwd");
1674
+ assertNoRemainingArgs(args, "internal-knowledge-sweep");
1675
+ const project = tryResolveHookProject(cwd);
1676
+ if (!project) {
1677
+ printJson({ command: "internal-knowledge-sweep", ok: true, launched: 0, skipped: true });
1678
+ return;
1679
+ }
1680
+ const jobs = listRetryableKnowledgeFinalizationJobs(project);
1681
+ let launched = 0;
1682
+ for (const jobPath of jobs) {
1683
+ try {
1684
+ launchKnowledgeFinalizationWorker(jobPath, project.projectRoot);
1685
+ launched += 1;
1686
+ }
1687
+ catch {
1688
+ // A later background sweep can retry a job that could not be launched.
1689
+ }
1690
+ }
1691
+ printJson({ command: "internal-knowledge-sweep", ok: true, discovered: jobs.length, launched });
1692
+ }
1693
+ async function runInternalBackgroundMaintenance(args) {
1694
+ const cwd = readRequiredFlag(args, "--cwd");
1695
+ const sessionKey = readOptionalFlag(args, "--session-key");
1696
+ assertNoRemainingArgs(args, "internal-background-maintenance");
1697
+ const sessionProject = sessionKey ? resolveSessionWorkflowContext(sessionKey) : null;
1698
+ const project = sessionProject ? null : tryResolveHookProject(cwd);
1699
+ let maintenance = { ran: false, skipped: true };
1700
+ if (sessionProject) {
1701
+ maintenance = runDailyMaintenance(sessionProject, { excludeSessionKey: sessionKey ?? undefined, includeProject: false });
1702
+ }
1703
+ else if (project) {
1704
+ maintenance = runDailyMaintenance(project, { excludeSessionKey: sessionKey ?? undefined });
1705
+ }
1706
+ let embedding = { warmed: false, reason: "skipped" };
1707
+ try {
1708
+ embedding = await warmProjectMemoryEmbedding({ cwd });
1709
+ }
1710
+ catch (error) {
1711
+ embedding = { warmed: false, reason: "failed", error: error instanceof Error ? error.message : String(error) };
1712
+ }
1713
+ let discovered = 0;
1714
+ let launched = 0;
1715
+ const knowledgeProject = project ?? sessionProject;
1716
+ if (knowledgeProject) {
1717
+ const jobs = listRetryableKnowledgeFinalizationJobs(knowledgeProject);
1718
+ discovered = jobs.length;
1719
+ for (const jobPath of jobs) {
1720
+ try {
1721
+ launchKnowledgeFinalizationWorker(jobPath, knowledgeProject.projectRoot);
1722
+ launched += 1;
1723
+ }
1724
+ catch {
1725
+ // A later background sweep can retry a job that could not be launched.
1726
+ }
1727
+ }
1728
+ }
1729
+ printJson({ command: "internal-background-maintenance", ok: true, maintenance, embedding, discovered, launched });
1730
+ }
1586
1731
  async function runInternalKnowledgeFinalize(args) {
1587
1732
  const jobPath = readRequiredFlag(args, "--job");
1588
1733
  const queued = readKnowledgeFinalizationJob(jobPath);
@@ -1640,8 +1785,6 @@ async function runInternalKnowledgeFinalize(args) {
1640
1785
  async function runKnowledgeDelegateForJob(running) {
1641
1786
  const dispatch = buildKnowledgeDelegateDispatch({
1642
1787
  policy: "background",
1643
- projectRoot: running.projectRoot,
1644
- taskName: running.taskName,
1645
1788
  finalizeId: running.finalizeId,
1646
1789
  writer: running.writer,
1647
1790
  });
@@ -1770,7 +1913,7 @@ async function runSessionStartHook(effectiveHost) {
1770
1913
  try {
1771
1914
  const context = await runContextCommand([], hookCwd, ownerSessionKey, effectiveHost);
1772
1915
  const contextProject = asJsonRecord(context.project);
1773
- const retryableJobs = contextProject?.scope !== "session" && !context.error
1916
+ const retryableJobs = effectiveHost !== "cindy" && contextProject?.scope !== "session" && !context.error
1774
1917
  ? listRetryableKnowledgeFinalizationJobs(resolveProjectContext(hookCwd))
1775
1918
  : [];
1776
1919
  if (contextProject?.scope !== "session"
@@ -1795,7 +1938,6 @@ async function runSessionStartHook(effectiveHost) {
1795
1938
  hookSpecificOutput: {
1796
1939
  hookEventName: "SessionStart",
1797
1940
  additionalContext,
1798
- ...(effectiveHost === "cindy" ? { knowledgeJobs: retryableJobs } : {}),
1799
1941
  },
1800
1942
  })}\n`);
1801
1943
  }
@@ -1829,6 +1971,21 @@ function readHookString(payload, key) {
1829
1971
  const value = payload[key];
1830
1972
  return typeof value === "string" && value.trim() ? value.trim() : null;
1831
1973
  }
1974
+ function readHookTaskConclusions(payload, turnId) {
1975
+ if (!turnId || !payload || typeof payload !== "object")
1976
+ return [];
1977
+ const value = payload.task_conclusions;
1978
+ if (!Array.isArray(value))
1979
+ return [];
1980
+ return value.flatMap((item) => {
1981
+ if (!item || typeof item !== "object")
1982
+ return [];
1983
+ const message = item.message;
1984
+ return typeof message === "string" && message.trim()
1985
+ ? [{ turnId, message: message.trim() }]
1986
+ : [];
1987
+ });
1988
+ }
1832
1989
  function containsClawDir(cwd) {
1833
1990
  try {
1834
1991
  const startDir = path.resolve(cwd);
@@ -1869,10 +2026,10 @@ function safeResolveTempDir() {
1869
2026
  }
1870
2027
  }
1871
2028
  function buildSessionStartAdditionalContext(context, sessionCwd, effectiveHost) {
2029
+ const versionSyncPrompt = buildVersionSyncPrompt(context);
1872
2030
  if (effectiveHost === "cindy") {
1873
- return buildCindySessionStartContext(context, sessionCwd);
2031
+ return buildCindySessionStartContext(context, sessionCwd, versionSyncPrompt);
1874
2032
  }
1875
- const versionSyncPrompt = buildVersionSyncPrompt(context);
1876
2033
  const searchGuidance = buildContextSearchGuidance(context);
1877
2034
  const runtimeErrorPrompt = buildCodexRuntimeErrorPrompt(context);
1878
2035
  const activeWorkflow = context.activeWorkflow;
@@ -1909,37 +2066,42 @@ function buildSessionStartAdditionalContext(context, sessionCwd, effectiveHost)
1909
2066
  }
1910
2067
  /**
1911
2068
  * Cindy Agents use the Ghost Tool gateway, not shell commands or Host actions.
1912
- * Keep startup recovery to the actionable plan snapshot only; the worker owns
1913
- * session identity, host selection, and any future Goal projection.
2069
+ * Match the Codex session-start wording and structure. Cindy's static entry
2070
+ * prompt supplies the shared skill and guidance lines; this dynamic context
2071
+ * supplies project identity or a recovered workflow snapshot. Goal Mode is
2072
+ * intentionally omitted because Cindy does not expose that Host surface.
1914
2073
  */
1915
- function buildCindySessionStartContext(context, sessionCwd) {
2074
+ function buildCindySessionStartContext(context, sessionCwd, versionSyncPrompt) {
1916
2075
  const activeWorkflow = asJsonRecord(context.activeWorkflow);
1917
2076
  if (activeWorkflow) {
1918
- const taskName = typeof activeWorkflow.taskName === "string" ? activeWorkflow.taskName.trim() : "current task";
1919
- const planStatus = typeof activeWorkflow.planStatus === "string" ? activeWorkflow.planStatus.trim() : "unknown";
1920
- const planSummary = typeof activeWorkflow.planSummary === "string" ? activeWorkflow.planSummary.trim() : "";
1921
- const nextTask = asJsonRecord(activeWorkflow.workflowGuidance)?.nextTask;
1922
- const nextTaskTitle = asJsonRecord(nextTask)?.title;
1923
- const lines = [
1924
- "claw-kit recovered a Cindy workflow.",
1925
- `- task: ${taskName}`,
1926
- `- plan status: ${planStatus}`,
1927
- ...(planSummary ? [`- plan summary: ${planSummary}`] : []),
1928
- ...(typeof nextTaskTitle === "string" && nextTaskTitle.trim() ? [`- next task: ${nextTaskTitle.trim()}`] : []),
1929
- "Use the claw-kit Ghost tools to inspect or advance this workflow. Do not run claw shell commands or manage host/session/Goal state yourself.",
1930
- ];
1931
- return lines.join("\n");
2077
+ return stripCindyGoalModeLines(buildRecoveredWorkflowAdditionalContext(activeWorkflow, versionSyncPrompt));
1932
2078
  }
1933
2079
  const project = asJsonRecord(context.project);
1934
2080
  if (!project)
1935
2081
  return null;
1936
2082
  const projectName = typeof project.projectName === "string" && project.projectName.trim()
1937
2083
  ? project.projectName.trim()
1938
- : path.basename(String(project.projectRoot ?? sessionCwd ?? "project"));
1939
- return [
1940
- `claw-kit is ready for the Cindy workspace: ${projectName}.`,
1941
- "Use the claw-kit Ghost tools when this work needs a plan; do not invoke claw shell commands directly.",
2084
+ : typeof project.projectId === "string" && project.projectId.trim()
2085
+ ? project.projectId.trim()
2086
+ : path.basename(String(project.projectRoot ?? sessionCwd ?? "project"));
2087
+ const projectRoot = typeof project.projectRoot === "string" ? project.projectRoot : sessionCwd;
2088
+ const projectId = typeof project.projectId === "string" ? project.projectId : projectName;
2089
+ const clawDir = typeof project.clawDir === "string" ? project.clawDir : path.join(projectRoot, ".claw");
2090
+ const prompt = [
2091
+ `This session started inside a .claw project: ${projectName} (${projectId}).`,
2092
+ `.claw directory: ${clawDir}`,
1942
2093
  ].join("\n");
2094
+ if (!versionSyncPrompt)
2095
+ return prompt;
2096
+ return versionSyncPrompt.placement === "prefix"
2097
+ ? `${versionSyncPrompt.lines.join("\n")}\n${prompt}`
2098
+ : `${prompt}\n${versionSyncPrompt.lines.join("\n")}`;
2099
+ }
2100
+ function stripCindyGoalModeLines(prompt) {
2101
+ return prompt
2102
+ .split("\n")
2103
+ .filter((line) => !/goal mode/i.test(line))
2104
+ .join("\n");
1943
2105
  }
1944
2106
  function buildCodexRuntimeErrorPrompt(context) {
1945
2107
  const error = asJsonRecord(context.error);