ralph-research 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -0
  3. package/dist/adapters/extractor/command-extractor.d.ts +9 -0
  4. package/dist/adapters/extractor/command-extractor.js +93 -0
  5. package/dist/adapters/extractor/command-extractor.js.map +1 -0
  6. package/dist/adapters/extractor/llm-judge-extractor.d.ts +9 -0
  7. package/dist/adapters/extractor/llm-judge-extractor.js +12 -0
  8. package/dist/adapters/extractor/llm-judge-extractor.js.map +1 -0
  9. package/dist/adapters/fs/json-file-decision-store.d.ts +10 -0
  10. package/dist/adapters/fs/json-file-decision-store.js +53 -0
  11. package/dist/adapters/fs/json-file-decision-store.js.map +1 -0
  12. package/dist/adapters/fs/json-file-frontier-store.d.ts +8 -0
  13. package/dist/adapters/fs/json-file-frontier-store.js +29 -0
  14. package/dist/adapters/fs/json-file-frontier-store.js.map +1 -0
  15. package/dist/adapters/fs/json-file-run-store.d.ts +10 -0
  16. package/dist/adapters/fs/json-file-run-store.js +53 -0
  17. package/dist/adapters/fs/json-file-run-store.js.map +1 -0
  18. package/dist/adapters/fs/lockfile.d.ts +24 -0
  19. package/dist/adapters/fs/lockfile.js +110 -0
  20. package/dist/adapters/fs/lockfile.js.map +1 -0
  21. package/dist/adapters/fs/manifest-loader.d.ts +10 -0
  22. package/dist/adapters/fs/manifest-loader.js +43 -0
  23. package/dist/adapters/fs/manifest-loader.js.map +1 -0
  24. package/dist/adapters/git/git-client.d.ts +9 -0
  25. package/dist/adapters/git/git-client.js +23 -0
  26. package/dist/adapters/git/git-client.js.map +1 -0
  27. package/dist/adapters/index.d.ts +1 -0
  28. package/dist/adapters/index.js +3 -0
  29. package/dist/adapters/index.js.map +1 -0
  30. package/dist/adapters/judge/llm-judge-provider.d.ts +33 -0
  31. package/dist/adapters/judge/llm-judge-provider.js +90 -0
  32. package/dist/adapters/judge/llm-judge-provider.js.map +1 -0
  33. package/dist/adapters/proposer/command-proposer.d.ts +15 -0
  34. package/dist/adapters/proposer/command-proposer.js +29 -0
  35. package/dist/adapters/proposer/command-proposer.js.map +1 -0
  36. package/dist/app/context.d.ts +5 -0
  37. package/dist/app/context.js +7 -0
  38. package/dist/app/context.js.map +1 -0
  39. package/dist/app/services/manual-decision-service.d.ts +20 -0
  40. package/dist/app/services/manual-decision-service.js +143 -0
  41. package/dist/app/services/manual-decision-service.js.map +1 -0
  42. package/dist/app/services/project-state-service.d.ts +52 -0
  43. package/dist/app/services/project-state-service.js +92 -0
  44. package/dist/app/services/project-state-service.js.map +1 -0
  45. package/dist/app/services/run-cycle-service.d.ts +25 -0
  46. package/dist/app/services/run-cycle-service.js +69 -0
  47. package/dist/app/services/run-cycle-service.js.map +1 -0
  48. package/dist/cli/commands/accept.d.ts +10 -0
  49. package/dist/cli/commands/accept.js +54 -0
  50. package/dist/cli/commands/accept.js.map +1 -0
  51. package/dist/cli/commands/demo.d.ts +9 -0
  52. package/dist/cli/commands/demo.js +108 -0
  53. package/dist/cli/commands/demo.js.map +1 -0
  54. package/dist/cli/commands/frontier.d.ts +8 -0
  55. package/dist/cli/commands/frontier.js +48 -0
  56. package/dist/cli/commands/frontier.js.map +1 -0
  57. package/dist/cli/commands/init.d.ts +10 -0
  58. package/dist/cli/commands/init.js +123 -0
  59. package/dist/cli/commands/init.js.map +1 -0
  60. package/dist/cli/commands/inspect.d.ts +8 -0
  61. package/dist/cli/commands/inspect.js +55 -0
  62. package/dist/cli/commands/inspect.js.map +1 -0
  63. package/dist/cli/commands/reject.d.ts +10 -0
  64. package/dist/cli/commands/reject.js +54 -0
  65. package/dist/cli/commands/reject.js.map +1 -0
  66. package/dist/cli/commands/run.d.ts +13 -0
  67. package/dist/cli/commands/run.js +71 -0
  68. package/dist/cli/commands/run.js.map +1 -0
  69. package/dist/cli/commands/serve-mcp.d.ts +7 -0
  70. package/dist/cli/commands/serve-mcp.js +32 -0
  71. package/dist/cli/commands/serve-mcp.js.map +1 -0
  72. package/dist/cli/commands/status.d.ts +8 -0
  73. package/dist/cli/commands/status.js +53 -0
  74. package/dist/cli/commands/status.js.map +1 -0
  75. package/dist/cli/commands/validate.d.ts +11 -0
  76. package/dist/cli/commands/validate.js +56 -0
  77. package/dist/cli/commands/validate.js.map +1 -0
  78. package/dist/cli/main.d.ts +2 -0
  79. package/dist/cli/main.js +38 -0
  80. package/dist/cli/main.js.map +1 -0
  81. package/dist/core/engine/anchor-checker.d.ts +35 -0
  82. package/dist/core/engine/anchor-checker.js +84 -0
  83. package/dist/core/engine/anchor-checker.js.map +1 -0
  84. package/dist/core/engine/audit-sampler.d.ts +16 -0
  85. package/dist/core/engine/audit-sampler.js +25 -0
  86. package/dist/core/engine/audit-sampler.js.map +1 -0
  87. package/dist/core/engine/change-budget.d.ts +11 -0
  88. package/dist/core/engine/change-budget.js +10 -0
  89. package/dist/core/engine/change-budget.js.map +1 -0
  90. package/dist/core/engine/cycle-runner.d.ts +39 -0
  91. package/dist/core/engine/cycle-runner.js +652 -0
  92. package/dist/core/engine/cycle-runner.js.map +1 -0
  93. package/dist/core/engine/experiment-runner.d.ts +13 -0
  94. package/dist/core/engine/experiment-runner.js +24 -0
  95. package/dist/core/engine/experiment-runner.js.map +1 -0
  96. package/dist/core/engine/history-compactor.d.ts +15 -0
  97. package/dist/core/engine/history-compactor.js +76 -0
  98. package/dist/core/engine/history-compactor.js.map +1 -0
  99. package/dist/core/engine/judge-pack.d.ts +44 -0
  100. package/dist/core/engine/judge-pack.js +111 -0
  101. package/dist/core/engine/judge-pack.js.map +1 -0
  102. package/dist/core/engine/parallel-proposer.d.ts +21 -0
  103. package/dist/core/engine/parallel-proposer.js +58 -0
  104. package/dist/core/engine/parallel-proposer.js.map +1 -0
  105. package/dist/core/engine/scope-checker.d.ts +35 -0
  106. package/dist/core/engine/scope-checker.js +166 -0
  107. package/dist/core/engine/scope-checker.js.map +1 -0
  108. package/dist/core/engine/workspace-manager.d.ts +32 -0
  109. package/dist/core/engine/workspace-manager.js +145 -0
  110. package/dist/core/engine/workspace-manager.js.map +1 -0
  111. package/dist/core/index.d.ts +1 -0
  112. package/dist/core/index.js +3 -0
  113. package/dist/core/index.js.map +1 -0
  114. package/dist/core/manifest/defaults.d.ts +55 -0
  115. package/dist/core/manifest/defaults.js +56 -0
  116. package/dist/core/manifest/defaults.js.map +1 -0
  117. package/dist/core/manifest/schema.d.ts +647 -0
  118. package/dist/core/manifest/schema.js +254 -0
  119. package/dist/core/manifest/schema.js.map +1 -0
  120. package/dist/core/model/decision-record.d.ts +38 -0
  121. package/dist/core/model/decision-record.js +29 -0
  122. package/dist/core/model/decision-record.js.map +1 -0
  123. package/dist/core/model/frontier-entry.d.ts +24 -0
  124. package/dist/core/model/frontier-entry.js +15 -0
  125. package/dist/core/model/frontier-entry.js.map +1 -0
  126. package/dist/core/model/metric.d.ts +13 -0
  127. package/dist/core/model/metric.js +10 -0
  128. package/dist/core/model/metric.js.map +1 -0
  129. package/dist/core/model/run-record.d.ts +110 -0
  130. package/dist/core/model/run-record.js +104 -0
  131. package/dist/core/model/run-record.js.map +1 -0
  132. package/dist/core/ports/decision-store.d.ts +6 -0
  133. package/dist/core/ports/decision-store.js +2 -0
  134. package/dist/core/ports/decision-store.js.map +1 -0
  135. package/dist/core/ports/frontier-store.d.ts +5 -0
  136. package/dist/core/ports/frontier-store.js +2 -0
  137. package/dist/core/ports/frontier-store.js.map +1 -0
  138. package/dist/core/ports/run-store.d.ts +6 -0
  139. package/dist/core/ports/run-store.js +2 -0
  140. package/dist/core/ports/run-store.js.map +1 -0
  141. package/dist/core/state/constraint-engine.d.ts +18 -0
  142. package/dist/core/state/constraint-engine.js +42 -0
  143. package/dist/core/state/constraint-engine.js.map +1 -0
  144. package/dist/core/state/frontier-engine.d.ts +24 -0
  145. package/dist/core/state/frontier-engine.js +178 -0
  146. package/dist/core/state/frontier-engine.js.map +1 -0
  147. package/dist/core/state/ratchet-engine.d.ts +28 -0
  148. package/dist/core/state/ratchet-engine.js +177 -0
  149. package/dist/core/state/ratchet-engine.js.map +1 -0
  150. package/dist/core/state/run-state-machine.d.ts +17 -0
  151. package/dist/core/state/run-state-machine.js +94 -0
  152. package/dist/core/state/run-state-machine.js.map +1 -0
  153. package/dist/mcp/main.d.ts +1 -0
  154. package/dist/mcp/main.js +8 -0
  155. package/dist/mcp/main.js.map +1 -0
  156. package/dist/mcp/server.d.ts +6 -0
  157. package/dist/mcp/server.js +97 -0
  158. package/dist/mcp/server.js.map +1 -0
  159. package/dist/shared/fs-errors.d.ts +1 -0
  160. package/dist/shared/fs-errors.js +4 -0
  161. package/dist/shared/fs-errors.js.map +1 -0
  162. package/dist/shared/logger.d.ts +2 -0
  163. package/dist/shared/logger.js +5 -0
  164. package/dist/shared/logger.js.map +1 -0
  165. package/dist/shared/template-utils.d.ts +9 -0
  166. package/dist/shared/template-utils.js +50 -0
  167. package/dist/shared/template-utils.js.map +1 -0
  168. package/package.json +44 -0
  169. package/templates/writing/docs/draft.md +1 -0
  170. package/templates/writing/prompts/judge.md +15 -0
  171. package/templates/writing/ralph.yaml +63 -0
  172. package/templates/writing/scripts/experiment.mjs +6 -0
  173. package/templates/writing/scripts/metric.mjs +24 -0
  174. package/templates/writing/scripts/propose.mjs +13 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-state-machine.js","sourceRoot":"","sources":["../../../src/core/state/run-state-machine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { startMcpServer } from "./server.js";
2
+ void startMcpServer({
3
+ repoRoot: process.cwd(),
4
+ }).catch((error) => {
5
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
6
+ process.exitCode = 1;
7
+ });
8
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/mcp/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,KAAK,cAAc,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE;CACxB,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export interface RalphResearchMcpServerOptions {
3
+ repoRoot?: string;
4
+ }
5
+ export declare function createRalphResearchMcpServer(options?: RalphResearchMcpServerOptions): McpServer;
6
+ export declare function startMcpServer(options?: RalphResearchMcpServerOptions): Promise<McpServer>;
@@ -0,0 +1,97 @@
1
+ import { resolve } from "node:path";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import * as z from "zod/v4";
5
+ import { getProjectFrontier, getProjectStatus } from "../app/services/project-state-service.js";
6
+ import { RunCycleService } from "../app/services/run-cycle-service.js";
7
+ export function createRalphResearchMcpServer(options = {}) {
8
+ const defaultRepoRoot = resolve(options.repoRoot ?? process.cwd());
9
+ const server = new McpServer({
10
+ name: "ralph-research",
11
+ version: "0.1.0",
12
+ });
13
+ server.registerTool("run_research_cycle", {
14
+ description: "Run one or more research cycles using the shared ralph-research service layer.",
15
+ inputSchema: {
16
+ repoRoot: z.string().optional().describe("Repository root; defaults to the server working directory."),
17
+ manifestPath: z.string().optional().describe("Optional path to the manifest file."),
18
+ cycles: z.number().int().min(1).max(20).default(1).describe("Number of cycles to run."),
19
+ resume: z.boolean().default(false).describe("Resume the latest run if it is recoverable."),
20
+ },
21
+ }, async ({ repoRoot, manifestPath, cycles = 1, resume = false }) => {
22
+ const service = new RunCycleService();
23
+ const resolvedRepoRoot = resolve(repoRoot ?? defaultRepoRoot);
24
+ const results = [];
25
+ for (let index = 0; index < cycles; index += 1) {
26
+ const result = await service.run({
27
+ repoRoot: resolvedRepoRoot,
28
+ ...(manifestPath ? { manifestPath } : {}),
29
+ resume,
30
+ });
31
+ results.push(result);
32
+ if (result.status === "failed" || result.status === "resume_required") {
33
+ break;
34
+ }
35
+ }
36
+ return {
37
+ content: [
38
+ {
39
+ type: "text",
40
+ text: JSON.stringify({
41
+ ok: results.every((result) => result.status !== "failed" && result.status !== "resume_required"),
42
+ cycles,
43
+ results,
44
+ }, null, 2),
45
+ },
46
+ ],
47
+ };
48
+ });
49
+ server.registerTool("get_research_status", {
50
+ description: "Get the latest run, frontier summary, and pending human review items.",
51
+ inputSchema: {
52
+ repoRoot: z.string().optional().describe("Repository root; defaults to the server working directory."),
53
+ manifestPath: z.string().optional().describe("Optional path to the manifest file."),
54
+ },
55
+ }, async ({ repoRoot, manifestPath }) => {
56
+ const payload = await getProjectStatus({
57
+ repoRoot: resolve(repoRoot ?? defaultRepoRoot),
58
+ ...(manifestPath ? { manifestPath } : {}),
59
+ });
60
+ return {
61
+ content: [
62
+ {
63
+ type: "text",
64
+ text: JSON.stringify(payload, null, 2),
65
+ },
66
+ ],
67
+ };
68
+ });
69
+ server.registerTool("get_frontier", {
70
+ description: "Get the current frontier entries for the active manifest.",
71
+ inputSchema: {
72
+ repoRoot: z.string().optional().describe("Repository root; defaults to the server working directory."),
73
+ manifestPath: z.string().optional().describe("Optional path to the manifest file."),
74
+ },
75
+ }, async ({ repoRoot, manifestPath }) => {
76
+ const payload = await getProjectFrontier({
77
+ repoRoot: resolve(repoRoot ?? defaultRepoRoot),
78
+ ...(manifestPath ? { manifestPath } : {}),
79
+ });
80
+ return {
81
+ content: [
82
+ {
83
+ type: "text",
84
+ text: JSON.stringify(payload, null, 2),
85
+ },
86
+ ],
87
+ };
88
+ });
89
+ return server;
90
+ }
91
+ export async function startMcpServer(options = {}) {
92
+ const server = createRalphResearchMcpServer(options);
93
+ const transport = new StdioServerTransport();
94
+ await server.connect(transport);
95
+ return server;
96
+ }
97
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function isMissingFileError(error: unknown): error is NodeJS.ErrnoException;
@@ -0,0 +1,4 @@
1
+ export function isMissingFileError(error) {
2
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
3
+ }
4
+ //# sourceMappingURL=fs-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-errors.js","sourceRoot":"","sources":["../../src/shared/fs-errors.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,CAAC;AACzG,CAAC"}
@@ -0,0 +1,2 @@
1
+ import pino from "pino";
2
+ export declare const logger: pino.Logger<never, boolean>;
@@ -0,0 +1,5 @@
1
+ import pino from "pino";
2
+ export const logger = pino({
3
+ name: "ralph-research",
4
+ });
5
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/shared/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,gBAAgB;CACvB,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export interface TemplateCopyOptions {
2
+ force?: boolean;
3
+ }
4
+ export declare function getTemplateRoot(templateName: string): string;
5
+ export declare function copyTemplate(templateName: string, targetDir: string, options?: TemplateCopyOptions): Promise<{
6
+ templateRoot: string;
7
+ targetDir: string;
8
+ copiedFiles: string[];
9
+ }>;
@@ -0,0 +1,50 @@
1
+ import { cp, mkdir, readdir, stat } from "node:fs/promises";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const packageRoot = resolve(fileURLToPath(new URL("../../", import.meta.url)));
5
+ export function getTemplateRoot(templateName) {
6
+ return join(packageRoot, "templates", templateName);
7
+ }
8
+ export async function copyTemplate(templateName, targetDir, options = {}) {
9
+ const templateRoot = getTemplateRoot(templateName);
10
+ const resolvedTargetDir = resolve(targetDir);
11
+ const copiedFiles = await copyDirectoryContents(templateRoot, resolvedTargetDir, options);
12
+ return {
13
+ templateRoot,
14
+ targetDir: resolvedTargetDir,
15
+ copiedFiles,
16
+ };
17
+ }
18
+ async function copyDirectoryContents(sourceDir, targetDir, options, relativeDir = "") {
19
+ const sourcePath = relativeDir ? join(sourceDir, relativeDir) : sourceDir;
20
+ const entries = await readdir(sourcePath, { withFileTypes: true });
21
+ const copiedFiles = [];
22
+ for (const entry of entries) {
23
+ const entryRelativePath = relativeDir ? join(relativeDir, entry.name) : entry.name;
24
+ const sourceEntryPath = join(sourceDir, entryRelativePath);
25
+ const targetEntryPath = join(targetDir, entryRelativePath);
26
+ if (entry.isDirectory()) {
27
+ await mkdir(targetEntryPath, { recursive: true });
28
+ copiedFiles.push(...(await copyDirectoryContents(sourceDir, targetDir, options, entryRelativePath)));
29
+ continue;
30
+ }
31
+ await mkdir(dirname(targetEntryPath), { recursive: true });
32
+ const exists = await pathExists(targetEntryPath);
33
+ if (exists && !options.force) {
34
+ throw new Error(`Refusing to overwrite ${targetEntryPath}; rerun with --force to replace it`);
35
+ }
36
+ await cp(sourceEntryPath, targetEntryPath, { force: options.force ?? false });
37
+ copiedFiles.push(entryRelativePath.replaceAll("\\", "/"));
38
+ }
39
+ return copiedFiles.sort();
40
+ }
41
+ async function pathExists(path) {
42
+ try {
43
+ await stat(path);
44
+ return true;
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
50
+ //# sourceMappingURL=template-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-utils.js","sourceRoot":"","sources":["../../src/shared/template-utils.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "ralph-research",
3
+ "version": "0.1.0",
4
+ "description": "Local-first runtime for recursive research improvement.",
5
+ "type": "module",
6
+ "bin": {
7
+ "rrx": "./dist/cli/main.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "templates",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.json",
17
+ "dev": "tsx src/cli/main.ts",
18
+ "mcp": "tsx src/mcp/main.ts",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "typecheck": "tsc --noEmit -p tsconfig.json"
22
+ },
23
+ "keywords": [
24
+ "research",
25
+ "ratchet",
26
+ "cli",
27
+ "mcp"
28
+ ],
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.17.4",
32
+ "commander": "^14.0.1",
33
+ "execa": "^9.6.0",
34
+ "pino": "^10.0.0",
35
+ "yaml": "^2.8.1",
36
+ "zod": "^4.1.11"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^24.7.2",
40
+ "tsx": "^4.20.6",
41
+ "typescript": "^5.9.3",
42
+ "vitest": "^3.2.4"
43
+ }
44
+ }
@@ -0,0 +1 @@
1
+ ralph-research is important for research work. It is important because teams need a loop, and the loop should help improve drafts. The system should look at a draft, make a change, and then maybe keep it if it seems better. This is useful, but the idea is still repetitive and not very concrete.
@@ -0,0 +1,15 @@
1
+ You are comparing two versions of the same technical draft.
2
+
3
+ Instructions:
4
+ - Read both drafts closely.
5
+ - Prefer the draft that is clearer, better structured, more concrete, and more faithful to the core idea.
6
+ - Penalize repetition, vague claims, and weak linkage between claim and evidence.
7
+ - If neither draft is materially better, return `"tie"`.
8
+ - Return JSON only.
9
+
10
+ Required JSON shape:
11
+ {
12
+ "winner": "candidate" | "incumbent" | "tie",
13
+ "confidence": 0.0-1.0,
14
+ "rationale": "short explanation"
15
+ }
@@ -0,0 +1,63 @@
1
+ schemaVersion: "0.1"
2
+
3
+ project:
4
+ name: writing-demo
5
+ artifact: manuscript
6
+ baselineRef: main
7
+ workspace: git
8
+
9
+ scope:
10
+ allowedGlobs:
11
+ - "**/*.md"
12
+ maxFilesChanged: 2
13
+ maxLineDelta: 40
14
+
15
+ proposer:
16
+ type: command
17
+ command: "node scripts/propose.mjs"
18
+
19
+ experiment:
20
+ run:
21
+ command: "node scripts/experiment.mjs"
22
+ outputs:
23
+ - id: draft
24
+ path: out/draft.md
25
+
26
+ judgePacks:
27
+ - id: writing-pack
28
+ mode: pairwise
29
+ blindPairwise: true
30
+ orderRandomized: true
31
+ repeats: 5
32
+ aggregation: majority_vote
33
+ judges:
34
+ - model: your-judge-model
35
+ weight: 1
36
+ lowConfidenceThreshold: 0.75
37
+ audit:
38
+ sampleRate: 0.1
39
+ freezeAutoAcceptIfAnchorFails: true
40
+
41
+ metrics:
42
+ catalog:
43
+ - id: quality
44
+ kind: numeric
45
+ direction: maximize
46
+ extractor:
47
+ type: command
48
+ command: "node scripts/metric.mjs"
49
+ parser: plain_number
50
+
51
+ constraints: []
52
+
53
+ frontier:
54
+ strategy: single_best
55
+ primaryMetric: quality
56
+
57
+ ratchet:
58
+ type: epsilon_improve
59
+ metric: quality
60
+ epsilon: 0
61
+
62
+ storage:
63
+ root: .ralph
@@ -0,0 +1,6 @@
1
+ import { cpSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ mkdirSync(join(process.cwd(), "out"), { recursive: true });
5
+ cpSync(join(process.cwd(), "docs", "draft.md"), join(process.cwd(), "out", "draft.md"));
6
+ console.log("experiment complete");
@@ -0,0 +1,24 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ const draft = readFileSync(join(process.cwd(), "out", "draft.md"), "utf8").toLowerCase();
5
+
6
+ let score = 0;
7
+
8
+ if (draft.includes("metric")) {
9
+ score += 0.3;
10
+ }
11
+ if (draft.includes("bounded experiment")) {
12
+ score += 0.3;
13
+ }
14
+ if (draft.includes("verified to be better")) {
15
+ score += 0.2;
16
+ }
17
+ if (draft.includes("claim and the evidence")) {
18
+ score += 0.1;
19
+ }
20
+ if (!draft.includes("it is important")) {
21
+ score += 0.1;
22
+ }
23
+
24
+ console.log(score.toFixed(2));
@@ -0,0 +1,13 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ const improvedDraft = [
5
+ "ralph-research improves a draft through a measurable loop.",
6
+ "",
7
+ "The loop defines a metric, runs one bounded experiment, and keeps the result only when the revision is verified to be better.",
8
+ "",
9
+ "For writing workflows, that means clearer structure, tighter wording, and a more explicit connection between the claim and the evidence.",
10
+ ].join("\n");
11
+
12
+ writeFileSync(join(process.cwd(), "docs", "draft.md"), improvedDraft, "utf8");
13
+ console.log("proposal complete");