Skip to content

Extensions

[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.

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";

fp loads extensions from two locations, checked in order:

  1. Project extensions.fp/extensions/ in your project root (takes precedence)
  2. 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.

Every extension receives a single fp argument of type FpExtensionContext:

PropertyTypePurpose
issuesExtensionIssueContextAccessPromiseCRUD operations + property registration
commentsExtensionCommentAccessPromiseCreate, list, delete comments
secretsExtensionSecretsAccessPromiseOS keychain secret storage
uiExtensionUiAccessPromiseActions, notifications, property helpers
configExtensionConfigAccessRead extension config values
logExtensionLoggerStructured logging
onHook registration functionSubscribe to lifecycle events
runtimeExtensionRuntime"cli" or "desktop"
projectDirstringAbsolute path to project root

Extensions must run in both the CLI (Bun runtime) and the desktop app (Node/Electron). Write Node-compatible code only.

  • node:child_processspawn, execFile
  • node:fs/promisesreadFile, writeFile, mkdir, rm
  • node:pathresolve, join
  • Bun global APIs (Bun.spawn, Bun.file, Bun.env)
  • Bun-only modules (bun:ffi, bun:sqlite)
  • Any API not present on the FpExtensionContext object

fp.runtime returns "cli" or "desktop" if you need conditional behavior, but prefer writing universal code.