New in the 0.4.0-SNAPSHOT development line of the Vidocq Runtime — everything listed here landed after the 0.3.0 release and is not part of it. Every entry links to the section that documents it, and those sections carry the NEW badge. Each brick of the suite keeps its own page of this kind; the ecosystem index gathers them. When the next release train ships, this page is frozen with it and restarts empty on the dev line.
Runtime
-
Startup banner with the exact Vidocq version — every boot tells which Vidocq starts, once per JVM, before anything later can fail:
Vidocq 0.4.0-SNAPSHOT (9beafc47+dirty, built 2026-09-17T14:02:11Z), then the Java version, the profile or dev launch, and the application. A terminal, a dev profile or IntelliJ’s Run console get the art on standard output; containers, CI, pipes and tests get one log line.vidocq.banner.mode=auto|console|log|off, a customvidocq-banner.txtwith placeholders, andVidocqBootstrap.banner(BannerMode.OFF)for embedders.vidocq devnow starts its spinner after the banner. Startup banner. -
The launch mode, and the debugger, in the startup identity — every boot says which of
dev,testandprodit is, with the signal it was read from:Java 25+36-LTS | dev (IntelliJ agent) | debug *:5005 | mcp-time-server 0.1.0-SNAPSHOT.prodnever shows without(no dev or test signal), since nothing proves it. A JVM started with-agentlib:jdwp=…shows the address a debugger has to attach to, in every mode, and repeats it on aVidocq debugger: attach to …record when the 80 columns of the banner could not hold it. Neither the mode nor the address is ever lost to the JVM vendor, which the line gives up first.vidocq.launch.mode=dev|test|prodforces the mode; it changes what is printed, and the runtime itself behaves the same in every mode. Launch mode. -
Build identity in every jar —
vidocq-parentwritesMETA-INF/vidocq/build-info/<artifactId>.properties(version, abbreviated commit, dirty flag, commit time, and build time outside releases, which stay reproducible), so two snapshots with the same version are told apart. Build identity. -
Every Java 25 main shape starts the application — when Vidocq picks the main itself, it now picks the one
javawould:main(String[])andmain(), static or an instance method, public or not, declared in the class, inherited from a superclass, or adefaultmethod of an implemented interface. The selection mirrors the launcher’s, down to the parts nobody guesses — a declared main ends the search even when it cannot be used, so aprivate main(String[])sends the launch tomain(). An IDE on JDK 25 flags thepublicof a main as an unnecessary modifier: following that advice no longer makesvidocq:runfail. Aprivateor non-voidmain is named as such, with the class that declares it, instead of being reported as a missing main (Vidocq/vidocq#88). Which main methods are accepted. -
Readable console logs by default — when the application has not configured logging, Vidocq replaces the JDK’s two-line records on standard error (red in an IDE) with one aligned line per record on standard output:
[LEVEL][timestamp][thread][class#method] : message, with a coloured level on a terminal or in IntelliJ’s Run console. Any logging setup of the application wins (logging.properties, an SLF4J or Log4j bridge,vidocq.log.console=jdk);vidocq.console.colorandNO_COLORcontrol the colours. The examples no longer carry their own copies of a stdout handler and formatter. Console logging. -
A startup report at the end of every boot — one INFO record, just before
Vidocq - Started in, says what has just started: the launch mode and the signal it was read from, the application layer and its modules, the configuration sources and the audited namespaces (never a value), the extensions and the time of eachonStart, and the section of every library that contributes one. One line per section by default, everything on the first boot of a dev launch, nothing for an embedded deployment such as the TCK;vidocq.startup.report=auto|off|summary|detailedchooses. Every anomaly is its own WARNING record, its code first, logged even with the reportoff:VIDOCQ-CFG-001for an invalidvidocq.startup.reportorvidocq.launch.mode,VIDOCQ-CFG-003for a key read by nothing —vidocq.startup.reprotincluded, andvidocq doctornow knows thevidocq.startup.*keys —VAUBAN-009for load-time weaving that could not be prepared,VIDOCQ-RPT-001andVIDOCQ-RPT-002for a contributor that fails or takes an id already used. A boot that fails logs one warning naming what was running, the time spent and the codes already logged, with the partial report in a dev launch, then lets the same exception through, untouched. A library adds its section withStartupReportContributor, in the new packageio.vidocq.runtime.spi.reportofvidocq-runtime-spi: an extension only implements it, any other library declares it as a service, and nothing needsvidocq-runtime-core. Extensions read the launch mode withExtensionContext.launchMode(). Startup report, Contributing to the startup report. -
Chappe listeners say where they really listen, and an extension can bring its own — every listener now logs the address it bound, so
port=0prints the real port and an IPv6 address is bracketed. An extension declares a listener of its own withChappeMountPoint.declareListener(listener, options): it may fall back to a free port when its port is taken, log quietly, stop with a short grace period, and is handed the address it bound.vidocq.chappe.listenerscan no longer list such a listener, nor silently replace it. A listener of an extension’s own. -
The dev console — run
mvn vidocq:dev, which adds the console itself (see the dev tools entry below):Vidocq dev console: http://127.0.0.1:8888/opens a read-only page, on a loopback listener of its own, with the startup report of the running boot, its anomalies first, then one tab per extension, and the JVM last. The Mansart pools show live: the active, idle and waiting connections of each pool, borrows and timeouts per second, leaks, the mean borrow time. It is on in a dev launch only (vidocq.devconsole.enabled=auto|true|false), listens onvidocq.devconsole.hostandvidocq.devconsole.port,0for a free port that the dev reloads keep, and the banner promises it:devconsole :8888. A port already taken never stops the application: the console takes a free one and says so loudly, in a boxed warning, asVIDOCQ-DEVC-004and on the page. It answers only a request that names its own address, never shows a secret, a JVM argument or a system property, and warns when it is on outside development or off the loopback address (VIDOCQ-DEVC-001toVIDOCQ-DEVC-005). An extension shows its section of the startup report live by implementingDevConsolePanel, from the newvidocq-runtime-devconsole-spi, in its own runtime extension: boot facts once, values sampled from memory on every poll, and the charts to draw.ExtensionContext.startupReport()gives an extension the report of its boot. The Mansart pool extension’s section also names its pools, their sizes and checks, and raisesMANSART-POOL-001for aminIdlepre-fill that opened nothing andMANSART-POOL-002for a named pool that no@Nameddatasource serves. Dev console, Writing a dev console panel. -
A langchain4j-cdi MCP server in one dependency —
vidocq-runtime-langchain4j-cdi-mcp-extensionbrings langchain4j-cdi’s MCP server, its CDI 4.1 invoker, the Jakarta REST runtime and the server’s bean list: an application drops its two langchain4j-cdi dependencies,parsson,yassonandscanDependencies, and an IDE launch finds/mcpwithout a Maven step. The server stays in the boot layer in every launch shape, the application layer holds the application alone, and ninevidocq.mcp.*keys configure it. The startup report gets anmcpsection (tools, prompts, resources, protocols, configuration, never the request-state secret), and five codes,VIDOCQ-MCP-001toVIDOCQ-MCP-005, name what the extension can see going wrong. Built in the reactor and not on Maven Central while langchain4j-cdi1.4.0is a SNAPSHOT (Vidocq/vidocq#94). langchain4j-cdi MCP server. -
The
mcpsection of the startup report is live in the dev console —vidocq-runtime-langchain4j-cdi-mcp-extensionnow implementsDevConsolePaneltoo: besides the boot facts, which stay, themcppanel samples seven values about once a second — the sessions the server holds, the SSE streams and thesubscriptions/listenstreams open, the requests it is still waiting a client’s answer of, and the three counters of the CDI 4.1 invoker — and plots Connections and Server-to-client requests.invoker.matchesandinvoker.missescount distinct methods, not calls: a server of four MCP methods reads4after six calls and still4after six hundred, which is why no chart plots them. The panel never creates a bean — it asks each bean’sContextfor the instance it already has, since creatingMcpSessionManagerwould start itsmcp-session-cleanupthread, once a second, on an application that has served no request — and a bean with no instance is shownabsentwith its reason,no request served yet,not created yet,reflectionorbuilt at the first call, never a zero that would claim a measure the panel does not have (Vidocq/vidocq#94). Themcppanel in the dev console. -
An MCP inspector in the dev console — in a
devlaunch, themcptab lists the application’s MCP tools, prompts and resources and calls them through its own/mcp: a Monitoring sub-tab and one per kind, a list to pick the item, a form from its input schema, the result in a block of its own through a JSON viewer that colours and folds it, the exact JSON-RPC exchange, the kind’s last calls with a replay, secrets masked. Built on actions that now take a JSON argument and return a structured result (ADR 0001, amendment 1). See MCP inspector, JSON viewer and a JSON argument. -
The dev console’s curves survive a hidden tab — the five minutes of history behind every chart moved from the page to the server, where a thread of the console’s own,
vidocq-devconsole-history, fills it once a second for the life of the boot, whether or not a page is open. The page used to keep it, one point per poll, and a browser stops the timers of a hidden tab — on macOS, Chrome counts a window another application covers as hidden — so every curve had a hole covering exactly the minutes you had left the console to go and cause something, which is the interval you came back to look at. A poll now asks for what it is missing,GET /api/snapshot?since=<its newest point>, and a tab that comes back after three minutes away redraws a complete curve in one document. The holes that are true are kept: a tick where a panel wroteabsentkeeps its place on the axis with a null value, and a tick the server itself missed — a long pause, a suspended process, a laptop that slept — leaves no point and breaks the curve, as before. The ring is bounded and the bound is a number: 256 series of 300 points, measured full at 1,966,960 bytes, 1.88 MB, whatever the panels do and however long the run; a series arriving past the cap keeps its live value and gets no curve, and the snapshot sayshistoryTruncated(Vidocq/vidocq#107). Where the history lives. -
The startup report lists the REST routes —
vidocq-runtime-cassini-rest-extensionwrites arestsection: the resource classes, routes and providers it mounted and where, then, in the detailed report, every route in match order with the class and method that handles it, each mount, and the@Providerclasses grouped by contract. It covers the automatic mount and every declarativetype=restfulmount. The section reads the route table Cassini now publishes,CassiniStack.routes(), and creates nothing (Vidocq/vidocq#103, Vidocq/cassini#41). Therestsection of the startup report. -
The startup report prints absolute URLs — a new
httpsection declares every listener of the configuration with the address it really bound, the real port when the configured one was0, so the routes of therestsection readhttp://localhost:8081/api/tasksinstead of/api/tasks, and themcpsection prints the URL of/mcponce, without the internal/mcp/_listenroute. Extensions read the address withChappeMountPoint.boundUrl(name)(Vidocq/vidocq#111). Thehttpsection. -
A metrics panel for Dirac —
vidocq-runtime-dirac-metrics-extensionnow writes ametricssection, Metrics (Dirac), shown live in the dev console: one card per registry, application first, with how many counters, timers, histograms and gauges it holds, every counter’s count, and every timer’s count and mean duration. Each metric gets a key derived from its name and tags, and the boot facts list every key next to the metric it stands for. The panel reads the registries of the producer the application already has and never creates it; it never calls a gauge, which is application code, and never takes a timer’s snapshot, which copies its reservoir (Vidocq/vidocq#115). Dirac metrics. -
A CDI panel in the dev console — the console now has a second panel of its own, CDI (Vauban), between the extensions' panels and the JVM: how many beans the container holds, by scope, its interceptors and its observer methods, and three tables — the beans with their kind, scope, qualifiers and whether they are alternatives, the interceptors with their bindings and priority, the observers with their event type and qualifiers — the application’s rows first. It reads Vauban’s metadata once at boot and creates no bean; Vauban implements CDI Lite, so there are no decorators to list (Vidocq/vidocq#117). Each row also says which code generator covers it —
APT,Class-File,partial,reflection— and what falls back to reflection, and every class outside the application is alibrary, notruntime. The CDI panel. -
A configuration panel in the dev console — the console has a third panel of its own, Configuration, before the CDI container: every
vidocq.andmp.key and every key of the application’s own sources, with the source that wins and its ordinal — the very sourcegetValuereads, so a-Dproperty that overrides the application’s file shows as such — its value in adevlaunch, and whether the core or an extension reads it or the key audit found itunused(VIDOCQ-CFG-003). A key that names a secret, such asdb.adminPasswordorvidocq.mcp.requestStateSecret, readsconfigured; a URL loses itsuser:password@and itspassword=parameter; outsidedev, no value is shown. Everything is masked in the application’s JVM, before the page gets it (Vidocq/vidocq#116). The configuration panel. -
A health panel for Knock —
vidocq-runtime-knock-health-extension, until now a wrapper with no Java class, writes ahealthsection, Health (Knock), shown live in the dev console: the checks of each probe, and per check its last status, when it answered, the name and data of its response,never calleduntil a probe request runs it, with the checks UP and DOWN charted per probe and a button to/health. A health check is application code and may do I/O, so the console never calls one: Knock now remembers the last answer of each check when/health,/health/live,/health/readyor/health/startedruns it, and a check that turns DOWN shows DOWN at the next probe request (Vidocq/vidocq#114). Knock health. -
Actions in the dev console, behind an origin check and a per-boot token — in a
devlaunch, a panel can now offer to do something from the page:DevConsolePanel.actions()listsPanelAction`s, each a button with its string arguments, a list of values or a pattern the console checks, an optional inline confirmation, and a function that returns one line. The console runs one only for its own page: `POST /api/action/<panel>/<action>,application/json, anOriginthat is the console’s own and theX-Vidocq-Console-Tokenof the boot, read from the snapshot; anything else is refused before it runs, and a cross-site attempt is logged asVIDOCQ-DEVC-006. One action at a time per panel, on a virtual thread, logged at INFO; a failure shows its exception class, never its message. Outsidedevthe console stays read-only. No panel offers one yet: the logs and migration panels will (Vidocq/vidocq#118, ADR 0001). Actions, declaring an action. -
A logs panel in the dev console, and a log level set without a restart — in a
devlaunch the console has a third panel of its own, Logs: the last 500 records kept in memory by a handler on the root logger, newest first, without the credentials of a URL and never with a stack trace; the WARNING and SEVERE records since the boot as counters drawn per second; the loggers whose level is set; and a Set level button, the first action of the console, that sets a logger’s level until the next dev reload, which puts it back. When an SLF4J or Log4j bridge takesSystem.Logger, the panel says it cannot see the records instead of showing an empty table.logsjoins the ids reserved for the console (Vidocq/vidocq#119). The logs panel. -
Migrate, or clean and migrate, from the dev console — the
migrationsection ofvidocq-runtime-migration-extensionis now a live panel: per datasource, the version its schema is at, what the last run applied, and in adevlaunch the migrations applied and pending, as Flyway’sinfoor Liquibase’s changelog table give them. Two actions come with it in adevlaunch: Migrate now applies the migrations added since the boot without a restart, and Clean and migrate drops every object of the schema and migrates it again, behind a confirmation, refused with nothing dropped unlessvidocq.migration[.<name>].cleanDisabled=false.SchemaMigratorgainsinfoandclean, default methods that a backend may leave unsupported. The datasource’s password reaches neither the page nor the log (Vidocq/vidocq#120). Themigrationpanel and its actions. -
Dev MCP: the dev console as read-only tools for coding agents — in a
devlaunch the console is also an MCP server, atPOST /mcpon its own listener, so a coding agent asks the running application what it serves:claude mcp add --transport http vidocq-dev http://127.0.0.1:8888/mcp. Five tools,vidocq_report,vidocq_panels,vidocq_panel,vidocq_anomaliesandvidocq_routes, answer from the very document the page polls, without the token of the boot or the actions, and change nothing. The console speaks the part of Streamable HTTP they need, JSON only and without sessions, with no new dependency, whether or not the application uses MCP; theHost,Origin, content type andAcceptare checked as for an action, but no token is needed. Its URL is printed after the console’s (Vidocq/vidocq#121). Dev MCP. -
Every dev services jar is a named module —
vidocq-runtime-devservices-spi,-host,-junit,vidocq-runtime-devservice-postgresand-keycloakused to ship without amodule-info.class; each is now a named module, its providers declared withprovides(Vidocq/vidocq#177). The PostgreSQL provider needs Testcontainers' core only: it configures a plain container, as Testcontainers'postgresqlmodule did, and gives the same JDBC URL. Every pull request now checks that no jar the build publishes is an automatic module (check-named-modules.sh). Every dev services jar is a named module. -
A query editor for JDQL in the dev console — the statement of the Mansart Data panel’s JDQL tab, in Query, Update / Delete and Export CSV, is typed in the dev console’s code editor in a new query mode: keywords, functions, the entity, its attributes, strings, numbers and parameters each coloured;
Ctrl+Spacecompletes the entities afterFROM, their attributes with their Java type and column inSELECT,WHERE,ORDER BYandSET—FROMwritten after the caret included — and a reference’s attributes afterproject.; an unknown entity or attribute, a path through an attribute that is no reference, an unterminated string or an unbalanced parenthesis is underlined before anything runs; Format puts each clause on its line. Itsparamsbecome a JSON editor whose schema follows the statement as you type:WHERE status = :statusoffersstatuswith the values of its enum and flags it missing. A panel publishes such a vocabulary withDevConsolePanel.languages()(orLivePanel’s), `PanelLanguagerecords the page fetches once atGET /api/language/<panel>/<id>in adevlaunch, and names it from ajsonargument’s schema with"contentMediaType": "text/x-query","x-language"and"x-parameters-of". Query editor, A JDQL console for Mansart Data. -
Tables and a SQL editor for each Mansart pool, and a table of rows in the dev console — under
mvn vidocq:dev, the Mansart pools panel gives each pool a tab: Tables lists its tables and views with their columns' number, Describe a table’s columns, types, keys and indexes, Preview its first rows, Query runs a statement that only reads in a transaction always rolled back, and Execute any one statement, asked first and rolled back unless committed; 30 seconds at most,:nameparameters bound fromparams, the pool’s URL and password never shown. The SQL is typed in the query editor, which now reads SQL: aliases, joins, several tables, quoted names, comments, the columns of every table in scope completed with their table, an unknown alias flagged and an ambiguous column warned,LEFT JOIN … ONformatted on one line; its vocabulary, the languagesql-<pool>, is read fromDatabaseMetaDataat boot. A result of rows is now a table — the type of each column under its name,NULLdimmed, Table / JSON and Copy as CSV — which the JDQL tab’s Query answers too; a panel answers one withPanelAction.ActionResult.rows(…). Tables and a SQL editor, A table of rows, SQL. -
Dev service containers are named
vidocq-dev-…— the PostgreSQL and Keycloak dev services used to leave their containers to Docker’s random names; each is now<prefix><application>-<service>[-<datasource>]-<suffix>, such asvidocq-dev-mcp-tasks-server-postgres-3f9a2c01, the prefixvidocq-dev-unlessvidocq.dev.container-prefixsays otherwise. The suffix is random, or for a reused container a digest of the application and the configuration, so reuse keeps finding it. Three labels,io.vidocq.dev,io.vidocq.dev.appandio.vidocq.dev.service, letdocker ps --filter label=io.vidocq.devlist them. A provider of its own names its containers the same way withDevContainers.nameandDevContainers.labels, from the SPI. Container names and labels. -
The PostgreSQL dev service starts only for an application on PostgreSQL — with
vidocq-runtime-devservice-postgreson the plugin, an application whosevidocq.propertiessaysvidocq.pool.url=jdbc:h2:…(or MySQL, or any other database) no longer gets a PostgreSQL container whose URL replaced its own: the provider reads which database the application’s file names and, with no URL at all, starts a container only whenorg.postgresql.Driveris on the application’s class path. A PostgreSQL URL in the file (or a wrapper driver’s, such asjdbc:otel:postgresql:) still gets its container: it is the production one. An application with no URL and the driver in test scope only now needs its URL invidocq.propertiesto keep the container undervidocq:devandvidocq:run. A provider that does not start says why —not started: vidocq.pool.url is jdbc:h2, not PostgreSQL, the scheme only — in the log, the state file, the startup report and the Dev services panel. TheDevServiceContextSPI gainsapplicationProperty(key)andonApplicationClasspath(className), andDevServicegainsskipReason(ctx), alldefault. A PostgreSQL container only for a PostgreSQL application. -
Dev services are visible,
vidocq.properties-aware, and available tovidocq:runand to tests — a dev service’s coordinates used to reach only the application’s-Darguments, invisible to the boot itself: the startup report now has adevservicessection, hostvidocq:dev/vidocq:run/test, image and endpoints per service, its injected keys, a secret alwaysconfigured; the dev console shows the same, live, as its own panel. Avidocq.dev.*tuning key —vidocq.dev.postgres.port,vidocq.dev.reuse,vidocq.dev.devServices— is now also read fromvidocq.properties/application.properties, so the stable-port recipe works without a-Don every run; an opt-out key such asvidocq.pool.urlstill never comes from those files.vidocq:runstarts no container unless asked, with the samevidocq.dev.devServices=true. Every host reads that key the same way, first match wins: the explicit value (-D, the goal’s configuration, a system property), then the application’s files, then the host’s default (on forvidocq:devand tests, off forvidocq:run), so-Dvidocq.dev.devServices=falseoverrides atrueinvidocq.propertiesfor one run. A test addsvidocq-runtime-devservices-junitand a provider, bothtestscope, and aLauncherSessionListenerstarts one set of containers for the whole run, no annotation needed. An unreadable state file isVIDOCQ-DEVS-001, which names its path; the boot goes on. The state file is the project’s, shared by every host:mvn testwhilevidocq:devruns overwrites it, then marks itstopped, hosttest.target/vidocq-dev-services.propertiesstill keeps a password in clear text, local to the machine, forpsql/DataGrip — the JSON state file the application reads never does (Vidocq/vidocq#123). Dev services. -
Continuous testing, in
vidocq:devand in a newvidocq:testgoal —vidocq:devnow runs the application’s tests after every reload, or alone after a test-only change, without reloading the application, and the dev console’s newtestspanel shows the last run: its counts, its failures with the first line of their message, a chart, and the buttons Run all tests and Rerun failed tests, which never name a test.vidocq:testruns the same loop without the application, with a summary in the terminal andr,fandqwhen a console is attached. A run is Surefire itself (mvn test-compile surefire:test), a new change cancels the run in flight, and the result is intarget/vidocq-dev-tests.json, the output intarget/vidocq-dev-tests.log; a run that fails before any test iscompile-errorwhen the compiler failed,errorotherwise, such as Surefire’s provider missing offline (Vidocq/vidocq#138). The tests reuse the dev services containers, and share their database.vidocq.dev.continuousTesting=falseturns it off; it is on when the project hassrc/test/java(Vidocq/vidocq#122). Continuous testing. -
Dev tools only under
vidocq:dev; the-devpanel modules, never packaged — the dev console and each extension’s live panel are development tools: nothing to declare any more,mvn vidocq:devadds the console itself the moment the application hasvidocq-runtime-chappe-webserver-extension, and each extension’s-devcompanion module with it, so its tab is live.vidocq:run,vidocq:package,vidocq:jlink,vidocq:jpackageandvidocq:dockernever contain any of it, even when a project still declares it: every dev-only jar is dropped, with a warning naming it, andvidocq:checkpomwarns about the same declaration earlier, outsidetestscope. A test that reads the console, or a live panel, declares both attestscope. The six extensions that had a live panel of their own — Mansart pools, Knock health, Cassini REST, Dirac metrics, schema migration, the langchain4j-cdi MCP server — each move it to a new-devmodule next to the runtime extension; the older, all-in-oneDevConsolePanelform still works, for an extension that keeps it, and the console SPI it requires, an ordinary API jar, ships in the binary with it.vidocq:ideanow writes a matching Dev,(packaged)and(debug)file for each application (Vidocq/vidocq#143). Getting it, Dev tools and binaries. -
A code editor for JSON arguments, and a form for an entity — in the dev console, every
jsonargument of an action, an MCP tool’s arguments as a Mansart Data repository method’s, is typed in a code editor written for the page: colours, line numbers, the first syntax error and then what the argument’s JSON Schema says at every depth (a missing required key, a wrong type, a value outside its enum, a key the schema does not list, a date that does not look like one), underlined with its message; completion of keys and values withCtrl+Space; Format (Shift+Alt+F), which keeps numbers and strings as written; brackets and quotes closed as you type; oneCtrl+Zper edit it makes. The generated form takes one level of nesting, soTaskRepository.save(entity: Task)gets fields: the required ones starred and refused by their path when empty, the generated id marked(generated), dates with the shape they expect. Mansart Data’s entity schema now says which attributes arerequiredandreadOnly, and names each column. JSON editor, The generated form. -
CSV export and import for Mansart Data — under
mvn vidocq:dev, the Mansart Data panel’s JDQL tab gains Export CSV, which runs a query and downloads its whole result as a CSV file, and Import CSV, which saves the rows of a file you paste or pick as entities, in a transaction rolled back unless you commit it: a header of attribute names,nullapart from"",,or;as separator, at most 5000 rows, the first bad line named before anything is saved. The console gains atext/csvaction result, shown with a Download button, and a Choose file input for a CSV field. CSV export and import for Mansart Data. -
A JDQL console for Mansart Data — under
mvn vidocq:dev, the Mansart Data tab ends with a JDQL tab that runs a statement you type against the application’s database: Query for aFROM, a projection, a count or an aggregate, Update / Delete for a write, asked first and rolled back unless you commit it; named parameters as a JSON object, converted to the attributes' types; the result as JSON, with the last 20 statements and a replay. Mansart gainsJdqlExecutor.runfor it, and a JSON argument’s form now shows a string of"format": "textarea"as a field of several lines. A JDQL console for Mansart Data. -
Run a Mansart Data repository method from the dev console — under
mvn vidocq:dev, the Mansart Data tab gets one tab per repository, which runs any of its methods against the application’s database: the arguments as JSON, converted to the method’s types, an entity built through Mansart’s own model; the result as JSON, with the last 20 calls and a replay. A write asks first and runs in a transaction rolled back by default, or committed. Running a repository method from the dev console. -
A Mansart Data catalogue in the startup report and the dev console —
vidocq-runtime-mansart-data-extensionwrites amansart-datasection: the application’s entities with their table and columns, as Mansart’s own model gives them, and its repositories with each declared method’s kind,@Querytext, parameters and return type, plus the methods they inherit from Jakarta Data. Undermvn vidocq:devits new companionvidocq-runtime-mansart-data-extension-devshows it as the Mansart Data tab, one card per entity with its repositories inside. It reads names only: no connection, no query. An entity whose model Mansart cannot build keeps its place and raisesMANSART-DATA-001. The Mansart Data catalogue. -
The MCP request state is encrypted — with langchain4j-cdi’s MCP server, the
REPLAYrequest state that carries a tool’s elicitation and sampling answers between rounds was signed but readable by anyone holding it; it is now encrypted and authenticated with AES-256-GCM, its key derived fromvidocq.mcp.requestStateSecret. Only this format is read: no released version ever issued the signed one (langchain4j/langchain4j-cdi#303, langchain4j/langchain4j-cdi#305). langchain4j-cdi MCP server. -
MicroProfile 7.2 — the runtime now targets MicroProfile 7.2: JWT Auth 2.2 (Cervantes), OpenAPI 4.2 (Grimm) and Telemetry 2.2 (Humboldt, on OpenTelemetry 1.66). The TCKs of the seven MicroProfile 7.2 component specs, and that of Metrics 5.1 (not part of the 7.2 platform), are green on the assembled runtime (1888 tests). Only the OpenAPI and Telemetry runs use release-candidate TCKs, published on Maven Central and byte-identical to the finals; the JWT Auth 2.2 TCK is final. The 7.2 platform release is still under ballot, and the two runs will be repeated on the finals once they are published. What you will notice: JWT accepts RS256 and ES256 (all RS/ES key sizes) when
mp.jwt.verify.publickey.algorithmis unset, rejects an unrecognised value at startup, and enforces the algorithm family when it is set;@WithSpanspans carrycode.function.nameand@WithSpan(inheritContext = false)starts a new trace; OpenAPI treats unknownSchemaproperties as extensions, reads@Header.example/examplesand method-level@ExternalDocumentation, maps Bean Validation@DigitstomultipleOf/pattern, and writes decimals in plain notation. See the TCK page. -
Buttons in the dev console, and the Swagger UI one click away — a section can now offer to open something the application serves:
StartupReportSection.link(label, listener, path). The log prints the absolute URL; the console shows a button under the panel’s title that opens it in a new tab. The Swagger UI and the OpenAPI document get one in therestpanel and in the newopenapisection, which also counts the operations of the document; aGETroute with no template variable is a link in the route table. A panel never writes a URL: Vidocq builds it from a listener the report declared and a path, and the page only openshttpandhttps. An extension offers a page it serves withChappeMountPoint.advertise(listener, label, path)(Vidocq/vidocq#113). Links. -
The
restpanel is live in the dev console — one card per mount, sampled about once a second from the counters Cassini now keeps,CassiniStack.statistics(): requests per second, responses by status class, requests in flight, the share of time spent in handlers, and the mean and longest time to answer. The counters cost about 25 ns per request and allocate nothing; there is no breakdown per route (Vidocq/vidocq#103, Vidocq/cassini#42). Therestpanel in the dev console. -
A boot that fails stops what it started — when
beforeStart, the container build or anonStartthrew, the extensions already started stayed started: a Mansart pool kept its connections open, and undervidocq:deva failed reload left the dev console’s live panels on the values of that boot. Every extension whosebeforeStartwas called now gets itsonStop, in reverse order, and the container is closed; a failingonStopis logged, the next one still runs, and the exception of the boot goes through untouched. An extension’sonStopmust therefore work when itsonStartnever ran (Vidocq/vidocq#145). When a boot fails. -
@Transactionalnow covers Mansart Data writes with one dependency —vidocq-runtime-mansart-transactions-extensionbringsmansart-transactions-jdbcitself, the JDBC-to-JTA bridge thatmansart-data-cdideclares optional: without it on the module path, a repository call took its own autocommit connection, so a@Transactionalmethod could begin and roll back a real JTA transaction while a write it made just before throwing stayed committed, with no anomaly reported. Adding the extension is now enough (Vidocq/vidocq#97). Mansart Data writes join the transaction. -
Schema migrations run where the application does — under
vidocq:dev,vidocq:runand the launchervidocq:packagewrites by default, the application boots in a module layer of its own, whose class loader lists no directory: Flyway found none of the scripts inclasspath:db/migration, logged one warning, and the boot went on with an empty schema until the first query failed withTable "…" not found, and Liquibase did not find its changelog. Both backends now listclasspath:locations from the application’s own modules, Flyway’s Java migrations and Liquibase’sincludeAllincluded, and a schema history written by a flat launch stays valid.vidocq.migration.locationsinvidocq.propertiesor as a-Dno longer stops the boot with aStringIndexOutOfBoundsException. A datasource that finds no migration on an empty history is now the anomalyVIDOCQ-MIG-001, a warning in every mode. The newmigrationsection of the startup report says what each datasource did, an up-to-date restart logs the version the schema is at instead ofversion=(none),vidocq.migration.failOnMissingLocations=truemakes an empty Flyway location stop the boot, and a mistypedvidocq.migration.*key is reported asVIDOCQ-CFG-003. An extension reads the application layer withApplicationLayer, new invidocq-runtime-spi(Vidocq/vidocq#96). Schema migration, Listing the application’s files. -
Clear errors when the application stays in the boot layer — when
Vidocq.run()finds no application module to move into the Vauban layer, it cannot export theVidocqAppclass’s package to itself, and the boot used to fail with a bareIllegalAccessException. The message now names the class, its package and the two fixes: anexports <package> to io.vidocq.runtime.core;inmodule-info.java, or a CDI bean (Vidocq/vidocq#201). When the application stays in the boot layer. -
@Inject @RestClientworks, and a Rest Client application links — the newvidocq-runtime-cyrano-rest-client-extension-codegenbundle runs Cyrano’s extension and generates each client’s proxy in the compiler: without it,@Inject @RestClientwas unsatisfied at boot.vidocq:checkpomnow fails an application that declares the Rest Client extension without the bundle, and prints the<path>to add;vidocq extension add cyrano-rest-clientwrites it.vidocq:jlinklinks such an application, since Cyrano no longer requiresorg.reactivestreams, an automatic module (Vidocq/cyrano#30). When upgrading, add the bundle to the compiler’sannotationProcessorPaths. The newvidocq-runtime-cyrano-rest-client-exampleshows the whole setup (Vidocq/vidocq#207). The Rest Client extension, Config and Rest Client need their codegen bundle, the example. -
An extension brings what its brick leaves to the runtime — a brick now depends on APIs, and its Vidocq runtime extension picks the implementations (vidocq-workspace#17). The Rest Client extension brings the Jakarta REST API and Champollion’s JSON-B implementation: an application with the Rest Client and no REST server used to fail on the first JSON response, with no JSON-B provider (BUG-20261010-02). The Telemetry extension brings the Jakarta REST API, which
humboldt-restnow leavesprovided. Rest Client extension, Telemetry extension. -
@Inject @ConfigPropertycompiles with validation on — the newvidocq-runtime-ravel-config-extension-codegenbundle puts Ravel’s extension on the processor path, so the Vauban processor sees the beans it synthesises: an application used to getUnsatisfied dependencyat compile time, and the only way out was-Avauban.validation=false.vidocq:checkpomrequires the bundle wherever the Config extension is declared. When upgrading, add it toannotationProcessorPaths(Vidocq/ravel#21). The Config extension, Config and Rest Client need their codegen bundle. -
/openapiin a sealed packaged application — the OpenAPI extension requires Grimm’s named module instead of the automatic one, whichcassini:generatecould fold into the application module, losing every Grimm bean:/openapianswered 404 (Vidocq/grimm#15). The OpenAPI extension. -
Liquibase’s usage analytics stay off — Liquibase 4.30+ sends usage data to Liquibase by default for open-source users. The Liquibase backend now runs every migration, listing and clean with that option off, unless a system property, the environment or a Liquibase defaults file sets it. Liquibase analytics stay off.
Maven plugin
-
vidocq:devpasses-Dvidocq.on to the application — a-Dvidocq.of the Maven command line used to stop at Maven:mvn vidocq:dev -Dvidocq.chappe.listener.default.port=8081still listened on the default port, silently, and-Dvidocq.devconsole.portnever moved the dev console. The goal now forwards the same keys asvidocq:run, by the same rule: everyvidocq.*key that is not a setting of the plugin. The properties the application sees. -
vidocq:devsays which dev service provided a key — each key that the application gets from a dev service is marked with-Dvidocq.dev.provided.<key>=<provider id>, such asvidocq.dev.provided.vidocq.pool.audit.url=postgres, so that the application can tell a dev-service datasource from one configured by hand: the Mansart pool section of the startup report and the dev console showdev service postgres, localhost:54213. The marker names the provider, never a value, and a key that an explicit value kept is not marked. The dev services report no longer takes the user info of a JDBC URL for its host. Mansart pools in the startup report and the dev console. -
vidocq:run— one run of the application, in a JVM forked as the production launcher does, after the goal has forked the lifecycle up toprocess-classes:mvn vidocq:runalone compiles, completes the bean index withvidocq:generateand starts the application. Ctrl+C stops it, its exit code is the goal’s result,-Dvidocq.run.debug=trueopens a JDWP agent, and a-Dvidocq.*of the command line reaches the application. Thevidocq:rungoal. -
The debugger listens on this machine only —
vidocq:dev, andvidocq:runwith-Dvidocq.run.debug=true, used to start the JDWP agent withaddress=:5005: every machine that could reach the port could attach, and a JDWP agent runs whatever code its debugger asks. The agent now listens on127.0.0.1:5005, which a debugger on the same machine reaches as before.-Dvidocq.dev.debugHost=''(vidocq.run.debug.hostforvidocq:run; quote the*, or zsh stops the command with "no matches found") opens it on every interface again,0.0.0.0too, and another address or host name on that interface; the goal then logs a warning that the debugger is reachable from the network. The connection hint ofvidocq dev --debugprintsaddress=127.0.0.1:5005as well. The debug agent. -
Maven’s colours reach the forked JVM —
vidocq:runandvidocq:devpass Maven’s own colour policy to the application as-Dvidocq.console.color. In an IDE’s Maven console, which is neither a terminal nor an IntelliJ Run console, the runtime used to drop its colours while Maven’s[INFO]lines kept theirs. An explicitvidocq.console.colorandNO_COLORstill win. Colours in the forked JVM. -
vidocq:idea(experimental) — IntelliJ IDEA shared run configurations per application of the reactor, written into.run/from what the poms already declare. By default it is three Maven/Remote files: a run ofvidocq:devunder the application’s own name (the one a developer already runs day to day), one ofvidocq:runsuffixed ` (packaged), and a Remote JVM Debug one suffixed ` (debug)that attaches tovidocq:dev’s own debug agent (`vidocq.idea.kind=applicationstill writes a single Application run of the main class instead, with Make andvidocq:generatebefore launch, and no console or debug file of its own). Because the IDE’s own build never runsvidocq:generate, the(packaged)file is what compiles, indexes and starts the application entirely through Maven (Vidocq/vidocq#83). It never overwrites a file you wrote or edited, never touches.idea/, and-Dvidocq.idea.check=truefails a CI build when.run/no longer matches the poms (=strictalso fails on the files you wrote or edited). Thevidocq:ideagoal. -
Generated code for third-party CDI jars —
vidocq:generatenow scans, besides<scanDependencies>, the jars an extension declares in its manifest and every CDI bean archive (vidocq.generate.autoScan, on by default), and gives each scanned jar the code the Vauban processor gives a project:_VaubanComponents, client proxies, intercepted subclasses. They ship in an enriched copy of the jar — given anopen modulefirst when it has no descriptor — thatdev,run,packageandjlinkuse in place of the original. The langchain4j-cdi MCP server’s beans move from reflection to generated code.mvn vidocq:analyze-depsexplains which jars are scanned and why (Vidocq/vidocq#186). Both goals resolve the runtime-scope dependencies as well as the compile-scope ones, so a class that only a runtime-scope extension makes a bean — a JAX-RS@Providerof a scanned jar, under Cassini’s — gets generated code too (Vidocq/vidocq#188). Thevidocq:generategoal. -
vidocq:modularizeis nowvauban:modularize— the goal moved toio.vidocq.vauban:vauban-maven-plugin, with its properties renamedvauban.modularize.*and its output intarget/vauban-modularized/, whichvidocq:dev,vidocq:jlinkandvidocq:packageread. When upgrading, change the plugin in the pom.modularizemoved to the Vauban plugin, migration. -
The legacy
vidocq:packagelayout starts — withvidocq.package.layer=false, the launchers passed a class name to--moduleand the JVM stopped on aFindException. They now launch<vidocq.mainModule>/<vidocq.mainClass>, or the runtime’s own main when the application has none, and a plain main class withoutvidocq.mainModulefails the build with a message that says what to set (Vidocq/vidocq#198). The legacy layout. -
vidocq:dockerchecks that the image is Linux —vidocq:jlinklinks against the build machine’s JDK, so on macOS or Windows the image holds a Mach-O or PEbin/javathat no Linux container starts.vidocq:dockerreads it: it warns and still writes theDockerfile, or, withvidocq.docker.build=true, fails beforedocker build(Vidocq/vidocq#199). Thevidocq:dockergoal. -
vidocq:checkpomprints the<path>to add — a missing codegen bundle used to be reported as a fall back to reflection, which only Cassini does; the message now gives the<path>entry to paste intoannotationProcessorPaths, with its group and version. A-devcompanion module is no longer asked for the codegen bundle of the extension it reads (Vidocq/vidocq#147). Goals. -
The dev console follows the application’s runtime version —
vidocq:devused to resolve the console at the plugin’s version, whatever runtime the application ran. It now takes the version of the application’s Chappe extension, warns when the plugin’s differs, and also looks in the plugin repositories, where a snapshot repository may be declared alone (Vidocq/vidocq#148). Getting it. -
An application can declare its own version —
vidocq-runtime-parentmanaged the Vidocq artifacts and the plugin at${project.version}, which Maven reads in the child: an application with a<version>of its own looked for the plugin and every extension at that version and could not build. The parent now writes the runtime version out. Maven coordinates.
CLI
-
A scaffolded application runs the same everywhere —
vidocq createnow writes a@VidocqMainclass whosemainisVidocq.run(args), as the examples do. TheVidocqBootstrapmain it wrote before booted in place: in a jlink image the application stayed in the boot layer, where the build-time generated_VaubanComponentsis not seen without aprovides, and Vauban fell back to reflection, so a bean with an interceptor (a@Retrymethod, for instance) failed withIllegalAccessExceptionunless the package was exported. An application scaffolded with0.3.0can replace itsmainby the new one.createalso refuses a name or--packagethat is not a valid Java package name (ft-030gave the moduleio.example.ft.030, which does not compile). Getting started. -
Scaffold against a SNAPSHOT — when the parent version is a SNAPSHOT,
vidocq createwrites the Central snapshot repository into the generatedpom.xml, for dependencies and plugins, so--parent-version 0.4.0-SNAPSHOT, or a CLI installed withVIDOCQ_VERSION=snapshot, gives a project that builds as is. See Trying a SNAPSHOT. -
vidocq devandvidocq startrun the project — both booted the runtime inside the CLI’s own JVM, which holds neither the project’s classes nor its extensions, so nothing listened. They now runmvn process-classes vidocq:devandmvn vidocq:run, through./mvnwwhen there is one, and behave as the goals do: live reload, dev console, debug agent.--portoutranks the project’svidocq.http.port.vidocq dev,vidocq start. -
vidocq extension adddeclares the module too — besides the dependency and the codegen bundle,addwrites the extension’s directives intomodule-info.java(itsrequires, and what Cassini and Mansart Data leave to the application), each marked// vidocq:<id>, and pins the parent’s version on what it adds;removetakes all of it back, the codegen path included. The catalog lists the OpenAPI, Swagger UI and migration extensions, and knows the Config and Rest Client codegen bundles.vidocq extension list,vidocq infoandvidocq doctorresolve the project’s dependencies with Maven, so they see its extensions, transitive ones marked(transitive), instead of none.vidocq extension. -
Completion for the whole command line — sub-commands, options and values: the extensions not yet in the pom after
extension add, those it declares afterextension remove, the keys ofvidocq.propertiesafterconfig get|set, all without starting a JVM.vidocq completion installsets it up in~/.zshrcor~/.bashrc, and an installed script follows the CLI that runs.vidocq completion. -
vidocq update— updates the CLI itself, a release to the latest release, a SNAPSHOT to the latest SNAPSHOT build;--checkonly reports. A SNAPSHOT CLI also prints its build time next to its version.vidocq update, Command reference.
Other bricks
-
Vauban — client proxies for third-party produced types, without
opens: the Java SE launcher places them,Vidocq.runre-layers with the same policy, and boot-time opening stays opt-in. What’s new in Vauban. -
Cassini — an unreadable request entity answers 400, not 500, and a host reads the route table and live request figures. What’s new in Cassini.
-
Mansart — enums stored as
@Enumeratedsays, a stricter JDQL parser, and the Jakarta Data core the dev console’s tools use. What’s new in Mansart. -
Heisenberg — fallback methods reached on a strict module path, with no
opens. What’s new in Heisenberg.