Skip to content

Latest commit

 

History

History
167 lines (124 loc) · 5.81 KB

File metadata and controls

167 lines (124 loc) · 5.81 KB

Development

This guide is for changing Druks itself. The backend and Vite dev server run on the host; Compose supplies isolated Postgres and Redis.

Set up

From the repository root:

docker compose -f deploy/compose.dev.yaml up -d
uv sync --locked --dev
cp .env.example .env
python3 -c 'import base64, os; print("DRUKS_SECRETS_KEY=" + base64.b64encode(os.urandom(32)).decode())' >> .env
uv run druks init-db

Local development runs DRUKS_AUTH_MODE=none (the .env.example default): the loopback dashboard has no authentication and exactly one operator account, created by your first harness connection. To exercise header mode against the dev server, set DRUKS_AUTH_MODE=header, name a header in DRUKS_AUTH_HEADER (no default), and send it yourself (for example with a browser header extension or curl -H 'X-Edge-Email: you@example.com').

The dev Compose project creates two databases:

  • druks_dev for the host-run application
  • druks_test for pytest, which rebuilds its schema during the suite

.env.example points the application at druks_dev. The suite reaches druks_test and Redis index 15 through DRUKS_TEST_DATABASE_URL and DRUKS_TEST_REDIS_URL, never through the application's own settings, so the two cannot be confused.

Start the backend:

uv run uvicorn druks.api.app:app --host 127.0.0.1 --port 8001

In another terminal:

npm --prefix frontend ci
npm --prefix frontend run dev

Vite proxies API traffic to the backend. The production backend image instead contains the built SPA and serves it from FastAPI.

Architecture map

Path Responsibility
backend/druks/workflows.py Public workflow, step, gate, scheduling, and start API
backend/druks/agents.py Public agent descriptor and output contract
backend/druks/durable/ DBOS integration, run projection, lifecycle internals
backend/druks/extensions/ Entry-point loading, discovery, author settings
backend/druks/events/, signals.py Event log, feed, and reactions
backend/druks/webhooks/ Authenticated delivery framework and deduplication
backend/druks/harnesses/ Claude/Codex invocation, auth, usage, capability manifests
backend/druks/sandbox/ Drukbox lifecycle, SSH execution, workspace delivery
backend/druks/api/ FastAPI composition and platform routes
backend/druks/{mcp,skills,notifications,user_settings}/ Shared operator services
backend/druks/contrib/ship/ Bundled reference extension, not framework core
frontend/src/ Shared dashboard shell and bundled extension UI
backend/migrations/ Core/bundled schema history
deploy/, scripts/ Images, Compose, Caddy, setup, and deployment

The API process embeds DBOS and executes workflows. Extension modules register capabilities during boot, after DBOS initialization and before launch.

Extension test surface

The main package registers bundled extensions through pyproject.toml. CI also installs backend/tests/druks-field_notes as a real editable distribution and runs the proof-extension tests. Those tests are the executable contract for:

  • app-less and boot-time entry-point loading
  • role-module discovery
  • route and subject read-side mounting
  • independent migrations and table-prefix enforcement
  • workflow start, settings, and feed formatting

When changing the author API, update the scaffold, proof extension, author guide, and tests together.

Database changes

Core and bundled historical tables use the core Alembic history:

uv run alembic -c backend/alembic.ini revision --autogenerate -m "describe change"
uv run druks init-db

For an independently packaged extension:

uv run druks makemigrations <extension-name> -m "describe change"
uv run druks init-db

The extension owns its migration directory and version table. Review every autogenerated revision before applying it.

Verification

Backend checks:

uv pip install -e backend/tests/druks-field_notes   # once per environment
uv run ruff check backend
uv run ruff format --check backend
uv run pytest backend/

The suite builds its subjects out of field_notes, the proof extension. It is a standalone distribution that depends on druks, so it installs like any author's extension rather than being a dependency of druks — install it once and the whole suite runs. The pull-request backend workflow does the same. Pyright is configured for local/editor use but is not currently a CI gate.

Frontend checks:

npm --prefix frontend run lint
npm --prefix frontend test
npm --prefix frontend run build

The frontend CI workflow runs those three commands on Node 22.

Documentation-only changes should also run:

git diff --check

and a relative-link/anchor check over Markdown. The repository does not currently ship a Markdown linter or link-check command.

Working with sandboxes

Backend tests mock most provider boundaries. For a real local sandbox, run Drukbox on the host as described in Full local setup and set:

DRUKS_SANDBOX_SERVICE_URL=http://127.0.0.1:8000
DRUKS_SANDBOX_SERVICE_TOKEN=dev-token
DRUKS_SANDBOX_IMAGE=ghcr.io/czpython/druks-sandbox:latest

uv run druks doctor --sandbox creates a real host. Run it deliberately; it is not part of the normal test suite.

Frontend ownership

Backend extension entry points and shared-shell React routes have different delivery mechanisms. Python discovery can load an installed extension at runtime. An extension can ship a standalone static app in its package's dist/, served at /app/<name>. React code that joins the bundled dashboard shell must already be in the SPA and register through frontend/src/extensions/index.ts; a wheel cannot inject routes into that existing JavaScript bundle.

See the frontend guide before adding dashboard pages.