Hot-reloadable plugin-based UI platform
npm install @bytespell/shellaA 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.
``
┌─────────────────────────────────────────────────────────────────────────────┐
│ 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 │ │
│ │ └─... │ │ └─... │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
`
1. 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.
2. Plugin Discovery: Any directory with a package.json is treated as a plugin. The daemon runs npm install if needed, allocates a port, and spawns a plugin instance.
3. Multi-Instance Support: Each plugin can have multiple concurrent instances. Each POST /plugins/:name/start spawns a new instance with its own port and process ID.
4. 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.
5. Remote Rendering: Clients connect directly to plugin instances (ports 47101-47199) to render/use their functionality. The daemon API provides instance URLs.
6. Management: Clients use the daemon's REST API to list plugins, start new instances, or stop specific instances.
`bash`
npm install
npm run build
`bashProduction
npm start
$3
| 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.
$3
| 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 |$3
`bash
curl http://localhost:47100/plugins
``json
{
"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"
}
]
}
]
}
`$3
`bash
curl -X POST http://localhost:47100/plugins/my-plugin/start
``json
{
"success": true,
"instance": {
"id": "3",
"status": "running",
"port": 47103,
"pid": 12347,
"url": "http://localhost:47103"
}
}
`$3
`bash
curl -X POST http://localhost:47100/plugins/my-plugin/instances/1/stop
``json
{
"success": true
}
`Creating a Plugin
Use
shella-init to scaffold a new plugin:`bash
Express + static serving (default)
shella-init my-pluginVite + React + shadcn/ui (with HMR)
shella-init my-plugin --template shadcn
`For shadcn template, run
npm install after creation:
`bash
cd ~/.local/share/shella/plugins/my-plugin
npm install
`The 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.
$3
Alternatively, create a plugin manually:
1. Create a directory in
~/.local/share/shella/plugins/
2. Add a package.json with "main": "index.js" (or your entry file)
3. Create an Express/HTTP server that listens on process.env.PORT`javascript
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
`bash
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 mode
``MIT