Rename .pi to .feynman, rename citation agent to verifier, add website, skills, and docs

- Rename project config dir from .pi/ to .feynman/ (Pi supports this via piConfig.configDir)
- Rename citation agent to verifier across all prompts, agents, skills, and docs
- Add website with homepage and 24 doc pages (Astro + Tailwind)
- Add skills for all workflows (deep-research, lit, review, audit, replicate, compare, draft, autoresearch, watch, jobs, session-log, agentcomputer)
- Add Pi-native prompt frontmatter (args, section, topLevelCli) and read at runtime
- Remove sync-docs generation layer — docs are standalone
- Remove metadata/prompts.mjs and metadata/packages.mjs — not needed at runtime
- Rewrite README and homepage copy
- Add environment selection to /replicate before executing
- Add prompts/delegate.md and AGENTS.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Advait Paliwal
2026-03-23 17:35:35 -07:00
parent 406d50b3ff
commit f5570b4e5a
98 changed files with 9886 additions and 298 deletions

View File

@@ -15,11 +15,12 @@ import {
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { Type } from "@sinclair/typebox";
import { getExtensionCommandSpec } from "../../metadata/commands.mjs";
import { formatToolText } from "./shared.js";
export function registerAlphaCommands(pi: ExtensionAPI): void {
pi.registerCommand("alpha-login", {
description: "Sign in to alphaXiv from inside Feynman.",
description: getExtensionCommandSpec("alpha-login")?.description ?? "Sign in to alphaXiv from inside Feynman.",
handler: async (_args, ctx) => {
if (isAlphaLoggedIn()) {
const name = getAlphaUserName();
@@ -34,7 +35,7 @@ export function registerAlphaCommands(pi: ExtensionAPI): void {
});
pi.registerCommand("alpha-logout", {
description: "Clear alphaXiv auth from inside Feynman.",
description: getExtensionCommandSpec("alpha-logout")?.description ?? "Clear alphaXiv auth from inside Feynman.",
handler: async (_args, ctx) => {
logoutAlpha();
ctx.ui.notify("alphaXiv auth cleared", "info");
@@ -42,7 +43,7 @@ export function registerAlphaCommands(pi: ExtensionAPI): void {
});
pi.registerCommand("alpha-status", {
description: "Show alphaXiv authentication status.",
description: getExtensionCommandSpec("alpha-status")?.description ?? "Show alphaXiv authentication status.",
handler: async (_args, ctx) => {
if (!isAlphaLoggedIn()) {
ctx.ui.notify("alphaXiv not connected", "warning");

View File

@@ -106,7 +106,7 @@ async function buildAgentCatalogSummary(): Promise<{ agents: string[]; chains: s
const agents: string[] = [];
const chains: string[] = [];
try {
const entries = await readdir(resolvePath(APP_ROOT, ".pi", "agents"), { withFileTypes: true });
const entries = await readdir(resolvePath(APP_ROOT, ".feynman", "agents"), { withFileTypes: true });
for (const entry of entries) {
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
if (entry.name.endsWith(".chain.md")) {
@@ -243,9 +243,13 @@ export function installFeynmanHeader(
pushList("Chains", agentData.chains);
if (activity) {
const maxActivityLen = leftW * 2;
const trimmed = activity.length > maxActivityLen
? `${activity.slice(0, maxActivityLen - 1)}`
: activity;
leftLines.push("");
leftLines.push(theme.fg("accent", theme.bold("Last Activity")));
for (const line of wrapWords(activity, leftW)) {
for (const line of wrapWords(trimmed, leftW)) {
leftLines.push(theme.fg("dim", line));
}
}

View File

@@ -1,59 +1,82 @@
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import {
extensionCommandSpecs,
formatSlashUsage,
getExtensionCommandSpec,
livePackageCommandGroups,
readPromptSpecs,
} from "../../metadata/commands.mjs";
import { APP_ROOT } from "./shared.js";
type HelpCommand = { usage: string; description: string };
type HelpSection = { title: string; commands: HelpCommand[] };
function buildHelpSections(): HelpSection[] {
function buildHelpSections(pi: ExtensionAPI): HelpSection[] {
const liveCommands = new Map(pi.getCommands().map((command) => [command.name, command]));
const promptSpecs = readPromptSpecs(APP_ROOT);
const sections = new Map<string, HelpCommand[]>();
for (const command of promptSpecs.filter((entry) => entry.section !== "Internal")) {
const live = liveCommands.get(command.name);
if (!live) continue;
const items = sections.get(command.section) ?? [];
items.push({
usage: formatSlashUsage(command),
description: live.description ?? command.description,
});
sections.set(command.section, items);
}
for (const command of extensionCommandSpecs.filter((entry) => entry.publicDocs)) {
const live = liveCommands.get(command.name);
if (!live) continue;
const items = sections.get(command.section) ?? [];
items.push({
usage: formatSlashUsage(command),
description: live.description ?? command.description,
});
sections.set(command.section, items);
}
const ownedNames = new Set([
...promptSpecs.filter((entry) => entry.section !== "Internal").map((entry) => entry.name),
...extensionCommandSpecs.filter((entry) => entry.publicDocs).map((entry) => entry.name),
]);
for (const group of livePackageCommandGroups) {
const commands: HelpCommand[] = [];
for (const spec of group.commands) {
const command = liveCommands.get(spec.name);
if (!command || ownedNames.has(command.name)) continue;
commands.push({
usage: spec.usage,
description: command.description ?? "",
});
}
if (commands.length > 0) {
sections.set(group.title, commands);
}
}
return [
{
title: "Research Workflows",
commands: [
{ usage: "/deepresearch <topic>", description: "Source-heavy investigation with parallel researchers." },
{ usage: "/lit <topic>", description: "Literature review using paper search." },
{ usage: "/review <artifact>", description: "Simulated peer review with objections and revision plan." },
{ usage: "/audit <item>", description: "Audit a paper against its public codebase." },
{ usage: "/replicate <paper>", description: "Replication workflow for a paper or claim." },
{ usage: "/draft <topic>", description: "Paper-style draft from research findings." },
{ usage: "/compare <topic>", description: "Compare sources with agreements and disagreements." },
{ usage: "/autoresearch <target>", description: "Autonomous experiment optimization loop." },
{ usage: "/watch <topic>", description: "Recurring research watch on a topic." },
],
},
{
title: "Agents & Delegation",
commands: [
{ usage: "/agents", description: "Open the agent and chain manager." },
{ usage: "/run <agent> <task>", description: "Run a single subagent." },
{ usage: "/chain agent1 -> agent2", description: "Run agents in sequence." },
{ usage: "/parallel agent1 -> agent2", description: "Run agents in parallel." },
],
},
{
title: "Project & Session",
commands: [
{ usage: "/init", description: "Bootstrap AGENTS.md and session-log folders." },
{ usage: "/log", description: "Write a session log to notes/." },
{ usage: "/jobs", description: "Inspect active background work." },
{ usage: "/search", description: "Search prior sessions." },
{ usage: "/preview", description: "Preview a generated artifact." },
],
},
{
title: "Setup",
commands: [
{ usage: "/alpha-login", description: "Sign in to alphaXiv." },
{ usage: "/alpha-status", description: "Check alphaXiv auth." },
{ usage: "/alpha-logout", description: "Clear alphaXiv auth." },
],
},
];
"Research Workflows",
"Project & Session",
"Setup",
"Agents & Delegation",
"Bundled Package Commands",
]
.map((title) => ({ title, commands: sections.get(title) ?? [] }))
.filter((section) => section.commands.length > 0);
}
export function registerHelpCommand(pi: ExtensionAPI): void {
pi.registerCommand("help", {
description: "Show grouped Feynman commands and prefill the editor with a selected command.",
description:
getExtensionCommandSpec("help")?.description ??
"Show grouped Feynman commands and prefill the editor with a selected command.",
handler: async (_args, ctx) => {
const sections = buildHelpSections();
const sections = buildHelpSections(pi);
const items = sections.flatMap((section) => [
`--- ${section.title} ---`,
...section.commands.map((cmd) => `${cmd.usage}${cmd.description}`),

View File

@@ -4,13 +4,14 @@ import { dirname, resolve as resolvePath } from "node:path";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { Type } from "@sinclair/typebox";
import { getExtensionCommandSpec } from "../../metadata/commands.mjs";
import { renderHtmlPreview, renderPdfPreview, openWithDefaultApp, pathExists, buildProjectAgentsTemplate, buildSessionLogsReadme } from "./preview.js";
import { formatToolText } from "./shared.js";
import { searchSessionTranscripts } from "./session-search.js";
export function registerInitCommand(pi: ExtensionAPI): void {
pi.registerCommand("init", {
description: "Initialize AGENTS.md and session-log folders for a research project.",
description: getExtensionCommandSpec("init")?.description ?? "Initialize AGENTS.md and session-log folders for a research project.",
handler: async (_args, ctx) => {
const agentsPath = resolvePath(ctx.cwd, "AGENTS.md");
const notesDir = resolvePath(ctx.cwd, "notes");