# Hermes plugin architecture
Every Hermes dashboard plugin is **four files**:
```
my-plugin/
└── dashboard/
├── manifest.json # metadata
├── plugin_api.py # FastAPI router
└── dist/
└── index.js # React component (no build step)
```
Drop the folder into `~/.hermes/plugins/`, restart the dashboard, done.
## Manifest — what it controls
```json
{
"name": "credits", // URL slug → /api/plugins/credits/...
"label": "Credits", // sidebar text
"description": "...", // shown in registries
"icon": "Wallet", // any lucide-react name
"version": "1.0.0",
"tab": { "path": "/credits", "position": "end" },
"slots": ["analytics:top"], // where to inject widgets
"entry": "dist/index.js",
"api": "plugin_api.py"
}
```
Three placement modes:
1. **Tab page** — `tab.path` set; sidebar entry rendered; `register(name, Component)` provides the page.
2. **Slot widget** — `slots: [...]` set; injected into existing dashboard pages without owning a route. Use `registerSlot(name, slotName, Component)`.
3. **Both** — useful when a small slot widget links into a larger detail page.
## SDK surface (frontend)
```js
const SDK = window.__HERMES_PLUGIN_SDK__;
const { React, hooks, components, fetchJSON, utils, api } = SDK;
const { useState, useEffect, useCallback, useMemo } = hooks;
const { Card, CardHeader, Button, Badge, Input, Select } = components;
```
- **No build step.** Plain IIFE that reads window globals. Edit and reload.
- **fetchJSON** auto-includes the dashboard session token.
- **components** are shadcn/ui primitives, themed by the active dashboard theme.
## Backend (FastAPI)
```python
from fastapi import APIRouter
router = APIRouter()
@router.get("/status")
async def status():
return {"ok": True}
```
Routes mount at `/api/plugins/<manifest.name>/<route>`. Standard FastAPI — async, dependency injection, the lot.
## Known slots
| Slot | Where |
|---|---|
| `analytics:top` | Top of /analytics |
| `sessions:top` | Top of /sessions |
| `cron:top` | Top of /cron |
| `header-right`, `header-banner` | Global chrome |
| `sidebar` | Below main nav |
| `pre-main`, `post-main` | Wrap the main column |
## What this unlocks
- **Three-file plugins** for cost/quota widgets, status indicators, custom config panels.
- **Slot-only plugins** — no new tab, just add a card to an existing page (e.g. credits widget on Analytics).
- **Hot iteration** — edit `dist/index.js`, hard-refresh the dashboard tab, see the change.
- **Independent versioning** — each plugin is its own git repo, semver-bumped, installable via `git clone`.
## See also
- The `hermes-plugin-template` repo: github.com/Atemndobs/hermes-plugin-template
- The credits plugin (real-world example): github.com/Atemndobs/hermes-plugin-credits
- The hub that auto-indexes them: hermes-plugins-hub.vercel.app
← All notes