thoth-agents 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/LICENSE +30 -0
  2. package/README.md +86 -58
  3. package/dist/agents/prompt-sections.d.ts +5 -3
  4. package/dist/agents/prompt-utils.d.ts +1 -1
  5. package/dist/agents/worker.d.ts +2 -0
  6. package/dist/{chunk-STCURXAQ.js → chunk-MRFCA3U2.js} +33 -67
  7. package/dist/{chunk-EFGSGPYM.js → chunk-OW6I7ZUU.js} +391 -416
  8. package/dist/chunk-V7HSGRMB.js +1016 -0
  9. package/dist/{chunk-WCLUZZHI.js → chunk-VUNYH263.js} +1580 -351
  10. package/dist/cli/claude-code-paths.d.ts +2 -2
  11. package/dist/cli/codex-install.d.ts +5 -2
  12. package/dist/cli/codex-paths.d.ts +2 -2
  13. package/dist/cli/index.js +47 -11
  14. package/dist/cli/operations/pi.d.ts +1 -0
  15. package/dist/cli/pi-effort.d.ts +1 -1
  16. package/dist/cli/pi-external-package.d.ts +24 -0
  17. package/dist/cli/pi-git-source.d.ts +1 -0
  18. package/dist/cli/pi-install.d.ts +92 -15
  19. package/dist/cli/pi-managed-write.d.ts +3 -0
  20. package/dist/cli/pi-model-config.d.ts +17 -0
  21. package/dist/cli/pi-native-probe.d.ts +2 -0
  22. package/dist/cli/pi-paths.d.ts +2 -0
  23. package/dist/cli/pi-resources.d.ts +3 -1
  24. package/dist/cli/pi-tool-config.d.ts +32 -0
  25. package/dist/cli/tui/index.js +3 -3
  26. package/dist/cli/types.d.ts +2 -0
  27. package/dist/config/constants.d.ts +4 -8
  28. package/dist/config/schema.d.ts +7 -36
  29. package/dist/harness/adapters/claude-code.d.ts +2 -4
  30. package/dist/harness/core/agent-pack.d.ts +52 -42
  31. package/dist/harness/core/memory-governance.d.ts +2 -2
  32. package/dist/harness/core/sdd.d.ts +159 -319
  33. package/dist/harness/writers/pi-agent.d.ts +3 -1
  34. package/dist/index.js +12 -6
  35. package/dist/pi/tools-panel.d.ts +51 -0
  36. package/dist/pi.d.ts +44 -2
  37. package/dist/pi.js +471 -9
  38. package/dist/utils/subprocess.d.ts +1 -0
  39. package/package.json +18 -4
  40. package/pi/.thoth-agents-assets.json +5 -6
  41. package/pi/agents/thoth-designer.md +23 -8
  42. package/pi/agents/thoth-explorer.md +29 -9
  43. package/pi/agents/thoth-librarian.md +30 -8
  44. package/pi/agents/thoth-oracle.md +18 -10
  45. package/pi/agents/thoth-worker.md +96 -0
  46. package/plugin/.claude-plugin/.thoth-agents-plugin-assets.json +7 -12
  47. package/plugin/.claude-plugin/plugin.json +2 -2
  48. package/plugin/.codex-plugin/plugin.json +2 -2
  49. package/plugin/agents/designer.md +13 -5
  50. package/plugin/agents/explorer.md +16 -5
  51. package/plugin/agents/librarian.md +15 -4
  52. package/plugin/agents/oracle.md +13 -7
  53. package/plugin/agents/orchestrator.md +82 -91
  54. package/plugin/agents/worker.md +76 -0
  55. package/plugin/skills/plan-reviewer/SKILL.md +39 -141
  56. package/plugin/skills/thoth-archive/SKILL.md +50 -47
  57. package/plugin/skills/thoth-archive/scripts/archive.mjs +287 -654
  58. package/plugin/skills/thoth-constitution/SKILL.md +23 -42
  59. package/plugin/skills/thoth-constitution/templates/constitution.md +54 -44
  60. package/plugin/skills/thoth-init/SKILL.md +19 -29
  61. package/plugin/skills/thoth-init/scripts/init.mjs +73 -66
  62. package/plugin/skills/thoth-sdd/SKILL.md +164 -117
  63. package/plugin/skills/thoth-sdd/references/phases/checklist.md +2 -22
  64. package/plugin/skills/thoth-sdd/references/phases/clarify.md +14 -12
  65. package/plugin/skills/thoth-sdd/references/phases/converge.md +2 -13
  66. package/plugin/skills/thoth-sdd/references/phases/explore.md +3 -8
  67. package/plugin/skills/thoth-sdd/references/phases/implement.md +58 -57
  68. package/plugin/skills/thoth-sdd/references/phases/plan.md +2 -18
  69. package/plugin/skills/thoth-sdd/references/phases/specify.md +2 -33
  70. package/plugin/skills/thoth-sdd/references/phases/tasks.md +4 -45
  71. package/plugin/skills/thoth-sdd/references/phases/verify.md +4 -22
  72. package/plugin/skills/thoth-sdd/scripts/validate.mjs +610 -1232
  73. package/plugin/skills/thoth-sdd/templates/change.md +94 -0
  74. package/skills/README.md +11 -13
  75. package/skills/plan-reviewer/SKILL.md +39 -141
  76. package/skills/thoth-archive/SKILL.md +50 -47
  77. package/skills/thoth-archive/scripts/archive.mjs +287 -654
  78. package/skills/thoth-constitution/SKILL.md +23 -42
  79. package/skills/thoth-constitution/templates/constitution.md +54 -44
  80. package/skills/thoth-init/SKILL.md +19 -29
  81. package/skills/thoth-init/scripts/init.mjs +73 -66
  82. package/skills/thoth-sdd/SKILL.md +164 -117
  83. package/skills/thoth-sdd/references/phases/checklist.md +2 -22
  84. package/skills/thoth-sdd/references/phases/clarify.md +14 -12
  85. package/skills/thoth-sdd/references/phases/converge.md +2 -13
  86. package/skills/thoth-sdd/references/phases/explore.md +3 -8
  87. package/skills/thoth-sdd/references/phases/implement.md +58 -57
  88. package/skills/thoth-sdd/references/phases/plan.md +2 -18
  89. package/skills/thoth-sdd/references/phases/specify.md +2 -33
  90. package/skills/thoth-sdd/references/phases/tasks.md +4 -45
  91. package/skills/thoth-sdd/references/phases/verify.md +4 -22
  92. package/skills/thoth-sdd/scripts/validate.mjs +610 -1232
  93. package/skills/thoth-sdd/templates/change.md +94 -0
  94. package/thoth-agents.schema.json +9 -77
  95. package/dist/agents/deep.d.ts +0 -2
  96. package/dist/agents/quick.d.ts +0 -2
  97. package/dist/chunk-2U5MBLLV.js +0 -312
  98. package/pi/agents/thoth-deep.md +0 -81
  99. package/pi/agents/thoth-quick.md +0 -81
  100. package/plugin/agents/deep.md +0 -68
  101. package/plugin/agents/quick.md +0 -68
  102. package/plugin/skills/plan-reviewer/templates/plan-review.md +0 -65
  103. package/plugin/skills/thoth-sdd/templates/archive-report.md +0 -25
  104. package/plugin/skills/thoth-sdd/templates/checklist.md +0 -27
  105. package/plugin/skills/thoth-sdd/templates/plan.md +0 -46
  106. package/plugin/skills/thoth-sdd/templates/spec.md +0 -62
  107. package/plugin/skills/thoth-sdd/templates/tasks.md +0 -58
  108. package/plugin/skills/thoth-sdd/templates/verify-report.md +0 -28
  109. package/skills/plan-reviewer/templates/plan-review.md +0 -65
  110. package/skills/thoth-sdd/templates/archive-report.md +0 -25
  111. package/skills/thoth-sdd/templates/checklist.md +0 -27
  112. package/skills/thoth-sdd/templates/plan.md +0 -46
  113. package/skills/thoth-sdd/templates/spec.md +0 -62
  114. package/skills/thoth-sdd/templates/tasks.md +0 -58
  115. package/skills/thoth-sdd/templates/verify-report.md +0 -28
@@ -1,53 +1,34 @@
1
1
  ---
2
2
  name: thoth-constitution
3
- description: Create or explicitly amend the project constitution, choose its governance SemVer bump, propagate its impact, and validate lifecycle metadata. Use only for constitution lifecycle work; routine SDD planning reads the constitution without activating this skill.
3
+ description: Create or explicitly amend the active .thoth constitution with SemVer and sync-impact lifecycle validation.
4
4
  license: MIT
5
- compatibility: Requires Node.js >=22.19 for bundled validation scripts.
5
+ compatibility: Requires Node.js >=22.19 for bundled validation.
6
6
  metadata:
7
7
  author: thoth-agents
8
- version: "1.0"
8
+ version: "2.0"
9
9
  ---
10
10
 
11
11
  # Thoth Constitution
12
12
 
13
- The canonical project constitution is `openspec/memory/constitution.md`.
14
- Resolve `<skill-dir>` as the directory containing this `SKILL.md`. Every bundled
15
- validator or template path below is anchored to that installed skill root rather
16
- than the project or current working directory.
17
-
18
- ## Routine SDD
19
-
20
- - Read every active principle before planning.
21
- - Record concrete pre-design and post-design Constitution Check evidence in
22
- `plan.md`.
23
- - Do not amend the constitution, bump its version, or run lifecycle validation
24
- for an ordinary feature change.
25
-
26
- ## Explicit amendment
27
-
28
- Activate this lifecycle only on explicit user direction or when the user accepts
29
- a confirmed durable governance change.
30
-
31
- 1. Read the current constitution and every affected template, instruction, and
32
- durable workflow document.
33
- 2. Classify the governance version bump:
34
- - **MAJOR** removes or redefines a principle or compatibility boundary.
35
- - **MINOR** adds a principle/section or materially expands guidance.
36
- - **PATCH** clarifies wording without semantic change.
37
- 3. Preserve the original ratification date, set `Last amended` to today, and
38
- update `Version` using complete `MAJOR.MINOR.PATCH` SemVer.
39
- 4. Prepend or refresh the HTML-comment `Sync Impact Report`: old → new version,
40
- modified principles, added/removed sections, affected templates with status,
41
- and follow-up TODOs.
42
- 5. Propagate the accepted rule to every affected template, instruction, and
43
- documentation surface in the same change.
44
- 6. Remove unexplained placeholders and deferred TODOs, then run:
45
-
46
- ```bash
47
- node "<skill-dir>/scripts/validate.mjs" \
48
- --constitution openspec/memory/constitution.md --json
13
+ Canonical active governance is `.thoth/constitution.md`; substantial change
14
+ records and durable specifications live under `.thoth/`. Historical changes are
15
+ preserved and are not an active workflow dependency. Routine SDD reads relevant
16
+ principles but does not amend constitution metadata.
17
+
18
+ Only explicit user direction or an accepted material governance change activates
19
+ amendment. Preserve original ratification, set last-amended to the amendment
20
+ date, choose MAJOR for redefinition/removal, MINOR for addition/material
21
+ expansion, PATCH for clarification, and refresh the Sync Impact Report (old/new
22
+ version, modified principles, added/removed sections, affected templates,
23
+ follow-up). This requirement for explicit activation is not replaced by a
24
+ defaulted choice. Any orchestrator choice presented during amendment follows the
25
+ shared per-question recommendation policy; a safe deferral keeps unresolved
26
+ human-owned intent open, and missing facts or secrets are never invented.
27
+ Propagate changes to affected instruction and template surfaces, then run:
28
+
29
+ ```text
30
+ node "<skill-dir>/scripts/validate.mjs" --constitution .thoth/constitution.md --json
49
31
  ```
50
32
 
51
- Initialization copies `<skill-dir>/templates/constitution.md` only when the
52
- project has no constitution, resolves its date placeholders, and never
53
- overwrites a project-owned constitution.
33
+ Initialization copies the bundled template only when the constitution is absent,
34
+ replaces date placeholders, and never overwrites project-owned governance.
@@ -15,57 +15,67 @@ Sync Impact Report
15
15
 
16
16
  ## Principles
17
17
 
18
- ### I. User-value first
18
+ ### I. Native authority and human choice
19
19
 
20
- Every change MUST map to an observable user or operator outcome. Speculative
21
- infrastructure without a current requirement is prohibited.
20
+ The active harness owns dispatch, status, wait, cancellation, and terminal
21
+ results. Workflow guidance MUST NOT build a scheduler, state mirror, or process
22
+ tools. Every change completes proportional explore, specify, and clarify
23
+ reasoning before the orchestrator classifies by meaningful coordination and
24
+ contract impact, uncertainty, and risk. File count alone does not increase scope:
25
+ a clear, low-risk localized mechanical change may touch several files and remain
26
+ small. Material product, architecture, security, and destructive decisions
27
+ remain human-owned; unresolved material intent blocks classification and
28
+ implementation. Whenever an orchestrator presents a choice with a meaningful
29
+ recommended action, it states that recommendation. For each choice separately,
30
+ repeat the same question after the first and second confirmed answerless native
31
+ returns without taking dependent action; after the third, select the
32
+ recommendation. Explicit answers and `Stop` win. Pending, unavailable, failed,
33
+ interrupted, or host-prohibited attempts do not count; report higher-priority
34
+ host limits accurately. Never fabricate facts or secrets. A safe deferral may be
35
+ the recommendation for unresolved human-owned intent and leaves it unresolved.
22
36
 
23
- ### II. Simplicity and bounded scope
37
+ ### II. Minimal recoverable SDD
24
38
 
25
- Delivery MUST use the smallest coherent design that satisfies accepted
26
- requirements. Non-goals MUST be named, and scope cannot expand silently.
27
- Before the SDD route question, Root MUST summarize relevant context, scope,
28
- clarity, risk, and its evidence-based recommendation. Any explicit answer wins.
29
- When the native question returns answerless, Root MUST make at most three total
30
- attempts; after the third answerless result, the recommended route counts as
31
- selected.
39
+ Small, clear, low-risk work uses test-first implementation and focused
40
+ verification without a persistent record. Substantial work uses one compact
41
+ `.thoth/changes/<id>/<id>.md` record for grounded exploration, intent, acceptance,
42
+ clarifications, decisions, plan, tasks, authorization, and verification. A
43
+ patch-sized change can still require planning when coordination impact,
44
+ uncertainty, or risk warrants it. Increased scope or risk reopens understanding
45
+ and classification. Avoid mandatory sidecar reports, evidence directories,
46
+ worker packets, or generated process tools. Historical changes remain untouched.
47
+ Provider memory is independent of project records.
32
48
 
33
- ### III. Testable contracts
49
+ ### III. Bounded ownership and verification
34
50
 
35
- Behavioral requirements MUST have observable acceptance evidence. Behavior
36
- changes MUST use test-first execution at an agreed public seam when practical.
51
+ Delegation depth is one and each mutable surface has one writer. Root accepts
52
+ terminal dependency results before releasing consumers. At substantial `ready`,
53
+ root always offers Oracle plan review (Recommended) or proceeding without review,
54
+ even if implementation was authorized; an unanswered offer never means skip.
55
+ After `[OKAY]`, root separately offers the Implement (Recommended) / Stop choice,
56
+ honors prior explicit authorization, and lets explicit Stop supersede it. Record
57
+ selection provenance as `EXPLICIT_REVIEW`, `EXPLICIT_SKIP`, or
58
+ `DEFAULT_REVIEW_AFTER_3`; only `EXPLICIT_SKIP` permits `SKIPPED`, and `OKAY`
59
+ requires explicit review or the third-return recommendation. A plan review is not
60
+ implementation authorization or final verification. Every change is verified;
61
+ substantial or materially risky work needs a fresh independent Oracle judgment,
62
+ and no implementation writer approves their own work. Archive only after
63
+ complete acceptance evidence and verification still match the actual record and
64
+ sources.
37
65
 
38
- ### IV. Independent assurance
66
+ ### IV. Durable governance
39
67
 
40
- Every route MUST include verification proportional to the changed behavior and
41
- risk. The implementation writer cannot approve its own work. Trivial
42
- deterministic Direct work MAY be verified by Root when the decision is bounded
43
- and independent of the implementation writer. Materially risky Direct work and
44
- every Accelerated or Full final verify MUST use a fresh independent read-only
45
- reviewer. Pre-implementation plan review is optional and is selected explicitly
46
- or by the bounded recommended fallback; when offered, any explicit answer wins.
47
- After the third answerless result,
48
- `Review plan with Oracle (Recommended)` counts as selected. Actionable review
49
- rejections MUST be repaired and revalidated before a fresh reviewer round until
50
- approval or a material human-owned blocker. After approval, Root MUST give an
51
- approved plan summary before asking `Implement (Recommended)` or `Stop`; any
52
- explicit answer wins, while the third answerless result selects implementation.
53
- Plan review never substitutes for final verification.
54
-
55
- ### V. Traceable delivery
56
-
57
- Specifications, plans, tasks, implementation evidence, verification verdicts,
58
- and archive reports MUST remain traceable without relying on chat history.
68
+ Declare ADDED, MODIFIED, REMOVED, or RENAMED requirement deltas by capability and
69
+ exact title against `.thoth/specs/`. Apply only reviewed deltas at transactional
70
+ archive; preserve unaffected canonical requirements and historical changes.
71
+ Recovery inspects retained transactions before retry and never blindly replays
72
+ external effects.
59
73
 
60
74
  ## Governance
61
75
 
62
- - Planning MUST record evidence-backed Constitution Check results before and
63
- after design; routine feature work reads the principles but does not amend or
64
- revalidate constitution lifecycle metadata.
65
- - Exceptions MUST identify the principle, reason, risk, owner, and removal
66
- condition.
67
- - Amendments require explicit user direction, an updated Sync Impact Report,
68
- and propagation to affected templates, instructions, and documentation.
69
- - MAJOR versions remove or redefine governance compatibility.
70
- - MINOR versions add a principle or materially expand guidance.
71
- - PATCH versions clarify wording without changing its meaning.
76
+ - Amendments require explicit user direction, a refreshed Sync Impact Report,
77
+ and propagation to affected templates and instructions.
78
+ - Routine work reads relevant active principles; it does not amend lifecycle metadata.
79
+ - MAJOR versions remove or redefine a principle or compatibility boundary.
80
+ - MINOR versions add principles or materially expand guidance.
81
+ - PATCH versions clarify wording without changing semantic behavior.
@@ -1,43 +1,33 @@
1
1
  ---
2
2
  name: thoth-init
3
- description: Initialize or synchronize the minimum project OpenSpec governance structure required by thoth-agents SDD flows.
3
+ description: Initialize canonical offline .thoth governance without modifying existing project records.
4
4
  license: MIT
5
- compatibility: Requires Node.js >=22.19 and write access to the target project.
5
+ compatibility: Requires Node.js >=22.19 and write access to target project.
6
6
  metadata:
7
7
  author: thoth-agents
8
- version: "1.0"
8
+ version: "2.0"
9
9
  ---
10
10
 
11
11
  # Thoth Init
12
12
 
13
- Initialize or synchronize the current project's OpenSpec governance from this
14
- installed skill bundle. Resolve `<skill-dir>` as the directory containing this
15
- `SKILL.md`, then run the bundled script by absolute path:
13
+ Run the installed script by absolute skill-root path:
16
14
 
17
15
  ```text
18
16
  node "<skill-dir>/scripts/init.mjs" --project <project-root> --json
19
17
  ```
20
18
 
21
- The project root must already exist. The initializer preflights the complete
22
- target structure before changing it, then ensures these minimum paths exist:
23
-
24
- - `openspec/changes/archive/`
25
- - `openspec/specs/`
26
- - `openspec/memory/`
27
- - `openspec/.thoth-agents.json`
28
-
29
- The missing constitution is copied from the installed sibling
30
- `thoth-constitution` skill. An existing constitution remains byte-for-byte
31
- intact, while the thoth-managed manifest may be normalized to the current
32
- contract. Any legacy `openspec/templates/` tree is outside the managed graph and
33
- remains untouched. Inspect the JSON `created`, `managed`, and `preserved` arrays
34
- when reporting the result.
35
-
36
- The initializer never creates, copies, validates, reads, or synchronizes SDD
37
- workflow templates. Those assets remain in the installed `thoth-sdd` skill and
38
- are consumed directly from that bundle by the workflow phase contracts.
39
-
40
- This operation is offline, idempotent, and harness-neutral. Every write stays
41
- inside `openspec/`. It never installs or synchronizes skills, agents, plugins,
42
- harness configuration, external dependencies, or global instruction files;
43
- those are responsibilities of `npx thoth-agents install`.
19
+ For a new project, initialize `.thoth/changes/archive/`, `.thoth/specs/`, and
20
+ `.thoth/constitution.md`. A missing constitution comes from the sibling
21
+ thoth-constitution template with date placeholders filled. Preserve an existing
22
+ constitution and all existing `.thoth` change/spec history byte-for-byte; never
23
+ auto-migrate or overwrite project governance. Refuse symlinked ancestors,
24
+ unknown path collisions, or an active legacy OpenSpec tree rather than creating a
25
+ duplicate active store. Migration is an explicit project change, not an init side
26
+ effect.
27
+
28
+ The operation is offline and idempotent. It creates no manifests, change records,
29
+ workflow templates, OpenSpec tree, process tools, or mirrored state. Return JSON
30
+ `created` and `preserved` paths. No installer or network access is involved.
31
+ This skill presents no interactive choices and does not infer missing target
32
+ facts. Any orchestrator choice around initialization follows the shared SDD
33
+ recommendation and per-question retry policy.
@@ -1,24 +1,21 @@
1
1
  #!/usr/bin/env node
2
-
3
- import {
4
- existsSync,
5
- lstatSync,
6
- mkdirSync,
7
- readFileSync,
8
- writeFileSync,
9
- } from 'node:fs';
10
- import { dirname, join, resolve } from 'node:path';
2
+ import { lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { dirname, join, parse, resolve, sep } from 'node:path';
11
4
  import { fileURLToPath } from 'node:url';
12
5
 
13
6
  const SCRIPT_PATH = fileURLToPath(import.meta.url);
14
7
  const SKILL_ROOT = dirname(dirname(SCRIPT_PATH));
15
8
  const BUNDLE_ROOT = dirname(SKILL_ROOT);
16
- const OPEN_SPEC_DIRECTORIES = [
17
- 'openspec',
9
+ const THOTH_DIRECTORIES = [
10
+ '.thoth',
11
+ join('.thoth', 'changes'),
12
+ join('.thoth', 'changes', 'archive'),
13
+ join('.thoth', 'specs'),
14
+ ];
15
+ const LEGACY_ACTIVE_PATHS = [
18
16
  join('openspec', 'changes'),
19
- join('openspec', 'changes', 'archive'),
20
17
  join('openspec', 'specs'),
21
- join('openspec', 'memory'),
18
+ join('openspec', 'memory', 'constitution.md'),
22
19
  ];
23
20
 
24
21
  function parseArgs(argv) {
@@ -33,25 +30,65 @@ function parseArgs(argv) {
33
30
  return options;
34
31
  }
35
32
 
33
+ function lstatMaybe(path) {
34
+ try {
35
+ return lstatSync(path);
36
+ } catch (error) {
37
+ if (error.code === 'ENOENT' || error.code === 'ENOTDIR') return undefined;
38
+ throw error;
39
+ }
40
+ }
41
+
42
+ function assertNoSymlinkAncestors(path, label) {
43
+ const absolute = resolve(path);
44
+ const { root } = parse(absolute);
45
+ let cursor = root;
46
+ for (const part of absolute.slice(root.length).split(sep).filter(Boolean)) {
47
+ cursor = join(cursor, part);
48
+ if (lstatMaybe(cursor)?.isSymbolicLink()) {
49
+ throw new Error(`${label} has a symlinked ancestor: ${cursor}`);
50
+ }
51
+ }
52
+ }
53
+
36
54
  function assertDirectory(path, label) {
37
- if (!existsSync(path)) return;
38
- const stat = lstatSync(path);
39
- if (stat.isSymbolicLink() || !stat.isDirectory()) {
55
+ assertNoSymlinkAncestors(path, label);
56
+ const stat = lstatMaybe(path);
57
+ if (stat && (!stat.isDirectory() || stat.isSymbolicLink())) {
40
58
  throw new Error(`${label} must be a directory: ${path}`);
41
59
  }
42
60
  }
43
61
 
44
62
  function assertRegularFile(path, label) {
45
- if (!existsSync(path)) return;
46
- const stat = lstatSync(path);
47
- if (stat.isSymbolicLink() || !stat.isFile()) {
63
+ assertNoSymlinkAncestors(path, label);
64
+ const stat = lstatMaybe(path);
65
+ if (stat && (!stat.isFile() || stat.isSymbolicLink())) {
48
66
  throw new Error(`${label} must be a regular file: ${path}`);
49
67
  }
50
68
  }
51
69
 
70
+ function assertNoLegacyActiveStore(project) {
71
+ const openspec = join(project, 'openspec');
72
+ assertDirectory(openspec, 'Legacy OpenSpec path');
73
+ for (const relativePath of LEGACY_ACTIVE_PATHS) {
74
+ const target = join(project, relativePath);
75
+ assertNoSymlinkAncestors(target, 'Legacy OpenSpec path');
76
+ if (lstatMaybe(target)) {
77
+ throw new Error(
78
+ `Active legacy OpenSpec content requires explicit migration before init: ${target}`,
79
+ );
80
+ }
81
+ }
82
+ }
83
+
52
84
  function preflight(project) {
53
- assertDirectory(project, 'Project root');
54
- if (!existsSync(project)) {
85
+ assertNoSymlinkAncestors(project, 'Project root');
86
+ const projectStat = lstatMaybe(project);
87
+ if (
88
+ !projectStat ||
89
+ !projectStat.isDirectory() ||
90
+ projectStat.isSymbolicLink()
91
+ ) {
55
92
  throw new Error(
56
93
  `--project must reference an existing project directory: ${project}`,
57
94
  );
@@ -64,64 +101,40 @@ function preflight(project) {
64
101
  'constitution.md',
65
102
  );
66
103
  assertRegularFile(constitutionSource, 'Bundled constitution template');
67
- if (!existsSync(constitutionSource)) {
104
+ if (!lstatMaybe(constitutionSource)) {
68
105
  throw new Error(
69
106
  `Bundled constitution template is missing: ${constitutionSource}`,
70
107
  );
71
108
  }
72
109
 
73
- for (const directory of OPEN_SPEC_DIRECTORIES) {
74
- assertDirectory(join(project, directory), 'OpenSpec path');
110
+ for (const directory of THOTH_DIRECTORIES) {
111
+ assertDirectory(join(project, directory), 'Thoth path');
75
112
  }
76
113
 
77
- const constitutionTarget = join(
78
- project,
79
- 'openspec',
80
- 'memory',
81
- 'constitution.md',
82
- );
83
- const manifestTarget = join(project, 'openspec', '.thoth-agents.json');
84
- assertRegularFile(constitutionTarget, 'OpenSpec constitution path');
85
- assertRegularFile(manifestTarget, 'OpenSpec manifest path');
86
-
87
- return {
88
- constitutionSource,
89
- constitutionTarget,
90
- manifestTarget,
91
- };
114
+ const constitutionTarget = join(project, '.thoth', 'constitution.md');
115
+ assertRegularFile(constitutionTarget, 'Thoth constitution path');
116
+ assertNoLegacyActiveStore(project);
117
+
118
+ return { constitutionSource, constitutionTarget };
92
119
  }
93
120
 
94
121
  function createDirectory(target, report) {
95
- if (existsSync(target)) return;
122
+ if (lstatMaybe(target)) return;
96
123
  mkdirSync(target);
97
124
  report.created.push(target);
98
125
  }
99
126
 
100
127
  function writePreservingExisting(target, content, report) {
101
- if (existsSync(target)) {
128
+ if (lstatMaybe(target)) {
102
129
  report.preserved.push(target);
103
130
  return;
104
131
  }
105
- writeFileSync(target, content);
132
+ writeFileSync(target, content, { flag: 'wx' });
106
133
  report.created.push(target);
107
134
  }
108
135
 
109
- function synchronizeManagedFile(target, content, report) {
110
- if (!existsSync(target)) {
111
- writeFileSync(target, content);
112
- report.created.push(target);
113
- return;
114
- }
115
- if (readFileSync(target, 'utf8') === content) {
116
- report.preserved.push(target);
117
- return;
118
- }
119
- writeFileSync(target, content);
120
- report.managed.push(target);
121
- }
122
-
123
- function synchronizeOpenSpec(project, assets, report) {
124
- for (const directory of OPEN_SPEC_DIRECTORIES) {
136
+ function initializeThoth(project, assets, report) {
137
+ for (const directory of THOTH_DIRECTORIES) {
125
138
  createDirectory(join(project, directory), report);
126
139
  }
127
140
 
@@ -134,11 +147,6 @@ function synchronizeOpenSpec(project, assets, report) {
134
147
  ),
135
148
  report,
136
149
  );
137
- synchronizeManagedFile(
138
- assets.manifestTarget,
139
- `${JSON.stringify({ version: 1, initializedBy: 'thoth-agents' }, null, 2)}\n`,
140
- report,
141
- );
142
150
  }
143
151
 
144
152
  try {
@@ -149,15 +157,14 @@ try {
149
157
  status: 'ready',
150
158
  project,
151
159
  created: [],
152
- managed: [],
153
160
  preserved: [],
154
161
  };
155
162
 
156
- synchronizeOpenSpec(project, assets, report);
163
+ initializeThoth(project, assets, report);
157
164
 
158
165
  const output = options.json
159
166
  ? JSON.stringify(report)
160
- : `thoth-agents synchronized OpenSpec governance in ${project}`;
167
+ : `thoth-agents initialized .thoth governance in ${project}`;
161
168
  process.stdout.write(`${output}\n`);
162
169
  } catch (error) {
163
170
  process.stderr.write(