API Reference
Could not copy markdown source body. Please use "view as markdown".
Entry Point
Section titled “Entry Point”ExtensionInit
Section titled “ExtensionInit”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>ExtensionRuntime
Section titled “ExtensionRuntime”type ExtensionRuntime = "cli" | "desktop"The fp Context Object
Section titled “The fp Context Object”The main context object passed to every extension’s init function. Provides access to issues, comments, secrets, UI, config, logging, and lifecycle hooks.
| Property | Type | Description |
|---|---|---|
comments | ExtensionCommentAccessPromise | Comment CRUD (create, list, delete). |
config | ExtensionConfigAccess | Read extension config from merged FP project config (.fp/config.toml + optional .fp/config.local.toml). |
issues | ExtensionIssueContextAccessPromise | Issue CRUD and custom property registration. |
log | ExtensionLogger | Structured logging prefixed with the extension name. |
on | (event, handler) => void | Register a hook handler for a lifecycle event. |
projectDir | string | Absolute path to the project root directory. |
runtime | ExtensionRuntime | "cli" when running in the fp CLI, "desktop" in the desktop app. |
secrets | ExtensionSecretsAccessPromise | OS keychain secret storage (get, set, delete). |
ui | ExtensionUiAccessPromise | Desktop 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.
Issue Operations
Section titled “Issue Operations”fp.issues
Section titled “fp.issues”The fp.issues interface — extends issue CRUD with custom property registration.
Extends ExtensionIssueAccessPromise.
ExtensionIssueAccessPromise
Section titled “ExtensionIssueAccessPromise”CRUD access to issues from within an extension.
get()returnsnullfor missing issues (does not throw).update()throws if the issue does not exist.delete()throws if the issue does not exist.
create()
Section titled “create()”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()
Section titled “delete()”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()
Section titled “list()”List issues, optionally filtered by status or parent.
list(filter?: IssueListFilter): Promise<ExtensionIssue[]>update()
Section titled “update()”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>| Parameter | Type | Optional | Description |
|---|---|---|---|
id | string | No | — |
updates | { ... } | No | — |
registerProperty()
Section titled “registerProperty()”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>Comment Operations
Section titled “Comment Operations”fp.comments
Section titled “fp.comments”CRUD operations for issue comments. Comments are plain-text or markdown strings attached to an issue.
create()
Section titled “create()”Add a comment to an issue. Returns the created comment with its assigned ID.
create(issueId: string, content: string): Promise<ExtensionComment>| Parameter | Type | Optional | Description |
|---|---|---|---|
issueId | string | No | — |
content | string | No | — |
delete()
Section titled “delete()”Delete a comment by ID. Throws if the comment doesn’t exist.
delete(commentId: string): Promise<void>list()
Section titled “list()”List all comments on an issue, ordered by creation time.
list(issueId: string): Promise<ExtensionComment[]>Secrets
Section titled “Secrets”fp.secrets
Section titled “fp.secrets”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()
Section titled “delete()”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>| Parameter | Type | Optional | Description |
|---|---|---|---|
key | string | No | — |
value | string | No | — |
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.
notify()
Section titled “notify()”Show a toast notification to the user (desktop only).
notify(message: string, options?: ExtensionUiNotifyOptions): Promise<void>| Parameter | Type | Optional | Description |
|---|---|---|---|
message | string | No | — |
options | ExtensionUiNotifyOptions | Yes | — |
properties
Section titled “properties”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;}registerAction()
Section titled “registerAction()”Register a command-palette action (desktop only).
registerAction(options: ExtensionUiActionOptions): Promise<void>ExtensionUiActionOptions
Section titled “ExtensionUiActionOptions”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.
| Property | Type | Description |
|---|---|---|
icon? | string | Lucide icon name shown alongside the label. |
id | string | Unique identifier, conventionally extension-name.action-name. |
keywords? | readonly string[] | Additional search terms for palette filtering. |
label | string | Display label in the command palette. |
onExecute | `(ctx: Record<string, unknown>) => void | Promise |
when? | `(ctx: Record<string, unknown>) => boolean | Promise |
ExtensionUiNotifyOptions
Section titled “ExtensionUiNotifyOptions”Options for fp.ui.notify().
| Property | Type | Description |
|---|---|---|
kind? | `“success" | "warning" |
title? | string | Notification title displayed above the message. |
Config
Section titled “Config”fp.config
Section titled “fp.config”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 | undefinedLogging
Section titled “Logging”fp.log
Section titled “fp.log”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.
| Property | Type | Description |
|---|---|---|
debug | (message: string) => void | Implementation details — hidden unless verbose/debug logging is enabled. |
error | (message: string) => void | Failures that prevent the extension from completing an operation. |
info | (message: string) => void | Normal operational messages. |
warn | (message: string) => void | Recoverable issues that don’t prevent the extension from functioning. |
Lifecycle Events
Section titled “Lifecycle Events”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 (validation)
Section titled “Pre-hooks (validation)”Pre-hooks fire before an operation is persisted. Return a HookValidationError to block it, or undefined to allow.
| Event | Context | Description |
|---|---|---|
comment:creating | HookCommentCreatingContext | Fires 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:deleting | HookCommentContext | Fires before a comment is deleted. Return a HookValidationError to prevent deletion. |
issue:creating | HookIssueContext | Fires before a new issue is persisted. Return a HookValidationError to block creation, or undefined to allow it. |
issue:deleting | HookIssueDeleteContext | Fires before an issue is deleted. Return a HookValidationError to prevent deletion. |
issue:status:changing | HookStatusChangeContext | Fires 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:updating | HookIssueUpdateContext | Fires 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 (side effects)
Section titled “Post-hooks (side effects)”Post-hooks fire after an operation succeeds. They are fire-and-forget — exceptions are logged but do not affect the operation.
| Event | Context | Description |
|---|---|---|
comment:created | HookCommentContext | Fires after a comment is successfully added. The context includes the full persisted comment with its ID. |
comment:deleted | HookCommentContext | Fires after a comment is permanently deleted. |
issue:created | HookIssueContext | Fires after an issue is successfully created. Use for side effects: auto-commenting, creating child issues, notifications. |
issue:deleted | HookIssueDeleteContext | Fires after an issue is permanently deleted. The context contains the issue as it was before deletion. |
issue:status:changed | HookStatusChangeContext | Fires after an issue’s status has changed. Use for post-transition side effects like running tests or notifications. |
issue:updated | HookIssueUpdateContext | Fires 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. |
Hook Context Types
Section titled “Hook Context Types”HookValidationError
Section titled “HookValidationError”Returned from a pre-hook to reject the operation.
| Property | Type | Description |
|---|---|---|
code | string | — |
details? | Record<string, unknown> | — |
message | string | — |
HookPreResult
Section titled “HookPreResult”Return type for pre-hooks: undefined to allow, HookValidationError to block.
type HookPreResult = undefined | HookValidationErrorHookIssueContext
Section titled “HookIssueContext”Hook context carrying the full issue state at the time the hook fires.
| Property | Type | Description |
|---|---|---|
issue | ExtensionIssue | — |
HookIssueUpdateContext
Section titled “HookIssueUpdateContext”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.
| Property | Type | Description |
|---|---|---|
issue | ExtensionIssue | — |
updates | { ... } | — |
HookIssueDeleteContext
Section titled “HookIssueDeleteContext”| Property | Type | Description |
|---|---|---|
issue | ExtensionIssue | — |
targetIds | readonly 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.
HookStatusChangeContext
Section titled “HookStatusChangeContext”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.
| Property | Type | Description |
|---|---|---|
from | string | — |
issue | ExtensionIssue | — |
to | string | — |
HookCommentCreatingContext
Section titled “HookCommentCreatingContext”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.
| Property | Type | Description |
|---|---|---|
content | string | — |
issueId | string | — |
HookCommentContext
Section titled “HookCommentContext”Context for comment:created, comment:deleted, and comment:deleting hooks.
| Property | Type | Description |
|---|---|---|
comment | ExtensionComment | — |
issueId | string | — |
Data Models
Section titled “Data Models”ExtensionIssue
Section titled “ExtensionIssue”| Property | Type | Description |
|---|---|---|
author? | string | — |
createdAt | string | — |
dependencies | readonly string[] | — |
description | string | — |
id | string | — |
parent | `string | null` |
priority | `Priority | null` |
properties? | Record<string, unknown> | — |
revisions | `Ref | readonly Ref[] |
status | Status | — |
title | string | — |
updatedAt | string | — |
ExtensionComment
Section titled “ExtensionComment”| Property | Type | Description |
|---|---|---|
author | string | — |
content | string | — |
createdAt | string | — |
id | string | — |
issueId | string | — |
IssueListFilter
Section titled “IssueListFilter”Filter for listing issues.
| Property | Type | Description |
|---|---|---|
parent? | `string | null` |
status? | string | — |
Value Types
Section titled “Value Types”Status
Section titled “Status”Issue workflow status.
type Status = "todo" | "in-progress" | "done"Priority
Section titled “Priority”Issue priority level.
low— backlog / nice-to-havemedium— default / normal priorityhigh— important, should be addressed sooncritical— 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;}Property System
Section titled “Property System”PropertyOptions
Section titled “PropertyOptions”Configuration for a custom issue property registered via fp.issues.registerProperty().
Properties add typed data to issues (environment, labels, category, etc.).
| Property | Type | Description |
|---|---|---|
display | PropertyDisplay | — |
icon? | string | Lucide icon name displayed alongside the property label. |
label? | string | Display label shown next to the property in the UI. |
schema? | unknown | Any 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.
PropertyOption
Section titled “PropertyOption”A single option in a select or multiselect property display.
| Property | Type | Description |
|---|---|---|
color? | PropertyColor | Color token for the option chip. |
icon? | string | Lucide icon name. |
label? | string | Display label shown in the UI. Defaults to value if omitted. |
value | string | The value stored in the issue’s properties record when this option is selected. |
icon — Lucide icon name. Recommended icons by category:
| Status | circlecircle-dotcircle-checkloaderclock |
| Priority | signalsignal-lowsignal-mediumsignal-higharrow-upflame |
| People | userusersuser-plus |
| Workflow | git-branchgit-mergerocketflagtag |
| Content | file-textfolderlinkcodeterminal |
| Feedback | checkxalert-circleinfothumbs-up |
| Objects | boxpackagelayerszapstarshieldlocksettings |
color — Color token for the option chip. Available colors:
neutralpurplepinkturquoiseblueyelloworangemintredlimesuccesswarningdestructivePropertyDisplay
Section titled “PropertyDisplay”Controls how a custom property is rendered and how its value is stored in properties.
select— single-value picker, stored as astringmultiselect— multi-value chips, stored as astring[]text— freeform input, stored as astring
type PropertyDisplay = { options: readonly PropertyOption[]; type: "select";} | { options: readonly PropertyOption[]; type: "multiselect";} | { type: "text";}PropertyColor
Section titled “PropertyColor”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