@bytespell/shella
v0.2.2
Published
Hot-reloadable plugin-based UI platform
Maintainers
Readme
Shella Plugin Daemon
A daemon for managing Shella Express.js plugins. It automatically discovers, starts, and manages plugin processes, allowing external clients to deploy and interact with plugin servers remotely.
How It Works
┌─────────────────────────────────────────────────────────────────────────────┐
│ External Clients │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Client A │ │ Client B │ │ Client C │ │
│ │ (UI/App) │ │ (UI/App) │ │ (Deployer) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
└──────────┼──────────────────┼──────────────────┼────────────────────────────┘
│ │ │
│ Render/Use │ Render/Use │ Deploy Plugin
│ Plugin Server │ Plugin Server │ (drop into ~/.local/share/shella/plugins)
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ Shella Daemon (port 47100) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ REST API │ │ Plugin │ │ Plugin │ │ │
│ │ │ /plugins │ │ Manager │ │ Watcher │ │ │
│ │ │ /health │ │ │ │ (fs.watch) │ │ │
│ │ └─────────────┘ └─────────────┘ └──────┬──────┘ │ │
│ │ │ │ │ │ │
│ │ │ │ │ Auto-detect │ │
│ │ │ │ │ new plugins │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ Port Allocator │ │ │
│ │ │ (ports 47101-47199) │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ Plugin Instances │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Plugin A │ │ Plugin A │ │ Plugin B │ ... │ │
│ │ │ Instance 1 │ │ Instance 2 │ │ Instance 1 │ │ │
│ │ │ :47101 │ │ :47102 │ │ :47103 │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ Express.js │ │ Express.js │ │ Express.js │ │ │
│ │ │ Server │ │ Server │ │ Server │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ ▲ ▲ ▲ │ │
│ └─────────┼─────────────────┼─────────────────┼───────────────────────┘ │
│ │ │ │ │
│ │ HTTP │ HTTP │ HTTP │
│ │ Requests │ Requests │ Requests │
└─────────────┼─────────────────┼─────────────────┼────────────────────────────┘
│ │ │
└────────┬────────┴────────┬────────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Client A │ │ Client B │
│ Rendering │ │ Rendering │
│ Plugin UI │ │ Plugin UI │
└─────────────┘ └─────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│ ~/.local/share/shella/plugins/ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ plugin-a/ │ │ plugin-b/ │ │ plugin-c/ │ (auto-detected) │
│ │ ├─package.json │ ├─package.json │ ├─package.json │
│ │ ├─index.js │ │ ├─index.js │ │ └─index.js │ │
│ │ └─... │ │ └─... │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘Flow
Daemon Startup: The daemon starts on port 47100, scans
~/.local/share/shella/plugins/for existing plugins, starts one instance of each, and begins watching for changes.Plugin Discovery: Any directory with a
package.jsonis treated as a plugin. The daemon runsnpm installif needed, allocates a port, and spawns a plugin instance.Multi-Instance Support: Each plugin can have multiple concurrent instances. Each
POST /plugins/:name/startspawns a new instance with its own port and process ID.Client Deployment: External clients can deploy new plugins by copying a directory into
~/.local/share/shella/plugins/. The watcher detects it and automatically starts an instance.Remote Rendering: Clients connect directly to plugin instances (ports 47101-47199) to render/use their functionality. The daemon API provides instance URLs.
Management: Clients use the daemon's REST API to list plugins, start new instances, or stop specific instances.
Installation
npm install
npm run buildUsage
Start the Daemon
# Production
npm start
# Development (with hot reload)
npm run devEnvironment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| SHELLA_PLUGINS_DIR | ~/.local/share/shella/plugins | Directory to scan for plugins |
| XDG_DATA_HOME | ~/.local/share | Base directory for user data (plugins) |
| XDG_STATE_HOME | ~/.local/state | Base directory for state data (registry) |
| LOG_LEVEL | info | Logging level (debug, info, warn, error) |
| NODE_ENV | - | Set to production for JSON logs |
The daemon follows the XDG Base Directory Specification. Registry state is stored at ~/.local/state/shella/registry.json.
REST API
The daemon exposes a REST API on port 47100.
Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /health | Health check (returns pid, uptime) |
| GET | /plugins | List all plugins with their instances |
| GET | /plugins/:name | Get single plugin details |
| POST | /plugins/:name/start | Start a new instance of a plugin |
| POST | /plugins/:name/instances/:id/stop | Stop a specific instance |
| GET | /registry | Get full registry data |
Example: List Plugins
curl http://localhost:47100/plugins{
"plugins": [
{
"name": "my-plugin",
"displayName": "My Plugin",
"path": "/home/user/.local/share/shella/plugins/my-plugin",
"main": "index.js",
"instances": [
{
"id": "1",
"status": "running",
"port": 47101,
"pid": 12345,
"url": "http://localhost:47101"
},
{
"id": "2",
"status": "running",
"port": 47102,
"pid": 12346,
"url": "http://localhost:47102"
}
]
}
]
}Example: Start a New Instance
curl -X POST http://localhost:47100/plugins/my-plugin/start{
"success": true,
"instance": {
"id": "3",
"status": "running",
"port": 47103,
"pid": 12347,
"url": "http://localhost:47103"
}
}Example: Stop an Instance
curl -X POST http://localhost:47100/plugins/my-plugin/instances/1/stop{
"success": true
}Creating a Plugin
Use shella-init to scaffold a new plugin:
# Express + static serving (default)
shella-init my-plugin
# Vite + React + shadcn/ui (with HMR)
shella-init my-plugin --template shadcnFor shadcn template, run npm install after creation:
cd ~/.local/share/shella/plugins/my-plugin
npm installThe daemon auto-detects new plugins. Shadcn plugins run in dev mode with Vite HMR - edit files and see changes instantly. APIs work in both dev and production modes.
Manual Setup
Alternatively, create a plugin manually:
- Create a directory in
~/.local/share/shella/plugins/ - Add a
package.jsonwith"main": "index.js"(or your entry file) - Create an Express/HTTP server that listens on
process.env.PORT
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.json({ message: 'Hello from my plugin!' });
});
app.listen(process.env.PORT);The daemon will automatically detect and start your plugin.
Instance Status
| Status | Description |
|--------|-------------|
| stopped | Instance is not running |
| starting | Instance process is spawning |
| running | Instance is running and healthy |
| crashed | Instance exited unexpectedly |
| installing | Running npm install for the plugin |
Ports
| Port | Usage | |------|-------| | 47100 | Daemon API | | 47101-47199 | Plugin instances (dynamically allocated) |
Development
npm run lint # Check code style
npm run lint:fix # Auto-fix issues
npm run typecheck # Type check
npm run test # Run tests
npm run test:watch # Watch modeLicense
MIT
