Skip to content

Added Plugins Menu Item#1267

Open
Nirflysher wants to merge 1 commit intokando-menu:mainfrom
Nirflysher:main
Open

Added Plugins Menu Item#1267
Nirflysher wants to merge 1 commit intokando-menu:mainfrom
Nirflysher:main

Conversation

@Nirflysher
Copy link
Copy Markdown

Kando Plugin System - Implementation Status

Live Documentation of All Changes


Overview

This document tracks all implementation changes made to integrate the Plugin System into Kando. It serves as a comprehensive guide for completing the fork and submitting a PR.
image


✅ Phase 1: Core Infrastructure (COMPLETE)

1. Plugin Manifest Parser

File: src/common/plugin-manifest.ts

Status: ✅ Implemented

Provides TypeScript interfaces and validation:

  • IPluginManifest - Main manifest interface
  • IPluginWindowConfig - BrowserWindow configuration
  • IPluginParameter - Union type for all parameter types
  • IPluginParameterString, IPluginParameterNumber, IPluginParameterBoolean, IPluginParameterSelect, IPluginParameterFile, IPluginParameterFolder, IPluginParameterPassword
  • validateManifest(json) - Validates manifest structure
  • getWindowConfigWithDefaults() - Applies default window settings
  • DEFAULT_WINDOW_CONFIG - Sensible defaults for plugin windows

2. Plugin Manager

File: src/main/plugins/plugin-manager.ts

Status: ✅ Implemented

Core plugin management singleton:

  • getInstance() - Singleton access
  • getPluginsDirectory() - Platform-specific path resolution
    • Windows: %APPDATA%/kando/plugins/
    • macOS: ~/Library/Application Support/kando/plugins/
    • Linux: ~/.config/kando/plugins/
  • scanPlugins() - Discovers and validates all plugin folders
  • validatePlugin(path) - Checks manifest and required files
  • getPluginManifest(id) - Returns parsed manifest
  • importPluginFromZip(zipPath) - Extracts and validates ZIP
  • removePlugin(id) - Deletes plugin folder
  • getPluginConfig(id) - Loads user configuration
  • savePluginConfig(id, config) - Persists user configuration

3. Plugin Config Storage

File: src/main/plugins/plugin-config-store.ts

Status: ✅ Implemented

Stores user-defined parameter values:

  • Config location: ~/.config/kando/plugin-configs/{plugin-id}.json
  • loadConfig(pluginId) - Load with defaults from manifest
  • saveConfig(pluginId, config) - Persist configuration
  • validateConfig(config, manifest) - Validate against schema
  • Handles migration when plugin updates change parameters

4. ZIP Handler Utility

File: src/main/plugins/zip-handler.ts

Status: ✅ Implemented

Dependency: adm-zip (must be installed in Kando)

ZIP file operations:

  • extractZip(zipPath, destFolder) - Extract ZIP contents
  • validateZipContents(zipPath) - Check for manifest before extracting
  • listZipContents(zipPath) - List all files in ZIP
  • readFileFromZip(zipPath, filePath) - Read specific file without extraction

5. Plugin Item Type

File: src/common/item-types/plugin-item-type.ts

Status: ✅ Implemented

Defines the "plugin" item type for Kando menus:

  • typeId: 'plugin'
  • defaultName: 'Plugin'
  • defaultIcon: 'extension'
  • defaultIconTheme: 'material-symbols-rounded'
  • PluginItemData: { pluginId: string }

6. Plugin Item Action

File: src/main/item-actions/plugin-item-action.ts

Status: ✅ Implemented

Executes plugins when triggered from menu:

  • Implements Kando's ItemAction interface
  • execute(item) - Main execution method
  • delayedExecution() - Returns false for immediate launch
  • Creates isolated BrowserWindow with manifest settings
  • Injects user config via additionalArguments
  • Fire-and-forget execution model

7. IPC Handlers

File: src/main/plugins/ipc-handlers.ts

Status: ✅ Implemented

Bridges main process to renderer:

  • plugins:get-list - Returns list of installed plugins
  • plugins:import - Imports plugin from ZIP path
  • plugins:remove - Removes installed plugin
  • plugins:get-config - Gets plugin configuration
  • plugins:save-config - Saves plugin configuration
  • registerPluginIPCHandlers() - Registration function

8. Module Exports

File: src/main/plugins/index.ts

Status: ✅ Implemented

Exports all plugin system components:

export { PluginManager } from './plugin-manager';
export type { IPluginInfo, IPluginImportResult } from './plugin-manager';
export { PluginConfigStore } from './plugin-config-store';
export { extractZip, validateZipContents, listZipContents, readFileFromZip } from './zip-handler';
export type { IZipValidationResult } from './zip-handler';
export { registerPluginIPCHandlers } from './ipc-handlers';
export type { IPluginListItem } from './ipc-handlers';

File: src/common/index.ts

Status: ✅ Implemented

Exports common types:

export type { IPluginManifest, IPluginWindowConfig, IPluginParameter, IPluginParameterString, IPluginParameterNumber, IPluginParameterBoolean, IPluginParameterSelect, IPluginParameterFile, IPluginParameterFolder, IPluginParameterPassword, IManifestValidationResult } from './plugin-manifest';
export { DEFAULT_WINDOW_CONFIG, validateManifest, getWindowConfigWithDefaults } from './plugin-manifest';
export { PluginItemType } from './item-types/plugin-item-type';
export type { PluginItemData, ItemType } from './item-types/plugin-item-type';

✅ Registration Changes (COMPLETE)

Item Type Registry

File: src/common/item-type-registry.ts

Required Change:

import { PluginItemType } from './item-types/plugin-item-type';

// In constructor or init method:
this.types.set('plugin', new PluginItemType());

Item Action Registry

File: src/main/item-action-registry.ts

Required Change:

import { PluginItemAction } from './item-actions/plugin-item-action';
import { PluginManager } from './plugins';

// In constructor or init method:
this.actions.set('plugin', new PluginItemAction(PluginManager.getInstance()));

Main Process Initialization

File: src/main/index.ts

Required Change:

import { PluginManager, registerPluginIPCHandlers } from './plugins';

// After kando.init():
kando.init().then(async () => {
  // ... existing init code ...
  
  // Initialize plugin system
  const pluginManager = PluginManager.getInstance();
  await pluginManager.scanPlugins();
  registerPluginIPCHandlers();
  
  console.log('Plugin system initialized');
});

✅ Phase 2: Settings UI (IN PROGRESS)

1. Settings Window API Extension

File: src/settings-renderer/settings-window-api.ts

Required Addition to SETTINGS_WINDOW_API:

// Plugin management methods
getPlugins: () => ipcRenderer.invoke('plugins:get-list'),
importPlugin: (zipPath: string) => ipcRenderer.invoke('plugins:import', zipPath),
removePlugin: (pluginId: string) => ipcRenderer.invoke('plugins:remove', pluginId),
getPluginConfig: (pluginId: string) => ipcRenderer.invoke('plugins:get-config', pluginId),
savePluginConfig: (pluginId: string, config: Record<string, unknown>) => 
  ipcRenderer.invoke('plugins:save-config', pluginId, config),

2. Plugin Item Config Component

File: src/settings-renderer/components/menu-properties/item-configs/PluginItemConfig.tsx

Status: ✅ Implemented

Key Implementation Notes:

  • All React hooks (useState, useEffect) must be at the TOP of the component, before any conditional returns
  • Uses local PluginTip wrapper to avoid crashes if native RandomTip fails
  • Async API calls wrapped in try-catch within useEffect
  • Matches Kando's existing UI patterns

3. Item Config Registry Update

File: src/settings-renderer/components/menu-properties/item-configs/index.tsx

Required Change:

import { PluginItemConfig } from './PluginItemConfig';

// In getConfigComponent function:
const components: Record<string, React.ComponentType<ItemConfigProps>> = {
  // ... existing entries ...
  plugin: PluginItemConfig,
};

4. CSS Fix for Toolbar Alignment

File: src/settings-renderer/components/menu-preview/PreviewFooter.module.scss

Status: ✅ Fix Identified

Problem: The 10th item (plugin icon) wraps to a new line due to fixed-width constraints.

Solution: Update .newItems to use Flexbox:

.newItems {
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  gap: 8px;
  padding: 10px;
  overflow-x: auto;
}

✅ Localization (COMPLETE)

Translation Keys

File: locales/en/translation.json

Required Addition:

{
  "menu-items": {
    "plugin": {
      "name": "Plugin",
      "description": "Execute an external plugin application.",
      "placeholder": "Select a plugin...",
      "loading": "Loading plugins...",
      "no-plugins": "No plugins installed. Import a plugin ZIP file to get started.",
      "tip-1": "Plugins extend Kando with custom functionality.",
      "tip-2": "You can import plugins from ZIP files.",
      "tip-3": "Each plugin runs in its own isolated window."
    }
  }
}

Note: RandomTip component expects numbered keys (tip-1, tip-2, tip-3), NOT a tips array.


📦 Dependencies

Required npm Packages

Package Purpose
adm-zip ZIP file extraction and validation
@types/adm-zip TypeScript definitions

Install in Kando:

npm install adm-zip
npm install -D @types/adm-zip

🧪 Test Plugin

Hello World Plugin

Location: docs/test-plugins/hello-world/

Files:

  • kando-plugin.json - Manifest with sample parameters
  • index.html - Simple test UI

Installation Path (Windows):

%APPDATA%\kando\plugins\hello-world\

📁 File Summary

File Type Status
src/common/plugin-manifest.ts New ✅ Complete
src/common/item-types/plugin-item-type.ts New ✅ Complete
src/common/index.ts New ✅ Complete
src/main/plugins/plugin-manager.ts New ✅ Complete
src/main/plugins/plugin-config-store.ts New ✅ Complete
src/main/plugins/zip-handler.ts New ✅ Complete
src/main/plugins/ipc-handlers.ts New ✅ Complete
src/main/plugins/index.ts New ✅ Complete
src/main/item-actions/plugin-item-action.ts New ✅ Complete
src/common/item-type-registry.ts Modify 📝 Pending
src/main/item-action-registry.ts Modify 📝 Pending
src/main/index.ts Modify 📝 Pending
src/settings-renderer/settings-window-api.ts Modify 📝 Pending
src/settings-renderer/.../PluginItemConfig.tsx New ✅ Complete
src/settings-renderer/.../item-configs/index.tsx Modify 📝 Pending
src/settings-renderer/.../PreviewFooter.module.scss Modify ✅ Fix Ready
locales/en/translation.json Modify 📝 Pending

🔒 Security Model

  • Plugins explicitly installed by user (trust model)
  • Each plugin runs in isolated BrowserWindow
  • nodeIntegration: false by default
  • contextIsolation: true by default
  • File/folder pickers use Electron's secure dialogs
  • Password parameters stored with OS keychain integration (future)

🐛 Known Issues & Solutions

Issue: Settings window grey/blank screen

Cause: React hooks called conditionally, breaking Rules of Hooks
Solution: Move ALL useState/useEffect to top of component, before any conditional returns

Issue: Plugin icon not aligned in toolbar

Cause: CSS grid/inline-block constraints limiting to 9 items
Solution: Change .newItems to flexbox layout

Issue: RandomTip crashes with plugin tips

Cause: Component expects tip-1, tip-2 keys, not array
Solution: Use numbered keys in translation.json


🚀 Next Steps

  1. Complete Settings API integration in Kando fork
  2. Add "Import Plugin" button to toolbar
  3. Implement dynamic parameter form in PluginItemConfig
  4. Test end-to-end with Hello World plugin
  5. Submit PR to Kando repository

@yar2000T
Copy link
Copy Markdown
Contributor

Hello, this is a pretty cool feature, but I think it would need to be implemented as a global plugin system. With such a system, you could not only use custom items, but also add new settings, change the menu layout, etc. That said, this is just my personal opinion. For a deeper analysis, you would need @Schneegans help.

@Nirflysher
Copy link
Copy Markdown
Author

Hi @yar2000T ,
Thank you for your feedback.
This is only ohase 1 of my plan to implement this as a general plugin system.
I'm currently collecting feedback on which types of plugins would users will want to create.
I've also send Simon a note and will be awaiting his professional comments and insights before moving forward.
The goal is to be able to run Electron apps (that can be easily generated using modern AIs) natively within Kando while leveraging the same Backend-Chromium infrastructure of Electron and Node.js to achieve super fast loading times.

@Schneegans
Copy link
Copy Markdown
Contributor

Thanks a ton for the initiative!

Yet, overall, I am a bit hesitant. I think this adds something to Kando which is really not in it's scope. Kando is a pie menu, not a framework to build apps on top. Why should these plugins be part of Kando? Is there any benefit from being part of Kando (except for using the same technology stack, which is not really a good reason)?

Because something can be done it does not necessarily should be done. I think, the functionality you suggest is 100% decoupled from Kando. Yet it introduces several thousands lines of code which need to maintained and which potentially bring bugs and security issues.

In my opinion, it would be much better to put the functionality you are envisioning here into a separate (electron?) app. Then you could simply use ordinary run-command items in Kando to open this separate app. Something like .\mini-webview C:\path\to\my\app.html. Maybe a tool like this already exists even.


That being said, I think Kando does indeed need a plugin system. Yet this should bring the possibility to augment the possibilities of the menu itself and not display websites on top.

Kando Plugins (as I imagine them)

Currently, we have a fixed set of menu items. In my opinion, the main purpose of plugins should be to add new menu-item types which are designed for a very specific purpose or which are platform-dependent. Like for instance a submenu which automatically lists all running applications on Windows. Or a submenu which shows all dock items on macOS. Or items which interact via some sort of IPC mechanism with some specific applications which can not easily be controlled via simulated keyboard shortcuts.

We could even think about menu item types which are not only simple buttons. We should have checkbox-like items, sliders for numeric input, maybe color choosers or date pickers. But I'm not sure whether those should come in the form of plugins or rather in core Kando as they will need to be themed by menu themes.


What do you think? Do you understand my point?

@yar2000T
Copy link
Copy Markdown
Contributor

Thanks a ton for the initiative!

Yet, overall, I am a bit hesitant. I think this adds something to Kando which is really not in it's scope. Kando is a pie menu, not a framework to build apps on top. Why should these plugins be part of Kando? Is there any benefit from being part of Kando (except for using the same technology stack, which is not really a good reason)?

Because something can be done it does not necessarily should be done. I think, the functionality you suggest is 100% decoupled from Kando. Yet it introduces several thousands lines of code which need to maintained and which potentially bring bugs and security issues.

In my opinion, it would be much better to put the functionality you are envisioning here into a separate (electron?) app. Then you could simply use ordinary run-command items in Kando to open this separate app. Something like .\mini-webview C:\path\to\my\app.html. Maybe a tool like this already exists even.

That being said, I think Kando does indeed need a plugin system. Yet this should bring the possibility to augment the possibilities of the menu itself and not display websites on top.

Kando Plugins (as I imagine them)

Currently, we have a fixed set of menu items. In my opinion, the main purpose of plugins should be to add new menu-item types which are designed for a very specific purpose or which are platform-dependent. Like for instance a submenu which automatically lists all running applications on Windows. Or a submenu which shows all dock items on macOS. Or items which interact via some sort of IPC mechanism with some specific applications which can not easily be controlled via simulated keyboard shortcuts.

We could even think about menu item types which are not only simple buttons. We should have checkbox-like items, sliders for numeric input, maybe color choosers or date pickers. But I'm not sure whether those should come in the form of plugins or rather in core Kando as they will need to be themed by menu themes.

What do you think? Do you understand my point?

Personally, I love idea about a plugins folder next to the menu themes folder, in which i can paste folders with code (typescript) and config file which defines properties of plugin (name, version, author, kando version). It will be loaded on start. I dont really know if its possible to side load code.

@yar2000T
Copy link
Copy Markdown
Contributor

It can be plugins like in flow launcher

@Nirflysher
Copy link
Copy Markdown
Author

Hi @Schneegans , @yar2000T ,

Thank you very much for your feedback.
I see Kando as much more than just a menu. It's an modern, highly flexible and agile launcher.
You have been able to implement beautifully many features I always dreamed on having.

I've started to develop some extensions to ease repetitive activities I'm doing at work and found out that the only way to add these additional functionalities was by creating a thin mini-apps in c++, compile them to exe and "run" them with Kando.
While this was exciting initially, I soon got my appetite and wanted to extend it even more to allow AI functionalities like "Rephrase", "Reject the idea respectfully", "summarize the main ideas" that will essentially "copy" highlighted text, send it any any LLM through API call along with a user defined prompt (similar to what Grammarly is doing today) and suggest the user a small window with the result allowing him to paste it with 1-click.

A different ability I wanted to add is the ability to communicate with other web services via REST API commands, fetching information from external data sources and presenting them to the user. For example stock exchange information.

I soon found out that creating separate exe for each functions didn't make sense, especially if I wanted the applications to have a nice and modern UI. Application size grew significantly, I had to suffer long loading times that resulted from loading the whole framework.

The ability of Electron to run separate application on different threads while avoiding loading times as both chromium and the backend are already initialized seemed as a very interesting approach.

While the first phase only loads html my final goal is to enable the Kando launch custom Electron applications on separate threads.
Another advantage of a flexible plugin system approach is that users will be able to very easily generate their own stand-alone vibe coded plugins using Lovable, Cursor or Base44. Applications that will be able to launch very quickly and leverage the same Electron infrastructure that is already loaded in memory.

I expect such functionality to be very attractive to many new users and will be happy to help on the definition, programming and testing.

With regards to the exact implementation of the plugins I'm not sure that html plugins are indeed the optimal approach however this was just for me to be able to quickly test the infrastructures.

To summarize, my main question is whether you be interested in enabling external plugins system to Kando allowing users to run Electron native mini-apps that will be able to communicate with external applications and databases ?

Regards,
Nir

@Schneegans
Copy link
Copy Markdown
Contributor

Thank you so much for your elaborate response! Your vision is now much clearer to me.
I absolutely see the value in what you are proposing, and I agree that having a way to run something like simple apps or maybe just scripts that can interact with external services would be a great addition to Kando.

Yet I still think that these apps are not really plugins in the traditional sense, as they don't extend Kando itself, but rather run alongside it. In fact, I think the only reason to make them "plugins" is to leverage Kando's existing infrastructure (e.g. Electron runtime) which may reduce loading times and memory usage. But at the same time, this also means that these apps would be tightly coupled to Kando, and need to be updated when electron changes...

Let's take a step back and consider the bigger picture, without focusing too much on the runtime. What if those apps were just standalone commandline tools that users drop into a "kando-apps" folder next to the "menu-themes" and "icon-themes"? We would define a metadata format (e.g. JSON) that describes the app's name, description, input parameters (like user-configurable options or context information like the clipboard content). Then Kando could be extended with a menu item that lists all discovered apps the same way it lists plugins in your current implementation.

We could create a new repository called "Kando Apps" with some example apps. The awesome thing about this approach is that these apps would not be tied to Kando at all, and could potentially be used by other launchers or even run standalone! This could potentially widen the user base and attract more developers to create apps for Kando. And it would be even simpler to create them using AI :)

Now back to the runtime question. I think it would be best to not force a specific runtime like Electron on these apps. Instead, the only requirement would be that they can be executed from the commandline. This way, developers could choose whatever technology they prefer (e.g. Python scripts, Node.js apps, compiled binaries, etc.). Kando would just need to handle launching them and passing the necessary input parameters. Either via commandline arguments or environment variables.

Only problem I see with this approach is that showing a custom UI for the apps would be more challenging, but definitely not impossible. I guess in many cases, no UI would be needed at all. And a simple message dialog will be supportable by most scripting languages.

What do you think about this idea?

@Nirflysher
Copy link
Copy Markdown
Author

Hi Simon, Yar,
I took the day to think on your thoughts and I completely agree with you. The application that we're envisioning are not part of the Kando menu itself. A repository of Kando-apps that are independent of Kando indeed feels to be a better way forward.

Nevertheless we will need to have some kind of mechanism within Kando that will enable designers to write mini-apps that will be able to run efficiently. I'm not sure that the current "Run command" will be sufficient as many of the mini-apps will want to address content that is being shown on the active window.
I loved your idea of having a separate JSON that we will define that will be accompanied to each Kando-app and will enable easy parameters injection to the app.

In the example above of an AI agent that helps rephrase text a user will need to copy the text and send it along with a prompt through RESTI API and present the respond in separate window. While it's easy to create a small app that will trigger the "clipboard copy" command and process it, the part that takes relatively long time is to initiate a modern user interface, especially if we would like to design a cross-platform app. We will probably need open text fields like "URI", "Auth Token", "Prompt" that can be defined on the json scheme.
image
This is a small idea of how I was thinking on it - it has 4 options "Rephrase more clearly", "Summarize in bullets", "Decline respectly", and "Propose a different idea".

Would you like to add an option for running Kando app that will receive a json in the format that we will define and parse the parameters for the CLI app ?
I'll probably want to have a first demo that will be integrating with Ollama AI model.

Another approach could be to ask the designer to just pack everything in one exe - maybe like a Tauri app that will be called through the "Run command" feature and ask him to take care of all the rest. The drawback on this approach is that it will be less flexible to configure.

Regards,
Nir.

@Schneegans
Copy link
Copy Markdown
Contributor

I think we are getting somewhere! First, let me explain my idea more clearly. Then, I'll tell you about another idea - I think we could combine our approach here with the original plugin concept about new menu types which I outlined above!

Example Kando App Manifest

For the Ollama agent idea, I thought about the following structure for a json manifest file. For instance, this file could be called manifest.json and could be placed next to a ollama_agent.py in kando-apps/ollama-agent.

{
  name: "Ollama Agent",
  description: "Interact with the Ollama API",
  exec: "ollama_agent.py",
  context: {
    OLLAMA_SELECTED_TEXT: "{{selected_text}}",
  },
  options: {
    OLLAMA_API_KEY: {
      type: "string",
      label: "Ollama API Key",
    },
    OLLAMA_API_URL: {
      type: "string",
      label: "Ollama API URL",
      default: "http://localhost:11434",
    },
    OLLAMA_TASK: {
      type: "enum",
      label: "Task",
      options: [
        { value: "rephrase", label: "Rephrase more clearly" },
        { value: "summarize", label: "Summarize in bullets" },
        { value: "decline", label: "Decline respectfully" },
        { value: "propose", label: "Propose a different idea" },
      ],
      default: "rephrase",
    },
  },
}

The idea would be that all keys in the context section would become available as environment variables when the ollama_agent.py script is executed by Kando. So in this example, the currently selected text when the user triggered the menu item would be available as OLLAMA_SELECTED_TEXT environment variable.

The options section would define configuration options that are available in the menu editor UI when the user adds this app to a menu. So imagine text entries and dropdowns for "Ollama API Key", "Ollama API URL", and "Task" in the following screenshot:

image

Kando would generate those widgets based on the JSON file and also provide the configured values as environment variables when executing the script.

Now the only thing the ollama_agent.py script would need to do after the API call to Ollama would be to show a dialog with the result. But this should be easy to do with Python or any other language.

However, continue reading, because I have another idea which could make this even easier!

Menu-Item Type Plugins

With this Kando-App idea, an app would always be a single menu item in the menu. So to achieve what you showed in your screenshot with multiple items, the user would need to add multiple instances of the Ollama Agent app to the menu, each with a different "Task" option selected.

While this is not bad in this example, it would not work for dynamic menu items. I'm thinking for instance about a menu item which acts like a submenu with entries automatically generated for all apps in your Windows task bar. Or something like an Alt-Tab window switcher. To create something like this, we would need an alternative plugin-based approach where a plugin can define a new type of menu item.

However, I think the border between both ideas is somewhat blurry. When should I create a Kando App with multiple options, and when should I create a Menu-Item Type plugin?

Combining Kando Apps and Menu-Item Type Plugins

So for users and developers, it would be great if both concepts could be combined. But how could this work? How could a Kando App define how it should appear in the menu, possibly with multiple entries?

My idea is that a Kando App manifest could optionally define a special script to generate menu entries dynamically. This will be called when the user opens the menu, and the script would output JSON data defining the menu entries to show. So a manifest.json could look like this:

{
  name: "Task Switcher",
  description: "Show running apps",
  init: "task_switcher.py --generate-menu",
  exec: "task_switcher.py --select",
  context: {
    SELECTED_ITEM: "{{selected_menu_item_name}}",
  },
  options: {
    SWITCHER_ONLY_ACTIVE: {
      type: "boolean",
      label: "Only show apps from active workspace",
      default: true,
    },
  },
}

The init key would define a script to generate menu entries dynamically. When the user opens the menu, Kando would execute task_switcher.py --generate-menu, and the script would output a menu structure in JSON format. Kando would use this to generate the menu on-the-fly. Then, when the user selects an entry, Kando would execute task_switcher.py --select with the selected item name available as SELECTED_ITEM environment variable.

If the init key is not defined, Kando would just create a single menu item as before.

Thinking Further

Now what if the exec script could also return structured data? Maybe we could define a standard way for Kando to parse the output of the script and do something with it. Like showing a notification, copying to clipboard, or even showing a dialog with formatted text?

Then using custom UI libraries could be avoided for simple use cases!

Conclusion

What do you think about these ideas? I think if we combine both concepts, we could again call this "Kando Plugins", but now with a more unified approach which allows both simple apps and more complex menu item types.

Sorry for the long text, but I fear that some of these ideas are still not 100% clear. Feel free to ask if you have questions or want me to clarify something!

@Nirflysher
Copy link
Copy Markdown
Author

Nirflysher commented Jan 31, 2026

Hi Simon,
This brainstorming is exciting and is also the most important part I see in such plugin-system project.
This is also the reason I stopped right after creating a basic plugin 'shell'.

I fully understood your first part and agree that each Kando-app should have it's own json manifest.
This is the same approach I used on the current proposed plugin system idea.

For example:
This is the json manifest for the "Hello-world" plugin in which the Kando opens a window but the content is actually populated by the web-app (in this case it's a simple html). In this approach we can both decouple the Kando-app from the Kando-menu while still using the same chromium and node.js to render additional web-apps on using a different thread independent of the Kando-menu.

{
  "id": "hello-world",
  "name": "Hello World",
  "description": "A simple test plugin to verify the Kando plugin system.",
  "version": "1.0.0",
  "author": "Kando Team",
  "window": {
    "width": 400,
    "height": 300,
    "frame": true
  },
  "parameters": {
    "greeting": {
      "type": "string",
      "title": "Greeting Message",
      "description": "The message to display when the plugin runs.",
      "default": "Hello from Kando!"
    },
    "showTimestamp": {
      "type": "boolean",
      "title": "Show Timestamp",
      "description": "Whether to display the current time.",
      "default": true
    }
  }
}

kando-plugin.json
index.html
These two files are the full "Hello-world" mini-app. Maybe I was wrong to call it plug-in while it's just a mini-app called Hello-world + a plugin engine for Kando that runs it.
I still think that if the Kando will only open the window while the content will be populated by the Kando-app it should be sufficiently independent. Won't you agree ?

Nevertheless, even this approach doesn't really resolve the full use case we started discussing above of having a sufficiently flexible plugin engine to allow users to easily create an Ollama plugin.

After selecting the Kando-Ollama app on the configuration menu the user will need to define the URI, then we will want to send a cmd like "Ollama list" to retrieve all the currently installed models and allow the user to select one for the current menu item along with a prompt open-text field.
To allow such functionality we will need to have a plugin-menu-pre-loading json manifest in which the user could executes simple commands like "Copy highlighted text", "Run command..." like "Ollama list" parse the returned results and display them to the use as a text box.
Alternatively, maybe this can be a mini-app on it's own that runs the Ollama list, allows the user to select the right model/prompt and create the final Kando-ollama json that the main Kando-apps system will be able to call.

To summarize,
I feel the idea you've proposed is very similar to what I've started to implement. A plugin engine (part of Kando) using a json manifest to render the kando-plugins-config-menu + decoupled Kando-apps (can be web-apps or any other compiled app)

I want to think of it a bit more...
I will also be happy to better understand your initial hesitation of implementing a plugin-engine like I was suggesting.

Regards,
Nir.

@Schneegans
Copy link
Copy Markdown
Contributor

Thanks for your thoughts! I think we are mostly on the same page, but there are a few differences in our approaches. The most important one is that I hope that we can make these plugins powerful enough without adding the possibility to create custom windows with custom UI. In my opinion, this would go way beyond the original vision of Kando as a simple, fast, and efficient menu system. I fear that if we allow plugins to create custom windows, we would end up with a situation where every plugin creates its own UI and user experience, which could lead to a very inconsistent and fragmented user experience. And most importantly, efficiency and speed are core to Kando's vision. Kando actions should be things that you do dozens maybe even hundreds of times a day. So it's not a good idea if an action opens a new window where you have to press another button or to copy something to the clipboard. This is 100% against the idea of having a seamless and efficient workflow.

So the ideal plugin in my vision would be something that you configure once, and then it just works with a single click in the menu. For instance, the Ollama plugin could be configured to take the currently selected text, send it to Ollama with a predefined prompt, and then automatically copy the result to the clipboard and show a notification once it's done. No additional windows, no additional clicks, just a seamless extension of the menu's functionality.

Of course, there might be some use cases where some additional UI is necessary, but I think we should try to avoid this as much as possible. The architecture I proposed with the JSON manifest and environment variables should be powerful enough to open custom dialogs if really needed. But the main focus should be on creating plugins that work seamlessly within the existing menu structure without the need for additional windows or complex interactions.

I think many use-cases could be addressed with the approach I outlined above. However, the model list which you mentioned for the Ollama plugin is indeed a tricky thing. I think the only solution would be a free-formed text field where the user can enter the model name. Alternatively we would need plugin code to generate the menu-item configuration UI dynamically and this would add a lot of complexity to the plugin system. So I would prefer to avoid this if possible. I think 90% of the use-cases will be covered with the JSON manifest listing predefined options.

What do you think about this? Is my idea mostly clear? Else I could try to explain it in more detail.

@Nirflysher
Copy link
Copy Markdown
Author

Hi Simon,
I understand you've worked hard to optimize the Kando for responsiveness.
Are you concerned that adding functionality to show custom menus/windows for these plugins/apps or running stand alone Electron apps that will share the same backend will interfere with the current operation ?

I think that we're aligned regarding the JSON manifest functionality.
The only thing we need to define is which functionality we would like to include on the JSON.

By the way, it will be possible to implement the Ollama functionality above either with python support or worst case scenario I can create a small Tauri executable and just invoke it with the "Run" command.
The standalone Tauri app will trigger "Copy" command, load the gui on one thread that will load and wait for the Ollama, while sending the copied text to Ollama on a different thread. When the Ollama will start streaming text it will be shown on the gui and allow the user to accept the revised text with 1-click.

Let me know what you want to do,
I'm on board if you need any help with it.

Regards,
Nir.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants