Skip to content

Instantly share code, notes, and snippets.

@rstacruz
Last active June 19, 2026 11:40
Show Gist options
  • Select an option

  • Save rstacruz/a4f0503a5d4d8910fb81bf11d78beb8b to your computer and use it in GitHub Desktop.

Select an option

Save rstacruz/a4f0503a5d4d8910fb81bf11d78beb8b to your computer and use it in GitHub Desktop.
pi /edit extension for editing Markdown plans
// Adds `/edit` to pi.
//
// Useful for plans: pi writes the Markdown, then you refine it in your editor.
//
// How it works:
// - remembers the last `.md` file written via the `write` tool
// - suggests `/edit` after writing a Markdown file
// - opens that file in `$EDITOR`
//
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { spawnSync } from "node:child_process";
import { resolve } from "node:path";
export default function (pi: ExtensionAPI) {
let lastMarkdownFile: string | null = null;
pi.on("tool_result", async (event, ctx) => {
if (event.toolName !== "write") return;
const path = event.input.path as string;
if (!path?.endsWith(".md")) return;
lastMarkdownFile = resolve(ctx.cwd, path);
const editor = process.env.EDITOR || "nvim";
ctx.ui.notify(`Use /edit to open the file in ${editor}`, "info");
});
pi.registerCommand("edit", {
description: "Open a file in a text editor. No arg = last written .md file",
handler: async (args, ctx) => {
await ctx.waitForIdle();
const editor = process.env.EDITOR || "nvim";
const filePath = args.trim()
? resolve(ctx.cwd, args.trim())
: lastMarkdownFile;
if (!filePath) {
ctx.ui.notify("No file specified and no recent .md file written", "error");
return;
}
if (!ctx.hasUI) {
ctx.ui.notify("/edit requires TUI mode", "error");
return;
}
const exitCode = await ctx.ui.custom<number | null>((tui, _theme, _kb, done) => {
tui.stop();
process.stdout.write("\x1b[2J\x1b[H");
const [cmd, ...editorArgs] = editor.split(/\s+/);
const result = spawnSync(cmd!, [...editorArgs, filePath], {
stdio: "inherit",
env: process.env,
});
tui.start();
tui.requestRender(true);
done(result.status);
return { render: () => [], invalidate: () => { } };
});
if (exitCode !== 0 && exitCode !== null) {
ctx.ui.notify(`Editor exited with code ${exitCode}`, "info");
}
},
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment