compose-agentsmd 5.0.0 → 6.0.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.
package/README.md CHANGED
@@ -116,14 +116,14 @@ Ruleset keys:
116
116
  - `domains` (optional): domain folders under `rules/domains/<domain>`.
117
117
  - `extra` (optional): additional local rule files to append.
118
118
  - `budget` (optional): global-rule budget thresholds in `o200k_base` tokens.
119
- - `budget.totalTokens` (optional): total token budget for the composed global instruction output (defaults to `4500`).
120
- - `budget.moduleTokens` (optional): per-module token budget for each composed global rule section (defaults to `400`).
119
+ - `budget.totalTokens` (optional): hard total token budget for the composed global instruction output (defaults to `8000`). Exceeding this is reported as a budget violation.
120
+ - `budget.moduleTokens` (optional): per-module advisory threshold for each composed global rule section (defaults to `800`). Crossing this is **not** a violation; it triggers a review prompt to check whether the listed modules contain procedural content that should move to skills (procedures belong in skills, not rules).
121
121
  - `claude` (optional): repository companion settings for Claude Code.
122
122
  - `claude.enabled` (optional): enable/disable companion generation (defaults to `true`).
123
123
  - `claude.output` (optional): companion file path (defaults to `CLAUDE.md`).
124
124
  - `output` (optional): repository output file name (defaults to `AGENTS.md`).
125
125
 
126
- When the composed global instruction output exceeds either budget, the CLI emits a warning to `stderr`. The machine-readable `--json` output includes the tokenizer name, total token count, and any over-budget modules.
126
+ When the composed global instruction output exceeds the total budget, the CLI emits a `⚠ Global rules budget exceeded` warning to `stderr`. When any module crosses the per-module advisory threshold, the CLI emits a separate `ℹ Modules over per-module review threshold` advisory to `stderr`. Both can be suppressed with `--quiet`. The machine-readable `--json` output includes `budget.totalExceeded`, `budget.moduleReviewTriggered`, the tokenizer name, total token count, and any over-threshold modules.
127
127
 
128
128
  ### Ruleset schema validation
129
129
 
@@ -25,8 +25,17 @@ const PACKAGE_JSON_PATH = new URL("../package.json", import.meta.url);
25
25
  const TOOL_RULES_PATH = new URL("../tools/tool-rules.md", import.meta.url);
26
26
  const USAGE_PATH = new URL("../tools/usage.txt", import.meta.url);
27
27
  const BUDGET_TOKENIZER = "o200k_base";
28
- const DEFAULT_TOTAL_BUDGET = 4500;
29
- const DEFAULT_MODULE_BUDGET = 400;
28
+ // Token budgets for the composed global rules.
29
+ // - DEFAULT_TOTAL_BUDGET: hard budget for the always-loaded global rules.
30
+ // Sized to accommodate realistic invariant density (~80–120 invariants ×
31
+ // ~30–50 tokens each ≈ 5–6k tokens) plus structural margin and growth
32
+ // headroom, while staying a small fraction of the smallest target model's
33
+ // effective system-prompt window. Total exceedance is a budget violation.
34
+ // - DEFAULT_MODULE_BUDGET: per-module advisory threshold, NOT a violation.
35
+ // Crossing it triggers a review prompt to check whether the module is
36
+ // leaking procedural content (procedures belong in skills, not rules).
37
+ const DEFAULT_TOTAL_BUDGET = 8000;
38
+ const DEFAULT_MODULE_BUDGET = 800;
30
39
  const LINT_HEADER = "<!-- markdownlint-disable MD025 -->";
31
40
  const readValueArg = (remaining, index, flag) => {
32
41
  const value = remaining[index + 1];
@@ -671,7 +680,8 @@ const composeRuleset = (rulesetPath, rootDir, options) => {
671
680
  totalBudget,
672
681
  moduleBudget,
673
682
  overBudgetModules,
674
- exceeded: totalTokens > totalBudget || overBudgetModules.length > 0
683
+ totalExceeded: totalTokens > totalBudget,
684
+ moduleReviewTriggered: overBudgetModules.length > 0
675
685
  };
676
686
  const repositoryOutputs = [toDisplayPath(rootDir, primaryOutputPath)];
677
687
  const globalOutputs = globalOutputPaths.map((filePath) => toDisplayPath(rootDir, filePath));
@@ -759,18 +769,20 @@ const formatComposedOutputs = (result) => {
759
769
  }
760
770
  return `${lines.join("\n")}\n`;
761
771
  };
762
- const formatBudgetWarning = (result) => {
763
- const totalInfo = result.totalTokens > result.totalBudget
764
- ? `: ${result.totalTokens}/${result.totalBudget} tokens`
765
- : "";
766
- const lines = [`⚠ Global rules budget exceeded (${result.tokenizer})${totalInfo}`];
767
- if (result.overBudgetModules.length > 0) {
768
- lines.push(` Over-budget modules (> ${result.moduleBudget} tokens):`);
772
+ const formatBudgetReport = (result) => {
773
+ const lines = [];
774
+ if (result.totalExceeded) {
775
+ lines.push(`⚠ Global rules budget exceeded (${result.tokenizer}): ` +
776
+ `${result.totalTokens}/${result.totalBudget} tokens`);
777
+ }
778
+ if (result.moduleReviewTriggered) {
779
+ lines.push(`ℹ Modules over per-module review threshold (> ${result.moduleBudget} tokens, advisory):`);
769
780
  for (const mod of result.overBudgetModules) {
770
781
  lines.push(` ${mod.name}: ${mod.tokens} tokens`);
771
782
  }
783
+ lines.push(" Review whether listed modules contain procedural content that should move to skills.");
772
784
  }
773
- return `${lines.join("\n")}\n`;
785
+ return lines.length === 0 ? "" : `${lines.join("\n")}\n`;
774
786
  };
775
787
  const LOCAL_RULES_TEMPLATE = "# Local Rules\n\n- Add project-specific instructions here.\n";
776
788
  const buildInitRuleset = (args) => {
@@ -951,8 +963,9 @@ const initProject = async (args, rootDir, rulesetName) => {
951
963
  if (composedOutput) {
952
964
  process.stdout.write(formatComposedOutputs(composedOutput));
953
965
  printOutputDiffs(composedOutput);
954
- if (composedOutput.budgetResult.exceeded) {
955
- process.stderr.write(formatBudgetWarning(composedOutput.budgetResult));
966
+ if (composedOutput.budgetResult.totalExceeded ||
967
+ composedOutput.budgetResult.moduleReviewTriggered) {
968
+ process.stderr.write(formatBudgetReport(composedOutput.budgetResult));
956
969
  }
957
970
  }
958
971
  }
@@ -1051,8 +1064,8 @@ const main = async () => {
1051
1064
  else if (!args.quiet) {
1052
1065
  process.stdout.write(formatComposedOutputs(output));
1053
1066
  printOutputDiffs(output);
1054
- if (output.budgetResult.exceeded) {
1055
- process.stderr.write(formatBudgetWarning(output.budgetResult));
1067
+ if (output.budgetResult.totalExceeded || output.budgetResult.moduleReviewTriggered) {
1068
+ process.stderr.write(formatBudgetReport(output.budgetResult));
1056
1069
  }
1057
1070
  }
1058
1071
  return;
@@ -1088,8 +1101,8 @@ const main = async () => {
1088
1101
  printOutputDiffs(result);
1089
1102
  }
1090
1103
  for (const result of outputs) {
1091
- if (result.budgetResult.exceeded) {
1092
- process.stderr.write(formatBudgetWarning(result.budgetResult));
1104
+ if (result.budgetResult.totalExceeded || result.budgetResult.moduleReviewTriggered) {
1105
+ process.stderr.write(formatBudgetReport(result.budgetResult));
1093
1106
  }
1094
1107
  }
1095
1108
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compose-agentsmd",
3
- "version": "5.0.0",
3
+ "version": "6.0.0",
4
4
  "description": "CLI tools for composing repository-local and user-global agent instruction files from modular rule sets",
5
5
  "license": "MIT",
6
6
  "repository": {