@interf/compiler 0.6.9 → 0.7.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
@@ -6,7 +6,7 @@ Agents now run real work from folders of PDFs, exports, notes, and transcripts.
6
6
 
7
7
  The fix is structure: summarize the files, organize by category, link what belongs together. You tell Interf Compiler how — that's a compilation workflow.
8
8
 
9
- `Interf Compiler` is the local, open-source runtime that runs compilation workflows on your files. Your local agent executes each stage. The compiler builds portable context — a local folder your agent reads. If the first build misses your questions, Interf improves the compilation workflow and builds again.
9
+ `Interf Compiler` is the local runtime that runs compilation workflows on your files. Your local agent executes each stage. The compiler builds portable context — a local folder your agent reads. If the first build misses your questions, Interf improves the compilation workflow and builds again.
10
10
 
11
11
  ```text
12
12
  project-root/
@@ -17,12 +17,32 @@ project-root/
17
17
  interf.json # main config: works, source paths, questions, workflow choices, and defaults
18
18
  interf/
19
19
  bristol-office-analysis/ # portable context your agent starts from
20
+ workflows/
21
+ interf-default/ # built-in compilation workflow, copied here on init — inspect, edit, or fork
22
+ your-custom-workflow/ # optional: your own, via `interf create workflow`
20
23
  tests/
21
24
  bristol-office-analysis/ # saved source-files vs portable-context comparisons
22
25
  ```
23
26
 
24
27
  The project root is the control plane. Your agent starts from `interf/<work>/` when the source files are not enough.
25
28
 
29
+ ## What a Run Looks Like
30
+
31
+ A recent public run — one PDF market report, two questions, two agents on the same setup — produced:
32
+
33
+ <!-- PUBLIC_BENCHMARK_TABLE:START -->
34
+ | Agent | Source files | Portable context |
35
+ | --- | --- | --- |
36
+ | Codex (GPT-5.4, xhigh) | `2/2` | `2/2` |
37
+ | Claude Code (Claude Opus 4.6, max) | `0/2` | `2/2` |
38
+ <!-- PUBLIC_BENCHMARK_TABLE:END -->
39
+
40
+ Codex passed on the raw files; Claude Code only passed after Interf prepared the portable context. Both numbers come from `interf test`, which scores the same questions against the source files and the portable context.
41
+
42
+ That gives you a readiness signal for the work and a fair comparison on the same files.
43
+
44
+ The table is a sample, not a leaderboard. Run it on your own files. If you run more than one local agent, the same pass gives you a fair comparison between them on the same files.
45
+
26
46
  ## Design Choices
27
47
 
28
48
  - `Check before build`: run `interf test --target raw` first — sometimes the source files already pass on your questions.
@@ -51,11 +71,11 @@ Requires Node.js 20+ and a local coding agent such as Claude Code or Codex. Run
51
71
  7. Run `interf test` again to compare source files and portable context on the same questions.
52
72
  8. If the portable context does better, point your agent at `interf/<work>/`.
53
73
 
54
- By default, Interf uses the built-in `interf` compilation workflow. Create your own compilation workflow only when the built-in method is not enough for the work, or you need a different output.
74
+ `interf init` copies the built-in compilation workflow to `interf/workflows/interf-default/`. That folder is yours inspect it, edit it, or fork it into a new compilation workflow with `interf create workflow`.
55
75
 
56
76
  ## Portable Context
57
77
 
58
- `interf/<work>/` is the local folder Interf Compiler builds from your files — a context layer your agents navigate, not a replacement for your files. For the built-in `interf` workflow, it includes:
78
+ `interf/<work>/` is the local folder Interf Compiler builds from your files — a context layer your agents navigate, not a replacement for your files. For the built-in `interf-default`, it includes:
59
79
 
60
80
  ```text
61
81
  interf/bristol-office-analysis/
@@ -73,18 +93,16 @@ The portable context is a folder you can inspect, diff, version, or hand to a di
73
93
 
74
94
  ## Workflow Packages
75
95
 
76
- A compilation workflow is how you tell Interf Compiler to organize and structure your files so your agents can reliably work from them. The built-in `interf` workflow covers common cases. Create your own when you need a different method, a different output, or both.
77
-
78
- Run `interf create workflow` to draft a reusable workflow package.
96
+ A compilation workflow is how you tell Interf Compiler to organize and structure your files so your agents can reliably work from them. `interf init` copies the built-in `interf-default` into your project at `interf/workflows/interf-default/` — it is a real folder you can inspect and edit. Fork it with `interf create workflow` when you need a different method, a different output, or both.
79
97
 
80
98
  ```text
81
- interf/workflows/office-analysis/
99
+ interf/workflows/interf-default/
82
100
  workflow.json # method: how to process and organize the files
83
101
  workflow.schema.json # output contract: what files and folders the output must contain
84
102
  README.md # what this compilation workflow is for, for humans and agents
85
103
  compile/
86
104
  stages/
87
- summarize/ # define your own stages here
105
+ summarize/ # stage instructions the compiler runs with your local agent
88
106
  structure/
89
107
  shape/
90
108
  use/
@@ -102,23 +120,6 @@ Think of it as method -> output shape.
102
120
 
103
121
  A workflow package bundles a compilation workflow. Interf Compiler runs it on your files. Your local agent runs each stage. The result is a local folder your agents can read.
104
122
 
105
- ## What a Run Looks Like
106
-
107
- A recent public run — one PDF market report, two questions, two agents on the same setup — produced:
108
-
109
- <!-- PUBLIC_BENCHMARK_TABLE:START -->
110
- | Agent | Source files | Portable context |
111
- | --- | --- | --- |
112
- | Codex (GPT-5.4, xhigh) | `2/2` | `2/2` |
113
- | Claude Code (Claude Opus 4.6, max) | `0/2` | `2/2` |
114
- <!-- PUBLIC_BENCHMARK_TABLE:END -->
115
-
116
- Codex passed on the raw files; Claude Code only passed after Interf prepared the portable context. Both numbers come from `interf test`, which scores the same questions against the source files and the portable context.
117
-
118
- That gives you a readiness signal for the work and a fair comparison on the same files.
119
-
120
- The table is a sample, not a leaderboard. Run it on your own files. If you run more than one local agent, the same pass gives you a fair comparison between them on the same files.
121
-
122
123
  ## Self-Improving Workflows
123
124
 
124
125
  When the first build still misses questions, Interf edits the workflow package itself and compiles again. Same files, same questions, different preparation.
@@ -145,7 +146,7 @@ Interf saves every scored run under `interf/tests/<work>/`. You can inspect what
145
146
  "name": "bristol-office-analysis",
146
147
  "path": "./bristol-office-analysis",
147
148
  "about": "Read the report and answer the saved questions.",
148
- "workflow": "interf",
149
+ "workflow": "interf-default",
149
150
  "checks": [
150
151
  { "question": "...", "answer": "..." }
151
152
  ]
@@ -154,7 +155,7 @@ Interf saves every scored run under `interf/tests/<work>/`. You can inspect what
154
155
  }
155
156
  ```
156
157
 
157
- The `workflow` field is the key choice per work. Set it to `interf` for the built-in workflow, or to a compilation workflow you have authored. A different compilation workflow is a different method and a different output. Same files, different portable context.
158
+ The `workflow` field is the key choice per work. It points to a folder id under `interf/workflows/`. Set it to `interf-default` (the built-in default, copied locally on init) or to a compilation workflow you have authored. A different compilation workflow is a different method and a different output. Same files, different portable context.
158
159
 
159
160
  ## Questions
160
161
 
@@ -3,7 +3,8 @@ import * as p from "@clack/prompts";
3
3
  import { resolve } from "node:path";
4
4
  import { listCompiledWorkflowChoices, getCompiledWorkflow, } from "../../packages/workflow-package/workflow-definitions.js";
5
5
  import { createLocalWorkflowPackageFromTemplate } from "../../packages/workflow-package/interf-workflow-package.js";
6
- import { isWorkflowId, } from "../../packages/workflow-package/local-workflows.js";
6
+ import { rmSync } from "node:fs";
7
+ import { isWorkflowId, loadWorkflowDefinitionFromDir, } from "../../packages/workflow-package/local-workflows.js";
7
8
  import { resolveOrConfigureLocalExecutor } from "./executor-flow.js";
8
9
  import { runWorkflowAuthoringDraft } from "../../packages/workflow-authoring/workflow-authoring.js";
9
10
  import { listSourceDatasetConfigs, loadSourceFolderConfig, resolveSourceDatasetPath, } from "../../packages/project-model/source-config.js";
@@ -214,9 +215,9 @@ export async function createCompiledWorkflowWizard(sourcePath, prompts = clackWo
214
215
  matchedDataset = matchedDataset ?? findMatchingDatasetConfig(sourcePath, datasetPath);
215
216
  }
216
217
  const taskPrompt = await prompts.text({
217
- message: "What kind of work should this workflow help with?",
218
- placeholder: "Example: chart reads, board prep, or latest planned launch status",
219
- validate: (value) => (value.trim().length === 0 ? "Work focus is required" : undefined),
218
+ message: "How do you want to organize your files?",
219
+ placeholder: "Research interview transcripts. Agent produces per-interview summaries and a themes list with supporting quotes. Flow: summarize each, group by theme, collect evidence across interviews.",
220
+ validate: (value) => (value.trim().length === 0 ? "A description is required" : undefined),
220
221
  });
221
222
  if (prompts.isCancel(taskPrompt))
222
223
  return taskPrompt;
@@ -254,6 +255,26 @@ export async function createCompiledWorkflowWizard(sourcePath, prompts = clackWo
254
255
  preparePreview: true,
255
256
  });
256
257
  if (result.status === "updated") {
258
+ const draft = loadWorkflowDefinitionFromDir(result.workflowPath);
259
+ const stageList = draft?.stages?.map((stage) => stage.id).join(" → ") ?? "—";
260
+ prompts.log.info(`Draft ready at ${result.workflowPath}`);
261
+ prompts.log.info(` Name: ${draft?.label ?? label}`);
262
+ prompts.log.info(` Description: ${draft?.hint ?? hint.trim()}`);
263
+ if (draft?.purpose)
264
+ prompts.log.info(` Purpose: ${draft.purpose}`);
265
+ prompts.log.info(` Stages: ${stageList}`);
266
+ const confirmChoice = await prompts.select({
267
+ message: "Save this workflow?",
268
+ options: [
269
+ { value: "save", label: "Save", hint: "Keep the draft as your new compilation workflow" },
270
+ { value: "cancel", label: "Discard", hint: "Remove the draft folder and exit without saving" },
271
+ ],
272
+ });
273
+ if (prompts.isCancel(confirmChoice) || confirmChoice === "cancel") {
274
+ rmSync(result.workflowPath, { recursive: true, force: true });
275
+ prompts.log.info(`Discarded draft at ${result.workflowPath}`);
276
+ return null;
277
+ }
257
278
  prompts.log.info(`Saved local workflow: ${result.workflowPath}`);
258
279
  return workflowId;
259
280
  }
@@ -5,6 +5,7 @@ import { detectInterf, readInterfConfig, resolveSourceControlPath, } from "../..
5
5
  import { SOURCE_FOLDER_CONFIG_FILE, syncCompiledInterfConfigFromSourceDatasetConfig, upsertSourceDatasetConfig, } from "../../packages/project-model/source-config.js";
6
6
  import { DEFAULT_COMPILED_NAME, describeCompileLoopSelection, promptSingleCompiledConfig, } from "./source-config-wizard.js";
7
7
  import { buildCompiledWorkflowOptions, chooseCompiledWorkflow, createWorkflowWizard, } from "./create-workflow-wizard.js";
8
+ import { seedLocalDefaultWorkflow } from "../../packages/workflow-package/local-workflows.js";
8
9
  import { findBuiltCompiledPath, findSavedCompiledConfig, listSavedCompiledEntries, } from "./compiled-flow.js";
9
10
  import { readCurrentSavedTestComparison, } from "./test-flow.js";
10
11
  import { runCompileCommand } from "./compile.js";
@@ -219,7 +220,7 @@ async function chooseCompiledForWizard(options) {
219
220
  return findSavedCompiledConfig(options.sourcePath, String(selected));
220
221
  }
221
222
  async function promptCompiledSetup(options) {
222
- let workflowId = options.initial?.workflow ?? "interf";
223
+ let workflowId = options.initial?.workflow ?? "interf-default";
223
224
  let workflowLabel = buildCompiledWorkflowOptions(options.sourcePath)
224
225
  .find((option) => option.value === workflowId)?.label ?? workflowId;
225
226
  if (options.introStyle === "edit") {
@@ -258,7 +259,7 @@ async function promptCompiledSetup(options) {
258
259
  console.log(chalk.dim(` Project folder: ${options.sourcePath}`));
259
260
  console.log(chalk.dim(` Setup: ${compiledConfigWithWorkflow.name}`));
260
261
  console.log(chalk.dim(` Source folder: ${compiledConfigWithWorkflow.path}`));
261
- console.log(chalk.dim(` Workflow: ${workflowLabel}`));
262
+ console.log(chalk.dim(` Workflow: ${workflowLabel} · interf/workflows/${workflowId}/`));
262
263
  console.log(chalk.dim(` Compile mode: ${describeCompileLoopSelection({
263
264
  maxAttempts: compiledConfigWithWorkflow.max_attempts,
264
265
  maxLoops: compiledConfigWithWorkflow.max_loops,
@@ -456,13 +457,18 @@ export const initCommand = {
456
457
  };
457
458
  export async function runInitCommand() {
458
459
  p.intro(chalk.bold("Interf"));
459
- p.log.info("Interf prepares portable context for your agents from the source folder you choose. Start with the work, review the suggested questions, check the source files first, and build a local folder when the files need more structure.");
460
+ p.log.info("Interf prepares portable context for your agents.");
461
+ p.log.info("Pick a source folder, review the suggested questions, and build when the files need more structure.");
460
462
  const cwd = process.cwd();
461
463
  const detected = detectInterf(cwd);
462
464
  const sourcePath = detected ? resolveSourceControlPath(detected.path) : cwd;
463
465
  if (detected) {
464
466
  p.log.info(`Working from the project folder: ${sourcePath}`);
465
467
  }
468
+ const seeded = seedLocalDefaultWorkflow({ sourcePath });
469
+ if (!seeded.alreadyExisted) {
470
+ p.log.info(`Copied built-in compilation workflow to interf/workflows/${seeded.workflowId}/ — inspect or fork it anytime.`);
471
+ }
466
472
  const savedEntries = listSavedCompiledEntries(sourcePath);
467
473
  if (savedEntries.length === 0) {
468
474
  const compiledConfig = await promptCompiledSetup({
@@ -37,6 +37,13 @@ export declare function loadWorkflowDefinitionFromDir(dirPath: string): LocalWor
37
37
  export declare function listLocalWorkflowDefinitions(sourcePath: string): LocalWorkflowDefinition[];
38
38
  export declare function loadLocalWorkflowDefinition(sourcePath: string, id: string): LocalWorkflowDefinition | null;
39
39
  export declare function resolveWorkflowPackageSourcePath(sourcePath: string, workflowId: string): string | null;
40
+ export declare function seedLocalDefaultWorkflow(options: {
41
+ sourcePath: string;
42
+ }): {
43
+ workflowId: string;
44
+ targetPath: string;
45
+ alreadyExisted: boolean;
46
+ };
40
47
  export declare function isWorkflowId(value: string): boolean;
41
48
  export declare function patchWorkflowPackageMetadata(dirPath: string, options?: {
42
49
  id?: string;
@@ -131,16 +131,33 @@ export function loadLocalWorkflowDefinition(sourcePath, id) {
131
131
  return loadWorkflowDefinitionFromDir(workflowDefinitionPath(sourcePath, id));
132
132
  }
133
133
  export function resolveWorkflowPackageSourcePath(sourcePath, workflowId) {
134
- const builtinPath = builtinWorkflowRootPath(workflowId);
135
- if (workflowId === "interf" && existsSync(join(builtinPath, "workflow.json")))
136
- return builtinPath;
137
134
  const localPath = workflowDefinitionPath(sourcePath, workflowId);
138
135
  if (existsSync(join(localPath, "workflow.json")))
139
136
  return localPath;
137
+ const builtinPath = builtinWorkflowRootPath(workflowId);
140
138
  if (existsSync(join(builtinPath, "workflow.json")))
141
139
  return builtinPath;
140
+ if (workflowId === "interf-default") {
141
+ const builtinInterfPath = builtinWorkflowRootPath("interf");
142
+ if (existsSync(join(builtinInterfPath, "workflow.json")))
143
+ return builtinInterfPath;
144
+ }
142
145
  return null;
143
146
  }
147
+ export function seedLocalDefaultWorkflow(options) {
148
+ const workflowId = "interf-default";
149
+ const targetPath = workflowDefinitionPath(options.sourcePath, workflowId);
150
+ if (existsSync(join(targetPath, "workflow.json"))) {
151
+ return { workflowId, targetPath, alreadyExisted: true };
152
+ }
153
+ const builtinInterfPath = builtinWorkflowRootPath("interf");
154
+ if (!existsSync(join(builtinInterfPath, "workflow.json"))) {
155
+ throw new Error(`Built-in "interf" workflow not found at ${builtinInterfPath}.`);
156
+ }
157
+ copyWorkflowPackageDirectory(builtinInterfPath, targetPath);
158
+ patchWorkflowPackageMetadata(targetPath, { id: workflowId });
159
+ return { workflowId, targetPath, alreadyExisted: false };
160
+ }
144
161
  export function isWorkflowId(value) {
145
162
  return WorkflowIdPattern.test(value);
146
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interf/compiler",
3
- "version": "0.6.9",
3
+ "version": "0.7.0",
4
4
  "description": "Local, open-source context compiler for agent work. Build portable context from your files with a compilation workflow you define. Check on your own questions.",
5
5
  "type": "module",
6
6
  "bin": {