Changelog · Changelogs
lockmq changelog
All notable changes to lockmq. The format follows Keep a Changelog; versions follow Semantic Versioning (no stability promise before 1.0).
[Unreleased] #
Fixed #
- Hub mode: a read or peek the hub decides within its short wait (an auto rule of
lox run, lockkit#162) runs in the same call and returns its result, ordenied, instead of answeringpendingwith no notification to follow (#64).
[0.9.0] - 2026-11-13 #
Builds on lockkit v0.19.0; works with lox run as v0.8.0.
Breaking #
- lockkit v0.18.0 (lockkit#120): the console's status answer no longer carries
auto_approve, and the auto-mode identifiers deprecated since lockkit v0.9.0 are gone. A client that readsauto_approvegets false; the hub's auto rules ([profiles.NAME.auto]) are unchanged. - lockkit v0.18.0: more config keys and values are refused as secrets: keys holding
passphrase,apikey,bearerorcookie(camelCase and joined parts too,apiKey,authToken), and values embedding a bearer token, anAuthorization:header or a URL with userinfo. A profile named like a secret no longer loads: rename it. - With a managed configuration (
/etc/lockfamily/managed.toml), a profile beyond its[lockmq.bounds], or a project or user profile named as a managed one, is refused (see Added). Without the file, nothing changes.
Behaviour #
- lockkit v0.19.0 (lockkit#130): masking with the default detectors can mask more, or under
another kind:
fr_nirruns beforecard(a NIR whose digits pass Luhn is masked as a NIR),phonealso finds a national number after a phone word and 12-digit German mobiles,be_nissfinds other separators afterNISS/rijksregister, an e-mail local part may hold an apostrophe. The new lockkit detectors are opt-in.
Added #
- The company's managed configuration (
/etc/lockfamily/managed.toml, the Lock Family'smanaged.toml): lockmq enforces its[lockmq]section (#57).[lockmq.profiles.<name>]are served as written and cannot be redefined in the config files;[lockmq.defaults]fill the keys a profile leaves unset;[lockmq.bounds]bound every profile (tier, production, tls, body_mode, vhosts, credentials, hosts, credentials_ttl, auto rules, limits): a profile beyond them is refused at the console's start and at every policy poll, with no prompt, citing the managed key, and no human can approve past it. Requireddetectorsand[[lockmq.bounds.pii_mask]]rules are always on; a user[[allow]]that could clear a managed mask is refused.[family] vault.requiredrequirescredentials = "vault". Keys: docs/configuration.md. lockmq managed showandlockmq managed check [--profile P](exit 3 on a violation, oneblocked by company policy: …line each;lox runruns it before it starts the lock), and amanagedline inlockmq doctor.
Changed #
-
A mask rule in
redactmode wins over a weaker rule on the same value, whatever their order. -
Hub mode: the console opens at most 30 tickets a human decides per 5 minutes (was 10) and 30 pending ones (was 20); a ticket
lox run's auto mode decides leaves that count, and a safety cap of 300 tickets per window counts every one (lockkit v0.15.0, lockkit#150). -
The profile's
limits.tickets_per_window,limits.ticket_windowandlimits.max_pendingset those limits; more tickets, a shorter window or more pending tickets is a loosening, reviewed like the others (the typed profile name on production). A lowering applies at once. The status screen shows the limits in force.
Fixed #
- The launcher mounts the machine's managed directory (
/etc/lockfamily,/Library/Application Support/lockfamilyon macOS) read-only on/etc/lockfamilyin its containers, aslox rundoes in its locks:lockmq managed show,managed check,doctorand the other commands run from the host see the company's managed configuration (#59). No directory: no mount; a path that is not a directory (a file, a dangling link) or holds a:stops the launcher.
[0.8.1] - 2026-11-07 #
Builds on lockkit v0.14.1.
Changed #
- Docs, agent assets (skill, instructions), the launcher, help, errors and
doctornamelox run, not the deprecatedlox up: one terminal outside the agent starts the hub and the locks, and serves the decisions. No behavior, flag, label or file name change (up.json,.lockfamily/stay) (#54). - lockkit v0.14.1: its shared texts (
StartHint,ErrNoHub) namelox run.
[0.8.0] - 2026-11-06 #
Builds on lockkit v0.13.0; needs lox run (lockhub#121) or a hub on lockkit v0.13.0 or later.
Added #
- Auto mode per profile:
[profiles.NAME.auto]rules (connect,list,read,peek,get,publish,purge,delete:auto,askordeny;auto = "full-auto"). Defaults:connect/peekask,list/readauto. The lock enforcesdeny(E_AUTO_DENIED) andask(never_autotickets). A looser rule is a policy loosening (typed name on production). The audit recordsauto_ruleanddecided_by. lockmq profile rules [--json], forlox run.
Changed #
- Tickets are version 2 (kinds
actionandconnect); an older hub refuses them. In hub mode a broker session serves the agent only after its connect ticket is approved. - CI: macOS tests run on main, nightly and on demand, not on pull requests.
[0.7.0] - 2026-11-01 #
Added #
--instance NAME: reach one lock among several of this type (lea mounts each at /run/lockmq/NAME). Every agent-side command,mcpanddoctortake it; it defaults toLOCKMQ_INSTANCE, then to the one lock listed inLEA_LOCKMQ_INSTANCES.credentials = "vault": the console asks the Vault token at its start (masked), underlox uptoo.
[0.6.1] - 2026-11-01 #
doctor --fix keeps .lockmq as lox up copies it and checks as the agent account. Builds
on lockkit v0.10.0; lockhub as v0.6.0 (v0.3.0 or later).
Fixed #
lockmq doctor --fixno longer breakslox up(found bylox init, DavidGodefroid/lockhub#92). It gave the project's.lockmq/to the console account (uid 10011), a leftover of the standalone console that read.lockmqitself;lox upreads it as you and copies only your own files, so it then refused it ("owned by uid 10011, not by you").doctornow checks.lockmqaslox upcopies it: yours, as are the files and directories in it, none writable by group or others, no link.--fixtakes group and others' write away there, and gives back to you what an olderdoctor --fixgave the console account (.lockmqitself and its copy ofpii.toml); a link or a file of another account is reported, never repaired. Removed with the standalone era: the console account's ownership of.lockmqandpii.toml, and the "readable by the console account" repair ofconfig.toml(lox upkeeps owner-only modes in its copy, which the console account owns).doctor --fixchecks as the agent account, not as root. The launcher ran the wholedoctor --fixas root, without lox up's socket: the console's check always failed (the console refuses root as a client) and the checks read files as root. The launcher now passes your uid (LOCKMQ_HOST_UID) and lox up's socket to everydoctor; with--fixthe image starts as root for the repairs only, then becomes the agent account for good before any check, as adoctorwithout--fixruns. On a fresh setupdoctor --fix --yes --jsonexits 0 (warnings only). The project-access check now names the agent account, which must enter the project, instead of the console account.
Added #
- Each release tag bumps the
lockmqformula of the Homebrew tap (brew install davidgodefroid/tap/lockmq): the release workflow's last job dispatches the bump once the release is signed (DavidGodefroid/lockfamily#8). It is skipped while theTAP_DISPATCH_TOKENsecret is not set.
[0.6.0] - 2026-11-01 #
The same launcher verbs as every lock of the family, which lox init drives
(DavidGodefroid/lockkit#111, T5; lockkit GUIDE §14): lockmq profile add replaces
lockmq setup, which is removed. Builds on lockkit v0.10.0; lockhub as v0.5.0 (v0.3.0 or
later).
Added #
lockmq profile addadds one broker profile to the project's.lockmq/config.tomlfrom its flags:--profile NAME(defaultdev),--url(management API),--user,--vhost(repeatable),--amqp-url,--stream-url,--production,--credentials ask|vault [--vault-path P],--tier read|peek,--project DIR. Without--non-interactive, in a terminal, it asks for what the flags did not give; without a terminal it refuses rather than wait.--non-interactivenever reads stdin (--urlis then required). No form takes, asks for or writes a secret: the arguments go through lockkit'sverbs.Parseandverbs.RefuseSecrets(a flag named like a secret, a value that embeds a password, a positional argument) andverbs.Credentials(keychainrefused), and an error names the flag, never its value. A profile already in the config is refused with codeexistsand nothing is written.--jsonprints exactly one line on stdout:verbs.Profile, orverbs.Error(usage,secret,exists,failed); questions and messages then go to stderr.lockmq doctor --jsonprints oneverbs.Doctor(ok,fixed, every check with its statusok|warn|fail, detail and fix); a usage error prints averbs.Error. The exit status is 0 exactly when no check fails: a console that does not run yet and unwired agents are warnings.
Changed #
lockmq doctor --fixwithout a terminal and without--yesis refused before any check (it was refused only when a repair was due);--yeswithout--fixstays a usage error.- The launcher runs
profile addas you withHOME=/tmp, as it ransetup; every flag reaches the image as given. - Builds on lockkit v0.10.0 (
verbs).
Removed #
lockmq setup, replaced bylockmq profile add(pre-release: no alias).
[0.5.0] - 2026-11-01 #
The console is hub-attached only (DavidGodefroid/lockkit#110): lox up starts it, and the
launcher's agent commands reach the console lox up runs through .lockfamily/up.json
(lockhub#78). Builds on lockkit v0.9.1.
Changed #
-
The agent commands reach the console
lox upruns (lockhub#78). The launcher'smcp,doctorand client commands (status,queues,read,peek...) mount the socket volume of the workspace's lockmq lock thatlox upnames in.lockfamily/up.json, read-only, once Docker confirms it is lox up's (the checks of lea; no container lox up did not start may mount it read-write), and no longer the fixedlockmq-run: withoutlox upthey exit 2 and say to run it (doctorruns without a socket and says why). With several lockmq locks,--instance NAMEpicks one (in.mcp.json:"args": ["mcp", "--instance", "NAME"])..mcp.jsonis unchanged (docs/docker.md). -
lockmq consoleis launched bylox uponly:--hub,--hub-key-fileand--instanceare required, and without them (or with only some) it refuses before anything else ("the console is launched bylox uponly", exit 3). The usage text andlockmq helplist them first. The quick start (README, docs, site) goes throughlox add lockmq <instance>,lox up,lox attachandlox approve. -
A pending answer of
lockmq readorlockmq peek(decided on lockhub) prints the ticket to run with--ticket, no longernull. -
No console running: the CLI,
lockmq_statusand the MCP tools now ask the user to runlox up("the console is started bylox uponly: ask the user to runlox up"), no longer alockmq consolecommand; the status'sstartislox upand carries no profile or project.lockmq doctorprints "the console runs underlox up: runlox up, thenlox attach <instance>for its questions". The agent skill says the same. -
The agent skill, the agent notes (
AGENTS.md, Claude Code) and the README say message reads are approved on lockhub (lox approve, the lea deck or a paired phone), no longer in the console; the console still asks its own questions (credentials, policy) throughlox attach. -
Builds on lockkit v0.9.1 (hub-only console,
lox upstart hint, console PolicyOnly mode). -
The docs and comments name lockhub's host CLI
lox(lockhub v0.3.0 renamed it fromlock, lockhub#79):lox upin docs/usage.md, docs/docker.md andlockmq hub-key's comment.
Removed #
--autoand auto mode (Shift+Tab,:mode); the dry run'sautoverdict. Requests are decided on lockhub; the console's own decisions (a policy change,:unmask) stay at its terminal.- The standalone start that withdrew the plans hub mode had left pending.
[0.4.3] - 2026-10-31 #
Builds on lockkit v0.8.1: a --hub URL is http(s)://host[:port] only, opt-in ip, secret
and person_name detectors, and no error echoes a value typed in the wrong place.
Added #
detectorsalso accepts lockkit v0.8.0's opt-inip(public IPv4 and IPv6 addresses),secret(credentials, tokens, private keys, masked as<redacted>) andperson_name; none is in the default set.
Changed #
- Builds on lockkit v0.8.1 (was v0.7.2).
console --hubtakeshttp(s)://host[:port]only: a hub URL with a path (https://h/lockhub), query, fragment, IPv6 zone, a host that is not a DNS name or an IP address, or a port outside 1-65535 is refused, without quoting the URL (such a URL never reached a working hub: lockhub serves/v1/at its root). A hub that cannot be reached is named by scheme and host, no longer by the whole request URL. - Through lockkit v0.8.0, the detectors read a JSON
\n,\ror\tescape, and the\u0026-style escapes of&,<,>,=and quotes, as the blank or delimiter they stand for: a value right after one ({"msg":"tel:\t0475123456"}) is now masked.
Fixed #
- Errors no longer quote a value typed in the wrong place (a token or a URL with a password
never reaches the terminal). The
--profileerrors of the client commands,consoleanddoctorrefuse an invalid name with the allowed form and an unconfigured one with the configured profiles only;setupchecks the typed profile name with lockkit'sCheckProfileName(an invalid or production-reserved name is a configuration error, exit 3) and does not name a duplicate; an unknown command prints the usage, an unknown agent ofinit(or a flag) the known agents, and a refused--allowed-uidsfield is not repeated. Through lockkit v0.8.1, neither do the errors of--instance,hub-key, a profile name in a config file,--require-device, the IPC socket names, theservice_userandclient_grouplookups and the console's isolation refusals: they name the key and the allowed form.
[0.4.2] - 2026-10-31 #
Errors never echo a value that may be a secret; builds on lockkit v0.7.2.
Fixed #
- Config and rule errors no longer quote the value they refuse: a token or a URL with a
password pasted into the wrong key never reaches the terminal, a log or an agent. The
errors of
credentials,tier,body_modeandtlsin a profile, of the globs,headerand fields of a.lockmq/pii.tomlor console mask rule, and ofconsole --allowed-uidsname the key and the values it accepts; a refused glob is named by its key and position (queue entry 2). A bad flag of a client command (lockmq queues --page ...) is reported as "wrong arguments", as for the other commands, and the image'sALLOWED_UIDSbuild check no longer prints the argument. Through lockkit v0.7.2, so dodetectors(by position),ssh.credentialsand the--hubURL errors.
Changed #
- Builds on lockkit v0.7.2 (was v0.6.0).
console --hubrefuses a hub URL with a user or password; a tightening that cannot be saved as the approved policy now applies anyway (auditedpolicy/unsaved), where the looser policy stayed in force before.
[0.4.1] - 2026-10-30 #
lea's agents reach the release image's console: console --allowed-uids (lea#226).
Added #
lockmq console --allowed-uids UID,...: these uids may connect besides the members oflockmq-clients, asallowed_uidsof the image'ssystem.toml(theALLOWED_UIDSbuild argument) does, for that console only, with the release image unchanged: an agent in a container of its own whose uid has no account in the console's image (lea's agents run as the host user's uid). Set only by whoever starts the console (the human: the launcher passes it on,lock upof lockhub v0.2.4 a lock's reviewedallowed_uids); root, leading zeros, 65534 (nobody) and the console's own uid are refused; every isolation check sees the uids (a session or terminal of one is the agent's), and the console prints them at start.
Changed #
- The
ALLOWED_UIDSbuild argument also refuses 65534 (nobody, the kernel's overflow uid). scripts/hygiene.shno longer matches lockkit'sCheckIsolation.
[0.4.0] - 2026-10-30 #
Hub mode on lockkit v0.6.0: expired tickets are approved again, reveal from a local facade, and a console restarted without the hub withdraws its hub plans.
Added #
- Hub mode renewals (lockkit decision H1): the run of an expired ticket answers
pendingwith a new ticket that renews it, instead of atimeout; the hub's own renew requests are served too. The plan records its plan-hash inputs by name (params,queue). The renewal is recomputed under the approved policy without the broker (it may run on the hub's watch goroutine): the params are compared, the queue isunchecked(never claimed unchanged), and the new ticket's run reads the queue and refuses one that moved. Renewals are audited (renew) with the stored request. - Hub mode reveal:
lockmq console --facade-keys-file FILE(written bylock up) pins the local facades that may reveal a ticket's clear screen (Ctrl-O), audited (reveal).
Changed #
- A console started without the hub flags after hub mode withdraws the plans left pending
and refuses a run naming a
ticketwithwithdrawn, before anything runs. - Builds on lockkit v0.6.0 (
ticket.UncheckedInput,console.Options.OnHub: the recompute is registered at hub start, before any request; was v0.3.1). - A closed broker session is no longer the backend's: nothing reads on it.
lockmq console's usage andlockmq helplist--hub-plain-http(the flaglock uppasses for itshttp://lockhub:8443);docs/usage.mdsays when it is needed.
[0.3.0] - 2026-10-30 #
Hub mode: reads and peeks can be decided on lockhub instead of the console's own prompt.
Added #
- Hub mode (
lockmq console --hub URL --hub-key-file FILE --instance NAME): a read or peek never runs without a decided plan.op.runstores it as a plan (lockkit plans: the client's uid, the agent's lea token, the policy), pushes a signed ticket with a masked screen and answerspending;op.runwithticket(--ticket, the MCP tools'ticket) runs it once decided, prepared again and hashing the same. Decisions are audited with the ticket, approver, facade and hub signature; the dry run sayshub.lockmq hub-key --instance NAMEprints the instance key. Requests carry the agent's lea name and the hash of its token (the raw token stays in the agent's process, lockkit#71). - Hub mode plan hash: the operation, vhost, target and arguments, plus the queue's
properties read on the operation's own session (type, arguments, policy, operator policy,
broker major; not its message counts). A queue changed between the approval and the run
is refused
E_STALE(retry: rewrite) before anything is read. - Builds on lockkit v0.3.1 (was v0.2.1). An
http://hub other than a loopback address needs--hub-plain-httpand must be a service name without a dot or a private address; redirects from the hub are refused (lockkit#72).
[0.2.0] #
Docker-only: every command runs in the image through the lockmq launcher,
the host install code is gone, and lockmq builds on lockkit v0.2.1. Upgrade
from v0.1.0 with scripts/install.sh (it installs the launcher); see
docs/docker.md. This release also holds the fixes
from the v0.1.0 spec audit (below), never tagged on their own as v0.1.1.
lockkit v0.2.1 #
lockmq now builds on lockkit v0.2.1 (was v0.1.0), the version locksql and lockhttp use. What changes for lockmq:
- Clear results are refused at desktop security level 1 (the agent's
account can read the console window):
lockmq console --show-resultsstops with a configuration error there, and Ctrl-O /:resultskeep the results masked withresults stay masked at level 1: the agent's account can read this window. Levels 0 and 2 are unchanged;--autoand--allow-unmaskare unchanged. - The PII detectors mask more: Unicode e-mail domains; non-breaking, narrow and thin spaces and full-width digits inside phone, IBAN, card and national-id values; integral floats in JSON bodies. A value masked before is still masked.
Removed #
- The host install (
cmd/lockmq/install.go) andinternal/separate: the binary refusedinstallsince the Docker-only launcher.lockmq installandlockmq updatein the image still print the hint to the launcher.doctor --fixkeeps its project-access repair (access.go), which runs in the image.
One lockmq command, backed by Docker #
Every lockmq command now runs in Docker, through one host command: the
lockmq launcher.
scripts/lockmq, a POSIX shell launcher, runs each command inghcr.io/davidgodefroid/lockmqwith the account and volumes it needs:consoleaslockmqin a container of its own per project (lockmq-console-<n>), confined (no capability,no-new-privileges, read-only root with a small/tmp, 256 processes, 1 GB), with no log driver,host.docker.internalmapped,VAULT_ADDR/VAULT_NAMESPACEpassed andVAULT_CACERT's file mounted read-only, volumeslockmq-runandlockmq-home,--projectadded;initas you with your home;setupas you;doctor --fixas root; everything else,mcpincluded, asagentwithlockmq-run. It mounts the project (the nearest directory up holding.lockmq/) at its own path (a path with:is refused) and never mounts the Docker socket.LOCKMQ_IMAGE,LOCKMQ_VAULT=1,LOCKMQ_DOCKER_ARGS(never globbed),LOCKMQ_READONLY_PROJECT=1andLOCKMQ_CONSOLE_NAMEadjust it.scripts/install.shinstalls the launcher, not the binary, after checking the cosign signature ofchecksums.txtagainst the release workflow run for that very tag (a signature of another release does not verify; only avX.Y.Ztag is accepted), the archive's checksum and the images' signatures; cosign is now required (LOCKMQ_SKIP_COSIGN=1is the explicit way past it, and replacesLOCKMQ_REQUIRE_COSIGN). The launcher runs its release's image by the verified digest.lockmq versionprints the launcher's and the image's versions;lockmq update [vX.Y.Z]replaces the launcher the same way, then pulls its image.- The release workflow builds the image (and its
-vaultvariant) for amd64 and arm64, publishes it to ghcr.io and signs it with cosign. The archives ship the launcher; the.deb,.rpmand.apkpackages are gone. - The binary refuses
installandupdate("lockmq runs in Docker").lockmq initwriteslockmq mcp, which now works as is.
Breaking, migration: install.sh installs the launcher in place of the
binary, and releases no longer ship packages. Replace the docker run … lockmq … commands and sh -c 'exec docker run … lockmq mcp' agent entries
of the former guide with lockmq … (the old ones keep working). A host
install (sudo lockmq install) leaves the lockmq account and group,
/etc/lockmq/ and the socket directory behind: see
docs/docker.md.
Docker image #
Docker is now the default and only documented way to run lockmq, at parity with locksql.
- A multi-stage
Dockerfile(base images pinned by digest): a static build, then the console image with the separated setup oflockmq installbaked in:lockmq(uid 10011) runs the console,agent(uid 10012, inlockmq-clients, gid 10010) runs the MCP server and the CLI, root-owns the binary and/etc/lockmq/system.toml, nosudo, and/run/lockmq(2710) and/home/lockmqas volumes.--build-arg ALLOWED_UIDS=names the uid of an agent in a container of its own; avaulttarget adds the Vault CLI checked against pinned sums. The build refuses root (0) and the console's uid (10011) inALLOWED_UIDS. lockmq setupknows when it runs in a container: the management URL defaults tohost.docker.internal,localhost,127.0.0.1and::1are refused, and the keychain is not offered.lockmq doctorchecks the project's.lockmq(owned by the console account, by uid, mode 0755, its files readable) anddoctor --fix [--yes]repairs it as root, withoutsudowhen it already is root (docker run --user 0 … lockmq doctor --fix --yes). The repair enters the directory and changes., so a symbolic link swapped in by the agent's account redirects nothing; a file is made readable only once the directory belongs to the console account and no other account may write it, and only a regular file of its checked, non-root owner with one link; apii.tomlthe console account does not own is replaced by a copy it owns (a new inode: a descriptor held open on the old file writes nowhere). A.lockmqthat is a link, and a directory or file owned by root, are reported only.- docs/docker.md is the setup guide (build, project, console, Vault, agent wiring, agent in its own container, broker in a container, what Docker does and does not separate). The README, docs/usage.md and the site describe only the Docker setup; the other deployment modes stay in the code, no longer documented.
- CI builds both targets, checks
ALLOWED_UIDS, and runs an end-to-end test of the guide against RabbitMQ (test/docker/e2e.py).
Fixes from the v0.1.0 spec audit #
- Security: a body without content type that looks like JSON but does not
parse is opaque under
redact-unknown(it was masked as text, detectors only), and a body the broker cut short on peek is always opaque: names and addresses of a large dead-lettered message no longer come back in clear. - Security: a vhost or name that is, or holds, a
.or..path segment is refused before any request (E_UNSAFE_NAME) and in the config, so a management path cannot be normalised outside the endpoint allowlist. limits.delivery_headroom = 0is refused (a peek could dead-letter a message); the peek guard never goes below 1.- Ctrl-O /
:resultsprints results in clear in the console, and--unmask(MCPunmask) returns them unmasked when the human allowed it with:unmask: approved every time, audited"unmasked":true; refused otherwise (E_UNMASK_OFF). Both were documented but did nothing. statusshows the profile's tier.- Stream offsets and lag say they are precise to one chunk (
precision). - Connection and channel user names and client properties go through the detectors.
queuereads its own consumers instead of the whole vhost's.
[0.1.0] - 2026-10-19 #
First release.
- Human-held console on lockkit v0.1.0: separate account (
lockmq install), approval screens, typed profile name on production, policy review (the AI tightens, the human loosens), audit log without message content. - Catalogue over the RabbitMQ management API, an allowlist of read-only operations: overview, queues, queue, exchanges, bindings, policies, consumers, connections, channels; stream metadata and a named consumer's lag over the stream protocol.
read: stream messages from first, last, an offset or a timestamp, over the stream protocol or AMQP 0-9-1, with an unnamed consumer; approved by the human.peek(tierpeekonly, off by default): the first messages of a classic or quorum queue, requeued; never auto-approved; refused near a quorum queue's delivery limit.- Message masking: JSON paths, header and property rules,
redact-unknownanddetectbody modes, value detectors, redacted references, opaque binary and compressed bodies; rules in.lockmq/pii.toml. - CLI and MCP server (17 tools),
setup,doctor,initfor Claude Code, Codex, Cursor and Gemini CLI. - Integration suite on RabbitMQ 3.13 and 4.1.