@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
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
|
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.
|
|
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/
|
|
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/ #
|
|
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`
|
|
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 {
|
|
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: "
|
|
218
|
-
placeholder: "
|
|
219
|
-
validate: (value) => (value.trim().length === 0 ? "
|
|
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
|
|
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.
|
|
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": {
|