# How to Extend PicList's Functionality: A Developer's Guide to Building PicGo Plugins

> Extend PicList functionality by developing custom PicGo GUI plugins. Learn the naming convention, automatic discovery, and seamless integration for enhanced developer control.

- Repository: [Kuingsmile/piclist](https://github.com/kuingsmile/piclist)
- Tags: how-to-guide
- Published: 2026-03-05

---

**Developers can extend PicList by creating standard PicGo GUI plugins using the `picgo-plugin-` naming convention, which the application automatically discovers, loads, and integrates into the Settings interface without requiring modifications to the core codebase.**

PicList, maintained by `kuingsmile/piclist`, is an image upload and management tool built on top of the PicGo framework. Because it inherits PicGo's robust plugin architecture, developers can extend PicList's functionality by creating custom uploaders, transformers, and GUI menus that integrate seamlessly with the existing Electron-based interface.

## Understanding the Plugin Architecture

PicList's extensibility is driven entirely by the PicGo plugin system. The application acts as a consumer of PicGo GUI plugins, handling discovery, state management, and UI rendering through a dedicated IPC layer.

### Plugin Discovery and Loading

On startup, PicList invokes `picgo.pluginLoader.getFullList()` to scan the application's `node_modules` directory for packages matching the `picgo-plugin-*` pattern. In [`src/main/events/rpc/routes/plugin/utils.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/utils.ts) (lines 45-70), the loader reads each plugin's [`package.json`](https://github.com/kuingsmile/piclist/blob/main/package.json) to verify it is a GUI plugin by checking for the `picgo-gui-plugin` keyword in the package metadata.

### Metadata Extraction and State Management

For each discovered plugin, PicList constructs an `IPicGoPlugin` object containing the name, version, author, description, logo, GUI flag, and configuration schemas for the plugin, uploader, and transformer. This process occurs in [`src/main/events/rpc/routes/plugin/utils.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/utils.ts) (lines 71-99). The enabled state is synchronized from the global configuration key `picgoPlugins.<fullName>`, defined in [`src/main/utils/configPaths.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/utils/configPaths.ts) (line 94), allowing PicList to persist user preferences across sessions.

### RPC Communication and GUI Rendering

The `pluginRouter` in [`src/main/events/rpc/routes/plugin/index.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/index.ts) handles UI actions such as install, uninstall, update, and import-local operations, forwarding results via Electron IPC using `event.sender.send`. When a plugin exports a `guiMenu(picgo)` function, PicList maps each menu item to a label object in [`src/main/events/rpc/routes/plugin/utils.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/utils.ts) (lines 58-63), displaying these items under **Settings → Plugins**. Configuration schemas are processed through `handleConfigWithFunction` in [`src/main/utils/common.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/utils/common.ts) (lines 33-42) to evaluate dynamic functions before rendering forms in the renderer process.

## Creating a Custom PicList Plugin

A PicList plugin is a Node.js module that conforms to the PicGo GUI plugin contract. The package must be published to npm or installed locally, following specific structural requirements.

### Package Structure and Naming

Your npm package name must start with `picgo-plugin-`. The package must export a default object conforming to the `IPlugin` interface and include `picgo-gui-plugin` in the `keywords` array of [`package.json`](https://github.com/kuingsmile/piclist/blob/main/package.json) to ensure PicList recognizes it during the discovery phase.

### Implementing an Uploader

The core functionality resides in the `uploader` method, which returns an object with a `name` identifier and an async `handle` function that processes image data.

```typescript
// index.ts – the only file that will be published to npm
import type { IPlugin, PicGo } from 'picgo'

// The plugin object follows PicGo's GUI plugin contract
const plugin: IPlugin = {
  // uploader implementation – called by PicGo when an image is uploaded
  uploader (ctx: PicGo) {
    return {
      name: 'hello',
      // handle must return an array of { url } objects
      async handle (ctx) {
        // For demonstration we just build a static URL
        const fileName = ctx.output[0].fileName
        const url = `https://example.com/${fileName}`
        ctx.log.info('hello-uploader →', url)
        return [{ url }]
      }
    }
  },

  // optional GUI menu – appears under Settings → Plugins → Hello Uploader
  guiMenu (picgo) {
    return [
      {
        label: 'Upload current clipboard image with Hello',
        async handle () {
          const img = await picgo.helper.getClipboardFile()
          const result = await picgo.upload([img])
          picgo.emit('notification', `Uploaded: ${result[0].url}`)
        }
      }
    ]
  },

  // optional plugin-level config (shown in the Settings UI)
  config (ctx) {
    return [
      {
        name: 'prefix',
        type: 'input',
        default: '',
        message: 'Optional URL prefix',
        required: false
      }
    ]
  }
}

export default plugin

```

### Adding GUI Menus and Configuration

To expose functionality in the PicList interface, export a `guiMenu` function that returns an array of menu items. Each item requires a `label` string and a `handle` function. For configurable options, export a `config` function returning an array of configuration objects that define input types, defaults, and validation rules. The `handleConfigWithFunction` utility in [`src/main/utils/common.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/utils/common.ts) processes these schemas to support dynamic default values.

### Persisting Plugin State

When users toggle a plugin on or off, PicList updates the configuration via `picgo.setConfig` at the key `picgoPlugins.<fullName>` and notifies the renderer with the `PICGO_TOGGLE_PLUGIN` event, as implemented in [`src/main/events/remotes/menu.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/remotes/menu.ts) (lines 284-303).

## Key Source Files in the Plugin Lifecycle

The following files form the complete pipeline for plugin discovery, configuration, and execution:

- **[`src/main/events/rpc/routes/plugin/utils.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/utils.ts)** – Core RPC functions that install, uninstall, list, and update plugins; builds the `IPicGoPlugin` objects served to the UI via `getFullList()`.
- **[`src/main/events/rpc/routes/plugin/index.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/index.ts)** – Registers the plugin RPC routes (`pluginRouter`) that forward UI actions between the renderer and main process.
- **[`src/main/utils/configPaths.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/utils/configPaths.ts)** – Defines the configuration schema, notably `picgoPlugins: IPicGoPlugins`, which stores each plugin's enabled flag at line 94.
- **[`src/main/utils/common.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/utils/common.ts)** – Contains helper functions `handleConfigWithFunction` and `handleStreamlinePluginName` that prepare plugin configuration for the renderer.
- **[`src/main/events/remotes/menu.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/remotes/menu.ts)** – Handles plugin state persistence and toggle notifications through the `PICGO_TOGGLE_PLUGIN` event (lines 284-303).
- **[`src/universal/types/types.d.ts`](https://github.com/kuingsmile/piclist/blob/main/src/universal/types/types.d.ts)** – TypeScript definitions for `IPicGoPlugin`, `IPluginMenuConfig`, and related interfaces essential for plugin development.

## Summary

- PicList extends PicGo's plugin architecture, accepting any npm package prefixed with `picgo-plugin-` and tagged with `picgo-gui-plugin`.
- Plugins are discovered automatically via `picgo.pluginLoader.getFullList()` in [`src/main/events/rpc/routes/plugin/utils.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/utils.ts) (lines 45-70).
- GUI integration requires exporting `guiMenu` and `config` functions, which the RPC layer processes to generate the Settings interface.
- Configuration persistence uses the `picgoPlugins.<fullName>` key defined in [`src/main/utils/configPaths.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/utils/configPaths.ts) (line 94).
- The renderer communicates with the main process through the `pluginRouter` in [`src/main/events/rpc/routes/plugin/index.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/index.ts) to manage the plugin lifecycle.

## Frequently Asked Questions

### What naming convention must I follow to create a PicList plugin?

Your npm package name must start with `picgo-plugin-` and include the `picgo-gui-plugin` keyword in [`package.json`](https://github.com/kuingsmile/piclist/blob/main/package.json) for PicList to recognize it as a GUI plugin during the discovery phase in [`src/main/events/rpc/routes/plugin/utils.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/utils.ts). Without this keyword, the loader will not identify your package as a GUI plugin.

### How does PicList handle plugin configuration UI?

PicList retrieves the `config` array from your plugin and processes it through `handleConfigWithFunction` in [`src/main/utils/common.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/utils/common.ts) (lines 33-42) to evaluate any dynamic functions, then renders the resulting schema as dynamic forms in the Settings interface under your plugin's name.

### Can I add custom keyboard shortcuts for my PicList plugin?

Yes, you can register custom shortcuts by invoking the PicList CLI's shortkey service during your plugin's post-install phase, or by handling keyboard events within your `guiMenu` implementation that communicates via the RPC layer in [`src/main/events/rpc/routes/plugin/index.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/events/rpc/routes/plugin/index.ts). The main process will bind these shortcuts to your plugin's handlers.

### Where does PicList store plugin enable and disable states?

The enabled state is stored in the global configuration under the key `picgoPlugins.<fullName>`, defined in [`src/main/utils/configPaths.ts`](https://github.com/kuingsmile/piclist/blob/main/src/main/utils/configPaths.ts) (line 94), and updated via `picgo.setConfig` when users toggle plugins in the interface, with changes synchronized through the `PICGO_TOGGLE_PLUGIN` event.