VSKI Dev Template
  • Python 75.1%
  • Makefile 15%
  • Dockerfile 9.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-24 22:58:34 +02:00
src/hello first commit 2026-10-24 22:58:34 +02:00
test first commit 2026-10-24 22:58:34 +02:00
.dockerignore first commit 2026-10-24 22:58:34 +02:00
.env.example first commit 2026-10-24 22:58:34 +02:00
.gitignore first commit 2026-10-24 22:58:34 +02:00
docker-compose.dev.yml first commit 2026-10-24 22:58:34 +02:00
docker-compose.e2e.yml first commit 2026-10-24 22:58:34 +02:00
docker-compose.yml first commit 2026-10-24 22:58:34 +02:00
Dockerfile first commit 2026-10-24 22:58:34 +02:00
Makefile first commit 2026-10-24 22:58:34 +02:00
pytest.ini first commit 2026-10-24 22:58:34 +02:00
README.md first commit 2026-10-24 22:58:34 +02:00

VSKI App Template

Starter template for a VSKI deployment with plugins enabled: the official standalone image (web frontend embedded) plus a Python environment for supervised plugin processes, wired up with Docker Compose and a Makefile.

Layout

.
├── Makefile                 # build, run, dev, test — see `make help`
├── Dockerfile               # standalone image + Python + vski-sdk + plugin deps
├── docker-compose.yml       # the stack: one vski service, plugins baked in
├── docker-compose.dev.yml   # dev overlay: mounts ./src over /app/plugins
├── docker-compose.e2e.yml   # e2e overlay: isolated env + state (used by make test-e2e)
├── .env.example             # server config template (copy to .env)
├── src/                     # plugin source — BAKED into the image at /app/plugins
│   └── hello/               # minimal starter plugin — copy it to start your own
│       ├── vski-plugin.json # manifest: entry point, config schema, functions
│       ├── requirements.txt # plugin dependencies (installed at image build)
│       └── hello/
│           └── main.py      # handlers: @on_event / @function / @cron
├── test/
│   ├── unit/                # pytest over plugin code — no server needed
│   └── e2e/                 # pytest over the running stack's REST API
└── data/                    # SQLite databases, files, plugin registry (gitignored)

Plugins are part of the image: Dockerfile copies src/ to /app/plugins and installs vski-sdk (from the vski.sh package registry) plus every plugin's requirements.txt into one locked Python environment. The ./src bind mount exists only as a dev-time overlay (make dev) — deployments run the baked image.

Quick start

cp .env.example .env
# set JWT_SECRET (openssl rand -hex 32) and ALLOWED_ORIGINS
make up

Open http://localhost:3000, create the first admin account, then create a plugin instance of the starter plugin (dashboard: Plugins, or the API):

TOKEN="<admin token>"

curl -X POST http://localhost:3000/api/plugin-instances \
  -H "Authorization: $TOKEN" -H "Content-Type: application/json" \
  -d '{"name": "hello_1", "plugin": "hello", "dbName": "default", "enabled": true}'

# invoke a function over the warm stdio pipe
curl -X POST http://localhost:3000/api/plugin-instances/hello_1/invoke?db=default \
  -H "Authorization: $TOKEN" -H "Content-Type: application/json" \
  -d '{"function": "echo", "params": {"message": "world"}}'

Testing

make test        # everything below
make test-unit   # plugin code against fake ctx, no server (needs make venv)
make test-e2e    # builds the image, boots an isolated stack, tests the real thing
  • Unit (test/unit): imports each plugin from src/, checks the manifest/entry layout, and exercises handlers with a fake ctx (test/unit/fakes.py). Runs in seconds; iterate here first.
  • E2E (test/e2e): the full lifecycle against a real server — health, web UI, catalog discovery, instance start, warm invoke, realtime event delivery, log capture, config-patch restart. make test-e2e writes a throwaway .env.e2e (test port 3999, random JWT secret), runs the stack with state in ./.e2e-data via docker-compose.e2e.yml, and always tears it down. To debug the suite against a stack that is already running: VSKI_E2E_URL=http://localhost:3000 .venv/bin/pytest test/e2e -v.

Developing plugins

make dev boots the stack with ./src mounted over the baked-in plugins: plugin code changes need an instance restart (dashboard/API) or a container restart — no image rebuild. Dependency changes always do need a rebuild (the image owns the Python environment).

Adding a plugin

  1. Copy src/hello/ to src/<your-plugin>/, rename the package and update runtime.entry (<package>.main:app) in the manifest.
  2. List its third-party dependencies in its requirements.txt.
  3. make test-unit — the layout checks import your entry module and verify the declared functions exist; add unit tests for your handlers beside test/unit/test_hello.py.
  4. make test-e2e — the baked image gets your plugin; e2e covers the runtime path.
  5. Create an instance (dashboard/API). POST /api/plugins/scan picks up new manifests without a container restart.

Instance API keys hold the plugin role and are subject to collection access rules (default-deny) — grant access like for any other service.

Production notes

  • Pin the base image in the Dockerfile to a versioned tag (e.g. vski.sh/x/vski:v0.14.0-standalone) instead of latest-standalone, and pin vski-sdk and plugin dependencies to exact versions. The vski.sh PyPI registry is public for reads (https://vski.sh/api/packages/x/pypi/simple/), so no registry credentials are needed at build time.
  • Set JWT_SECRET and ALLOWED_ORIGINS in .env; never ship the defaults.
  • data/ is the single stateful volume — back it up (see the wiki's Backup page). Instance configs and secrets live in the database; treat it like JWT_SECRET.

Reference

  • Plugins wiki page — manifest, lifecycle, plugin:// triggers, security model, troubleshooting.
  • examples/plugins/ in the platform repository — more complete plugins (embeddings indexer, graph sync, calendar index).