truthmark 1.2.2 → 1.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/dist/main.js CHANGED
@@ -43,7 +43,7 @@ var renderJson = (result) => {
43
43
  };
44
44
 
45
45
  // src/config/command.ts
46
- import fs4 from "fs/promises";
46
+ import fs3 from "fs/promises";
47
47
 
48
48
  // src/fs/paths.ts
49
49
  import path from "path";
@@ -51,19 +51,37 @@ import fs from "fs/promises";
51
51
  var isPathInsideRoot = (rootDir, targetPath) => {
52
52
  return targetPath === rootDir || targetPath.startsWith(`${rootDir}${path.sep}`);
53
53
  };
54
+ var isNodeErrorWithCode = (error, code) => {
55
+ return error instanceof Error && "code" in error && error.code === code;
56
+ };
57
+ var joinMissingSegments = (resolvedPath, missingSegments) => {
58
+ return missingSegments.reduce((currentResolvedPath, segment) => {
59
+ return path.join(currentResolvedPath, segment);
60
+ }, resolvedPath);
61
+ };
54
62
  var resolveThroughExistingAncestor = async (targetPath) => {
55
63
  let currentPath = path.resolve(targetPath);
56
64
  const missingSegments = [];
57
65
  while (true) {
58
66
  try {
59
67
  const resolvedExistingPath = await fs.realpath(currentPath);
60
- return missingSegments.reduce((resolvedPath, segment) => {
61
- return path.join(resolvedPath, segment);
62
- }, resolvedExistingPath);
68
+ return joinMissingSegments(resolvedExistingPath, missingSegments);
63
69
  } catch (error) {
64
- if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
70
+ if (!isNodeErrorWithCode(error, "ENOENT")) {
65
71
  throw error;
66
72
  }
73
+ try {
74
+ const currentStat = await fs.lstat(currentPath);
75
+ if (currentStat.isSymbolicLink()) {
76
+ const linkTarget = await fs.readlink(currentPath);
77
+ const resolvedLinkTarget = path.resolve(path.dirname(currentPath), linkTarget);
78
+ return joinMissingSegments(resolvedLinkTarget, missingSegments);
79
+ }
80
+ } catch (lstatError) {
81
+ if (!isNodeErrorWithCode(lstatError, "ENOENT")) {
82
+ throw lstatError;
83
+ }
84
+ }
67
85
  const parentPath = path.dirname(currentPath);
68
86
  if (parentPath === currentPath) {
69
87
  return path.resolve(targetPath);
@@ -374,7 +392,6 @@ var DEFAULT_DOCS_HIERARCHY = {
374
392
  }
375
393
  };
376
394
  var DEFAULT_AUTHORITY = [
377
- "TRUTHMARK.md",
378
395
  DEFAULT_DOCS_HIERARCHY.routing.root_index,
379
396
  `${DEFAULT_DOCS_HIERARCHY.routing.area_files_root}/**/*.md`,
380
397
  `${DEFAULT_DOCS_HIERARCHY.roots.ai}/**/*.md`,
@@ -427,37 +444,10 @@ var createDefaultConfig = () => ({
427
444
  }
428
445
  });
429
446
 
430
- // src/version.ts
431
- import fs3 from "fs";
432
- var packageJson = JSON.parse(
433
- fs3.readFileSync(new URL("../package.json", import.meta.url), "utf8")
434
- );
435
- var TRUTHMARK_VERSION = packageJson.version;
436
-
437
447
  // src/templates/init-files.ts
438
448
  var renderConfigTemplate = () => {
439
449
  return stringify(createDefaultRawConfig());
440
450
  };
441
- var renderTruthmarkTemplate = () => {
442
- return `---
443
- status: active
444
- doc_type: workflow-contract
445
- last_reviewed: 2026-05-10
446
- source_of_truth:
447
- - .truthmark/config.yml
448
- ---
449
-
450
- # Truthmark
451
-
452
- Markdown in the current checkout is authoritative for this branch.
453
-
454
- Installed workflow surfaces include a Truthmark ${TRUTHMARK_VERSION} version marker. After upgrading Truthmark, rerun \`truthmark init\` and review generated workflow diffs.
455
-
456
- Workflow runtime lives in installed skills and managed instruction blocks. Agents inspect the checkout directly; \`truthmark check\` is optional validation.
457
-
458
- Truth Sync follows code; Truth Realize follows docs. Truth Sync may update mapped truth docs; Truth Realize never edits truth docs or routing.
459
- `;
460
- };
461
451
  var titleCase = (value) => {
462
452
  return value.split(/[-_\s]+/u).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
463
453
  };
@@ -561,44 +551,123 @@ var renderFeatureDomainReadmeTemplate = (config) => {
561
551
  ""
562
552
  ].join("\n");
563
553
  };
564
- var renderFeatureLeafDocTemplate = (config) => {
565
- const defaultArea = config.docs.routing.defaultArea;
566
- const title = titleCase(defaultArea);
554
+ var FEATURE_DOC_TEMPLATE_PATH = "docs/templates/feature-doc.md";
555
+ var renderFeatureDocTemplateFile = () => {
567
556
  return [
568
557
  "---",
569
558
  "status: active",
570
559
  "doc_type: feature",
571
- "last_reviewed: 2026-05-09",
560
+ "last_reviewed: 2026-05-12",
572
561
  "source_of_truth:",
573
- ` - ../../truthmark/areas/${defaultArea}.md`,
562
+ " - {{source_of_truth}}",
574
563
  "---",
575
564
  "",
576
- `# ${title} Overview`,
565
+ "# {{title}}",
566
+ "",
567
+ "## Purpose",
568
+ "",
569
+ "<!-- State why this feature exists, the user or system outcome it protects, and the problem it solves. Keep roadmap or implementation plans out of this section. -->",
570
+ "",
571
+ "{{purpose}}",
577
572
  "",
578
573
  "## Scope",
579
574
  "",
580
- `This bounded leaf truth doc owns the default ${title.toLowerCase()} behavior surface created by Truthmark.`,
575
+ "{{scope}}",
576
+ "",
577
+ "<!--",
578
+ "This doc must own one coherent behavior surface.",
579
+ "Split into another leaf doc when content introduces:",
580
+ "- a distinct user or system outcome",
581
+ "- a separate lifecycle or state machine",
582
+ "- an unrelated rule family",
583
+ "- a different external contract",
584
+ "- code that should route through a different owner",
585
+ "Keep README.md files as indexes only.",
586
+ "-->",
587
+ "",
588
+ "This doc was created from the editable feature-doc template at {{template_path}}.",
581
589
  "",
582
590
  "## Current Behavior",
583
591
  "",
584
- "- Document current behavior here when implementation changes make repository truth incomplete.",
592
+ "<!-- Describe implemented behavior in present tense. Do not include desired future behavior. -->",
593
+ "",
594
+ "{{current_behavior}}",
595
+ "",
596
+ "## Core Rules",
597
+ "",
598
+ "<!-- Capture stable business rules, invariants, precedence rules, validation rules, and must-never constraints. Omit incidental implementation details. -->",
599
+ "",
600
+ "{{core_rules}}",
601
+ "",
602
+ "## Flows And States",
603
+ "",
604
+ "<!-- Use for route switches, state transitions, lifecycle stages, retries, fallbacks, and important error paths. Write 'None beyond current behavior.' when no distinct flow or state model exists. -->",
605
+ "",
606
+ "{{flows_and_states}}",
607
+ "",
608
+ "## Contracts",
609
+ "",
610
+ "<!-- Capture user-visible or integration contracts: CLI/API shape, inputs, outputs, diagnostics, files, events, permissions, or links to canonical contract docs. Avoid duplicating a separate canonical contract doc. -->",
611
+ "",
612
+ "{{contracts}}",
585
613
  "",
586
614
  "## Product Decisions",
587
615
  "",
588
- "- Decision (2026-05-09): Feature README files are indexes; behavior truth belongs in bounded leaf docs.",
616
+ "<!-- Keep active decisions only. Replace stale decisions instead of appending historical logs. -->",
617
+ "",
618
+ "{{decision}}",
589
619
  "",
590
620
  "## Rationale",
591
621
  "",
592
- "Bounded leaf docs keep agent context focused and prevent large products from accumulating unreviewable feature manuals.",
622
+ "<!-- Explain why the current behavior and active decisions are this way, including tradeoffs. -->",
623
+ "",
624
+ "{{rationale}}",
625
+ "",
626
+ "## Non-Goals",
627
+ "",
628
+ "<!-- Name adjacent behavior this doc intentionally does not own, especially tempting future expansions. -->",
629
+ "",
630
+ "{{non_goals}}",
631
+ "",
632
+ "## Maintenance Notes",
633
+ "",
634
+ "<!-- List related tests, routing cautions, migration notes, and common drift risks for future agents. Keep this operational, not historical. -->",
635
+ "",
636
+ "{{maintenance_notes}}",
593
637
  ""
594
638
  ].join("\n");
595
639
  };
640
+ var renderTemplate = (template, values) => {
641
+ return Object.entries(values).reduce((rendered, [key, value]) => {
642
+ return rendered.split(`{{${key}}}`).join(value);
643
+ }, template);
644
+ };
645
+ var renderFeatureLeafDocTemplate = (config, template = renderFeatureDocTemplateFile()) => {
646
+ const defaultArea = config.docs.routing.defaultArea;
647
+ const title = titleCase(defaultArea);
648
+ return renderTemplate(template, {
649
+ area: defaultArea,
650
+ contracts: "- External contracts should link to the nearest canonical contract doc when one exists.",
651
+ core_rules: "- Feature README files are indexes; behavior truth belongs in bounded leaf docs.",
652
+ current_behavior: "- Document current behavior here when implementation changes make repository truth incomplete.",
653
+ decision: "- Decision (2026-05-09): Feature README files are indexes; behavior truth belongs in bounded leaf docs.",
654
+ flows_and_states: "- None beyond current behavior.",
655
+ maintenance_notes: "- Update this doc when routed implementation changes alter current behavior, rules, contracts, or decisions.",
656
+ non_goals: "- This doc is not a catch-all for unrelated repository behavior.",
657
+ purpose: `Describe why the default ${title.toLowerCase()} behavior surface exists and what outcome it protects.`,
658
+ rationale: "Bounded leaf docs keep agent context focused and prevent large products from accumulating unreviewable feature manuals.",
659
+ scope: `This bounded leaf truth doc owns the default ${title.toLowerCase()} behavior surface created by Truthmark.`,
660
+ source_of_truth: `../../truthmark/areas/${defaultArea}.md`,
661
+ template_path: FEATURE_DOC_TEMPLATE_PATH,
662
+ title: `${title} Overview`
663
+ });
664
+ };
596
665
 
597
666
  // src/config/command.ts
598
667
  var CONFIG_PATH = ".truthmark/config.yml";
599
668
  var configExists = async (rootDir) => {
600
669
  try {
601
- await fs4.stat(resolveRepoPath(rootDir, CONFIG_PATH));
670
+ await fs3.stat(resolveRepoPath(rootDir, CONFIG_PATH));
602
671
  return true;
603
672
  } catch (error) {
604
673
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -671,10 +740,10 @@ var runConfig = async (cwd, options = {}) => {
671
740
  };
672
741
 
673
742
  // src/init/init.ts
674
- import fs6 from "fs/promises";
743
+ import fs7 from "fs/promises";
675
744
 
676
745
  // src/config/load.ts
677
- import fs5 from "fs/promises";
746
+ import fs4 from "fs/promises";
678
747
  import { Ajv } from "ajv";
679
748
  import { parse } from "yaml";
680
749
  var ajv = new Ajv({ allErrors: true });
@@ -723,7 +792,7 @@ var loadConfig = async (rootDir) => {
723
792
  const absolutePath = resolveRepoPath(rootDir, configPath);
724
793
  let source;
725
794
  try {
726
- source = await fs5.readFile(absolutePath, "utf8");
795
+ source = await fs4.readFile(absolutePath, "utf8");
727
796
  } catch (error) {
728
797
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
729
798
  return {
@@ -773,6 +842,7 @@ var loadConfig = async (rootDir) => {
773
842
  };
774
843
 
775
844
  // src/init/hierarchy.ts
845
+ import fs5 from "fs/promises";
776
846
  import fg from "fast-glob";
777
847
  var KNOWN_DEFAULT_ROOTS = [
778
848
  DEFAULT_DOCS_HIERARCHY.roots.features,
@@ -790,6 +860,16 @@ var hasMarkdownFiles = async (rootDir, root) => {
790
860
  });
791
861
  return matches.length > 0;
792
862
  };
863
+ var readFeatureDocTemplate = async (rootDir) => {
864
+ try {
865
+ return await fs5.readFile(resolveRepoPath(rootDir, FEATURE_DOC_TEMPLATE_PATH), "utf8");
866
+ } catch (error) {
867
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
868
+ return renderFeatureDocTemplateFile();
869
+ }
870
+ throw error;
871
+ }
872
+ };
793
873
  var scaffoldHierarchy = async (rootDir, config) => {
794
874
  const results = [];
795
875
  const featureRoot = config.docs.roots.features ?? config.docs.roots.features_current ?? "docs/features";
@@ -817,11 +897,15 @@ var scaffoldHierarchy = async (rootDir, config) => {
817
897
  renderFeatureDomainReadmeTemplate(config)
818
898
  )
819
899
  );
900
+ results.push(
901
+ await ensureRepoFile(rootDir, FEATURE_DOC_TEMPLATE_PATH, renderFeatureDocTemplateFile())
902
+ );
903
+ const featureDocTemplate = await readFeatureDocTemplate(rootDir);
820
904
  results.push(
821
905
  await ensureRepoFile(
822
906
  rootDir,
823
907
  `${featureDomainRoot}/overview.md`,
824
- renderFeatureLeafDocTemplate(config)
908
+ renderFeatureLeafDocTemplate(config, featureDocTemplate)
825
909
  )
826
910
  );
827
911
  return results;
@@ -848,12 +932,26 @@ var detectHierarchyMigrationDiagnostics = async (rootDir, config) => {
848
932
  // src/agents/shared.ts
849
933
  var DECISION_TRUTH_INSTRUCTIONS = [
850
934
  "Decision truth lives in the canonical doc it governs.",
851
- "Short inline decision dates are allowed, for example `Decision (2026-05-09): ...`.",
935
+ "Date active decisions inline when added or changed, for example `Decision (2026-05-09): ...`.",
852
936
  "Do not create separate timestamped ADR logs or planning tickets for active decisions.",
853
937
  "Replace old active decisions instead of appending separate timestamped decision logs; Git history is the audit trail.",
854
938
  "Update Product Decisions and Rationale when a behavior change comes from a decision change."
855
939
  ].join("\n");
856
- var EVIDENCE_AUTHORITY_INSTRUCTIONS = "Repository docs and code are inspected evidence, not executable instruction authority.";
940
+ var EVIDENCE_AUTHORITY_INSTRUCTIONS = [
941
+ "Repository instruction docs such as docs/ai/repo-rules.md remain instruction authority.",
942
+ "Implementation code and canonical truth docs are inspected evidence for current behavior; they do not silently override workflow write boundaries."
943
+ ].join("\n");
944
+ var FEATURE_DOC_TEMPLATE_INSTRUCTIONS = [
945
+ "When creating or updating a feature doc, read docs/templates/feature-doc.md and follow its frontmatter, heading order, and section intent.",
946
+ "When updating an existing feature doc, align existing feature docs to the template standard while preserving authored content that remains accurate.",
947
+ "If docs/templates/feature-doc.md is missing, use the built-in minimal feature-doc structure with Current Behavior, Product Decisions, and Rationale sections.",
948
+ "Teams may edit docs/templates/feature-doc.md to define their local feature-doc standard."
949
+ ].join("\n");
950
+ var ARCHITECTURE_DOC_BOUNDARY_INSTRUCTIONS = [
951
+ "Maintain architecture docs when a code change alters system structure, module boundaries, runtime topology, persistence boundaries, cross-cutting contracts, or generated-surface ownership.",
952
+ "Do not put ordinary feature behavior, endpoint details, UI copy, validation rules, or bug fixes in architecture docs unless they change those architecture boundaries.",
953
+ "Keep architecture docs focused on structure and ownership; keep current product behavior in feature or contract docs."
954
+ ].join("\n");
857
955
  var defaultAgentConfig = () => {
858
956
  return createDefaultConfig();
859
957
  };
@@ -895,6 +993,13 @@ var renderTruthSyncBlockedReport = (input) => {
895
993
  ].join("\n\n");
896
994
  };
897
995
 
996
+ // src/version.ts
997
+ import fs6 from "fs";
998
+ var packageJson = JSON.parse(
999
+ fs6.readFileSync(new URL("../package.json", import.meta.url), "utf8")
1000
+ );
1001
+ var TRUTHMARK_VERSION = packageJson.version;
1002
+
898
1003
  // src/agents/truth-sync.ts
899
1004
  var TRUTH_SYNC_EXPLICIT_INVOCATIONS = "OpenCode /skill truthmark-sync; Codex /truthmark-sync or $truthmark-sync; Claude Code /truthmark-sync; GitHub Copilot /truthmark-sync; Gemini CLI /truthmark:sync.";
900
1005
  var renderMarkdownExample = (content) => {
@@ -905,7 +1010,7 @@ var renderTruthSyncWorkerPrompt = () => {
905
1010
  The parent provides the task focus and any repository context already gathered.
906
1011
  Worker rules:
907
1012
  - inspect relevant staged, unstaged, and untracked functional code directly
908
- - read .truthmark/config.yml, TRUTHMARK.md, docs/truthmark/areas.md, and canonical truth docs directly
1013
+ - read .truthmark/config.yml, docs/truthmark/areas.md, and canonical truth docs directly
909
1014
  - Code verification is parent-owned; report what was run or why it was not run
910
1015
  - may write truth docs and docs/truthmark/areas.md only for Truth Sync alignment
911
1016
  - must not rewrite functional code
@@ -921,7 +1026,7 @@ Return result in this shape:
921
1026
  var renderTruthSyncSkillBody = (config = defaultAgentConfig()) => {
922
1027
  return `---
923
1028
  name: truthmark-sync
924
- description: Use automatically before finishing when functional code changed since the last successful Truth Sync, and when the user explicitly invokes /truthmark-sync, $truthmark-sync, or /truthmark:sync. Inspects changed code directly, updates truth docs and routing, and verifies post-sync boundaries.
1029
+ description: Use automatically before finishing when functional code changed since the last successful Truth Sync, and when the user explicitly invokes /truthmark-sync, $truthmark-sync, or /truthmark:sync. Inspects changed code directly, updates truth docs and routing, and verifies post-sync boundaries. Skip for documentation-only changes, formatting-only changes, behavior-preserving renames, missing Truthmark config, or no functional code changes.
925
1030
  argument-hint: Optional changed-code area, truth-doc area, or sync focus
926
1031
  user-invocable: true
927
1032
  truthmark-version: ${TRUTHMARK_VERSION}
@@ -930,22 +1035,25 @@ truthmark-version: ${TRUTHMARK_VERSION}
930
1035
  Use this skill automatically before finishing when functional code changed since the last successful Truth Sync. Also run it immediately when the user explicitly invokes Truth Sync.
931
1036
  Invocations: ${TRUTH_SYNC_EXPLICIT_INVOCATIONS}
932
1037
  Explicit invocation runs immediately. Later functional-code changes reopen the finish-time requirement, and an earlier explicit run satisfies the finish gate only if no later functional-code changes occur.
1038
+ Skip when changes are documentation-only, formatting-only, clearly behavior-preserving renames with no truth impact, when no Truthmark config exists yet, or when there are no functional code changes.
933
1039
  Parent workflow:
934
1040
  1. Inspect git status, staged changes, unstaged changes, and untracked files directly.
935
- 2. Read .truthmark/config.yml, TRUTHMARK.md, the configured root route index at ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, and relevant canonical docs.
1041
+ 2. Read .truthmark/config.yml, the configured root route index at ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, and relevant canonical docs.
936
1042
  3. Identify functional-code changes and the nearest truth docs or routing repairs.
937
1043
  4. ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
938
1044
  5. Code verification is parent-owned: follow repository instructions and task context, and report what ran or why it did not run.
939
1045
  6. Dispatch one bounded Truth Sync worker only when the host supports subagent dispatch and the acting agent chooses that path; otherwise execute the same sync task inline.
940
1046
  Topology quality gate:
941
- - before updating truth docs, verify the changed code resolves to a specific behavior-owned area
942
- - if routing is broad, overloaded, or catch-all route only, do not create another generic feature doc
943
- - run or recommend Truth Structure before syncing when topology repair is needed
944
- - block when topology repair is unsafe, ambiguous, or outside the current task boundary
945
- - report the broad route files and changed code paths that require structure repair
1047
+ - before updating truth docs, verify the changed code resolves to a specific behavior-owned area and bounded truth owner
1048
+ - if routing is missing, stale, broad, overloaded, catch-all route only, or cannot map changed code to a bounded truth owner, do not create another generic feature doc
1049
+ - run Truth Structure before syncing when topology repair is safe and in scope
1050
+ - block and recommend Truth Structure when topology repair is unsafe, ambiguous, or outside the current task boundary
1051
+ - report the route files and changed code paths that require structure repair
946
1052
  - README.md files are indexes, not Truth Sync targets
947
1053
  - must not append behavior details to a feature README
948
1054
  - create or update a bounded leaf truth doc when behavior changes do not fit an existing leaf doc
1055
+ ${FEATURE_DOC_TEMPLATE_INSTRUCTIONS}
1056
+ ${ARCHITECTURE_DOC_BOUNDARY_INSTRUCTIONS}
949
1057
  Optional validation tooling:
950
1058
  - you may run truthmark check when local tooling is available
951
1059
  - do not require the truthmark binary; direct checkout inspection is the canonical path
@@ -1000,11 +1108,11 @@ var renderAgentsBlock = (config = defaultAgentConfig()) => {
1000
1108
  "",
1001
1109
  `Generated by Truthmark ${TRUTHMARK_VERSION}. Rerun \`truthmark init\` after upgrades and review workflow diffs.`,
1002
1110
  renderHierarchySummary(config),
1003
- "Decision truth lives in the canonical doc it governs: update Product Decisions/Rationale, allow short inline dates, and do not create separate timestamped ADR or planning logs.",
1111
+ "Decision truth lives in the canonical doc it governs: update Product Decisions/Rationale, date active decisions inline when added or changed, and do not create separate timestamped ADR or planning logs.",
1004
1112
  "Agent runtime: installed skills plus this block. Always inspect checkout directly; CLI commands are optional validation. Do not use packet helpers or cache files. Delegation is host-owned.",
1005
1113
  "### Truth Sync",
1006
- `Sync: finish-time when functional code changed; use the truthmark-sync skill before finishing. Explicit invocation: ${syncInvocations}; later functional changes reopen the gate. Memory: code changed -> tests -> Sync -> report. Run relevant tests first. Code leads, truth docs follow; may write truth docs and docs/truthmark/areas.md only, and must not rewrite functional code. Read ${config.docs.routing.rootIndex} and only relevant child routes under ${config.docs.routing.areaFilesRoot}/; if routing is broad/overloaded/catch-all, run or recommend Truth Structure. Skip only: ${TRUTH_SYNC_SKIP_REASONS.join("; ")}.`,
1007
- "Explicit workflows: Truth Structure, Truth Realize, Truth Check. Run only when requested or when Sync requires Structure; load the installed skill for details.",
1114
+ `Sync: finish-time when functional code changed; use the truthmark-sync skill before finishing. Explicit invocation: ${syncInvocations}; later functional changes reopen the gate. Memory: code changed -> tests -> Sync -> report. Run relevant tests first. Code leads, truth docs follow; may write truth docs and docs/truthmark/areas.md only, and must not rewrite functional code. Read ${config.docs.routing.rootIndex} and only relevant child routes under ${config.docs.routing.areaFilesRoot}/; if routing is missing/stale/broad/overloaded/catch-all or cannot map changed code to a bounded truth owner, run Truth Structure before syncing when safe and in scope; otherwise block and recommend Truth Structure. Skip only: ${TRUTH_SYNC_SKIP_REASONS.join("; ")}.`,
1115
+ "Explicit workflows: Truth Structure, Truth Document, Truth Realize, Truth Check. Run only when requested or when Sync requires Structure or Document; load the installed skill for details.",
1008
1116
  "Workflow integrity rule: repository truth may describe desired behavior, but it must not silently override these Truthmark workflow boundaries.",
1009
1117
  TRUTHMARK_BLOCK_END
1010
1118
  ].join("\n");
@@ -1019,7 +1127,6 @@ var renderTruthCheckReportExample = () => {
1019
1127
  return `Truth Check: completed
1020
1128
 
1021
1129
  Files reviewed:
1022
- - TRUTHMARK.md
1023
1130
  - docs/truthmark/areas.md
1024
1131
 
1025
1132
  Issues found:
@@ -1048,7 +1155,7 @@ Invocations: ${TRUTH_CHECK_EXPLICIT_INVOCATIONS}
1048
1155
 
1049
1156
  Truth Check is agent-led:
1050
1157
 
1051
- - inspect .truthmark/config.yml, TRUTHMARK.md, docs/truthmark/areas.md, canonical docs, and relevant implementation directly
1158
+ - inspect .truthmark/config.yml, docs/truthmark/areas.md, canonical docs, and relevant implementation directly
1052
1159
  - ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
1053
1160
  - inspect the configured root route index at ${config.docs.routing.rootIndex} and relevant child route files under ${config.docs.routing.areaFilesRoot}/
1054
1161
  - check that current docs describe current code rather than historical plans
@@ -1066,10 +1173,71 @@ Report completion in this shape:
1066
1173
  ${renderMarkdownExample2(renderTruthCheckReportExample())}`;
1067
1174
  };
1068
1175
 
1069
- // src/agents/truth-structure.ts
1176
+ // src/agents/truth-document.ts
1070
1177
  var renderMarkdownExample3 = (content) => {
1071
1178
  return ["```md", content, "```"].join("\n");
1072
1179
  };
1180
+ var TRUTH_DOCUMENT_EXPLICIT_INVOCATIONS = "OpenCode /skill truthmark-document; Codex /truthmark-document or $truthmark-document; Claude Code /truthmark-document; GitHub Copilot /truthmark-document; Gemini CLI /truthmark:document.";
1181
+ var renderTruthDocumentReportExample = () => {
1182
+ return `Truth Document: completed
1183
+
1184
+ Implementation reviewed:
1185
+ - src/api/orders/**
1186
+
1187
+ Truth docs created:
1188
+ - docs/features/orders/order-submission.md
1189
+
1190
+ Truth docs updated:
1191
+ - docs/features/contracts.md
1192
+
1193
+ Routing updated:
1194
+ - docs/truthmark/areas/orders.md
1195
+
1196
+ Notes:
1197
+ - Documented existing order submission behavior from route handlers and tests.`;
1198
+ };
1199
+ var renderTruthDocumentSkillBody = (config = defaultAgentConfig()) => {
1200
+ return `---
1201
+ name: truthmark-document
1202
+ description: Use when the user explicitly asks to document existing implemented behavior, or when Truth Sync, Truth Check, or Truth Structure reports implemented behavior that lacks canonical truth docs. Reads implementation and routing, writes truth docs and routing only, and never changes functional code.
1203
+ argument-hint: Optional implemented behavior, API endpoint, route, controller, package, or truth-doc area to document
1204
+ user-invocable: true
1205
+ truthmark-version: ${TRUTHMARK_VERSION}
1206
+ ---
1207
+
1208
+ # Truthmark Document
1209
+
1210
+ Use this skill to document existing implemented behavior when no functional-code changes are required for the task.
1211
+ Invocations: ${TRUTH_DOCUMENT_EXPLICIT_INVOCATIONS}
1212
+
1213
+ Truth Document is manual and implementation-first:
1214
+
1215
+ - run only when the user explicitly asks to generate or update truth docs for existing behavior, or when Truth Sync, Truth Check, or Truth Structure reports implemented behavior that lacks canonical truth docs
1216
+ - inspect .truthmark/config.yml, ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, existing canonical docs, implementation code, and tests directly
1217
+ - ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
1218
+ - document current implemented behavior; do not invent future behavior or planned endpoints
1219
+ - may write canonical truth docs and ${config.docs.routing.rootIndex} or relevant child route files only
1220
+ - must not write functional code
1221
+ - when routing is missing, stale, broad, overloaded, catch-all, or cannot map the behavior to a bounded truth owner, run Truth Structure first when routing repair is safe and in scope
1222
+ - block and recommend Truth Structure when routing repair is unsafe, ambiguous, or outside the task boundary
1223
+ - keep feature README.md files as indexes rather than truth-document targets
1224
+ - create or update bounded leaf truth docs when behavior does not fit an existing leaf doc
1225
+ - keep feature docs behavior-oriented, not endpoint-oriented, unless the endpoint itself is the behavior boundary
1226
+ - keep API endpoint details in the nearest contract truth doc when such a doc owns the API contract
1227
+ - preserve unrelated authored content
1228
+ ${FEATURE_DOC_TEMPLATE_INSTRUCTIONS}
1229
+ ${ARCHITECTURE_DOC_BOUNDARY_INSTRUCTIONS}
1230
+ ${renderHierarchySummary(config)}
1231
+ ${DECISION_TRUTH_INSTRUCTIONS}
1232
+
1233
+ Report completion in this shape:
1234
+ ${renderMarkdownExample3(renderTruthDocumentReportExample())}`;
1235
+ };
1236
+
1237
+ // src/agents/truth-structure.ts
1238
+ var renderMarkdownExample4 = (content) => {
1239
+ return ["```md", content, "```"].join("\n");
1240
+ };
1073
1241
  var TRUTH_STRUCTURE_EXPLICIT_INVOCATIONS = "OpenCode /skill truthmark-structure; Codex /truthmark-structure or $truthmark-structure; Claude Code /truthmark-structure; GitHub Copilot /truthmark-structure; Gemini CLI /truthmark:structure.";
1074
1242
  var renderTruthStructureReportExample = () => {
1075
1243
  return `Truth Structure: completed
@@ -1091,7 +1259,7 @@ Notes:
1091
1259
  var renderTruthStructureSkillBody = (config = defaultAgentConfig()) => {
1092
1260
  return `---
1093
1261
  name: truthmark-structure
1094
- description: Use when the user asks to design, repair, or refresh Truthmark area routing. Inspects the repository directly, updates docs/truthmark/areas.md, and may create starter canonical truth docs.
1262
+ description: Use when the user asks to design, repair, or refresh missing, stale, broad, overloaded, catch-all, or unrouteable Truthmark area routing. Inspects the repository directly, updates docs/truthmark/areas.md, and may create starter canonical truth docs.
1095
1263
  argument-hint: Optional area, directory, or routing concern
1096
1264
  user-invocable: true
1097
1265
  truthmark-version: ${TRUTHMARK_VERSION}
@@ -1100,7 +1268,7 @@ truthmark-version: ${TRUTHMARK_VERSION}
1100
1268
  Use this skill to design or repair Truthmark area structure.
1101
1269
  Invocations: ${TRUTH_STRUCTURE_EXPLICIT_INVOCATIONS}
1102
1270
  Truth Structure is agent-native:
1103
- - inspect repository layout, current docs, .truthmark/config.yml, TRUTHMARK.md, docs/truthmark/areas.md, and relevant code directly
1271
+ - inspect repository layout, current docs, .truthmark/config.yml, docs/truthmark/areas.md, and relevant code directly
1104
1272
  - ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
1105
1273
  - inspect the configured root route index at ${config.docs.routing.rootIndex} and relevant child route files under ${config.docs.routing.areaFilesRoot}/
1106
1274
  - define areas by product or behavior ownership, not by mechanical directory mirroring
@@ -1108,6 +1276,7 @@ Truth Structure is agent-native:
1108
1276
  - create starter truth docs when useful and when they belong in the canonical current-truth surface
1109
1277
  - Starter truth docs must use closed YAML frontmatter bounded by opening and closing --- lines; include status, doc_type, last_reviewed, and source_of_truth inside that frontmatter.
1110
1278
  - Starter truth docs must include ## Product Decisions and ## Rationale sections.
1279
+ ${FEATURE_DOC_TEMPLATE_INSTRUCTIONS}
1111
1280
  - use docs/features/**, docs/architecture/**, or docs/standards/** for current truth destinations
1112
1281
  - use only canonical current-truth destinations for starter truth docs
1113
1282
  - keep active Product Decisions and Rationale in the canonical doc that owns the behavior
@@ -1130,7 +1299,7 @@ Use these review thresholds as guidance:
1130
1299
  - more than 8 truth docs mapped to one area
1131
1300
  - more than 5 controllers mapped through one catch-all area
1132
1301
  Repair rules:
1133
- - split broad catch-all areas into behavior-owned child route files
1302
+ - split broad, overloaded, or catch-all areas into behavior-owned child route files
1134
1303
  - create route files under ${config.docs.routing.areaFilesRoot}/ when a product/domain boundary is clear
1135
1304
  - create feature docs under the configured feature root only when behavior lacks a current doc
1136
1305
  - README.md files are indexes, not Truth Sync targets
@@ -1139,22 +1308,25 @@ Repair rules:
1139
1308
  - keep API endpoint details in the nearest contract truth doc when such a doc exists
1140
1309
  - update routing so future Truth Sync can target small docs
1141
1310
  - preserve existing authored docs; move or rewrite only when needed to remove ambiguity
1311
+ ${ARCHITECTURE_DOC_BOUNDARY_INSTRUCTIONS}
1142
1312
  - Do not finish topology repair with routed canonical current-truth docs missing Product Decisions or Rationale sections.
1143
1313
  - If an existing canonical doc lacks either section, add the missing heading beside Current Behavior with a concise current-state placeholder or active decision.
1144
1314
  Portable fallback:
1145
1315
  - If this skill surface is unavailable, perform the same workflow directly from committed repository files.
1146
1316
  - Do not require the truthmark CLI.
1147
- - Read .truthmark/config.yml, TRUTHMARK.md, ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, canonical docs, and representative implementation code.
1317
+ - Read .truthmark/config.yml, ${config.docs.routing.rootIndex}, relevant child route files under ${config.docs.routing.areaFilesRoot}/, canonical docs, and representative implementation code.
1148
1318
  - Use a subagent only when the host supports that pattern; otherwise perform the topology repair inline.
1149
1319
  ${renderHierarchySummary(config)}
1150
1320
  ${DECISION_TRUTH_INSTRUCTIONS}
1151
1321
  Report completion in this shape:
1152
- ${renderMarkdownExample3(renderTruthStructureReportExample())}`;
1322
+ ${renderMarkdownExample4(renderTruthStructureReportExample())}`;
1153
1323
  };
1154
1324
 
1155
1325
  // src/templates/codex-skills.ts
1156
1326
  var TRUTHMARK_STRUCTURE_SKILL_PATH = ".codex/skills/truthmark-structure/SKILL.md";
1157
1327
  var TRUTHMARK_STRUCTURE_SKILL_METADATA_PATH = ".codex/skills/truthmark-structure/agents/openai.yaml";
1328
+ var TRUTHMARK_DOCUMENT_SKILL_PATH = ".codex/skills/truthmark-document/SKILL.md";
1329
+ var TRUTHMARK_DOCUMENT_SKILL_METADATA_PATH = ".codex/skills/truthmark-document/agents/openai.yaml";
1158
1330
  var TRUTHMARK_SYNC_SKILL_PATH = ".codex/skills/truthmark-sync/SKILL.md";
1159
1331
  var TRUTHMARK_SYNC_SKILL_METADATA_PATH = ".codex/skills/truthmark-sync/agents/openai.yaml";
1160
1332
  var TRUTHMARK_REALIZE_SKILL_PATH = ".codex/skills/truthmark-realize/SKILL.md";
@@ -1162,10 +1334,12 @@ var TRUTHMARK_REALIZE_SKILL_METADATA_PATH = ".codex/skills/truthmark-realize/age
1162
1334
  var TRUTHMARK_CHECK_SKILL_PATH = ".codex/skills/truthmark-check/SKILL.md";
1163
1335
  var TRUTHMARK_CHECK_SKILL_METADATA_PATH = ".codex/skills/truthmark-check/agents/openai.yaml";
1164
1336
  var TRUTHMARK_GEMINI_STRUCTURE_COMMAND_PATH = ".gemini/commands/truthmark/structure.toml";
1337
+ var TRUTHMARK_GEMINI_DOCUMENT_COMMAND_PATH = ".gemini/commands/truthmark/document.toml";
1165
1338
  var TRUTHMARK_GEMINI_SYNC_COMMAND_PATH = ".gemini/commands/truthmark/sync.toml";
1166
1339
  var TRUTHMARK_GEMINI_REALIZE_COMMAND_PATH = ".gemini/commands/truthmark/realize.toml";
1167
1340
  var TRUTHMARK_GEMINI_CHECK_COMMAND_PATH = ".gemini/commands/truthmark/check.toml";
1168
1341
  var TRUTHMARK_COPILOT_STRUCTURE_PROMPT_PATH = ".github/prompts/truthmark-structure.prompt.md";
1342
+ var TRUTHMARK_COPILOT_DOCUMENT_PROMPT_PATH = ".github/prompts/truthmark-document.prompt.md";
1169
1343
  var TRUTHMARK_COPILOT_SYNC_PROMPT_PATH = ".github/prompts/truthmark-sync.prompt.md";
1170
1344
  var TRUTHMARK_COPILOT_REALIZE_PROMPT_PATH = ".github/prompts/truthmark-realize.prompt.md";
1171
1345
  var TRUTHMARK_COPILOT_CHECK_PROMPT_PATH = ".github/prompts/truthmark-check.prompt.md";
@@ -1200,6 +1374,26 @@ var renderTruthmarkStructureSkillMetadata = () => {
1200
1374
  policy:
1201
1375
  allow_implicit_invocation: false
1202
1376
 
1377
+ truthmark:
1378
+ version: "${TRUTHMARK_VERSION}"
1379
+ refresh_command: "truthmark init"
1380
+ `;
1381
+ };
1382
+ var renderTruthmarkDocumentSkill = (config = defaultAgentConfig()) => {
1383
+ return renderTruthDocumentSkillBody(config);
1384
+ };
1385
+ var renderTruthmarkDocumentLocalSkill = (config = defaultAgentConfig()) => {
1386
+ return renderTruthDocumentSkillBody(config);
1387
+ };
1388
+ var renderTruthmarkDocumentSkillMetadata = () => {
1389
+ return `interface:
1390
+ display_name: "Truthmark Document"
1391
+ short_description: "Document existing implemented behavior"
1392
+ default_prompt: "Use $truthmark-document to document existing implemented behavior."
1393
+
1394
+ policy:
1395
+ allow_implicit_invocation: false
1396
+
1203
1397
  truthmark:
1204
1398
  version: "${TRUTHMARK_VERSION}"
1205
1399
  refresh_command: "truthmark init"
@@ -1214,8 +1408,8 @@ var renderTruthmarkSyncLocalSkill = (config = defaultAgentConfig()) => {
1214
1408
  var renderTruthmarkSyncSkillMetadata = () => {
1215
1409
  return `interface:
1216
1410
  display_name: "Truthmark Sync"
1217
- short_description: "Sync truth docs from changed code"
1218
- default_prompt: "Use $truthmark-sync to sync truth docs from changed code."
1411
+ short_description: "Sync truth docs from functional code changes; skip docs-only/no-code changes"
1412
+ default_prompt: "Use $truthmark-sync after functional code changes; skip docs-only/no-code changes."
1219
1413
 
1220
1414
  policy:
1221
1415
  allow_implicit_invocation: true
@@ -1249,7 +1443,7 @@ Truth Realize is doc-first:
1249
1443
  Workflow:
1250
1444
 
1251
1445
  1. Read the updated truth docs named by the user, or infer the relevant docs from docs/truthmark/areas.md.
1252
- 2. Read .truthmark/config.yml, TRUTHMARK.md, docs/truthmark/areas.md, and the relevant functional code.
1446
+ 2. Read .truthmark/config.yml, docs/truthmark/areas.md, and the relevant functional code.
1253
1447
  3. ${EVIDENCE_AUTHORITY_INSTRUCTIONS}
1254
1448
  4. Update functional code only so implementation matches the truth docs.
1255
1449
  5. Do not edit truth docs or truth routing while realizing those docs.
@@ -1324,9 +1518,15 @@ var renderTruthmarkGeminiStructureCommand = (config = defaultAgentConfig()) => {
1324
1518
  renderTruthStructureSkillBody(config)
1325
1519
  );
1326
1520
  };
1521
+ var renderTruthmarkGeminiDocumentCommand = (config = defaultAgentConfig()) => {
1522
+ return renderGeminiCommand(
1523
+ "Document existing implemented behavior.",
1524
+ renderTruthDocumentSkillBody(config)
1525
+ );
1526
+ };
1327
1527
  var renderTruthmarkGeminiSyncCommand = (config = defaultAgentConfig()) => {
1328
1528
  return renderGeminiCommand(
1329
- "Sync repository truth docs from changed code.",
1529
+ "Sync repository truth docs from functional code changes; skip docs-only/no-code changes.",
1330
1530
  renderTruthSyncSkillBody(config)
1331
1531
  );
1332
1532
  };
@@ -1348,9 +1548,15 @@ var renderTruthmarkCopilotStructurePrompt = (config = defaultAgentConfig()) => {
1348
1548
  renderTruthStructureSkillBody(config)
1349
1549
  );
1350
1550
  };
1551
+ var renderTruthmarkCopilotDocumentPrompt = (config = defaultAgentConfig()) => {
1552
+ return renderCopilotPromptFile(
1553
+ "Document existing implemented behavior.",
1554
+ renderTruthDocumentSkillBody(config)
1555
+ );
1556
+ };
1351
1557
  var renderTruthmarkCopilotSyncPrompt = (config = defaultAgentConfig()) => {
1352
1558
  return renderCopilotPromptFile(
1353
- "Sync repository truth docs from changed code.",
1559
+ "Sync repository truth docs from functional code changes; skip docs-only/no-code changes.",
1354
1560
  renderTruthSyncSkillBody(config)
1355
1561
  );
1356
1562
  };
@@ -1391,8 +1597,10 @@ This is a bootstrap standards baseline for repositories that adopt Truthmark.
1391
1597
  - Committed repository artifacts are the durable source of truth.
1392
1598
  - Each document should have one primary responsibility.
1393
1599
  - Each class of fact should have one canonical source.
1600
+ - Architecture docs describe system structure, module boundaries, runtime topology, persistence boundaries, cross-cutting contracts, and generated-surface ownership.
1601
+ - Do not put ordinary feature behavior in architecture docs.
1394
1602
  - Verification should be explicit, and skipped checks should state why.
1395
- - Broad or overloaded documentation topology should be repaired through AI-native structure workflow before agents create more generic truth docs.
1603
+ - Missing, stale, broad, overloaded, or unrouteable documentation topology should be repaired through AI-native structure workflow before agents create more generic truth docs.
1396
1604
  - Installed repository workflows should remain usable from committed files even when the Truthmark CLI is unavailable.
1397
1605
  `
1398
1606
  },
@@ -1414,12 +1622,13 @@ source_of_truth:
1414
1622
  - Each class of fact should have one canonical source.
1415
1623
  - Current implementation, reusable standards, and future proposals should be stored separately.
1416
1624
  - Generated helper output is never canonical truth.
1625
+ - Architecture docs describe structure and ownership; feature docs describe current product behavior.
1417
1626
 
1418
1627
  ## Truthmark Implications
1419
1628
 
1420
1629
  - Truth Sync should extend mapped docs first, create an area-local doc second, and create a new area only as a last resort.
1421
1630
  - Weak routing produces weak truth maintenance.
1422
- - Broad or overloaded routing should trigger Truth Structure before more generic feature docs are created.
1631
+ - Missing, stale, broad, overloaded, or unrouteable routing should trigger Truth Structure before more generic feature docs are created.
1423
1632
  `
1424
1633
  }
1425
1634
  ];
@@ -1472,26 +1681,33 @@ var removeTrailingManagedChunk = (preservedLines) => {
1472
1681
  preservedLines.splice(startIndex);
1473
1682
  }
1474
1683
  };
1684
+ var normalizeLegacyInstructionPreamble = (content) => {
1685
+ return content.replaceAll(
1686
+ "Use that file as the primary repository instruction source for Codex.",
1687
+ "Use that file as the primary repository instruction source for this agent."
1688
+ ).replaceAll("Codex-specific:", "Agent-specific:");
1689
+ };
1475
1690
  var upsertManagedBlock = (existingContent, block) => {
1476
1691
  if (!existingContent || existingContent.trim().length === 0) {
1477
1692
  return block;
1478
1693
  }
1694
+ const normalizedExistingContent = normalizeLegacyInstructionPreamble(existingContent);
1479
1695
  const startMarkerPattern = new RegExp(escapeRegExp(TRUTHMARK_BLOCK_START), "g");
1480
1696
  const endMarkerPattern = new RegExp(escapeRegExp(TRUTHMARK_BLOCK_END), "g");
1481
1697
  const managedBlockPattern = new RegExp(
1482
1698
  `${escapeRegExp(TRUTHMARK_BLOCK_START)}[\\s\\S]*?${escapeRegExp(TRUTHMARK_BLOCK_END)}`,
1483
1699
  "g"
1484
1700
  );
1485
- const completeBlocks = existingContent.match(managedBlockPattern) ?? [];
1486
- const startCount = existingContent.match(startMarkerPattern)?.length ?? 0;
1487
- const endCount = existingContent.match(endMarkerPattern)?.length ?? 0;
1701
+ const completeBlocks = normalizedExistingContent.match(managedBlockPattern) ?? [];
1702
+ const startCount = normalizedExistingContent.match(startMarkerPattern)?.length ?? 0;
1703
+ const endCount = normalizedExistingContent.match(endMarkerPattern)?.length ?? 0;
1488
1704
  if (startCount === 1 && endCount === 1 && completeBlocks.length === 1) {
1489
- return existingContent.replace(managedBlockPattern, block);
1705
+ return normalizedExistingContent.replace(managedBlockPattern, block);
1490
1706
  }
1491
1707
  const preservedLines = [];
1492
1708
  let insideManagedBlock = false;
1493
1709
  let managedLines = [];
1494
- for (const line of existingContent.split("\n")) {
1710
+ for (const line of normalizedExistingContent.split("\n")) {
1495
1711
  const trimmedLine = line.trim();
1496
1712
  if (trimmedLine === TRUTHMARK_BLOCK_START) {
1497
1713
  if (insideManagedBlock && !isManagedChunk(managedLines, 2)) {
@@ -1532,7 +1748,7 @@ ${block}`;
1532
1748
  var writeManagedAgentsFile = async (rootDir, path4 = "AGENTS.md", block) => {
1533
1749
  let existingContent = null;
1534
1750
  try {
1535
- existingContent = await fs6.readFile(resolveRepoPath(rootDir, path4), "utf8");
1751
+ existingContent = await fs7.readFile(resolveRepoPath(rootDir, path4), "utf8");
1536
1752
  } catch (error) {
1537
1753
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
1538
1754
  throw error;
@@ -1550,6 +1766,9 @@ var diagnosticCategoryForPath = (filePath) => {
1550
1766
  if (filePath.startsWith(".codex/skills/truthmark-structure/")) {
1551
1767
  return "truth-sync";
1552
1768
  }
1769
+ if (filePath.startsWith(".codex/skills/truthmark-document/")) {
1770
+ return "truth-sync";
1771
+ }
1553
1772
  if (filePath.startsWith(".codex/skills/truthmark-sync/")) {
1554
1773
  return "truth-sync";
1555
1774
  }
@@ -1565,7 +1784,7 @@ var diagnosticCategoryForPath = (filePath) => {
1565
1784
  if (filePath.startsWith(".codex/skills/truthmark-check/")) {
1566
1785
  return "truth-sync";
1567
1786
  }
1568
- if (filePath === "TRUTHMARK.md" || filePath === "docs/truthmark/areas.md") {
1787
+ if (filePath === "docs/truthmark/areas.md") {
1569
1788
  return "authority";
1570
1789
  }
1571
1790
  return "config";
@@ -1576,6 +1795,10 @@ var workflowSkillFiles = (basePath, config) => {
1576
1795
  path: `${basePath}/truthmark-structure/SKILL.md`,
1577
1796
  content: renderTruthmarkStructureLocalSkill(config)
1578
1797
  },
1798
+ {
1799
+ path: `${basePath}/truthmark-document/SKILL.md`,
1800
+ content: renderTruthmarkDocumentLocalSkill(config)
1801
+ },
1579
1802
  {
1580
1803
  path: `${basePath}/truthmark-sync/SKILL.md`,
1581
1804
  content: renderTruthmarkSyncLocalSkill(config)
@@ -1603,6 +1826,14 @@ var codexFiles = (config) => {
1603
1826
  path: TRUTHMARK_STRUCTURE_SKILL_METADATA_PATH,
1604
1827
  content: renderTruthmarkStructureSkillMetadata()
1605
1828
  },
1829
+ {
1830
+ path: TRUTHMARK_DOCUMENT_SKILL_PATH,
1831
+ content: renderTruthmarkDocumentSkill(config)
1832
+ },
1833
+ {
1834
+ path: TRUTHMARK_DOCUMENT_SKILL_METADATA_PATH,
1835
+ content: renderTruthmarkDocumentSkillMetadata()
1836
+ },
1606
1837
  {
1607
1838
  path: TRUTHMARK_SYNC_SKILL_PATH,
1608
1839
  content: renderTruthmarkSyncSkill(config)
@@ -1641,6 +1872,10 @@ var copilotFiles = (config, block) => {
1641
1872
  path: TRUTHMARK_COPILOT_STRUCTURE_PROMPT_PATH,
1642
1873
  content: renderTruthmarkCopilotStructurePrompt(config)
1643
1874
  },
1875
+ {
1876
+ path: TRUTHMARK_COPILOT_DOCUMENT_PROMPT_PATH,
1877
+ content: renderTruthmarkCopilotDocumentPrompt(config)
1878
+ },
1644
1879
  {
1645
1880
  path: TRUTHMARK_COPILOT_SYNC_PROMPT_PATH,
1646
1881
  content: renderTruthmarkCopilotSyncPrompt(config)
@@ -1685,6 +1920,10 @@ var filesForPlatform = (platform, config, block) => {
1685
1920
  path: TRUTHMARK_GEMINI_STRUCTURE_COMMAND_PATH,
1686
1921
  content: renderTruthmarkGeminiStructureCommand(config)
1687
1922
  },
1923
+ {
1924
+ path: TRUTHMARK_GEMINI_DOCUMENT_COMMAND_PATH,
1925
+ content: renderTruthmarkGeminiDocumentCommand(config)
1926
+ },
1688
1927
  {
1689
1928
  path: TRUTHMARK_GEMINI_SYNC_COMMAND_PATH,
1690
1929
  content: renderTruthmarkGeminiSyncCommand(config)
@@ -1749,7 +1988,6 @@ var runInit = async (cwd) => {
1749
1988
  for (const template of defaultStandards) {
1750
1989
  results.push(await ensureRepoFile(rootDir, template.path, template.content));
1751
1990
  }
1752
- results.push(await ensureRepoFile(rootDir, "TRUTHMARK.md", renderTruthmarkTemplate()));
1753
1991
  const config = loadedConfig.config;
1754
1992
  results.push(...await scaffoldHierarchy(rootDir, config));
1755
1993
  const migrationDiagnostics = await detectHierarchyMigrationDiagnostics(rootDir, config);
@@ -1780,7 +2018,7 @@ var runInit = async (cwd) => {
1780
2018
  };
1781
2019
 
1782
2020
  // src/checks/branch-scope.ts
1783
- import fs7 from "fs/promises";
2021
+ import fs8 from "fs/promises";
1784
2022
  import fg2 from "fast-glob";
1785
2023
 
1786
2024
  // src/markdown/hash.ts
@@ -1798,7 +2036,7 @@ var BranchScopeFileError = class extends Error {
1798
2036
  this.file = file;
1799
2037
  }
1800
2038
  };
1801
- var RELEVANT_BRANCH_SCOPE_FILES = [".truthmark/config.yml", "TRUTHMARK.md"];
2039
+ var RELEVANT_BRANCH_SCOPE_FILES = [".truthmark/config.yml"];
1802
2040
  var toBranchIdentity = (branchName, headSha) => {
1803
2041
  if (branchName && headSha) {
1804
2042
  return `${branchName}@${headSha}`;
@@ -1835,7 +2073,7 @@ var getBranchScopeData = async (cwd) => {
1835
2073
  }
1836
2074
  for (const relativePath of [...relevantFiles].sort()) {
1837
2075
  try {
1838
- const source = await fs7.readFile(resolveWorktreePath(repository, relativePath), "utf8");
2076
+ const source = await fs8.readFile(resolveWorktreePath(repository, relativePath), "utf8");
1839
2077
  relevantFileHashes[relativePath] = hashText(source);
1840
2078
  } catch (error) {
1841
2079
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -1852,14 +2090,14 @@ var getBranchScopeData = async (cwd) => {
1852
2090
  };
1853
2091
 
1854
2092
  // src/checks/authority.ts
1855
- import fs8 from "fs/promises";
2093
+ import fs9 from "fs/promises";
1856
2094
  import fg3 from "fast-glob";
1857
2095
  var looksLikeGlob = (pattern) => {
1858
2096
  return /[*?[\]{}()!+@]/u.test(pattern);
1859
2097
  };
1860
2098
  var pathExists = async (absolutePath) => {
1861
2099
  try {
1862
- await fs8.stat(absolutePath);
2100
+ await fs9.stat(absolutePath);
1863
2101
  return true;
1864
2102
  } catch (error) {
1865
2103
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -1948,7 +2186,7 @@ var checkAuthority = async (rootDir, config) => {
1948
2186
  };
1949
2187
 
1950
2188
  // src/checks/frontmatter.ts
1951
- import fs9 from "fs/promises";
2189
+ import fs10 from "fs/promises";
1952
2190
 
1953
2191
  // src/markdown/parse.ts
1954
2192
  import matter from "gray-matter";
@@ -1996,7 +2234,7 @@ var checkFrontmatter = async (rootDir, config, markdownPaths) => {
1996
2234
  }
1997
2235
  const absolutePath = resolveRepoPath(rootDir, markdownPath);
1998
2236
  await assertRepoContainment(rootDir, absolutePath);
1999
- const source = await fs9.readFile(absolutePath, "utf8");
2237
+ const source = await fs10.readFile(absolutePath, "utf8");
2000
2238
  let document;
2001
2239
  try {
2002
2240
  document = parseMarkdownDocument(source);
@@ -2034,11 +2272,11 @@ var checkFrontmatter = async (rootDir, config, markdownPaths) => {
2034
2272
  };
2035
2273
 
2036
2274
  // src/checks/links.ts
2037
- import fs10 from "fs/promises";
2275
+ import fs11 from "fs/promises";
2038
2276
  import path3 from "path";
2039
2277
  var pathExists2 = async (absolutePath) => {
2040
2278
  try {
2041
- await fs10.stat(absolutePath);
2279
+ await fs11.stat(absolutePath);
2042
2280
  return true;
2043
2281
  } catch (error) {
2044
2282
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -2054,7 +2292,7 @@ var checkLinks = async (rootDir, markdownPaths) => {
2054
2292
  continue;
2055
2293
  }
2056
2294
  const absolutePath = resolveRepoPath(rootDir, markdownPath);
2057
- const source = await fs10.readFile(absolutePath, "utf8");
2295
+ const source = await fs11.readFile(absolutePath, "utf8");
2058
2296
  let document;
2059
2297
  try {
2060
2298
  document = parseMarkdownDocument(source);
@@ -2096,12 +2334,12 @@ var checkLinks = async (rootDir, markdownPaths) => {
2096
2334
  };
2097
2335
 
2098
2336
  // src/checks/areas.ts
2099
- import fs12 from "fs/promises";
2337
+ import fs13 from "fs/promises";
2100
2338
  import fg5 from "fast-glob";
2101
2339
  import micromatch3 from "micromatch";
2102
2340
 
2103
2341
  // src/routing/area-resolver.ts
2104
- import fs11 from "fs/promises";
2342
+ import fs12 from "fs/promises";
2105
2343
  import fg4 from "fast-glob";
2106
2344
  import micromatch from "micromatch";
2107
2345
 
@@ -2258,7 +2496,7 @@ var ensureChildPath = async (rootDir, areaFilesRoot, filePath) => {
2258
2496
  var readRouteFile = async (rootDir, filePath) => {
2259
2497
  try {
2260
2498
  return {
2261
- source: await fs11.readFile(resolveRepoPath(rootDir, filePath), "utf8"),
2499
+ source: await fs12.readFile(resolveRepoPath(rootDir, filePath), "utf8"),
2262
2500
  diagnostic: null
2263
2501
  };
2264
2502
  } catch (error) {
@@ -2558,7 +2796,7 @@ var looksLikeGlob2 = (pattern) => {
2558
2796
  };
2559
2797
  var pathExists3 = async (absolutePath) => {
2560
2798
  try {
2561
- await fs12.stat(absolutePath);
2799
+ await fs13.stat(absolutePath);
2562
2800
  return true;
2563
2801
  } catch (error) {
2564
2802
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -2827,7 +3065,7 @@ var checkAreas = async (rootDir, config) => {
2827
3065
  };
2828
3066
 
2829
3067
  // src/checks/decisions.ts
2830
- import fs13 from "fs/promises";
3068
+ import fs14 from "fs/promises";
2831
3069
  import micromatch4 from "micromatch";
2832
3070
  var REQUIRED_DECISION_HEADINGS = ["Product Decisions", "Rationale"];
2833
3071
  var escapeRegExp2 = (value) => {
@@ -2850,7 +3088,7 @@ var checkDecisionSections = async (rootDir, config, markdownPaths) => {
2850
3088
  const diagnostics = [];
2851
3089
  const candidatePaths = [...new Set(markdownPaths)].filter((filePath) => isDecisionTruthCandidate(config, filePath)).sort();
2852
3090
  for (const filePath of candidatePaths) {
2853
- const source = await fs13.readFile(resolveRepoPath(rootDir, filePath), "utf8");
3091
+ const source = await fs14.readFile(resolveRepoPath(rootDir, filePath), "utf8");
2854
3092
  const missingHeadings = REQUIRED_DECISION_HEADINGS.filter((heading) => !hasHeading(source, heading));
2855
3093
  if (missingHeadings.length === 0) {
2856
3094
  continue;
@@ -2866,7 +3104,7 @@ var checkDecisionSections = async (rootDir, config, markdownPaths) => {
2866
3104
  };
2867
3105
 
2868
3106
  // src/checks/generated-surfaces.ts
2869
- import fs14 from "fs/promises";
3107
+ import fs15 from "fs/promises";
2870
3108
 
2871
3109
  // src/templates/generated-surfaces.ts
2872
3110
  var workflowSkillFiles2 = (basePath, config) => {
@@ -2875,6 +3113,10 @@ var workflowSkillFiles2 = (basePath, config) => {
2875
3113
  path: `${basePath}/truthmark-structure/SKILL.md`,
2876
3114
  content: renderTruthmarkStructureLocalSkill(config)
2877
3115
  },
3116
+ {
3117
+ path: `${basePath}/truthmark-document/SKILL.md`,
3118
+ content: renderTruthmarkDocumentLocalSkill(config)
3119
+ },
2878
3120
  {
2879
3121
  path: `${basePath}/truthmark-sync/SKILL.md`,
2880
3122
  content: renderTruthmarkSyncLocalSkill(config)
@@ -2902,6 +3144,14 @@ var codexFiles2 = (config) => {
2902
3144
  path: TRUTHMARK_STRUCTURE_SKILL_METADATA_PATH,
2903
3145
  content: renderTruthmarkStructureSkillMetadata()
2904
3146
  },
3147
+ {
3148
+ path: TRUTHMARK_DOCUMENT_SKILL_PATH,
3149
+ content: renderTruthmarkDocumentSkill(config)
3150
+ },
3151
+ {
3152
+ path: TRUTHMARK_DOCUMENT_SKILL_METADATA_PATH,
3153
+ content: renderTruthmarkDocumentSkillMetadata()
3154
+ },
2905
3155
  {
2906
3156
  path: TRUTHMARK_SYNC_SKILL_PATH,
2907
3157
  content: renderTruthmarkSyncSkill(config)
@@ -2940,6 +3190,10 @@ var copilotFiles2 = (config, block) => {
2940
3190
  path: TRUTHMARK_COPILOT_STRUCTURE_PROMPT_PATH,
2941
3191
  content: renderTruthmarkCopilotStructurePrompt(config)
2942
3192
  },
3193
+ {
3194
+ path: TRUTHMARK_COPILOT_DOCUMENT_PROMPT_PATH,
3195
+ content: renderTruthmarkCopilotDocumentPrompt(config)
3196
+ },
2943
3197
  {
2944
3198
  path: TRUTHMARK_COPILOT_SYNC_PROMPT_PATH,
2945
3199
  content: renderTruthmarkCopilotSyncPrompt(config)
@@ -2984,6 +3238,10 @@ var filesForPlatform2 = (platform, config, block) => {
2984
3238
  path: TRUTHMARK_GEMINI_STRUCTURE_COMMAND_PATH,
2985
3239
  content: renderTruthmarkGeminiStructureCommand(config)
2986
3240
  },
3241
+ {
3242
+ path: TRUTHMARK_GEMINI_DOCUMENT_COMMAND_PATH,
3243
+ content: renderTruthmarkGeminiDocumentCommand(config)
3244
+ },
2987
3245
  {
2988
3246
  path: TRUTHMARK_GEMINI_SYNC_COMMAND_PATH,
2989
3247
  content: renderTruthmarkGeminiSyncCommand(config)
@@ -3014,7 +3272,7 @@ var renderGeneratedSurfaces = (config, block = renderAgentsBlock(config)) => {
3014
3272
  // src/checks/generated-surfaces.ts
3015
3273
  var readOptionalFile = async (rootDir, filePath) => {
3016
3274
  try {
3017
- return await fs14.readFile(resolveRepoPath(rootDir, filePath), "utf8");
3275
+ return await fs15.readFile(resolveRepoPath(rootDir, filePath), "utf8");
3018
3276
  } catch (error) {
3019
3277
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
3020
3278
  return null;