Phials developer documentation
User guide

Commands

Commands are discrete, named actions that can appear in shortcuts, the command bar, the PathBar toolbar, the header bar, context menus, and the multi-select selection bar. Prefer CommandProvider for any new UI that would previously have used legacy context or selection providers.

Types: Command, PluginProvider union — in your local clone, open sdk/command-types.generated.d.ts.

Related: Plugin API · Getting started

Mental model

  • One Command describes visibility (contextKeys, when), disabled state, action(ctx), optional toastData, keyboard shortcut, command-bar metadata (category, searchAliases), optional children (nested commands), and defaultPlacements (where the action appears by default; users can override some layouts in persisted settings).
  • Placement areas: toolbar, headerBar, contextMenu, selectionBar. The command bar does not use a placement flag: registered commands can appear there unless hidden by session state.
  • Execution uses CommandContext: pane, selectedFiles, targetFile (context menu: item under cursor), currentPath, vial flags, activeContextKeys, etc. — see sdk/command-types.generated.d.ts.

CommandProvider and Command

interface CommandProvider {
	type: "command";
	id: string;
	name: string;
	commands: Command[];
}

Important Command fields:

ConcernFields
Fast visibility filtercontextKeys?: CommandContextKey[] — if present and not containing "always", all listed keys must be active.
Fine-grained visibilitywhen?: (ctx: CommandContext) => boolean
Grey-out vs hidedisabled?: (ctx: CommandContext) => boolean
Runaction: (ctx: CommandContext) => void \| Promise<void>
FeedbacktoastData — static or derived from context
Shortcutshortcut?.defaults, allowDefault, priority
Command barcategory, searchAliases
Surface placementdefaultPlacements — per-area configs

Context menu placement

ContextMenuPlacementConfig adds selectionMode ("single" | "multi" | "both"), submenu, danger, order. Commands may supply renderSnippet(ctx) for custom context-menu rows.

Host registration

When your PhialsPlugin activates, the host registers each CommandProvider with the command subsystem and wires shortcuts for commands that declare shortcut.defaults. Shortcut ids follow the pattern command.${providerId}.${command.id}.

Superseding legacy context and selection

  • Context menus: Prefer defaultPlacements: [{ area: "contextMenu", … }] on Command. Legacy ContextProvider exists only for older plugins; new work should not add it.
  • Selection bar: Prefer area: "selectionBar" placements. Legacy SelectionProvider is deprecated — use commands so actions actually appear in the selection UI.

Example: context menu + selection bar

import { SystemIcons } from "$core/utils/icons";

const demoCommandsProvider: CommandProvider = &#123;
	type: "command",
	id: "my.vendor.demo",
	name: "Demo",
	commands: [
		&#123;
			id: "my.demo.archiveSelection",
			label: "Archive…",
			icon: SystemIcons.archive,
			category: "File",
			contextKeys: ["hasMultiSelection"],
			when: (ctx) =&gt; ctx.selectedFiles.every((f) =&gt; !f.name.endsWith("..")),
			disabled: (ctx) =&gt; ctx.selectedFiles.length &lt; 2,
			action: async (ctx) =&gt; &#123;
				void ctx.selectedFiles;
			&#125;,
			toastData: &#123; variant: "success", title: "Archived" &#125;,
			defaultPlacements: [
				&#123; area: "contextMenu", selectionMode: "multi", order: 120 &#125;,
				&#123; area: "selectionBar", icon: SystemIcons.archive, priority: 10 &#125;,
			],
		&#125;,
	],
&#125;;

Pitfalls

  • Shortcuts vs when: Shortcut eligibility may not mirror command.when(ctx) in every build — guard inside action when correctness matters.
  • Duplicate command ids collide in the registry; use a vendor prefix.
  • Nested children: Only the flat commands list on the provider receives standalone registration for shortcuts unless you add custom wiring.