@interf/compiler 0.6.9 → 0.7.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.
package/README.md CHANGED
@@ -2,32 +2,55 @@
2
2
 
3
3
  Interf prepares portable context for your agents.
4
4
 
5
- Agents now run real work from folders of PDFs, exports, notes, and transcripts. They don't reliably assemble the full picture from them: missed evidence, links lost across files, or answers that sound confident but are wrong. A chart inside one PDF can be obvious to a human analyst and easy for an agent to miss.
5
+ Point an agent at a folder of files. It gets a partial picture. It picks up false hypotheses from a shallow read. Then it carries those into the work — missed evidence, links lost across files, confident answers that are wrong.
6
6
 
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.
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 a local runtime. It runs your compilation workflow on your files. Your local agent executes each stage. The output is portable context — a local folder your agent reads. If the first build misses your questions, Interf improves the workflow and builds again.
10
10
 
11
11
  ```text
12
12
  project-root/
13
13
  bristol-office-analysis/
14
- report.pdf
14
+ report.md
15
15
  notes.md
16
16
  exports/
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
+ Same files, same questions. What changes is whether the context was prepared first.
32
+
33
+ A recent public run — one market report, two questions, two agents on the same setup — produced:
34
+
35
+ <!-- PUBLIC_BENCHMARK_TABLE:START -->
36
+ | Agent | Source files | Portable context |
37
+ | --- | --- | --- |
38
+ | Codex (GPT-5.4, xhigh) | `2/2` | `2/2` |
39
+ | Claude Code (Claude Opus 4.6, max) | `0/2` | `2/2` |
40
+ <!-- PUBLIC_BENCHMARK_TABLE:END -->
41
+
42
+ 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.
43
+
44
+ That gives you a readiness signal for the work and a fair comparison on the same files.
45
+
46
+ 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.
47
+
26
48
  ## Design Choices
27
49
 
50
+ - `Local-first`: your files, your questions, and your agent stay on your machine. No cloud, no uploads.
51
+ - `File over app`: the portable context is a local folder next to the source files. Inspect it, diff it, version it.
28
52
  - `Check before build`: run `interf test --target raw` first — sometimes the source files already pass on your questions.
29
53
  - `Scored on your own questions`: every build is checked against questions you wrote from the files. If the portable context does not help, `interf test` tells you.
30
- - `File over app`: the portable context is a local folder next to the source files. Inspect it, diff it, version it.
31
54
  - `Bring your own AI`: use Claude Code, Codex, or another local agent.
32
55
  - `Explicit`: no hidden store, no hidden index. The portable context is plain files on disk.
33
56
 
@@ -51,11 +74,11 @@ Requires Node.js 20+ and a local coding agent such as Claude Code or Codex. Run
51
74
  7. Run `interf test` again to compare source files and portable context on the same questions.
52
75
  8. If the portable context does better, point your agent at `interf/<work>/`.
53
76
 
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.
77
+ `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
78
 
56
79
  ## Portable Context
57
80
 
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:
81
+ `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
82
 
60
83
  ```text
61
84
  interf/bristol-office-analysis/
@@ -73,18 +96,16 @@ The portable context is a folder you can inspect, diff, version, or hand to a di
73
96
 
74
97
  ## Workflow Packages
75
98
 
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.
99
+ 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
100
 
80
101
  ```text
81
- interf/workflows/office-analysis/
102
+ interf/workflows/interf-default/
82
103
  workflow.json # method: how to process and organize the files
83
104
  workflow.schema.json # output contract: what files and folders the output must contain
84
105
  README.md # what this compilation workflow is for, for humans and agents
85
106
  compile/
86
107
  stages/
87
- summarize/ # define your own stages here
108
+ summarize/ # stage instructions the compiler runs with your local agent
88
109
  structure/
89
110
  shape/
90
111
  use/
@@ -92,8 +113,6 @@ interf/workflows/office-analysis/
92
113
  improve/ # how Interf revises this compilation workflow if questions still fail
93
114
  ```
94
115
 
95
- Think of it as method -> output shape.
96
-
97
116
  - `workflow.json` describes the method: expected inputs, stages, and how the files should be processed.
98
117
  - `workflow.schema.json` describes the output contract: what files and folders the output must contain. Technically, this is the `context interface`, declared in `workflow.schema.json` and enforced by the compiler.
99
118
  - `compile/stages/<stage>/` is where you author one folder per stage — a small, specific phase like `summarize` or `structure`. You write the instructions; the compiler runs them with your local agent.
@@ -102,23 +121,6 @@ Think of it as method -> output shape.
102
121
 
103
122
  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
123
 
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
124
  ## Self-Improving Workflows
123
125
 
124
126
  When the first build still misses questions, Interf edits the workflow package itself and compiles again. Same files, same questions, different preparation.
@@ -145,7 +147,7 @@ Interf saves every scored run under `interf/tests/<work>/`. You can inspect what
145
147
  "name": "bristol-office-analysis",
146
148
  "path": "./bristol-office-analysis",
147
149
  "about": "Read the report and answer the saved questions.",
148
- "workflow": "interf",
150
+ "workflow": "interf-default",
149
151
  "checks": [
150
152
  { "question": "...", "answer": "..." }
151
153
  ]
@@ -154,7 +156,7 @@ Interf saves every scored run under `interf/tests/<work>/`. You can inspect what
154
156
  }
155
157
  ```
156
158
 
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.
159
+ 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
160
 
159
161
  ## Questions
160
162
 
@@ -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.1",
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": {