Make Feynman a standalone CLI

This commit is contained in:
Advait Paliwal
2026-03-20 11:11:15 -07:00
parent 1fe1ce04a5
commit 1e68c872df
7 changed files with 137 additions and 17 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
node_modules
.env
.feynman
dist
outputs/*
!outputs/.gitkeep

View File

@@ -1,6 +1,6 @@
# Feynman
`feynman` is a research-first agent scaffold built on `@mariozechner/pi-coding-agent`.
`feynman` is a research-first CLI built on `@mariozechner/pi-coding-agent`.
It keeps the useful parts of a coding agent:
- file access
@@ -19,7 +19,20 @@ But it biases the runtime toward research work:
The primary paper backend is `@companion-ai/alpha-hub` and your alphaXiv account.
The rest of the workflow is augmented through a curated `.pi/settings.json` package stack.
## Setup
## Install
```bash
npm install -g @companion-ai/feynman
```
Then authenticate alphaXiv and start the CLI:
```bash
feynman --alpha-login
feynman
```
For local development:
```bash
cd /Users/advaitpaliwal/Companion/Code/feynman
@@ -28,13 +41,7 @@ cp .env.example .env
npm run start
```
If you already use `pi`, Feynman will reuse the usual auth/config locations for model access.
Before deep paper work, make sure alphaXiv auth is set up:
```bash
npx @companion-ai/alpha-hub login
```
Feynman uses Pi under the hood, but the user-facing entrypoint is `feynman`, not `pi`.
## Commands

2
bin/feynman.js Executable file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env node
import "../dist/index.js";

11
package-lock.json generated
View File

@@ -1,19 +1,22 @@
{
"name": "feynman",
"name": "@companion-ai/feynman",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "feynman",
"name": "@companion-ai/feynman",
"version": "0.1.0",
"dependencies": {
"@companion-ai/alpha-hub": "file:../alpha-hub/cli",
"@companion-ai/alpha-hub": "^0.1.1",
"@mariozechner/pi-ai": "^0.56.1",
"@mariozechner/pi-coding-agent": "^0.56.1",
"@sinclair/typebox": "^0.34.41",
"dotenv": "^16.4.7"
},
"bin": {
"feynman": "bin/feynman.js"
},
"devDependencies": {
"@types/node": "^24.3.0",
"tsx": "^4.20.5",
@@ -25,7 +28,7 @@
},
"../alpha-hub/cli": {
"name": "@companion-ai/alpha-hub",
"version": "0.1.0",
"version": "0.1.1",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.27.1",

View File

@@ -1,12 +1,26 @@
{
"name": "feynman",
"name": "@companion-ai/feynman",
"version": "0.1.0",
"private": true,
"description": "Research-first agent built on pi-coding-agent",
"description": "Research-first CLI agent built on Pi and alphaXiv",
"type": "module",
"bin": {
"feynman": "./bin/feynman.js"
},
"files": [
"bin/",
"dist/",
".pi/",
"extensions/",
"prompts/",
"skills/",
"README.md",
".env.example"
],
"scripts": {
"build": "tsc -p tsconfig.build.json",
"dev": "tsx src/index.ts",
"start": "tsx src/index.ts",
"start:dist": "node ./bin/feynman.js",
"typecheck": "tsc --noEmit"
},
"keywords": [
@@ -27,7 +41,7 @@
]
},
"dependencies": {
"@companion-ai/alpha-hub": "^0.1.0",
"@companion-ai/alpha-hub": "^0.1.1",
"@mariozechner/pi-ai": "^0.56.1",
"@mariozechner/pi-coding-agent": "^0.56.1",
"@sinclair/typebox": "^0.34.41",
@@ -40,5 +54,13 @@
},
"engines": {
"node": ">=20.6.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/getcompanion-ai/feynman.git"
},
"homepage": "https://github.com/getcompanion-ai/feynman#readme",
"bugs": {
"url": "https://github.com/getcompanion-ai/feynman/issues"
}
}

View File

@@ -7,6 +7,12 @@ import { parseArgs } from "node:util";
import { fileURLToPath } from "node:url";
import readline from "node:readline/promises";
import {
getUserName as getAlphaUserName,
isLoggedIn as isAlphaLoggedIn,
login as loginAlpha,
logout as logoutAlpha,
} from "@companion-ai/alpha-hub/lib";
import {
AuthStorage,
createAgentSession,
@@ -24,6 +30,9 @@ type ThinkingLevel = "off" | "low" | "medium" | "high";
function printHelp(): void {
console.log(`Feynman commands:
/help Show this help
/alpha-login Sign in to alphaXiv
/alpha-logout Clear alphaXiv auth
/alpha-status Show alphaXiv auth status
/new Start a fresh persisted session
/exit Quit the REPL
/lit-review <topic> Expand the literature review prompt template
@@ -34,6 +43,9 @@ function printHelp(): void {
CLI flags:
--prompt "<text>" Run one prompt and exit
--alpha-login Sign in to alphaXiv and exit
--alpha-logout Clear alphaXiv auth and exit
--alpha-status Show alphaXiv auth status and exit
--model provider:model Force a specific model
--thinking level off | low | medium | high
--cwd /path/to/workdir Working directory for tools
@@ -78,6 +90,9 @@ async function main(): Promise<void> {
options: {
cwd: { type: "string" },
help: { type: "boolean" },
"alpha-login": { type: "boolean" },
"alpha-logout": { type: "boolean" },
"alpha-status": { type: "boolean" },
model: { type: "string" },
"new-session": { type: "boolean" },
prompt: { type: "string" },
@@ -91,6 +106,35 @@ async function main(): Promise<void> {
return;
}
if (values["alpha-login"]) {
const result = await loginAlpha();
const name =
(result.userInfo &&
typeof result.userInfo === "object" &&
"name" in result.userInfo &&
typeof result.userInfo.name === "string")
? result.userInfo.name
: getAlphaUserName();
console.log(name ? `alphaXiv login complete: ${name}` : "alphaXiv login complete");
return;
}
if (values["alpha-logout"]) {
logoutAlpha();
console.log("alphaXiv auth cleared");
return;
}
if (values["alpha-status"]) {
if (isAlphaLoggedIn()) {
const name = getAlphaUserName();
console.log(name ? `alphaXiv logged in as ${name}` : "alphaXiv logged in");
} else {
console.log("alphaXiv not logged in");
}
return;
}
const workingDir = resolve(values.cwd ?? process.cwd());
const sessionDir = resolve(values["session-dir"] ?? resolve(appRoot, ".feynman", "sessions"));
mkdirSync(sessionDir, { recursive: true });
@@ -191,6 +235,35 @@ async function main(): Promise<void> {
continue;
}
if (line === "/alpha-login") {
const result = await loginAlpha();
const name =
(result.userInfo &&
typeof result.userInfo === "object" &&
"name" in result.userInfo &&
typeof result.userInfo.name === "string")
? result.userInfo.name
: getAlphaUserName();
console.log(name ? `alphaXiv login complete: ${name}` : "alphaXiv login complete");
continue;
}
if (line === "/alpha-logout") {
logoutAlpha();
console.log("alphaXiv auth cleared");
continue;
}
if (line === "/alpha-status") {
if (isAlphaLoggedIn()) {
const name = getAlphaUserName();
console.log(name ? `alphaXiv logged in as ${name}` : "alphaXiv logged in");
} else {
console.log("alphaXiv not logged in");
}
continue;
}
if (line === "/new") {
await session.newSession();
console.log("started a new session");

12
tsconfig.build.json Normal file
View File

@@ -0,0 +1,12 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "./dist",
"declaration": false,
"sourceMap": false
},
"include": [
"src/**/*.ts"
]
}