Extensions
Could not copy markdown source body. Please use "view as markdown".
Extensions are TypeScript files that hook into fp’s issue-tracking lifecycle. They run in both the CLI (Bun) and the desktop app (Node/Electron). Each extension exports an init function that receives the fp context object.
Quick Start
Section titled “Quick Start”import type { ExtensionInit } from "@fiberplane/extensions";
const init: ExtensionInit = (fp) => { fp.on("issue:created", ({ issue }) => { fp.log.info(`New issue: ${issue.title}`); });};
export default init;The ExtensionInit signature is (fp: FpExtensionContext) => void | Promise<void>. The default export is the entry point.
When your init function needs to await calls like registerProperty, make it async:
const init: ExtensionInit = async (fp) => { await fp.issues.registerProperty("environment", { label: "Environment", icon: "globe", display: fp.ui.properties.select( fp.ui.properties.option("staging", { label: "Staging", color: "yellow" }), fp.ui.properties.option("production", { label: "Production", color: "red" }), ), });};
export default init;Always use the type-only import:
import type { ... } from "@fiberplane/extensions";Extension Discovery
Section titled “Extension Discovery”fp loads extensions from two locations, checked in order:
- Project extensions —
.fp/extensions/in your project root (takes precedence) - Global extensions —
~/.fiberplane/extensions/
Supported file types: .ts, .js, .mts, .mjs. An extension can be a single file or a directory with an index.* entry point. Files ending in .d.ts are skipped.
When both locations contain an extension with the same name, the project-level extension wins.
The fp Context Object
Section titled “The fp Context Object”Every extension receives a single fp argument of type FpExtensionContext:
| Property | Type | Purpose |
|---|---|---|
issues | ExtensionIssueContextAccessPromise | CRUD operations + property registration |
comments | ExtensionCommentAccessPromise | Create, list, delete comments |
secrets | ExtensionSecretsAccessPromise | OS keychain secret storage |
ui | ExtensionUiAccessPromise | Actions, notifications, property helpers |
config | ExtensionConfigAccess | Read extension config values |
log | ExtensionLogger | Structured logging |
on | Hook registration function | Subscribe to lifecycle events |
runtime | ExtensionRuntime | "cli" or "desktop" |
projectDir | string | Absolute path to project root |
Runtime Compatibility
Section titled “Runtime Compatibility”Extensions must run in both the CLI (Bun runtime) and the desktop app (Node/Electron). Write Node-compatible code only.
Allowed APIs
Section titled “Allowed APIs”node:child_process—spawn,execFilenode:fs/promises—readFile,writeFile,mkdir,rmnode:path—resolve,join
- Bun global APIs (
Bun.spawn,Bun.file,Bun.env) - Bun-only modules (
bun:ffi,bun:sqlite) - Any API not present on the
FpExtensionContextobject
fp.runtime returns "cli" or "desktop" if you need conditional behavior, but prefer writing universal code.