@companion-ai/feynman 0.2.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/.env.example +8 -0
- package/.feynman/SYSTEM.md +62 -0
- package/.feynman/agents/researcher.md +63 -0
- package/.feynman/agents/reviewer.md +84 -0
- package/.feynman/agents/verifier.md +38 -0
- package/.feynman/agents/writer.md +51 -0
- package/.feynman/settings.json +20 -0
- package/.feynman/themes/feynman.json +85 -0
- package/AGENTS.md +53 -0
- package/README.md +99 -0
- package/bin/feynman.js +2 -0
- package/dist/bootstrap/sync.js +98 -0
- package/dist/cli.js +297 -0
- package/dist/config/commands.js +71 -0
- package/dist/config/feynman-config.js +42 -0
- package/dist/config/paths.js +32 -0
- package/dist/feynman-prompt.js +63 -0
- package/dist/index.js +5 -0
- package/dist/model/catalog.js +238 -0
- package/dist/model/commands.js +165 -0
- package/dist/pi/launch.js +31 -0
- package/dist/pi/runtime.js +70 -0
- package/dist/pi/settings.js +101 -0
- package/dist/pi/web-access.js +74 -0
- package/dist/search/commands.js +12 -0
- package/dist/setup/doctor.js +126 -0
- package/dist/setup/preview.js +20 -0
- package/dist/setup/prompts.js +29 -0
- package/dist/setup/setup.js +119 -0
- package/dist/system/executables.js +38 -0
- package/dist/system/promise-polyfill.js +12 -0
- package/dist/ui/terminal.js +53 -0
- package/dist/web-search.js +1 -0
- package/extensions/research-tools/alpha.ts +212 -0
- package/extensions/research-tools/header.ts +379 -0
- package/extensions/research-tools/help.ts +93 -0
- package/extensions/research-tools/preview.ts +233 -0
- package/extensions/research-tools/project.ts +116 -0
- package/extensions/research-tools/session-search.ts +223 -0
- package/extensions/research-tools/shared.ts +46 -0
- package/extensions/research-tools.ts +25 -0
- package/metadata/commands.d.mts +46 -0
- package/metadata/commands.mjs +133 -0
- package/package.json +71 -0
- package/prompts/audit.md +15 -0
- package/prompts/autoresearch.md +63 -0
- package/prompts/compare.md +16 -0
- package/prompts/deepresearch.md +167 -0
- package/prompts/delegate.md +21 -0
- package/prompts/draft.md +16 -0
- package/prompts/jobs.md +16 -0
- package/prompts/lit.md +16 -0
- package/prompts/log.md +14 -0
- package/prompts/replicate.md +22 -0
- package/prompts/review.md +15 -0
- package/prompts/watch.md +14 -0
- package/scripts/patch-embedded-pi.mjs +319 -0
- package/skills/agentcomputer/SKILL.md +108 -0
- package/skills/agentcomputer/references/acp-flow.md +23 -0
- package/skills/agentcomputer/references/cli-cheatsheet.md +68 -0
- package/skills/autoresearch/SKILL.md +12 -0
- package/skills/deep-research/SKILL.md +12 -0
- package/skills/docker/SKILL.md +84 -0
- package/skills/jobs/SKILL.md +10 -0
- package/skills/literature-review/SKILL.md +12 -0
- package/skills/paper-code-audit/SKILL.md +12 -0
- package/skills/paper-writing/SKILL.md +12 -0
- package/skills/peer-review/SKILL.md +12 -0
- package/skills/replication/SKILL.md +14 -0
- package/skills/session-log/SKILL.md +10 -0
- package/skills/source-comparison/SKILL.md +12 -0
- package/skills/watch/SKILL.md +12 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const appRoot = resolve(here, "..");
|
|
8
|
+
const piPackageRoot = resolve(appRoot, "node_modules", "@mariozechner", "pi-coding-agent");
|
|
9
|
+
const packageJsonPath = resolve(piPackageRoot, "package.json");
|
|
10
|
+
const cliPath = resolve(piPackageRoot, "dist", "cli.js");
|
|
11
|
+
const bunCliPath = resolve(piPackageRoot, "dist", "bun", "cli.js");
|
|
12
|
+
const interactiveModePath = resolve(piPackageRoot, "dist", "modes", "interactive", "interactive-mode.js");
|
|
13
|
+
const interactiveThemePath = resolve(piPackageRoot, "dist", "modes", "interactive", "theme", "theme.js");
|
|
14
|
+
const piTuiRoot = resolve(appRoot, "node_modules", "@mariozechner", "pi-tui");
|
|
15
|
+
const editorPath = resolve(piTuiRoot, "dist", "components", "editor.js");
|
|
16
|
+
const workspaceRoot = resolve(appRoot, ".feynman", "npm", "node_modules");
|
|
17
|
+
const webAccessPath = resolve(workspaceRoot, "pi-web-access", "index.ts");
|
|
18
|
+
const sessionSearchIndexerPath = resolve(
|
|
19
|
+
workspaceRoot,
|
|
20
|
+
"@kaiserlich-dev",
|
|
21
|
+
"pi-session-search",
|
|
22
|
+
"extensions",
|
|
23
|
+
"indexer.ts",
|
|
24
|
+
);
|
|
25
|
+
const piMemoryPath = resolve(workspaceRoot, "@samfp", "pi-memory", "src", "index.ts");
|
|
26
|
+
const settingsPath = resolve(appRoot, ".feynman", "settings.json");
|
|
27
|
+
const workspaceDir = resolve(appRoot, ".feynman", "npm");
|
|
28
|
+
const workspacePackageJsonPath = resolve(workspaceDir, "package.json");
|
|
29
|
+
|
|
30
|
+
function ensurePackageWorkspace() {
|
|
31
|
+
if (!existsSync(settingsPath)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
36
|
+
const packageSpecs = Array.isArray(settings.packages)
|
|
37
|
+
? settings.packages
|
|
38
|
+
.filter((value) => typeof value === "string" && value.startsWith("npm:"))
|
|
39
|
+
.map((value) => value.slice(4))
|
|
40
|
+
: [];
|
|
41
|
+
|
|
42
|
+
if (packageSpecs.length === 0) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
mkdirSync(workspaceDir, { recursive: true });
|
|
47
|
+
|
|
48
|
+
writeFileSync(
|
|
49
|
+
workspacePackageJsonPath,
|
|
50
|
+
JSON.stringify(
|
|
51
|
+
{
|
|
52
|
+
name: "pi-extensions",
|
|
53
|
+
private: true,
|
|
54
|
+
dependencies: Object.fromEntries(packageSpecs.map((spec) => [spec, "latest"])),
|
|
55
|
+
},
|
|
56
|
+
null,
|
|
57
|
+
2,
|
|
58
|
+
) + "\n",
|
|
59
|
+
"utf8",
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const npmExec = process.env.npm_execpath;
|
|
63
|
+
const install = npmExec
|
|
64
|
+
? spawnSync(process.execPath, [npmExec, "install", "--prefix", workspaceDir, ...packageSpecs], {
|
|
65
|
+
stdio: "inherit",
|
|
66
|
+
})
|
|
67
|
+
: spawnSync("npm", ["install", "--prefix", workspaceDir, ...packageSpecs], {
|
|
68
|
+
stdio: "inherit",
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (install.status !== 0) {
|
|
72
|
+
console.warn("[feynman] warning: failed to preinstall default Pi packages into .feynman/npm");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
ensurePackageWorkspace();
|
|
77
|
+
|
|
78
|
+
if (existsSync(packageJsonPath)) {
|
|
79
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
80
|
+
if (pkg.piConfig?.name !== "feynman" || pkg.piConfig?.configDir !== ".feynman") {
|
|
81
|
+
pkg.piConfig = {
|
|
82
|
+
...(pkg.piConfig || {}),
|
|
83
|
+
name: "feynman",
|
|
84
|
+
configDir: ".feynman",
|
|
85
|
+
};
|
|
86
|
+
writeFileSync(packageJsonPath, JSON.stringify(pkg, null, "\t") + "\n", "utf8");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for (const entryPath of [cliPath, bunCliPath]) {
|
|
91
|
+
if (!existsSync(entryPath)) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const cliSource = readFileSync(entryPath, "utf8");
|
|
96
|
+
if (cliSource.includes('process.title = "pi";')) {
|
|
97
|
+
writeFileSync(entryPath, cliSource.replace('process.title = "pi";', 'process.title = "feynman";'), "utf8");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (existsSync(interactiveModePath)) {
|
|
102
|
+
const interactiveModeSource = readFileSync(interactiveModePath, "utf8");
|
|
103
|
+
if (interactiveModeSource.includes("`π - ${sessionName} - ${cwdBasename}`")) {
|
|
104
|
+
writeFileSync(
|
|
105
|
+
interactiveModePath,
|
|
106
|
+
interactiveModeSource
|
|
107
|
+
.replace("`π - ${sessionName} - ${cwdBasename}`", "`feynman - ${sessionName} - ${cwdBasename}`")
|
|
108
|
+
.replace("`π - ${cwdBasename}`", "`feynman - ${cwdBasename}`"),
|
|
109
|
+
"utf8",
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (existsSync(interactiveThemePath)) {
|
|
115
|
+
let themeSource = readFileSync(interactiveThemePath, "utf8");
|
|
116
|
+
const desiredGetEditorTheme = [
|
|
117
|
+
"export function getEditorTheme() {",
|
|
118
|
+
" return {",
|
|
119
|
+
' borderColor: (text) => " ".repeat(text.length),',
|
|
120
|
+
' bgColor: (text) => theme.bg("userMessageBg", text),',
|
|
121
|
+
' placeholderText: "Type your message or /help for commands",',
|
|
122
|
+
' placeholder: (text) => theme.fg("dim", text),',
|
|
123
|
+
" selectList: getSelectListTheme(),",
|
|
124
|
+
" };",
|
|
125
|
+
"}",
|
|
126
|
+
].join("\n");
|
|
127
|
+
themeSource = themeSource.replace(
|
|
128
|
+
/export function getEditorTheme\(\) \{[\s\S]*?\n\}\nexport function getSettingsListTheme\(\) \{/m,
|
|
129
|
+
`${desiredGetEditorTheme}\nexport function getSettingsListTheme() {`,
|
|
130
|
+
);
|
|
131
|
+
writeFileSync(interactiveThemePath, themeSource, "utf8");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (existsSync(editorPath)) {
|
|
135
|
+
let editorSource = readFileSync(editorPath, "utf8");
|
|
136
|
+
const importOriginal =
|
|
137
|
+
'import { getSegmenter, isPunctuationChar, isWhitespaceChar, truncateToWidth, visibleWidth } from "../utils.js";';
|
|
138
|
+
const importReplacement =
|
|
139
|
+
'import { applyBackgroundToLine, getSegmenter, isPunctuationChar, isWhitespaceChar, truncateToWidth, visibleWidth } from "../utils.js";';
|
|
140
|
+
if (editorSource.includes(importOriginal)) {
|
|
141
|
+
editorSource = editorSource.replace(importOriginal, importReplacement);
|
|
142
|
+
}
|
|
143
|
+
const desiredRender = [
|
|
144
|
+
" render(width) {",
|
|
145
|
+
" const maxPadding = Math.max(0, Math.floor((width - 1) / 2));",
|
|
146
|
+
" const paddingX = Math.min(this.paddingX, maxPadding);",
|
|
147
|
+
" const contentWidth = Math.max(1, width - paddingX * 2);",
|
|
148
|
+
" // Layout width: with padding the cursor can overflow into it,",
|
|
149
|
+
" // without padding we reserve 1 column for the cursor.",
|
|
150
|
+
" const layoutWidth = Math.max(1, contentWidth - (paddingX ? 0 : 1));",
|
|
151
|
+
" // Store for cursor navigation (must match wrapping width)",
|
|
152
|
+
" this.lastWidth = layoutWidth;",
|
|
153
|
+
' const horizontal = this.borderColor("─");',
|
|
154
|
+
" const bgColor = this.theme.bgColor;",
|
|
155
|
+
" // Layout the text",
|
|
156
|
+
" const layoutLines = this.layoutText(layoutWidth);",
|
|
157
|
+
" // Calculate max visible lines: 30% of terminal height, minimum 5 lines",
|
|
158
|
+
" const terminalRows = this.tui.terminal.rows;",
|
|
159
|
+
" const maxVisibleLines = Math.max(5, Math.floor(terminalRows * 0.3));",
|
|
160
|
+
" // Find the cursor line index in layoutLines",
|
|
161
|
+
" let cursorLineIndex = layoutLines.findIndex((line) => line.hasCursor);",
|
|
162
|
+
" if (cursorLineIndex === -1)",
|
|
163
|
+
" cursorLineIndex = 0;",
|
|
164
|
+
" // Adjust scroll offset to keep cursor visible",
|
|
165
|
+
" if (cursorLineIndex < this.scrollOffset) {",
|
|
166
|
+
" this.scrollOffset = cursorLineIndex;",
|
|
167
|
+
" }",
|
|
168
|
+
" else if (cursorLineIndex >= this.scrollOffset + maxVisibleLines) {",
|
|
169
|
+
" this.scrollOffset = cursorLineIndex - maxVisibleLines + 1;",
|
|
170
|
+
" }",
|
|
171
|
+
" // Clamp scroll offset to valid range",
|
|
172
|
+
" const maxScrollOffset = Math.max(0, layoutLines.length - maxVisibleLines);",
|
|
173
|
+
" this.scrollOffset = Math.max(0, Math.min(this.scrollOffset, maxScrollOffset));",
|
|
174
|
+
" // Get visible lines slice",
|
|
175
|
+
" const visibleLines = layoutLines.slice(this.scrollOffset, this.scrollOffset + maxVisibleLines);",
|
|
176
|
+
" const result = [];",
|
|
177
|
+
' const leftPadding = " ".repeat(paddingX);',
|
|
178
|
+
" const rightPadding = leftPadding;",
|
|
179
|
+
" const renderBorderLine = (indicator) => {",
|
|
180
|
+
" const remaining = width - visibleWidth(indicator);",
|
|
181
|
+
" if (remaining >= 0) {",
|
|
182
|
+
' return this.borderColor(indicator + "─".repeat(remaining));',
|
|
183
|
+
" }",
|
|
184
|
+
" return this.borderColor(truncateToWidth(indicator, width));",
|
|
185
|
+
" };",
|
|
186
|
+
" // Render top padding row. When background fill is active, mimic the user-message block",
|
|
187
|
+
" // instead of the stock editor chrome.",
|
|
188
|
+
" if (bgColor) {",
|
|
189
|
+
" if (this.scrollOffset > 0) {",
|
|
190
|
+
" const indicator = ` ↑ ${this.scrollOffset} more`;",
|
|
191
|
+
" result.push(applyBackgroundToLine(indicator, width, bgColor));",
|
|
192
|
+
" }",
|
|
193
|
+
" else {",
|
|
194
|
+
' result.push(applyBackgroundToLine("", width, bgColor));',
|
|
195
|
+
" }",
|
|
196
|
+
" }",
|
|
197
|
+
" else if (this.scrollOffset > 0) {",
|
|
198
|
+
" const indicator = `─── ↑ ${this.scrollOffset} more `;",
|
|
199
|
+
" result.push(renderBorderLine(indicator));",
|
|
200
|
+
" }",
|
|
201
|
+
" else {",
|
|
202
|
+
" result.push(horizontal.repeat(width));",
|
|
203
|
+
" }",
|
|
204
|
+
" // Render each visible layout line",
|
|
205
|
+
" // Emit hardware cursor marker only when focused and not showing autocomplete",
|
|
206
|
+
" const emitCursorMarker = this.focused && !this.autocompleteState;",
|
|
207
|
+
" const showPlaceholder = this.state.lines.length === 1 &&",
|
|
208
|
+
' this.state.lines[0] === "" &&',
|
|
209
|
+
' typeof this.theme.placeholderText === "string" &&',
|
|
210
|
+
" this.theme.placeholderText.length > 0;",
|
|
211
|
+
" for (let visibleIndex = 0; visibleIndex < visibleLines.length; visibleIndex++) {",
|
|
212
|
+
" const layoutLine = visibleLines[visibleIndex];",
|
|
213
|
+
" const isFirstLayoutLine = this.scrollOffset + visibleIndex === 0;",
|
|
214
|
+
" let displayText = layoutLine.text;",
|
|
215
|
+
" let lineVisibleWidth = visibleWidth(layoutLine.text);",
|
|
216
|
+
" const isPlaceholderLine = showPlaceholder && isFirstLayoutLine;",
|
|
217
|
+
" if (isPlaceholderLine) {",
|
|
218
|
+
" const marker = emitCursorMarker ? CURSOR_MARKER : \"\";",
|
|
219
|
+
" const rawPlaceholder = this.theme.placeholderText;",
|
|
220
|
+
' const styledPlaceholder = typeof this.theme.placeholder === "function"',
|
|
221
|
+
" ? this.theme.placeholder(rawPlaceholder)",
|
|
222
|
+
" : rawPlaceholder;",
|
|
223
|
+
" displayText = marker + styledPlaceholder;",
|
|
224
|
+
" lineVisibleWidth = visibleWidth(rawPlaceholder);",
|
|
225
|
+
" }",
|
|
226
|
+
" else if (layoutLine.hasCursor && layoutLine.cursorPos !== undefined) {",
|
|
227
|
+
' const marker = emitCursorMarker ? CURSOR_MARKER : "";',
|
|
228
|
+
" const before = displayText.slice(0, layoutLine.cursorPos);",
|
|
229
|
+
" const after = displayText.slice(layoutLine.cursorPos);",
|
|
230
|
+
" displayText = before + marker + after;",
|
|
231
|
+
" }",
|
|
232
|
+
" // Calculate padding based on actual visible width",
|
|
233
|
+
' const padding = " ".repeat(Math.max(0, contentWidth - lineVisibleWidth));',
|
|
234
|
+
" const renderedLine = `${leftPadding}${displayText}${padding}${rightPadding}`;",
|
|
235
|
+
" result.push(bgColor ? applyBackgroundToLine(renderedLine, width, bgColor) : renderedLine);",
|
|
236
|
+
" }",
|
|
237
|
+
" // Render bottom padding row. When background fill is active, mimic the user-message block",
|
|
238
|
+
" // instead of the stock editor chrome.",
|
|
239
|
+
" const linesBelow = layoutLines.length - (this.scrollOffset + visibleLines.length);",
|
|
240
|
+
" if (bgColor) {",
|
|
241
|
+
" if (linesBelow > 0) {",
|
|
242
|
+
" const indicator = ` ↓ ${linesBelow} more`;",
|
|
243
|
+
" result.push(applyBackgroundToLine(indicator, width, bgColor));",
|
|
244
|
+
" }",
|
|
245
|
+
" else {",
|
|
246
|
+
' result.push(applyBackgroundToLine("", width, bgColor));',
|
|
247
|
+
" }",
|
|
248
|
+
" }",
|
|
249
|
+
" else if (linesBelow > 0) {",
|
|
250
|
+
" const indicator = `─── ↓ ${linesBelow} more `;",
|
|
251
|
+
" const bottomLine = renderBorderLine(indicator);",
|
|
252
|
+
" result.push(bottomLine);",
|
|
253
|
+
" }",
|
|
254
|
+
" else {",
|
|
255
|
+
" const bottomLine = horizontal.repeat(width);",
|
|
256
|
+
" result.push(bottomLine);",
|
|
257
|
+
" }",
|
|
258
|
+
" // Add autocomplete list if active",
|
|
259
|
+
" if (this.autocompleteState && this.autocompleteList) {",
|
|
260
|
+
" const autocompleteResult = this.autocompleteList.render(contentWidth);",
|
|
261
|
+
" for (const line of autocompleteResult) {",
|
|
262
|
+
" const lineWidth = visibleWidth(line);",
|
|
263
|
+
' const linePadding = " ".repeat(Math.max(0, contentWidth - lineWidth));',
|
|
264
|
+
" const autocompleteLine = `${leftPadding}${line}${linePadding}${rightPadding}`;",
|
|
265
|
+
" result.push(bgColor ? applyBackgroundToLine(autocompleteLine, width, bgColor) : autocompleteLine);",
|
|
266
|
+
" }",
|
|
267
|
+
" }",
|
|
268
|
+
" return result;",
|
|
269
|
+
" }",
|
|
270
|
+
].join("\n");
|
|
271
|
+
editorSource = editorSource.replace(
|
|
272
|
+
/ render\(width\) \{[\s\S]*?\n handleInput\(data\) \{/m,
|
|
273
|
+
`${desiredRender}\n handleInput(data) {`,
|
|
274
|
+
);
|
|
275
|
+
writeFileSync(editorPath, editorSource, "utf8");
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (existsSync(webAccessPath)) {
|
|
279
|
+
const source = readFileSync(webAccessPath, "utf8");
|
|
280
|
+
if (source.includes('pi.registerCommand("search",')) {
|
|
281
|
+
writeFileSync(
|
|
282
|
+
webAccessPath,
|
|
283
|
+
source.replace('pi.registerCommand("search",', 'pi.registerCommand("web-results",'),
|
|
284
|
+
"utf8",
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (existsSync(sessionSearchIndexerPath)) {
|
|
290
|
+
const source = readFileSync(sessionSearchIndexerPath, "utf8");
|
|
291
|
+
const original = 'const sessionsDir = path.join(os.homedir(), ".pi", "agent", "sessions");';
|
|
292
|
+
const replacement =
|
|
293
|
+
'const sessionsDir = process.env.FEYNMAN_SESSION_DIR ?? process.env.PI_SESSION_DIR ?? path.join(os.homedir(), ".pi", "agent", "sessions");';
|
|
294
|
+
if (source.includes(original)) {
|
|
295
|
+
writeFileSync(sessionSearchIndexerPath, source.replace(original, replacement), "utf8");
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (existsSync(piMemoryPath)) {
|
|
300
|
+
let source = readFileSync(piMemoryPath, "utf8");
|
|
301
|
+
const memoryOriginal = 'const MEMORY_DIR = join(homedir(), ".pi", "memory");';
|
|
302
|
+
const memoryReplacement =
|
|
303
|
+
'const MEMORY_DIR = process.env.FEYNMAN_MEMORY_DIR ?? process.env.PI_MEMORY_DIR ?? join(homedir(), ".pi", "memory");';
|
|
304
|
+
if (source.includes(memoryOriginal)) {
|
|
305
|
+
source = source.replace(memoryOriginal, memoryReplacement);
|
|
306
|
+
}
|
|
307
|
+
const execOriginal = 'const result = await pi.exec("pi", ["-p", prompt, "--print"], {';
|
|
308
|
+
const execReplacement = [
|
|
309
|
+
'const execBinary = process.env.FEYNMAN_NODE_EXECUTABLE || process.env.FEYNMAN_EXECUTABLE || "pi";',
|
|
310
|
+
' const execArgs = process.env.FEYNMAN_BIN_PATH',
|
|
311
|
+
' ? [process.env.FEYNMAN_BIN_PATH, "--prompt", prompt]',
|
|
312
|
+
' : ["-p", prompt, "--print"];',
|
|
313
|
+
' const result = await pi.exec(execBinary, execArgs, {',
|
|
314
|
+
].join("\n");
|
|
315
|
+
if (source.includes(execOriginal)) {
|
|
316
|
+
source = source.replace(execOriginal, execReplacement);
|
|
317
|
+
}
|
|
318
|
+
writeFileSync(piMemoryPath, source, "utf8");
|
|
319
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentcomputer
|
|
3
|
+
description: Delegate research tasks to remote Agent Computer machines for cloud execution. Manages machine discovery, remote agent sessions, task delegation, progress monitoring, result retrieval, and ACP bridging via the aicomputer CLI.
|
|
4
|
+
allowed-tools: Bash(npm:*), Bash(npx aicomputer@latest:*), Bash(aicomputer:*), Bash(computer:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Agent Computer
|
|
8
|
+
|
|
9
|
+
Use Agent Computer to run Feynman research workflows on remote cloud machines when local compute is insufficient or when tasks should run unattended.
|
|
10
|
+
|
|
11
|
+
## When to use
|
|
12
|
+
|
|
13
|
+
- A research task needs GPU, large memory, or long-running compute
|
|
14
|
+
- `/autoresearch` or `/deepresearch` should run unattended in the cloud
|
|
15
|
+
- The user explicitly asks to delegate work to a remote machine
|
|
16
|
+
- An experiment loop would take hours and should not block the local session
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
The `aicomputer` CLI must be installed and authenticated:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
if command -v computer >/dev/null 2>&1; then
|
|
24
|
+
COMPUTER=computer
|
|
25
|
+
elif command -v aicomputer >/dev/null 2>&1; then
|
|
26
|
+
COMPUTER=aicomputer
|
|
27
|
+
else
|
|
28
|
+
npm install -g aicomputer
|
|
29
|
+
COMPUTER=computer
|
|
30
|
+
fi
|
|
31
|
+
$COMPUTER whoami || $COMPUTER login
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Fleet control
|
|
35
|
+
|
|
36
|
+
### Discover machines and agents
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
$COMPUTER ls --json
|
|
40
|
+
$COMPUTER agent agents <machine> --json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Sessions
|
|
44
|
+
|
|
45
|
+
Create, reuse, and manage named sessions on a machine:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
$COMPUTER agent sessions new <machine> --agent claude --name research --json
|
|
49
|
+
$COMPUTER agent sessions list <machine> --json
|
|
50
|
+
$COMPUTER agent status <machine> --session <session_id> --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Prompting and monitoring
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
$COMPUTER agent prompt <machine> "<task>" --agent claude --name research
|
|
57
|
+
$COMPUTER agent watch <machine> --session <session_id>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Stopping and cleanup
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
$COMPUTER agent cancel <machine> --session <session_id> --json
|
|
64
|
+
$COMPUTER agent interrupt <machine> --session <session_id> --json
|
|
65
|
+
$COMPUTER agent close <machine> --session <session_id>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Research delegation workflow
|
|
69
|
+
|
|
70
|
+
1. Pick a machine: `$COMPUTER ls --json`
|
|
71
|
+
2. Create a session: `$COMPUTER agent sessions new <machine> --agent claude --name research --json`
|
|
72
|
+
3. Send a self-contained research prompt:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
$COMPUTER agent prompt <machine> \
|
|
76
|
+
"Run a deep research workflow on <topic>. Write all outputs to /workspace/outputs/. When done, write a summary to /workspace/outputs/summary.md." \
|
|
77
|
+
--agent claude --name research
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
4. Monitor: `$COMPUTER agent watch <machine> --session <session_id>`
|
|
81
|
+
5. Retrieve: `$COMPUTER agent prompt <machine> "cat /workspace/outputs/summary.md" --session <session_id>`
|
|
82
|
+
6. Clean up: `$COMPUTER agent close <machine> --session <session_id>`
|
|
83
|
+
|
|
84
|
+
## ACP bridge
|
|
85
|
+
|
|
86
|
+
Expose a remote machine agent as a local ACP-compatible stdio process:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
$COMPUTER acp serve <machine> --agent claude --name research
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This lets local ACP clients (including Feynman's subagents) talk to a remote agent as if it were local. Keep the bridge process running; reconnect by restarting the command with the same session name.
|
|
93
|
+
|
|
94
|
+
## Session naming
|
|
95
|
+
|
|
96
|
+
Use short stable names that match the task:
|
|
97
|
+
|
|
98
|
+
- `research` — general research delegation
|
|
99
|
+
- `experiment` — autoresearch loops
|
|
100
|
+
- `review` — verification passes
|
|
101
|
+
- `literature` — literature sweeps
|
|
102
|
+
|
|
103
|
+
Reuse the same name when continuing the same line of work.
|
|
104
|
+
|
|
105
|
+
## References
|
|
106
|
+
|
|
107
|
+
- [CLI cheatsheet](references/cli-cheatsheet.md) — full command reference
|
|
108
|
+
- [ACP flow](references/acp-flow.md) — protocol details for the ACP bridge
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# ACP Flow
|
|
2
|
+
|
|
3
|
+
The `computer acp serve` bridge makes a remote machine agent look like a local ACP server over stdio.
|
|
4
|
+
|
|
5
|
+
## Basic shape
|
|
6
|
+
|
|
7
|
+
1. The local client starts `computer acp serve <machine> --agent <agent> --name <session>`.
|
|
8
|
+
2. The bridge handles ACP initialization on stdin/stdout.
|
|
9
|
+
3. The bridge maps ACP session operations onto Agent Computer session APIs.
|
|
10
|
+
4. Remote session updates are streamed back as ACP `session/update` notifications.
|
|
11
|
+
|
|
12
|
+
## Good commands
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
computer acp serve my-box --agent claude --name research
|
|
16
|
+
computer acp serve gpu-worker --agent claude --name experiment
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Recommended client behavior
|
|
20
|
+
|
|
21
|
+
- Reuse a stable session name when reconnecting.
|
|
22
|
+
- Treat the bridge as the single local command for remote-agent interaction.
|
|
23
|
+
- Use the normal `computer agent ...` commands outside ACP when you need manual inspection or cleanup.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# CLI Cheatsheet
|
|
2
|
+
|
|
3
|
+
## Authentication
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
computer whoami
|
|
7
|
+
computer login
|
|
8
|
+
computer claude-login # install Claude credentials on a machine
|
|
9
|
+
computer codex-login # install Codex credentials on a machine
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Machine discovery
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
computer ls --json
|
|
16
|
+
computer fleet status --json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Agent discovery
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
computer agent agents <machine> --json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Sessions
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
computer agent sessions list <machine> --json
|
|
29
|
+
computer agent sessions new <machine> --agent claude --name research --json
|
|
30
|
+
computer agent status <machine> --session <session_id> --json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Prompting
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
computer agent prompt <machine> "run the experiment" --agent claude --name research
|
|
37
|
+
computer agent prompt <machine> "continue" --session <session_id>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Streaming and control
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
computer agent watch <machine> --session <session_id>
|
|
44
|
+
computer agent cancel <machine> --session <session_id> --json
|
|
45
|
+
computer agent interrupt <machine> --session <session_id> --json
|
|
46
|
+
computer agent close <machine> --session <session_id>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## ACP bridge
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
computer acp serve <machine> --agent claude --name research
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Machine lifecycle
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
computer create my-box
|
|
59
|
+
computer open my-box
|
|
60
|
+
computer open my-box --terminal
|
|
61
|
+
computer ssh my-box
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Good defaults
|
|
65
|
+
|
|
66
|
+
- Prefer machine handles over machine ids when both are available.
|
|
67
|
+
- Prefer `--name` for human-meaningful persistent sessions.
|
|
68
|
+
- Prefer `--json` when another program or agent needs to read the result.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: autoresearch
|
|
3
|
+
description: Autonomous experiment loop that tries ideas, measures results, keeps what works, and discards what doesn't. Use when the user asks to optimize a metric, run an experiment loop, improve performance iteratively, or automate benchmarking.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Autoresearch
|
|
7
|
+
|
|
8
|
+
Run the `/autoresearch` workflow. Read the prompt template at `prompts/autoresearch.md` for the full procedure.
|
|
9
|
+
|
|
10
|
+
Tools used: `init_experiment`, `run_experiment`, `log_experiment` (from pi-autoresearch)
|
|
11
|
+
|
|
12
|
+
Session files: `autoresearch.md`, `autoresearch.sh`, `autoresearch.jsonl`
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deep-research
|
|
3
|
+
description: Run a thorough, source-heavy investigation on any topic. Use when the user asks for deep research, a comprehensive analysis, an in-depth report, or a multi-source investigation. Produces a cited research brief with provenance tracking.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deep Research
|
|
7
|
+
|
|
8
|
+
Run the `/deepresearch` workflow. Read the prompt template at `prompts/deepresearch.md` for the full procedure.
|
|
9
|
+
|
|
10
|
+
Agents used: `researcher`, `verifier`, `reviewer`
|
|
11
|
+
|
|
12
|
+
Output: cited brief in `outputs/` with `.provenance.md` sidecar.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docker
|
|
3
|
+
description: Execute research code inside isolated Docker containers for safe replication, experiments, and benchmarks. Use when the user selects Docker as the execution environment or asks to run code safely, in isolation, or in a sandbox.
|
|
4
|
+
allowed-tools: Bash(docker:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Docker Sandbox
|
|
8
|
+
|
|
9
|
+
Run research code inside Docker containers while Feynman stays on the host. The container gets the project files, runs the commands, and results sync back.
|
|
10
|
+
|
|
11
|
+
## When to use
|
|
12
|
+
|
|
13
|
+
- User selects "Docker Sandbox" as the execution environment in `/replicate` or `/autoresearch`
|
|
14
|
+
- Running untrusted code from a paper's repository
|
|
15
|
+
- Experiments that install packages or modify system state
|
|
16
|
+
- Any time the user asks to run something "safely" or "isolated"
|
|
17
|
+
|
|
18
|
+
## How it works
|
|
19
|
+
|
|
20
|
+
1. Build or pull an appropriate base image for the research code
|
|
21
|
+
2. Mount the project directory into the container
|
|
22
|
+
3. Run experiment commands inside the container
|
|
23
|
+
4. Results write back to the mounted directory
|
|
24
|
+
|
|
25
|
+
## Running commands in a container
|
|
26
|
+
|
|
27
|
+
For Python research code (most common):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
docker run --rm -v "$(pwd)":/workspace -w /workspace python:3.11 bash -c "
|
|
31
|
+
pip install -r requirements.txt &&
|
|
32
|
+
python train.py
|
|
33
|
+
"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
For projects with a Dockerfile:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
docker build -t feynman-experiment .
|
|
40
|
+
docker run --rm -v "$(pwd)/results":/workspace/results feynman-experiment
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For GPU workloads:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
docker run --rm --gpus all -v "$(pwd)":/workspace -w /workspace pytorch/pytorch:latest bash -c "
|
|
47
|
+
pip install -r requirements.txt &&
|
|
48
|
+
python train.py
|
|
49
|
+
"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Choosing the base image
|
|
53
|
+
|
|
54
|
+
| Research type | Base image |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| Python ML/DL | `pytorch/pytorch:latest` or `tensorflow/tensorflow:latest-gpu` |
|
|
57
|
+
| Python general | `python:3.11` |
|
|
58
|
+
| Node.js | `node:20` |
|
|
59
|
+
| R / statistics | `rocker/r-ver:4` |
|
|
60
|
+
| Julia | `julia:1.10` |
|
|
61
|
+
| Multi-language | `ubuntu:24.04` with manual installs |
|
|
62
|
+
|
|
63
|
+
## Persistent containers
|
|
64
|
+
|
|
65
|
+
For iterative experiments (like `/autoresearch`), create a named container instead of `--rm`. Choose a descriptive name based on the experiment:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
docker create --name <name> -v "$(pwd)":/workspace -w /workspace python:3.11 tail -f /dev/null
|
|
69
|
+
docker start <name>
|
|
70
|
+
docker exec <name> bash -c "pip install -r requirements.txt"
|
|
71
|
+
docker exec <name> bash -c "python train.py"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This preserves installed packages across iterations. Clean up with:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
docker stop <name> && docker rm <name>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Notes
|
|
81
|
+
|
|
82
|
+
- The mounted workspace syncs results back to the host automatically
|
|
83
|
+
- Containers are network-enabled by default — add `--network none` for full isolation
|
|
84
|
+
- For GPU access, Docker must be configured with the NVIDIA Container Toolkit
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jobs
|
|
3
|
+
description: Inspect active background research work including running processes, scheduled follow-ups, and pending tasks. Use when the user asks what's running, checks on background work, or wants to see scheduled jobs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Jobs
|
|
7
|
+
|
|
8
|
+
Run the `/jobs` workflow. Read the prompt template at `prompts/jobs.md` for the full procedure.
|
|
9
|
+
|
|
10
|
+
Shows active `pi-processes`, scheduled `pi-schedule-prompt` entries, and running subagent tasks.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: literature-review
|
|
3
|
+
description: Run a literature review using paper search and primary-source synthesis. Use when the user asks for a lit review, paper survey, state of the art, or academic landscape summary on a research topic.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Literature Review
|
|
7
|
+
|
|
8
|
+
Run the `/lit` workflow. Read the prompt template at `prompts/lit.md` for the full procedure.
|
|
9
|
+
|
|
10
|
+
Agents used: `researcher`, `verifier`, `reviewer`
|
|
11
|
+
|
|
12
|
+
Output: literature review in `outputs/` with `.provenance.md` sidecar.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: paper-code-audit
|
|
3
|
+
description: Compare a paper's claims against its public codebase. Use when the user asks to audit a paper, check code-claim consistency, verify reproducibility of a specific paper, or find mismatches between a paper and its implementation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Paper-Code Audit
|
|
7
|
+
|
|
8
|
+
Run the `/audit` workflow. Read the prompt template at `prompts/audit.md` for the full procedure.
|
|
9
|
+
|
|
10
|
+
Agents used: `researcher`, `verifier`
|
|
11
|
+
|
|
12
|
+
Output: audit report in `outputs/`.
|