Skip to content

Releases ​

This documentation describes dqx 1.78.0.

bash
dqx version        # what you are running
dqx self-update    # what is current

The last 5 releases stay downloadable, each with its install line below; anything older is gone from the host. An older version says how to go back.

What changed ​

1.78.0 ​

  • minor: The router marks what it serves with an X-Dqx-Router header, so dqx can tell its own answers from another server's
  • minor: The dashboard shows a banner when 80 or 443 are held by another server (lerd, Herd, DDEV or something unnamed) and the router cannot serve your domains, with the command that frees them and a Recheck button
  • patch: doctor, verify and up no longer warn that a proxied site has no proxy_pass: the check now reads the $dqx_upstream variable sync writes since 1.73, so verify passes those sites again
  • patch: dqx up, doctor and router status no longer trust the engine's port list: a router that lost 80/443 to lerd, Herd or DDEV is recreated, or dqx up refuses and names who holds them
  • patch: dqx verify fails a site whose answer did not come from the dqx router, names who holds 80/443 and how to stop it, and checks routed sites over https as the browser does
  • patch: The MCP server says when the dqx on the machine is newer than the one it runs, and how to restart it
  • patch: dqx sync on DDEV says which packages it cannot install because they have no apt name, and a DDEV project serving several sites now installs every site's packages and extensions, not only the first site's

1.77.0 ​

curl -fsSL https://dqx.dolphiq.nl/install.sh | bash -s -- --to 1.77.0 or dqx self-update --to 1.77.0

  • minor: sites[].checkoutFiles: false keeps dqx's README block, agent notes and .mcp.json out of a checkout that is not yours, such as a client's repository under review.
  • minor: Recognise the dqx-php images (dolphiq/dqx-phpXY-<distro>-<flavour>) and propose their :X.Y tag
  • minor: Switch Xdebug per site through XDEBUG_MODE on the dqx-php images, from the CLI and the dashboard, with a new coverage mode
  • minor: dqx image info: what a dqx-php image contains, read from its label on the registry without pulling, and inside a project what each app container runs and where it differs
  • minor: Daemons by preset (horizon, queue, schedule, reverb, ssr), autostart, an own image, grace period and healthcheck; they stop gracefully, and dqx daemon lists, starts, stops and switches them on or off for yourself
  • minor: Daemons restart once their code changed (dqx daemon restart --changed, after dqx packages pull and switch), dqx daemon shows uptime, health and memory, and the dashboard switches and restarts them per site
  • minor: New qore-works-business and qore-cms projects get dolphiq/dq-sonar, which reports runtime and package versions to My Dolphiq once a server has DQ_SONAR_DSN; the scaffold's note says where to get the DSN
  • minor: dqx doctor checks daemons: a preset whose package composer.lock lacks, a queue whose every worker is switched off, a wanted daemon without a container, one on older code, and on DDEV and lerd the daemons they leave out; a switched-off daemon is no longer a stopped service, and init and adopt propose the daemons a checkout's packages ask for
  • minor: New projects run on the dqx-php images (dolphiq/dqx-phpXY-alpine-slim:1.0 for PHP 8.2-8.5); distro: debian or --distro debian picks Debian, which init also picks when a checkout needs glibc
  • minor: dqx image switch moves a site to the dqx-php image or the other distro; adopt, doctor and dqx images --outdated propose it, and the dashboard shows what a site's image contains
  • minor: The dashboard shows a project's images from the card's menu, also read-only; dqx image info keeps what Docker Hub said for a day, and --refresh asks again
  • patch: Daemons on docker wait for composer install instead of crash-looping before it, no longer inherit the app image's healthcheck, and are regenerated on dqx sync so a changed command reaches the stack.
  • patch: A second dqx sync of a project with Pest browser tests no longer writes a compose file docker refuses with "dependency cycle detected: app -> pest-browser -> app".
  • patch: A declared Typesense service gets a data directory under docker/data, so it starts and keeps its index across recreates.
  • patch: dqx doctor names the env keys an app's own config/database.php reads where .env does not point them at dqx's values, code using GLOB_BRACE on a PHP built without it, node_modules installed for another libc than the app image, and images that run emulated.
  • patch: dqx install names the service that kept the stack from starting, and whether it is a daemon; dqx sync no longer keeps a .bak of a file only dqx wrote.
  • patch: phpExtensions build on the dqx-php Debian images (the app image installs the compilers first when the image has none), and dqx down and clean also stop the e2e browser and daemons behind a profile, which left the project shown as running
  • patch: A regenerate no longer makes the app depend on Pest's browser (compose refused the cycle), and daemons carried through from the last stack move on to the newly built app image
  • patch: dqx runs on zod 4, which closes GHSA-mrhx-c7xc-m3w5 (memory exhaustion on oversized constrained collections). Config, request and settings checks parse the same; a config error now prints one line per problem, a few messages name the expected pattern, and .inf or out-of-range numbers are refused.

1.76.0 ​

curl -fsSL https://dqx.dolphiq.nl/install.sh | bash -s -- --to 1.76.0 or dqx self-update --to 1.76.0

  • minor: dqx prune reports what on this machine belongs to nothing (the containers, volumes, dangling images and build cache of projects that are gone, the copies that are finished with, and the stacks left running for nobody) and removes it with --yes; dqx doctor names it when there is a gigabyte or more in it, and an agent can ask with dqx_prune_check and report what it finds; dqx prune -v names the files keeping each copy it could not take; dqx config machine pruneMode aggressive makes a day unused enough instead of a week, and a request a stack served counts as use; the dashboard's ⋯ menu opens a prune page with the same report, its progress, every name it keeps, and a button that prunes after it asks; each copy it keeps opens a panel with the files that keep it, and Remove anyway… there does what dqx clone --remove does; Prune… in the desktop tray's Machine menu opens that page, also when the window is closed; the dqx logo goes back to the home page
  • minor: A project can declare database: {type: postgres} and get a working postgres on the docker backend: its own container, accounts and schemas, DB_CONNECTION=pgsql, and imports, snapshots and dqx db through psql and pg_dump. lerd, DDEV and Herd refuse it until they support it.
  • minor: database.image runs another image of the same engine, such as postgis/postgis:17-3.5, and database.extensions has dqx create postgres extensions like postgis as the superuser in every schema. Adoption recognises PostGIS, pgvector and TimescaleDB stacks as postgres.
  • minor: On docker, phpExtensions and packages are installed on top of the site's image through a Dockerfile dqx generates and dqx up builds, on Alpine, Debian or Fedora images; a postgres project gets pdo_pgsql, pgsql and the postgres client without declaring them. database.settings work on postgres as -c flags, and dqx doctor checks every site's PHP for the extensions it needs.
  • patch: Removing a copy takes its database volume with it, where dqx clone --remove, dqx clone --prune and dqx_agent_env_remove stopped the stack and left the volume behind forever with nothing on disk left to name it; --prune also tells the original to forget the worktrees the copy held
  • patch: A second dqx sync no longer makes the app depend on the site's daemons, so dqx install no longer stops at its start step waiting for a queue worker that cannot run before composer has.
  • patch: A postgres project's entrypoint database is now the first site's schema instead of one named after the client key, so no empty extra database is created and dqx doctor stops asking about it.
  • patch: Images are read in one place: pgvector/pgvector:0.8.0-pg17 and timescale/timescaledb-ha:pg17 are recognised as postgres, a digest no longer reads as a version, and a company image's own tag no longer makes doctor report a version disagreement.
  • patch: dqx adopt reads postgres:17-alpine as postgres 17 and keeps the alpine image, instead of writing version: 17-alpine that every later command refused; the database address in CLAUDE.md, AGENTS.md, dqx info --json and dqx_service_address is the engine's port, 5432 for postgres.
112 earlier releases, 1.0.0 to 1.75.0

1.75.0 ​

curl -fsSL https://dqx.dolphiq.nl/install.sh | bash -s -- --to 1.75.0 or dqx self-update --to 1.75.0

  • minor: The Browser tests page offers Run and watch and Keep traces for a Playwright suite too: watching opens Playwright's UI mode in a new tab with a Stop beside it, keeping passes --trace on; dqx e2e --ui opens the host address itself once the UI answers
  • minor: dqx e2e --headed opens a visible browser on this machine for a Playwright suite too, instead of running headless in the container without a word (SL34)
  • minor: dqx e2e --ui opens Playwright's UI inside dqx's header and in the dashboard's light or dark theme, served on one origin with the UI under ui/ (SL35)
  • minor: The dashboard's Run and watch opens a visible, slowed-down browser for a Playwright suite too, as for Pest; Playwright's UI mode is an option of its own, Open in Playwright UI
  • minor: Bitbucket moves Git over SSH to ssh.bitbucket.org (brownouts from 12 November 2026, gone on 10 December): dqx bitbucket-ssh sets the machine up and moves every known project, sync moves a project's remotes and config URLs once ssh knows the new host, doctor says what is left, and new clones, the app container and dqx review use the new host
  • patch: php-ini-overrides.ini and mysql_extra.cnf carry the dqx marker and say which lines come from php: and database.settings, so a new setting reaches the container instead of the file being kept as a hand edit; an unmarked file with only dqx's lines is replaced, a kept one makes sync name the settings it could not apply and fail, and sync says when MySQL or PHP need a restart
  • patch: dqx sync writes nginx configs under a temporary name and renames them into place, and tests nginx once more when it only caught a file mid-write, instead of rolling back as a refused config
  • patch: sync rebuilds the PHP variant containers from the sites instead of carrying the old ones through, so a version no site runs any more leaves the stack (SL27)
  • patch: dqx up removes the container of a service gone from the stack, such as a PHP version no site runs any more (SL29)
  • patch: sync names a kept php-ini-overrides.ini or mysql_extra.cnf's own lines, and after --force says they are now only in the .bak and belong under php: or database.settings (SL28)
  • patch: after a run dqx e2e names dqx e2e --report: Playwright's own npx playwright show-report hint looks in the wrong folder on this machine
  • patch: dqx e2e --headed --slowmo <ms> slows a headed Playwright run down, so a fast journey can be followed
  • patch: The generated PHP ini no longer turns allow_url_fopen off: PHP's own default is On, and Off broke every app that fetched a URL with file_get_contents. dqx doctor names each PHP default dqx sets that PHP itself does not (SL36)

1.74.0 ​

curl -fsSL https://dqx.dolphiq.nl/install.sh | bash -s -- --to 1.74.0 or dqx self-update --to 1.74.0

  • minor: sites[].configFiles: files dqx install copies into a checkout when they are missing, such as a config template kept outside www/; dqx adopt fills it from the old install script's cp -n lines
  • minor: dqx sync generates a routed stack while the shared router runs, instead of fixed ports that clash with it, and says so; --no-router keeps the fixed ports
  • minor: dqx generate docker prints the compose file and each site's nginx config that dqx sync would write, or one site's with --site
  • minor: dqx doctor says when a routed project's .env or config files still point at the old stack: a local domain with a port, host.docker.internal with a port, or docker.for.mac.localhost
  • patch: A site with its own nginx.frontController sends folders to it too (try_files without $uri/), as the legacy app's own nginx and Symfony's config do: a folder's index.html no longer answers in its place
  • patch: A service the config declares with a compose override is built from the config on every sync, so a mount removed from the override leaves the stack
  • patch: dqx adopt lifts the old db service's --flag=value command into database.settings, drops links and a web image that is only FROM nginx, names Dockerfiles nothing builds, and proposes install.composer, npm and env only where a checkout has the file
  • patch: dqx sync and dqx adopt say when the database image changes under a data folder that exists, and point at dqx snapshot first
  • patch: dqx adopt marks every site secured, as dqx init does and as the router serves it, instead of secured: false from an old http-only server block
  • patch: Before adoption the agent block in AGENTS.md and CLAUDE.md says the project is not adopted yet and points at dqx adopt, and dqx info --json (dqx_project_info) reports config: null

1.73.0 ​

  • minor: dqx e2e init sets up Pest browser tests and journeys in a Laravel site: the packages, phpunit.xml suites kept out of the default run, tests/Pest.php, example tests and .gitignore, each only when missing; it refuses before changing anything on PHP below 8.3, Laravel below 12, Pest 3 or a missing Packagist token, then syncs, restarts and runs the example browser test. --playwright keeps the TypeScript suite, and dqx_e2e_init takes runner and site and stops after dqx sync
  • minor: e2e.directory may sit outside www/ in a multi project (for example e2e at the project root): dqx mounts it at /var/www/<last segment> in the app and the browser container, the Browser tests page reads its runs from there, and dqx sync refuses when www/<last segment> also holds files
  • minor: A site's nginx can name its own front controller (nginx.frontController, for a legacy app routing through /cms/_hubfile.php) and fastcgi params (nginx.fastcgiParams, such as PHP_VALUE); dqx adopt reads both from an old server block, and a backend that cannot carry them says so
  • minor: dqx adopt reads a project's real repositories from each checkout's git (several per checkout, with their path and branch), turns localbuild/local_install.sh into postInstall hooks of the site or the project and lists what it cannot place, and finds the schemas MYSQL_DATABASE and init .sh files create
  • minor: dqx sync, dqx adopt and dqx doctor say when another project on this machine already routes one of this project's domains, naming that project
  • minor: Sites on different PHP versions each run on their own version on docker: an app<version> container beside app, with the site's nginx, daemons and dqx exec pointed at it
  • patch: dqx dashboard serves in about a second instead of twelve: it opens on a quick pass over the projects and fills in each project's packages and an unadopted project's URLs a moment later, it reads each package with one git process instead of four, and it runs at most eight git processes at once, so the burst no longer starves the engine socket and takes the memory reading beside it down
  • patch: Fix a flaky error message when the visible browser's server stops before it listens: its output is read to the end before the error is raised
  • patch: The playwright browser container no longer mounts the host's SSH key, composer credentials and other app mounts: only the code under /var/www and the suite
  • patch: A docroot holding an index.html beside PHP files is served as PHP, not as a static site that answered every route with the HTML page
  • patch: nginx looks up php-fpm and a dev server per request through docker's DNS, so a recreated app container is reached at its new address instead of whichever container took over its old one
  • patch: dqx up in a multi project no longer waits for its daemons: a queue worker that cannot start before composer has run no longer marks a fresh install unhealthy
  • patch: nginx refuses a PHP file asked for in another case (init.PHP, .php5, .phtml, .phar) with 404: on macOS the case-insensitive mount found the file and served its source; dqx doctor warns when a docroot holds .env, .git, vendor or protected/
  • patch: dqx snapshot no longer prunes a labelled snapshot by count: a restore point another task named on the same project is kept until it is 60 days old

1.72.0 ​

  • minor: Pest browser tests run with the rest of a Laravel site's suite: dqx writes a pest-browser service (the official Playwright image in the app's network namespace) for a site that requires pestphp/pest-plugin-browser, and dqx e2e runs its journeys suite with the site's own environment, visibly with --headed --slowmo
  • minor: Pest journeys report like a Playwright suite: dqx e2e keeps Pest's JUnit and a Playwright trace per failed journey (--keep-traces for all), the dashboard shows their history and failures and opens a trace on a dqx page with Playwright's viewer in the dashboard's theme, and a Pest suite gets Run and watch and a Run per journey
  • minor: A Pest journey records a video of each page beside its trace, a watched run keeps every journey's traces and videos, and each failed run's error is kept in the history
  • minor: A browser suite has a page of its own in the dashboard: Run with Run and watch and Run failed behind its caret, Keep traces, the week's overview, a filter by state, tag and title that lives in the link, and per journey its runs of the week with each failure's whole error and its last run's traces and videos; a run shows its progress there, journey by journey, and the card keeps only the state, the week and Open
  • minor: dqx self-update from a build of a checkout asks to switch to development, pull, install and run bun run build instead of only refusing; it refuses while the checkout has uncommitted changes, and without a terminal, with --check, --to or --previous it still only says how
  • patch: Run and watch no longer hangs when npx is a version manager's shim: the visible browser's server runs in its own process group and is stopped with it, so dqx e2e --headed exits and a dashboard restart no longer waits on it for ever
  • patch: A Pest journey whose test file is gone leaves the browser tests list and cannot be run, and a run in which no journey matched keeps the last run's traces, videos and results instead of replacing them with nothing
  • patch: One Pest journey run per checkout: dqx e2e takes a lock beside its results, a second run from a terminal or the dashboard is refused with who holds it, the browser tests page shows a terminal's run as running, and a lock left by a crashed run (dead or foreign pid, or older than two hours) is taken over

1.71.1 ​

  • patch: The shared router starts again when a site serves wildcard domains: dqx wrote *.domain unquoted into the router's network aliases, which YAML reads as an anchor, so docker compose refused the file and every project behind the router stayed down

1.71.0 ​

  • minor: MCP dqx_build builds a dev-server site with the command its config names (proxyBuild), behind --allow-write; the instructions tell an agent never to build any other way
  • patch: dqx up and dqx install free only the ports actually in the way: a port of the project's own that another container publishes no longer stops dqx's router, and with it every project behind it, as well
  • patch: dqx sync pins a Vite port no other project on this machine has: a new pin takes the first block clear of the others, and a pin another project shares (a copy and its original) moves on, said so; a pin already in use otherwise stays

1.70.0 ​

  • minor: dqx e2e scenario init gives a Laravel site the e2e:scenario command a journey makes its people with (the command and two core classes stamped as dqx's, Scenarios and People as the app's own), and dqx e2e scenario new <name> adds a scenario, its entry in Scenarios::all() and a journey that asks for it through the relay, also as the MCP tool dqx_e2e_scenario
  • minor: dqx e2e scenario update (and action update of dqx_e2e_scenario) brings the e2e:scenario core dqx wrote up to today's version, file by file: a file still as dqx wrote it is replaced, one the app changed or without dqx's stamp is kept and named
  • minor: A scenario can have steps of its own beside start, queue and state (the core's new Steps interface), each run as --phase=<step>; scenario new writes no journey into a suite without tests/support/run.ts, which would break the whole run
  • patch: dqx install adds a new project's domains to a running router's aliases, as dqx up does, so a browser suite or a site-to-site call reaches the site from a container right after the install
  • patch: A router recreated by dqx up or dqx install keeps every known project's domains as aliases: one recreated from a project outside the usual tree kept only the projects beside it, and other projects' containers could no longer reach their sites
  • patch: A project's .gitignore keeps out .playwright-mcp/, where a coding agent's Playwright MCP server leaves screenshots of local pages: a new project has the line, and dqx sync adds it to an existing one, beside .dq/snapshots/ under one generated-by-dqx heading

1.69.0 ​

  • minor: The dashboard has a Browser tests section per project with the last run and its failures, opens a run's results, report, traces, videos and logs from 127.0.0.1, and dqx e2e --open-report does the same for a downloaded CI report; package modes switch with one local | packaged toggle, and a finished job is one line
  • minor: The dashboard keeps a browser suite's run history, read from its Playwright HTML report, shows how far a run is while it runs, and the results page opens with an overview of the last 7 days: success rate, healthy, flaky and failing tests, and per test its failure rate, duration and spread
  • minor: dqx e2e init proposes a browser suite for a project, and with --write makes it: the browser container, e2e.directory and a site's scenario command in .dq/config.yml (only those lines change), a Playwright suite with a tagged journey per site, and CI; dqx_e2e_init does the same for an agent
  • minor: The dashboard's Browser tests section lists every journey of the suite, from Playwright's own list, grouped by tag with one Run per tag, with each journey's latest outcome and its own Run; Run failed runs every journey whose latest outcome failed. A partial run (dqx e2e --partial, used by the dashboard) keeps its report in .dqx/partial so the full report stays, and the report opens in the dashboard's theme
  • minor: dqx e2e asks every site of the project before it resets anything, and stops with which site is down and how to start it (a dev server that is not running answers 502); --no-site-check skips it, and the dashboard and dqx_e2e check the same way
  • minor: A dev-server site (proxy) serves its build from publicDir while its dev server is down, on docker and DDEV, marked X-Dqx-Served: build; dqx build [--site|--here] runs the site's new proxyBuild, and dqx verify and dqx e2e say when a site answers with its build; the dashboard shows dev, build or off after a dev-server site's url
  • patch: A dqx too old for a config says which version it needs before it reads the config, rather than naming a key it does not know

1.68.0 ​

  • minor: dqx e2e runs a relay for the run: a journey runs the commands a site lists under sites[].e2e.commands, such as a scenario seeder, from inside the browser container, through E2E_RUN_URL and E2E_RUN_TOKEN

1.67.0 ​

  • minor: dqx e2e runs a suite of the project's own (e2e.directory), resets and sets up every site that declares sites[].e2e.reset or setup, and gives the suite E2E_<NAME>_URL for every site and E2E_MAILPIT_URL
  • patch: dqx_e2e over MCP gives the database reset and the browser suite 30 minutes instead of a minute, and a failure answers with stdout and stderr in order and the runner's own exit code
  • patch: dqx install runs npm install in the e2e.directory suite on docker, after the sites' own, and --only npm includes it
  • patch: The test gate runs its timing tests on their own instead of beside nineteen other test files, so a busy machine no longer fails it

1.66.0 ​

  • minor: A compose override merges into what dqx generates the way compose merges an override file: environment adds a variable instead of dropping VITE_PORT, volumes add a mount, command still replaces
  • patch: install.sh asks for the project's own requires, not dqx 1.0, so a new developer meets the right version first
  • patch: The generated Xdebug ini files comment with ; like every other PHP ini, and nginx site confs no longer listen on 8080, which nothing reached
  • patch: dqx info counts a compose container as the project's only when it was started from the project root, so a compose project inside it (an e2e proof stack) no longer adds a second Mailpit
  • patch: dqx dev stops its dev server in the container when it is stopped itself, also without a terminal, and dqx dev --replace takes over a port an older server still holds

1.65.0 ​

  • minor: dqx packages local and packaged take --site, so one site of a project uses the local packages while another keeps the registry's; install, status, doctor, info and the dashboard follow each site's mode, and the dashboard's Packages group switches a site in its own row

1.64.1 ​

  • patch: install keeps the other sites of the project in SANCTUM_STATEFUL_DOMAINS, and a SESSION_DOMAIN that covers every name of the site
  • patch: adopt and migrate import only the database settings a project changed, never dqx's own defaults or a line outside [mysqld]
  • patch: A config with a proxied site or nginx.cors: open requires dqx 1.64, the first release where both work
  • patch: doctor no longer reports a missing docroot for a site proxied to its dev server

1.64.0 ​

  • minor: nginx.cors takes an object: allowed origins, credentials, methods, headers, exposed headers and a preflight cache
  • patch: Restart a running dashboard after bun run build or with dqx dashboard --restart, and reload its pages on a new build
  • patch: dqx dev runs a proxied site's proxyCommand in a shell, starts Vite on the proxy port, and gives it an overlay with TLS off and HMR through the router on 443
  • patch: sync, up and doctor say when a proxied site's proxy_pass is written but the running nginx does not load it, and verify no longer passes such a domain on its 200
  • patch: Make nginx.cors: open work for a SPA that sends cookies: echo the origin instead of answering *
  • patch: test:gate runs the suite in parallel, then the core tests alone for the coverage gate: about 100 s instead of 9.5 minutes
  • patch: sync and up remove a pre-router project's override and route once its stack joins the router, up and doctor name two route files claiming one host, and every router file removal makes Traefik reload, which it missed on macOS
  • patch: adopt turns a hand-written CORS block in the project's nginx into nginx.cors: open and says so, instead of dropping it
  • patch: adopt's preview lists the agent files it would change per repository, marked tracked, and a dqx hook edited by hand is kept until githooks --force
  • patch: a proxied site without a database of its own no longer gets the client key's schema pair, so snapshot and the init SQL stop looking for and creating it
  • patch: install leaves composer and npm out of the plan for a cloned checkout without composer.json or package.json, so the dry run no longer lists steps it would skip
  • patch: the generated pre-commit hook stages again the files its formatters rewrote, for files that were staged whole, and names the ones staged in part
  • patch: up and doctor name the route files of a clash in name order, which on Linux they were not

1.63.1 ​

  • patch: The documentation site shows the dqx logo card when a page is shared in Slack or Teams
  • patch: A site's install hooks run with that site's own env, so an E2E site on a shared checkout migrates and seeds its own database instead of the main site's
  • patch: dqx doctor judges a site on a shared checkout by its own env, so an E2E site no longer reports the main site's APP_URL and queue as wrong
  • patch: dqx domains --to only renames the old TLD at the end of a host name, so a value like DB_DATABASE=app_test stays as it is, and a --site in .mcp.json moves with its site
  • patch: dqx domains --to lists the project's files that still name the old TLD only where it ends a host, once per checkout, rather than every line with the word in it

1.63.0 ​

  • minor: dqx desktop install builds the dashboard as a Mac app on this Mac and installs it in ~/Applications/dqx.app: the dashboard in a window and every project in the menubar, with start and stop, its URLs and the dashboard's editor, open and git places per project. Apple silicon only.
  • patch: dqx snapshot restore, dqx switch and dqx db import load a dump without writing MySQL's binary log, so a 335 MB dump loads in 43 seconds instead of 52.
  • patch: dqx snapshot and dqx snapshot restore on docker copy the database's data directory with clonefile while the database stops for a few seconds, so both take seconds instead of minutes on a large database. dqx switch still takes a SQL snapshot, because another backend must be able to read it.
  • patch: Leave out the files the reviewed branch deleted when a clone attaches a worktree
  • patch: Run composer and npm in an agent environment when its branch changes a lockfile
  • patch: A generated mysql_extra.cnf trades crash durability for write speed on a local database: innodb_flush_log_at_trx_commit = 2, sync_binlog = 0 and skip-log-bin, so imports and test suites no longer fsync the redo log and a binary log on every commit that nothing replicates from. Verified by starting mysql:8.0, mysql:8.4 and mariadb:10.6 against the stub, and dqx tune adds the three lines to a hand-maintained file

1.62.0 ​

  • minor: dqx exec --here runs in the site whose checkout you stand in and refuses anywhere else; the git hooks use it from a worktree outside the checkout they were written for
  • patch: dqx clone and dqx agent-env copy the database of a running original by its data directory, with the original's database stopped for a few seconds, so a 6.5 GB database takes seconds instead of a 9-minute dump and import.
  • patch: dqx clone and dqx agent-env copy the project with one clonefile call for the whole directory, so a project of 400,000 files copies in about 10 seconds instead of 75.
  • patch: A clone no longer copies .claude/worktrees.
  • patch: Git hooks work from a git worktree: a worktree inside the checkout has its staged files formatted by the site's tools under their own path, instead of Pint reading or rewriting the main checkout's files; refresh with dqx githooks
  • patch: dqx artisan and dqx test run a git worktree's code from inside it, not the main checkout's, and a project with one site no longer falls back to it from a worktree beside its checkout

1.61.1 ​

  • patch: Start a fresh install whose own nginx config loads the project certificate, behind the router too
  • patch: Recreate only the containers that did not start, so a database initialising its first data directory survives a retry
  • patch: Keep login working on a site's aliases: host-only session cookie, every name stateful for Sanctum, dev-server ports kept

1.61.0 ​

  • minor: An adopted project's README gets the install block on top, and the generated README and INSTALL.md both explain how to install dqx itself
  • minor: dqx adopt proposes a cleaned-up README: sections on the old tooling removed and the project's own links moved off port 8080, applied with --write
  • minor: dqx adopt and dqx migrate keep the comments in .dq/config.yml, and name the ones whose key is gone
  • minor: dqx adopt installs the pre-commit hooks install.gitHooks asks for, replacing the old tooling's hook and keeping it as pre-commit.bak
  • minor: Package checkouts get a pre-commit hook too, from dqx install, dqx githooks and dqx adopt, running the site's tools on the package's staged files
  • minor: Git hooks can be switched per site (install.gitHooks) and per package (gitHooks) in .dq/config.yml; null follows the project's install.gitHooks
  • minor: Any git hook can be configured per site and package in hooks.git, as commands run in the site or the team's own scripts in the wrapper repository
  • patch: A wrapper's install instructions clone into a folder named after the client key, and dqx adopt writes the install.sh they point to
  • patch: The MCP tools find a project the way the CLI does, so a project with a docker-compose.yml and no .dq/config.yml is no longer passed over for a .dq/config.yml in a folder above it, and the home folder is never taken as a project.
  • patch: dqx agent-env and dqx clone with --worktree refuse before they copy anything when no checkout can become a worktree, instead of copying the whole project and only then printing a warning.
  • patch: The MCP instructions tell an agent asked to work in a clone to check the project with dqx_project_info and pass the same path to dqx_agent_env.
  • patch: dqx info and dqx_project_info read a project without a .dq/config.yml through the config dqx derives from its stack, so they no longer answer "no readable config" or report a .dq/config.yml in a folder above it.
  • patch: The README clean-up of dqx adopt keeps the title and the subsections of a stale section, and the clone line in the README takes origin's URL instead of the first URL in .git/config

1.60.1 ​

  • patch: Copying or making an environment of a project without a v4 config no longer fails on a missing .dq directory, and the copy's derived config declares the packages found under www/; a failed environment names dqx agent-env, the command that exists. The database retries during an install no longer print the expected not-ready errors of a database that is still starting. An environment of a project that declares no way to fill its database now copies the running original's data in instead of leaving empty schemas, and dqx clone dumps a running original's database rather than refusing it; both read every schema and login the checkouts' .env files name, DB_DATABASE_CRM and the like included. A copy whose derived host ports clash with a running project, or with the block another known project owns, gets a free block pinned in its .dq/compose.env before it starts, instead of a dqx up that refuses.

1.60.0 ​

  • minor: Packages developed inside a project: declared in packages:, cloned and access-checked by install, dqx packages (status, pull, switch, clone, scan, local/packaged), doctor, sync, copies, PR overview, info/MCP and the dashboard.
  • minor: dqx adopt makes the alias APP_URL names the primary domain (keeping the checkout's directory); doctor reports a primary the application does not route on, and doctor and install stop on a checkout under an alias's name.
  • patch: A dqx run from a checkout or built from one warns about a project's version floor instead of refusing it.

1.59.0 ​

  • minor: dqx dev runs Vite through an overlay that moves a port the project's vite.config pins to the one Vite runs on, and the guide shows how to read VITE_PORT in Vite, Laravel Mix, webpack-dev-server and Gulp
  • patch: Notice and restart a resolver agent that is loaded but not answering, and name the fix in dqx doctor
  • patch: Warn when a Vite config pins the browser to a port other than the one dqx dev runs Vite on (dqx dev, doctor, sync and adopt), pass VITE_PORT to the dev server, and name a dev server already holding the port before starting another

1.58.0 ​

  • minor: An older dqx can be installed when the newest breaks something: dqx self-update --to <version> or --previous, install.sh --to <version>, with the last five releases kept on the host and listed in releases.json and on the releases page
  • patch: Dashboard branch chips dim their prefix and highlight the ticket key, and the open menus on a card are quiet until pointed at
  • patch: The dashboard header's rescan and docs buttons are quiet beside + add, and a card's menu is split into groups with a rule between them
  • patch: Dashboard dialogs label their fields in sentence case, put the labels above the fields in a narrow window, and name what a destructive or posting button acts on
  • patch: The review page's sticky bar says how many findings are already on the pull request, beside Post selected

1.57.0 ​

  • minor: Fold stopped projects on the dashboard into rows that keep their folder, first address, branch and database, and expand one in place
  • minor: Every service on a dashboard card opens a popup naming its image and state, and the database's version, source and mismatch move there from the DATABASE row, which goes
  • minor: The dashboard's details switch goes: a card always shows its config version, and php, image, wildcards, layout and pinned runtime are at the top of the open menu they describe
  • minor: Each pull request row shows two lanes, Claude's last run and your own review with its comments and files reviewed, each with its own button, so a human review stands beside Claude's instead of behind a chevron
  • patch: Make the dashboard easier to read: one type scale with nothing clickable under 13px, button edges you can see, a focus ring, and a wider page
  • patch: Give the dashboard one filled button per screen, a real switch for a card's details, a square button for its menu and a separated dialog footer
  • patch: Dashboard menus open towards the page from the right half of the window and work with the arrow keys; dialogs get a close button and keep the focus inside until they close
  • patch: Project settings move from the card's gear into its ··· menu, and a running card's memory reads as quiet text whose breakdown opens as a popup
  • patch: A dashboard card's head keeps not adopted and the config version as chips and puts copy, temp, a shared key's folder and pre-router behind one badge, amber when one of them is a warning
  • patch: A dashboard card offers the schema a site's own .env connects to when its config names none, instead of the empty key schema, and opens it with that .env's login; dqx doctor warns about such a site
  • patch: The output of a dashboard card's actions and its dqx doctor check share one panel: what ran and how it went on one line with show/hide output and close, while the card's menu button stays as it is
  • patch: The pull request list folds repositories with nothing open into one line, leads each row with its author and age, opens the last review from one chip, and offers human review behind a split Review button
  • patch: The review page shows each file's full name with its folder under it, softer added and removed lines, larger finding text, and j, k and x to step through and tick findings
  • patch: A site that shares another site's checkout (an E2E or preview variant) no longer makes every command in that checkout ask which site; the checkout's owner is the default, --site reaches the variant, and dqx ai and dqx doctor say when Laravel Boost's entry could not start
  • patch: The agent note in a checkout an E2E or preview variant shares no longer repeats it in a list of applications or says a bare command lands on whichever site the directory belongs to
  • patch: A dashboard card's menu and Start/Stop buttons stay at its bottom right however many services wrap beside them

1.56.2 ​

  • patch: dqx help lists its commands alphabetically

1.56.1 ​

  • patch: Install without launchctl noise, and write the resolver files in one sudo: only the password to type
  • patch: dqx loopback adds and removes its address with your password instead of printing sudo lines to copy

1.56.0 ​

  • minor: Read each Fix feedback point in full, with its code, and hide pipeline status messages (review.ignoreAuthors)
  • minor: Fix automatically, the groundwork: a read-only plan run and a fix run on its own branch, guarded against secret files and against touching your checkout. The review, map, trace and suggestion runs no longer read secret files, even when they are committed.
  • minor: The qore-cms scaffold installs qore-frontend, renders the CMS home entry on /, and creates a local Statamic super user admin@dolphiq.nl / password.
  • minor: Fix the feedback automatically: Claude plans per point, you approve, it fixes on a branch of its own that opens as a review, then Apply to my branch, Discard and Run tests (also dqx review fix --auto, --apply, --discard, --test)
  • patch: The documentation and the dashboard demo use .dqx domains, and the domains page explains dqx's own suffixes before local.dolphiq.eu and .test
  • patch: Explain the Statamic licensing alert that a qore-cms project shows on a .dqx domain
  • patch: Let dqx remember --off remove a forgotten project's route, certificate, profiles and domains-cache entry, so nothing is left behind
  • patch: Fix automatically watches every checkout of the project, can plan again over a previous fix in one step, and streams Run tests output live
  • patch: After the Mac wakes from sleep the dashboard no longer prints 'could not read this machine' and 'reading this machine again' on every tick: each clock keeps its own streak, says what it could not do, and a failing memory or project read waits longer between tries.
  • patch: dqx e2e recreates the Playwright browser container when it still points at a network the project no longer has ("network … not found"), instead of failing the run; the app and the database are left alone.
  • patch: The dashboard's project cards are balanced over its two columns: each card goes to the shorter column, so the left one no longer stays half empty. Cards stay in place when one opens its output or details.
  • patch: dqx loopback refuses to move the router while a served suffix has no working resolver file - local.dolphiq.eu would otherwise land on Herd or Valet at 127.0.0.1 - and checks afterwards that every suffix answers the new address.
  • patch: Dependencies: fast-uri 3.1.7 (GHSA-qw65-cvwx-89v3, GHSA-58mr-gqgx-xq4g) and ip-address 10.5.1, both within their ranges.

1.55.0 ​

  • minor: The change map zooms from 50 to 200 %, keeps its flow legend on one row with +n more, routes arrows through the gaps between cards, ends an arrow to an off-screen station in a chip that goes there, and draws a collapsed flow only as wide as its files
  • minor: The change map has a focus layout: pick a station and it moves to the centre, with where things come from on the left and what depends on it on the right.
  • minor: Fix feedback: pick the AI findings, your own comments and your colleagues' open PR comments, and open Claude Code on the pull request's branch with them as a brief.

1.54.0 ​

  • minor: The human review marks the words that changed in a line, folds whitespace-only changes, and shows moved code as a move with a link to the other end
  • minor: The human review has a third view: the change map draws the pull request as a metro map, with arrows checked against the code, the unchanged code the change depends on, and Find uses and AI traces to follow a thread. dqx review --map prints the arrows too.
  • patch: The e2e browser container no longer shows as failed on the card or in dqx doctor when it is stopped: dqx e2e starts it per run

1.53.0 ​

  • minor: Human review: read a pull request by its flows, open context and whole files, and post your own comments with the AI findings; dqx review --map
  • minor: Suggest with AI in the human review: Claude drafts a code change for the lines you pick, posted as a GitHub suggestion or a Bitbucket code block and marked as drafted with AI

1.52.0 ​

  • minor: Review with the built-in quick, thorough or security profile in any repository, and set up every review setting from one popup on the pull requests page
  • minor: Agents can read dqx reviews, check the machine and verify sites through MCP, snapshot and sync behind --allow-write; dqx_run refuses deploys; database snapshots are never committed

1.51.0 ​

  • minor: Choose the model, effort and a review profile per review, set up from the dashboard or the config; review every repository of a project

1.50.0 ​

  • minor: Review a Bitbucket or GitHub pull request with Claude and post the findings you pick: dqx review, dqx auth --set bitbucket, and a review tab in the dashboard

1.49.0 ​

  • minor: dqx runs next to Herd: its resolver answers dqx's suffixes with the router's own address (no IPv6 answer when that is one IPv4 address), and alsoResolve in ~/.config/dqx/config.yml hands a suffix such as .test to Herd; walked end to end in the new guide page dqx next to Herd
  • minor: New projects get .dqx domains: dqx suffix lists, adds and removes the suffixes dqx serves and sets the default; a Dolphiq machine serves local.dolphiq.eu as well without being told, and dqx init refuses a domain under a suffix this machine does not serve
  • minor: .test is no longer served for every machine, because Herd and Valet use it; a project whose config states .test keeps working, and dqx doctor warns about it where Herd or Valet is installed
  • minor: dqx loopback 127.0.0.2 moves dqx off 127.0.0.1 so Herd or Valet keep it and both serve 80 and 443 at once; it prints the one sudo step, keeps the address across reboots, and dqx loopback reset puts it all back
  • minor: The shared router listens on 127.0.0.1 by default instead of every address, so 80, 443 and every site behind them are no longer reachable from the network; routerBindAddress: 0.0.0.0 brings that back, and every router is recreated once
  • patch: dqx up names what holds 80 and 443 by its process - MAMP, XAMPP, Apache, nginx, Valet, Herd, Laravel Sail - stops it where that needs no password and prints the command where it does, and leaves a server on another address alone
  • patch: The installer always sets up dqx's resolver, which a check that never matched had skipped on every new machine; local.dolphiq.eu then resolves locally, without the internet

1.48.1 ​

  • patch: The documentation site builds again when a changelog entry names a placeholder with a space in it, such as <primary domain>: it is quoted as code instead of read as an unclosed HTML tag

1.48.0 ​

  • minor: dqx init --from carries every key it accepts into the written config - database, install, notes and each site's branch, schema, services, hooks, php, image, secured and nginx - refuses the ones it cannot carry by name, and reads a .dq/config.yml itself
  • minor: The generated nginx site no longer adds wide-open CORS headers or answers preflights itself, which doubled the headers of an app that sends its own; sites[].nginx.cors: open brings the old block back
  • minor: dqx sync replaces a site conf the old dq tool wrote and nobody edited (byte-equal to its output), keeping a .bak, so those sites lose the wide-open CORS and get room for their headers; an edited one is still kept
  • minor: sites[].nginx takes maxBodySize, timeout and headers: an upload limit, how long nginx waits on PHP or a dev server, and response headers written into every location it generates
  • minor: A site's own nginx lines live in .dq/nginx/<primary domain>.conf: dqx sync pastes them into its server block before its own locations, nginx -t checks them, doctor names one that no site reads, and dqx domains --write renames it with the domain
  • minor: dqx doctor lists site confs a project has taken over, warns when one is not committed, and says what the config or a snippet could carry instead; dqx adopt lifts a site's upload limit and timeout from its server block into keys
  • minor: A site's nginx keys and .dq/nginx/ snippet reach DDEV (.ddev/nginx/ and the server blocks dqx writes) and Lerd (custom.d/ and request_timeout, tested with nginx -t in Lerd's own container); what a backend cannot carry, Herd all of it, is reported by sync and doctor
  • minor: sites[].install.npm: false skips the node install and build for one site, such as an API without a front end, while the rest of the project installs as before
  • patch: dqx sync adds the database service when database is declared in a project whose stack has none, instead of reporting the stack unchanged
  • patch: sites[].secured is described as what it is, https, and defaults to true as dqx init already wrote it
  • patch: Rewriting a config no longer drops its notes or a site's empty services list, and no longer loses edited project hooks and shared repositories to the copy that was read
  • patch: The generated nginx site gives PHP responses 32k for their headers instead of nginx's 4 KB default, which answered 502 as soon as a Laravel page sent one security header more than usual
  • patch: PHP in the generated stack no longer sends X-Powered-By with its version on every response; dqx tune adds expose_php=Off to an existing project
  • patch: dqx sync tests the new site configs with nginx -t before it reloads, puts the previous ones back when nginx refuses them, and says the project is not running rather than to start it
  • patch: dqx init --from a project's own .dq/config.yml clones it instead of running its scaffold again, and still records the scaffold it was made with
  • patch: dqx sync updates an existing .lerd.yaml: the keys dqx writes follow the config, and every other key Lerd or a person put there is kept, where before any difference left the file as it was

1.47.0 ​

  • minor: A second site on one checkout can run on a database of its own: sites[].env reaches its requests as fastcgi_param, and its commands and daemons export the same values
  • minor: dqx e2e: run a project's Playwright suite in the stack, in a browser container that trusts the local certificates, against a site with a database of its own
  • minor: services[] can declare a command, join the shared router's network and trust this machine's certificate authority, which is what a browser container needs
  • minor: Dashboard: run a project's browser suite from its card, on a project that declares a browser container
  • minor: dqx e2e --ui, --report and --show-trace serve Playwright's UI and its trace viewer on ports of this project's own, and dqx prints the address to open rather than the container's own
  • minor: dqx up, install, sync, switch, doctor and the dashboard say when a newer dqx is out, and self-update restarts a running dashboard without losing its open tabs
  • patch: dqx install and switch no longer write SESSION_DOMAIN into a .env that does not have it, and never when the session cookie is __Host- prefixed: a project that removed the key on purpose had its login broken on the next install
  • patch: A site that declares no database still owns the client key, so adding a schema to a second site no longer removes the first one's CREATE and GRANT from the generated init SQL
  • patch: The generated init SQL is regenerated again: its marker was a line the classifier did not recognise, so dqx treated its own output as a hand edit and every schema added to a config was silently never created
  • patch: dqx sync --dry-run says which files it would replace, not only which it would write
  • patch: dqx sync reloads nginx after rewriting a site config, so a site added by hand is served instead of answering 404 until the stack is restarted
  • patch: dqx up teaches the router a domain added since it was created, so a new site resolves from inside a container and not only from the browser
  • patch: dqx doctor no longer calls a site's own database an oddity when the site states it in sites[].env
  • patch: dqx e2e starts the browser container in seconds rather than a minute: seeding Chromium's certificate store ran certutil -N against a database that already existed, which asks for a password and asks again forever until the capture timeout killed it

1.46.0 ​

  • minor: Every config key says what it is, in dqx config schema, --json, the dqx_config_schema MCP tool and the configuration reference, from one source that a test refuses to leave empty
  • patch: dqx up on a running single-layout project no longer calls its own containers a port conflict: the check that asks which ports this project already publishes ran a bare docker compose ps, which finds no stack in a project that keeps one under .dq/
  • patch: The install block in a README builds a clone line that works: a repository stated as a full URL had the fleet's base glued onto it, by both dqx sync and dqx layout
  • patch: dqx doctor agrees with the browser about certificates: it read the shared dqx.crt, which is deleted once every project has its own, so every routed project reported no certificate while being served a valid one
  • patch: dqx layout single converts a checkout that is not a git repository yet, and a dry run says how many entries would move
  • patch: Raise the per-test timeout to 30s: nineteen test files spawn a real process and bun runs files concurrently, so two of them crossed the 5s default on a two-core CI container. A timeout in bunfig.toml is silently ignored by bun 1.4, so it is the flag

1.45.0 ​

  • minor: Clone a legacy or unadopted project, and rewrite every env file the copy needs
  • minor: dqx agent-env: a running copy of a project for an agent, with a database of its own
  • minor: dqx clone --worktree and dqx agent-env --worktree: share the original's git database
  • minor: Dashboard: file a project's copies and agent environments under it
  • minor: Dashboard: say how a copy is attached, and make agent environments from the card
  • minor: Worktrees across several repositories, each on a branch of its own
  • minor: Start an environment's branches from origin/development, or wherever --from says
  • minor: Remove an environment's own branches with it, keeping any that hold work
  • minor: MCP: an agent can make, list and remove its own environments
  • minor: dqx init --like: a new project with the shape of an existing one
  • minor: Offer the Claude Code registration while installing dqx, and check it in doctor
  • patch: Keep a checkout that is already there rather than cloning over it
  • patch: Attach the checkout you are standing in when --worktree names none
  • patch: Raise nginx's server name bucket so a copy's longer domains start
  • patch: Say when an environment's schemas will stay empty

1.44.1 ​

  • patch: Keep the dashboard serving when a clock tick cannot read the machine

1.44.0 ​

  • minor: dqx install refuses on a project dqx has not adopted, and names dqx adopt as the way in
  • minor: dqx up frees 80 and 443 from whatever holds them, and recreates a router that is up but bound to neither

1.43.0 ​

  • minor: dqx auth --apply writes this machine's composer credentials into a project's environment, and dqx doctor reports when composer inside a project cannot read credentials this machine holds. A legacy stack mounts auth.json where it decided to and composer reads where it decided to, and those disagree silently: composer picks ~/.composer when that directory exists and ~/.config/composer otherwise, and every stack here mounts a cache at /root/.composer/cache - which makes docker create /root/.composer. A stack mounting auth at the XDG path therefore misses by one directory, and composer install prompts for a password that is in the container all along. --apply runs composer config --global --auth, so composer writes to its own home whatever that is: it works on any config version, on none at all, and on stacks dqx did not generate and nobody is going to edit
  • minor: dqx up mounts your composer credentials where composer reads them, on a legacy stack that mounts them somewhere else or nowhere. Composer takes ~/.composer as its home whenever that directory exists, and every stack here mounts a cache at /root/.composer/cache - which creates it. A stack mounting auth.json at the XDG path therefore misses by one directory and an install prompts for a password the machine already holds. Layered as a compose override outside the checkout, so the project's own docker-compose.yml is untouched and down, exec and logs address the same stack up created. Only services that would actually run composer: an image naming php or composer, or a built service called app - four legacy stacks here copy the composer cache onto their nginx, and a token does not belong there. Three of 35 projects need it

1.42.0 ​

  • minor: Remove the watch feature: dqx watch, watch:install, watch:uninstall and watch:status are gone, along with the login agent they installed, the activity sampler, the per-engine event streams and ~/.local/share/dqx/activity.json. An installed watcher cost about 200 MB resident for as long as you were logged in, and the only thing consuming what it measured was the card's "active 3s" - so that goes too, and a card now reads up 14h and nothing else. The idle ladder meant to justify the measurement was never built. An agent already installed is not removed by this release; .ai/plans/watch-removal.md has the three lines that remove it, and a note that the dqx entry in Login Items is more likely the DNS resolver, which stays. That plan also records what it would take to sense activity again without a background process
  • minor: Act on the branch code review: refuse a git transport that runs commands (ext::) and pass -- before git clone's positionals; constrain domains in the config schema; read both pipes in proc.capture so a command that floods stderr cannot deadlock; give capture and the dashboard's spawns a timeout; make the coverage gate refuse a stale or partial lcov and fail on a core file no test loads; pin the CI images and add bun audit; one quoting helper in the core instead of three copies outside it; atomic writes for the JSON dqx keeps about itself; validate every dashboard request body with zod; and split the three biggest functions - projectReport 567 to 64 lines, envCommands 509 to 21, App.vue 2834 to 1909 with the configure, copy and create dialogs as their own components. Verified against byte-identical dqx doctor and --help output, and in the browser. New guard test: every Vue template only names bindings its script declares

1.41.1 ​

  • patch: The dashboard's log panel drops the same lines the terminal drops. It only stripped colour codes before, so every container-state line dqx up filters was shown on a card - and so was i18next's sponsor banner, which a project's dev server prints on every start and nobody acts on. Filtered when the log is rendered rather than as it streams, because chunks arrive without regard for line endings

1.41.0 ​

  • minor: The dashboard card says how long, not what: up 12h · active 10s for a running project, last used 3d ago for a stopped one. It named the signal before - net, exec, files - and 59 of 63 cards read files, whose timestamp was 7 to 30 days old for most of them: the newest mtime in a checkout is when somebody edited the code, not when anybody used the project. Activity now counts only a request, a shell or a start, only for running projects, and only while something is sampling - a stale activity.json is ignored by the reader rather than presented as current, because a sampler that stopped cannot flag its own absence. The sampler skips stopped projects and caches the project list, which took a pass from 920 ms to 60 ms

1.40.3 ​

  • patch: dqx watch:install says what it costs before installing: about 200 MB resident for the watcher and one event stream per engine, for as long as you are logged in, and nothing consumes what it records yet beyond the dashboard's ordering. dqx watch in a terminal is the way to gather data without a permanent agent. The four watch commands also reach the published command reference for the first time
  • patch: dqx self-update refuses unless it is a released binary. It renames the download over process.execPath, which from a checkout is bun - so it could replace a developer's bun with a dqx release. The Homebrew guard only caught that where bun happens to live in /opt/homebrew/Cellar; installed the official way at ~/.bun/bin/bun it read as standalone and nothing stopped it. A build in a checkout's dist/ is refused for the same reason, since bun run build is what replaces that. After a successful update it restarts a loaded watch agent, which otherwise keeps running the old binary indefinitely - a rename leaves the old inode mapped and KeepAlive never fires because the process never dies. And watch:install records the resolved real path rather than the symlink that invoked it

1.40.2 ​

  • patch: The dashboard's db dot opens the same schema picker as the mysql 8.0 button beside it - one popover, two triggers - so the two places that name a project's database behave alike. from image reads as a note rather than a heading: it wore the uppercase letter-spacing that labels the DATABASE and PROJECT rows use, on two thirds of the cards here, for something an unadopted project cannot act on. And a project's open button sits on the same right edge as every site's, with its path no longer in the faintest ink, which made a working button look disabled

1.40.1 ​

  • patch: The dashboard offers a project's schemas even where no .dq/config.yml declares them, read from each site's .env. An unadopted project showed "no schema named" and Open → TablePlus landed on whichever database the server listed first; five projects on this machine were affected. Craft's CRAFT_DB_DATABASE is read as well as Laravel's DB_DATABASE

1.40.0 ​

  • minor: dqx no longer sets BOOST_PHP_EXECUTABLE_PATH, and dqx ai --write removes it from a Boost project's .env, .env.example, .env.testing, .env.testing.example and .env.profile-dev, saying which of them git tracks. The example is included because a committed one re-seeds the key into every clone; nothing production-shaped is ever written. Boost 2 reads that key on every tool call, in the process running boost:mcp, so dqx php there is dqx: not found inside a container - measured, every Boost tool dead while the server still connected. Unset, Boost uses the php already running it, which is right everywhere. .mcp.json is still corrected - that is what the key was for - and dqx ai and dqx doctor now say when boost:install has written a host-php command there.
  • minor: dqx talks to the container engine over its HTTP API where the socket answers, and falls back to the CLI where it does not. Measured on a 27-container fleet: dqx memory 2828 ms to 389 ms, the dashboard's memory clock 7.3% of a core to 0.02%, its liveness clock 7.1% to 4.6%. dqx doctor gains an engines line naming each engine, the socket it resolved to and which adapter answered - orb start repoints /var/run/docker.sock and switches the active docker context without saying so, and that line is where you see it. Compose stays on the CLI: it is a client-side plugin the daemon knows nothing about
  • minor: dqx watch measures when each project was last actually used - network bytes on its containers, execs somebody typed, and edits in the checkout - and writes it to ~/.local/share/dqx/activity.json. The dashboard's "last used" stops being a proxy for when a container was recreated. A counter that went backwards is a restart and therefore a use; a pass that came more than three intervals late is a gap and says nothing about idleness, so a laptop that slept overnight does not wake to a fleet that looks idle
  • patch: dqx no longer counts one container engine as two. It asked docker and podman by name and concatenated both, and a context pointing at the socket another engine owns made both names answer with the same fleet: that engine's memory doubled in dqx memory and on the card, while the other engine's containers went unasked and invisible
  • patch: The dashboard's cpu figure is the share of the machine's CPU actually in use, measured by diffing os.cpus() between passes. It showed the one-minute load average against the core count before, which is a queue length rather than a utilisation: measured on a 16-core Mac it read 73%, 45% and 41% at moments when the machine was 18.5%, 22.4% and 18.8% busy. The new figure matched top to within half a point in every check. It costs one os.cpus() call, 7 µs, and reads nothing until the second pass because the counters are cumulative since boot

1.39.3 ​

  • patch: dqx tune sizes a project's database server for a laptop instead of a server: measured idle, mysql:8.0 goes 363 MB to 118 MB and mariadb:10.6 74 MB to 39 MB. It writes one file, docker/conf/mysql/mysql_extra.cnf, so it works on a pre-v4 project whose stack is hand-maintained and which dqx sync would regenerate whole - and it merges rather than replaces, so a buffer pool the project raised for its own dumps survives. --dry-run shows the change, --all reports every project on the machine without writing to any of them
  • patch: dqx tune also sizes a project's search node: it lowers an Elasticsearch or OpenSearch heap to 256m, which is 960 MB idle against 701 MB measured on elasticsearch:8.17.0. It swaps the value inside the ES_JAVA_OPTS line the project already wrote and touches nothing else in a hand-maintained stack; a service stating no heap at all is reported with the line to add rather than edited, because where its environment block starts is a guess. Redis is deliberately left alone - it idles at 15 MB
  • patch: dqx tune also raises the OPcache ceiling and the realpath cache in docker/conf/php/php-ini-overrides.ini. Measured on one app container serving two Laravel checkouts out of one pool: 30 892 PHP files between them, and on the old defaults OPcache filled at 5 572 scripts with no free memory - past which it stops caching rather than evicting, so every further script is recompiled on every request. A ceiling, not an allocation: the segment is resident only as it fills, which is why that container idles at 15 MB with 128M configured. The PHP ini is now merged the way mysql_extra.cnf always was, so a raised memory_limit no longer returns to the default on the next sync
  • patch: dqx tune reports what it will not decide for you: Xdebug left on for every request, an opcache.revalidate_freq that delays seeing your own edit, and a Docker Desktop given less than 8 GB for every container on the machine
  • patch: dqx tune turns an idle php-fpm pool from dynamic to ondemand. Measured on one app container: five idle workers at 10.2 MB each, and the same five at ~51 MB after twenty-five requests, where they stay - dynamic keeps up to max_spare_servers of those alive, ondemand reaps them after 30s and idles at zero. pm.max_children is deliberately left as the project set it: these apps call each other server-side, and a pool too small to hand a request its second worker does not slow down, it deadlocks
  • patch: dqx tune reports what a project's front end costs without touching it: a Vite project compiling Sass with sass rather than sass-embedded (measured on the same stylesheet in the same container - 0.92s and 4.35s of CPU against 0.45s and 0.95s, so 4.6x the CPU on every save), inline sourcemaps embedded in every chunk, a front end still building with Laravel Mix, and usePolling - which a measurement here shows buys nothing, since a host write produced three of three watch events inside the container. vite.config.js and package.json are the application's own code, so these are findings, never edits

1.39.2 ​

  • patch: The dashboard no longer scrolls anywhere when you start or stop a project: the card moving between Stopped and Running is enough to see, and a page that jumps under you while you read the output is more unsettling than a card that moved
  • patch: Every site a project answers on is a site you can run a command in: dqx shell, exec, php, composer, npm, test, dev and db now resolve the domains an older config never named but its nginx serves - the same list the dashboard has always offered - and standing in one of those checkouts picks that site instead of asking

1.39.1 ​

  • patch: A wheel tick during a start no longer costs you the scroll: somebody scrolling still stops the dashboard correcting the card's position, but the card actually moving in the list - the reorder the follow exists for - is followed either way. One tick from a resting hand used to leave the card 900px above the viewport with the page anchored somewhere unrelated

1.39.0 ​

  • minor: dqx memory and the dashboard card report the same figure docker stats does - cgroup usage less reclaimable file cache - instead of anonymous memory alone, so an idle php-fpm reads 14 MB where the card said 10; the docker exec per container that derived it is gone with the --cgroup flag it made redundant, and the reading no longer costs 3.5 seconds
  • minor: A generated mysql_extra.cnf turns performance_schema off - 229 MB of an idle mysql:8.0's 361 MB, measured - and a project that needs it back declares performance_schema = ON in database.settings
  • minor: A pre-router stack whose database says nothing about performance_schema starts with it off - 229 MB of an idle mysql:8.0, measured; one project here went from 386 MB to 137 MB. The flags that stack already passes are reproduced verbatim, and a project that names the setting itself, in its command or a mounted .cnf, keeps what it says
  • minor: A project counts as used when you stop it, not only when you start it: dqx down records the time, so a stack left running since this morning and stopped just now sorts above one started an hour ago and never opened
  • patch: The dashboard re-reads memory every thirty seconds instead of every two minutes: the reading no longer execs into each container, so the figure can follow a project that has just started working
  • patch: A declared database setting the stub also names is now the value written: sql_mode = TRADITIONAL in database.settings was accepted and silently replaced by the default, which the reference had documented as working
  • patch: The dashboard re-reads memory the moment a start or stop finishes, and again at 3, 10 and 30 seconds while the servers inside are still warming up - a card no longer shows a stopped project holding what it gave back, or a started one holding nothing
  • patch: The dashboard scrolls the card you pressed Start on to the top of the screen, instead of stopping wherever its top happened to enter the upper three quarters - which on a 712px viewport left a median card two thirds below the fold, with the command output that renders inside it off screen
  • patch: The dashboard says v1.38.1 (+dev) when it is not the released binary, so a build of a checkout and the checkout itself are told apart from a release - all three print the same version number, and hovering says which one you are looking at

1.38.1 ​

  • patch: After a release, the main pipeline opens the pull request back to development through the house pipe, so the next release does not roll the same pending changes again

1.38.0 ​

  • minor: The pipeline rolls the release on main: it runs dqx release, commits Release x.y.z [skip ci], tags it and pushes the repository before publishing to the host - so a version is never forgotten and two merges on one day cannot conflict in package.json
  • patch: The pipeline tags the commit it published on main - v<version>, with that version's changelog entry as the message - so git can answer what a release contained
  • patch: The dashboard says demo instead of its version in demo mode, so a release no longer changes a word in every screenshot on the documentation site

1.37.0 ​

  • minor: dqx up no longer writes .mcp.json, CLAUDE.md, AGENTS.md or an .env key: it says when they are out of date, and the new dqx ai [--write] [--site] does it when you ask. dqx sync and dqx adopt still write them as part of taking a project over

1.36.0 ​

  • minor: dqx adopt reports the env values naming this project's own domain on the legacy 8080 port, and rewrites them to the address the router serves with --write - .env.example and .env.testing included, because that is what a fresh install copies

1.35.0 ​

  • minor: dqx verify and dqx switch fail a site that answers a redirect to a port nothing serves - the shape of an application still naming the port its stack used to publish, which a status code alone reported as a success

1.34.1 ​

  • patch: A project you have just started shows its ports and its place in the list within a tick: the two-second pass now reads what the once-a-minute discovery used to, and a start - from a button or a terminal - reads that one project again rather than the whole fleet
  • patch: The dashboard keeps the card you pressed Start on in view while the list reorders around it, and stops following the moment you scroll yourself

1.34.0 ​

  • minor: A service that stopped while the rest of a project runs is reported as itself: dqx doctor and the card name it, with its exit code and the line from its log, instead of leaving an application to say 'Name does not resolve'

1.33.4 ​

  • patch: dqx list shows a project whose containers no backend knows any more - never started, or removed - so it says the same thing about the machine as the dashboard

1.33.3 ​

  • patch: A site's wildcard is written out on the card - *.example.test rather than a lone asterisk beside the domain

1.33.2 ​

  • patch: The dashboard shows a site's wildcard subdomains again: a config states them in domains.wildcardSubdomains, and the card only looked for a *. alias

1.33.1 ​

  • patch: A project on a v1-v3 config shows every domain its nginx serves, not only the ones its REPOSITORIES list names - and dqx adopt keeps them, saying which checkout and public directory each came from

1.33.0 ​

  • minor: The dashboard follows your system's light or dark setting, with a pill in the header that switches it and remembers the choice
  • patch: The dashboard starts in a browser told to block site data: reading a remembered preference no longer throws before the page mounts
  • patch: Every colour in the dashboard comes from a token, and the smallest labels now reach AA contrast in both themes - a test asserts the ratios rather than trusting the eye

1.32.0 ​

  • minor: The documentation site gained a task-oriented front door, a page for developers outside Dolphiq, contributor pages on code style and pull requests, screenshots of the dashboard from a fictional fleet, and generated command output
  • minor: dqx dashboard --demo serves a fictional fleet from a file, read only and marked, and --port picks another port
  • patch: Correct the documentation and dqx repair where they still described one shared certificate for the machine rather than one per project, and where the config reference showed a services: shape v4 refuses
  • patch: An access failure names repositoryBase and the command that sets it when the repository was a bare name

1.31.1 ​

  • patch: dqx dev and dqx db take the site from the directory you are standing in, the way dqx bash always has - and a test now fails any new command that takes --site without reading it

1.31.0 ​

  • minor: Add a project from the dashboard: dqx remember, and a + menu that links an existing project or creates a new one
  • minor: Cards say which layout a project has and show v4 in green, not only the older dialects
  • minor: dqx configure --from - prints a review of a settings change: what moves in the config, which directories move, and how much of the stack it costs
  • minor: dqx images --catalogue lists the house PHP images from the registry with the PHP and node versions the images themselves report
  • minor: A gear on every current docker project opens a settings screen: images, php, node, public dir, catch-all subdomains and install flags, applied with the cheapest step that makes them real
  • minor: The gear applies a domain rename too: the config, the checkout directory, every .env value naming the old domain, the certificate, the route and the framework caches - without stopping the project
  • minor: The settings screen folds php.ini, hooks, notes, catch-all and PHP extensions behind a summary, and its image field takes any reference - the catalogue is a list of suggestions rather than the only choice
  • minor: dqx dev also runs the asset dev server of a normal site, on the port the project's stack publishes, and the stack now passes VITE_PORT into the container - assets no longer fail with ERR_CONNECTION_REFUSED while the page itself works
  • minor: Every project owns a block of four dev-server ports, published by its stack - so several projects and several sites can run a dev server at the same time
  • minor: A rename from the configure dialog names the project's own files that still hold the old domain, the way dqx domains --write does, and the scan follows the checkouts the config names so single-repo projects are covered
  • minor: dqx configure --json answers with one object (plan, steps, log, refusals included) and dqx images --catalogue --json returns the catalogue entries
  • patch: dqx install issues the project's own certificate and reloads the router, so a new project is not served Traefik's default certificate
  • patch: A multi-layout project with a scaffold no longer needs a repository per site: the scaffolded site is created, not cloned
  • patch: dqx sync rewrites its own out-of-date nginx and php configs again, keeping a .bak; only a file whose generated marker was removed is left alone
  • patch: The settings dialog reads better: read-only facts sit in a strip at the top of each block instead of under a folded section, the rename note appears where the rename happens, and the image dropdown always lists every option including the project's own
  • patch: Dialogs scroll their own content and lock the page behind them, so a tall settings screen stays usable on a short window
  • patch: The dashboard tells the browser it is dark, so the scrollbars and select popups match it, and reserving the scrollbar gutter stops the page shifting when a dialog opens
  • patch: A dialog taller than the window is reachable: the veil scrolls and aligns to the top instead of centring the title out of view
  • patch: The test suite no longer writes machine-wide router files, certificates or caches: a fixture keyed like a real project overwrote that project's route
  • patch: An apply reports a failed step instead of throwing, so a machine without docker or mkcert says which step could not run
  • patch: The settings dialog lines its notes up with the fields they belong to, grows a textarea to fit what it holds, and wears a hairline scrollbar

1.30.0 ​

  • minor: dqx githooks: write, refresh or remove a site's pre-commit hook, with --force to replace one dqx did not write and --off to remove only its own

1.29.0 ​

  • minor: Read what a project's own pre-commit hook runs when adopting it, and give each tool the file list it needs so a formatter never runs on the whole checkout

1.28.1 ​

  • patch: Accept dqx adopt --dry-run, which is what it already does by default, instead of answering 'unknown option'

1.28.0 ​

  • minor: One floating panel and one dialog for the whole dashboard, placed against the button that opened them and flipping when the window has no room

1.27.2 ​

  • patch: Link to the documentation from the dashboard header, taken from the release host so a staging build links to staging

1.27.1 ​

  • patch: Take a project's names off the shared certificate when it gets its own, so a machine coming from an older dqx completes the move on its first up
  • patch: Point at dqx doctor --all and dqx repair after a self-update, rather than changing the machine inside an update nobody asked for

1.27.0 ​

  • minor: A certificate per project instead of one carrying every domain on the machine, with the shared one shrinking to the remainder and removing itself

1.26.0 ​

  • minor: Keep each project's domains in a cache, refreshed on up and sync and pruned only when a project is gone from disk - 1 ms instead of a 1.3 s scan
  • patch: Issue the shared certificate from one machine-wide domain list, so a reissue cannot leave the domains it never looked at reported as missing

1.25.0 ​

  • minor: dqx repair reissues the shared certificate itself, and serves a reserved suffix that stopped resolving - saying which steps need your password and which do not

1.24.0 ​

  • minor: Check the router, the shared certificate's coverage and real DNS resolution per suffix in dqx repair and dqx doctor --all
  • patch: Name a site by its checkout directory as well as its domain, and find the site you are standing in when a project has no config
  • patch: Show what a project's nginx actually serves on the card of a project dqx has not adopted, instead of directory names that are not domains

1.23.1 ​

  • patch: dqx kill no longer removes a network a stopped container still needs, which made the next dqx up fail with 'network not found' or a container-name conflict
  • patch: Clear a stopped container of this project holding a name its stack needs, and name the one that belongs to another project instead of repeating docker's conflict four times

1.23.0 ​

  • minor: Verify what dqx self-update installs: a sha256 from the manifest, and assets only from the manifest's own host
  • minor: Refuse a clone destination the dashboard has no business writing to, and gate the clone routes behind --read-only
  • patch: Report in dqx doctor what a project's config would execute

1.22.0 ​

  • minor: Offer to stop a running project from the copy dialog, instead of refusing with an instruction the dashboard could carry out itself

1.21.0 ​

  • minor: Remove a copy from its own dashboard card, behind a question that says it goes to the trash
  • patch: Make the copy dialog solid rather than transparent - it referred to a colour token that does not exist

1.20.2 ​

  • patch: Ask for the identifier and the destination in a proper dialog when copying a project from the dashboard

1.20.1 ​

  • patch: Move check and copy into a per-project menu on the dashboard, so Start is the only button of its weight on a card

1.20.0 ​

  • minor: Copy a project from its dashboard card: a form for the name, branch and temporary flag, with the output streaming into the card

1.19.0 ​

  • minor: Write an explicit priority on every route, so an exact domain always beats another project's wildcard, and report overlapping wildcards in dqx doctor --all

1.18.0 ​

  • minor: dqx clone --branch, --temp, --list, --remove and --prune: switch a copy to a pull request's branch, and remove copies to the trash

1.17.0 ​

  • minor: dqx clone: copy a v4 project so the copy runs beside it, on its own URLs, containers and database

1.16.2 ​

  • patch: Keep public domains out of local routes and the shared certificate - a stack answering to *.ngrok.io was putting it on both

1.16.1 ​

  • patch: Route and certify the domains a pre-router stack serves but its config never declared - one project served seven and declared two
  • patch: Leave nginx regular expressions, addresses and host.docker.internal out of the names read from server_name

1.16.0 ​

  • minor: Dashboard: what each project is holding, with a per-container breakdown, and the machine's own memory and load beside the version
  • patch: Dashboard: one line per checkout - directory, branch and the way in, without the labels in front of them

1.15.1 ​

  • patch: A Bitbucket link names its branch as a parameter rather than in the path. After /src/ Bitbucket reads <ref>/<path> and cannot tell where a branch name ends when it has a slash in it, which nearly every branch here does - measured, that url does not resolve and this one does
  • patch: A GitLab link carries ref_type=heads, the parameter GitLab puts in these urls itself. GitHub needs nothing: it looks the branch name up rather than guessing where it ends, measured against a public repository with a real branch called 12/SECO-414
  • patch: The git column appears on the project as well as on each checkout. A wrapper is often the clone - 41 of the 51 projects here - and ten of those hold checkouts with no remote at all, so asking only about the sites left them with no way to their repository
  • patch: Cards flow down a column and on to the next instead of sitting in rows. A grid row is as tall as its tallest card, so a project with one site left hundreds of pixels of nothing beside a project with four, and the row after it began below both

1.15.0 ​

  • minor: A card opens a project or a checkout in the editor you work in. The open button shows a panel in two columns - the editors this machine has, and Finder, a terminal, a container shell and the database client - and dqx looks for PhpStorm, Cursor, Antigravity, VS Code and Warp, offering the ones actually installed. It opens a directory, which is what reopens the project somebody already has rather than making a new one
  • minor: The database line on a card is the server and nothing else, and clicking it names the schemas on it and the clients this machine has to open them with. It used to be a dot, a version, every schema as a chip and a client button beside them. dqx looks for TablePlus, Beekeeper Studio, Sequel Ace, DataGrip and DBeaver, and dqx db takes --schema for the same reason: a client cannot switch after connecting
  • minor: The open panel gains a git column: the repository's own page on the branch the checkout is on, and the desktop git clients this machine has. The page comes from the remote in .git/config, so Bitbucket, GitHub and GitLab each get the spelling that host uses for a branch, and a self-hosted server still gets a link to the repository itself
  • patch: The dashboard reads better: a card is as tall as its own content instead of stretching to the tallest in its row, which left a project with one site under 250 pixels of nothing; the php version and the branch are small pills again rather than card-wide boxes that read as empty input fields; the hide button no longer sits over the first line of the output; the mark is bigger; and the web container is not listed as a service on either card path, because the urls above already are it
  • patch: The php tag on a card reads 'php 8.3' and names the exact image when you hover it. The version is what a person thinks in; the image is what they need when the version is not the whole answer
  • patch: The php tag shows a help cursor, the way every other thing on a card that only carries a tooltip does
  • patch: Both columns are ordered by what has actually been used on this machine, counted in opened.json. A menu that always leads with the same entry is one somebody scrolls past every time, and the editor a person reaches for is a habit rather than a property of the project
  • patch: The editor list knows more editors, and puts a terminal where a terminal belongs. PhpStorm, Cursor, VS Code, Windsurf, Zed, Sublime, Nova, WebStorm, IntelliJ and PyCharm are editors; Warp, iTerm, Ghostty and Antigravity sit beside the shell instead
  • patch: dqx db takes --schema, which the handler read and the command never declared - so every attempt from the dashboard's database panel ended at 'unknown option --schema' and opened nothing
  • patch: A connection is named after the schema it opens. One server here holds five, and all five arrived in the client under the same name
  • patch: Each schema carries one button per database client rather than a column that set a preference and did nothing when clicked. With two clients installed there is no single obvious answer to hide behind one button
  • patch: A card lets its panel out. The panel was clipped at the card's own edge and the card below painted over the rest, so a project with three schemas showed one of them

1.14.0 ​

  • minor: The dashboard opens a running mail catcher in the browser and a running redis in TablePlus. Both need a published port, so the override for a project behind the router keeps one for each the way it already did for the database: loopback, and a port the kernel picks
  • minor: dqx inbox opens the mail a project sent and dqx redis opens redis in TablePlus, both with --url to print the address instead. The dashboard's footer says every button on it is a dqx command you can run yourself, and for these two that was not true
  • patch: The agent block goes into both CLAUDE.md and AGENTS.md where a project has the first. Claude Code reads one and Codex, Cursor and Zed read the other, so choosing between them always left some agent seeing nothing. In CLAUDE.md it goes inside Boost's project-guidelines section where there is one and at the top of the file where there is not: Boost replaces only its own block either way
  • patch: A card lists the services actually running as well as the ones its config declares. A config older than v4 has no services key, so a legacy card listed none of them - and no button to open one could ever appear
  • patch: Site urls sit one per line rather than wrapping when they fit, and the output of a start or stop folds itself away five seconds after it succeeded, leaving the line that says how it went. A failure never folds
  • patch: A project dqx has not adopted gets the same service buttons as one it has. Its card is built on a different path, and the published ports were only wired into the other one
  • patch: Output that folded away can be folded again. Clicking the summary opened it and there was no way back to the one line that said how it went
  • patch: The redis database number is in the url, and the dashboard offers one button per database a project uses. TablePlus cannot switch after connecting - 'This feature is not available for this driver' - and one project here spreads across four, read from its checkouts' env files, so a single button on database 0 reached a quarter of what is there
  • patch: A service with several ways in opens a short list instead of lining a button up for each. Redis is the one that has them: a project can spread across four databases and a client cannot switch between them after connecting
  • patch: The shared certificate covers a project whose stack predates the router. It is served through the router like any other, and only a stack that declared the router triggered a reissue - so the project started fine and every one of its domains answered net::ERR_CERT_COMMON_NAME_INVALID
  • patch: The certificate reads the domains of a project dqx has not adopted off its stack. Such a project names no sites in its config, so its domains never reached the certificate at all

1.13.2 ​

  • patch: The agent block goes into CLAUDE.md's project-guidelines section where a project has one, because that is the file an agent opens. Laravel Boost reserves that section for the project's own knowledge and rewrites only its own block above it. Writing to AGENTS.md beside such a file left it unread, and an agent asked to install composer dependencies reached for docker exec instead of dqx composer
  • patch: The note about where agent guidelines go is corrected from Boost's own source. It said a block in CLAUDE.md is lost at the next boost:install; Boost's GuidelineWriter replaces only its own block and writes the rest of the file back untouched. That belief is what sent the notes to a file no agent was reading

1.13.1 ​

  • patch: The dashboard says "Started in 12s" rather than "[dqx up exited 0]" when a project starts: an exit code is a developer's unit and zero-means-success is the least intuitive convention we have. A failure keeps the code, where it is the only information in the line, and names the command to run in a terminal for more
  • patch: The dashboard tells two copies of one project apart by the directory compose recorded, not by container name: starting the copy in one tree used to show the copy in another as running too, because both declare the same client key

1.13.0 ​

  • minor: dqx up sets BOOST_PHP_EXECUTABLE_PATH to dqx php where a project uses Laravel Boost, so the command Boost writes into .mcp.json does not go stale. dqx never writes Boost's own entry - Boost regenerates that file on every install - and this key is the hook it reads. The value it replaces names a backend, a container and a checkout, each going stale on its own schedule
  • minor: dqx sync and dqx adopt --write set up the agent files exactly as dqx up does: the .mcp.json entry, the agent block and the Boost key, from one function so none of them can quietly do less than another
  • minor: A stale Laravel Boost entry in .mcp.json is pointed through dqx, so the server works without waiting for a boost:install. Three shapes exist across this fleet, each naming a backend, a container or a checkout. Rewritten only, never created, and a .mcp.json in the project root is covered as well as the ones in the checkouts

1.12.0 ​

  • minor: A project with a docker-compose.yml and no usable config runs through dqx like any other: dqx up, php, artisan, composer and shell all work there, reading the config dqx adopt would write without writing it. The dashboard runs dqx up for every project again instead of calling docker compose itself for those, which is where the two had already drifted
  • patch: The dashboard retries a start that failed on a stale network id, the way dqx up already did. dqx kill removes a project's network while its containers still hold the old one, so the next start from the dashboard failed with 'network <id> not found' and stopped there
  • patch: A route is named after the project rather than the client key, and names its project in its first line. 47 projects here share 30 keys and one key belongs to six directories, so every copy wrote the same route and declared the same Traefik router - stopping the copy you were not using removed the route the one you were using needed
  • patch: dqx router:up drops a route whose project has been moved or deleted. Such a route answers 502 for a domain nobody serves, and can win on priority over a project that does serve it. Only routes that name their owner, because guessing is how a route somebody still needs gets deleted
  • patch: The docs build no longer fails on a changelog entry that quotes an error message. VitePress renders markdown through Vue, so a <id> in a sentence was parsed as a tag and the build stopped with 'Element is missing end tag', naming a generated file rather than the entry behind it

1.11.1 ​

  • patch: dqx up starts the shared router for any docker project, not only one whose stack declares it. A project served through the router has no host ports of its own, so after a dqx kill it came up with five containers, nothing published and nothing answering
  • patch: dqx down removes the route as well as the override. A stopped project's route can win on priority over a running project that declares the same domain, so the working one was unreachable while Traefik reported its own backend as UP. Matched by the container it points at, because a client key is what a project shares with its copies
  • patch: A project that declares no sites says so, instead of 'Several sites here - name one:' followed by an empty list. It points at dqx adopt, which reads the sites off the stack
  • patch: The agent block and the .mcp.json entry are written once per checkout rather than once per project, and each note describes the checkout it is in. An agent opens the application it works on, and a file in the first site's checkout says nothing to one sitting in the fourth

1.11.0 ​

  • minor: dqx up writes the two things a coding agent needs, on every start: dqx's entry in .mcp.json, and the agent block in the file that agent actually reads. Only dqx sync used to, and sync regenerates a project's whole stack - so an older project never got either, and its instructions went on hardcoding a docker exec path that stops existing at the next domain change
  • patch: Closing the tab during a start or stop no longer prints a stack trace. The output of that command was still being written to a reader that had gone, and 'Invalid state: Controller is already closed' escaped from a child-process event handler where nothing catches it. The command itself carries on: somebody who closes the tab during a start wants the project started, not half started
  • patch: A restart of the router puts it back on the network of every project it was serving that way. Those connections are made at runtime and a restart drops all of them, so several projects answered 502 at once with nothing saying why. It works this out from the running containers rather than from bookkeeping: a web container that is not on the shared network is one the router can only reach by joining its own
  • patch: The shared servers transport is declared once, in its own file, instead of in every route that names it. Traefik logs 'HTTP servers transport already configured, skipping' for each duplicate, because a file provider assembles one document and a key defined four times is a conflict
  • patch: The port preflight reads the ports a pre-router project will actually publish, override included. Without it dqx up refused to start a project over a clash that could not happen: a stack declaring 1025 and 6379 while its override published neither
  • patch: Six source comments named a client by its short key, which the guard did not catch because its list held full names only. Both are in it now

1.10.0 ​

  • minor: The dashboard keeps finding a project after its containers are gone. Discovery used to start only from what a backend still knows, so removing the containers of the last running project in a directory made every project in that tree disappear at once - nine of them, measured, each with a valid config and nothing on screen saying so. dqx now records where it has been in projects.json, and counts every project it has ever started
  • minor: A directory with a docker-compose.yml and no usable dqx config gets a card too, marked not adopted: no config at all, one dqx cannot read, or one that names no client. Its key, sites, services and database are read off the stack, and start and stop run docker compose there rather than dqx, which the button says. One such project was invisible beside a clone of itself that did have a config
  • patch: Nothing dqx does in a temporary directory is remembered, and neither is anything its own test suite touches. Without the first the neighbour scan read the whole temp directory and listed four thousand projects; without the second a test fixture appeared on the developer's real dashboard
  • patch: An unadopted project starts through the router too. The override that serves a stack predating the router reads that stack and no config, so it applies unchanged: without it the dashboard's start button ended at 'Bind for 0.0.0.0:443 failed: port is already allocated', which is what the stack asks for and not what anybody wanted

1.9.0 ​

  • minor: The dashboard shows a project's database beside its sites, where it belongs: one server, the schemas on it, and whether it is up. The version comes from the config where one is declared and from the running image otherwise, and a disagreement between the two is shown rather than resolved out of sight
  • minor: The dashboard has a search box beside the sort row. It filters on a project's name, its client key, a domain it serves or the directory it is in, every word having to match; the group counts and the footer follow the filter, and it clears with the cross, with Esc, or from the footer
  • patch: A running database opens in TablePlus from the dashboard. It runs dqx db, so the backend answers which host port it published and the url goes straight to the client application rather than through the browser
  • patch: A pre-router project keeps a published database port, on loopback and a port the kernel picks. Dropping every host binding was right for the fixed ones and wrong for this one: dqx db reads back whatever compose published, so a stack with no published port takes the project out of TablePlus entirely
  • patch: A project whose stack predates the router no longer joins the router's network; the router joins the project's network instead. Compose names every container after its service on each network it joins, and these stacks say fastcgi_pass app:9000 in an nginx file that lives in their own repository, so on a shared network that name resolved into whichever project answered first
  • patch: The router speaks TLS to a legacy stack that terminates it, rather than plain http. Over http that stack's nginx reports HTTPS off, the application builds every asset url as http, and the browser blocks the lot on an https page: a site with no stylesheet and no layout
  • patch: The guide explains both routes into the router: how a generated project joins the shared network, and a page of its own for a stack that predates it - what is overridden, which file holds it, what dqx down puts back, and how to start such a project with plain docker compose when you need to

1.8.0 ​

  • minor: dqx up serves a project whose stack predates the shared router, instead of refusing it: a compose override drops its host bindings and puts its containers on the router's network for as long as it runs, and a route sends its domains at its web container. The project's own docker-compose.yml is never touched and dqx down removes the override. Measured: 35 stacks here still publish their own ports and 25 of them bind 443
  • patch: dqx up no longer refuses a pre-router project whose stack collides with nothing: the check fired on any stack that did not declare the router and asserted a clash without looking, while one such project publishes 8000, 3306, 8025, 1025 and 8080 to the container's 80, none of which the router holds
  • patch: A port clash names the process that actually holds that port, rather than whoever holds 80 and 443. It also recognises a published range: docker prints 127.0.0.1:8025-8026->8025-8026 and the check looked for :8025->, so a port that was plainly taken had no owner
  • patch: The override also resets expose, which unblocks a second class of project entirely: six stacks write expose: '3306:3306', a mapping form that key never took, and compose validates the file then refuses to create the container
  • patch: A router route names its target as a whole url. It used to wrap a bare container name in http://...:80, so a caller that knew its own port produced http://http😕/name:80:80, which Traefik answers as a 502 and says nothing about
  • patch: The dashboard marks a project whose stack predates the router, and its site URLs are links again: the checkout name was the button that opened Finder, and for a single-domain checkout that name is the domain, so clicking what looked like a URL opened a file browser
  • patch: Only the web service of a pre-router project joins the router network, and it keeps its own. Moving the whole stack there put app, db and redis on a shared network under the names every stack uses, so one project's nginx could resolve app:9000 into another project's application container

1.7.0 ​

  • minor: dqx dashboard: every project on this machine in a browser, grouped by client with running ones first, sites as links, service dots, doctor findings on demand, and start and stop that stream the output of the dqx command they run
  • minor: Running dqx dashboard while one is already serving stops that one and takes over, so a dashboard left running elsewhere is never in the way and the flags just typed are the ones that apply
  • minor: The dashboard shows where each project is and takes you there: click the path for Finder, a terminal button for a shell in that directory, and a container button for dqx shell inside it. A multi-site project gets those per site, resolved to each site's own checkout
  • minor: dqx shell takes --site, the flag every other site-scoped command already takes and the one the generated agent guidance tells an agent to type. The positional still works, so nothing that worked stops working
  • patch: The dashboard starts and stops projects by default; --read-only turns that off. It binds loopback, checks Origin and mints a token per run, and doctor and rescan stay available read-only because neither changes anything
  • patch: A project is addressed by an id derived from its directory rather than by its client key: measured on a real machine, 42 projects share 27 keys, so a key identifies a client and not a project
  • patch: Running dqx dashboard while one is already serving stops that one and takes over, so the flags just typed are the ones you get; a public /api/whoami is how it recognises a dashboard, and anything that does not answer it is reported rather than signalled
  • patch: The dashboard starts writable, with --read-only for a shared screen: the MCP posture does not transfer to a person clicking a button on their own machine, and a flag everybody types every time protects nothing
  • patch: The dashboard marks a project whose config predates v4. dqx reads v1 to v3 perfectly well, which is why they appear and work; nothing on screen said so, and 25 of 54 projects on a real machine are older than v4
  • patch: The dashboard skips a .dq/config.yml that declares no client key. One such file is a two-line marker for other tooling and rendered as a card with no name
  • patch: The dashboard opens a container shell with dqx shell --site, which is what it should have run: --site was not an option shell had, so the button opened a terminal that printed unknown option
  • patch: The dashboard card is laid out as labelled lines rather than one crowded row: project path, then a block per checkout with its branch, the domains it serves and the buttons that open it. A checkout whose name is already its only domain does not repeat it
  • patch: The dashboard groups projects into Running, Stopped and Legacy with counts, sorts by recently used or by name, and shows the git branch each checkout is on read from .git/HEAD
  • patch: The dashboard shows the backend a project pins, and says in the footer how many projects it is not showing because they pin another one. 34 of 44 configs declare no runtime at all, so a badge appears only for a real pin rather than asserting docker on every card
  • patch: A dashboard tab whose session was taken over says so within a couple of seconds, instead of sitting on reconnecting: a heartbeat asks a body-less endpoint whether the token still opens anything, and runs only while disconnected so a healthy dashboard pays nothing
  • patch: Recently used ordering now takes the later of dqx's own record and when docker created a project's containers. The record alone covered 3 of 41 projects on a real machine, so the order was indistinguishable from sorting by name

1.6.0 ​

  • minor: The last four things a hand-written local_install.sh did that no config could say: a dump loaded into a schema, a service configured once it is up, a repository not everyone can read, and a site whose application is created rather than cloned
  • minor: database.imports fills a schema from a dump the checkout ships, so a legacy database a test suite reads survives a fresh install instead of coming up empty
  • minor: services[].postStart runs a project's own configuration call against a service once the stack is up, which an image cannot carry and a healthcheck cannot make
  • minor: repositories[].optional marks code not every colleague can read: the install reports it and goes on, where a required repository still stops it before the first clone
  • minor: sites[].scaffold declares a site whose application dqx creates, so a scratch application built to prove a package installs is a site rather than a directory dqx doctor reports as unclaimed
  • minor: dqx doctor reports a site whose php and image disagree: docker runs the image and every other backend runs the declared version, so the pair is a PHP version that changes on dqx switch
  • minor: dqx init and dqx adopt write the URL a bare repository name resolves to, so a committed config no longer depends on repositoryBase, a setting that belongs to one developer's machine. A full URL given at init is taken as written
  • minor: dqx config schema prints every key the config accepts, its type and its default, from the schema itself. The dqx_config_schema MCP tool already answered this and nothing on the command line did
  • minor: routerBindAddress in ~/.config/dqx/config.yml chooses which address the shared router publishes 80 and 443 on. Naming one loopback address leaves the others free, which is how dqx runs beside Herd: Herd has no port setting at all, only herd loopback, so the two separate by address and both keep standard ports and clean URLs. The default is unchanged and writes the same stack a machine already has
  • minor: Three pages the site did not have: how to remove dqx (the binary, its state, the router, and the certificate authority and resolver files it shares with other tools), what dqx stores and where (which credentials are committed, which are only mounted, and what the local CA means), and the shared router as a subject rather than as an aside in four other pages
  • patch: A site declaring php and no image gets the image the fleet runs for that version. It used to leave the compose template's own placeholder in the generated stack, so the app service ran with no image at all, and the documented example was one of the configs that did it
  • patch: A php version dqx has no image for is refused by name at dqx sync instead of being guessed into an image that does not exist
  • patch: A site declaring neither a repository nor a scaffold is refused when the config is read, rather than installing nothing and reporting success
  • patch: dqx doctor reports a config whose requires floor is below what its own keys need. Nothing rewrites the floor when a config is edited by hand, which is how most of them change, so a colleague on an older dqx read a key it silently dropped
  • patch: A directory holding code the project clones is no longer reported as a site nothing claims: the check knew only about sites, so a project cloning shared packages was told every install that nothing owned the directory it had just created
  • patch: The nginx config for a site whose repository is stated as a URL is named after the repository rather than the URL, instead of writing a filename carrying a colon, a slash and an @
  • patch: The MCP schema walker reaches one level deeper, so sites[].repositories[].branch and its siblings are listed at all. A site's repositories were one opaque entry, which is the shape an agent most often has to write
  • patch: The generated agent guidance says how to change the configuration - read dqx config schema, edit .dq/config.yml, run dqx sync - rather than leaving an agent to write keys from memory
  • patch: dqx doctor names the config dialect when a project is still on a pre-dqx one. .dq/ is the directory every version of the tool has used, so nothing outside the file says which it is, and dqx reading all of them means a v1 project looks entirely healthy until something rewrites more than expected
  • patch: The Requirements and Install pages state the download size. A curl | bash that fetches 62 MB should say so first
  • patch: No client name or container key appears in the source, matching the rule the published site already had, with a test that keeps it that way

1.5.0 ​

  • minor: dqx up returns once the containers are started instead of waiting for every healthcheck; dqx up --wait keeps the old behaviour, and install, switch, link and the MCP tools still wait because each runs a command straight after
  • patch: Redis and Meilisearch healthchecks state their own interval, so dqx up stops waiting 30 seconds for docker's default probe on a service that was ready at once

1.4.0 ​

  • minor: dqx sync regenerates a stack dqx wrote itself when .dq/config.yml has moved on, instead of refusing it as a hand edit
  • minor: dqx doctor reports a stack that is behind .dq/config.yml
  • minor: dqx info prints and returns the raw docker compose call for this project, for a machine where dqx is not what runs
  • patch: The project certificate's private key is gitignored - it was committed to wrapper repositories
  • patch: dqx up reissues the project certificate before starting a stack that terminates TLS itself
  • patch: dqx up refuses a docker project with no generated stack instead of starting whatever compose file the directory holds
  • patch: dqx sync reads the stack from .dq/ in a single-repo project when deciding router mode, so a plain sync no longer answers routed
  • patch: dqx doctor finds a single-repo project's certificate under .dq/ instead of reporting it missing
  • patch: up --wait no longer calls a project unhealthy for a declared daemon carried through from a hand-written stack

1.3.1 ​

  • patch: The advice for a stack still holding 443 names the flag that converts it: dqx sync --force keeps a pre-router project on its own ports, only --router moves it behind the shared proxy

1.3.0 ​

  • minor: A snapshot that captured no database stops the switch it was taken for, prunes nothing, and says so on restore: one taken while its backend was down left an empty directory that looked like a safety net
  • minor: The quiet output path carries stdin, so install --only schemas actually runs its SQL instead of reporting success on an empty pipe, and the nginx map dqx generates moves into a file it owns so a project keeping its own default.conf still starts

1.2.0 ​

  • minor: When 443 is taken, dqx names the project and the container holding it and offers dqx sync in that directory: several docker projects are meant to run at once behind the shared router, and the one that cannot is a stack that still binds the port itself

1.1.0 ​

  • minor: Create a project from a recipe: dqx init and the scaffold registry - laravel, qore-works-business and qore-cms - including for coding agents through MCP
  • minor: A repository is a full URL, per repository, so a project can span Bitbucket and GitHub at once
  • minor: Documentation for four audiences, with dqx docs opening it locally and a published site carrying the release it documents
  • minor: One place the binary lives: install.sh, latest.json and the binaries published together, so dqx self-update reads the same host the docs do
  • minor: dqx healthchecks finds compose probes that can never pass - a quoted test: exits 127 for ever and up --wait believes it
  • minor: dqx images pins the image tags of services that keep data on disk, and --outdated says when a pin has fallen behind
  • minor: dqx update-images refreshes the house images this machine already has, and never fetches a version line it does not run
  • minor: notes: in the config are printed after a successful install - what a person still has to do that no command can
  • minor: dqx adopt reads a project's init SQL for the schemas and the user no .env mentions, and stops overwriting declared MySQL server settings
  • minor: dqx version --where says which of the three dqx installs is answering, and bun run link:release goes back to the released one without downloading it again
  • minor: database.password and database.rootPassword may be declared for a stack whose data directory was initialised with different credentials; dqx adopt records them only when they differ from the fleet's
  • minor: dqx_config_schema: an MCP tool that reads every config key, type and default out of the schema, so an agent writing a config or an init document does not work from a list that has fallen behind
  • minor: The version floor a config writes is derived from every key it uses, not from the layout alone: compose overrides, a scaffold, declared credentials and a repository URL each raise it, and an older dqx misreads all four silently
  • patch: The documentation drops em-dashes and is tightened throughout; a guard test keeps them out, generated pages included

1.0.0 ​

  • major: One committed config drives four local backends - docker, ddev, lerd and herd - chosen per project
  • minor: Every project served at once behind a reverse proxy dqx owns: no fixed host ports, one certificate, no port collisions
  • minor: Install a project from nothing, and adopt an existing one of any dialect - v1, v2, v3 or no dq tools at all
  • minor: The daily verbs on every backend - shell, artisan, composer, npm, test, db, logs, xdebug - and dqx switch to move a project between them
  • minor: dqx doctor and dqx info: what is wrong with the machine or the project, in facts a developer and a coding agent read the same way

dqx v1.78.0