vidocq-runtime-cli is the zero-dependency, JPMS-native command-line interface for the
Vidocq runtime. It scaffolds new applications, runs them in a live-reloading dev mode,
wraps the packaging goals of the Maven plugin, manages extensions and configuration, and
diagnoses your environment — all from a single vidocq command. This page is a complete
user guide; jump straight to Getting started — Hello World for a Hello-World walkthrough.
Coordinates
Artefact |
|
JPMS module |
|
Main class |
|
Dependencies |
None beyond the JDK and |
Prerequisites
-
Java 25 (Temurin recommended) — the CLI refuses to run a project on an older JVM and
vidocq doctorflags it. -
Maven 3.9.16 — pinned per project via
.sdkmanrc(sdk env). The build/clean commands reuse the project’smvnwwrapper, falling back tomvnon thePATH.
Installing the vidocq command
The installer downloads the CLI distribution into ~/.vidocq/cli/<version> and puts a
vidocq launcher on your PATH:
curl -fsSL https://vidocq.dev/install.sh | sh # latest release
curl -fsSL https://vidocq.dev/install.sh | VIDOCQ_VERSION=0.3.0 sh # a given release
curl -fsSL https://vidocq.dev/install.sh | VIDOCQ_VERSION=snapshot sh # latest build of main
On Windows (PowerShell), set the same variable before running the script:
irm https://vidocq.dev/install.ps1 | iex
$env:VIDOCQ_VERSION = 'snapshot'; irm https://vidocq.dev/install.ps1 | iex
VIDOCQ_VERSION=snapshot NEW takes the newest -SNAPSHOT of the CLI from the
Central snapshot repository, where every build of main is published. A SNAPSHOT is
downloaded again on every run, since it changes with every build; a release already
installed is kept. A CLI installed this way scaffolds projects against its own SNAPSHOT
runtime (see Trying a SNAPSHOT NEW). Run the installer again to go back to the latest release.
Without the installer, download vidocq-runtime-cli-<version>-cli.zip from Maven Central,
unzip it anywhere and add its bin/ directory to your PATH. The launcher runs the CLI
as a JPMS module:
java -m io.vidocq.runtime.cli/io.vidocq.runtime.cli.VidocqCli <command> [options]
|
Enable tab-completion with |
Getting started — Hello World
This walkthrough scaffolds, inspects, and boots a brand-new Vidocq application in under a minute, using only the CLI.
1. Check your environment
vidocq doctor
doctor verifies the Java version, JAVA_HOME, the Maven wrapper, the project layout, the
extensions in the project’s runtime dependencies, and your vidocq.properties keys. Fix any ✘ before continuing;
⚠ warnings are safe to ignore for now.
2. Scaffold the project NEW
vidocq create --name hello-world --group-id com.example
This generates a ready-to-build Maven project:
hello-world/
├── pom.xml # inherits vidocq-runtime-parent, depends on core
└── src/main/
├── java/
│ ├── module-info.java # module com.example.hello.world { requires io.vidocq.runtime.core; }
│ └── com/example/hello/world/
│ └── HelloWorldApp.java # main() that boots the runtime
└── resources/
└── vidocq.properties # vidocq.http.port=8080
The generated entry point is a complete, runnable Vidocq application. Its main is a Vidocq.run trampoline: the runtime re-resolves the application into the Vauban layer, which reads the build-time generated code through META-INF/services without a provides in your module-info.java, the same way in the IDE, with vidocq start and in a jlink image:
package com.example.hello.world;
import io.vidocq.runtime.core.Vidocq;
import io.vidocq.runtime.spi.VidocqMain;
/**
* Entry point. {@code main} is a trampoline: {@code Vidocq.run} resolves the application
* into the Vauban layer and boots it there, from the IDE, {@code vidocq start} or a jlink
* image alike. Put no code before it: it would run outside that layer.
*/
@VidocqMain
public final class HelloWorldApp {
public static void main(String[] args) {
Vidocq.run(args);
}
}
|
The project name is converted to a |
3. Move in and build
cd hello-world
vidocq build --skip-tests
vidocq build (no type) runs the Maven package lifecycle through the project wrapper and
produces a standalone distribution. Add --dry-run to preview the exact Maven command
without executing it.
4. Run it
vidocq start
The runtime boots in the foreground and awaits shutdown (Ctrl-C). To iterate with live reload instead, use dev mode:
vidocq dev
dev boots the runtime and watches src/main/java, src/main/resources and
target/classes; any .java / .properties / .xml / .yml change is debounced and
re-applies your configuration and resources in-process without leaving the CLI.
5. Add an HTTP endpoint
A bare core application boots the runtime but serves no routes. To expose a REST resource, add the Cassini REST extension and follow the full Jakarta REST + CDI walkthrough:
vidocq extension add cassini-rest
See Getting started for a complete REST + persistence example,
including the resource class, the JPMS module declarations, and curl calls.
Command reference
Run vidocq help for the command list, or vidocq help <command> for per-command options.
| Command | Description |
|---|---|
|
Print the CLI and runtime version string. A SNAPSHOT CLI adds its build time, |
|
Display the CLI/Java version and the extensions of the project in the current directory. |
|
Run environment & project health checks (see |
|
Scaffold a new Vidocq Maven application (see |
|
Run the project in dev mode with live reload, |
|
Build and run the project’s application, |
|
Build/package the project, wrapping the Maven plugin goals (see |
|
Remove build output ( |
|
Manage project extensions (see |
|
Read or write keys in |
|
Print a shell-completion script (see |
|
Set up (or remove) completion in your shell’s rc file (see |
|
Update the CLI itself to the latest release, or the latest SNAPSHOT build (see |
|
Show the command list or detailed help for one command. |
vidocq create
Scaffolds a minimal Maven project (pom.xml, module-info.java, an …App entry point and
vidocq.properties).
| Option | Description |
|---|---|
|
Project / artifact name (required). |
|
Maven groupId (default |
|
Root Java package, also the module name (default |
|
Extension to enable; repeatable. |
|
Version of |
vidocq create --name my-api -g com.acme -x cassini-rest -x knock-health
Trying a SNAPSHOT NEW
Every build of main publishes the Vidocq SNAPSHOTs to the Central snapshot repository, https://central.sonatype.com/repository/maven-snapshots/. When the parent version is a SNAPSHOT, the generated pom.xml declares that repository, for dependencies and for plugins, with releases disabled: the SNAPSHOT artifacts come from there, everything else from Maven Central.
vidocq create --name my-api -x cassini-rest --parent-version 0.4.0-SNAPSHOT
A CLI installed from a SNAPSHOT (VIDOCQ_VERSION=snapshot, see Getting started) scaffolds with its own SNAPSHOT runtime, so --parent-version is not needed there. A SNAPSHOT changes with every push to main: run mvn -U package to pick up the newest one.
vidocq dev
NEW Runs mvn process-classes vidocq:dev in the project, through ./mvnw when there is one: the
application starts with its dependencies and extensions on the module path, the dev console and
a debug agent on port 5005, and restarts on every source change — exactly as
mvn vidocq:dev does, see the Maven plugin for
its settings (continuous testing, dev services, …).
| Option | Description |
|---|---|
|
HTTP listening port, passed as |
|
Config profile to activate ( |
|
Force the debug agent on ( |
Ctrl+C stops Maven and the application; the CLI returns once both are down. vidocq dev and vidocq start
used to boot the runtime inside the CLI’s own JVM, which holds neither the project’s classes nor its
extensions: the runtime came up empty, with nothing listening.
vidocq start
NEW Runs mvn vidocq:run in the project, through ./mvnw when there is one: the goal compiles the
project and starts the application with its dependencies and extensions on the module path.
| Option | Description |
|---|---|
|
HTTP listening port, over the project’s own setting. |
|
Path to an external |
|
Open a debug agent on port |
vidocq build & vidocq clean
Thin, coloured wrappers around the real vidocq-runtime-maven-plugin goals. The CLI resolves
the project mvnw wrapper (walking the cwd and its ancestors) and falls back to mvn;
Maven’s output streams straight to the terminal.
| Type | Maven invocation | Result |
|---|---|---|
|
|
Standalone distribution ZIP. |
|
|
Self-contained jlink runtime image (no |
|
|
Native installer ( |
|
|
Dockerfile around the jlink image. |
Shared options:
| Option | Description |
|---|---|
|
Run Maven offline ( |
|
Skip tests ( |
|
Print the resolved Maven command without running it. |
|
Pass everything after |
vidocq build jlink --skip-tests
vidocq clean
vidocq build -- -Dvidocq.docker.build=true # extra args after --
vidocq extension
Manages project-level extensions by editing ./pom.xml in place (text-based, preserving
formatting; idempotent thanks to a StAX dependency scan).
| Sub-command | Description |
|---|---|
|
List extensions. |
|
Inject the matching |
|
Remove the matching project-level |
An id may be a known short name (e.g. cassini-rest; the catalog now has grimm-openapi, grimm-openapi-ui,
migration, flyway-migration and liquibase-migration too NEW), an explicit groupId:artifactId, or
any name (resolved by convention as io.vidocq.runtime:vidocq-runtime-<id>-extension).
In module-info.java, add declares requires on the extension’s module, which re-exports most
extension APIs (MicroProfile Health through knock-health, Fault Tolerance through
heisenberg-fault-tolerance, …). cassini-rest also needs Jakarta REST, JSON-B, CDI and the Cassini
API, requires static java.compiler for its generated adapters, and opens the application
package its resources live in; mansart-data needs the same requires static and opens. Each
added line ends with // vidocq:<id>, which is what remove takes back — never a line written by
hand, except a requires of the removed extension’s own module, which no longer resolves.
vidocq create -x writes the same directives.
NEW list --installed, vidocq info and vidocq doctor resolve the project’s runtime dependencies
with Maven (maven-dependency-plugin:list, compile + runtime scopes, transitively) and keep every
JAR whose module provides io.vidocq.runtime.spi.VidocqExtension. An extension pulled in by
another one — chappe-webserver under cassini-rest — is listed and marked (transitive).
Resolving takes as long as a Maven run, and may download artifacts on first use, so the answer
is cached in ~/.vidocq/cache/project-extensions/, one file per project:
-
the entry is keyed by the content of
pom.xml— any edit resolves again; -
when nothing resolved is a SNAPSHOT, the entry is final: a release never changes;
-
otherwise it records the size and modification time of every SNAPSHOT JAR and POM in the local repository (and of a SNAPSHOT parent POM), and resolves again as soon as one of them was re-downloaded. A newer SNAPSHOT still sitting in the remote repository is not seen until something fetches it:
vidocq extension list --refreshforces a resolution.
vidocq extension list --available
vidocq extension add cassini-rest knock-health
vidocq extension remove knock-health
|
The public extension registry ( |
vidocq config
Reads and writes the project’s vidocq.properties (project root, falling back to
src/main/resources). set preserves comments, blank lines, key order and separator
spacing, and creates the file when none exists.
| Sub-command | Description |
|---|---|
|
Print the value bound to |
|
Set (or append) |
|
Print every |
vidocq config get vidocq.http.port
vidocq config set vidocq.http.port 9090
vidocq config list
vidocq doctor
Inspects the local environment and current project and prints a ✔/⚠/✘ report. It exits
non-zero when a blocking issue is found, so it doubles as a CI pre-flight gate
(vidocq doctor && vidocq build).
| Check | Meaning |
|---|---|
Java version |
✔ running JVM ≥ minimum (25); ✘ below minimum. |
JAVA_HOME |
✔ set and a directory; ⚠ unset / not a directory. |
Maven wrapper |
✔ |
Vidocq project |
✔ |
Extensions |
✔ ≥ 1 extension in the project’s runtime dependencies; ⚠ none found, or Maven could not resolve them. |
Config |
✔ no |
--verbose, -v appends a per-status summary footer and the minimum Java version. Warnings
never fail the command; only ✘ checks set a non-zero exit code.
vidocq completion
Prints a self-contained completion script to stdout. It completes NEW commands, sub-commands
(extension list|add|remove, config get|set|list, …), each command’s options, build types,
and values: the catalog’s extension ids after extension add and create -x, less those the pom.xml already declares, the extensions
the current pom.xml declares after extension remove, the keys of the project’s
vidocq.properties after config get|set. These values are read by the script itself, so
pressing TAB never starts a JVM.
# bash — load for the current shell
source <(vidocq completion bash)
# zsh — install into the completion path
vidocq completion zsh > "${fpath[1]}/_vidocq"
vidocq completion install NEW does it for you: it writes the script to
~/.vidocq/completion/vidocq.<shell> and adds a marked block sourcing it to ~/.zshrc or
~/.bashrc. The shell comes from $SHELL unless named (vidocq completion install bash).
Running it again replaces the block instead of adding another. The script records which CLI
build wrote it, and every vidocq run rewrites an installed script another build wrote, so the
completion follows the CLI however it was replaced. vidocq completion uninstall removes the
block and the script.
On macOS, Terminal starts bash as a login shell, which reads ~/.bash_profile, not
~/.bashrc. Source ~/.bashrc from ~/.bash_profile if it does not already.
|
vidocq update NEW
Updates the CLI itself, from the same repositories as install.sh:
-
a release CLI moves to the latest release on Maven Central (
0.3.0→0.4.0); -
a SNAPSHOT CLI moves to the latest build of the highest SNAPSHOT line in the Central snapshot repository. It records the build it installed, so the next run knows whether a newer one was published. A SNAPSHOT CLI without that record — installed by
install.sh, or built locally — takes the published build only when it was deployed after the running CLI was built: a local build of newer sources is never downgraded.
The new version is unpacked next to the others in ~/.vidocq/cli and swapped in by renaming
the directory, the vidocq launcher in ~/.local/bin (or $VIDOCQ_BIN) is pointed at it, and
an installed completion script is regenerated. Earlier versions stay where they are.
vidocq update --check # only report
vidocq update
VIDOCQ_CENTRAL and VIDOCQ_SNAPSHOTS point it at repository mirrors, as for install.sh.
Configuration & profiles
The CLI operates on the standard Vidocq configuration model. vidocq.properties lives in the
project root or src/main/resources; profile overlays (vidocq-<profile>.properties) are
layered by vidocq dev --profile. Any key is overridable via -Dkey=value, environment
variables, or an external file — see Reference for the full ordinal
hierarchy.
Exit codes
| Code | Meaning |
|---|---|
|
Success (including |
|
A usage error, a failed command, or a |
Extending the CLI (plugin SPI)
Third-party modules can contribute extra top-level commands without forking the CLI by
implementing io.vidocq.runtime.cli.spi.VidocqCliPlugin and declaring it as a
ServiceLoader provider. Any command token that is not a built-in is matched against the
registered plugins; built-ins always win, and vidocq help lists discovered plugins.
Next steps
-
Getting started — full REST + persistence walkthrough
-
Usage — packaging workflows (jlink, jpackage, Docker), profiles
-
vidocq-runtime-maven-plugin — the goals the CLI wraps
-
Reference — configuration keys and ordinals