Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,84 @@
All notable changes to Druks. Versions follow [semantic versioning](https://semver.org);
while Druks is pre-1.0, a minor bump may break compatibility.

## [0.3.0] — 2026-08-22

### Added

- **Logged-in browser sessions.** An extension declares the browser session a
site needs, and the operator signs in once through a Druks-hosted login window
— real Chrome over noVNC, opened on the site itself, with an optional timezone
and an egress proxy (authenticated if needed) for sign-ins that reject
datacenter IPs. A workflow then borrows that authenticated browser; the login
is encrypted, stored the first time a run reaches for it, and reused across
runs, and a session set to persist saves its refreshed state after each borrow.
- **OAuth connections.** You can sign in to an OAuth service more than once, and
Druks keeps each account as its own connection — one per mailbox, handle, or
workspace, owned by the account that consented and labeled with the provider's
own facts. A Connections page in Settings lists them; disconnecting keeps the
row as a revoked, auditable record rather than deleting it, and a repeat
sign-in reuses the matching connection instead of duplicating it. Extensions
build on one engine, `OauthClient` in `druks.services`, which runs the
authorization-code-with-PKCE flow with token caching and refresh; MCP sign-ins
ride the same engine.
- **Installed apps in the shell.** Every installed app appears in the dashboard
navigation and renders inside the shell instead of a separate page. An app with
a frontend ships an ESM `entry.js` and declared tabs and borrows the shell's
React, components, markdown renderer, and gate controls; an app with no
frontend still gets pages for free — a home page that stacks its subject
boards, and a subject page with summary facts, the run timeline, the latest
transcript, and gate controls.
- **Scheduled workflows can dispatch.** A workflow on a cron cadence can declare
a `dispatch()`; the schedule fires it instead of `run()`, so a subject-backed
workflow resolves its subject and starts the real run without a shim.

### Changed

- **Deployment is one profiled compose file.** Every service lives in a single
`compose.yaml`, with a `hosted` profile for the edge and janitor and a
`gateway` profile for the SSH gateway, so provider choice is a matter of
profiles and `.env`. `SERVICE_TOKENS` renders on every shape with no compose
default, so a missing token stops the sandbox plane instead of it starting on a
known one, and `install.sh` seeds an empty `compose.override.yaml` it never
overwrites, so host-local services survive installs and upgrades.
- **A service keys on a derived slug.** A service no longer declares a name or
title; the slug comes from the class name — `GoogleCalendar` becomes
`google_calendar` — and the card heading derives from it. The wire field and
connect route (`/api/services/{slug}`) follow, and an extension that still
declares `name` or `title` is rejected at load.
- **Board reads know the calling account.** A board scopes its rows to the
operator reading it, a subject carries a readable label, and a subject page and
the free board lead with the subject's type and name — `pull request:
owner/repo#7` — instead of a bare id.
- **One control frame across the shell.** The accent color reaches every surface,
and the status glyph pulses whenever any run is still going.
- **MCP tool names derive from `operation_id`.** An agent-tagged route gives an
unprefixed `operation_id`, and Druks prefixes it with the extension name, so an
author no longer writes the prefix by hand.
- **An app's subjects are checked at load.** A declared subject must supply a real
read-side; the loader rejects the platform stub and fails the boot instead of
the first request.
- **An approved, clean PR merges directly** instead of looping back through the
work gate; only a PR with unmet requirements falls back to auto-merge.

### Removed

- **The per-shape compose files.** `compose.local.yaml` and `compose.remote.yaml`
fold into the one profiled `compose.yaml`; `install.sh` removes the retired
overlays on upgrade.

### Fixed

- **Connect forms draw every declared field.** A bool, int, `Literal`, or
multiline field renders through the shared field component wherever it appears,
instead of falling back to a free-text box, and the replace placeholder
reflects the stored secret.
- **A spend-controlled Codex plan reports its quota as a weekly window** instead
of reading as a parse failure.
- **Sandbox provisioning failures retry.** A transient provisioning error is now
classified as transient, so the in-run retry covers it.
- **The app engine pool is sized for the run queue**, not a single request.

## [0.2.0] — 2026-08-10

### Added
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "druks"
version = "0.2.0"
version = "0.3.0"
description = "Autonomous software delivery; the self-hosted home for durable agent apps."
readme = "README.md"
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.