Skip to content

Latest commit

 

History

History
204 lines (155 loc) · 6.99 KB

File metadata and controls

204 lines (155 loc) · 6.99 KB
title Develop Druks
description Set up the repository, understand its architecture, change the database, and run verification.
sidebarTitle Development
icon code

This guide is for changes to Druks itself. The backend and Vite development server operate 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 druks.toml.example druks.toml
cp .env.example .env
python3 -c 'import base64, os; print(base64.b64encode(os.urandom(32)).decode())'

Paste the generated value into secrets.secrets_key in druks.toml, then initialize the development database:

uv run druks init-db

Settings reads ./druks.toml from the current directory. The example uses [identity].mode = "none". The loopback dashboard has no authentication and exactly one operator account. Your first provider connection creates this account.

To use header mode with the development server, set identity.mode = "header" in druks.toml. Set identity.header in the same file. Then send the header with a browser add-on or curl -H 'X-Edge-Email: you@example.com'.

The dev Compose project creates two databases:

  • Development: druks_dev for the host-run server.
  • Tests: druks_test for pytest. The suite rebuilds this schema.

.env.example points the server at druks_dev. The suite reaches druks_test and Redis index 15 through DRUKS_TEST_DATABASE_URL and DRUKS_TEST_REDIS_URL. It does not use the server settings. Thus, the two databases cannot be confused.

Start the backend:

uv run uvicorn druks.api.server: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/apps/ Entry-point loading, discovery, author settings
backend/druks/ui/ Page declarations, the block/value/field catalog, the page API
backend/druks/events/, signals.py Event log, feed, and reactions
backend/druks/webhooks/ Authenticated delivery framework and deduplication
backend/druks/harnesses/ Harness invocation, authentication, usage, and 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/software_factory/ Bundled reference app, not framework core
frontend/src/ Shared dashboard shell and bundled app UI
frontend/src/druksui/ The renderer for an app's Python pages
backend/migrations/ Core/bundled schema history
deploy/, scripts/ Images, Compose, Caddy, setup, and deployment

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

App test surface

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

  • Headless 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.

If you change the author API, update the scaffold, proof app, 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 app:

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

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

An encrypted column seals each value with <table>.<column> as the AAD. A migration that renames that table or column must also decrypt every row under the old name and re-encrypt it under the new one, or every stored value stops decrypting. e3a9c7d1b5f4_providers_own_logins.py shows the step.

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 from field_notes, the proof app. This standalone distribution depends on Druks. It installs like an author app, not as a Druks dependency. Install it one time for the full suite.

The pull-request backend workflow does the same. Pyright is available for local and editor use. It is not 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.

For documentation-only changes, also run these commands:

git diff --check
cd docs
mint validate
mint broken-links --check-anchors --check-redirects

Mintlify builds docs/ directly. Its GitHub App owns deployments and pull-request previews. The repository does not require a documentation-specific GitHub Actions workflow.

Working with sandboxes

Backend tests mock most provider boundaries. For a real local sandbox, run Drukbox on the host from its own checkout (DOCKER_SSH_USERNAME=druks make dev in czpython/drukbox) and set:

[sandbox]
service_url = "http://127.0.0.1:8000"
service_token = "dev-token"
image = "ghcr.io/czpython/druks/sandbox:latest"

uv run druks doctor --sandbox creates a real host. If you require a real sandbox test, run this command. It is not part of the normal test suite.

Frontend ownership

An app's screens are Python. It declares them in pages.py, and the shell renders them through frontend/src/druksui/. An installed wheel therefore adds pages without touching the JavaScript bundle. The Druks UI contract is the one description of what those pages carry; change it first, then the renderer.

Two escape hatches remain, and both are for an app that needs full control of its interface. An app can ship a standalone static frontend 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/apps/index.ts; a wheel cannot put routes into that existing JavaScript bundle.

See the frontend guide before adding dashboard pages.