oris-skills 2.2.3 → 3.0.1

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 (79) hide show
  1. package/.cursor-plugin/plugin.json +2 -3
  2. package/CHANGELOG.md +24 -6
  3. package/README.md +23 -59
  4. package/docs/architecture.md +15 -11
  5. package/docs/distribution.md +3 -3
  6. package/docs/maintainer-guide.md +4 -4
  7. package/docs/user-guide.md +12 -20
  8. package/package.json +3 -6
  9. package/references/conventions.md +20 -13
  10. package/references/doc-policy.md +5 -5
  11. package/references/research.md +45 -0
  12. package/references/settings.md +11 -5
  13. package/references/settings.schema.json +10 -0
  14. package/scripts/flow/oris-flow-layout.mjs +0 -16
  15. package/scripts/flow/oris-flow-scan.mjs +32 -317
  16. package/scripts/flow/oris-gitignore.mjs +1 -5
  17. package/scripts/install/install-user-skills.mjs +3 -3
  18. package/scripts/install/uninstall-user-skills.mjs +2 -29
  19. package/scripts/oris-skills.mjs +0 -47
  20. package/scripts/tests/run-all-tests.mjs +1 -9
  21. package/scripts/tests/test-cleanliness.mjs +54 -0
  22. package/scripts/tests/test-oris-flow-scan.mjs +21 -91
  23. package/scripts/tests/test-routing-lifecycle.mjs +22 -53
  24. package/scripts/tests/test-schemas.mjs +17 -31
  25. package/scripts/tests/test-skill-style.mjs +5 -2
  26. package/skills/oris-flow/SKILL.md +6 -8
  27. package/skills/oris-flow/references/architecture.md +1 -1
  28. package/skills/oris-flow/references/commit.md +9 -8
  29. package/skills/oris-flow/references/criteria.md +2 -2
  30. package/skills/oris-flow/references/discover.md +2 -2
  31. package/skills/oris-flow/references/fix.md +7 -3
  32. package/skills/oris-flow/references/help.md +1 -6
  33. package/skills/oris-flow/references/implement.md +5 -3
  34. package/skills/oris-flow/references/new.md +6 -6
  35. package/skills/oris-flow/references/plan.md +7 -2
  36. package/skills/oris-flow/references/setup.md +28 -35
  37. package/skills/oris-flow/references/verify.md +4 -5
  38. package/agents/oris-loop-debriefer.md +0 -30
  39. package/agents/oris-loop-doctor.md +0 -32
  40. package/agents/oris-loop-executor.md +0 -35
  41. package/agents/oris-loop-verifier.md +0 -35
  42. package/references/loop-adapter.schema.json +0 -93
  43. package/references/loop-contract.md +0 -126
  44. package/references/loop.schema.json +0 -156
  45. package/references/repo-map.md +0 -51
  46. package/references/repo-map.schema.json +0 -213
  47. package/scripts/flow/oris-flow-clean-runtime.mjs +0 -182
  48. package/scripts/install/generate-agent-adapters.mjs +0 -81
  49. package/scripts/loop/oris-loop-bootstrap.mjs +0 -383
  50. package/scripts/loop/oris-loop-bundle.mjs +0 -22
  51. package/scripts/loop/oris-loop-chat.mjs +0 -396
  52. package/scripts/loop/oris-loop-demo.mjs +0 -171
  53. package/scripts/loop/oris-loop-document.mjs +0 -196
  54. package/scripts/loop/oris-loop-dry-run.mjs +0 -114
  55. package/scripts/loop/oris-loop-fixtures.mjs +0 -149
  56. package/scripts/loop/oris-loop-list.mjs +0 -81
  57. package/scripts/loop/oris-loop-paths.mjs +0 -232
  58. package/scripts/loop/oris-loop-run.mjs +0 -301
  59. package/scripts/loop/oris-loop-stop.mjs +0 -358
  60. package/scripts/loop/oris-loop-templates.mjs +0 -80
  61. package/scripts/loop/oris-loop-verify.mjs +0 -205
  62. package/scripts/tests/test-agent-adapters.mjs +0 -70
  63. package/scripts/tests/test-oris-1-0-cleanliness.mjs +0 -58
  64. package/scripts/tests/test-oris-flow-clean-runtime.mjs +0 -75
  65. package/scripts/tests/test-oris-loop-bootstrap.mjs +0 -94
  66. package/scripts/tests/test-oris-loop-document.mjs +0 -148
  67. package/scripts/tests/test-oris-loop-list.mjs +0 -74
  68. package/scripts/tests/test-oris-loop-run.mjs +0 -71
  69. package/scripts/tests/test-oris-loop-smoke.mjs +0 -120
  70. package/scripts/tests/test-oris-loop-stop.mjs +0 -432
  71. package/skills/oris-flow/references/loop-craft.md +0 -59
  72. package/skills/oris-flow/references/loop-improve.md +0 -32
  73. package/skills/oris-flow/references/loop-run.md +0 -47
  74. package/skills/oris-flow/references/loop.md +0 -56
  75. package/skills/oris-flow/templates/debriefer.md +0 -19
  76. package/skills/oris-flow/templates/doctor.md +0 -22
  77. package/skills/oris-flow/templates/executor.md +0 -25
  78. package/skills/oris-flow/templates/orchestrator.md +0 -36
  79. package/skills/oris-flow/templates/verifier.md +0 -24
@@ -0,0 +1,54 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import assert from "node:assert/strict";
4
+ import test from "node:test";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
8
+ const ignoredDirs = new Set([".git", "node_modules", ".cursor", ".claude", ".codex", "dist", ".cursor-plugin-install-backups", ".oris-flow"]);
9
+
10
+ function walk(dir, matches = []) {
11
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
12
+ if (ignoredDirs.has(entry.name)) continue;
13
+ const full = path.join(dir, entry.name);
14
+ if (entry.isDirectory()) walk(full, matches);
15
+ else matches.push(full);
16
+ }
17
+ return matches;
18
+ }
19
+
20
+ function repoFiles() {
21
+ return walk(repoRoot).map((filePath) => ({
22
+ filePath,
23
+ relative: path.relative(repoRoot, filePath).replace(/\\/g, "/"),
24
+ }));
25
+ }
26
+
27
+ test("repository contains no PowerShell scripts", () => {
28
+ const psFiles = repoFiles().filter((entry) => entry.relative.endsWith(".ps1"));
29
+ assert.deepEqual(psFiles.map((entry) => entry.relative), []);
30
+ });
31
+
32
+ // Machinery removed in 3.0: the loop runtime and the manifest/maps knowledge store.
33
+ // The agent-facing surface (skills, references, docs, README) must never point at it;
34
+ // CHANGELOG keeps the history, and the uninstaller/gitignore keep legacy-cleanup paths.
35
+ const removedMachinery = /oris-skills loop |scripts\/loop\/|\.oris-flow\/(?:loops|runtime|manifest\.json|maps|adapter\.json)|loop-contract|references\/repo-map|flow scan[^\n]*--(?:check|write|area)|flow clean-runtime/;
36
+
37
+ test("agent-facing text never references machinery removed in 3.0", () => {
38
+ const offenders = repoFiles()
39
+ .filter((entry) => /^(skills|references|docs)\/.*\.md$|^(README|AGENTS|CONTEXT)\.md$/.test(entry.relative))
40
+ .filter((entry) => removedMachinery.test(fs.readFileSync(entry.filePath, "utf8")))
41
+ .map((entry) => entry.relative);
42
+ assert.deepEqual(offenders, []);
43
+ });
44
+
45
+ test("production scripts never invoke machinery removed in 3.0", () => {
46
+ const offenders = repoFiles()
47
+ // scripts/tests assert absences; the uninstaller/gitignore clean legacy paths — both must name them.
48
+ .filter((entry) => /^scripts\/(flow|install)\/.*\.mjs$|^scripts\/[^/]+\.mjs$/.test(entry.relative))
49
+ .filter((entry) => entry.relative !== "scripts/install/uninstall-user-skills.mjs")
50
+ .filter((entry) => entry.relative !== "scripts/flow/oris-gitignore.mjs")
51
+ .filter((entry) => removedMachinery.test(fs.readFileSync(entry.filePath, "utf8")))
52
+ .map((entry) => entry.relative);
53
+ assert.deepEqual(offenders, []);
54
+ });
@@ -1,18 +1,16 @@
1
- import assert from "node:assert/strict";
1
+ import assert from "node:assert/strict";
2
2
  import fs from "node:fs";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
5
  import test from "node:test";
6
- import childProcess from "node:child_process";
7
- import { checkFreshness, scanRepository, writeScanResult } from "../flow/oris-flow-scan.mjs";
8
- import { ORIS_FLOW_MANIFEST } from "../flow/oris-flow-layout.mjs";
6
+ import { scanRepository } from "../flow/oris-flow-scan.mjs";
9
7
 
10
8
  function write(filePath, content) {
11
9
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
12
10
  fs.writeFileSync(filePath, content, "utf8");
13
11
  }
14
12
 
15
- test("scanner creates only evidence-backed map sections", () => {
13
+ test("scanner reports only evidence-backed areas and writes nothing", () => {
16
14
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "oris-flow-scan-"));
17
15
  try {
18
16
  write(path.join(root, "README.md"), "# Demo\n");
@@ -20,17 +18,13 @@ test("scanner creates only evidence-backed map sections", () => {
20
18
  write(path.join(root, "src", "index.js"), "export const value = 1;\n");
21
19
 
22
20
  const scan = scanRepository(root);
23
- assert.ok(scan.manifest.sections.docs);
24
- assert.ok(scan.manifest.sections.stack);
25
- assert.ok(scan.manifest.sections.commands);
26
- assert.ok(scan.manifest.sections.code);
27
- assert.equal(scan.manifest.sections.backendData, undefined);
28
- assert.equal(scan.manifest["known" + "Gaps"], undefined);
21
+ assert.ok(scan.areas.docs);
22
+ assert.ok(scan.areas.code);
23
+ assert.ok(scan.stacks.some((stack) => stack.id === "node"));
24
+ assert.ok(scan.commands.some((command) => command.command === "npm run test"));
25
+ assert.equal(scan.areas.tests, undefined, "no test evidence → no tests area");
29
26
 
30
- const written = writeScanResult(scan);
31
- assert.equal(written.manifestPath, ORIS_FLOW_MANIFEST);
32
- assert.ok(fs.existsSync(path.join(root, ORIS_FLOW_MANIFEST)));
33
- assert.ok(fs.existsSync(path.join(root, ".oris-flow", "maps", "stack.md")));
27
+ assert.equal(fs.existsSync(path.join(root, ".oris-flow")), false, "scan never writes");
34
28
  } finally {
35
29
  fs.rmSync(root, { recursive: true, force: true });
36
30
  }
@@ -41,8 +35,9 @@ test("scanner supports documentation-only repositories", () => {
41
35
  try {
42
36
  write(path.join(root, "docs", "guide.md"), "# Guide\n");
43
37
  const scan = scanRepository(root);
44
- assert.deepEqual(Object.keys(scan.manifest.sections), ["docs"]);
38
+ assert.deepEqual(Object.keys(scan.areas), ["docs"]);
45
39
  assert.deepEqual(scan.stacks, []);
40
+ assert.deepEqual(scan.commands, []);
46
41
  } finally {
47
42
  fs.rmSync(root, { recursive: true, force: true });
48
43
  }
@@ -61,96 +56,31 @@ test("scanner detects project type and derives inferred stack commands", () => {
61
56
  const dotnetTest = scan.commands.find((command) => command.command.startsWith("dotnet test"));
62
57
  assert.ok(dotnetTest, "expected an inferred dotnet test command");
63
58
  assert.equal(dotnetTest.confidence, "inferred");
64
- assert.equal(scan.manifest.setup.tasksRoot, ".oris-flow/tasks");
65
59
  } finally {
66
60
  fs.rmSync(root, { recursive: true, force: true });
67
61
  }
68
62
  });
69
63
 
70
- test("refresh preserves confirmed sections, commands, and tasksRoot", () => {
64
+ test("scanner flags truncation instead of silently under-reporting", () => {
71
65
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "oris-flow-scan-"));
72
66
  try {
73
- write(path.join(root, "README.md"), "# Demo\n");
74
- write(path.join(root, "package.json"), `${JSON.stringify({ scripts: { test: "node --test" } })}\n`);
75
-
76
- const first = scanRepository(root);
77
- first.manifest.setup.tasksRoot = "docs/tasks";
78
- first.manifest.setup.confirmedDecisions = ["tests live under scripts/tests"];
79
- first.manifest.sections.docs.confidence = "confirmed";
80
- first.manifest.commands[0].confidence = "confirmed";
81
- writeScanResult(first);
82
- const enriched = "# Docs\n\nUser-confirmed enrichment that must survive refresh.\n";
83
- write(path.join(root, ".oris-flow", "maps", "docs.md"), enriched);
84
-
85
- const second = scanRepository(root);
86
- assert.equal(second.manifest.setup.tasksRoot, "docs/tasks");
87
- assert.deepEqual(second.manifest.setup.confirmedDecisions, ["tests live under scripts/tests"]);
88
- assert.equal(second.manifest.sections.docs.confidence, "confirmed");
89
- assert.equal(second.manifest.sections.docs.stale, false);
90
- assert.equal(second.manifest.commands[0].confidence, "confirmed");
91
- assert.ok(second.preservedSections.has("docs"));
92
-
93
- writeScanResult(second);
94
- assert.equal(fs.readFileSync(path.join(root, ".oris-flow", "maps", "docs.md"), "utf8"), enriched);
67
+ for (let index = 0; index < 12; index += 1) {
68
+ write(path.join(root, "src", `file-${index}.js`), "export {};\n");
69
+ }
70
+ const scan = scanRepository(root, { maxFiles: 5 });
71
+ assert.equal(scan.truncated, true);
72
+ assert.ok(scan.fileCount <= 5);
95
73
  } finally {
96
74
  fs.rmSync(root, { recursive: true, force: true });
97
75
  }
98
76
  });
99
77
 
100
- test("confirmed section without fresh evidence is marked stale, not deleted", () => {
101
- const root = fs.mkdtempSync(path.join(os.tmpdir(), "oris-flow-scan-"));
102
- try {
103
- write(path.join(root, "README.md"), "# Demo\n");
104
- const first = scanRepository(root);
105
- first.manifest.sections.docs.confidence = "confirmed";
106
- writeScanResult(first);
107
-
108
- fs.rmSync(path.join(root, "README.md"));
109
- const second = scanRepository(root);
110
- assert.equal(second.manifest.sections.docs.confidence, "confirmed");
111
- assert.equal(second.manifest.sections.docs.stale, true);
112
- } finally {
113
- fs.rmSync(root, { recursive: true, force: true });
114
- }
115
- });
116
-
117
-
118
- test("scan anchors the map to HEAD; --check answers freshness from the SHA + changed files", () => {
78
+ test("empty repository classifies as empty", () => {
119
79
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "oris-flow-scan-"));
120
- const git = (...args) => childProcess.execFileSync("git", args, { cwd: root, encoding: "utf8" });
121
80
  try {
122
- write(path.join(root, "README.md"), "# Demo\n");
123
- write(path.join(root, "package.json"), `${JSON.stringify({ scripts: { test: "node --test" } })}\n`);
124
- git("init", "-q");
125
- git("-c", "user.email=t@t", "-c", "user.name=t", "add", ".");
126
- git("-c", "user.email=t@t", "-c", "user.name=t", "commit", "-q", "-m", "init");
127
-
128
- const scan = scanRepository(root);
129
- assert.equal(typeof scan.manifest.headSha, "string", "scan records the HEAD anchor");
130
- writeScanResult(scan);
131
-
132
- const fresh = checkFreshness(root);
133
- assert.equal(fresh.fresh, true, "same SHA + clean tree → fresh, zero reads");
134
- assert.deepEqual(fresh.changedFiles, []);
135
-
136
- write(path.join(root, "src", "new.js"), "export const later = 1;\n");
137
- const stale = checkFreshness(root);
138
- assert.equal(stale.fresh, false, "working-tree change → stale");
139
- assert.ok(stale.changedFiles.some((file) => file.includes("new.js")), "changed files name the delta");
140
- } finally {
141
- fs.rmSync(root, { recursive: true, force: true });
142
- }
143
- });
144
-
145
- test("outside git the map still works — no anchor, never an error", () => {
146
- const root = fs.mkdtempSync(path.join(os.tmpdir(), "oris-flow-scan-"));
147
- try {
148
- write(path.join(root, "README.md"), "# Demo\n");
149
81
  const scan = scanRepository(root);
150
- assert.equal(scan.manifest.headSha, null);
151
- writeScanResult(scan);
152
- const check = checkFreshness(root);
153
- assert.equal(check.fresh, false, "no anchor → refresh advised, not an error");
82
+ assert.equal(scan.projectType.id, "empty");
83
+ assert.deepEqual(scan.areas, {});
154
84
  } finally {
155
85
  fs.rmSync(root, { recursive: true, force: true });
156
86
  }
@@ -72,58 +72,27 @@ test("every skill points at conventions instead of repeating shared rules", () =
72
72
  }
73
73
  });
74
74
 
75
- test("loop skill covers craft, demo, run, audit, improve and editable prompt files", () => {
76
- const skill = read("skills/oris-flow/references/loop.md");
77
- assert.match(skill, /references\/loop-craft\.md/);
78
- assert.match(skill, /references\/loop-run\.md/);
79
- assert.match(skill, /references\/loop-improve\.md/);
80
- assert.match(skill, /oris-skills loop demo/);
81
- assert.match(skill, /oris-skills loop dry-run/);
82
- assert.match(skill, /oris-skills loop list --json/);
83
- assert.match(skill, /prompts\//);
84
- assert.match(skill, /improve\.mode: auto/);
85
- assert.match(skill, /Cursor|Claude Code|Codex/);
86
- for (const reference of ["craft", "run", "improve"]) {
87
- assert.equal(exists(`skills/oris-flow/references/loop-${reference}.md`), true, reference);
88
- }
89
- for (const template of ["orchestrator", "executor", "verifier", "doctor", "debriefer"]) {
90
- assert.equal(exists(`skills/oris-flow/templates/${template}.md`), true, template);
91
- }
92
- });
93
-
94
- test("loop contract stays subagent-first with per-role editable prompts", () => {
95
- const contract = read("references/loop-contract.md");
96
- assert.match(contract, /schemaVersion: 2/);
97
- assert.match(contract, /approved: true/);
98
- assert.match(contract, /prompts\/orchestrator\.md/);
99
- assert.match(contract, /improve/);
100
- assert.match(contract, /inherit/);
101
- assert.match(contract, /NEVER success/i);
102
- const run = read("skills/oris-flow/references/loop-run.md");
103
- assert.match(run, /oris-skills loop chat --action start --loop <slug>/);
104
- assert.match(run, /NEVER do executor\/verifier\/doctor work in the main chat/i);
105
- assert.match(run, /set-state blocked/);
106
- assert.match(run, /oris-skills loop run --loop <slug> --agent codex\|claude/);
107
- const craft = read("skills/oris-flow/references/loop-craft.md");
108
- assert.match(craft, /skills\/oris-flow\/templates\//);
109
- assert.match(craft, /write the loop \| edit verifier \| edit executor \| edit doctor/);
110
- assert.match(contract, /ORIS LOOP ACTIVE/, "the contract defines the executor gate literal");
111
- for (const text of [contract, run, craft, read("skills/oris-flow/references/loop.md")]) {
112
- assert.doesNotMatch(text, /node scripts\/(?:flow|loop)\//);
113
- assert.doesNotMatch(text, /composer-2\.5/);
114
- }
115
- for (const text of [run, craft, read("skills/oris-flow/references/loop.md")]) {
116
- assert.doesNotMatch(text, /ORIS LOOP ACTIVE/, "the gate literal lives in the contract and executor prompts only");
75
+ test("the loop runtime is fully removed", () => {
76
+ for (const legacy of [
77
+ "scripts/loop",
78
+ "agents",
79
+ "skills/oris-flow/templates",
80
+ "skills/oris-flow/references/loop.md",
81
+ "references/loop-contract.md",
82
+ "references/repo-map.md",
83
+ ]) {
84
+ assert.equal(exists(legacy), false, `${legacy} must not exist`);
117
85
  }
86
+ const skill = read("skills/oris-flow/SKILL.md");
87
+ assert.doesNotMatch(skill, /\bloop\b/i, "the router must not mention loops");
118
88
  });
119
89
 
120
- test("setup and repo-map keep the installed CLI as the command surface", () => {
90
+ test("setup keeps the installed CLI as the command surface and AGENTS.md as the store", () => {
121
91
  const setup = read("skills/oris-flow/references/setup.md");
122
92
  assert.match(setup, /oris-skills flow scan --repository-root <repo> --json/);
123
- assert.match(setup, /oris-skills loop bootstrap --repository-root <repo>/);
124
- assert.match(setup, /oris-skills flow clean-runtime --repository-root <repo> --dry-run/);
125
- const repoMap = read("references/repo-map.md");
126
- assert.match(repoMap, /never `node scripts\/\.\.\.` paths/);
93
+ assert.match(setup, /oris-skills flow version-control --repository-root <repo> --mode commit\|gitignore/);
94
+ assert.doesNotMatch(setup, /node scripts\//, "always the installed CLI, never source paths");
95
+ assert.match(setup, /AGENTS\.md/);
127
96
  });
128
97
 
129
98
  test("no markdown references the pre-2.0 layout", () => {
@@ -165,18 +134,18 @@ test("uninstall and reinstall dry-runs show destructive plan before action", ()
165
134
  }
166
135
  });
167
136
 
168
- test("CLI exposes install, loop learnability, and flow helper commands", () => {
137
+ test("CLI exposes install and flow helper commands, and no loop surface", () => {
169
138
  const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "oris-cli-help-"));
170
139
  try {
171
140
  const help = runCli(["help"], homeDir);
172
141
  assert.equal(help.status, 0, help.stderr);
173
142
  assert.match(help.stdout, /--agents cursor,claude,codex/);
174
- assert.match(help.stdout, /oris-skills loop demo/);
175
- assert.match(help.stdout, /oris-skills loop dry-run --loop <slug>/);
176
- assert.match(help.stdout, /oris-skills loop verify --temp/);
177
- assert.match(help.stdout, /oris-skills loop chat --action start --loop <slug>/);
178
- assert.match(help.stdout, /oris-skills loop run --loop <slug> --agent codex\|claude/);
179
143
  assert.match(help.stdout, /oris-skills flow scan/);
144
+ assert.match(help.stdout, /oris-skills flow version-control/);
145
+ assert.doesNotMatch(help.stdout, /loop/i);
146
+
147
+ const loop = runCli(["loop", "list"], homeDir);
148
+ assert.equal(loop.status, 1, "loop is an unknown command in 3.0");
180
149
  } finally {
181
150
  fs.rmSync(homeDir, { recursive: true, force: true });
182
151
  }
@@ -12,45 +12,31 @@ function read(relativePath) {
12
12
  return JSON.parse(fs.readFileSync(path.join(root, relativePath), "utf8"));
13
13
  }
14
14
 
15
- test("settings schema is the minimal v1 contract: only responseStyle and artifactLanguage", () => {
15
+ test("settings schema is the v1 contract: preferences only, no secrets, no profiles", () => {
16
16
  const schema = read("references/settings.schema.json");
17
17
  assert.equal(schema.properties.version.const, 1);
18
18
  assert.deepEqual(schema.required, ["version", "orisFlow"]);
19
- assert.ok(schema.properties.orisFlow.properties.responseStyle);
20
- assert.ok(schema.properties.orisFlow.properties.artifactLanguage);
21
- assert.ok(!schema.properties.defaultProfiles, "test profiles were removed from settings");
22
- assert.ok(!schema.properties.profiles, "test profiles were removed from settings");
23
- });
24
-
25
- test("adapter schema v1 declares paths, commands, model aliases, preflight (no test profiles)", () => {
26
- const schema = read("references/loop-adapter.schema.json");
27
- assert.equal(schema.$id, "https://oris.dev/schemas/oris-loop-adapter-v1.json");
28
- assert.equal(schema.properties.schemaVersion.const, 1);
19
+ const properties = schema.properties.orisFlow.properties;
29
20
  assert.deepEqual(
30
- schema.required,
31
- ["$schema", "schemaVersion", "repository", "paths", "commands", "preflight"],
21
+ Object.keys(properties).sort(),
22
+ ["artifactLanguage", "responseStyle", "tasksRoot", "versionControl"],
32
23
  );
33
- assert.ok(schema.properties.paths.properties.loops);
34
- assert.ok(schema.properties.models, "adapter schema must allow a model alias map");
35
- assert.ok(!schema.properties.profile, "test profiles were removed from the adapter");
24
+ assert.deepEqual(properties.versionControl.enum, ["commit", "gitignore"]);
25
+ assert.ok(!schema.properties.defaultProfiles, "test profiles were removed from settings");
26
+ assert.ok(!schema.properties.profiles, "test profiles were removed from settings");
36
27
  });
37
28
 
38
- test("loop document schema is v2 with approved gate, per-role models, and improve mode", () => {
39
- const schema = read("references/loop.schema.json");
40
- assert.equal(schema.$id, "https://oris.dev/schemas/oris-loop-v2.json");
41
- assert.equal(schema.properties.schemaVersion.const, 2);
42
- assert.ok(schema.required.includes("approved"));
43
- assert.ok(!schema.required.includes("runtime"), "runtime field was removed in v2");
44
- for (const role of ["default", "executor", "verifier", "doctor", "debriefer"]) {
45
- assert.ok(schema.properties.models.properties[role], `models.${role}`);
29
+ test("no loop or repo-map schemas survive the 3.0 cleanup", () => {
30
+ for (const legacy of [
31
+ "references/loop.schema.json",
32
+ "references/loop-adapter.schema.json",
33
+ "references/repo-map.schema.json",
34
+ ]) {
35
+ assert.equal(fs.existsSync(path.join(root, legacy)), false, `${legacy} must not exist`);
46
36
  }
47
- assert.deepEqual(schema.properties.improve.properties.mode.enum, ["propose", "auto"]);
48
- assert.equal(schema.$defs.model.type, "string", "models are free strings (inherit | alias | model id), not a hardcoded enum");
49
37
  });
50
38
 
51
- test("repository map schema v1 allows stack-aware optional sections", () => {
52
- const schema = read("references/repo-map.schema.json");
53
- assert.equal(schema.properties.schemaVersion.const, 1);
54
- assert.deepEqual(schema.required, ["$schema", "schemaVersion", "repository", "generatedAt", "updatedAt", "setup", "sections"]);
55
- assert.ok(schema.$defs.sections.additionalProperties);
39
+ test("devops schema stays the only other JSON contract", () => {
40
+ const schemas = fs.readdirSync(path.join(root, "references")).filter((name) => name.endsWith(".schema.json"));
41
+ assert.deepEqual(schemas.sort(), ["devops.schema.json", "settings.schema.json"]);
56
42
  });
@@ -36,8 +36,11 @@ test("skill style: oris-flow", () => {
36
36
  assert.match(front[1], /^name: oris-flow$/m, "front matter name matches the folder");
37
37
  const description = front[1].match(/^description: (.+)$/m)?.[1];
38
38
  assert.ok(description, "front matter has description");
39
- assert.match(description, /Use for/, "description names its triggers");
40
- assert.doesNotMatch(front[1], /disable-model-invocation/, "the single entry point must stay model-invocable");
39
+ assert.match(
40
+ front[1],
41
+ /^disable-model-invocation: true$/m,
42
+ "the entry point is user-invoked only (/oris-flow) — decision 2026-07-10, never auto-triggered",
43
+ );
41
44
  assert.ok(text.includes("## Never"), "carries an explicit Never block");
42
45
  assert.ok(text.includes("## Done when"), "ends with a Done when checklist");
43
46
  const lines = text.split(/\r?\n/).length;
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: oris-flow
3
- description: The one Oris skill - read the intent, pick ONE route, apply it in the same chat. Use for /oris-flow and whenever the user wants to set up a repo for agents, start a project, understand or define behavior, write acceptance criteria, plan, implement, fix a bug, verify criteria, handle a spec change, run a work loop (fix until green, repeat until verified), review architecture, update task docs, commit changes, open a pull request, or asks how Oris works.
3
+ description: The one Oris skill - read the intent, pick ONE route, apply it in the same chat. Routes setup, new project, discovery, acceptance criteria, technical plan, implement, fix, verify, spec change, architecture review, docs, commit, pull request, and help.
4
+ disable-model-invocation: true
4
5
  ---
5
6
 
6
7
  # Oris Flow — the router
@@ -29,10 +30,9 @@ Match the desired outcome to ONE route, then apply its reference:
29
30
  | fix | broken behavior, a regression, a failed QA check | `skills/oris-flow/references/fix.md` |
30
31
  | verify | check acceptance criteria against the real product, once | `skills/oris-flow/references/verify.md` |
31
32
  | change | the spec changed — update analysis, criteria, plan, and history together | `skills/oris-flow/references/change.md` |
32
- | loop | repeat work until verified — fix until green, step through a plan | `skills/oris-flow/references/loop.md` |
33
33
  | architecture | review architecture, find deepening/refactor opportunities | `skills/oris-flow/references/architecture.md` |
34
34
  | docs | update task docs after a change | `skills/oris-flow/references/docs.md` |
35
- | commit | commit changes with the Oris standard — map fresh, Conventional Commits, work item linked | `skills/oris-flow/references/commit.md` |
35
+ | commit | commit changes with the Oris standard — Conventional Commits, work item linked | `skills/oris-flow/references/commit.md` |
36
36
  | pr | open or update a pull request, English title/description linked to the work item | `skills/oris-flow/references/pr.md` |
37
37
  | help | how Oris works, install, update, troubleshooting | `skills/oris-flow/references/help.md` |
38
38
 
@@ -46,10 +46,9 @@ Match the desired outcome to ONE route, then apply its reference:
46
46
  change owns the delta and the history.
47
47
  4. BROKEN behavior → fix. NEW planned work → implement. The menu answer "Implement or
48
48
  fix" gets exactly one follow-up question to split them.
49
- 5. CHECK onceverify. Repeat-until-verified loop.
50
- 6. EMPTY directory or from-scratch intent new. Existing repo without
51
- `.oris-flow/manifest.json`recommend setup first; respect the user's choice.
52
- 7. COMMIT staged/working changes with the standard → commit. OPEN or update a pull request
49
+ 5. EMPTY directory or from-scratch intent new. Existing repo never touched by Oris
50
+ (no `AGENTS.md`, no `.oris-flow/`) recommend setup first; respect the user's choice.
51
+ 6. COMMIT staged/working changes with the standard commit. OPEN or update a pull request
53
52
  → pr. Neither writes product code — they package and publish what implement/fix produced.
54
53
 
55
54
  ## Menu (low confidence)
@@ -66,7 +65,6 @@ fallback in `references/conventions.md` `## Questions`), options:
66
65
  - Implement or fix
67
66
  - Verify acceptance criteria
68
67
  - Spec changed: update feature docs
69
- - Loop: repeat until verified
70
68
  - Architecture review
71
69
  - Update docs
72
70
  - Commit changes
@@ -22,7 +22,7 @@ routes to plan/implement.
22
22
 
23
23
  ## 1. Explore
24
24
 
25
- 1. READ first: setup map, `CONTEXT.md` (domain names for good seams), `docs/adr/`
25
+ 1. READ first: `AGENTS.md`, `CONTEXT.md` (domain names for good seams), `docs/adr/`
26
26
  (decisions NOT to re-litigate).
27
27
  2. WALK the codebase with parallel subagents. No rigid heuristics — note real friction:
28
28
  - understanding one concept requires bouncing between many small modules;
@@ -1,15 +1,16 @@
1
1
  # Commit
2
2
 
3
- Turn staged or working changes into one clean commit — map fresh, message in English,
4
- work item linked. NEVER commit without showing the message and getting a yes.
3
+ Turn staged or working changes into one clean commit — message in English, work item
4
+ linked. NEVER commit without showing the message and getting a yes.
5
5
 
6
6
  RULES: `references/conventions.md`. DevOps config: `references/devops.md`.
7
7
 
8
8
  ## Before the commit
9
9
 
10
- 1. FRESHEN the map: `npx oris-skills flow scan --repository-root <repo> --check`. Stale
11
- refresh ONLY the changed areas (`--area <section>`) and stage `.oris-flow/` with the change.
12
- 2. READ the diff (`git status`, `git diff --staged`) to know what actually changed.
10
+ 1. READ the diff (`git status`, `git diff --staged`) to know what actually changed.
11
+ 2. IF the diff proved a durable fact `AGENTS.md` lacks or contradicts (a new command, a
12
+ moved area) correct `AGENTS.md` and stage it with the change (`references/conventions.md`
13
+ `## Project facts`).
13
14
  3. RESOLVE the work item id from context — current branch, the active task doc, or the
14
15
  DevOps provider's active items. Unsure → ASK once for the id; never invent one.
15
16
 
@@ -23,7 +24,7 @@ RULES: `references/conventions.md`. DevOps config: `references/devops.md`.
23
24
 
24
25
  ## Gate (never skipped)
25
26
 
26
- SHOW the full message + the files it will commit (code + refreshed map). ASK:
27
+ SHOW the full message + the files it will commit. ASK:
27
28
  commit | edit message | cancel. ON commit → `git commit`; NEVER `--no-verify`.
28
29
 
29
30
  ## After
@@ -36,10 +37,10 @@ commit | edit message | cancel. ON commit → `git commit`; NEVER `--no-verify`.
36
37
  - Commit before the message and file list are shown and confirmed.
37
38
  - Write the message in any language but English.
38
39
  - Invent a work item id, or bypass hooks with `--no-verify`.
39
- - Refresh confirmed map sections, or scan-rewrite areas the diff did not touch.
40
+ - Touch `AGENTS.md` sections the diff did not contradict.
40
41
 
41
42
  ## Done when
42
43
 
43
- - [ ] Map checked, and refreshed in place only where the diff touched.
44
+ - [ ] Diff read; `AGENTS.md` corrected only where the diff proved it wrong.
44
45
  - [ ] English Conventional message with the work item linked, confirmed at the gate.
45
46
  - [ ] Commit made without `--no-verify`; next step offered, not auto-run.
@@ -1,8 +1,8 @@
1
1
  # Acceptance Criteria
2
2
 
3
3
  Generate verifiable criteria grounded in observable product behavior — UI, API response,
4
- CLI output, or a visible system effect. They later feed verify-route checks and
5
- loop VERIFIER prompts — precision here pays twice.
4
+ CLI output, or a visible system effect. They are the exact checklist the verify route
5
+ executes — precision here pays twice.
6
6
 
7
7
  RULES: `references/conventions.md`. Doc standards: `references/doc-policy.md`.
8
8
 
@@ -1,7 +1,7 @@
1
1
  # Discovery
2
2
 
3
3
  Interview the stakeholder until the desired business behavior is clear enough to
4
- document. The cornerstone of the flow: everything downstream (criteria, plan, loops)
4
+ document. The cornerstone of the flow: everything downstream (criteria, plan, implement)
5
5
  builds on this.
6
6
 
7
7
  RULES: `references/conventions.md`. Doc standards: `references/doc-policy.md`.
@@ -9,7 +9,7 @@ RULES: `references/conventions.md`. Doc standards: `references/doc-policy.md`.
9
9
  ## Before asking
10
10
 
11
11
  1. EXPLORE first: task folder (`{tasksRoot}/{task}/`), existing task docs, project docs,
12
- setup map, code evidence, DevOps context when available.
12
+ `AGENTS.md`, code evidence, DevOps context when available.
13
13
  2. DEDUCE create vs update: existing `functional-analysis.md` → update; missing → create.
14
14
  Ask only on contradictory signals.
15
15
  3. Technical evidence = private input. TRANSLATE it to business language; never show file
@@ -3,7 +3,7 @@
3
3
  The smallest safe change near the failing behavior. Reproduce first, root cause before
4
4
  any edit, evidence before done.
5
5
 
6
- RULES: `references/conventions.md`.
6
+ RULES: `references/conventions.md`. Research: `references/research.md`.
7
7
 
8
8
  ## Triage
9
9
 
@@ -19,8 +19,12 @@ RULES: `references/conventions.md`.
19
19
  - REPRODUCE or trace the failure path in code before proposing anything.
20
20
  - FIND root cause, not symptom. Check whether the documented behavior
21
21
  (criteria/analysis) defines "correct".
22
- - SUMMARIZE: root cause proposed minimal fix files → verification plan.
23
- CONFIRM explicitly.
22
+ - RESEARCH when the cause crosses the repo boundary (`references/research.md`): a
23
+ third-party error, a library behaving unlike its docs, a known-issue smell → search
24
+ for the documented behavior and standard workarounds at the repo's pinned versions,
25
+ instead of guessing.
26
+ - SUMMARIZE: root cause → proposed minimal fix → files → verification plan (+ sources
27
+ when research ran). CONFIRM explicitly.
24
28
 
25
29
  ## Fix
26
30
 
@@ -8,24 +8,19 @@ details on request.
8
8
  | Need | Answer |
9
9
  |------|--------|
10
10
  | Start anything | Type `/oris-flow` — it routes or shows the menu. The only command to remember. |
11
- | Try loops safely | `npx oris-skills loop demo` → follow the 3 printed steps (`dry-run` previews, `chat --action start` runs). |
12
11
  | Install / update | `npx oris-skills@latest install` (detects Cursor, Claude Code, Codex, Copilot; or `--agents cursor,claude,codex,copilot`). Reload the agent afterwards. |
13
12
  | Copilot / any other agent | Copilot Chat: enable `chat.promptFiles` once, then `/oris-flow`. Anything else that reads files: point it at `~/.oris/oris-flow.md`. |
14
13
  | Uninstall / reinstall | `npx oris-skills uninstall` / `npx oris-skills reinstall` (preview with `--dry-run`). |
15
- | Stop a loop | `npx oris-skills loop chat --action stop` |
16
- | Loop status | `npx oris-skills loop chat --action status` / `npx oris-skills loop list` |
17
14
  | Skill missing after install | Reload the agent; check `~/.oris/oris-skills/` exists; re-run install with `--force`. |
18
- | Hook not firing | `npx oris-skills loop verify --temp` self-checks the runtime; `npx oris-skills loop bootstrap` re-arms repo hooks. |
19
15
  | Change document language / chat verbosity | `/oris-flow` → Setup (settings live in `.oris-flow/settings.json`). |
20
16
  | Ultra-short answers | `/oris-flow` → Setup → set `responseStyle: caveman` — chat shrinks to maximum token density; documents stay complete. |
21
- | Edit a loop's behavior | Edit the files in `.oris-flow/loops/{slug}/prompts/` — the next pass obeys them. |
22
17
 
23
18
  Deeper docs: `docs/user-guide.md`, `docs/architecture.md` in the bundle (`~/.oris/oris-skills/`).
24
19
 
25
20
  ## Never
26
21
 
27
22
  - Tell users to paste secrets anywhere.
28
- - Dump internals (manifest JSON, hook mechanics) unless the user asks for technical
23
+ - Dump internals (settings JSON, install layout) unless the user asks for technical
29
24
  troubleshooting.
30
25
 
31
26
  ## Done when
@@ -2,14 +2,14 @@
2
2
 
3
3
  Execute the confirmed plan — nothing more, nothing less.
4
4
 
5
- RULES: `references/conventions.md`.
5
+ RULES: `references/conventions.md`. Research: `references/research.md`.
6
6
 
7
7
  ## Prepare
8
8
 
9
9
  1. FIND `{tasksRoot}/{task}/implementation-plan.md`. IF missing → reconstruct a technical
10
10
  recap from chat, task docs, and code; SHOW it; CONFIRM before any edit.
11
- 2. READ setup map, project standards, local skills/rules, tests and build conventions for
12
- the touched area.
11
+ 2. READ `AGENTS.md`, project standards, local skills/rules, tests and build conventions
12
+ for the touched area.
13
13
  3. MAP the code, tests, config, and translations the plan touches (parallel subagents
14
14
  when available).
15
15
 
@@ -22,6 +22,8 @@ RULES: `references/conventions.md`.
22
22
  ## While coding
23
23
 
24
24
  - FOLLOW existing project patterns; no new abstractions without need.
25
+ - RESEARCH mid-build only when an external API resists (`references/research.md`) —
26
+ verify its current docs at the repo's pinned version; never guess signatures.
25
27
  - STAY inside the confirmed scope; park discoveries as notes, don't chase them.
26
28
  - ADD or update focused tests for the changed behavior.
27
29
  - CLEAN as you finish (`references/clean-code-checklist.md`): remove dead code, debug