Skip to content

API Reference

[view as markdown]

Entry point for an extension. Called once when the extension is loaded. Can be async (Promise<void>) when setup requires awaiting registerProperty or other async calls.

type ExtensionInit = (fp: FpExtensionContext) => void | Promise<void>
type ExtensionRuntime = "cli" | "desktop"

The main context object passed to every extension’s init function. Provides access to issues, comments, secrets, UI, config, logging, and lifecycle hooks.

PropertyTypeDescription
commentsExtensionCommentAccessPromiseComment CRUD (create, list, delete).
configExtensionConfigAccessRead extension config from merged FP project config (.fp/config.toml + optional .fp/config.local.toml).
issuesExtensionIssueContextAccessPromiseIssue CRUD and custom property registration.
logExtensionLoggerStructured logging prefixed with the extension name.
on(event, handler) => voidRegister a hook handler for a lifecycle event.
projectDirstringAbsolute path to the project root directory.
runtimeExtensionRuntime"cli" when running in the fp CLI, "desktop" in the desktop app.
secretsExtensionSecretsAccessPromiseOS keychain secret storage (get, set, delete).
uiExtensionUiAccessPromiseDesktop command-palette actions, notifications, and property display builders.

on — Register a hook handler for a lifecycle event.

The typed overload provides autocomplete for known events in ExtensionHookMap. The loose overload accepts arbitrary event strings for forward-compatible registration of future hook events.

The fp.issues interface — extends issue CRUD with custom property registration.

Extends ExtensionIssueAccessPromise.

CRUD access to issues from within an extension.

  • get() returns null for missing issues (does not throw).
  • update() throws if the issue does not exist.
  • delete() throws if the issue does not exist.

Create a new issue. Only title is required — other properties default to status: "todo", no priority, no parent.

create(data: {
description?: string;
parent?: string;
priority?: string;
properties?: Record<string, unknown>;
status?: string;
title: string;
}): Promise<ExtensionIssue>

Delete an issue permanently. Throws if the issue doesn’t exist.

delete(id: string): Promise<void>

Get a single issue by ID. Returns null if the issue does not exist.

get(id: string): Promise<ExtensionIssue | null>

List issues, optionally filtered by status or parent.

list(filter?: IssueListFilter): Promise<ExtensionIssue[]>

Update an existing issue. Only provided properties are modified. Throws if the issue doesn’t exist.

update(id: string, updates: {
description?: string;
priority?: string;
properties?: Record<string, unknown>;
status?: string;
title?: string;
}): Promise<ExtensionIssue>
ParameterTypeOptionalDescription
idstringNo
updates{ ... }No

Register a custom property on issues.

Keys are append-only per process lifetime and cannot collide with built-in attributes (title, description, status, priority, parent, dependencies). Must be called during init, not inside hook handlers.

registerProperty(key: string, options: PropertyOptions): Promise<void>

CRUD operations for issue comments. Comments are plain-text or markdown strings attached to an issue.

Add a comment to an issue. Returns the created comment with its assigned ID.

create(issueId: string, content: string): Promise<ExtensionComment>
ParameterTypeOptionalDescription
issueIdstringNo
contentstringNo

Delete a comment by ID. Throws if the comment doesn’t exist.

delete(commentId: string): Promise<void>

List all comments on an issue, ordered by creation time.

list(issueId: string): Promise<ExtensionComment[]>

OS keychain-backed secret storage, scoped per extension and project. Uses macOS Keychain or Linux secret-tool under the hood. All methods throw on keychain errors (e.g. access denied, service unavailable).

Delete a secret. Throws if the key doesn’t exist.

delete(key: string): Promise<void>

Retrieve a secret. Returns undefined if the key doesn’t exist.

get(key: string): Promise<string | undefined>

Store a secret. Overwrites any existing value for the key.

set(key: string, value: string): Promise<void>
ParameterTypeOptionalDescription
keystringNo
valuestringNo

UI integration: desktop command-palette actions, notifications, and builder helpers for property display configuration.

In CLI mode, registerAction and notify are silent no-ops. The properties builders work in both runtimes.

Show a toast notification to the user (desktop only).

notify(message: string, options?: ExtensionUiNotifyOptions): Promise<void>
ParameterTypeOptionalDescription
messagestringNo
optionsExtensionUiNotifyOptionsYes

Builder functions for constructing PropertyOption and PropertyDisplay values used with fp.issues.registerProperty().

properties: {
multiselect: (options: PropertyOption[]) => PropertyDisplay;
option: (value: string, opts: { ... }) => PropertyOption;
select: (options: PropertyOption[]) => PropertyDisplay;
text: () => PropertyDisplay;
}

Register a command-palette action (desktop only).

registerAction(options: ExtensionUiActionOptions): Promise<void>

Configuration for a command-palette action registered via fp.ui.registerAction(). Actions appear in the desktop app’s command palette. In CLI mode, registration is a no-op.

PropertyTypeDescription
icon?stringLucide icon name shown alongside the label.
idstringUnique identifier, conventionally extension-name.action-name.
keywords?readonly string[]Additional search terms for palette filtering.
labelstringDisplay label in the command palette.
onExecute`(ctx: Record<string, unknown>) => voidPromise`
when?`(ctx: Record<string, unknown>) => booleanPromise`

Options for fp.ui.notify().

PropertyTypeDescription
kind?`“success""warning"
title?stringNotification title displayed above the message.

Reads config values from the project’s merged FP config: shared .fp/config.toml plus optional .fp/config.local.toml overrides. The extension filename (without .ts) maps to the config section. E.g., my-extension.ts reads from [extensions.my-extension].

get(key: string): T | undefined

Structured logging. Messages are automatically prefixed with the extension name. Use debug for internals, info for normal operations, warn for recoverable issues, error for failures.

PropertyTypeDescription
debug(message: string) => voidImplementation details — hidden unless verbose/debug logging is enabled.
error(message: string) => voidFailures that prevent the extension from completing an operation.
info(message: string) => voidNormal operational messages.
warn(message: string) => voidRecoverable issues that don’t prevent the extension from functioning.

Maps hook event names to their handler signatures.

Pre-hooks (*:creating, *:updating, *:deleting, *:changing) can be async. Return a HookValidationError to reject the operation, or undefined to allow it. When multiple extensions register the same pre-hook, they run in discovery order; the first rejection stops remaining hooks.

Post-hooks (*:created, *:updated, *:deleted, *:changed) are fire-and-forget. Uncaught exceptions are logged but do not affect the operation.

The on() method also accepts arbitrary event strings for forward compatibility.

Pre-hooks fire before an operation is persisted. Return a HookValidationError to block it, or undefined to allow.

EventContextDescription
comment:creatingHookCommentCreatingContextFires before a comment is added to an issue. The context has issueId and content but no comment.id yet. Return a HookValidationError to block the comment.
comment:deletingHookCommentContextFires before a comment is deleted. Return a HookValidationError to prevent deletion.
issue:creatingHookIssueContextFires before a new issue is persisted. Return a HookValidationError to block creation, or undefined to allow it.
issue:deletingHookIssueDeleteContextFires before an issue is deleted. Return a HookValidationError to prevent deletion.
issue:status:changingHookStatusChangeContextFires before an issue’s status changes. This is the most common hook for workflow enforcement. from and to are status values (e.g. "todo", "in-progress", "done"). Return a HookValidationError to block the transition.
issue:updatingHookIssueUpdateContextFires before issue properties are modified. The context contains the current persisted issue state and the pending updates. Return a HookValidationError to reject the update.

Post-hooks fire after an operation succeeds. They are fire-and-forget — exceptions are logged but do not affect the operation.

EventContextDescription
comment:createdHookCommentContextFires after a comment is successfully added. The context includes the full persisted comment with its ID.
comment:deletedHookCommentContextFires after a comment is permanently deleted.
issue:createdHookIssueContextFires after an issue is successfully created. Use for side effects: auto-commenting, creating child issues, notifications.
issue:deletedHookIssueDeleteContextFires after an issue is permanently deleted. The context contains the issue as it was before deletion.
issue:status:changedHookStatusChangeContextFires after an issue’s status has changed. Use for post-transition side effects like running tests or notifications.
issue:updatedHookIssueUpdateContextFires after issue properties are successfully modified. ctx.issue reflects the final persisted issue state at hook time. Use for side effects like syncing external systems.

Returned from a pre-hook to reject the operation.

PropertyTypeDescription
codestring
details?Record<string, unknown>
messagestring

Return type for pre-hooks: undefined to allow, HookValidationError to block.

type HookPreResult = undefined | HookValidationError

Hook context carrying the full issue state at the time the hook fires.

PropertyTypeDescription
issueExtensionIssue

Hook context for issue update events. For issue:updating, issue is the current persisted state BEFORE the updates are applied. For issue:updated, issue is the final persisted state AFTER the updates are applied. updates is a sparse object containing only the properties being changed, including extension properties.

PropertyTypeDescription
issueExtensionIssue
updates{ ... }
PropertyTypeDescription
issueExtensionIssue
targetIdsreadonly string[]All issue IDs being deleted in this operation (descendants first, root last).

targetIds — All issue IDs being deleted in this operation (descendants first, root last). When targetIds.length > 1, this is a cascade delete that will also remove all sub-issues. Extensions can inspect this list to react differently to single vs. cascade deletions.

Hook context for status transition events. from and to are Status values as strings (e.g. "todo", "in-progress"). In pre-hooks (issue:status:changing), issue reflects state before the transition. In post-hooks (issue:status:changed), issue reflects the final persisted state.

PropertyTypeDescription
fromstring
issueExtensionIssue
tostring

Context for the comment:creating pre-hook, fired before a comment is persisted. There is no comment.id yet — only the target issue and the comment content.

PropertyTypeDescription
contentstring
issueIdstring

Context for comment:created, comment:deleted, and comment:deleting hooks.

PropertyTypeDescription
commentExtensionComment
issueIdstring
PropertyTypeDescription
author?string
createdAtstring
dependenciesreadonly string[]
descriptionstring
idstring
parent`stringnull`
priority`Prioritynull`
properties?Record<string, unknown>
revisions`Refreadonly Ref[]
statusStatus
titlestring
updatedAtstring
PropertyTypeDescription
authorstring
contentstring
createdAtstring
idstring
issueIdstring

Filter for listing issues.

PropertyTypeDescription
parent?`stringnull`
status?string

Issue workflow status.

type Status = "todo" | "in-progress" | "done"

Issue priority level.

  • low — backlog / nice-to-have
  • medium — default / normal priority
  • high — important, should be addressed soon
  • critical — urgent / blocking other work
type Priority = "low" | "medium" | "high" | "critical"

A VCS reference captured at a status transition. Single Ref when one VCS reference exists, array when multiple (e.g. colocated Git + JJ).

type Ref = {
_tag: "Git";
sha: string;
} | {
_tag: "JJ";
changeId: string;
}

Configuration for a custom issue property registered via fp.issues.registerProperty(). Properties add typed data to issues (environment, labels, category, etc.).

PropertyTypeDescription
displayPropertyDisplay
icon?stringLucide icon name displayed alongside the property label.
label?stringDisplay label shown next to the property in the UI.
schema?unknownAny Standard Schema v1 validator (Zod, Valibot, ArkType).

schema? — Any Standard Schema v1 validator (Zod, Valibot, ArkType). Values are validated on write — invalid values are rejected with an error.

A single option in a select or multiselect property display.

PropertyTypeDescription
color?PropertyColorColor token for the option chip.
icon?stringLucide icon name.
label?stringDisplay label shown in the UI. Defaults to value if omitted.
valuestringThe value stored in the issue’s properties record when this option is selected.

icon — Lucide icon name. Recommended icons by category:

Statuscirclecirclecircle-dotcircle-dotcircle-checkcircle-checkloaderloaderclockclock
Prioritysignalsignalsignal-lowsignal-lowsignal-mediumsignal-mediumsignal-highsignal-higharrow-uparrow-upflameflame
Peopleuseruserusersusersuser-plususer-plus
Workflowgit-branchgit-branchgit-mergegit-mergerocketrocketflagflagtagtag
Contentfile-textfile-textfolderfolderlinklinkcodecodeterminalterminal
Feedbackcheckcheckxxalert-circlealert-circleinfoinfothumbs-upthumbs-up
Objectsboxboxpackagepackagelayerslayerszapzapstarstarshieldshieldlocklocksettingssettings

color — Color token for the option chip. Available colors:

neutralpurplepinkturquoiseblueyelloworangemintredlimesuccesswarningdestructive

Controls how a custom property is rendered and how its value is stored in properties.

  • select — single-value picker, stored as a string
  • multiselect — multi-value chips, stored as a string[]
  • text — freeform input, stored as a string
type PropertyDisplay = {
options: readonly PropertyOption[];
type: "select";
} | {
options: readonly PropertyOption[];
type: "multiselect";
} | {
type: "text";
}

Color token for property options and chips.

Rendering rules:

  • icon + color: colored chip with icon
  • icon only: icon with plain label
  • color only: colored dot with label
  • neither: plain text
neutralpurplepinkturquoiseblueyelloworangemintredlimesuccesswarningdestructive