Changelog
Release by release, in user-facing words. The first section is what the develop branch already holds: merged, tested, not yet in a numbered release.
Unreleased (on develop)
Fixed
- Opening reports in quick succession could show the wrong one. Two report openings in flight (Back twice, two quick clicks) could finish out of order: the slower one replaced the report on screen and added a stray entry to the browser history. The last report asked for now wins.
- A ticket opened from My tickets no longer shows an empty Technical brief section. It stays closed until you click Specify technically — or when a brief (even a draft) is already saved.
- Scrolling a full-screen view or a dialog no longer scrolls the page behind it. Reading a long AI answer, the wheel used to carry on to the screen underneath once the end of the pane was reached, and closing the view left you at the bottom of the page. The page now stays still while a full-screen view or a dialog is open and is exactly where you left it when you close it.
- A long request no longer pushes the AI's answer off screen. In a session's "Retour de l'IA" view, the What was asked block now has a bounded height and scrolls on its own, so the answer stays within reach however long the prompt was.
- The AI no longer reports an "import missing from the file" because it only saw the diff. The diff handed to a review shows a few lines around each change, so the top of a file (imports, declarations) is usually absent from it, and the AI sometimes took that for a missing import. The default review prompt now tells it to open the whole changed file before reporting anything as missing. An installation whose prompt is still the default gets the new one automatically; a prompt you edited is left alone — add the same rule to it by hand if you want it.
Added
- Out-of-repo sessions can start from a Jira ticket. The out-of-repo session dialog now has the Enrich from a Jira ticket field like coding sessions: type or pick a ticket to put its context at the top of the prompt, and tick the ticket's screenshots to attach them. Fetch now offers the screenshots in every kind of session.
- Start an out-of-repo coding session from a Jira ticket. A new Code outside a repo button on the ticket opens the out-of-repo session dialog pre-filled with the ticket and, when there is one, its technical brief — whether or not you ran the brief.
- Pick a branch per repository for an agent. In an agent's scope (chosen repositories) and when creating a domain agent, each repository has a searchable branch field; left empty, the default branch is used as before. A domain agent keeps the branches it was mapped on, so its updates read the same ones.
- Save a ticket's technical brief without running it. The brief form (Jira → a ticket → Technical brief) has a new Save without analysing button: what you typed (repositories and their branches, Confluence pages, complement, options) is kept, no AI session is started and nothing is spent. The ticket shows up as to run — in the Analysed tab and in the already analysed filter of My tickets — and the form comes back filled when you reopen it: start the analysis whenever you want. Unlike the analysis, saving does not require a repository yet.
3.0.0
Added
- A branch per repository in a ticket's technical brief, an "Analysed" tab in Jira, and an "Analysis" filter on "My tickets". Ticking a repository in the brief now offers its branch (a searchable list, the repository's default branch when left empty): the code you describe often lives on a release or feature branch, and the AI reads that one. The branches read are shown on the brief, travel with the team's shared specs, and the "Have the AI code" session opened from a brief starts from them. The new Analysed tab lists every ticket whose brief was started or proposed — with its repositories, branches, state and version — and opens the ticket and its brief alongside; its badge counts them. My tickets gets an Analysis filter (all · already analysed · not analysed yet), remembered across reloads and updated as soon as a brief arrives.
- An "Update" button on each installed plugin (Settings → Plugins). Mergerie keeps where a plugin was installed from (git address and branch or tag, or folder); one click clones it again, disables the plugin, replaces its folder with the latest version and enables it again if it was — its data, settings and secrets untouched, the page reloading when it was active. A network failure leaves the plugin as it was. A plugin installed before this release has the button greyed out with a hint: install it once more from git and the address is kept.
- The Jenkins plugin can announce EVERY job, not only the builds you started from Mergerie. A new setting, Announce ALL jobs (on by default; untick it to only follow your own launches), makes it ask Jenkins once a minute (one call for the whole job tree) and emit
jenkins.job.started/jenkins.job.finishedfor every build, whoever started it. Each event now carriessource("mergerie"or"jenkins") so a listener can tell them apart; plugins such as Jenkins Teams Notify use it to post about a chosen list of jobs whoever launched them. - Jenkins Teams Notify has a single "Jobs notified" choice list, fed by the Jenkins plugin (new
jenkins.jobsservice: the full job names). Tick the jobs to notify, whoever started the build; a filter box hides rows without unticking any, a glob pattern can be added by hand, nothing ticked means nothing notifies. The former second list ("whoever started them") is merged into it at startup. The plugin also installs Playwright and Chromium from a Settings button, and reports the outcome of a test or sign-in on screen. - Job parameters in the Teams message.
jenkins.job.finishednow carriesparameterslikestarteddid (secret-looking ones left out), so a Jenkins Teams Notify template can say which environment a build deployed to:{{param.ENV}}for one parameter,{{params}}for all of them. Plugin SDK 1.2.0 (additive). - A "copy" button next to every token in Settings — GitLab, GitHub, Jira, Confluence and Jenkins. Tokens still never reach the page (the field keeps showing
***): the button asks the server for the value on that click, writes it to the clipboard and keeps it out of the screen. A token you just typed and have not saved is copied as is. A plugin gets the same button for any setting its schema marks as a secret. - Jenkins Teams Notify, a plugin in its own repository (https://gitlab.com/amady/jenkins-teams-notify): notifies a Microsoft Teams channel when a Jenkins job started from Mergerie starts or finishes. Teams webhooks and the Graph API not being an option, it drives a browser with Playwright — a persistent profile, or your own Chrome over CDP — and posts as you. Per-type message templates, a job filter (glob on the full name), a send log kept as long as you choose, and a "sign-in required" state (tab badge, brief) that stops sending until a manual test succeeds. A third-party plugin, installed from Settings → Plugins (from git), disabled until you enable it. To support it the plugin API gains, additively and on the same
apiVersion: a private folder for a plugin's files (ctx.dataDir, permissionstorage), the build address, duration and starter in thejenkins.job.*events, and anenvoption onctx.exec. The generated settings form now honoursx-hidden, and the plugins' own tests run withnpm test. - Plugin system. Mergerie can now be extended by plugins: a folder with a
plugin.jsonand anindex.jsthat declares what it needs (permissions) and receives a closed, documentedctx— settings and secrets, its own prefixed tables, routes under/api/plugins/<name>/, periodic tasks, events, a tab, actions on merge request cards, a section of the morning brief, desktop notifications. Settings → Plugins lists them with their version, state, permissions and events, enables or disables them without restarting (the page reloads, data is kept), and installs a third-party plugin from a local folder or a git address — third-party plugins run in their own worker, disabled until you enable them, andexecshows an explicit warning. A developer kit (sdk/,@mergerie/plugin-sdk) gives the TypeScript types, an in-memory test context and a generator (npm create mergerie-plugin);plugins/hellois the generated example, shipped disabled. Documentation indocs/plugins/(fr and en), every example of which the CI runs. - A first installation starts with no plugin enabled. Jenkins and the other built-in plugins are disabled on a brand-new database and are switched on from Settings → Plugins, without a restart. A machine that already runs Mergerie keeps Jenkins enabled when it upgrades: nothing disappears.
- Jenkins becomes a built-in plugin (
plugins/jenkins) — no functional change for those who already had it: the tab, the job sheet, the launches, the linked jobs, the badges, the end-of-build notification, the « CI red » section of the brief and the console in a session's follow-up are exactly as before. On upgrade, the connection (URL, user, token, refresh cadence), the linked jobs and the last connection test move to the plugin with nothing lost; the Jenkins settings now live in Settings → Jenkins as the plugin's own settings (the URL is a per-machine setting, like the rest of the connection), and the API moved from/api/jenkins/*to/api/plugins/jenkins/*. - Tags by period, in the Git tab. "What did we ship these two weeks?" used to mean opening every repository. The new Tags by period sub-tab takes two dates (last 7 or 30 days in one click) and lists every tag created between them across all active repositories: repository, tag, date, first line of the message. Copy the table puts it in the clipboard as a real table and as tab-separated text, so it pastes as is into Teams, an email or a spreadsheet. A tag's date is its creation date when the forge gives it (GitLab, annotated tags), otherwise the date of the commit it points to; GitHub tags are dated from the local clone. A tag the tool cannot date is counted, never guessed.
- Technical brief of a Jira ticket. A ticket written by a Product Owner says what, never where nor how. From the ticket's detail, "Technical brief" lets you pick the repositories involved, attach the epic and its tickets, one or several Confluence pages and a complement of your own; the AI explores the code in a read-only session, asks you what only you can answer, and proposes a short brief in six fixed sections (repositories, existing code, what to do, points of attention, out of scope, open questions for the PO). You send follow-ups to have it rewritten, edit it by hand, then post it as a comment on the ticket — and reposting after a new analysis updates the same comment instead of piling up a new one. The brief turns stale when the ticket's title or description changes, can prefill a coding session, and an epic launches one analysis per ticket you tick. In AI Dev, these analysis sessions carry the ticket's key and a chip hides them in one gesture.
- The code explorer can hide the code too. Next to "Report" and "Tree", a "Code" button hides the file panel so the report takes the full width of the screen; one panel always stays visible.
- "Update with the AI" also on a merge request that is behind its target. Each open merge request now carries how many commits its target branch has that the branch does not (GitLab's diverged commits count, GitHub's
base...headcomparison), read at discovery and when the merge modal opens. A branch behind by one commit or more shows a "N commit(s) behind" badge — it still merges, but its code never ran with what the target brought — with the same "Update with the AI" button as a conflict; the instruction says the delay instead of a conflict, and rebases the same way. "Not known yet" shows nothing: the tool does not guess. - "Update with the AI" on a merge request in conflict. Next to the "in conflict" badge, a button opens the coding session modal already filled in: the merge request's branch, its target branch as the base, automatic push unticked, and the instruction — understand what the branch changes and why, replay those changes on top of the target with
git rebase, resolve each conflict keeping what the target brings and the branch's intent, check, commit, and do not push. You review the instruction, launch, review the diff, then push: the session is marked for a forced push (--force-with-lease), the history having been rewritten. Works on a colleague's merge request as well as yours.
Changed
- "Tell Jira when the merge request is created" moved to Settings → Jira, and the comment is editable. The checkbox (which ticks "Tell Jira" by default in the new-session window) left the General tab for the Jira tab, and a new template field sets the text posted on the ticket:
{url}(required),{iid},{project},{title},{branch},{target}(the destination branch),{key}, with a live preview; empty keeps the shipped message. The template is shared with the team like the review-link template. - Settings → AI sessions has ONE "Save" button, in a bar pinned to the bottom of the screen, instead of five identical ones (one per section, all writing the same configuration). The bar says "unsaved changes" as soon as a field changes, then "saved"; and every Settings save now shows a confirmation toast (an error toast when the server refuses).
- "An MR is dormant after (days)" moved from Settings → General to Settings → Merge Request, next to the automatic refresh.
- "New session — boxes ticked by default" (Auto-push, the AI may ask questions, Converge after) moved from Settings → General to Settings → AI sessions, with the other agent settings.
- Settings tabs reordered: General now comes first of the tool settings, then Notifications and Shared data, so the bar reads connect → code → review → tool → integrations.
- The Jenkins tab is now a third-party plugin, in its own repository (https://gitlab.com/amady/jenkins-mergerie), installed from Settings → Plugins (from git) and enabled like any third-party plugin; it no longer ships with Mergerie. Nothing changes on screen once it is on: the job list and sheet, launches, the linked jobs and their buttons on merge requests, branches and sessions, the badges, the end-of-build notification, the "CI red" section of the brief and the console in a follow-up all come with it. Nothing is lost: the connection (URL, user, token, refresh rate), the linked jobs and the last connection test already live under the plugin's name, so a Mergerie that had the tab finds them all again — the plugin comes up enabled the day you install it, and until you do the tab is simply absent. It now runs in an isolated worker;
JENKINS_CA_CERTandJENKINS_INSECURE_TLSstill apply to its calls. - The Links tab is now a plugin, in its own repository (https://gitlab.com/amady/link-mergerie), installed from Settings → Plugins (from git) and enabled like any third-party plugin. Nothing changes on screen once it is on: the services × environments grid, free links, bookmark import, address pasting, the environment buttons on a merge request, on a session's project line and on a Jira ticket, and the palette entries all come with it. Your links are not lost: a Mergerie that already had the tab keeps its grid, its addresses, its templates, its free links and their order — the tables are renamed in place on upgrade, ids included — and so does the "most opened" ranking; the plugin comes up enabled the day you install it, and until you do the tab is simply absent. The palette (
Ctrl/Cmd+K) stays in the core; links join it as a plugin source, still first in the list. The plugin API gains, additively and on the sameapiVersion: themr-detailandjira-tickettargets,ui.onKey(the keyboard of the open tab), thecloseSplitMenuskit name and agroupon palette entries. A plugin tab positioned "before" a tab that is not there (a plugin that is not installed) no longer disappears from the bar. - The Docker tab is now a plugin, in its own repository (https://gitlab.com/amady/docker-mergerie), installed from Settings → Plugins (from git) and enabled like any third-party plugin. Nothing changes on screen once it is on: compose projects and
.envdrift, containers outside compose, group actions,maketargets, live logs, the health badge, the "container went down" notification and the brief section all come with it. A Mergerie that already had the tab keeps its data — saved container inspects and the lastmakeruns move to the plugin's tables on upgrade — and the plugin comes up enabled the day you install it; until you do, the tab is simply absent. The plugin API gains, additively and on the sameapiVersion: jobs in the core queue (ctx.jobs, with the live log and Stop), long-lived processes (ctx.execStream),http.ssefrom a worker, the declared local folders (ctx.repos.localRoots()), therepo-rowandverify-launchscreen targets, and ajob.finishedbrowser event. Offering a service'sdocker composevariants in the verifier's command suggestions and reading theMakefilestay in the core. - The branch explorer no longer remembers the repositories you ticked. An analysis is about the repositories of the moment; finding yesterday's still ticked launched, without meaning to, an analysis on three repositories instead of one. Each visit starts unticked.
- Git → Merge puts the work first. The open merge now sits at the top of the tab — above the list of running merges, where its row says "open above", and above the form, which becomes "Prepare another merge" — instead of starting below the fold behind three blocks repeating the same branches. Its banner shows the three steps
Resolve › Commit › Pushwith the current one highlighted; each version of a conflict can be clicked as a whole and the kept one says "kept" (the destination is kept by default); the files already ready to commit stay listed, ticked, next to those still in conflict; once resolved, a note says what "ready to commit" means and that nothing reaches the branch before "Push". A merge whose working folder is gone says so instead of showing an empty panel.
Fixed
- A plugin's description is shown in full in Settings → Plugins. It was cut with "…" on one line like a list row; it now wraps.
- A plugin the upgrade had already marked enabled now comes up the moment you install it. On a machine that had the Docker, Jenkins or Links tab, the upgrade keeps the plugin "enabled"; installing it from Settings → Plugins used to leave it showing as "in error" until the next restart, with its data back but its tab missing. It is activated at once, and a plugin with no earlier state still stays disabled until you enable it. The page reloads by itself when the install activated the plugin (and after an uninstall), so its menu appears without a manual refresh.
- A plugin's SQL may use
ON CONFLICT … DO UPDATE SET. The plugin SQL guard read theUPDATEof an upsert as a table namedsetand refused the statement; it now reads the upsert for what it is, and still refuses a foreign table inside it. - An open report that becomes stale updates on screen. "Relancer (delta)" and the stale badge only appeared after reloading the page: a discovery (the Search button, the discovery on opening the tab, the automatic poll) reloaded the lists but not the report you were reading. Only a finished job, or a team sync, refreshed it. The discovery now refreshes the open report itself.
- Plugin tables of two plugins can no longer be mixed up.
plugin_jenkins_is the beginning ofplugin_jenkins_teams_notify_: the Jenkins plugin could read, empty or drop the other one's table, and uninstalling it with "also delete its data" removed it (a SQLLIKEwhose_is a wildcard). A table now belongs to the plugin with the longest matching prefix among the known plugins, in the SQL guard, inctx.db.tables()and when uninstalling. - A plugin's routes are built once per activation, not once per request, and are rebuilt when it is reactivated.
ctx.execno longer lets a plugin setPATH,LD_PRELOAD,NODE_OPTIONS,GIT_*… through itsenvoption, which bypassed the sub-command allowlist.- The Jenkins data migration is one transaction: a stop in the middle leaves the previous database, which the migration replays.
- The linked projects you add in a merge request's Context are kept. Saving the Context sent an empty list, so reopening it showed no linked project: a rename made for the Links screen had changed the class of the rows without changing the code that reads them. The Context modal now saves and shows them again, and a test does the whole gesture in a browser.
- Yolo is yolo everywhere, and a write always comes with the rights to write. Yolo means "no restriction", yet a CLI run non-interactively refuses every tool it was not explicitly allowed: on a Copilot machine the review ended with "I could not write review.md" as its whole report. In yolo mode Mergerie now sets the CLI's own wide-open flag itself (
--dangerously-skip-permissions,--allow-all-tools,--dangerously-bypass-approvals-and-sandbox,--yolo) when the agent's arguments say nothing about permissions, and says so in the run's journal. In secure mode, a Copilot too old for--allow-toolgets--allow-all-toolson write runs instead of nothing at all, and a Copilot read run is always asked for its answer on the standard output, never for a file the launcher would refuse. - Copilot CLI can code again in secure mode. Non-interactive Copilot refuses every tool it was not allowed to run, and Mergerie only passed it denials: a coding session could neither write a file nor run
git rebase, and "Update with the AI" failed with "no approval possible". It now receives the same allowlist as Claude (--allow-tool write, the git subset, approved verifier commands), and that git subset admitsrebaseandmergefor both backends. - The code explorer shows the whole merge request after an incremental re-review. The diff stored next to the report was the delta sent to the AI, so "Open the code" only listed the files of the last commits; it is now the full
target...sourcediff, the delta staying what the AI reads.
- Updating a domain agent's knowledge on Copilot CLI no longer comes back empty. In secure mode, the launcher denies the agent every write, but its instruction still said "write the answer ONLY in this file, do not repeat it on the output": the agent obeyed both, produced nothing, and its session log was taken for the knowledge. As with Claude, Codex and Gemini, a read-only run on Copilot is now asked for its final answer instead of a file it cannot write.
- A profile's subagents are only named in the request when the CLI will receive them. Only Claude Code takes
--agents; on another backend the cartographer was told to hand the search to achercheursubagent, could not find it, and said so instead of answering. - A merge request you reviewed no longer comes back to "To review" after a team sync. A colleague's machine rewrites the merge request's shared file for reasons that carry no decision (a title or an author re-read from the forge) with its status, still "to review"; when both machines had touched the file, the remote version won as a whole and undid your review. The status now travels with the instant it was decided, and the most recent decision wins on every machine — a status decided earlier, or never decided, no longer overwrites yours.
- The "no AI agent found" banner no longer flashes for a binary that is there. Detection used to run
<binary> --versionwith a five-second limit and remember the answer for a minute: under load — an agent working alongside — the probe timed out, the banner said "not found", and worse, a review launched during that minute came back as a simulated report. A binary is now available when it resolves — an existing executable path, or a name found on the server's PATH — with no process, no delay and nothing to expire. - "Ask the AI" on a merge's conflicts no longer fails with
spawn E2BIGon a large conflicted file. The content of every conflicted file was packed into the command line used to launch the agent; a big enough file (or several at once) overflowed what the OS accepts there. Conflicted files already sit on disk in the merge's own workspace, where the agent runs — it now reads them itself, and only their paths travel in the request.
2.0.1
Fixed
- An answer being typed to the agent's question no longer vanishes. The session list redraws itself when another job ends or when a sync lands, and the questions form came back empty — "Reply" then refused the blank fields. What is typed or ticked now survives the redraw, cursor included.
2.0.0
Added
- Feedback on a plan before approving it. On a “plan to approve” line, “Regenerate the plan with my feedback” sends your remarks to the same agent session, which rewrites the whole plan without coding; the line waits again. Approve only when everything is right, after as many rounds as needed. The view “Read the plan” opens offers the same feedback field and the same two actions in place of “Prepare a follow-up”: you re-read a plan to correct or approve it, not to send it a follow-up.
- Several agent binaries, one default, chosen per session. Settings → AI session → “Agent binaries” is now a list — the default first, marked, then as many others as you like (a Claude Code on a local Ollama next to your Claude Max, a Copilot to compare), each complete (binary, arguments, environment variables, timeout, backend), with its state, a Test button and one shared edit form. The session modal then offers a “Binary” picker; the choice holds for every pass of the session and shows on its card. “Use as default” swaps a profile with the default. This workstation only, never shared.
- Agent environment variables, on screen. Settings → AI session takes
NAME=valuelines — an Ollama behind Claude Code (ANTHROPIC_BASE_URL,ANTHROPIC_AUTH_TOKEN), a proxy, a key — passed to the agent Mergerie launches only, never to your terminal, overriding the shell; this workstation only, never shared, applied on the next launch. - Types on the pure layers, without a build.
src/core,src/forgeandsrc/verifycarry// @ts-checkand JSDoc;npm run checknow runstsc --noEmiton them (TypeScript is a development dependency only). Editors get completion and error detection on those modules. - What grows without limit is kept in check. Closed merge requests slim down after a delay of their own (Settings → General, 180 days by default): the last report stays, previous versions, the stored diff, the questions asked on the report and the working folder go. Clones nobody has fetched for a month get a
git gc. A clone can be made without blobs (--filter=blob:none, Settings → Git, this workstation, next clones only). And a disk usage gauge by category, with a “Clean up now” button that runs the daily pass at once and reports what left. - Verifier suggestions for every ecosystem. The verifier form proposes exact lines from what the clone declares — npm, pnpm or yarn scripts, composer and phpunit, Makefile targets, pytest, tox and ruff,
go test ./...,cargo test, Maven, Gradle,dotnet test— and, when a compose file is there, thedocker compose run --rm <service> …variant of each test command: the commands run on the host, and the container goes in the line. - “This run sees your HOME.” The launch dialogs say it at the moment you click, with a throwaway HOME box remembered per verifier (also in Settings → Verifiers); the journal says which HOME a run saw.
- The verifier's verdict beside the convergence loop. After each pass, the verifier carrying the merge request runs inside the job and the convergence panel shows its verdict — green, red or stale; a verdict that turns red is called out in the journal without stopping the loop. Never an exit condition: the score threshold keeps the last word (the roadmap now says so).
- Plan first, then approve. A coding session can start with a reading pass that returns a plan (files, steps, risks, open questions) instead of code; the project line says plan to approve, offers to read it, a remark, and Approve and code, which resumes the same agent session to carry the plan out. With Claude the pass runs in its plan mode whatever the secure/yolo switch says.
- Stop and resume with this instruction. While a session runs, the follow-up field's button stops the pass and sends the instruction back into the same agent session (Claude's handle is known before it says a word), or into a fresh one that receives the task and the transcript.
- The journal stays short, the annex holds the rest. Agent messages are still cut at 600 characters and an
Editis one line with its size, but each now carries a “… see” that opens the full text or the diff in a panel; the agent's reasoning shows as a short line too. - Jobs run in parallel by themselves when they touch different repositories or folders: a review on one repository no longer delays a session on another. Jobs on the same repository keep their order, and jobs launched by hand pass before automatic ones.
- The first quarter of an hour. The Reviews tab's start-up assistant has five steps instead of three, and works for GitHub as well as GitLab: the AI agent (found, simulated on purpose, or missing — with a button to set it up and one to retry), the forge (GitLab or GitHub, each with its own button), the repositories, what your team uses (Jira, Jenkins, Docker, environments: what is ticked unfolds its menu, the rest stays folded — the same preference as Settings → General → Menus) and the first fetch. An installation that already had merge requests skips the new step by itself.
- The AI agent is set on screen, and applies without a restart. Settings → AI session gets the agent's binary, its base arguments and the timeout of one call, plus a Test the agent button: one real, short, read-only call whose expected answer is “OK”. The
.env(AGENT_BIN,AGENT_ARGS,AGENT_TIMEOUT_MS; the oldCOPILOT_*names are still read) is only the default for an installation that never touched that screen. Changing the binary drops the sandbox proof until the next sandbox test, exactly as for a CLI never verified. - No agent found? A banner says so — at the top of every screen, with the path looked for, the install commands for Claude Code and Copilot CLI, and a Retry that redoes the detection on the spot. The detection used to be cached for the life of the process: installing the agent after starting changed nothing until a restart, and the only sign was a mute “dry-run” badge.
- The folded menus are found by use. Git, Docker, Jenkins and Links still start folded; a door to one of them — “Resolve in Git → Merge” on a conflicting merge request, “See the logs” from the brief, a Jenkins job from a card, and a new “this repository has a compose file: show Docker” on a repository's row — now unfolds the menu for good, as if the Settings box had been ticked. The Jenkins sub-tab of Settings follows its menu. The session dialog's Jira field lists your tickets as you type, and picking one fills the key and fetches the ticket; the READMEs open with what the cockpit is for: N repositories at once, and sessions that start from a ticket.
- Repository groups. Settings → Repositories gets Repository groups: a name, its members, and — folded — the review, fix and modification templates and the standing instructions that apply to every repository of the group (empty: the global settings). A review rule can be limited to a group, a verifier can cover a group as a whole (worktree; “in place” stays line by line), and wherever repositories are picked — a coding or exploration session, a Git action, a verifier's coverage — one chip per group adds or ticks all its members. A repository can belong to several groups; the oldest group carrying a value wins, and the repository's sheet says where each value comes from. Groups travel with the team's data repository; a coverage that arrives through the sync waits for approval like any command that runs. Deleting a group disables the rules that only targeted it rather than letting them apply everywhere.
- Approve from the report. An Approve button next to Publish posts the verdict the forge reads — a GitLab approval, a GitHub
APPROVEreview — with no comment, never a burst of inline remarks. The confirmation states the score against the threshold and the verification verdict without forbidding anything; the button then reads “Approved ✓”, read back from the forge, and is withdrawn in one click. - Resolve or reopen a discussion thread from the report or the diff viewer, without going to the forge. On GitHub the resolved state, which only GraphQL knows, is now read back too.
- The forge's CI on every card. A CI badge reads the latest GitLab pipeline or the GitHub check-runs and statuses of the merge request — green, red, running — with a link to what broke. It is not Mergerie's verdict, which keeps its own badge.
- Secured or yolo: one switch for what the agent may do, per machine. Settings → AI session now opens with a single choice. Yolo — the default of an installation that touched nothing, and of an existing database — runs the agent with no restriction from the launcher, every flavour and every backend alike: arguments intact (wide-open mode included), no sandbox, no allowlist, no refused read, no after-the-fact integrity check; a discreet “yolo” badge in the header leads to the setting, and every run's journal opens with it. Secured is what the previous release's hardening did — the CLI's sandbox once proven, else an allowlist, proven read-only for reviews and explorations, leak denials — and its details (sandbox, allowlist, “Test the sandbox”) now live under that choice, folded away in yolo. The start-up assistant asks the question once, with the tools your team uses. What yolo never lifts, because it is the server's limit and not the agent's: the local token on
/api/, theHostallowlist, the nonce on protocol blocks, the per-machine approval of what arrives through the sync, the agent's allowlisted environment. - Four agent backends, and a guarantee level said in plain words. Next to Claude Code and Copilot CLI, Codex CLI and Gemini CLI are wired — from their documentation, without a binary to try them on, and Settings say so (“unverified”) — and any other CLI is run as is instead of being refused. The backend is detected from
--version, then from the binary's name, and can be chosen in Settings → AI session (orAGENT_BACKEND). Every run's journal now opens with the level of what its backend can promise — proven (sandbox verified here), declared (the CLI can restrict itself, nothing proved it), lightened (no restriction, the after-the-fact integrity check is the only net) — and so does Settings. A Copilot that cannot restrict a read-only run is no longer refused: it runs at the lightened level, said as such; the “leave Copilot unrestricted” checkbox is gone with the refusal it excused. - Reviews refreshes on its own. A new database starts with automatic refresh every 5 minutes (it was off, so nothing ever arrived without a click), and opening the Reviews tab runs a discovery when the last one is older than that interval.
- “Ask the AI” proposes a resolution for every conflict of every file in one go — you still validate each one individually. One button on Git → Merge's conflict screen, not one per file: it sends the whole merge to the agent as a single background job, so it sees every conflicted file together before proposing anything — a fix that only makes sense read alongside a change happening in another file isn't lost by asking file-by-file. Each proposal shows up as a third version next to “ours” and “theirs”, with its own “Keep” button — nothing is applied on its own, and a conflict the agent skipped simply shows no third version rather than a guess. Proposals are kept with the merge, so reopening a file doesn't lose what was already asked for. Each proposal also carries the reason behind it, hidden by default behind a “See reason” button — the request asks the agent for a short explanation per conflict, not just the resolved text. The button asks for confirmation before sending anything, since it means the content of every conflicted file leaves for the agent. The full-screen view (below) gets a fourth column for the AI proposal and its reason, shown only on a file that has one — clicking a proposal there selects it, exactly like a passage on the destination or source side, and its text wraps instead of opening a horizontal scrollbar. Each of the four full-screen columns can be hidden and shown back on its own — the remaining ones share the freed-up width instead of leaving it blank — with at least one always left visible. The full-screen view also gets previous/next arrows to jump straight to the next conflict, with a “conflict N/M” counter — scrolling by hand through a long file to find the next one was slower than the click itself. They stay active even on a file with a single conflict or at either end of the list: clicking past the last one, or the only one there is, just re-centers and re-marks it instead of doing nothing, so the arrows never look broken.
- Git → Merge's conflict screen says which version is newer, and gets a full-screen view. Each side of a conflict now shows the date AND time of its last commit on that branch, so picking one no longer means guessing which is more recent — two commits made the same day would otherwise have looked identical. “Keep both” now names the two branches and the order it applies them in (it was “in this order” with no order shown). A new “Fullscreen” button shows the whole file three times side by side — destination, source, and the current result in the middle — instead of three lines of context per conflict; clicking a passage on either side still picks it, and the choice carries back to the normal view on close.
- A full-screen view for a note page. Notes → Pages: a button next to Rendered / Two columns / Markdown drops the page list and expands the editor to fill the window — the three view buttons stay available, so the display can still be switched while reading. Escape, or the same button, exits back to the normal two-column layout.
- Read-only linked projects for a coding session. The session dialog's Advanced section lets you add other repositories as context — the AI reads their API, schema and contracts to code correctly in the projects it modifies, without ever being allowed to change them. A repository (with search) and an optional branch, mounted read-only for the duration of the pass and reset afterwards, the same mechanism as a review's linked projects. Coding only; a repository already a coding target of the same session cannot also be linked read-only.
- Schedule a session for a date and time. The session modal — coding, exploration and off-repo alike — has a “Launch later, on” field: fill it and the primary button becomes “Create and schedule”; the session is created and waits, its card showing the date with a cross to cancel it. Editing the session shows the date and saves it with the rest. A waiting follow-up can be scheduled the same way (“Or send it on…”): it then goes out by itself at that moment, whether or not the “automatically at the end” box is ticked — a follow-up has one trigger, never two. Launching a session by hand cancels its date, a date already past is refused, and the date belongs to the workstation that set it: that one launches, and catches up at the next minute if it was switched off at the time. Free questions are not schedulable.
- “Check all” / “Uncheck all” on the branch explorer's repository picker, with a running count of how many are ticked (Git → Explorer of branches). Matches what “Git commands” already offered on its own project picker.
- The footer's “journal” button turns amber and pulses while a job still runs behind it. Hiding the log panel (“masquer”, or its own auto-collapse a few seconds after a job finishes) left the button looking the same whether the job was still working or long done — it now marks “still running” separately from “done” (green) and “failed” (red).
- A session error's remedy buttons (“Catch up with the base and retry”, “Resolve the conflict”, “Start from a fresh agent session”, “Re-clone the repository”) explain themselves on hover.
- A coding session's project line shows the same “in conflict” tag as the merge request queue, next to “Update with {base}”, when the forge has actually flagged a conflict — not just any rejected push. The button offered the fix already; nothing said why it was there.
- “Send a follow-up” now shows up on a project that stopped without coding, as long as its AI session is still alive. An AI that pauses to ask “should I continue into the next batch?” in plain text (no structured question) had nothing committed, so the project landed in “error” — and with it, the one button that could actually reply to that pause and say “continue”.
- “Update with {base}” now says when it's done, and that a force-push is next. It runs in the background (the AI may need to settle conflicts), and the only sign it had finished was a button quietly changing label on a card that redraws itself every second and a half. A toast now follows that one job to its end, success or failure, instead of leaving it to be noticed.
- The report-link comment can say how many findings the pass carries. Three new variables in the comment template —
{blockers},{majors}and{minors}— give the number of blocking, major and minor findings of the pass, counted as on the report card (findings the pass saw resolved are left out). “Review ready: {url} — {blockers} blocking, {majors} major” tells the author whether there is anything urgent without opening the report. And the variables are now listed under the field, where you look while typing, instead of hiding in a tooltip.
- The screen follows your team's work after a sync. A merge request a teammate reviewed moves from “To review” to “Reviewed” on your open screen, with its counters and menu badge; the same goes for an open report, todos, notes pages, questions, agents, verifiers, review rules, team settings and stats — with the manual sync buttons and with automatic sync alike, without reloading the page.
- Shared items say who shared them: “shared by Claire” or “shared by me” on sessions, questions, notes pages and todos.
- An open notes page no longer overwrites a teammate's edit. If a sync brought their version while you were typing, a banner names them and lets you take their version or keep yours; nothing is saved until you choose.
- “How many iterations already?” is answered without opening “Agent's response.” The session's follow-up button now carries its own count in its label — “Send a follow-up (2)” — on every session, question and off-repo card. Inside “Agent's response”, each iteration shows its token count, and the list's heading adds up the tokens of every iteration shown below it. A follow-up can also be written and sent right there — no need to close the view, find the card again, and reopen its own form to ask for the thing you were just reading about.
- Stats → “Findings that keep coming back” gained a cross-repository twin. The existing card only ever compares a finding against merge requests of the same repository, so a finding raised twice on one repository and once on another never reached its threshold of three anywhere. The new “The same findings, across repositories” card catches exactly that case (three merge requests, at least two repositories) and proposes a rule scoped to no repository and no file path — a
**trigger, since two unrelated repositories share no path prefix worth deducing.
Changed
- No more “yolo” badge in the header. The agent mode is read and changed in Settings → AI session only; every run's journal still opens with it.
npx mergeriewrites its.envin~/.mergerie/, next to the data, not in the folder the command happens to be run from — a file written in one project folder was silently ignored when the command was run from another. It is now a dozen lines: the agent found, the port, the dry-run switch. A.envin the current folder still overrides it, and the shell wins over both.- A repository's forge is recognised by its host. Pasting a GitHub Enterprise address on a host without “github” in its name used to add it as a GitLab repository; the address is now compared with the hosts configured in Settings → Git first.
- The guide opens with a table of contents and a “First real review in 5 minutes” section; the npm description says GitHub too.
- Repositories join Docker, Jenkins, Git and Jira on the local side. Which repositories you follow no longer travels through the team's data repository: adding one used to make it appear on every machine, with its cloning and its merge-request discovery starting there too — on that machine's own token — the moment anyone synced, with no checkbox to decline it. Each machine now keeps its own list and syncs only the repositories on it. A merge request, a review rule or a verifier's coverage still designates its repository the same way for everyone once discovered, so a team still reads the same history on the repositories it follows on both sides. Repositories already sent to a team's data repository are removed from it once, on the next start — otherwise they would sit there and land back on a colleague's machine at their next sync.
- The screen's code is now organised by screen and by layer (
public/js/core/,public/js/ecrans/<screen>/,public/css/,public/i18n/,public/html/— see PLAN.md). Nothing changes on screen: same tabs, same shortcuts, same labels, same behaviour. What changes is where a thing is found: one short file per screen section instead of a twenty-five-thousand-lineapp.js, one dictionary file per family with French and English side by side, one stylesheet per screen, one HTML piece per tab and per modal, and a check that refuses a file missing from the page or a call crossing a screen's boundary undeclared. A browser's error names the file. - The session form keeps “The AI may ask me questions” in plain sight, and starts with “Advanced” folded. The box has left the Advanced accordion: whether the AI may stop and ask is a decision you take for each session, not a setting to go looking for — it now sits above “Launch later”, in the coding, exploration and off-repo forms alike. The accordion (commit message, agent session to resume, skills) is folded by default so the form fits the screen; one click unfolds it, and editing a session unfolds it by itself when one of its fields holds a value.
- Scheduling a session's launch now uses a date field and a time field, side by side, instead of one combined field — each opens its own native picker (a calendar, a clock), and both stay just as typeable by hand. Filling only one of the two is signalled under the field that's missing, the same way a passed date already was.
- The default review prompt (Settings → Review, when the field is left empty) now asks for a structured report: findings ranked 🔴 blocking / 🟠 important / 🟡 minor, an overall score calibrated on named anchors (a score ≥ 7 excludes any remaining blocker), a “what's good” section and a merge checklist — instead of one free-form paragraph. A review prompt already customized in Settings is untouched; installations still on the previous default pick up the new one automatically, in their configured language.
- A session card in Dev IA says exactly when it finished — date and time, e.g. “finished on 09/23/2026 at 08:34” — instead of a relative “yesterday”/“the day before yesterday” that only told you it was recent, not which of several same-week sessions came first. The relative wording still shows up on hover, like every other date in the app.
- The server's code is now organised by layer (
src/app/,src/jobs/,src/db/,src/agent/profile/… — see PLAN.md). Nothing changes on screen or in the API: same routes, same database schema, same behaviour. What changes is where a thing is found: one file per route domain instead of an eight-thousand-lineserver.js, one schema slice per domain, one runner per job kind, and a check that refuses an import going the wrong way. A fork or a reader of the code finds each piece in a folder that names it. - Code contributions are closed. Mergerie is written by one maintainer, who stays its only rights holder — that is what keeps the project free to evolve its licensing, the AGPL staying in place. Pull requests on the GitHub mirror are now closed automatically with a note explaining why. Issues remain the place for bugs, ideas and translation errors; CONTRIBUTING.md says what a useful report carries, and asks for the fix in words rather than as a patch, for the same reason.
Removed
npm run pipe(src/cli.js). That smoke test wrote a fake forge address and token into the real configuration and a fake repository into the real database wheneverMERGERIE_DATA_DIRwas not set.npm run demoand the end-to-end suite cover the same path, isolated.- Voice dictation. The microphone on text fields, its Settings → Voice dictation screen, the local whisper.cpp engine (and its install scripts), the OpenAI-compatible and browser providers, and every setting that configured them are gone. Text fields go back to typing and pasting only.
- The dollar cost of a session, everywhere it showed up — the sessions list, “Agent's response” — is gone; only the token count remains. A dollar figure only ever came from a backend willing to report one, didn't compare from one month to the next as prices moved, and duplicated the token count sitting right next to it. Tokens alone are shown now, consistently with what Stats already did.
Fixed
- Journal lines shown twice. Two overlapping polls of the journal could read the same cursor before either advanced it and append every line twice; a single poll runs at a time now.
- A review's stored diff survives a re-read of the shared data. Re-reading the shared format (after a version upgrade, or a sync that only brought new report versions) reset the local diff of every review; the screen then recomputed it from the clone, and the demo, which has no clone, showed an empty diff and lost the remarks placed on it. The diff now stays as long as the review still points at the same report version.
- Journal stuck on “done” after re-reading a past job. Reopening a past job's log from Activity pins the view; a job launched afterwards (approving a plan, a rerun…) then wrote into a hidden pane and the banner never said “in progress” until the page was reloaded. A new job now takes the view.
- A question asked on a review report, and its answer, are never shared with the team — they used to travel with the team's data repository unconditionally, on the theory that the report itself is team work. The report still is; a personal question about it, and what the agent answered, now stay on the machine that asked, like a session's own follow-ups.
- Scrolling to the top or bottom of a review report, or of the merge request list next to it, now keeps scrolling the page, instead of stopping dead and forcing the mouse out of the panel to reach the rest of the screen. The list used to hold the wheel at its own edges on purpose, to keep a short scroll there from jumping the whole screen — but getting stuck inside the panel turned out to be the worse annoyance of the two.
- The “in conflict” tag and the “Update with {base}” button no longer outlive the conflict they pointed at. A successful catch-up replays the session's commits on top of an up-to-date base — resolved, locally — but the flag behind both stayed set until a push and the forge's next sync caught up, so a card kept offering (and warning about) a conflict already gone.
- A merge request merged directly on the forge no longer loses its link to the coding session that opened it. Merging from the session's own “Merge” button recorded the link; discovery, which is what actually notices a merge done anywhere else (GitLab's UI, another teammate), only ever updated the merge request's own row — never the session's. Once the forge stopped listing it as open, the project's link to it vanished from the session card, and “Create the MR” reappeared on a branch that was already merged. Sessions that already lost that link before this fix are repaired automatically on the next start — nothing to do.
- A coding session that fails now says why, instead of “claude failed (code 1): ” with nothing after the colon. In streaming mode, the CLI's explanation for a failed run arrives as a
resultevent on stdout, not on stderr — the error message only ever looked at stderr, which is essentially always empty there, so the actual cause (an API error, a service outage…) was visible only in the job's full log, never in the error itself. - The “in conflict” badge on a merge request card had the wrong shape. It shared its class name with an unrelated block on Settings → Sharing (a kept version of a data-sync conflict), which leaked that block's square corners, padding and background onto the badge. Renamed the Sharing screen's classes to stop the collision — same conflict-resolution UI, unrelated pill.
- “Catch up with the base and retry” now offers something to catch up on plain push rejections too, not only forge-flagged conflicts. The button appeared on any rejected push, but the project card's own “Update base” action only showed up once GitLab had flagged the merge request as conflicting — a plain non-fast-forward push (no forge-side conflict yet) left the button with nothing to click, and a “not available here” message instead.
- The assembled page tolerates CRLF line endings in
public/index.html. A checkout with Windows-style line endings made the<!--@include …-->markers stop matching entirely, serving the bare shell with none of its screens or modals filled in. - Reviews: sorting by lowest score now sorts. “Lowest score first” left the list in arrival order, and “Blocking first” did not break ties by score either.
- Reviews: “ready to merge” no longer includes low-scored merge requests. A merge request scored 2/10 with a green verification was listed as ready; the list now applies the same score threshold as the morning brief. The copied reference of a scored merge request shows its score properly.
- Reviews: “Search for new MRs” updates the counter and the Review button. On an empty queue they stayed at 0 and greyed out above the merge requests just found.
- Reviews: the “To review by me” chip appears in the “To review” queue, where review requests wait — it only looked at reviewed reports.
- AI dev: “Resume in terminal” is offered on free questions and out-of-repo folders again; the list never carried the command.
- AI dev: the verifier list follows the projects of the session form when a project is added or removed, not only when a repository is changed.
- AI dev: choosing “none” as the verifier of a coding session now sticks, in editing and in duplication alike. Reopening or duplicating the session brought back the single verifier that covers its projects, silently undoing the deliberate choice to run without one.
- Agents: “Sessions” on an exploration agent opens the Exploration list, filtered on that agent, instead of an empty Coding list.
- Agents: “Duplicate” and “Code” on an agent awaiting approval say why they are refused instead of reporting an unexpected error.
- Stats: the period and repository filters apply to every block. Token cost and the sent/received ratio now follow the period; “Per project”, recurring findings and the green rate follow the chosen repository. The repository list is filled even when Stats is the first screen opened, and an exploration among the most expensive sessions opens in the Exploration list.
- Settings: a review rule added without choosing a repository applies to all repositories, as its help says — it was silently limited to the first one.
- Settings: editing a verifier keeps its environment variables. The form opened with the field empty, and saving it again erased the values stored on this machine.
- Git: “Select all” in Git commands ticks the projects instead of doing nothing, and the merge work screen names the merge request it belongs to, like the running-merges list.
- Jira: a short outage no longer hides the Sprint filter or the workflow statuses until the next restart; removing a field-filter criterion keeps the filter menu open; “Make the AI code” offers the ticket's screenshots; the comment box offers to insert the links of the ticket's merge requests; and changing a status or un-watching from the Watched list refreshes that list.
- Notes: the todo add bar understands the short syntax it advertises (
@tomorrow,!!,!217,PROJ-12), and the hint shows it as code rather than raw tags. A ticket linked from a note or a todo opens that ticket, not the first of your list, and the share button is there from the first visit to Todos.
- A window opened from another window now opens on top of it. “Add to todos” and “Investigate” from a Jenkins job's window opened behind it, out of reach of the mouse.
- Jenkins: “My branches” and the
!iidtags work when Mergerie opens straight on Jenkins, without visiting Reviews first — a remembered “My branches” used to empty the list. - Docker: “Put in the grid” appears for a local project again — the server call behind it always failed.
- Links: the copy button of a grid cell can be clicked — it sat under the edit pencil.
- Activity: “Retry” is offered on a failed or stopped job, as in the log banner, and double-clicking a log line opens the merge request it is about. The banner counts only the jobs still running (“2 jobs running” with one stopped and one running).
- A pasted link wins over the last tab and over the morning brief: the object opens in front, instead of in a hidden Reviews tab.
- Keyboard: Enter opens the selected report, and Enter on a branch chip only copies its name — it also started the review of another merge request. The palette opens a watched ticket instead of the first of your list. The footer's “stats” mode is shown correctly after a reload.
- Sync: a push refused at every attempt (protected branch, read-only access) is reported instead of showing “up to date” forever, and a new sync cadence applies without a restart.
- Sharing: only its author can unshare or delete a shared note page or todo — from a colleague's machine it removed the file from the shared repository, for everyone. Editing stays open to the team, as before.
- Settings: saving no longer writes back a team setting a teammate changed meanwhile — the form now sends only the fields you changed.
- Sync: a review report deleted by a teammate is deleted here too; it survived, still openable, next to a merge request back in “To review”.
- “Ask the AI” on Git → Merge no longer fails the whole request over one unreadable path — a submodule whose commit pointer diverges between the two branches, for instance, is a directory on disk, and reading it as text used to throw Node's raw
EISDIR, failing every file's proposal along with it, not just that one. That path is now skipped like any conflict the agent can't resolve, and opening it by hand reports a clear message instead of the raw error. - A finding git had confirmed fixed no longer flips back to “gone, unverified” on the next pass, and the review card no longer counts it as still blocking. Once resolved, it stayed in the comparison pool for every future pass; the next one, having nothing left to change at that already-fixed line, found no trace of it in its own diff and downgraded it to “disappeared” — forever after, since each pass carried the same stale finding into the next. A resolved finding now leaves the pool for good, the way a merged branch leaves a to-do list.
- The merge dialog no longer offers to advance a Jira ticket that doesn't exist. The ticket key is guessed from the title or branch (e.g. a branch named after a word that happens to look like a ticket key), and when a fetch of that key had already failed — wrong guess, deleted ticket, no access — the dialog still proposed “move TICKET-1 to its next state and drop the merge request's link on it” for a ticket that was never there. A key already known to fail no longer counts.
- A coding session's card no longer offers “Tell Jira” for a ticket that doesn't exist, same root cause as the merge dialog above: the button used to test the branch name against a bare “looks like a ticket key” pattern, with no idea that a fetch of that very key had already failed at discovery. It now reads the same, error-aware ticket key the ticket badge already used.
- “Clean up now” (Settings → General, disk usage) now asks for confirmation before it runs. It deletes old job logs, slims down long-closed merge requests (previous versions, stored diff, questions, working folder) and compacts inactive clones — all irreversible — but a bare click ran it immediately, with no more warning than any read-only button on the same screen.
Security
- Note on the default. The agent restrictions below apply in secured mode, which is now chosen in Settings → AI session; the default of an installation that touched nothing is yolo (no restriction of the agent). The server-side limits — local token,
Hostallowlist, protocol nonces, per-machine approval, allowlisted environment — hold in both. - The API on
localhostnow belongs only to your browser. A second, local-only session token — separate from the one an exposed server already required — closes every/api/route to any other process on the machine: an AI agent's own shell, a verifier command, a script run by a dependency under test. Nothing to configure; it's issued and renewed automatically. - Coding sessions no longer run the AI agent in an unrestricted (“yolo”) mode. Settings → AI session has a new “Test the sandbox” button: it runs a real check (a blocked write outside the working folder, a blocked network call) and only turns the CLI's own sandbox on if both are confirmed blocked — never a checkbox on trust. Until verified, or on a CLI that doesn't support it, Mergerie falls back to a command allowlist; the old wide-open mode still exists but is now an explicit, clearly-flagged opt-in, never the default. Copilot CLI's own
--deny-tool/--allow-toolare now used when available, and a read-only session on a CLI that can't prove it's restricted is refused rather than assumed safe. - The team data repository can no longer be made to silently rewrite a review verdict, push on your behalf, or run with a weaker git setup than a code clone. Verdicts and attachments synced from a colleague are fingerprinted the same way reports already were; a session's “push automatically” flag stays a setting of your own machine; the sync itself now runs with the same hardened git invocation (no hooks, no
fsmonitor, filtered environment) as any other clone, and a.gitmodulesfile in the shared repository suspends the sync instead of being checked out. - Text an AI agent reads — a merge request description, a Jira ticket, a previous report — can no longer forge one of the agent's own protocol blocks (its findings, its questions, the repository it names, the agent it proposes to create). Every such block now carries a nonce tied to the run that asked for it, on top of the existing data-tagging; a look-alike block a piece of text might contain is neutralised regardless.
- Follow-up hardening, from an internal review of the changes above:
- The local session token closed
/api/requests case-sensitively;GET /API/configslipped through unrouted case-insensitively by Express itself. Both the local token and the cross-origin guard now compare paths without regard to case. - The nonce carried by an agent's protocol blocks was derived from a plain hash of a sequential database id — guessable in advance for every plausible id. It's now an HMAC keyed by a per-installation secret that never leaves this machine and is closed to the agent itself.
- A verifier command approved for the unsandboxed write allowlist granted the whole program (
npm testopened all ofnpm, includingnpm publish;node script.jsopenednode -e). Only the exact approved command line is granted now. - A verification synced while still running (before it has a verdict) no longer has its fingerprint locked in — syncing mid-run used to make the real, later verdict look like a silent rewrite and get rejected.
- “Test the sandbox” could mark the sandbox verified from an offline machine, since any failed network probe — including “no network at all” — looked like “the sandbox blocked it”. It now checks the network works outside the sandbox first.
- An automatic verifier's outbound network was briefly cut off (
unshareon Linux,sandbox-execon macOS) for the duration of this work, then removed again: cutting the network also cut access tolocalhost, breaking any verifier whose commands reach a database, Redis, or adocker-composeservice there — with no way to opt back in. Automatic verifiers keep the network open; what still closes this path is the local session token above and the throwawayHOMEthey already ran under. - A second review pass caught two of its own fixes: the “verification synced mid-run” fix above had left a hole where a verification whose verdict was already locked in could be erased by resending it without a verdict; and narrowing the injection-marker regex to known names had dropped its case-insensitive flag along the way, so
<<<findingsin lowercase slipped through neutralisation. Both are closed now.
- The local session token closed
A security review of the whole tool, and what came out of it. Most of it is invisible when all goes well; a few things now ask for a click or a setting, and those are listed first.
What you may notice
- Exposing the server now requires a token. With
HOSTset to anything but a loopback address, Mergerie refuses to start withoutMERGERIE_ACCESS_TOKEN; the browser enters it once on an/accespage, scripts send it as aBearerheader. Onlocalhost, nothing changes. - Reaching Mergerie through a host name (reverse proxy,
/etc/hostsentry) needs that name inMERGERIE_ALLOWED_HOSTS; anything else gets a 421.localhostand IP addresses always work. - Code that arrives through the shared data repository waits for you. A verifier whose commands changed, an agent whose permissions or schedule changed, the automatic reviews switched on by a colleague: each is marked “to approve”, shows what changed, and does not run on your machine until you click Approve on this machine. The click approves what the screen showed: if sync brings yet another version in between, it is refused and the new one is shown. Every change that counts is listed — “all the project's authors” for automatic verifications, an agent's skills and subagents with their tools. What you create or edit yourself is approved on the way, and everything that existed before this version is taken over once.
- Reviews, explanations, questions and explorations run the agent read-only. The broad mode from
COPILOT_ARGS(--dangerously-skip-permissions) no longer applies to them; the report comes back as the agent's answer. Coding sessions keep your mode but lose web fetching,curl,ssh,git push,git remoteandgit config. With Copilot CLI, which has no tool list, the run log says the read is not restricted. - Converging or coding on a branch that changes
CLAUDE.md,.claude/,.mcp.jsonor.github/copilot-instructions.mdstops first and names the files: that branch would rewrite the rules of the agent about to work in it. Confirm once for that content; a new push that changes them asks again. - “The merge request's author” is now recognised by the forge username only, not by the display name, which anyone can change to someone else's: the display name is kept as a fallback for a merge request discovered before its username was recorded.
- Automatic verifications run only on your own merge requests by default, never on a draft or a fork, with a throwaway
HOME. “All the project's authors” is a new explicit choice in Settings → Verifiers. - Two new AI bounds in Settings → AI, set per machine: at most N turns per agent session (200 by default) and an optional daily spend cap. They do not travel with the team settings — one push could otherwise lift both on every machine.
- The git palette is an allowlist of everyday subcommands (status, fetch, pull, push, log, diff, branch, checkout, rebase, stash, tag…). Entries outside it —
config,bisect,submodule, an option that runs a program or writes outside the repository — are refused when saved and when run. - “Test” with a changed address requires typing the token again: the saved token is only ever sent to its own address.
- The backup README no longer claims the tokens are removed: the archive carries the database, tokens included, and now says to keep it like a password.
What closed without asking anything
- Another website open in your browser can no longer drive Mergerie:
Hostcheck against DNS rebinding,Sec-Fetch-Sitecheck on the API, a strict Content Security Policy,nosniff,no-referrer; the backup and the data repository preview becamePOSTs. - The forge token is no longer written in the clones'
originURL, where the agent could read it: it travels as an HTTP header in the git process's environment only, and existing clones are cleaned at startup. Every git command runs without hooks,fsmonitor, external diff ortextconv. - The agent's environment is an allowlist — nothing from Mergerie's
.env— and its file tools cannot read the database or the.env. - Text from elsewhere (MR title and description, Jira ticket, previous report, exchanges from another machine, domain cards) enters the prompt framed as data, between tags a text cannot close. Automatic posting waits for a complete findings block; convergence reads its score only from the requested “Overall score: X/10” line.
- Importing the shared repository validates each file (types, closed lists, 8 MB, no symbolic link) and refuses silent rewrites of append-only documents; a verifier's local folder no longer travels. Each review rule shows who set it.
- Files supplied by others (attachments, note captures, ticket images) are served through one careful door: only raster images and PDFs display, the rest downloads, under
nosniffand asandboxCSP. - Docker actions only run in a compose folder found under your local folders; the data repository address refuses
http://,ext::and friends; Docker drift masks secrets by value, not just by name. - “Stop” now kills the whole process group, grandchildren included.
- The CI pins its actions by commit and runs with a read-only token. A
.envin the current folder that picks the agent binary is flagged at startup. - The data folder is created readable by you only.
1.7.0
Added
- “The merge request's author” can be the runner of the automatic reviews. Until now the automatic reviews and verifications needed a designated machine: one person paid the AI calls for the whole team, and nothing ran while that machine was off. The runner list now offers a second answer — the author — and the decision stops being global: each machine takes only the merge requests whose forge account is its own, on its own subscription, and leaves its neighbour's alone. The account is the one behind that forge's token, matched against the merge request's author on the username or the display name, since GitLab and GitHub do not store the same one. If that account cannot be known (no token, forge unreachable), the machine runs nothing and says why in the log — better nothing than the same review twice on every machine.
- Publish the link to a review report, instead of the report. Six hundred lines of report copied into a merge request comment: nobody reads them, and the next pass posts six hundred more. When your team shares a data repository, the report already lives there in Markdown — rendered by the forge like any other file. A new button on the report, “Publish the report LINK”, posts a three-line comment pointing at that address, with the score and the pass number. One copy, read by everyone in the same place, and a merge request that stays readable. The button only exists when a data repository is configured — without one there would be nowhere to point. The sync runs before publishing: a link to a file still sitting on your machine would send the team to a 404, which is worse than no comment at all, so if the repository cannot be sent the screen says why and nothing goes out. A repository on a local path (a shared drive, a USB key) has no web address, and the button says that too rather than inventing a link. The address is computed from the file the report occupies — never taken from the browser — and a token carried in the clone URL never reaches the comment. And it says when it already went out. Like the report button, this one turns into “Publish the report link again” and carries the date of the first send — except the date is read from the comments the team shares, so it also stops you when a colleague published that pass before you. Publishing again is not a correction: it puts a second comment in front of the same report. And it can happen by itself. Under “Automatically post the review report on the MR”, a new checkbox — “Post the link to the report, not the report” — changes what that automation sends: three lines instead of six hundred, on every pass. It does not decide whether the author is told, only the form; the checkbox above still decides that. And if the link cannot be made — no data repository any more, a repository on a local path, a sync that will not go through — the report itself is posted and the job log says why the form changed. Staying silent would leave a review with no reader, which is not what ticking the box asked for. The line only shows when a data repository is configured. And the text is yours. Under the two checkboxes, a comment template — a team setting, so everyone posts the same thing. Left empty it is the shipped message, which follows the interface language; filled, it is taken word for word, with
{url}(required),{note},{v}for the pass number,{iid},{project}and{title}substituted, and any variable it does not know left exactly as written. An empty field shows the shipped message as its placeholder rather than making you publish once to find out. A template without{url}is refused when you save it, not when it publishes: it would announce a report without saying where it is, on the merge requests of the whole team.
Changed
- The menu bar starts with the everyday work, and folds the rest away. Eleven entries is a list you stop reading. Git, Docker, Jenkins and Links are conveniences — you go there the day you need them, not ten times a day — so they now start folded, leaving Reviews, AI Dev, Agents, Notes, Jira, Stats and Settings in the bar. Nothing is disabled, removed or hidden from the product: the screens, their data and their shortcuts are whole, and one tick in Settings → General → Menus brings a menu back for good. “Restore the original menus” returns to that starting point rather than showing everything. If you had already arranged your own bar, it is left exactly as you set it — the new default only applies to a bar nobody has touched.
Fixed
- Review reports read as paragraphs again, not as a pile of fragments. Agents now wrap their reports at about a hundred characters, the way they write source files, and each wrapped line was shown as a paragraph of its own — with its own spacing — so a report looked like a column of broken sentences, and the continuation of a bullet fell out of it. Text written by the AI (reports, explanations, answers, session output, domain cards) now follows the Markdown rule: consecutive lines make one paragraph, and an indented line continues its bullet. Level-5 and level-6 headings (
##### 🟠 IMPORTANT) are shown as headings instead of raw text. Notes and Jira texts keep their line breaks — there, a new line is what the person typed.
- “Bulk add from GitLab / GitHub” now says what is missing instead of quoting the forge. With no token the button was still there — and rightly so: it tells you what the tool can do, which is worth knowing before you have a token. But clicking it went to fetch the list anyway and came back with the forge's own words, “401”, “missing token”: what happened, never what to do. The modal now names the connection that is missing and carries the door — Settings → Git, cursor in the field, and the GitHub button leads to the GitHub field rather than the GitLab address.
- A team setting added by a new version now reaches the machines that were already up to date. Hydration is incremental: it applies the files that changed since the last mark. So a setting a new version understands was never read from a file an older one had already hydrated — the file had no reason to change again, the mark had moved past it, and restarting changed nothing. That is how “post the link, not the report” stayed unticked on a machine whose
settings.jsoncarried it at “1”, with nothing broken and nothing to see. The tool now keeps a signature of what its code understands — its version, and the list of shared settings fields — and re-reads the repository once when that signature changes. It adds, it never removes, and it does nothing at all when the signature has not moved, so an ordinary start costs nothing.
npx mergerieno longer starts on an agent you do not have. Without a.env,COPILOT_BINwas “copilot”: whoever had installed Claude Code did not have that binary, the tool silently fell back to dry-run, and every review came back a fake report — it “worked” and was useless. From a clone you copy.env.example; undernpxthere is no clone, nothing to copy, and nothing saying where the file should go. The first launch now writes one in the folder you run it from: it looks forclaudethencopilot(on thePATH, then where the installers put them) and pointsCOPILOT_BINat the one it finds, with that agent's own arguments. The file is written once, mode600, and never rewritten — it will end up carrying tokens. The command says what it created, rather than leaving a file to be discovered. The two TLS escape hatches are written commented out: nobody should turn off certificate checking without meaning to.npx mergerie demowrites none — it promises to leave nothing behind. And it explains the option that lets the agent act without asking.--dangerously-skip-permissions(claude) and--yolo(copilot) are not a convenience: the agent is called non-interactively (-p), so nobody is there to answer a permission prompt — without them the work hangs, or everything that would prompt is denied without a word and the report comes back poorer for no visible reason. A file you did not write carrying “dangerously” and no explanation is exactly what should worry someone, so the generated.envnow says why it is there, what it does not protect (the agent runs with your rights; the option builds no wall around the clone), and offers the narrower--permission-mode acceptEditsas a commented line — with its price written next to it, since under-pa denial is silent.
- The sync indicator no longer says “↑1” just after sending. The counters were read to decide whether to push, and never again afterwards: a successful send left the footer showing one commit still waiting until the next round, up to thirty seconds later. They are refreshed as soon as the push lands — and so is what reads them to decide, such as “is that report really on the forge?”.
- A
.envasking for another data folder is now obeyed bynpx mergerie. The file was read — its port, its agent, its proxy all worked — but itsMERGERIE_DATA_DIRline was quietly dropped and the database went to~/.mergerie/dataanyway: the command had already decided where the data lived before the server got to read the file. It now reads the.envof the folder you run it from before deciding, and what your shell exports still wins over the file. The two READMEs and the guides said the variable was honoured either way; they now also say which folder the file is looked for in — withnpx, the one you are standing in when you type the command. And sincemergerie demoerases its data folder before re-seeding it, the command now names that folder out loud rather than erasing in silence.
1.6.0
Added
npx mergerie demo— the tool in one command, with nothing to clone. The package now ships amergeriecommand:npx mergerie demoseeds the fictional database and opens the tool on it, in dry-run and with no token;npx mergerieis the real thing. Undernpxthe code lives in a cache that can vanish at any time, so the data no longer goes next to the code: it goes to~/.mergerie/data, and the demo to~/.mergerie/demo, unlessMERGERIE_DATA_DIRsays otherwise.PORT,HOSTand a.envin the current folder are honoured as withnpm start, and Ctrl-C stops the server rather than leaving it running on its port. The archive published to npm carries the command, the server, the screen and the demo seed — never the tests, the plans, the data or the demo video — andscripts/publish-npm.shrehearses the whole thing from an empty folder with a throwaway home before anything is published.
- Share your work with a team, through a git repository. A domain map costs hours of agent time to produce; redoing it on six machines means paying six times for the same thing and getting six slightly different answers. Point Mergerie at a git repository — your team's own, on the forge you already have — and it keeps the accumulated work there: review rules, verifiers, agents and their map of the code, todos, and the notes pages you tick, one readable file per object. Everyone keeps their own instance, their own tokens and their own AI subscription: the requests leave your machine and are billed to you, and it is the result that is shared. Nothing to install, nothing to administer — and you get “who decided what, and when” for free. Joining takes your history with you. A repository created on the forge almost always comes with an initial commit — a README —, and attaching to it brings the team's content down. It also sends everything this machine had already accumulated up, in the same gesture: the months of reviews and sessions that predate the switch are what the team wants most, and they would otherwise have stayed behind while only future work travelled. The screen says how many documents went up. Day to day you do nothing: every thirty seconds the tool sends what is new and fetches what is new elsewhere, and the footer shows
↑2 ↓0. Offline, everything keeps working — commits stay local and catch up on return. When two people change the same thing, the remote version wins and yours is kept, with two buttons to take it back or keep theirs: never a half-finished rebase, never a conflict marker, never a git command to type. Everything the team accumulates travels: repositories, the review state of merge requests, reports and every pass of them, findings, convergence runs, rules, verifiers and their verdicts, agents and their map of the code, coding and exploration sessions with their agent passes and attachments, free questions, todos, lots, and the team settings. Deletereviewer.dband it all comes back from the files. Nothing secret ever goes in. The seven API tokens, the clone folder, the language, the dictation engine, this machine's absolute paths, agent session handles, tidied-away sessions and job logs all stay here — and so does the whole Links tab, which says where you go to work rather than what you produced. Every column is classified by name, and the tests refuse a secret-looking column that is not declared, because a secret committed to git is permanent.
- The “AI output” and “diff” buttons show up on a session that came from the team. Whether to offer them was decided from file paths on your own machine, which a received session does not have — so they vanished, while every iteration's text sat right there and the branch diff was one
git diffaway from the clone (the server already knew how to recompute it). They are now decided from what actually travels: the iterations themselves, and the commit the session produced. Whether to offer it was decided from a file path on your own machine, which a received session does not have — so the button vanished while every iteration's text sat right there. It is now decided from the iterations themselves, which is what travels and what the button opens.
- You can open the diff of an iteration a colleague ran. The patch itself stays on the machine that ran the agent — sending hundreds of kilobytes into the team repository to carry something entirely recomputable would be a poor trade. What travels is the pair of commits the iteration sits between, and that is enough: your own clone recomputes the same diff, to the byte. If your clone does not have those commits yet, the screen says so and tells you to fetch the branch, rather than opening an empty view.
- An iteration received from the team no longer claims it changed nothing. A patch is a file on your own machine and does not travel, and “nothing changed” was deduced from “we measured, and no patch is on file” — so every iteration of a session that came through the repository announced that it had changed nothing, when it had changed everything. The two commit ids do travel: equal, the agent committed nothing; different with no patch at hand, we do not know — and the screen says nothing at all, which it already knew how to do.
- A merge request reviewed by a colleague now shows up as reviewed on your machine. Everyone discovers the same merge requests from the forge, and each machine gives them an internal id of its own — so the identity of a merge request is (repository, number), not that id. It was the id, and the colleague's review was refused on arrival with a uniqueness error: their work simply never showed up. The same held for a review, and for a verifier two people had named the same thing. Every uniqueness rule in the database is now checked against the registry by a test, so the next one cannot be discovered in production, on someone else's machine.
- Attaching and re-sending now say what they will do, before they do it. “Clone / attach” and the new Send everything again both open a summary first: which way the exchange goes, what leaves by kind, what stays on this machine (sessions and todos are private by default — better to learn it here than by looking for your session on a colleague's screen), how many documents the repository already holds, and file by file how many will be added, changed or left unchanged. Deleted: none — sending writes, it never deletes, and the summary says how many of the repository's files it will not touch at all. The summary is read, not deciphered: what leaves and what stays sit side by side, one line per kind with the count on the left, because their opposition is the information; the file counts are four figures under them, the zero of deletions included — that one is what you came to check. In front of an empty repository everything counts as added: the files this machine already wrote for itself are “unchanged” on disk and yet all of them will travel, and announcing “0 added” before initialising a bare repository would have said that nothing leaves. Building the summary questions the remote repository, which takes as long as the network takes, so the button spins and the line next to it says what is being waited for.
- “Send everything again”, because “Sync” only sends what changed. After a repository emptied or truncated by hand, a normal sync put nothing back — the queue of pending writes was empty, and nothing said so. The button now exists and is named for what it does. It goes through the attach path on purpose: a repository reset by an orphan force-push shares no ancestor with your local history, and a plain commit-and-push would be refused.
- A sync can no longer empty your database. “A file gone takes its row with it” is right for one document: someone deletes a note, it goes away for everyone. Applied to a repository that was just reset — a force push, a recreated project, a truncated clone — the same rule wiped reviews, sessions, agents and verifiers in one pass, and the database's own cascades took the rest. That happened. A pass that would remove more than half of what the repository holds, and at least ten documents — or that would leave the repository with nothing at all, which is the same accident on a small team — is now refused outright: nothing is deleted, everything is kept, and the sync indicator turns red with the reason instead of reporting “up to date”. Deleting three notes still works.
- Todos are personal unless you share them, one at a time. A todo list is somebody's list — the tool already said so by keeping “you have been reminded” local. Yet every todo travelled, including the ones nobody typed: the one a Jira watch created, the one an agent left when it stopped to ask a question. Those two sources are local, so their todos never leave at all now, whatever you tick. A team todo still exists (“review lot X before Friday”) — it is the checkbox, not the default. And closing todos when a merge request lands now only closes yours.
- Eight settings moved from “team” to “this machine”. Opening the morning brief at launch, how often this machine polls the forge and Jira, closing your todos on merge, and the four boxes ticked by default on a new session: those are habits, not policies. Imposing yours on everyone made the tool unpleasant for five people to suit one. Retention stays a team setting, and deliberately: a purge removes files from the repository for everybody, so one value keeps a machine set to seven days from erasing everyone else's history.
- Machine paths no longer leak in error messages. The text of a failed session or a verification log quotes
/Users/you/…happily. It is not a secret, but it identifies a machine, and the rule is that none of that enters the repository: those are replaced on the way out by<data>,<clones>and~, so the message keeps its meaning and reads on any machine.
- Automatic reviews and verifications now have a runner, like a scheduled agent. They are team settings and they travel, but every machine has its own queue and its own discovery — so with two machines left open, each new merge request got two reviews (two versions, two billed AI calls) and, with automatic publishing on, two comments on the forge. Settings → Merge Request now asks who honours them; with nobody named, they run nowhere, and the screen says so next to the boxes. On a single machine nothing changes at all.
- The merge-request author filter is back. “Mine / the others” had quietly vanished when shared data arrived: a second route of the same name was declared ahead of the one that asks each forge who you are, so the screen got an answer with no forge account in it and stopped drawing the chips. No test was watching that screen; one is now.
- A verifier's environment values stay on your machine, and what each iteration cost stays yours. A variable on a test command is the natural home of a
DATABASE_URL, anNPM_TOKEN, a sandbox API key — and nothing stopped them from being committed, because the safety net only looks at column names. A verifier is still a team product: its commands, its coverage, and now the names of the variables it expects, so a colleague knows what to fill in. The values live on the machine that typed them, and a verifier that arrives with names you have not filled in says so on its card rather than failing later for a reason you would have to hunt down. In the same vein, the dollar cost of each iteration no longer travels: spending is already opt-in as a daily total, and sharing it per pass gave away by session what the checkbox refuses to give by day.
- A draft never leaves. Inline remarks you have written on a merge request but not sent yet, the text of a follow-up you are still typing, the agent profile you are trying out: none of them travel now, whatever the parent's checkbox says. A draft is not a comment — it changes until you press send — and sharing them meant two reviewers watched each other write, with the last one to save quietly overwriting the other's remarks. What is the product is the posted comment, and posting an inline remark now records it in the merge request's comment log, where the team can read it back without opening the forge.
- Your sessions are yours until you say otherwise. A coding session, an exploration, a free question: what they hold is not a product the team consumes but the way you worked — the prompt as you typed it, the three follow-ups, the question you would not have asked out loud, the screenshot you pasted that shows another window, and what each attempt cost. The result is already shared through its own channel: the branch and the merge request on the forge, the map of the code, the notes page an agent wrote. So sessions now carry the same Share checkbox as a notes page — unticked — and nothing leaves until you tick it. Their iterations and attachments follow the session: it cannot be half shared. Untick it and the whole folder leaves the repository. Sessions written before this update become private, and leave the repository on the next start. And a session someone else shared can no longer be deleted from your machine — you put it away instead; deleting it here would delete their work for everyone.
- Docker, Jenkins, Git and Jira stay on your machine. They join the Links tab on the local side, and for the same reason: a palette of git commands, a Jenkins job you point at, a container you backed up, a ticket you watch — all of that describes a machine, its access and a way of working, not a product the team accumulates. Sharing it imposed one person's tooling on everyone, carried a log of git actions nobody else can replay or undo, and filled everyone's todo list the moment a ticket watched by a single person changed state. Whatever had already gone into the repository is removed from it once, on the next start — otherwise it would sit there and land back on a colleague's machine at their next sync.
- A closed merge request takes its title, branches and author with it. Once a merge request is closed those stop being able to change, so they are no longer the forge's alone to tell: they travel with it. A machine that has just joined can therefore read its own history — every review report opening on a real title rather than a bare number — without needing a forge token at all. While a merge request is still open, the forge remains the only source: a title gets rewritten, a branch renamed, and two machines would overwrite each other in turns.
- A closed merge request gets its title, branches, author and merge date back — so the cycle-time chart has a past. Discovery only lists open merge requests: anything already closed never comes up again. A machine that has just joined the team therefore received reviews on merge requests closed months ago and could only show a number at the top of the report — no title, no branches, no author. And the cycle-time chart measured from a line in this machine's own activity log, written when it noticed the merge, which says nothing on anyone else's machine and does not exist at all on a new one. The merge date now comes from the forge — the real instant, the same for everyone, and it travels with the merge request — and one catch-up call per repository fills in everything a closed merge request was missing, without ever overwriting what is already known.
- The link to the merge request on the forge now travels, and so does its opening date. The forge is authoritative for a merge request's title, branches and SHA — sharing those would make stale data travel. Its address and its opening date are the two things that never change, so they go with it: a machine that has just joined shows the header's link to GitLab or GitHub without having to discover the merge request itself first, and the cycle-time chart has an opening date to measure from. (The merge instant is still only known to whichever machine was watching when it happened, so that chart fills in as the team merges from here on.)
- A session's AI output finds its way back. Each iteration's text travels in its own file, but the pointer a session keeps to its latest output is a local path, rebuilt on arrival — and it was not being rebuilt, so a session that had come through the repository announced “no output” with the text sitting right next to it. Sessions older than the iteration history carry their output along with the session itself, since they have no iteration to put it in.
- A machine that already has the same agent — or note, or repository — can now join. Install the shipped “Librarian” on two machines and each gets its own internal id for it; attaching then failed outright with UNIQUE constraint failed: agent.slug, and since an import walks the registry in dependency order, everything after that point never arrived — sessions, notes, and the pointers to the review reports, computed at the very end. The file is named by the slug, so two files of the same name are the same document: the local row now adopts the repository's identity instead of fighting it. And one document that cannot be posed no longer costs the whole pass — it is reported and the import carries on.
- A review's report now arrives even when it lands after the review itself. On a freshly attached machine, reviews came through but their reports were blank. The report lives on your own disk — the path means nothing on anyone else's machine — so the pointer to it is recomputed on arrival; but that recomputation only ran when the review row itself was in the same batch. A batch carrying only new report passes — a colleague reviewing, or simply two commits — left the pointer on the previous pass, or empty. It is now refreshed by both.
- Shared data has a settings tab of its own. It used to be three fields between the theme picker and the danger zone, in General. But this is not a display preference: it is where you decide to open your work to other people, and where you come back — to see where the sync is, to settle a conflict. Settings → Shared data.
- The footer says when the next sync leaves. Hover the
↑2 ↓0indicator and it counts down to the next round, second by second — the question you ask in passing, answered where you pass, without opening the settings to look up the interval. Click it and the round happens now.
- Cards say who did the work. “by Claire” on a review, a session or a verification — read from git, which already knows who committed the file. No field to fill in, and nothing at all when you work alone.
- Your AI spend stays yours unless you say otherwise. A checkbox in Shared data sends a daily total to the team — never the per-call detail, which would say what you asked and when. Off by default.
npm run demonow shows the sharing too, with a real local git repository and three fictitious authors: the footer counts, the “by <name>” lines and a notes page's History all work, because they are the real mechanism rather than a mock.
- Notes pages are shared one by one, and not by default. Everything else the tool keeps is a product — a review, a rule, a map of the code — and producing one for yourself alone makes little sense, so it all travels together. A notes page does not: it is the one place in the tool where you write with no reader in mind — a draft, a password pasted for the length of a test, what you think of an architecture before you can say it out loud. So each page carries a Share checkbox, unticked, and nothing leaves until you tick it. Untick it and the page is removed from the team repository — and from your teammates' instances, since it was never theirs; your own copy stays, whole. Pages already written stay yours. Sharing a sub-page takes its parent page with it, and un-sharing a parent takes its sub-pages back — a sub-page alone would arrive nowhere, since it is named by its parent — and the screen says so rather than doing it quietly.
- A notes page now has a History. Who changed it, when, and what changed — read straight from the data repository. It needed no new bookkeeping: the information exists because the page is a file in git.
- A scheduled agent has a runner. Three instances left open would launch the same agent three times, and the team would pay three times. The agent form now asks who honours the schedule; with nobody named, the agent only runs by hand — which is the default.
- Every setting now says what it commits: “team” or “this machine”. Settings were all shown the same way, and they are not the same thing. The prompt templates, the thresholds, the review policies and the forge address describe the tool — two reviews of the same merge request written under different instructions are not comparable, so those are meant to be shared. The API tokens, the clone folder, the language and the dictation engine belong to your machine alone. A small badge next to each field says which, in both themes and both languages, and the tokens are now stored in a table of their own — one that is never meant to travel. Nothing changes in how you use the screen; what changes is that the tool now knows the difference, which is what a future shared setup will stand on.
- The librarian draws, and a note page knows how to show it. Twenty services described in prose is a page you read once: what you actually want to know is who calls whom, and what a service's tables look like. The librarian now puts a “who calls whom” diagram on the general page — one node per service, the arrow saying the means (REST, event, job), databases and queues as nodes too — plus a sequence diagram when a flow crosses three services. And each repository gets its own sub-page with its database schema, read from the migrations or the models, with the path it came from. A repository with no database says so in one line: the instruction forbids it to invent a table, exactly as the investigator is forbidden to invent a repository.
- A
`mermaidblock in a note becomes a diagram. The renderer used to drop the language of a fence, so a diagram was displayed as its own source code. Colours follow the theme, and switching themes redraws them — they are baked into the SVG, and a dark diagram on a light page is unreadable. A diagram that does not compile keeps its source on screen with the error above it: notes are written by hand and by agents, and a typo must not take the page down. The library is shipped in the repository (public/vendor/), never fetched from a CDN — nothing leaves the machine — and it is loaded only when a rendering actually contains a diagram, so a page without one costs nothing.
Fixed
- A review of a single pass now shows its findings. The list of findings — one line per finding, its severity, the link to the file and the line, the filters by severity — lived inside the resolution banner, which only exists from the second pass onwards, when there is a delta to tell. A review that had only been run once therefore displayed the report and nothing else: no blocker, no major, no minor, no way to turn a finding into a draft comment. Barely visible while you reviewed your own merge requests — you re-run, you reach v2 — and systematic on a review received from a colleague through the shared repository, which arrives with its single pass. The list now stands on its own; the banner joins it when there is something to compare.
- A merge request no longer produces a commit — and a conflict — on every discovery. The file of a merge request carried
updated_at, and discovery rewrites every open merge request on every pass: same values, fresh timestamp. So every pass changed every merge request file, committed one line per merge request, and two machines that had refreshed between two syncs collided on every one of them — conflicts, a red indicator and a “kept version” for documents nobody had touched. That is the promise “conflicts are rare by construction” turned against itself, and it made sharing unusable as soon as automatic refresh was on. The timestamp stays local now: it says when this machine last saw the merge request move.
- A rebase with two conflicting local commits now converges. Saving the same note twice before a sync makes two local commits. Only the first was resolved: the second made
rebase --continuefail, the rebase was abandoned, the overwritten versions were not even kept, and the next round replayed the same scene — the machine stayed “↑2” forever, without a word on screen. The rebase now loops until it is done, skipping a replayed commit that the resolution has emptied, and it says so if it truly cannot finish.
- An empty database in front of an up-to-date clone hydrates itself again. “Delete
reviewer.dband it all comes back from the files” was false: with nothing to exchange the round returned before reaching the branch that hydrates, so the database stayed empty until someone clicked Clone / attach. Worse, in that state the first local deletion swept the repository clean of a table nothing protected any more, and pushed it. A round now hydrates when this machine never has, and a sweep refuses to remove a dozen files for a table that holds no rows at all — deleting your last note still removes its file.
- One malformed document no longer blocks the whole sync, permanently. Only the database write was protected; reading a document back — which writes files, and refuses a path that would escape the data folder — was not. One such file and the hydration marker stopped moving, so every round replayed the same failure: the whole team's sync held up by a file one machine wrote. Such a document is now reported as an orphan, and the rest goes through.
- A hydration no longer throws away writes that were waiting. The queue is emptied at the end of a hydration — what it just imported does not need re-exporting — but that also emptied what was waiting before: a row held back because its dependency was not there yet, and everything a background job had written that no request had flushed. Those files would only have been written at the next change to their row, which is to say possibly never.
- A review rule that fires on a path, with no branch, now reaches the team. Such a rule (the most common kind: “on
**/migrations/**, check reversibility”) was written to the data repository but refused on every other machine — the file arrived, the row never did, and the colleagues kept reviewing without it. It now lands like the others.
- Opening the code on a review received from the team shows the changed files again. The report arrived, but the code to read it against did not:
review.diff_pathis a path on the machine that ran the review, so it never travels — and the two endpoints behind “open the code” read nothing else. The colleague got a file tree with not one file coloured and an empty diff. The diff is now recomputed from their own clone when the file is missing: a merge request's diff is not data to carry around, it is a function of two references everyone has. It targets the reviewed commit while the clone still holds it — the tree next to it shows that same commit — and falls back to the branch head otherwise. No fetch as long as the references are there: the two calls leave the screen in parallel, and two fetches at once in one clone would fight over its locks.
- And the mirror case: an iteration done by a colleague catches your own agent up. Your session here is resumable, so the agent picks up its own conversation — which never contained the colleague's iteration: another agent did it, on another machine. Yours restarted from the state it had left things in while the branch already carried someone else's commits, and nothing on screen said so. Each local iteration now leaves a marker, so the next turn can recognise the iterations that came from elsewhere and replay only those, under a heading that says what happened. Your own conversation is not replayed: the agent remembers it, and serving it back would make it doubt what it had already done. Sessions that predate the marker are covered too: an iteration that came through the repository is recognised by the file hydration wrote for it, so a session started before all this still catches up — otherwise a colleague's iteration that arrived before your next local one would have stayed invisible for good.
- A follow-up sent from the machine that received a coding session now carries the conversation. The agent's session handle only means something in the
~/.claudeof the machine that opened it: it does not travel, and it could not. So the colleague's follow-up started a brand new agent that receivedapply this correctionand nothing else — not the original task, not one word of what had been said before. What does travel is the iterations: each one's request and the agent's answer are shared, file by file. They are now replayed at the top of the prompt when there is no local session to resume — it is not the agent's memory, it is its transcript, and that is all that can cross a machine. Bounded, and from the end: the most recent iterations are kept, and the prompt says how many were left out rather than implying a complete history.
- Same for a coding session received from the team: “See the diff” shows the branch again. A fallback did exist when the patch file is missing, but it compared
origin/<base>...HEAD— and HEAD is the branch the clone happens to be sitting on, not the session's. On the machine that ran the agent those are the same, so the fallback looked right; anywhere else it answered the diff of unrelated work, or nothing. It now targets the session's commit, which is also the version the file tree beside it shows. The test was passing for that same reason and now puts the clone somewhere else first, which is the colleague's situation.
- A merge request received from the team now arrives with its title. Title, branches and author only travelled once an MR was closed: while it is open the forge is authoritative, and sharing a mutable value makes stale data travel. The argument does not survive what it produced — a machine that had not yet discovered the MR itself listed it in to review with no title at all, and “See the diff” then ran
git diff origin/null...origin/nulland put git'sambiguous argumenton screen. There is no tug of war: both machines read the same forge, so they converge; the worst case is a title a minute out of date, and that beats a blank line — it is all a machine without forge access will ever have. The current SHA still does not travel: it moves with every push, and a stale one is the single value that makes you review a diff that no longer exists.
- Without branches, the diff says what is missing instead of quoting git. A merge request that arrived through the data repository before this machine discovered it has no branches yet; the message now names that and points at refreshing the repository's MRs. And a merge request whose title is not known yet shows its number alone rather than
!203 —, with the reason on hover: a dangling dash reads as an empty title, the number alone reads as a title not known yet — which is what is true.
- A row that could not become a file no longer vanishes without a trace. The queue of pending writes was meant to hold on to anything that cannot be written yet — a review whose merge request was just deleted, a pass whose session does not resolve — and retry on the next pass. The comment said so; the code removed the row right after, unconditionally, so the retry never happened and nothing was logged. Found on a real database: two follow-ups out of a session's nine had no file in the shared repository and had never had one, with an empty queue and no error anywhere. Such a row now stays queued until it can be written, and a row that can never be written says so in the log instead of disappearing.
- Automatic sync now sends what runs in the background, instead of waiting for a click. The queue of pending writes is drained at the end of every non-GET request, and that is what arms the grouped commit. Anything written outside a request went through nobody: a merge request discovered on its own, a review finishing, a session committing, the Jira watch. Their work stayed in the queue, no commit was armed, and the next round found nothing to push — while the Sync button, which commits first, sent everything. Hence “it only leaves when I click.” A round now makes the same gesture as the button. With nothing to commit it costs one
git add -Aand an emptydiff --cached: the price of a loop that stands on its own.
- “Clone / attach” no longer fails on
index.lock. Three things write into the shared repository without knowing about each other: the periodic round, the commit grouped three seconds after your last write, and the attach you just asked for. Two of them at once and git answersUnable to create index.lock: File exists— in practice it is your gesture that fails, because a timer took the lock a second earlier. The guard only protected the periodic round against itself. The three now queue: a request waits its turn instead of failing, in the order asked. A periodic round that falls while something else is working is skipped rather than queued — it comes back in a few seconds, and stacking identical rounds behind a slow attach would only replay them for nothing.
- Answering an exploration's question now closes the todo it left behind. A session that stops to ask puts a high-priority todo in your list — the queue is free and nothing will restart on its own. It was closed only once no repository of the session was waiting any more, which is right for coding, where each repository has its own session and its own questions: answering the first does not settle the four others. An exploration is the opposite — one session for all its repositories — so the question is written on every target, and answering once answers for the whole session, which is exactly what the resume does when it unblocks the others before relaunching. The count still saw them waiting, and the todo stayed open forever as soon as there were two repositories: that is, for the three shipped agents, all scoped to every repository.
- The demo now writes its review in the language of the screen. The simulated report, the explanation and the answer to a question were written in French, hard-coded: an interface switched to English showed “Revue — Paiement 3×”, “Points d’attention” and “Note globale” under English menus — including on the screenshot that illustrates the tool. Every sentence now goes through the shared dictionary, so the language check guarantees none is missing on either side, and the score follows suit:
7,4/10in French,7.4/10in English, both still read by the screen's score filter. The “simulated analysis” banner, which used to be cut over two lines and rendered as two stacked quotes, is one again.
1.5.0
Added
- A documentation agent writes a general page and its sub-pages. The librarian rendered one block: twenty services in a single page is a page nobody re-reads, and splitting it by hand undid itself at the next run. Note pages now hold sub-pages, one level deep, and an agent whose output is a note page decides itself whether any are needed, how many, and how to split them — the general text stays on the root page, the detail of each point goes to its own. Sub-pages are matched by title from one run to the next, so a weekly agent updates them instead of piling up copies; the ones it stops producing are kept, not deleted, because one may have been completed by hand, and the run says which. In
Notes, a sub-page is indented under its parent and joined to it by a tree guide, a search that finds one brings its parent along for context, and deleting a page says how many sub-pages go with it. Sub-pages are folded by default — a column where every general page unrolls its eight children is no longer a column you can scan — with the count shown on the folded parent; the parent of the page you are reading unfolds on its own, and folds back when you leave it, and a search unfolds everything it matched. - Reading and writing a note no longer share the width. Two half-columns cut both: a table overflowed the rendered side while a Markdown line wrapped in the middle of a link. A page now opens on the rendered view alone, full width — notes are re-read far more often than they are written — and one click switches to the Markdown alone, or back to two columns. The choice is remembered. An empty page opens on the Markdown: there is nothing to read yet.
- The agents screen counts in tokens, and says what each button does. An agent's card showed the dollar cost of its last run — a figure only some backends announce, absent everywhere else, and not comparable from one month to the next as prices move. It now shows what the run actually brushed against, in tokens, which is measured in every case. A domain agent also shows what its knowledge costs to read: the map is copied into the request on every single run, so its size is a recurring expense, and the
Knowledgewindow now gives it version by version — the only way to notice a v4 that swelled from eight to thirty thousand tokens before every run pays for it. Every button on the screen explains itself on hover, saying in particular which ones start a session that costs. - The two agent modals are as wide as the coding-session one.
New agentandNew domain agentopened narrower — amax-width: 980pxadded later silently pulled every wide modal back to 980, Jenkins included, contradicting the rule declared right above it. Widening the box was not enough: the form inside stayed capped at 720px, so the window grew and its content did not. Both now fill the same width, and a repository checklist flows into columns instead of scrolling as one tall narrow strip. - A job panel no longer swallows the clicks meant for the bottom of the page. The panel is fixed, spans the whole column and stands a hundred and seventy pixels tall; the end of every page passed underneath it. It happens for real — a job that ends in error never folds away on its own, by design, so you can read the error — and what it covered included the action bar of the Settings form, hence the
Savebutton: measured at 769→801 for the button against 787→958 for the panel. The page now reserves the panel's measured height, so anything under it can always be scrolled clear. - Statistics count in tokens too. The dashboard showed dollars next to the costliest sessions and next to each agent; it now reads in tokens like the agents screen, for the same reason — a dollar figure exists only on the backends that announce one.
N commits since the mapopens on the commits. The badge said a domain agent's map had aged, never by what: you re-read the map without knowing whether twelve typos or a rewrite had dated it, and so without knowing whether the update — which costs an AI call — was worth it. Clicking it now lists them per repository, with sha, date, author and message.
- Ask a question about a review without rewriting it. Asking why a finding was blocking meant
Ask the AI for a change, which regenerates the report and makes it one version more — so the question cost you the report you were reading, and the score could move with it. A review now has its own exchanges: ask, get an answer under the report, and the report, its score and its versions stay exactly as they were. The question resumes the review session when there is one, so the AI answers from the diff and its own report rather than reading everything again. Exchanges are searchable in the same column view as a session's iterations, and they are deleted along with the report they quote. - The diff of a single follow-up. Seeing what one correction changed meant re-reading the whole branch diff: by the third follow-up, the three lines you had asked for were buried among two hundred. Every iteration of a coding session on a repository now keeps its own patch, and
AI outputoffers, right under the request, “See what this iteration changed” — the same screen as the project diff (file tree, whole file with the changes in place), bounded to that one pass. Only the latest measurement is kept — what you just asked for is what you re-read, and every new pass erases the one before it. Out-of-repo coding gets the same thing, where there is no branch and no commit: Mergerie keeps a tracking repository whose.gitlives in its own working directory, so your folder receives nothing — dependency and build folders stay out of the diff, and past a size guard rail the measurement is dropped rather than slowing the coding down. Those tracking repositories clean themselves up: the ones no session references any more are removed daily, the rest are compacted. An iteration that changed nothing says so; one older than this addition shows nothing rather than promise a diff it does not have. - Agents — a new tab, and a different way of launching the AI. An agent is a session profile: a role, a scope of repositories, tools, skills, subagents, an output, sometimes a schedule. A session launched inside a clone already has the code, the repository's CLAUDE.md and its skills; what it does not have, Mergerie does — the twenty other clones, what was just merged, and cross-cutting knowledge that lives between repositories. An agent run is an ordinary session: same follow-ups, same questions, same archived passes, same cost. Three rules hold everywhere: an agent never pushes and never publishes on its own, never guesses a repository, and never handles conversations between humans.
- Two agents ship with the tool. The incident investigator takes a trace, a log or a ticket excerpt, searches every clone, and names the repository, the file and the line with a likely cause — and if nothing matches it says so instead of offering a plausible repository. Its report carries a Fix in <repository> button that opens a coding session on the right one. The librarian keeps the service map in a note page — created once, updated on every run, never duplicated. Both are editable, and restorable with one button.
- Domain agents: “where do we handle notifications, here?”, answered once. Give a subject; the cartographer searches the repositories and writes the map — entry points, mechanisms, types, configuration, tests, pitfalls. Every quoted path is opened inside the clone: one that does not exist is marked (unverified) and counted. The agent can then be asked, or asked to code with its repositories pre-ticked. It reports what it finds wrong in its own map rather than silently fixing it.
- You know when a map has aged, for free. The knowledge records each repository's SHA and the paths it quotes; Mergerie counts the commits that touched those paths since — “7 commits since the map”, with no AI call. Update relaunches the cartographer with the previous map, the reported gaps and those commits (“look here first”); the result waits for you with a readable diff, and the agent keeps working from the old one until you validate. The team's hand-written notes are carried over by the code, not merely by the prompt.
- Your skills, listed instead of remembered. A sub-tab shows the
.claude/skills/and.claude/agents/of your cloned repositories and of your home — read-only, Mergerie never writes there. In a session they are ticked, and typing/in the request offers the skills,@the subagents. Nothing is inserted without an explicit choice. - The log finally says what the AI used, and what it cost. A skill invocation now appears as
» skill <name>, a subagent as» sous-agent <name> — <what it was asked>, and what a subagent says is indented so you can tell who is speaking. Actions blocked by permissions are reported at the end of the run, and the real cost in dollars is kept alongside the token estimate — including per agent, in the statistics. - Agents can run on a schedule. Every day, every week, or every month, at a set time. A slot missed because the machine was off is caught up rather than lost, and a daily ceiling bounds what may trigger on its own. The morning brief says what ran during the night, and what is waiting for you.
- Any window you type into can be set aside and picked back up. A modal covered the whole screen, so going to check a branch name or a ticket's state meant either giving up on checking or closing the window and losing what you had written. Every window with fields now has a
—button in its corner: it minimises to the bottom of the menu, and one click brings it back exactly as it was — the fields you filled, the cursor in the field you left, and the tab it started from. The chip's cross discards it for good. Windows that ask a question (a confirmation, picking a verifier) have no such button: setting one aside would keep whatever opened it waiting forever.
- A Jira ticket's detail now shows the tickets it is linked to. "is blocked by", "duplicates", "relates to" — those links are what says which part you cannot ship on your own, and the card said nothing about them: reading them meant reopening Jira. They now sit under the attachments, grouped by relation, each with its summary and its status; the wording is your instance's own and follows the direction of the link. Sub-tasks and the parent of a sub-task join the same list, a link that is done is struck through, and clicking the key opens that ticket in the column you are reading rather than in a Jira tab.
- The remarks and follow-ups you wrote and never sent are picked up by the morning brief. Three inline comments written in the viewer, the window closed to check something else, and the merge request merged without them — the quietest loss of work in the tool. The brief now has a section for them, oldest first, and the button reopens the viewer where they are sent from. A draft badge sits on the merge request card and in its report header as well. Same for the follow-ups written while a session was running and then forgotten; the ones that leave on their own at the end say so.
- A review report shows the todos already open on that merge request. It offered to add one without showing what existed: two days later you had written the same note twice. They are ticked right there — which is the whole point of showing them.
- A free question becomes an exploration or a coding session, like an exploration already could: the answer named the repository, and nothing carried it further than the screen it was on.
- “The AI has a question” leads to the session that asked it. The notification opened AI Dev on the sub-tab you last consulted, leaving you to find which of twelve sessions was waiting — while the event has carried its identifier from the start. Every notification that names an object now opens that object, from the branch explorer, the palette, the brief and the statistics alike.
- A review report says which notes cite it, and which domain map it touches. The autolink ran one way only: a note led to the merge request, and the merge request had no idea three paragraphs had been written about it on Monday. Incoming links are now listed on the report and on the Jira ticket sheet, with the excerpt taken around the citation. And a merge request whose diff touches the paths a domain map quotes carries a badge to that map — which is also handed to the AI as review context, so it knows what that corner of the code does instead of rediscovering it.
- “Investigate” now starts from a red Jenkins console and a failed verification, not only from a Jira ticket. Those are the two places where you actually read a trace; the incident investigator opens with it already in the request. On a verification, it sits next to Fix: a red test whose trace you do not understand is not fixed, it is searched for first.
- A red verdict leaves a todo behind, and can comment the Jira ticket. The notification goes by and is forgotten; the badge assumes you reopen Reviews. A todo is now created per merge request (running the same verification three times updates one row rather than stacking three) and a green run closes it. Optionally — unchecked by default, like “Notify Jira” — the merge request's ticket also receives a comment when the branch breaks what the base passed: the ticket is read by QA and support, who ask “is it tested?” without ever opening the forge.
- Git operations, fallen containers and finished Jenkins builds finally say something. Deleting a branch or pushing a tag is the most irreversible gesture in the tool and it happened in silence; a container going down woke nobody; and the end of a build you started from here was only noticed if the Jenkins tab had stayed open — when you start a build precisely to go and do something else. A background watch on the server handles the last two, once a minute, asking Jenkins nothing while no launch is pending and alerting on a transition rather than a state. The morning brief picks up the merge left half-resolved yesterday and the Git operations that failed, and Statistics gained an Git operations card — the last trace table it ignored: thirty deletions without a failure is routine, ten with four refused says you are aiming at protected branches.
- A todo can be attached to a branch, a verification, a build or a container. “Rebase this branch before Monday”, “this build breaks one time in three” are exactly what you jot down, and nothing carried them: the button existed on a merge request and a ticket only. It now sits on a branch row, a verification report, a Jenkins build row and a container row — and the todo knows how to take you back there.
- The palette acts, it no longer merely navigates. A verifier, a Jenkins job, a compose project and a saved git command joined it, each opening the screen that knows how to do it — never running anything on its own: a job deploys, it gets started deliberately. A merge request is also found by its ticket key, the way half a team refers to it.
- A repository's settings row carries a
Sheet. The row said what concerns the repository itself; the sheet says what is attached to it — verifiers, Jenkins jobs, review rules limited to it, grid services, default linked projects, agents it belongs to. Six answers to “what breaks if I remove it?”, all of them joins that already existed. - Reports, sessions and note pages have an address.
#/reviews/216can be pasted into a note or a message, the browser's Back button returns to the previous object instead of leaving the tool, and a link you receive wins over the tab of your last visit. “Copy the reference” now hands over both links: the forge shows the diff, Mergerie shows the report, the score and the verdict. - The merge dialog restates what is known before the irreversible gesture — score, blocking findings, verdict, stale report, and the remarks written and never sent, which would go out with the merge request. It asked “squash? branch?” and nothing else.
- The brief picks up out-of-repo sessions stopped on a question, which no screen surfaced: they have no branch and no merge request to remind you of them, which makes them the easiest to forget.
- A branch row carries what the database knows about it — its Jira ticket and that ticket's state, the last verification verdict, and the repository's Jenkins job with the branch already filled in (that button existed only on a merge request verified green, when deploying a branch to staging before opening a merge request is exactly the case).
- A report's findings become inline remarks in one gesture — all of them, or only the blocking ones. Eight findings meant eight trips through the viewer; they carry their file and their line, which is exactly what an inline draft asks for. Only the findings that fall inside the diff are turned into remarks: a report may well talk about a line the branch never touched, but an inline comment attaches to the diff, and the forge refuses a position that is not in it. What is left aside is counted and named. Nothing is sent: they are drafts, re-read and sent as a batch like the others — and
Delete allempties the batch in one go when one of them blocks it, instead of reopening every file to remove them one by one. - The viewer's tree says what each file carries: unresolved findings, discussion threads, remarks in draft, changed lines. On a forty-file merge request, knowing which ones to open meant opening them one by one.
- A verification report shows the five slowest tests, and marks the flaky ones. The durations were in the runners' output all along and thrown away; a red test that was already green on the very same code in another run now says so, instead of sending you looking for what the branch broke.
- “Try” really tries an agent profile. It opened a session pre-filled with the template while the model, the tools and the subagents stayed behind — you were trying everything except what you had just set. The draft now travels with the session, and no agent is created: trying leaves nothing behind.
- A merge in progress says which merge request it is catching up — number, score, ticket — and, once committed, offers the diff of the merge itself: that SHA had been stored and read by nobody, while it is the only way to check what you just assembled.
- A job's log can be searched, and filtered down to its error lines. A verification run pours out two thousand lines; finding
ECONNREFUSEDin them was done by scrolling. - A dozen everyday frictions. Searchable dropdowns answer the keyboard (
↓/↑/Enter, andEscapecloses the list rather than the window you were filling in);/searches in the tab you are in instead of throwing you back to Reviews; a job that cannot be replayed says why; the ticket key in a report title is the one the server computed rather than a second rule; duplicating a session keeps its agent; the dictation vocabulary knows your container names.
- You can dictate into any text field — and the transcription knows your repositories' names. A microphone appears on the field you are writing in; you speak, and the text lands at the caret, exactly as if you had typed it (so drafts still autosave and "unsaved changes" still shows).
Ctrl/Cmd+Shift+Spacestarts and stops it,Escstops. It works on session prompts, follow-ups, answers to the agent, merge request comments, notes, todos, commit messages and review rules — not on URL, token, path or search fields, where a microphone would just be noise. What makes it usable on technical French or English is not the engine, it is what Mergerie sends it with every sentence: the names of your repositories, the services and environments of the Links tab, your Jira key prefixes, your verifiers, your linked Jenkins jobs and the branches of open merge requests. The same audio that a bare engine writes as "the merge rec west 244 on web app front" comes back as "merge request 244 on webapp-front". A glossary and a list of corrections (heard => written) cover what the database cannot guess, and!214/PROJ-720are rebuilt from their spoken forms — those are what become links in your notes and targets in the palette. A hiccup on one sentence no longer costs you the rest: a segment the engine could not answer is dropped and the ones behind it still land, while a refusal that cannot be retried — the dictation switched off, an audio format the engine will never take — stops the microphone and says so on the button rather than leaving it listening into the void. Sentences are sent as you pause (700 ms of silence, adjustable), so the text arrives while you are still talking rather than ten seconds later; when you stop, the whole take is re-read in the background and replaces what was inserted, unless you have already corrected it yourself. What the engine invents over silence — "Sous-titres réalisés par la communauté d'Amara.org" and its English cousins — is dropped by four successive guards, and what is dropped is counted on screen: if that number climbs, the microphone is picking up noise. One sentence in the other language does not need a settings trip: ⇧-click the microphone and that take alone is dictated in the other language, which the bubble announces. Three providers, one setting, and the screen says where the audio goes before you choose: whisper.cpp running locally (the recommendation — nothing leaves the machine, and the audio is never written to disk), any OpenAI-compatible API, or the browser's own recognition (nothing to install, but the audio goes to Google or Apple, said in plain words). Dictation is off by default: until you pick a provider, no microphone appears anywhere.
- Installing the local dictation engine is a button, and it tells you what it is doing. The settings panel does not ping: it walks the whole chain — binary, model, voice detection, startup (naming the acceleration it found: Metal, CUDA, Vulkan or CPU), a real transcription, vocabulary, then the secure origin and the microphone — and names the first step that breaks with the gesture that repairs it. "Install" runs as a job: its log shows live, "Stop" ends it cleanly, an interrupted download resumes, nothing is asked as administrator, and a 1.6 GB download is announced before it starts. When it finishes it fills in the settings itself and re-runs the test.
- Filing a link is now paste-and-Enter. The free-link form opens on the address rather than the label — the address is what you paste, the label is what the tool can guess from it — and Enter saves, as it already did for a quick todo or a watched ticket. The same key saves a service, an environment and a context link.
- “Verify a branch” no longer forces you to take every covered repository. Each row now carries a checkbox, ticked to start with, so a verifier covering five repositories can verify just one — previously all five branches had to be supplied, and a row whose default branch could not be read (an unreachable repository) blocked the launch of the others. The selection is remembered per verifier, because “only
api-core” is a habit rather than a whim of the day, and a filter above the list hides rows without unticking them: what is ticked goes out, visible or not. The server already accepted a subset — it is the screen that refused to form one.
- Automatic publishing can now be limited to reports that block. Settings → Merge Request: when "Automatically post the review report on the MR" is ticked, a second checkbox appears under it — "Only post when there are blocking findings". The report is then posted only when it holds at least one finding of severity blocker; the others stay saved and readable in the tab, they just do not land on someone's merge request for three minor remarks. A report with no finding at all does not go out either, and the job log writes how many the pass held — "nothing blocking" and "the findings block is missing" are not the same event. The
Publishbutton on a report ignores the filter: an explicit gesture always goes out. Unticked by default, so turning automatic publishing on keeps behaving exactly as before.
- A second pass over the whole tool: 59 changes, from the three defects found while reading the code to eleven crossings that did not exist. Nothing new to configure; almost all of it reads data that was already in the database. Deciding faster in the queue What the session already knew Crossings that did not exist Memories, copies and gestures Settings and lots Statistics
- The queue sorts: usual order, smallest first, oldest first, lowest score — a dropdown on the same row as the author chips, because who and in which order are two ways of narrowing the same queue. The size and the age were written on every card since 1.4.0 but could not be used to choose what to start with. The order you pick is remembered, and it wears the same pill as the chips beside it — an unusual order is highlighted like an active chip, because a queue sorted by lowest score otherwise just looks out of order.
- The morning brief counts what is ready to merge: score above the convergence threshold, verified green and not stale, and no ticket standing in the way — three columns already in the database. Nothing is merged: the tool says how many merge requests are only waiting for a decision.
- A merge request in conflict says so on its card, and the badge opens
Git → Mergeprefilled to catch the branch up — where Update with main only ever existed for merge requests born from a session. - The ticket's status reaches every merge request, not just watched ones. Discovery already read the whole issue for its context; it now keeps its status too, at no extra call.
- After a green verdict, the verification report offers what comes next — Merge, Run <job> — where until now you closed the window, found the card again and opened its "⋯" menu.
- A finding says how long it has been there:
since v1is not the same as "not fixed yet", and three passes later that is the whole difference.
- The verifier picks itself when exactly one covers every repository of the session.
- The dialog proposes the repositories of your last session of that flavour, instead of the first of the list — wrong thirty-nine times out of forty on a forty-repository setup.
- A card says when it finished ("finished 3 h ago") and when a todo is waiting for you because the AI stopped on a question.
- A session offers to review the merge request it just opened, and a checkbox in the dialog does it at creation — the global "review on arrival" setting engages the whole estate, this one only engages what this session wrote.
- The resumable agent sessions are proposed instead of asking for a UUID copied by hand out of a resume command.
- Four session defaults are settings (auto-push, AI questions, tell Jira, converge afterwards): they no longer start unticked at every opening for someone who ticks them every day.
- Merging closes the Jira loop: a checkbox in the merge confirmation moves the ticket to its next state and drops the merge request link there — the transition read from Jira, never guessed, remembered per Jira project, unticked by default.
- A ticket becomes a lot: Verify together on a ticket carrying several merge requests creates the lot named by the key and launches the joint verification, instead of going back to Reviews to tick five cards and type a name.
- The Jenkins console enters a follow-up:
Use the consolefills the field with the last thirty lines and the build number, exactly as Use the verification report does. Jenkins keeps the verdict; the agent only receives the text to fix. - The morning brief says what CI broke on your branches, computed when it opens from the list Jenkins already loads — no polling.
- A watched ticket can raise a todo when its state changes, carrying the reason you wrote for watching it: a desktop notification dies with the tab, a todo stays in sight.
- A note becomes a coding session: the page is the prompt, its screenshots are the attachments — the same path as from a Jira ticket.
- A compose service that publishes a port offers to open it, and to fill the empty "local" cell of the Links grid with the address it already publishes.
- A green Jenkins build carrying
ENV=preprodoffers to open that environment of the linked repository — the same resolution already done on merge requests.
- Git → Merge and Git → Actions remember their repository, branches, action and targets, as Compare, Navigate and Commands already did. The create-MR dialog reads the same per-project memory as the merge dialog for squash and branch deletion.
- Three filters stop forgetting: the todo filter, Jenkins's search and checkboxes, and Docker → Actions.
- Copy where you paste into Slack: the full SHA (shown short), a Jira key, a verifier's command, a Jenkins console, a container name, the address of a grid cell.
Ctrl/⌘ + Entersends the forge comment, the Jira comment and "Request a change" — and all three keep a draft that survives a reload.- Changing a Jira status asks first, naming the ticket and the state: a native
selectapplied onchange, so an arrow key was enough to move a ticket in front of the whole team. - Shortcuts:
/searches the tab you are on instead of ejecting you to Reviews,j/kwalk Jira, Jenkins, todos and lots,Nopens a session,fasks for a fix on the focused card, and the?panel finally listsCtrl+Enterand⇧-click. - Quick capture: "tomorrow 9 am / Monday / +1 h" buttons, the last priority reused, and the short syntax finally written under the add bar.
- A review rule can be limited to one repository, instead of being guessed through a
path_matchonly that repository would satisfy. - A verifier says how many sessions carry it — renaming or deleting one was done blind.
- A lot's name is proposed (the common Jira key, failing that the common branch prefix), Create and verify does both in one gesture, and a lot remembers which verifier it uses. A merge request says which lots it belongs to.
- A deleted non-compose container can be restored: the tool saved its full inspect before every deletion and no screen ever read it.
- The Jira witness ticket is a setting instead of being retyped at every connection test, and the effective defaults are written into the empty fields.
- The cost of a review, on its report and in a "most expensive reviews" ranking next to the sessions — reviews now carry their own token usage, as sessions have since 1.4.0.
- What goes in versus what comes back: characters sent per character received, which is what points at an over-long template rather than at an unavoidable cost.
- The green rate of verifications per repository, least green first.
Changed
- The Links tab has been rebuilt around what it actually is: a place you read, and a place you write. It presented itself as a search engine — one field and three rows of pills, all lit, so the grid started a third of the way down the screen — while its grid, designed for one address per cell, could not hold a list. Three rows of filters become one: a switch per column, and a
Tag ▾menu that says what it will find on each half of the screen ("3 services · 2 links"). Hiding a column now hides a column and never a row, so looking for the holes in prod is possible again; the old behaviour is a checkbox you tick yourself. The service pills are gone — they repeated the rows visible five centimetres below.
- A cell with fifty addresses no longer makes a seven-hundred-pixel row. Expanding in place pushed the service name into a void and the free links off the screen, and the way back was an eleven-pixel "Collapse". A cell shows the three most opened — frecency has always been counted per address, it just never showed — then
▸ 50 addresses, which opens the list in a panel anchored on the cell: one line per address with its last opening, a filter,↑↓,Enterto open. The list scrolls inside the panel; the grid does not move.✎ Editswitches the same list to editing, with arrows to reorder and aPaste several addressesbox. A row's height no longer depends on its content.
- Adding starts from the address.
+ Paste an addressreplaces the menu that asked you to file before pasting. One URL per line; for each one the tool suggests a name (from the path), a service (if the host names one, or its repository) and an environment (if the host names one). Nothing is guessed silently — every suggestion is a selector you can change — and an address whose host names no known environment falls into a free link rather than a "likely" column. The selectors carry+ new serviceand+ new environment, so creating the columns is no longer a prerequisite: on an empty database, one paste is enough.Ctrl/Cmd+Von the tab opens the same dialog pre-filled, and the empty state is now a single field.
- An address with no name is shown by what tells it apart. The cell printed a shortened URL:
api-preprod.demo.invalid/healthrepeated the column (preprod) and the row (api-core) and drowned the only useful word at the end of forty characters. It now readshealth. The rule — last path segment, else the host stripped of what the row and column already say, else the host — applies in the palette too. The full URL stays in the tooltip and in the copy.
- A grid row fits on one line, and can be reordered. The name, the repository and the tags took three lines of text, so a row was 90 pixels tall for one address per cell; they now sit on one line behind a letter tinted from the name, and the column carries its environment's colour so preprod is recognisable without reading. Rows and columns are dragged into place with one save on release — moving a column from sixth to first cost five clicks and five reloads. Pinned services are separated by a rule, and the pin is in the row (it was set in the service sheet, and drawn with a tag icon).
- Free links are a list, not cards. Forty-five pixels and a border per link meant sixty links took two and a half screens for sixty lines of text. Twenty-eight pixels, a letter, the name, the shortened host, the tags — and on hover: copy, file into the grid, edit, and delete with an undo instead of pencil → Delete → confirm. Sorting follows frecency, like the palette, rather than a raw counter that kept last month's favourite on top for six months. The grouping by folder starts as soon as a folder exists, instead of past twelve links — that is, exactly when you are trying to recognise your own filing.
- The Links tab has a keyboard.
/puts the cursor in the search,Enteropens the first result,↓moves into the grid,j/kwalk the rows,←/→the cells,Enteropens,eedits,ccopies. A cell with a single address is clickable as a whole, and an empty cell's+only appears when its row is hovered — it used to dominate the addresses on a grid where half the cells are legitimately empty.
- The service sheet shows all the addresses of a cell, one line per address plus an empty one, instead of the first followed by a count of the rest that you could not open. Context links can be set from creation, the repository is suggested from the name you type when exactly one matches, and a repository already used by another service is announced before saving — only the first one feeds the merge request buttons.
- The “ticked by default” boxes of Settings → General were never saved. Ticking “The AI may ask questions” and coming back showed it unticked, and a new session ignored it. Two defects one behind the other: a checkbox's
.valueis"on"whether it is ticked or not — so the form sent"on"in both cases — and those five settings are stored as integers, so the database hands back1where the screen compared against the string'1'. The screen also had no Save button at all in General: its fields belong to the shared settings form, whose only buttons live in the other sub-tabs. All three are fixed, and the confirmation now appears in General like everywhere else.
- “Ready to merge” in the brief always counted zero. Two defects at the same spot, each hiding the other: the threshold arrives on a /10 scale while the score is stored on /1 (0.84 for 8.4), so the comparison was never true — and the sub-query meant to check “this merge request has a green verification” resolved against the outer row instead, which made a single green verification anywhere enough for every well-scored merge request. Fixing one was needed to see the other. A verdict on a SHA the branch has moved past no longer counts either.
- A JUnit report and a TAP report now count the same thing. TAP excluded skipped tests from its total, JUnit counted them: the same project announced two different totals depending on the format its runner emits.
- A report left by the previous run is no longer read as this one's result. In
in placemode the repository keeps its files between runs; a report file older than the run that was supposed to produce it is now ignored, and says so, instead of passing for a fresh verdict. - An
in placeverification reserves the folder it works in, with the same key as an out-of-repo session: both worked in the user's own working folder, and nothing stopped them from running at the same time in it. - The retention purge finally covers the Git operation history, the only trace table that grew without bound.
- “Waiting for answers” in the convergence banner showed a raw key (
converge.status.needs_input) at the exact place an instruction is expected, and the correction prompt existed twice, in French, in two files — it is now a template like the others: translated, editable, read in one place.
Fixed
- An up-to-date map no longer claims one commit has aged it.
N commits since the mapread1 commiton a repository where nothing had moved. On an emptygit log, a fallback landed on the command object itself and[object Object]counted as a line — so as a commit. The same phantom went into the Cartographer's context on every knowledge update, which was told a commit named[object Object]had touched the map it was asked to re-check.
- A domain agent stopped reading every repository behind your back.
New domain agentasks where to look, and ticking a single repository held for the initial mapping — then quietly stopped holding. A knowledge update is run by the Cartographer, whose own scope is all repositories, so every update cloned, read and paid for the whole estate on a subject you had said concerned one repository; a repository added to Mergerie months later joined in too. The repositories a run is given now restrict it always, whatever the profile's scope and whatever the mode, and they still never widen it: a repository outside the scope, or disabled, does not become a target because someone named it.
- Every field of the agent forms now says what it is for. The form asks for a model, a permission mode, a tool list, a turn bound — settings you cannot guess, and where being wrong is expensive: an agent that writes where you thought it only read. Three fields out of seventeen carried the ⓘ. They all do now, sections included, and the explanation says what happens when the field is left empty. Clicking the ⓘ of a section no longer folds it.
- The card kept counting pending remarks that had been deleted. The viewer's counter and the card's
n pending remarksbadge count the same thing, but only the first one redrew: delete a remark — one by one, or withDelete all— and the viewer said1while the card behind it still announced3. The badge exists precisely so that unsent work is not forgotten; stale, it sent you back to re-read a batch that was already empty. Both now follow the same count, in the queue, in the reviewed list and in the report header, without reloading the list.
- The three fields of "Jobs linked to repositories" now fill the row instead of a third of it. Settings → Jenkins reserved three wide columns, but its fields are searchable pickers whose box was not told to grow: each one fell back to the default width of a text input, about twenty characters, so a job path like
boutique/api-deploy-recettehad to be read through a slot half as wide as its own label. The job column is now the widest of the three — it holds the longest value of the row.
- « Install » failed on WSL before doing anything. A checkout made with Git for Windows (
core.autocrlf=true) gives the install script Windows line endings, andshstops on its first line with a message the carriage return itself truncates (set: Illegal option -). Shell scripts are now pinned to LF in the repository, and when an existing checkout still carries CRLF, the server runs a normalised copy and says so in the job log, with the two git commands that fix the checkout for good. - Esc during the "warming up" moment now cancels dictation instead of closing the window behind it. Between the shortcut and the first "listening", dictation spends a second or two opening the microphone: pressing Esc in that gap found nothing to stop, closed the session dialog on its way through, and dictation then started into a field that was no longer there — the microphone stayed lit with nowhere to write. A dictation that is opening is now a dictation that can be cancelled, and it hands the microphone back.
- "Test" no longer turns red the moment dictation actually works. The check probed the binary with
whisper-server --help, and that call does not return while another whisper-server is alive — so the very first successful dictation made the next test report "binary missing" while transcription was working. A running engine is now taken as its own proof.
- The dictated context no longer pushes your glossary out of the engine's prompt. The last words spoken are appended after the vocabulary, and Whisper keeps only the last 224 tokens: what fell off was the head — your glossary and your repository names, the very things with the highest priority. Their room is now reserved in advance.
- Adding the first link on an empty Links tab no longer pops the "New environment" dialog. An older click handler was still listening on the grid and answered the empty state's "Add" button as well as the paste dialog, so closing the one opened the other.
- Esc closes a cell panel even after you have done something in it. Pasting several addresses redraws the panel's body and the focus falls back to the page; the key was only listened to inside the panel, so from that moment on the panel could only be closed with the mouse.
- Opening a link from a merge request was not counted. The buttons carried a two-segment reference (
service:environment) where frecency counts three (service:environment:address): every opening from a merge request was lost — neither the palette nor "last opened" ever saw it.
- A context link's ⚡ now shows what it opens. The "1 context link" chip had a tag's styling and led nowhere; hovering it now resolves each template on an example, and clicking opens the service sheet at the right section.
- The "File N links" counter follows the ticks, instead of catching up at the next render.
- Fields you type in were sometimes the browser's, not the app's. A field built in JavaScript outside a
.formblock inherited nothing: 21 pixels tall with one pixel of padding, next to 38-pixel fields in the same box. It hit the per-environment addresses of a service — where you paste a URL — the label of a review rule, the free answer to a question from the agent, and the three fields of the Docker log tail. Every field of every add/edit dialog now carries the app's own size, and a test measures them so the next one cannot slip through.
- Adding an address in the links grid gave you a 90-pixel field. The editor lives in the cell — one click, type, Enter, which is the point of it — but a column is 190 pixels wide once you have six environments, and the editor inherited that: the address field was 90 pixels, the panel spilled over the neighbouring columns and its hint wrapped onto three lines. It still opens from the same
+, with the same keys, but as a panel anchored under the cell at its own width (a 304-pixel address field), naming the service and environment it edits and underlining the cell. The cell keeps what it was showing, so you can see what you are correcting.
- The label of a free link stopped being suggested from the address. It was proposed only on an empty field: typing the URL character by character made "h" a valid host, so the label became "h" and stayed there. And once you had typed a label by hand, the suggestion was dead for every link afterwards until the page was reloaded. The suggestion now follows the address as you type and steps aside for good the moment you write in the field yourself.
- The "⋯" menu of a merge request card opened off-screen. It really did open —
hiddenflipped, the button reported itself expanded — but it was placed with the rules written for the combo boxes: the left edge and the width of its trigger, a 39-pixel button pinned to the right of a card. With its 210-pixel minimum width, the box ended past the edge of the window, at every window size. From where you sit: you click, nothing happens. The menu is now anchored by the stylesheet, as the "Review ▾" caret next to it already was — and the list unclips its overflow, so the menu is not cropped from below either.
- A late file render no longer wipes the one you are reading. Opening a file in the code viewer empties the pane, awaits its diff, then writes it back — so two renders could overlap (opening the viewer starts one, clicking a finding starts another on a different file). The slower one won: it rewrote the pane with its own content, erasing the file you had just opened and any inline comment editor open on it — that is, what you were in the middle of writing. A render that is no longer the latest now stands down.
- Clicking a finding always does something. It could land on a line that carries no "+" button (a deleted line, a hunk header), or on a row detached by a re-render between aiming and clicking — and in both cases the function gave up without a word. It now retries on the effect and, when a file genuinely has no commentable line in this diff, says so.
- A filter that leaves nothing, then removed, gives the list back. Filtering on "Other people's" (or searching for something absent) until the queue was empty, then going back to the whole list, left the screen empty: the "nothing to show" branches wrote the DOM without recording their signature, so the stored one stayed that of the last non-empty render. Coming back computed exactly that signature again, and the render was skipped — no error, and nothing left to click to get out of it.
- Every comment posted to Jira sent the source code of a function.
addCommentbuilt its body from the translation function instead of the text you typed, so the "Comment" button on a ticket and "Tell Jira" on a session both posted a block of JavaScript to your colleagues. Demo mode does not go through that route, which is why nothing ever showed it.
- "Verify afterwards" is filled in when the dialog opens from a merge request or a ticket. Those are the two most frequent ways into the coding dialog, and neither refreshed the selector: it stayed empty, or kept the list of the previous opening — the verifiers of other repositories. You clicked Have the AI fix it, launched, and the session finished "pushed" with no verdict.
Escon a confirmation answers it. It hid the dialog without resolving the promise, so the button that opened it stayed in its loading state for good, waiting for an answer that could never come.
- The CI badge showed a cross on a green build. It compared the build state against values the Jenkins client never produces (
ok/koinstead ofsucces/echec), so every build was read as a failure and none carried a colour.
npm run checknow refuses a file that does not parse, front and server. Every guard in those two scripts reads the code as text: an unbalanced brace escaped all of them, and the check answered OK on anapp.jsthe browser refuses to run — or on aserver.jsthat turns the whole test suite into a hang with no error message.
1.4.0
Added
- A third pass: what the tool already knew but did not say, and what it did not cross. Fifty-two changes from a walk through the whole demo, tab by tab. Nothing new to configure — almost all of it reads data that was already in the database. Deciding without opening anything Turning a reading into a gesture Saying what was already known Crossings that did not exist Remembered instead of retyped
- A merge request card carries its size and its age:
12 files · +340 −80 · last activity 2 d ago. Both are taken in the same call that already fetched the changed paths, so the queue says which one to start with without opening three cards. - The "out of date" badge says by how much:
out of date · 3 commits, and hovering it lists their messages. One call to the forge, made on hover only — never for a whole list. - The score badge says which pass it comes from:
v3 · 07/08 · 1 resolved · 1 still there— what the version selector says once the report is open. - Two chips above the queue: Mine / Other people's. A tech lead sorts first for what the team is waiting on. The token's account is read once from each forge; without it the chips do not appear at all.
- A finding is a door. Clicking
src/checkout/total.js:8opens the code viewer on that line with the comment box open and pre-filled with the finding — a draft, like every inline comment, so you reread and adjust instead of retyping what the AI just wrote. - A branch name copies in one click, everywhere it shows (merge request card, session project line, branch explorer, report). Shift-click copies
git fetch origin && git checkout <branch>— the gesture that follows the copy nine times out of ten. - "Copy the reference" in the ⋯ menu:
!217 — 3× payment (8.1/10 · verified) <url>, the Slack message already written. - The morning brief carries the action, not just the link: Fix on a failed verification, Review on a fresh merge request, Run / Push / Create the MR on waiting sessions. One action per line, the one that closes it.
- Every statistics number is a door: clicking "worst 5.5" or "pending 3" opens Reviews filtered on that repository, at the right stage.
- Keyboard:
vverify,ccontext,mmark handled,xtick for a joint verification, on the focused card — next to thej/k/Enter/dthat already existed. They click the rendered button, so what is disabled stays disabled. - The palette opens a reference typed alone:
!217orPROJ-1408go straight there on Enter, ⌘/Ctrl+Enter opening the diff instead of the report. - A quick capture understands a short syntax:
!217 reread the total @tomorrow !!becomes a todo linked to !217, due tomorrow at 9, high priority. What is not recognised stays in the title, as written.
- A session's project line shows what its merge request became: score, verdict, pending comments — instead of a bare
MR !216 ↗that sent you back to Reviews. - Exploration, free-question and out-of-repo cards show the first lines of the answer (expandable) and what the pass cost:
3 min · ~13,500 tokens. Token usage is now attached to the session that spent it, which is also what makes the new five most expensive sessions ranking possible. - An empty "Verify afterwards" list explains itself: which verifier covers what, what it is missing, and the door to Settings → Verifiers.
- A todo linked to a merge request shows the state of that merge request; hovering an autolink
!214orPROJ-720in a note shows title, score, verdict and state. - A Jira ticket gains a "In Mergerie" section — the merge requests carrying its key, with score and verdict, and the sessions started from it — and the list cards carry the same marker in one line. "Have the AI code this" now proposes the last repository used for that Jira project.
- The deletion preview says whether it is safe: per branch,
merged into main/MR !217 still open/not merged. And a branch is no longer anonymous in the explorer: the score of its merge request's review, and the coding session that created it. - A compose project says which branch is running (branch and short commit of the directory that carries the compose, read from
.giton disk — no process, no polling), each Makefile target says when it last ran (migrate · 40 min ago · ✓), and every Docker command copies — service, logs, Make target — to continue in a terminal exactly where Mergerie stops. - Jenkins: the last 30 console lines of a red build inside "Details", a My runs filter (the list of jobs launched from Mergerie already existed for the end-of-run notification), and pinning a job to the top of a two-hundred-job list.
- Links: hovering a cell shows the full URL and when it was last opened; "Open this whole environment" in a column header; and the contextual buttons now also appear on a session's project line and on a Jira ticket — same
{env}/{branch}resolution as on a merge request. - Settings: each verifier shows its last verdict and how many merge requests to handle it covers; each review rule shows how many open merge requests it matches (locally, without the AI) — a rule that no longer matches anything stands out; each repository shows its open merge requests, the date of the last discovery and the state of its clone, with Re-clone.
- A todo tied to a merge request ticks itself when that merge request is merged, with a note saying what closed it. Nothing is deleted, and it can be reopened; a general setting turns it off. A session whose projects are all merged offers Put away.
- The last Jenkins build carrying a branch is written on it:
CI #40 ✗on the merge request card and on the session's project line, clickable through to Details. No new request — the list Jenkins already loads — and never confused with Mergerie's own verdict. - A ticket in review pushes its merge requests to the top of the queue, with a
ticket in reviewbadge; a ticket closed while its merge request is still open says so too. - A finding that comes back on three merge requests of the same repository offers Make it a rule, opening the review-rule form pre-filled —
path_matchderived from the files, the finding as the content. - "Tell Jira" on a session's project line: a comment carrying the merge request link plus the transition to review when Jira offers one, behind a confirmation that names the ticket. A checkbox in the session dialog, unchecked by default, does it at every merge request creation.
- A verification that runs in place says the state of the services of the compose project its working directory carries, at the moment of the click, with an Up button — instead of dying three seconds later on
ECONNREFUSED. - The branches of merged merge requests gather into one lot: a button fills Git → Actions with all of them, and the usual preview then says, branch by branch, whether it still exists and whether it is safe. The brief mentions it past ten.
- A Jenkins job links to a repository (Settings → Jenkins). A verified green merge request then offers Run <job> with its branch pre-filled — the job page opens, nothing is launched without the usual confirmation.
- An exploration turns into code: Turn into code opens the coding dialog on the same repositories, with the question and the answer as context, and the exploration's agent session in "resume an existing session" — the agent keeps what it has read instead of re-reading three repositories.
- A ticket's screenshots come with it: "Have the AI code this" proposes the Jira images as checkboxes (ticked by default up to three) and attaches the ones you keep, without a round trip through the Downloads folder.
- The starting branch, per repository, in the session dialog. The merge options (squash, delete the source branch), per repository. The projects ticked and the last command, per local directory, in Git → Commands and Git → Navigation. The containers ticked, per compose project, in Docker logs. Your last entry per Jenkins job — and, failing that, the parameters of the last build, instead of the job's bare defaults.
- The verifier form suggests the commands the repositories already declare —
package.jsonscripts,composer.jsonscripts, Makefile targets — read from the clone on disk, nothing executed. - "Add to todos" from a Jira ticket carries the ticket's due date and priority.
- Absolute dates carry their "3 hours ago" on hover, on session cards, merge requests and builds.
- A merge request card carries its size and its age:
- What you type in Settings is no longer wiped by a late load. Opening a Settings sub-tab fires a request for the current configuration, and its answer lands a few dozen milliseconds later — overwriting whatever you had started typing in the meantime, without a word. On a loaded machine the window widens: a token pasted right after opening the page could simply vanish. The form now ignores an answer that comes back after you started typing. This was found by a test that pasted Jenkins credentials and clicked “Test the connection” on three fields that had silently gone empty again — it failed about one CI run in two, and the message said only “timeout”.
- The demo can actually show all this. Every repository in the demo data points at a fictional forge, which is fine for screens that read the database but leaves anything that really clones — the Merge tab above all — unreachable in
npm run demo. The demo now ships a small real git repository with two branches editing the same line, so conflict resolution can be tried out on first contact; and one merge request is seeded in conflict, so the catch-up button is visible where it matters. In demo mode a repository that exists on disk serves its real branches rather than invented ones — offering a branch that does not exist would fail the moment it is picked.
- Asking to catch a branch up now confirms from the merge dialog too, as it already did from the project's line. Same history rewrite, same question: where you clicked should not change what you are committing to.
- Merge a branch into another, conflicts and all, without leaving the tool. A new
Git → Mergetab: pick a repository, a branch to merge, a branch to merge it into. The merge is prepared in a workspace of its own, so the shared clone is never left half-merged under a review or a coding session running alongside. Conflicts are resolved on screen, one conflict at a time: the destination's version and the incoming version shown one under the other,Keepon each,Keep bothunder them, and the side you keep highlighted so you can see where you stand without re-reading the buttons. You never see a<<<<<<<marker. When neither side fits,Write it myselfhands you the result of your choices in a plain text field and saves what you write. ThenCommit— with the message already filled in from what git itself wrote — andPush, each behind its own confirmation, in that order.Abandonrestores everything; until you push, the destination branch has not moved. When the two branches share no common ancestor, the tool explains what that means and offers to go ahead anyway, instead of passing on git's barefatal: refusing to merge unrelated histories.
- Pull the verification report into a follow-up too. When a verification breaks tests, the report's
Fix (AI session)button opens a brand-new coding session that rediscovers the code. From the session that produced the branch,Send a follow-upnow carriesUse the verification report, filling the field with the very same prompt — the broken tests, their messages, the commits that were tested — so the agent picks up its own thread instead. Both buttons build that prompt from one function, so the two can never drift apart. The button only appears when the latest verification is red and attributable to these branches: an already-red base is not yours to fix, and pointing the agent at it would send it into unrelated code.
- Catch a session's branch up with the branch it started from. A coding session opens its merge request, then
mainmoves on and the forge starts showing conflicts — until now the only way out was to leave the tool and rebase by hand. Each project line now grows anUpdate with mainbutton — only when the forge says the merge request is in conflict, so it is not sitting there inviting you to rebase for nothing — that replays the session's commits on top of an up-to-date starting branch: a rebase, somain's history is kept exactly as it is and your changes go back on top of it. When git stops on a conflict the AI resolves it, told to keep what the starting branch brings and reapply the branch's intent over it — that is what the button adds over plaingit rebase. It refuses to commit a file that still has conflict markers in it, and if the resolution does not converge it puts the branch back exactly as it was rather than leaving a half-done rebase behind. Nothing is pushed: rewriting a branch other people may have pulled is a second, deliberate gesture, so the existingPushbutton takes over — with--force-with-lease. The conflict flag is read from the forge (has_conflictson GitLab,mergeableon GitHub) during the discovery pass that already fetches those merge requests to see whether they were merged, so the button costs no extra API call. GitHub computesmergeablelazily and answersnullat first: while the answer is unknown the button stays hidden rather than guessing, and appears at the next discovery. The merge dialog asks the forge too, when it opens: a merge request in conflict now says so in red, naming the branch it clashes with, and carries the same catch-up button — you find out before clicking “Merge”, instead of in the refusal that would follow. For a merge request that did not come from a session the conflict is reported all the same, without the button: there is no session branch to replay. ThePushconfirmation also grows a “Force the push (--force-with-lease)” checkbox, unchecked by default — forcing rewrites a published branch, and that is yours to decide. It comes pre-checked only when the branch has just been caught up, because there we know a normal push will be refused. Ticked, it uses--force-with-lease --force-if-includes, never a bare--force: a teammate's commit that landed on the branch since the last fetch makes the push fail instead of disappearing, and the refusal now shows on the project's line rather than only at session level.
- Pull the review report straight into a follow-up. After a merge request is reviewed, the obvious next move is to have the AI work through the findings. Until now the only button for that —
Let the AI fix the code, on the report — opened a new coding session, which rediscovers the code from scratch. From the session that produced the branch you want a follow-up instead, so the agent picks up its own thread.Send a follow-upnow carries aUse the review reportbutton that fills the field with exactly the same prompt, report included. It only appears when there is a report to use, it asks before overwriting a draft you had already written, and it only fills the field — the text stays readable and editable, and you are still the one who sends it. On a multi-project session it pulls in every project's report, each one named, since the follow-up goes out to all of them.
- Re-review by itself when a report goes stale. After a review the branch keeps moving, and the report stops describing the code that is actually there — that is the
stalebadge. Settings → Merge Request → “Automatically re-review when the report goes stale” restarts the review at the next discovery, incrementally: the AI only reads what changed and gets the previous report as context, which is what makes this affordable on a branch that moves ten times a day. It is unchecked by default and independent of the arrival checkbox — arriving and moving are two different costs — and it gets its own share of the per-discovery cap, so a big push on merge requests you already know cannot eat the budget of the new ones. Merge requests that were never reviewed are left alone: no report, nothing to go stale.
- Review new merge requests on arrival, without asking. Settings → Merge Request → “Automatically review a merge request when it arrives” puts every newly discovered merge request into review by itself. It is unchecked by default, and it comes with a cap per discovery (5 by default) that applies even once ticked — because unlike the
Review the N MRsbutton, nobody is watching when discovery runs, and the first discovery of a fresh install brings in every open merge request you have. Merge requests beyond the cap keep theirReviewbutton and the server log says how many did not start, so a silent cap can never read as “everything was reviewed”.0means no limit. And “when it arrives” means exactly that: a branch moving forward on a merge request you already know triggers nothing — re-reviewing stays a deliberate gesture, and an incremental one.
- Hand the review back to its author: publish the report on the merge request. Until now a review report lived in Mergerie and nowhere else — to share it you copied it by hand. The report now carries a
Publish to GitLab/Publish to GitHubbutton that posts it as a comment on the merge request, exactly as it was written. It asks first, because what goes out is read by the whole team; and once it is out the button saysPublish againand carries the date of the first send, so you do not post the same text twice believing the first one failed. Settings → Merge Request has a matching “Automatically post the review report on the MR”, which does it at the end of every review. It is unchecked by default, and stays unchecked if the value is ever unreadable: writing on other people's work is a decision, not a default. A forge that refuses does not cost you the review — the report stays saved and the job log says why nothing was published.
Changed
- A design and usability pass over the whole application, following a screen-by-screen review. What changes, in the order you meet it:
- A fresh install opens where you can start. On a new installation the application opened the morning brief — which announces "nothing needs your attention" to someone who has not plugged anything in yet. It now opens on Reviews and its three-step assistant, and the brief takes its place back the next day, once the forge is connected.
- "Test the connection" tests what is on screen. It read the stored configuration: you typed the URL and the token, clicked, and were told "GitLab token not configured" by an application that had the value in front of it. It now sends the form values, as "Test GitHub" already did, and says what to do when something is missing.
- The assistant's steps tick themselves as you go: forge connected, repositories added, merge requests fetched. Three buttons become a progression.
- The job panel no longer pushes the page. It sat in the flow: everything moved down 78 px when it opened and back up when it closed, two jumps per job, while you read or aimed at a button. It now floats at the bottom of the screen.
- A merge request card holds one row of actions: See the diff · Context · Review ▾ · ⋯. The seven same-weight buttons are grouped in the "⋯" menu, and the action column becomes a rail again — the same button in the same place from one card to the next.
- The review report starts inside the first screen. Eleven buttons on three rows pushed it out of sight; three remain — Open the code · Have the AI fix it · Merge — plus the "⋯" menu, where "Delete the report" moved down, last and behind a separator: it wore the same red as "Merge", a centimetre away from it.
- A single filter idiom. Rule written and applied: chips when values are few and stable, a checkbox list with a search field beyond that. Docker's two "Show only" dropdowns become chips; the Reviews score brackets take the same shape.
- Two heading levels instead of five, and a single content width. Margins no longer jump from one tab to the next.
- Docker speaks French too.
running,exited,created,restartingwere shown as-is next to "non créé" and "arrêté". - Docker's and Jenkins's action rows no longer move: fixed order, unavailable actions disabled rather than absent — with a tooltip that says why. A disabled coloured button now wears the same grey as the others.
- The work-session clock carries an icon that names it, comes after the state badges and shrinks while it reads zero.
- The session dialog keeps its footer on screen ("Cancel" and the main button fell below the fold), its three per-project fields finally have a header row, and "Save" becomes "Create the session".
- A counter no longer shows before its data, the merge request queue shows a skeleton during its first load, and a statistics bar at zero no longer draws a coloured stub.
- When the server does not answer, the screen says so in plain words — "Mergerie is not answering — check that the server is running" — and offers "Retry" instead of showing "Failed to fetch".
- In the verification dialog,
!204leads back to its merge request instead of being dead text. - The palette no longer opens on eight Kibana URLs. With no query everything ranked the same, and the most numerous source — the grid links — took every slot: no merge request, no session, although both are found the moment you type a letter. On opening it now offers three short sections — Actions, Recent merge requests, Recent sessions — and every line carries its type. Dev sessions became searchable for the first time, by label, prompt or branch, and the result opens the right AI Dev sub-tab.
- Details: the navigation column's "to handle" badge finally says what it counts, a bulk confirmation asks its question in its title ("Review 11 merge requests?" rather than "Confirm the action"), Jenkins's "8 jobs out of 8" counter no longer breaks into four lines, its duplicated state badge was removed from the action row, and the two labels demo mode builds itself ("My repositories", "(demo)") finally follow the interface language.
- A second pass, on the forms. Twenty-two forms, a single validation model — and it was wrong everywhere. What changes:
- The session dialog starts with what you came to say. The prompt opens the form and takes the cursor; picking the projects, which held first place, comes below it; "Verify afterwards" and auto-push move above the attachments, because they change the outcome; and three fields you do not touch one time in ten (AI questions, commit message, resuming an agent session) are grouped under Advanced, which closes the form — expanded, but collapsible in one click. Attaching a file is a line again instead of an empty 80-pixel dashed box.
- One verb per effect, and the main path in one gesture. The same window said "Start coding", "Ask the question" and "Create and run" for one and the same gesture, depending on the session flavour — and two flavours out of four (coding, exploration) offered no run at all: you created, closed the window, found the card in AI Dev, clicked "Run". All four flavours now carry the same two buttons, which read against each other: "Create and run" (primary) creates then runs, "Create without running" creates and stops — preparing now and triggering later stays possible, and this is the only place that allows it.
- "Converge" leaves the dialog footer — two solid buttons side by side, one of them without a word of explanation. It is now a checkbox under "Verify afterwards" that announces what it promises: "…then converge up to 8/10 (3 passes max)", threshold and cap read from the settings. Converging a session already written stays on its card.
- A field error shows under the field — under the row when the field lives in a project line, where the message used to line up as one more column: it squeezed "Starting branch" from 285 to 157 px and pushed the project's "×" onto the next line. That is the rule, and it now applies to the four "test a connection" buttons, to the free link and to a session's branch name: a toast only announces the result of an action. And an error toast no longer settles in for good — it leaves after eight seconds, pauses while the mouse is on it, and dies with the dialog that produced it.
- Settings → Merge Request reads as three titled groups — Review, Automation, Convergence — instead of nine settings in a row. The automatic-review cap moved under its own checkbox, indented and greyed out while it is unchecked; the automatic verification cap moved to Settings → Verifiers, next to the switch that triggers them. The "Save" button carries an "unsaved changes" state that follows you from one sub-tab to the next — and switching sub-tabs no longer overwrites what you have just typed.
- The Git, Jira and Jenkins connections answer alike. The same empty guard in all four, required fields marked,
autocomplete="off"on the tokens, Enter saves (and says so — it used to do nothing), and the main button does the nominal path in one click: "Save and test". - The ⓘ icons leave the tab order. Six stops out of sixteen, in the session dialog alone, for the same icon. And the bubble opens only on the ⓘ — never on focusing a field, where it covered what you had just clicked.
- The verdict badge is a real button — it did not exist for the keyboard — and it says the door it opens: "✗ 1 broken test · see the report". The job banner offers "See the report" after a verification, instead of a "session" that does not exist. On the Jenkins side, "Open" becomes "Details": it stayed inside Mergerie, next to an icon that really does open Jenkins.
- Details: the Git tab with no tracked repository shows a guided empty state instead of a disabled field and a "loading…" that never ends, and "Verify a branch" moves down next to "Preview"; the Docker tab no longer shows a red badge before being opened once; the start assistant and bulk import put the cursor on their first field; the free link marks its required fields and gives an example of tags; the palette's footer recalls that ⌘K or
oreopens it; and in demo mode the session dialog preselects the only genuinely clonable repository, the others being marked "not runnable in demo mode" rather than dying on a Node stack at the first clone.
Fixed
- A local path is a valid repository URL again. The guard added on adding a repository only knew
http(s)andssh: it rejected/srv/repos/project.git, which is a perfectly ordinary clone source.
- Settings → Repositories: the add row is a row again. Its three labelled fields were laid out down the page, 780 px tall with 200 px of empty space between each, the button stranded at the bottom. The form carries two classes, and the one that says "column" is declared later in the stylesheet: at equal specificity the last one wins, so the row fell back to a column and each field's
flex-basis: 320pxwas read as a height. Settled by specificity now, not by ordering — the file can be reordered without breaking it.
- Reviewing a merge request finally shows on screen. This was the audit's number-one weakness and it was still whole: you clicked "Review", the banner said "finished", and the card stayed at the top of "to handle" with unchanged counters — the screen showing 10/7 while the server already answered 9/8, indefinitely. Detection relied on "a poll was running", so never for a job that finishes before the first loop turn: which is what a short review is. It now relies on the job id. Measured: the screen updates in 0.2 s instead of never. In the same pass, the banner's "See the report" link switches to the right stage — it used to open the report in a hidden panel — and server answers can no longer overwrite each other out of order: a stale request put the previous numbers back over the good ones, and the screen went from 3 back to 4 a second after telling the truth (seen on a two-core runner, not in theory). Same guard on the counters, the session list and the palette.
- Contrast holds WCAG AA everywhere, in both themes. The interface's most common pattern — a brand colour on a background tinted with that same colour — reads fine when large and failed when small: nineteen labels between 10 and 12 px were under the threshold in the light theme (Docker states, Jira statuses and labels, Jenkins parameters, the "pushed" and "waiting for answers" tags, the error banner). Semantic colours now have a variant tuned for text, per theme. A test measures it on every build: it walks the ten tabs in both themes, composes semi-transparent backgrounds and refuses any text under its threshold.
- A list that is loading says so, from the first paint. The fake "0"s were gone, but the column stayed a silent blank under latency — no way to tell "loading" from "there is nothing". The skeleton is now written in the page itself: posting it from JavaScript was not enough, since the request that triggers it only leaves after the configuration one. Measured under 5 s of latency, the list area held nothing at all at 400, 900, 1600, 2600 and 3600 ms; it now shows three grey cards throughout. And until the queue has answered, the screen no longer concludes anything about its content — the welcome screen used to take its place as soon as the configuration came back first.
- The interface language now applies to the server too. It lives in the browser; the server read the stored configuration. Switching the interface to English therefore left everything the server composes in French — "Mes dépôts (démo)" in the middle of a translated tab, and the error messages. The other way round, Docker filters kept "Arrêtés (exited)", "Unhealthy" and "En restarting" inside a French interface.
- The nine Statistics card titles join the single section level: the application's chrome now knows only two title treatments, everywhere.
- A session frozen on “running” after the server stopped can be started again. When Mergerie is stopped mid-run — a restart, a laptop closing — the job it was carrying is marked
interruptedon the next boot. The session it was running, however, stayed “running” forever, and the card only offersRun againonnew,error,committedorpushed: no button to restart it, and none to stop it either, since the job to stop no longer existed. The tool blocked itself by shutting down at the wrong moment. Sessions, off-repo tasks and verifications left mid-flight now come back aserrorwith the reason written on the card (“the server stopped while this was running”), which is a state you can start again from — and whatever had already been committed or pushed is left exactly as it was. The interrupted job itself is replayable too, and the Activity panel finally shows interrompu / interrupted instead of a raw status it had no translation for.
- Git → Actions: long branch names no longer run off the edge of the field. The branch picker shared its width evenly with the project picker, though a branch name is routinely twice as long as a project name. Past roughly forty characters the end of the name simply left the field — no ellipsis, no wrap, nothing saying anything was missing — so
hotfix/COMPTA-2210-correction-arrondi-echeancesandhotfix/COMPTA-2210-correction-arrondi-echeances-fractionneeslooked identical, and you could preview an operation on the wrong branch. The branch field now takes the larger share, the per-project name box moves to its own line instead of squeezing it, and on a narrow window the branch takes the full row.
1.3.0
Added
- Tell Mergerie you answered the AI's questions in your terminal. “Resume in terminal” hands you the agent session, so you can answer there — and the agent carries on inside Mergerie's clone, which knows nothing about it. The project stayed waiting forever, with a form offering to answer a second time, which would have sent the agent back over finished work. A second button on the questions form settles that wait without re-running anything. The resulting state is not guessed: on a repository session the branch is re-read (commits ahead → committed or pushed, with the diff; nothing → back to to do), and out of a repository — where there is no branch to question — the folder is returned to done.
- Attach files to a session, not just screenshots — in all four flavours. “Here is the client's quote, implement the discount rules”: a PDF, a spreadsheet or a
.txtsays in one file what a prompt takes twenty lines to describe. TheAttach a filebutton now takes images, PDFs, text, data files and Office documents (up to 10 MB each); anything else is refused with its reason, before anything is stored. Works at creation and in follow-ups, for coding, out-of-repo coding, exploration and the free question — the last of which had no attachments at all until now. To the agent a screenshot and a PDF are the same thing, a file to open, so both now travel through one mechanism: images show a thumbnail, documents a named chip, and the original file name goes into the prompt (pj_2.pdfteaches an agent nothing) while the file on disk carries a made-up name — a name coming from a form has no business in a path. What the agent can read is its own business: a.txtis safe, an.xlsxmuch less so; Mergerie provides the file, it does not convert it.
- A red badge on the Jenkins menu: what failed today. The blue count says how many jobs ran, which also goes up when everything is fine. The red one answers the question you actually ask walking past the tab — did something fall over this morning? — from any other tab. It counts failures only (unstable keeps its own colour and its own filter), today only (yesterday's failure sits at the top of the tab, where you go looking for it), and not while a job is re-running. Nothing broken, no badge.
- Arrange the menu bar: order and visibility. Nine tabs, and everyone uses a handful. Settings → General now lists them: drag or use the arrows to move what you open ten times a day to the top, untick what you never use. Applied at once, remembered in this browser like the theme. A hidden menu also leaves the command palette and the number shortcuts —
3opens the third shown menu — because offering a screen whose menu entry has gone is a one-way ticket; the feature itself stays, nothing is disabled. Settings cannot be hidden: it is the way back. What is stored is deliberately partial — the tabs you moved and the ones you hid — so a tab added in a future version appears on its own, in its original place, instead of being invisible to everyone who had touched their bar.
- Pin and name the iterations of an AI output. Past a few passes, “Iteration 7 · fix requested · 14/08” says nothing about what happened in it. Each iteration now carries a tag that lifts it to the top of the column — the number stays visible, so the chronology still reads — and a name you type in place, which shows in bold and joins the search. Neither goes to the AI: it is filing, written for the human scanning the column, exactly like a session's label. Iterations predating the pass history have no row to mark, and the screen says so instead of offering a gesture with no effect.
- Paste a screenshot into a note page. Ctrl+V in the editor inserts the image at the caret, on its own line, and the preview shows it immediately. The file goes to disk and the page keeps only a link — a base64 image inside the content would swell the row by megabytes, resent in full on every autosave, about once a second while you write. Only Mergerie's own image addresses are rendered, so an address typed into the text stays text: a note page never becomes a place where pasting a line calls a third-party server. Deleting the page removes its screenshots, files included. An exported
.mdkeeps the links, which resolve inside Mergerie only — stated in the guide.
- Paste a screenshot into a follow-up. “The button overflows, see the screenshot” — an image says in one glance what takes ten lines, and the moment you have it is the moment you write the follow-up. The follow-up form now takes images the way the creation form does: an
Add a screenshotbutton, or plain Ctrl+V in the field, with thumbnails you can remove. Works for coding, exploration and out-of-repo coding, each of which has its own route and its own table. A screenshot belongs to its request: the follow-up prompt carries the initial screenshots plus the new one, never those of an earlier follow-up, which illustrated something else. Saving a follow-up as a draft still keeps the text only — the screenshots stay on the open form and go out with the follow-up, and the screen says so instead of dropping them silently.
- Duplicate a session into a pre-filled form — coding, exploration and out-of-repo. Next to Edit, a button reopens the session's form with everything already there — prompt, label, commit message, repositories or folders, base branch, options, verifier — but with no identifier behind it, so saving creates a new session instead of overwriting the one you copied. What is deliberately not copied is stated on screen: the agent session is never resumed, since a copy starts a fresh conversation, and attached images stay with the original. In coding, the working branch is shifted (
feature/x→feature/x-2, avoiding branches other sessions already occupy) because two sessions on one branch would commit on top of each other; in exploration the branch is the one being read, so it is copied as is — shifting it would point at a branch that does not exist.
- Iterations of an AI output are a list, not a dropdown.
AI outputnow shows every iteration in a column on the left — number, kind, date and, above all, the request that produced it — and the one you pick on the right. A search field at the top of the column looks through those requests, because that is what you remember; iterations that do not match are hidden, not dropped, and the filter survives switching iterations. A single iteration shows no column at all: there is nothing to pick.
- Compare two repositories, side by side. A
Comparesub-tab in Git takes two repositories and one branch each, and answers the question agit diffcannot: these two repositories share no history — a service extracted into its own repository, a fork gone its own way — so what exists here and not there? Each side takes a branch or a tag (comparing two released versions means comparing two tags), and the two are never confused when they share a name. Three columns: left only, on both sides but different, right only, with a filter that searches all three at once. Files that are identical are counted, not listed, so the screen shows what is missing instead of drowning it in what is fine. Click any file to see its differences — both versions in a unified diff, with a file that exists on one side only read against the void, so you see exactly what the other side is missing. Both sides may point at the same repository on two branches. Very large comparisons are truncated, and say so.
- Ping people when a verification breaks — and only then. A verifier carries a
People to ping when it breaksfield (handles like@amady, or a group like@my-team, which ages better than a list of names), written into the comment wherever you put{mentions}in the template. The forge resolves the mention and sends the mail; Mergerie only writes it. Nothing is mentioned on a green verdict — pinging someone to say all is well is the surest way to end up in a mail filter. Two facts worth knowing: it must be the handle, not the numeric id (GitLab does not resolve@42), and you are never notified of your own mentions, since the comment is posted with your token.
- Automatic publication now waits for a green base. A verifier that publishes its verdict writes on the merge request only when the base run passed — “it passed before, your branch breaks it”, or “verified, and it holds”. If the base was already red, or if there is no base run at all, nothing is published: the verdict would say nothing about that branch, and writing it on its merge request would blame the author for what someone else broke. The server log says why it stayed quiet, because silence reads as “published”. Publishing by hand from the report is unaffected — there, a human decides with the text in front of them.
- Publish a verdict on the merge request, after reading it.
Publish as a commenton a verification report opens the body pre-filled with exactly what automatic publication would send, and lets you edit it before it goes out. A confirmation names the merge request; once published the screen says when and where, instead of offering the button again as if nothing had happened — that is what stops the same verdict being posted twice on someone's work. If publishing fails, the text you wrote stays on screen.
- The published comment has an editable template. Under
Publish the verdict as a comment, a template with fields replaced when it is sent:{verdict},{tests},{commits},{verificateur},{commandes},{date}and{heure}— so the comment carries the date and time it was published. Each field is explained on the spot, with what it actually produces (a field name teaches nothing: between{tests}and{commits}, nobody guesses which one carries the broken test names — and{commandes}, part of the default template, names the failing commands with their exit code, which{tests}cannot say when the output names the tests itself), and a collapsed “See an example comment” renders your own template on sample data — composed by the same engine as the real comment, so the preview cannot drift from what is sent. An unknown field stays visible rather than vanishing: a typo should show in the preview, not become a hole in the comment. Left empty, the default template is used, and it then benefits from later improvements a frozen copy would miss.
- A verifier can re-run when its verdict goes stale. A second checkbox: when a verified merge request receives new commits, the green given on the old commits is worth nothing. Separate from “run on every new merge request”, because it is a different appetite — on a branch that moves ten times a day, that is ten batteries.
- Verify a branch, with no merge request. Back from holiday, the question is no longer “what does this branch break?” but “is
developstill green?”.Verify a branchsits in the Git tab and on every verifier's card: one row per covered repository, each on its default branch, picked from a searchable selector, and the last branch used is remembered. Two things change meaning and are deduced from the absence of a merge request: the causal double run switches off (the branch IS the base), and nothing is “broken by this branch” — what is red is red. The result lands in the verification history and in the morning brief, as “repository · branch”.
- The cap on automatic verifications is a setting. Five per discovery round was a constant only the code knew; the right number depends on the machine and on how long the suites take. It now lives in Settings → Merge Request, and
0means “no limit”.
- A fourth kind of AI session: the free question. AI Dev gains a
Free questionsub-tab for everything you ask an AI outside any repository — a notion to dig into, two options to compare, a plan to challenge. Nothing on your machine is read or changed: no clone, no folder, none of your files. The point is what happens next: the answer is kept, an optional label files the study away, and a follow-up resumes the same agent session, so a subject can be worked through in five questions instead of one — each of them archived with the answer it got, and replayable from the iteration selector.Resume in terminalhands the thread back to you, and the answer exports to HTML, Word or PDF like any other. A free question reserves no repository: it never blocks a review or a coding session, and nothing blocks it.
Changed
- The session form now reads in the order things happen. Same form for all four flavours, but the optional label came before the required prompt, the Jira ticket that fills the prompt sat three fields above it, the “edits in place, no commit” warning waited at the very bottom — after the choice it qualifies — and commit/push/verifier were wedged between the request and the agent options. It now goes: where → what (Jira, prompt, attachments, label) → how the AI works (questions, resuming a session) → once the code is written (commit message, auto-push, verifier), the last two groups under a discreet caption. A free question shows the request alone.
Removed
- “Script” verifiers are gone; a verifier is a list of commands. Writing an executable that speaks a JSON contract was a lot of work for what three lines —
npm ci,npm test— already give, and that contract was the part of the tool nobody read until they needed it. Everything it fed still exists: the causal base/head double run, the named broken tests (read from TAP or a JUnit report), multi-repository coverage, batches,Fix (AI session). What is lost: a script could declare its own failed test names whatever its output looked like — a suite that prints neither TAP nor JUnit now yields a verdict from exit codes alone, and the report names the failing command instead of the failing test. A verifier of that family still on file is not deleted and not converted: it stays visible in Settings → Verifiers, markedfamily removed, and refuses to run — converting it into a single command would have kept it running while silently changing what its verdict meant. Rewrite it as a list of commands, then delete it.
Fixed
- A review always gets asked for its overall score, and a report without one no longer vanishes. The score is read back from the report, never computed — so a custom template that forgets to ask for one produced reports the score filter silently left out, and you could not tell them from merge requests that were never reviewed. The instruction is now added at run time, like the line numbers and the findings block, whatever the template says; if the AI still writes no score, the job log says so. And the filter gained a fourth box, “— no score”, with its own counter: those reports are now somewhere, instead of nowhere.
- The shipped review template no longer invokes a skill you do not have. It opened with “use the git-review skill”, which whoever installs Mergerie has no reason to own: the very first review asked the agent for something that does not exist — ignored at best, refused at worst, and nothing in the report said why. The default now assumes nothing about the machine; anyone with a skill writes it into the template, which is where the rest of the request already lives. An existing install still carrying the old template word for word is moved to the new one, in its own language; a template you have edited is left alone.
- Attachments are visible again when you reopen a session. Attach a quote to a coding session, reopen it to edit: the form only said “2 screenshots attached” — not which ones, with no way to open one, check you picked the right file, or drop one that had no business being there. The edit form now shows the attachments themselves — thumbnail for an image, name for a document — openable and removable, in all four flavours. An attachment that arrived with a follow-up is shown as such, since it does not belong to the instruction being edited.
- A button on a Jenkins row no longer opens the job's page on top of what you clicked. The whole row was clickable, so leaving for Jenkins opened the external tab and dropped the job page over it, and Run on a job without parameters made that page flash open and shut. The page now opens from the job's name — a real button, reachable from the keyboard — and the controls on the right do their own job and nothing else.
- Answering the AI's questions works on an out-of-repo session. The answers form is rendered in three places — a project line of a coding session, an exploration card, and a folder line of an out-of-repo session — but its button was only wired on the first list. On an out-of-repo session you could answer everything, click Answer and resume, and nothing happened: no resume, not even an error. The gesture is now bound once, at the document level, where the route already travels with the form.
- A second follow-up on the same project no longer forgets the first. Resuming an agent session does not always continue under the same identifier —
claude --resume <id>opens a new one, carrying the whole exchange plus the turn just made. Only the identifier from the initial run was kept, so every follow-up resumed the state of that run: two corrections in a row on one project of a multi-repository session ignored each other, and “Resume in terminal” opened the conversation as it was several follow-ups ago. The identifier the agent reports is now recorded after every pass — coding, exploration, out-of-repo, free question and convergence alike.
- Line numbers quoted by a review report now match the code on screen. The AI was handed a patch and nothing else: in a patch, line numbers live only in the
@@headers, so quoting “line 137” means counting by hand across every hunk — right most of the time, wrong sometimes, and one wrong number makes the reader doubt the whole report. It now also receives the same diff already numbered, each line carrying its real number in the final version of the file (blank for deleted lines, which no longer exist), and is told to read numbers there rather than recount them. Second cause, in the viewer itself: the full-screen view listed the file tree of the branch head while the file content and its line numbers came from the reviewed commit — so a commit pushed after the review made the two disagree. Everything now speaks the reviewed commit, with a fallback to the head if that commit is gone.
- An exploration's questions now reach the screen. When the AI hesitated during an exploration, its
<<<QUESTIONS>>>block was looked for on standard output only — while the exploration prompt tells the agent to write everything into the answer file and to duplicate nothing on standard output. The agent obeyed, the block went into the file, nobody read it: the exploration finished "normally" with the raw protocol block as its answer, and no form to answer it. Both places are now read, and the instruction no longer contradicts itself — the block is explicitly allowed in either. Dry-run simulates the realistic case (block in the file), so the path that actually broke is the one under test.
- The red Docker badge no longer counts containers you stopped yourself.
docker stop— and sodocker compose stop— sends SIGTERM and then SIGKILL once the grace period runs out, so a container that does not trap SIGTERM exits with 143 or 137 although nothing broke. Those two codes were read as crashes, which set the alarm off on every deliberate stop; an alarm that always rings stops being read. They now count as stopped, named in the tooltip and in the Exited filter, while the codes that really do mean a crash stay red — including a 137 caused by running out of memory, whichdocker inspectdistinguishes from a requested kill. The menu badge and the Exited with an error filter apply the same rule, so clicking the red count opens exactly the containers it counted.
1.2.0
Added
- A verifier can now start by itself on every new merge request. Tick
Run on every new merge request of the covered repositoriesand the battery runs at discovery, without a click — which is the whole point: verifying required noticing the merge request first. Only new merge requests trigger it, since a known one is seen again at every sync. At most five verifications per discovery round, because fifteen functional batteries would saturate the machine for an hour and block the queue shared with reviews; beyond that the merge requests keep theirVerifybutton and the server log says what did not start. Verifications of the same repository queue up instead of being refused — they never run together, but none is silently lost.
See the verifiers' resultson a merge request. The button opens the details of every verifier that ran on it: verdict, tested commits, broken tests, and the command-by-command breakdown with exit codes and output. It shows up as soon as a result exists, not only when something is red — "it is green, but what exactly ran?" is a fair question, especially now that a battery can start without you seeing it. A stale result says so, and each red block carries its ownFix (AI session)button, because a single button at the bottom would not say which report it fixes.
- “The AI may ask me questions” now covers out-of-repo coding and exploration. The option only existed for coding inside a repository, yet an exploration hesitates the same way — and out of a repository it matters most, since the agent works in place, with no branch and no commit to re-read. In all three flavours the session now goes into waiting, shows its questions on its card, and resumes in the same agent session once answered. An exploration asks once for all its repositories, which share one session; out of a repository each folder has its own questions, and answering one does not make the others work again. While a question stands nothing has been done: no summary is saved, no file is touched. The todo raised for an out-of-repo session carries its own kind, so it cannot be confused with — or closed by — a repository session that happens to have the same number.
- A verifier can be duplicated. Covering ten repositories with the same command save one detail meant retyping everything — or worse, editing the existing one while believing you were creating another.
Duplicatereopens the form filled with the original's commands, timeout, options and covered repositories, but without its id: saving creates a new verifier instead of overwriting the one you started from. The name cannot be copied as-is — they are unique, and the save would fail after you had adjusted everything — so "X (copy)" is proposed, then "(copy 2)", with the field selected because renaming is the first thing you do.
- Standing instructions, added to every coding session. Settings → AI sessions holds a free text field appended to the prompt of every coding session — in a repository and out of one, on the first run as on every follow-up. It is what you repeat every time: the language of comments, a command to run before committing, something not to do; copying it into each prompt works right up to the day you forget, and that is always the one you re-read three hours later. It comes after the task and before the questions block, it is re-read on every prompt so a change applies to the very next session, and an empty field adds nothing — not even an orphan heading. Exploration is left out: it produces no code.
- A session stopped on a question raises its own todo, and answering closes it. When the AI interrupts itself to ask something, the queue is free, nothing will restart, and the desktop notification was dismissed long ago — so a high-priority todo is created, naming the session and the projects concerned, and it sits in Notes and in the morning brief until you answer. On a multi-repository session it only closes once no project is waiting any more. It stays an ordinary todo: the tool raises it and closes it, it does not take over what you did with it.
- The morning brief counts the sessions waiting for a gesture. How many were never run, how many are committed but not pushed, how many are pushed without a merge request — the work is done, only a click is missing. Numbers rather than lists, and a branch that already has an open merge request is not counted.
- The Jenkins menu carries a badge: how many jobs ran today. The question you ask walking past the tab is "did anything move this morning?", not "how many jobs exist". It is filled once at startup, like the Docker badge, then kept current by the tab's own refresh — Jenkins is not polled from the other tabs. Nothing ran today means no badge at all: a zero in a menu teaches nothing. A job that ran five times counts once, since the list only carries each job's last build; the tooltip says "jobs", not "runs".
- Jenkins parameters that recur across jobs carry a colour, and can be filtered. On a team installation the same three or four parameters come back from one job to the next; shown in each job's own order, the eye has to hunt for them on every line. From three jobs on, a parameter gets a tint derived from its name — so it never shifts as jobs come and go — and a dropdown above the list to filter on its values. A filter you do not need can be put away with a cross, its value cleared with it, and it comes back from the same window as hidden folders. Three rather than two: at two, a coincidence between two jobs would colour it for everyone.
- The todo list can be arranged by hand, inside each priority. Priority still comes first — it answers "what is pressing" — and your own order arranges what sits inside it: drag a row by its grip, or use the two arrows on each row, since dragging is neither announceable nor reliable with a keyboard or a finger. Reordering never crosses a priority boundary: the todo would spring back, and a gesture that does not land is worse than no gesture; changing group means changing the priority, which is an explicit gesture of its own. The order is saved, a new todo lands at the top of its group where you just typed it, and the due date keeps feeding the morning brief and the reminders. Existing lists keep the exact order they had, and done and archived todos keep their chronological order — you do not arrange your drawer.
- Inline comments can now wait. Next to "Comment on GitLab", which still publishes right away, a
Savebutton keeps the remark pending and local: you review a merge request file by file, and sending one at a time showers the author with notifications while freezing remarks you would have dropped three files later. Pending comments show under their line in amber, can be edited and deleted, and a header button sends them all at once — asking first, and saying how many are about to be published. Whatever fails stays pending with its reason, so a network error on the third comment does not take the first two with it, and positions are resolved at send time so a merge request that moved meanwhile is not annotated on code that no longer exists.
- A job's history shows what each run went out with, in the same colours as the list. Two green lines from the same afternoon are told apart by their parameters, and nothing else: reading them meant clicking each run in turn. Every line now carries its parameters as name/value pills under it, tinted from the parameter's name — so
ENVhas the same colour in a job's history as it has in the job list, and the eye follows a column down without reading. In a history every parameter comes back on every line, so they are all tinted.
- Find the run you are thinking of, then start from its values. "When did this last go to production, and with which version?" is the question you ask in front of a deployment job's history. Each parameter the history carries gets a filter above it, and a
Reusebutton on every matching run fills the launch form with that run's values — without sending anything, because the reason to start from an old run is usually to change one thing. The filters suggest the values they have seen rather than restricting you to them: the values on screen are only those of the runs loaded, and a value that does not appear is still perfectly valid, so it can be typed. And filtering does not stop at the ten runs shown: the first time you filter, the job's history is fetched deeper, once, so a run from six weeks ago is found instead of answering "no matching run" about something that did happen. A value that no longer exists among the job's choices is added back and flagged rather than silently dropped — a field quietly left on something else would launch with a value nobody chose.
Run againon a Jenkins job, with the same parameters. In the list it reuses the last run's values; in the job's page every run in the history has its own button and reuses that run's values — what you want after reading the console of a failed build. The confirmation shows the values about to be sent, because "run again" says nothing if you cannot see with what, and it counts the secret parameters that cannot be sent back: Jenkins will fall back to their defaults rather than the job going out silently amputated.
- Jenkins parameters whose values are computed now come through. Git Parameter (a repo's branches and tags), Extended Choice, Active Choices: these plugins do not declare their options, they compute them while rendering their own page, so no API request will ever return them. Mergerie now reads Jenkins' build form for the parameters the API said nothing about — what the API declares still wins — and a multiple choice stays multiple, sent comma-separated as those plugins expect. When the page cannot answer either, the field stays empty and says so, as before.
- The Jenkins tab refreshes itself, tells you when your own job is done, and opens each run side by side. The list refreshes every 30 seconds — only while the tab is open and the window visible, with a checkbox to turn it off and the choice remembered — and a background refresh never blinks the list nor wipes it when the network hiccups. A desktop notification fires when a job you started from Mergerie finishes, with its verdict; the team's nightly builds stay silent, because being told about those is how you end up turning notifications off. A job's page is now two columns: the run history on the left, each run keeping its Console button, and on the right the run you select — when, how long, by whom, on which branch, and with which parameters and values. Every line, and every run, carries a link that opens it in Jenkins in a new tab.
- The Jenkins list shows the parameters the last run went out with. Up to three per line, the rest counted and spelled out in the tooltip. They cost nothing: they already came with the list, in the same request. Password parameters are left out — Jenkins returns an encrypted form and a secret does not belong in a list — and so are empty values.
- Jenkins folders you never use can be put away. A cross on a folder's checkbox takes it out of the filter list — unticking says "not now", hiding says "not my subject" — and its jobs go with it, since a job you cannot filter has no business being in the list. The hidden ones stay listed in small type underneath, and one click brings back the one you want; their ticked state is kept meanwhile. Remembered across sessions, like the rest of the filter.
- The Jenkins list now reads by freshness, and says who ran what. Jobs are sorted from the latest run to the oldest — in a list of three hundred, what just ran is what you came for — with the never-run ones at the end. Each line carries the date of the last build, its number, who started it (or what did: the scheduler, a push, an upstream job) and the branch or tag that was built. Folders moved to the top as a filter: one checkbox each with its job count, its own search, and the choice is remembered. It stores the folders you unticked, so a folder your team creates tomorrow shows up on its own.
- Jenkins behind a corporate certificate. An internal server is almost always served by a certificate a freshly installed Node does not know, and Node's own message — unable to get local issuer certificate — names neither the cause nor the cure.
JENKINS_CA_CERTpins your internal CA (the clean way) andJENKINS_INSECURE_TLS=1skips the check while troubleshooting, for Jenkins only, exactly like the GitLab and GitHub settings. The error now names both variables, and so does the Settings → Jenkins page.
- A Jenkins tab: see where your jobs stand, and run them. Every job your account can see, grouped by folder, with a search (a company installation lines up hundreds) and a filter for what is failing, unstable or running. A job's page shows its parameters and its last ten builds, and each build's console opens in one click, scrolled to where the error is. Running always asks first and names the job — it deploys on a shared machine and cannot be cancelled from here — and a parameterised job opens its page instead of starting, so the values you are about to send are values you have seen. Nothing is polled: the screen asks when you open the tab or hit Refresh. The connection (URL, user, API token) lives in a new Settings → Jenkins tab, with a test that returns the account name the server sees.
- A brief line can be dismissed for good. The morning brief recomputes everything each time it opens, so a fact that stays true comes back every day — a failed verification you have already been through reappears indefinitely and eventually teaches you to skip the section. A cross on hover dismisses the line: verifications, waiting sessions and merge requests. It dismisses the finding, not the subject — a new verification of the same set reappears, because a real regression must never stay invisible. Nothing is deleted, the brief says how many lines it hides, and one button shows them all again. A dismissed line makes the next one move up, so a section never shrinks below what is really left to do.
- Running a session again now asks first.
Run againsends the initial prompt once more: the agent starts from the beginning, on top of work already produced, and anything asked since — follow-ups, answers to questions — is not replayed. The button sits next to the ones you use all the time, and one click too many costs a whole session. The confirmation says what is about to happen rather than just "are you sure?", and the very first run stays a single click.
- A follow-up can be written while a session is running, and sent when you decide — or by itself. The remark comes while you read what the agent is doing, not twenty minutes later — so you write it there and then, and it waits on the card. You can reword it as long as it has not gone out, delete it, and send it in one click once the session is over. A checkbox,
Send it automatically when the session finishes, arms it instead: the card then reads Follow-up armed and the session chains the follow-up on its own. Unticked — the default — nothing sends it for you. Armed or not, it goes out once: the text is consumed before launching, so a session cannot loop on its own follow-up, and nothing goes out after a failure or while the agent is waiting for an answer. A verifier chosen for the session waits for the automatic follow-up before rendering its verdict. Applies to coding, out-of-repo and exploration sessions.
- A session can carry a short label. Coding, out-of-repo and exploration sessions take an optional title at creation: a list is otherwise read through its prompt, three folded lines whose first words look alike from one session to the next. The label says what a session is about where the prompt says what to do; it heads the card, joins the search, and can be changed later. It is never sent to the AI and never used as a commit message — it is a filing title, and a test keeps that door shut. Out-of-repo sessions have their own form wiring, so a browser test covers all three families rather than one.
- A coding session can carry a verifier, and runs it by itself when it is done. Picking one in the session form makes it run once at the end — after convergence if you converge, after the coding run otherwise — so you launch in the morning and find a verdict rather than one more box to tick. Only verifiers covering every repository of the session are offered. A verifier reads what the forge exposes, so it needs pushed code: picking one ticks auto-push and says why, and unticking auto-push drops the verifier — the server applies the same rule, not just the screen. Nothing pushed, coverage lost or another verification already running are refusals written in the session's log; none of them fails the session, whose code is written either way.
- A Links tab — the work links your bookmarks cannot structure. The same service exists in local, dev, staging and production; a folder tree scatters it across four places. A grid shows it at once — services as rows, environments as columns, one URL per cell. That URL is written out, never guessed from another by swapping a piece of domain: that kind of magic eventually sends you to the wrong environment without a word. An empty cell takes the address in place, no dialog. Whatever has no environment dimension — Confluence, a doc, a tool — stays a free link, found by tag.
- A global palette on
Ctrl/Cmd+Kor theokey, and a search field in the header so it can be found without knowing the shortcut. It searches everything at once: grid cells, free links, merge requests, watched tickets, note pages, open todos and navigation actions. Fuzzy by subsequence (kib prefinds “Kibana · preprod”) and ranked by frecency — what you open often and recently. - Contextual buttons on merge requests when a service is linked to a repository: its grid URLs, plus templates with
{env},{branch},{mr_iid}and{service}resolved on click. Unknown variables are refused as you type them, every substituted value is URL-encoded, and a variable with no value here leaves the button greyed with its reason rather than a URL with holes. - Chrome bookmarks import, preview first: the folder tree as it was, each link tickable, tagged by its folder path. Replayable — re-importing the same file does not duplicate what is already there. The file is parsed, never executed.
- A global palette on
- The navigation moved into a left sidebar. At nine entries a horizontal bar was out of room — “AI Dev” already wrapped onto two lines. Vertically each entry gets its own row, its badges fit, and the tenth costs nothing. The bar collapses to icons from a button at the foot of the column, remembers the choice, and collapses on its own below 1100 px. The header space this freed now carries the palette's search field, which had the opposite problem: being invisible unless you knew the shortcut. The README's animation was re-recorded on the new shell, and the settings that turn the recording into that GIF now live in
scripts/demo-gif.sh(npm run demo:gif) instead of having to be worked out again each time.
- Back up your data in one click. Settings → General now produces a dated
.zipholding the database and every file it points at — reports, agent answers, context screenshots — plus a short note on how to restore it. The database is copied through SQLite's own backup API rather than a plain file copy, which would silently produce a corrupt file if a write happened mid-copy. Clones and worktrees are left out on purpose: agit clonebrings them back, and including them would multiply the archive size for nothing. Until now the months of accumulated work — reports, verdicts, resolution tracking — lived in a single folder that no command could export.
- History no longer grows forever. Job logs, finished jobs and the activity feed are now trimmed past a configurable age (Settings → General, 90 days by default,
0to keep everything). The cleanup runs at startup then once a day, never touches a job that is still running, and leaves two things alone on purpose: token costs, whose running total must not drop by itself, and agent iterations, which already disappear with their session.
- An orange badge on Reviews counts the weak reports still waiting. Next to the blue “to review” count, it shows how many reports scored under 7/10 have not been dealt with yet — which ones to read first, rather than how many exist. It only counts the Reviewed stage, so marking a merge request as processed brings it down: a counter that never goes down stops being looked at.
- See which projects are alive over the last six months. A new chart in Statistics: one bar per tracked repository — a horizontal bar, longest first, with the name spelled out on the left. The chart has a fixed height and scrolls, so twenty repositories fit without pushing the rest of the page down and without a single name being cut off. The length is the number of active days, not commits: a working day means the same thing everywhere, whereas a commit count mostly measures whether you squash — the same work lands as one commit in one repository and forty in the next. Being bounded (about twenty working days a month), it also compares honestly across repositories. Commits and contributors are one hover away. Each bar is stacked by month, one colour per month with a legend underneath, oldest on the left to most recent on the right, so you can point at a month instead of counting segments. Clicking a project's name opens it over twelve months: six months say which repositories move, twelve say in which direction — quiet for two months after ten busy ones is not the same story as dead for a year, and the overview cannot tell them apart. The window also names the busiest month and the last month with any activity. Bot commits (Dependabot, Renovate, GitHub Actions) are left out: a repository nobody maintains but a robot updates weekly would otherwise never be flagged as asleep. Repositories are queried four at a time, so a first load over twenty of them takes seconds rather than a minute. A repository with nothing in the last two months turns grey and is labelled asleep: still on screen, since that is exactly what you came to see, but not to be mistaken for a merely quiet one. Hovering a bar gives the month-by-month breakdown and the number of distinct contributors. Counts are cached per month, so a closed month is never paid for twice.
- Export an AI answer as HTML, Word or PDF. An agent's answer often has to be read outside Mergerie — pasted into a ticket, attached to a report, sent to somebody who does not run the tool. The full-screen view now has an Export button. The HTML is a standalone document: styles embedded, nothing loaded from the network, so it reads offline and travels as one file. The
.docxis a real Word document — headings, lists, tables, code blocks — built without installing anything. PDF goes through your browser's own print dialog (“Save as PDF”), which lays the page out better than a rendering engine we would have to ship. All three carry the title and the date inside the document, since a file loses its name long before it loses its content.
- Read a watched Jira ticket without leaving Mergerie. Picking a ticket in the “Watched” list now opens it on the right, exactly as under “My tickets”: description, metadata, comments, attachments, and the same actions — change status, comment, “Let the AI code it”. It is the same panel rather than a copy, so the two can never drift apart. Each sub-tab keeps its own selection, and the card's own controls (unwatch, edit the reason) still do only what they say.
- Say why you are watching a Jira ticket. An optional note next to the key — “blocks the billing migration”, “tell Sofia as soon as it is in review”. Three months later a key and a summary no longer recall the reason. It shows under the ticket title and can be edited from its line at any time: going through unwatch-then-rewatch would lose the date you added it and the last state Mergerie knows, and would fire a false notification on the next check. Clearing it is fine too — a stale reminder helps nobody.
- Filter reviewed merge requests by score colour. Three checkboxes sit above the list, under “Reviewed” and “Processed”: green (7/10 and above), amber (4 to 6.9), red (below 4). They combine, so “show me the red and amber ones” is one click each, and each carries the number of merge requests it will bring up. The choice is remembered between visits, unticking the last box brings everything back rather than leaving you with an empty list and no way out, and the summary on the right follows the filter instead of describing merge requests you can no longer see.
- Ask for a fix on one repository of a multi-repo coding session. Each project line now has its own “Request a fix” button, next to “Run”. A remark is nearly always about one repository — “use AbortController here” means nothing in the other four — yet the only way to say it was to send it to the whole session: one AI call per repository, to redo work that was already good, and the agent walking back over code you did not want touched. The session-wide button is unchanged, and the per-project one only shows up from two projects on. An exploration still answers as a whole, so it cannot be narrowed that way.
- “AI's answer” on an out-of-repo session, not just on each folder. Looking at the card, the question is “what did the AI do?”, not “what did it do in that one folder” — and since the folder list now starts folded, the per-folder buttons were a click away. When a session covers several folders the full-screen view gains a folder selector, so you move from one answer to the next without closing it.
- Sessions with several projects now fold away. Exploration and out-of-repo coding gained the collapse that coding already had, and all three start folded: past a few repositories a single session filled the screen and hid the others, which are exactly what you came to look at. The state is remembered per session, so it survives the automatic refresh that redraws the list every second and a half.
- Objective verification of a merge request. A review says what it thinks of the code; a verifier says what happens when you run it. A verifier is your own script: Mergerie hands it repositories already positioned on the right commits and reads its verdict —
✓ verified,✗ N tests broken,⚠ base already red,⟳ out of date. It runs without a shell, with an environment that carries no token, and its answer is validated against a fixed contract: an unreadable output never becomes a green. Mergerie runs the same suite on the base first, so a test broken by somebody else is never blamed on your branch — that distinction is the whole point of the verdict. - A verifier can be just a list of commands. Writing an executable that speaks a JSON contract is a lot to ask when all you want is “run
npm cithennpm testin this repository”. So a verifier can now be a plain ordered list of commands: the verdict comes from the exit codes, the first failing command stops the rest, and the report shows what each one did. Commands run without a shell —&&, pipes, redirections and$VARare refused at save time, with the reason, rather than becoming baffling arguments ten minutes into a run. One repository per verifier of this kind, because a list of commands runs in one directory, not several. - One command list, several repositories. Projects that test themselves the same way no longer need one identical verifier each: a “commands” verifier can cover as many repositories as you like, and the list is replayed in each one, with the verdict being the AND. The order of the commands carries meaning, so each line shows its rank and can be moved up or down without retyping anything. Inside a repository the first failing command stops the rest, since they depend on it; from one repository to the next it carries on, because they do not — knowing that two are broken beats stopping at the first. Failures are prefixed with the repository, without which two projects owning a test of the same name would be indistinguishable.
- Broken test names are recovered without guessing. A verdict is far more useful when it says which test broke — that name is what makes the base/head comparison causal. Mergerie looks for it in a JUnit report if you declare one (pytest, jest, PHPUnit, Surefire, go-junit-report all write it), then in the TAP many runners emit as soon as their output is not a terminal — recognised with nothing to declare, sub-tests not double-counted,
# TODOand# SKIPhonoured, and the plan line used to notice a truncated output instead of presenting a partial list as complete. When neither is there, the command itself is what is reported: no invented test count, and a command already red on the base still yields “base already red”. The report then also isolates what is new compared to the base — the lines that appear on the branch and not before, which usually points straight at the regression even behind an opaquemake test. - Two verifications can run at once when nothing ties them together. Refusing every second verification outright sent you back to your screen while every other job in Mergerie simply waits its turn. What is refused now follows what the runs actually do: a multi-repository verification is an integration run — it brings up a whole environment, so it blocks everything and is blocked by everything — whereas a single-repository one is contained in its directory and only has to avoid the same repository. The refusal says which of the two reasons applies, since they are not fixed the same way.
- Pick the working directory instead of typing it. In “in place” mode, a selector now lists the git projects of every local directory you have declared — with type-ahead search, since one root commonly holds dozens — and fills in the absolute path. Typing a path by hand still works for a directory outside any declared root, but a typo there is only discovered on the first run, and costs that run.
- A confirmation before running anything. Clicking “Verify” now opens a dialog that says what is about to happen — which commands or which script, which repository, which mode, which time limit — and lets you pick between the verifiers that cover it. It appears even when only one does: running commands on your machine deserves a screen, not a silent click.
- Verify a merge request that has already been reviewed. The button now sits on reviewed merge requests too, in the list and in the report panel. A review is an opinion, a verdict is a fact; the second keeps all its value once the first is in.
- The contract is written on the screen where you configure it. Settings → Verifiers unfolds the full format: which file is expected (any executable — the extension is irrelevant, but the executable bit and a shebang are not, and the Command field takes a path, never a command line with arguments), the JSON Mergerie sends on stdin, the JSON it expects back, the limits, and two complete example scripts in shell and in Python. Sending someone to the guide to find the exact field names would mean changing screen at the exact moment they are writing the script.
- Verify merge requests together, as a batch. Some merge requests only hold together as a set: the front one and the API one that pass only when combined. Tick them in Reviews and verify them in one run — the verdict then applies to all of them. Name the selection and it becomes a batch, re-verifiable with one button. Two merge requests from the same repository are refused: nobody could say which code was tested.
- “Fix (AI session)” on a red verdict. One coding session covering every repository of the batch — not only the one where the test broke, because the cause of an integration failure is often elsewhere. The prompt carries the facts (broken tests, messages, log excerpts, the exact commits tested) and the work happens on the merge requests' existing branches, so pushing updates them in place.
- Two ways to run a verifier, repository by repository. A throwaway worktree created and removed by Mergerie, or in place in your own working directory when the test environment cannot be recreated (local database, warm containers, installed dependencies). In place asks for explicit consent, checks the directory really is that repository, and refuses outright if it has uncommitted changes — never an automatic stash. Your directory is put back on its original ref in every case, including on timeout; if that fails, the report says so in a banner instead of burying it in a log.
- Filter Jira tickets by sprint. A Sprints chip appears as soon as your tickets carry one. Sprint is a custom field whose identifier differs from one Jira to the next, so it is found by its Jira schema marker rather than its name — a field labelled "Itération" is recognised just the same. The selection is applied by Jira itself (
sprint IN (…)), like projects, so it narrows the search instead of sifting a capped extract. Sprints already seen stay on offer after you pick one, otherwise you could never tick a second. The active sprint sits at the top and is marked as such — it is the one you want nine times out of ten, and a date alone does not tell it apart from an upcoming one; the rest follow by sprint date, most recent first.
- Watch Jira tickets and be told when they move. Some tickets matter to you without being yours — the one blocking your work, held by someone else. Checking them by hand three times a day is the kind of thing a tool should do. The Jira tab now has two sub-tabs: My tickets, and Watched. Add a ticket by its key, or from the Watch button on any ticket's detail; a background check (every N minutes, set in Settings → Jira,
0disables it) compares each watched ticket's status and raises a desktop notification giving the old and the new one — To do → In Progress — with a click that takes you back to the list. The current status is recorded when you add the ticket, so the first check cannot announce a change that never happened, and a ticket that disappears or becomes invisible is flagged on its own row without interrupting the others or losing its last known status. A change is announced once: checks are serialised, so the timer and the "Check now" button cannot both report the same move, and the new status becomes the reference until it moves again. - The Jira status filter now has a search box, like the assignee one. With a workflow carrying a dozen states, finding the one you wanted meant scanning the list. Searching hides rows without unticking anything, so a selection is never lost by filtering.
- Check all / uncheck all on the Jira assignee and status filters. With a dozen lines, clearing everything to keep one or two meant a dozen clicks. Both buttons ship together: uncheck-all on its own would be a one-way trip.
- Ticking nobody in the Jira assignee filter now means "everyone". An empty selection quietly fell back to
assignee = currentUser(), so unticking every person handed you your own tickets — the opposite of what you asked for. It now applies no assignee constraint at all: every ticket the account can see, including those assigned to someone else or to nobody. The default, before you touch anything, is still your own tickets. - The Jira filters now sit on one line above the ticket detail. Assignees, statuses and the field filter stacked three rows deep inside the narrow ticket column, pushing the list down before you had filtered anything, and squeezing their own labels. They are now chips on a single row spanning the full width above the detail panel, where there is room. The one you open floats over the page instead of shoving it, so neither the row nor the list ever moves; clicking outside closes it.
- A generic field filter in the Jira tab. Pick the field first — epic, type, priority, project, assignee, reporter, labels, components, fix versions — then one or more values, offered from what the loaded tickets actually contain, each with its ticket count. Both the field picker and every value list have their own search box; searching a value list hides rows without unticking anything, so a selection is never lost by filtering. Criteria combine as AND between fields and OR within a field, and a criterion with nothing ticked filters nothing — adding a field never empties the list on you. Your criteria are remembered.
- Jira tickets now show their epic, and it opens Jira. The list carries the epic key and title above each ticket's summary, the detail carries it among the metadata, and the search box matches on it — asking for "everything under that epic" is a routine need. In the detail panel the epic is a link that opens it in Jira in a new tab; in the list it stays plain information, since the whole card is the button that selects the ticket. The epic is read from Jira's
parentfield, keeping only parents that really are epics: a sub-task's parent is a story, and calling that an epic would be wrong. Localised type names (Epic, Épique, Épopée) are handled. - The Jira menu now carries a badge: your in-progress tickets. "In progress" means Jira's In Progress status category, the only definition that survives across workflows, since status names are free-form per project. The count is cached server-side and refreshed by the watch timer, so showing it never costs a Jira call — and a status you change from inside the tool updates it at once, without waiting for the next check.
- Stop fetching merge requests from a repository, without disabling it. Some repositories are needed for git operations and coding sessions, but their merge requests are none of your business — and they kept filling the review queue. Settings → Repositories now carries a fetch MRs checkbox per repository, ticked by default. Unticked, "Fetch new MRs" skips that repository entirely; everything else about it keeps working. Unticking does not purge: merge requests already fetched, and their reports, stay where they are — you stop bringing in new ones, you do not lose the old ones. This is deliberately separate from enabled, which removes the repository from everywhere at once.
- Asking the AI to fix a review now offers to resume the session that wrote the code. The coding session behind a branch is looked up and its identifier pre-filled, so the agent picks up its own work instead of rediscovering a codebase it just wrote. It is a suggestion, not a rule: the link is inferred from the repository and the branch, which is not proof — a branch can have been taken over by hand — so the field stays editable, and clearing it starts a fresh session as before. Nothing is proposed when no coding session matches.
- Activity — what you launched, and what finished while you were away. Launch a few reviews and coding sessions, come back later, and finding out what is done meant opening every tab and reading every card. The log panel gained an Activity view: what ran, on what, how long it took, how it ended, with the date and time it finished — each line naming its object and leading to it in one click, with the log of any past job one more click away. What finished since your last visit is marked, and the count sits on the button so the information comes to you. Both the activity view and the queue are height-capped and scroll on their own, so opening them never pushes the log itself off the screen. Desktop notifications did not answer this: they live only in the server's memory and are deliberately not replayed on load, so anything that finished with the tab closed existed nowhere.
- Multi-repo sessions: fold the project list, push everything, open every MR. A session on several repositories can now collapse its list of projects — past a few repositories one session filled the screen and hid the others — and the folded state is remembered, so an automatic refresh does not reopen it under you. Two grouped actions appear when they have something to do: Push all, which pushes every committed-but-not-pushed branch in one job, and Create all MRs, which opens a merge request for each pushed project that has none. The bulk MR dialog asks for the options once — squash, delete source branch — and gives each merge request the session's commit message as its title, rather than asking for ten titles in a row. In both cases a project that fails does not stop the others, and the summary names the ones that did.
- Run one project of a multi-repo session on its own. Each project of a coding session now has its own Run button, and a session with several failures offers Re-run failed projects. Until now a session could only be re-run whole: on ten repositories where six had succeeded, that meant six AI calls to redo good work — and the agent going back over code you did not want touched again. A targeted pass also only reserves the repositories it touches, so two projects of the same session, on different repositories, can run side by side. Re-running everything is still one click away; nothing became implicit.
- Check branch state — repair a session without spending an AI call. When projects are stuck in error although their work is already committed, a button on the session re-reads the real state of each branch: if it carries commits its diff is regenerated and the project goes back to commit ready (or pushed), with the Create MR button back. Nothing is glossed over — a branch that really is empty stays in error, with its message. Re-running the session would fix the same thing, but at the cost of one AI call per repository, to redo work that is already done. The button only appears when at least one project is in error.
- Notes, todos, reminders — and a morning brief. A new Notes tab replaces the sticky notes and the notepad tab of everyday work, with one difference that is the whole point: it lives inside Mergerie, so a note can point at what you actually track, and it travels in the backup.
- Today opens the day: reminders due, today's todos, sessions where the AI is waiting for an answer, failed verifications, merge requests that arrived since yesterday, and those reviewed days ago but still open. Action-first, each section hidden when empty, every line clickable. It is computed entirely from the local database — no AI call, no token, no network — so it appears instantly. On the first opening of the day the app lands here rather than on the tab you left; once a day, and switchable off in Settings → General.
- Todos with high/normal/low priority and an optional due date that doubles as a desktop reminder, snoozable by +1 h or tomorrow 9 am. Ticking one keeps it, struck through, for seven days, then files it under Archived — nothing is ever deleted behind your back.
- Pages of free-form notes in Markdown, with live preview, autosave, pinning, search over title and content, and export to
.md. nfrom anywhere opens a one-field capture: type, Enter, done — no navigation, because you were in the middle of something else.!214andPROJ-720become links wherever you write them. If a number exists on several repositories the link goes to a pre-filled search rather than guessing one; if it exists nowhere it stays plain text rather than becoming a dead link.- A merge request or a Jira ticket can be added to the todos in one click, pre-filled and linked — and if one already follows that object, the button says so instead of creating a silent duplicate.
- The tab carries two badges: red for what presses — todos overdue or at high priority — and blue for the rest still to do, their sum being the number of open todos. Red does not read off the “High” badges alone: a normal todo whose due date passed three days ago asks just as much, and lateness is exactly what gets forgotten. Hovering says what the number is made of.
- The full guide now exists in English. Every tab, objective verification and its script contract,
.envconfiguration, enterprise TLS, local clones, data & backup and the security model — the whole document, not a summary. Until now the only complete documentation was in French, which put anyone arriving from the mirror in front of eleven hundred lines they could not read. The two versions must keep the same section structure, andnpm run checkfails when they drift apart or when a link points at a heading that no longer exists.
Changed
- The Settings sub-tabs are ordered by the journey, and the first one is Git. The old order told the story of the order in which features were written: the bar opened on "Specific review rules", whose contents apply to nothing as long as no repository is tracked and no token is set — while the onboarding was already sending its own first step to Git. It now reads connect (Git) → choose the code (Repositories) → tune the review (Merge Request, Rules, Verifiers) → tune the tool (Notifications, General) → the optional integrations (Jira, Jenkins) → the test bench. A fresh install therefore lands on the token without which nothing works, the last sub-tab you visited is still remembered (by name, so nobody is displaced), and three tooltips that had stopped being true were fixed along the way.
- The "review skill" setting is gone: the skill is written in the prompt template. A field of its own meant understanding that it fed a
{skill}hole hidden inside a text you can rewrite anyway — and the template is exactly where you choose what you ask the AI. Existing installations are migrated: whatever skill was configured is copied into the templates, so nothing changes for anyone and no{skill}is left to be sent verbatim to the agent. A template that was never touched comes out identical to the default, so it keeps following the interface language.
- The commit message chosen for a session now applies to every one of its commits. It was used by the first run only: a follow-up committed under its own first line, the resume after questions under a fixed sentence, and a convergence pass under the pass number. Anyone who prefixes commits with a ticket key or a team convention had the rule broken exactly where nobody re-reads it — the commit is already pushed. When the field is filled it is now the rule for the whole session; left empty, nothing changes and each gesture keeps its own default, which says what it just did.
- A Jenkins job's page is three separated blocks instead of one flat sheet. The launch form, the run history and the details of the selected run all sat on the same background, with the same gap between two zones as between two lines: it read as one column, not three subjects. Each is now a card of its own on a recessed background — the boundary is seen rather than inferred, in both themes. The history became a real list (rules between rows, no floating gaps, the date on its own line so verdicts line up), the selected run is marked by an accent bar and a bold number and not by a shade of grey alone, and the filters sit in a header that stays put while you scroll — filtering after ten lines no longer means scrolling back up. Only the body scrolls now, so
Runstays reachable instead of sinking under the history, and the run details follow you down: comparing "what I am about to launch" with "what went out last time" is what this window is for.
- The Jenkins refresh interval is now a setting. Settings → Jenkins holds it — every N minutes, 0 = never, one minute by default and capped at an hour — instead of a hard-coded 30 seconds, and it lives in the database like the merge request and Jira intervals rather than in one browser. It applies without reloading the page. The tab's "Do not refresh on its own" checkbox stays as a local, immediate pause that wins without touching the setting.
- The Jenkins filter dropdowns look like the rest of the tab. Raw browser selects belonged to neither the chips below nor the folder boxes above; each filter is now a pill — parameter name inside, value on the right, drawn chevron — and it tints when a value is picked, so an active filter is visible without reading it.
- The Jenkins menu icon says which tab it is. It used to be the play triangle — the very symbol on the tab's own "Run" buttons, which told you the tab could start something rather than what it was. It is now a pipeline: one stage feeding the next, which is what a Jenkins job is, and it cannot be mistaken for the git branch icon two rows above.
- The parameters in the Jenkins list are readable. They sit on their own line as name/value chips instead of trailing the status, the date and the author — all grey, all separated by middle dots, which read as a sentence rather than as pairs.
- The Jenkins list spells out every parameter of the last run. It used to show three and count the rest as
+2, which sent you hovering or opening the job's page for the very question you were asking while reading the list. Lines wrap instead. Values longer than 60 characters are still cut — three thousand characters in a list row is a wall, not information.
- The Jenkins job search now matches what the line shows. Not just the path: the branch or tag, who started the run, and the parameters it went out with. Searching
ENV=prodand finding nothing while it is written on screen is the surest way to stop using a search field.
- The Jenkins job page and build console are wider. The history now sits next to the run details, and console lines of three hundred characters had nowhere to go in 900 px.
- A Jenkins job that expects parameters now says so before you click. Its button reads
Run…and its tooltip gives the number of parameters, and the job's page explains that the values shown are the ones that will be sent. The behaviour had not changed — the button already opened the page instead of launching blind — but nothing announced it, so the page read as an information panel rather than the form it is.
- The tab shortcuts now go up to ten. With Jenkins the bar holds ten tabs, and there is no "10" key: the tenth is on
0, as in a browser. Without it, adding a tab silently took its shortcut away from the last one — and the help sheet reads the real range from the bar.
Request a fixis nowSend a follow-up. The button was named after one of its uses, and people were using it for all the others: asking for changes, giving further instructions, asking what was done and why. One word now covers the whole cycle — prepare a follow-up while the session runs, follow-up waiting on the card, send the follow-up when you decide — and the tooltip says what actually happens: the session continues, the AI keeps all its context. The exploration button (Follow-up question) and the form'sRun iteration/Ask the questionfollow suit.
- The tabs are reordered into four pairs. Their order used to be the order they were added in, not a designed one — which put Stats, the rarest tab and one of the three carrying no badge, in third place, and Notes second-to-last even though it holds the morning brief the app opens on. They now read Reviews · AI Dev (the core: review, produce), Notes · Jira (what I have to do: my todos, my tickets), Git · Docker (my machine: repositories, containers), Stats · Settings (the meta: measure, configure). At eight items a flat list gets counted rather than scanned; four pairs are remembered — and the number shortcuts become learnable along with them. The keys now follow the bar read from the DOM instead of a list copied beside it, which could silently drift so that
3opened something other than the third tab. The command palette and the guide follow the same order.
- The Statistics menu entry is now “Stats”, and the tagline sits on two lines. With an eighth tab in the bar, the longest label was the one that could most afford to shrink — English already said “Stats”. The tagline under the product name no longer runs all the way to the navigation: it breaks where the sentence does, between what the AI prepares and what you merge.
- The Links tab now leads with what you do every day. Its top bar carried setup buttons only — new environment, new service, import — while finding a link, the daily gesture, had no place at all. A single search field takes that space and filters both halves of the screen, grid and free links together;
+ Addand a⋯menu hold the rest. When the grid has nothing but the free links do, the message points down instead of claiming nothing matches. Creating a service now asks for its addresses, one row per environment, and scrolls to the new row rather than leaving you to find it. Columns can be reordered from their header, services pinned to the top, and the free-link checkboxes only appear when you ask to select. The⋯menu also carries Delete every free link — the escape hatch from a bad bookmark import, with a confirmation that states the count and says the grid is left alone.
- A grid cell can hold several addresses, each with a name. One cell was one URL, so writing a second one silently overwrote the first — which is wrong the moment a service exposes more than one view in the same place: a production Kibana is as many addresses as it has saved filters. Each now carries a name (“payment errors”, “API latency”), the pencil opens one row per address, and the palette finds each by its name. How many a cell shows is judged on the row: under five addresses everything is displayed, past that a
+Nexpands in place and its tooltip names what it hides.Expand allopens every cell at once and is remembered. Existing cells are carried over untouched, as single unnamed addresses.
- Filters for environments and services, labelled and always on screen. Environments are chips that hide columns — one click means “that one”, and a service with no address in the kept columns drops out rather than showing an empty row. Services are chips as well — opening a menu to see what you filter on is one click too many — with a sifting field past a dozen of them. Tags now carry their count. All three survive a reload, and one button releases them.
- A free link can be filed into a service — a new one or one that already exists. Turning links into a service could only ever create one, so filing had to happen in a single sitting or not at all. Every free-link row now carries a
Filebutton, the picker offers the existing services with a search field, andFile everything intosets one environment for all the rows at once.Select allticks whatever the current filter left — sift, tick, file, repeat — and a link filtered out of sight leaves the selection rather than being filed silently. Addresses are appended to the cell instead of replacing it — two links filed into the same place both fit, where the previous code silently kept only the last — and the link's label becomes the address's name.
- Bookmark import now builds the grid it finds in your tree. A folder whose children carry environment names describes a grid, not filing — and flattening it into free links was strictly worse than what the browser already does. The preview builds the grid and shows it before creating anything, with a count per cell and a box to refuse it. Labels that repeat across environments become one row each (
bo,api); labels specific to each environment become one row for the folder with named addresses (a Kibana and its saved queries). Two spellings of one environment merge into a single column, a numbered environment stays distinct, and a sub-folder below the environment becomes its own row. Nothing is guessed about your domain: the only clue is an environment name, from a wide French and English list.
- An environment is edited and deleted from its own name. Renaming, recolouring or removing a column sat behind a gear that only appeared on hover: the feature existed and nobody found it. The column's name is now the button, and deleting says how many addresses go with it. The free links open their first level of folders and no more, with
Expand all/Collapse allfor the two extremes — remembered across reloads — and a fold button on every folder that holds others.
- An environment with no service could not be reached at all. Its settings live in the grid's column header, and the header was not rendered until a service existed: a freshly created environment could be neither renamed nor deleted, and the screen announced “nothing matches this search” to someone who had searched for nothing. The table is now drawn as soon as there is one column, with a row saying why it is empty.
- The search reaches the names of the addresses inside the grid, not just service names and URLs — and a cell then shows only the addresses that match, so you read the answer instead of re-reading the cell. A query can mix both levels:
logs apachetakes one word from the row and the other from the address. The grid's columns also share the available width and shorten long addresses instead of pushing the table into a horizontal scroll.
- A free link is filed into a folder as you create it. The form offers the existing folders and accepts new ones — a slash creates the sub-folder on the way. The import preview also lets you rename a proposed row and merge several of them into one service, since the detection reads folder names and cannot know that two of them mean the same thing to you. The import dialog is wider, so a five-column grid can be read straight on.
- Free links keep their full folder path. Grouping on the last segment made
seres/prodandlogs/prodmerge into a single “prod” group — the tool destroyed a structure the browser preserves. The list is now the real tree, at full depth.
- Bookmark import no longer dumps everything in. The preview is folded by folder, with a count and a checkbox per folder, and nothing is ticked: you unfold what you want and import twelve links instead of two hundred. The root folder no longer becomes a tag — present on every link, it filtered nothing while taking the first spot. Past a dozen, the free links group by folder.
- The presentation video is recorded in both languages, and shows the new tabs.
npm run record:demonow produces a French and an English.webmrather than one French recording, and the tour takes in Notes, Links and the collapsing column alongside the screens it already covered. Dropdowns are redrawn inside the page while recording: a native list is painted by the operating system, outside the page the camera films, so it never appeared — you saw the cursor click and the value change on its own.
- AI Dev lists lead with what just finished running. They were ordered by creation, so a session you launched minutes ago sat below one created last week and never run. Whatever is running now comes first, then the most recently executed. Execution is what counts: fixing a prompt, pushing a branch or tidying a session away no longer jumps it ahead of the one that actually just ran.
- The verifier form now opens on demand. Settings → Verifiers used to lead with the whole form — name, command list, covered repositories — which pushed the verifiers you came to look at off the screen. The list comes first now, and “Add a verifier” opens the form; so does “Edit”, already filled in. Saving or cancelling closes it again.
Fixed
- The demo no longer empties itself at midnight. Jenkins demo data is dated relative to now, so past midnight the most recent run fell "yesterday" and the menu badge — which counts the jobs that ran today — hid itself. A demo that cannot produce the screen its own documentation describes is worse than no demo: the recording of the English presentation started at 23:50 and failed on that badge at 00:10. The most recent run is now kept on the right side of midnight, the others keep their real spacing, and the job list is rebuilt on each request so a demo server left open overnight does not serve yesterday's "today".
- Pending review comments now show up in the demo. They were seeded on files that the demo diff never contained, so they existed in the database and nowhere on screen. The seed and the viewer now read the same diff for a given merge request.
- A running verification is now visible. Clicking
Verifyon a merge request started a job and then showed nothing: the request answers in milliseconds while the work takes minutes, so the button's spinner was gone before the run even began. The button now readsVerifying…, spinner included and disabled — a second click cannot start the same verification again — and the card carries the same "in progress" marker a review uses. The state comes from the server, so it survives a tab change, a re-sorted list and a page reload, and it clears itself when the job ends. A review on the same merge request marks the card without spinning theVerifybutton: a spinner pointing at the wrong command is worth less than none.
- A page open in another tab can no longer act on your behalf. Listening on
localhostprotected nothing against this: your own browser is the one sending, and a plain form on any website goes out without a preflight — the routes that do not read their body ran as-is, which covers wiping every report, publishing your pending comments on a real merge request with your token, and launching an agent on your folders. Any request that writes while announcing a foreign origin is now refused, with a message that names the likely culprit. Reads are untouched, and so are requests with no origin at all —curland your own scripts keep working, while a browser always sends one.
- A brand-new install no longer loses its first coding session. One migration sat before the
CREATE TABLEit patches: on a fresh database it threw "no such table", the emptycatchswallowed it, and the column only existed on databases where the table predated the migration. The first coding session ran the agent for minutes, then died onno such column: session_note, leaving the work uncommitted. The migration moved, andnpm run checknow verifies that every migration follows itsCREATE TABLE— the rule was written down, it is now enforced.
- A follow-up you did not push is no longer destroyed by the next pass. Without auto-push — the default — a follow-up commits without pushing, so the local branch is the only place that commit exists. The next pass realigned on
origin/<branch>as soon as the remote branch existed, and the log said "aligning". The local branch is now kept whenever it carries commits the remote does not have, and the log says how many. If both sides diverged the local still wins: a push refused for non-fast-forward is a failure you can see and repair, unlike an overwrite.
- Everything the server writes now follows the interface language. The interface had been translated for a long time; the server had not. An English user got English screens and then, the moment anything ran, a French job log and French error messages — precisely when you need to understand what is happening. The job logs, error messages and job boundary lines of the server modules now go through the dictionary, and a test runs the same session in both languages and fails if a single accented line comes back.
- A commit message filled in after the fact is applied on the next run. You launch a session, you see a badly named commit go by, you fill in the commit message field and relaunch — and nothing changed, because the AI finds the work already done and commits nothing, leaving the field with nothing to name. The last commit is now renamed instead: only the message changes, the commit's contents are untouched and no extra commit appears. Not when the branch is already on
origin— renaming a published commit would rewrite a history the forge, a merge request and possibly a colleague already have; the job log says so rather than staying silent.
- Reopening Mergerie on the Jenkins tab no longer lands on an empty tab. The last tab you visited is restored at startup, and it was opened while the script was still being evaluated: the Jenkins tab reads state declared further down the same file, so it threw, the list stayed empty and an "unexpected error" appeared. The landing now happens once the script is fully loaded. The failure only showed up on the second reload of a day — the first goes through the morning brief, which lands later and therefore worked.
- Open dropdown lists are readable in dark mode. The list a
<select>opens is drawn by the operating system, not by the page, and without acolor-schemedeclaration it was always painted light — light text on a white background. Every native control now follows the theme: dropdowns, scrollbars, date pickers.
- A Jenkins field no longer shows up prefilled with a plugin error. Dynamic parameters (Extended Choice, Active Choices) build their list from a script evaluated when the page is rendered; seen from the API that evaluation can fail, and the plugin returns its error message — Could not get Environment from ENV Param — where the list should be. It was taken for a value and prefilled the field, so a run would have sent that sentence to Jenkins. The field is now left empty, says why, and links to the job in Jenkins.
- Jenkins choice parameters are dropdowns again. The job request asked for a fixed list of fields, so anything a parameter plugin exposes under another name never arrived — a choice parameter fell back to a free-text field where you retyped, by hand, a value Jenkins already knew. Every field is now requested, and Extended Choice parameters (all options in one comma-separated string) are understood too.
- A Jenkins build console no longer scrolls sideways. Long lines — a command, a classpath — went off to the right, so reading the error you had opened the console for meant scrolling horizontally. Lines now wrap.
- A confirmation no longer opens behind the window that asked for it. Confirming an action started from another modal — running a Jenkins job from its page — put the question underneath, with its button unreachable. Confirmations now sit above other modals.
- Error messages are no longer hidden behind a modal. An error is most often raised from inside a modal — that is where forms get validated — and the message appeared underneath it: you saw a form refusing without ever being able to read why, and its
Copybutton was out of reach. Messages now sit above everything, including modals and the full-screen code explorer.
- The code explorer's tree no longer closes under your fingers. Clicking a file rebuilt the tree and recomputed which folders were open from a single rule — "expanded if it carries a change" — so a folder you had opened by hand collapsed at the very moment you opened one of its files. What you expand or collapse yourself is now remembered for the visit; the next diff starts fresh.
- “Mark as handled” now moves the merge request out of the Reviewed list. The button in the report refreshed the report and nothing else, so the card stayed in a list it no longer belonged to and the stage counter kept the old number until the next reload — the same gesture from the “To handle” queue already updated the list. “Reopen” brings it back the same way.
- Importing bookmarks no longer leaves the Links tab saying it is empty. The grid only looked at services and environments, so after an import it answered “no links yet” directly above the links that had just arrived — and offered to import them a second time. The two empty screens are now told apart: with nothing at all, importing is offered as the shortest path to a useful tool; with free links but no grid yet, the message explains what the grid is for and points at the links below.
- A filled grid cell can be corrected again. The Links tab let you type a URL into an empty cell, and then never again: a filled cell was only a link, and the service form held no address field. Fixing a typo meant deleting the whole service — losing its other URLs and its contextual links — and typing everything back. A pencil now appears on hover, the field opens pre-filled, and clearing it clears the cell, which is what the guide had been promising all along.
- Collapsing the navigation column no longer empties the screen. The collapse button lives in the column with the tabs, and the tab handler took it for one of them: clicking it deactivated every tab, blanked the content area, and stored “undefined” as the last tab visited — so the next reload showed nothing either. It now only listens to buttons that actually carry a tab.
- A link pasted into a note is now clickable. URLs written in a note page or a todo's note become links opening in a new tab —
http/httpsonly, since a note is text you paste without re-reading it and a link the tool builds has no business being able to run anything. Sentence-ending punctuation stays outside the link, and a reference contained in a URL is no longer transformed a second time: pasting a Jira link no longer built a ticket link inside the URL's own text.
- The “say why” field of a watched ticket holds several lines. A reason rarely fits on one — “blocks the billing migration — tell Sofia as soon as it is in review” already overflowed. Both the add field and the one on the card are now resizable text areas: Enter starts a new line, Ctrl/Cmd + Enter saves, Esc closes without changing anything. On the card the buttons moved below the field, which in a narrow column left barely a hundred pixels to write in. Line breaks are kept when the note is displayed back.
- The branch explorer now says it is working. Clicking “Analyse” could look like nothing happened: the loading skeleton sat inside blocks that open folded, and a clone can take a minute. Each repository now announces its state in its own header — waiting, then analysing with a spinner, then its branch count — so on several repositories you can see which one is being worked on, since they are handled one after another. The button spins too, and a repository that fails opens its block to show why rather than keeping the reason shut inside. Those blocks also regained a chevron:
display: flexon their summary had removed the browser's native marker, so nothing said whether a block was folded or not.
- A code template inside a Jira table is readable again. Technical tickets routinely lay a template out as a table — a label on the left, JSON on the right. A Markdown table holds one line per cell, so the code arrived flattened onto a single line, its indentation collapsed by the HTML and impossible to copy. Tables whose cells carry a code block, a list or several paragraphs are now unfolded: each row becomes the label followed by its block, rows separated by a rule. Ordinary data tables are untouched — and a
|inside a cell no longer opens a column of its own and shifts the whole row.
- A Jira table with no header no longer loses its first row. Markdown requires a header row; a Jira table does not. The first row was promoted to a title regardless — so a header-less table lost a line of data to the heading, and a key/value table (whose header is the first column, making its first row mixed) lost a whole pair. Only a row whose cells are all headers is treated as one now; otherwise an empty header is emitted, which the display hides rather than showing a blank grey band. Header cells outside the header row are rendered in bold, Markdown having no column header.
- Markdown rendered outside a review report had no styling at all. The Jira description and comments, the note-page preview and a todo's note all use a container that, it turned out, no CSS rule ever matched: code blocks had no background, no padding and no horizontal scroll, so a long line pushed out of the card instead of scrolling inside it. They now look like the code in a review report.
- The inline comment box no longer runs off the side of the screen. In the code explorer, the diff area is as wide as the file's longest line, and the comment editor stretched to match — so on a file with one long line, its “Send” button sat thousands of pixels to the right and you had to scroll sideways to post what you had just typed. The editor now sticks to the left edge of what you can see and sizes itself on its own content, whichever way you scroll. Existing comment threads got the same treatment: they were stretched to the same width and read as one endless line.
- Saving an exploration again no longer resets its repositories. Reopening a finished exploration and saving it — even without changing anything — sent every repository back to “to run” while the session itself still read “done”. Mergerie only rebuilds the project rows when their composition changes, but the comparison included the base branch, which the run resolves and writes back and which the form never sends. That branch is a result, not a choice, so it no longer takes part in the comparison. Genuinely changing the repositories still rebuilds them, as it should.
- The base run is replayed every time, instead of being reused. Mergerie used to cache it per set of commits — the base does not move while you iterate, so why pay for it twice? Because the commits are only half the story: restart a local service, apply a migration, reinstall a dependency, and the same commits give a different answer. The cache was wrong in both directions: a red base you had just fixed outside git stayed stuck, blocking the merge request on a "base already red" that was no longer true — and a green base that had since gone red made your branch take the blame for a failure that was not its doing. A verification now costs two runs; unticking "also run the base" still buys you one, at the price of a verdict flagged as non-causal.
- Dropdown lists no longer spill out of their block. Any list-with-search — “pick a local project” in a verifier, a branch, a git ref — now opens attached to its field and flips above it when there is no room below. It used to be clipped by whatever container it sat in, and the workaround for that reset the container's scroll position, so the list you were reading jumped back to the top and the menu ended up floating well under the block, detached from its field.
- An “in place” verifier no longer refuses a directory that merely holds untracked files. It asked for a directory with nothing at all in
git status, which in practice meant almost none: a.env.local, a build folder, a scratch note were enough to be turned away. What has to block is a checkout that would lose work — untracked files are in no commit, so the detached checkout leaves them alone. They are now counted, reported by “Test the directory” and noted in the run log, since they are still there while the tests run. Modified tracked files still refuse the run: Mergerie never stashes your work for you.
- The report stays put while you scroll the list of merge requests. Under “Reviewed” and “Processed”, list and report shared a single page scrollbar: going down the list to pick another merge request carried the report off the screen, and you had to scroll back up to read it — though the whole point of the two columns is to look at both at once. Each column now keeps its own scrollbar, and reaching the bottom of the list no longer starts moving the page underneath.
- “Top 5 — recent activity” now shows the time, not just the date. It ranks repositories by how recently they were pushed to, and several of them usually share the same day — so the order looked arbitrary. The last-commit column of the projects table is unchanged: there, nothing depends on the order.
- “Top 5 — recent activity” now ignores repositories you no longer follow. A repository whose merge request fetching is switched off is one you have stopped watching; it had no business heading the list of what is moving, and the forge call it cost is exactly what turning that switch off was meant to avoid. It disappears from the ranking, and from the “last commit” column, until you follow it again — disabled repositories already behaved this way. The caption under the ranking also said “default branch”, which stopped being true when the ranking started looking at every branch.
- A modal no longer takes your typing with it when you click beside it. Two different mishaps looked the same. Selecting text in a field and releasing the mouse a few pixels outside it counts, for the browser, as a click on the backdrop — so a dialog you never meant to leave closed, and the prompt you had written was gone; the same went for dragging a textarea's resize handle. A click now only closes a modal if the mouse was pressed on the backdrop too. And a genuine click beside a dialog you have started filling in no longer discards it: the dialog gives a short pulse and reminds you that Escape or Cancel closes it. Untouched dialogs still close on a click beside them — opening one and changing your mind stays a quick gesture — and searching or filtering inside one does not count as filling it in.
- Tell one AI Dev session from the next at a glance. A session is a tall block — prompt, project list, the agent's questions, an error — and a one-pixel rule between two blocks that size gets lost in the whitespace: you could not see where one ended. The three lists now show real cards with air between them. The error box, which used to be rendered beside the card, sat between two sessions without saying which one it belonged to; it now lives inside its own.
- “Top 5 — recent activity” now looks at every branch. It only ever read the default branch, so a repository where the work lives on feature branches looked asleep for months while people pushed to it daily. GitLab is asked for commits across all refs; GitHub has no equivalent, so the repository's events — the only place a push outside the default branch shows up — are read instead, falling back to the default branch when they are unavailable or older than the 90 days GitHub keeps them.
- Stop sending the same instructions twice when a session cannot be resumed. Falling back to a fresh session re-injects the context the lost session was holding — which is right for a follow-up request, but a first run already carries the whole task. The prompt, review report included, was therefore sent twice in a single call.
- Escape no longer leaves a button spinning forever. Some dialogs hand back a promise — the one that asks which verifier to run, for instance. Closing them with Escape hid the dialog without settling that promise, so the button that opened it stayed in its loading state indefinitely.
- Say when a requested agent session could not be resumed. An agent session belongs to the directory it was created in, and Mergerie works in its own clone — so an identifier taken from your own checkout, or from a session opened by hand, is never found there. The work already restarted from a fresh session with the context re-injected, but the substitution was only visible in a log line that scrolls away: the card now says it, and the field warns as soon as you paste something.
- “Merge” and “Create the MR” now show they are working. Both call the forge, which takes a moment while the dialog stays on screen; with no indicator the button looked inert and invited a second click.
- Hiding a status now narrows the search instead of sifting an extract. Jira caps a search at a hundred tickets; unticking a status only removed it from those hundred, so tickets you expected to surface never did. The exclusion is part of the query now, like projects and sprints. Custom workflow statuses were already handled — the colour follows the status category, not its name — and a status stays on offer once hidden, so you can put it back.
- The status filter now lists your workflow's statuses, not just the ones on screen. A status that exists but happens to be on none of the fetched tickets was simply not offered. The statuses of the projects concerned are loaded alongside — the selected ones, or those of the tickets shown. Not the whole instance: that would add dozens of unrelated entries, and the endpoint for it requires administering Jira, which most accounts cannot.
- The Jira ticket list no longer changes width with the tickets in it. A long title stretched the left column from 360 to 610 pixels, so filtering made the whole layout jump. A flex item refuses by default to go below the width of its own content; the column now holds its size, and a long title wraps onto the next line instead of being cut — it is what tells you whether to open the ticket, so hiding half of it meant hovering to read it.
- The "watch a ticket" key box looks like the rest of the tool. It was the one unstyled browser input among styled controls. It now has the same treatment as the other fields, in a fixed-width font — you type a reference there, not a sentence.
- Filtering by project no longer makes tickets vanish. Narrow to your own tickets, pick the project, then drop the assignee filter, and the tickets you were looking at disappeared instead of being joined by their colleagues'. Jira caps a search at a hundred results ordered by last update: with no assignee constraint those hundred come from the whole instance, and your project's tickets can be nowhere in them — the project filter was then sifting an extract, not the project. The selected projects are now part of the query Jira answers. And whenever a list is capped, the counter says so ("100 of 340 shown") instead of letting it look complete.
- A Jira ticket's title no longer shares a line with the buttons above it. A global
headerrule written for the app's own header applied to every<header>, including the one in the ticket detail: its title and chips were laid out beside the action buttons instead of below them. The rule is now scoped to the app header. - The ticket key in the watched list opens Jira. It was plain text, while every other key in the tool is a way to get to the ticket.
- Confirmation messages are no longer written in red. Every toast used the error colour, so "Repository updated" looked exactly like a failure — the one thing a confirmation must not do. A success now carries a discreet green edge and reads in the normal text colour; an error keeps its full red border and red text, and still stays on screen until you dismiss it. The louder of the two is the one that needs you.
- A Jira refusal now says what Jira actually refused. Errors surfaced as a bare "Jira 400 Bad Request": the response body, where Jira explains itself ("The JQL query is unbounded", "Field 'x' does not exist"), was thrown away. Its messages are now part of the error you see.
- Asking for every assignee no longer breaks the search. With nobody ticked and done tickets included there was no constraint left at all, and Jira Cloud rejects an unbounded query. The search is now bounded to the last year of activity in that one case — invisible in practice, since the list is sorted by last update and capped at a hundred results.
- Creating a coding session no longer fails with "t is not a function". Any validation problem — a missing branch name, the same project picked twice, an unknown project — produced that message instead of the real one, because a callback parameter shadowed the server's translation function. The four messages now say what is actually wrong. The same shadowing existed in fourteen other places, all waiting to bite the same way; they are renamed, and a new check (
npm run check) fails the build if the nametis ever bound to anything but the translation again. - Demo mode applies Jira status changes for real. Picking a transition answered "ok" and changed nothing: the list reloaded on the old status, and the menu counter never moved. A demo that accepts an action without reflecting it teaches the opposite of what the tool does.
- Demo mode can finally open the code viewer. "View diff" — on a merge request as well as on a session project — failed every time in demo mode: the viewer goes through a real git clone, and the demo repositories point at a forge that does not exist. Anyone discovering the tool hit an error on one of its most central buttons. Demo mode now serves a coherent fictional repository: real unified diffs, a browsable file tree, per-file diffs, and file contents. As everywhere else, a path outside the tree is still refused — a demo must not teach the wrong reflex.
- "Fetch new MRs" no longer fails in demo mode. The button sits at the top of the home screen, and pressing it in the demo produced one red "GitLab token not configured" card per repository — the first thing a newcomer saw. A scan now legitimately reports what is already there, without going near the network.
- Stop now really stops the agent. The button did what it promised everywhere except where you press it: queued jobs were cancelled and git steps were interrupted, but the agent itself — the long phase, and the reason one presses Stop at all — kept running to its fifteen-minute timeout, still writing into the clone and still spending tokens. Its process was never registered with the cancellation machinery, so the stop flag was raised with nothing to kill. It is registered now, like the git and copilot paths already were.
- The red Docker badge no longer counts containers you stopped yourself. A container that exited cleanly — you stopped it, or a job finished its work — was counted as red alongside crash-looping ones, so the alarm rang every single day; an alarm that always rings stops being read. Only what is actually wrong is counted now: restarting / dead, plus containers that exited with an error. Clean stops stay visible in the tooltip, just not in the number, and a container whose exit code cannot be read is left out — one does not cry wolf on a guess. The state filter gained a matching Exited with an error entry, next to the existing Stopped (exited) which still covers both.
- Re-running a session whose work was already committed no longer reports a failure. When a project failed after its commit — a refused push, for instance — re-running it sent the AI over code that was already written. It changed nothing, and "nothing to commit" was read as "the AI replied instead of coding": the project went back to error, with no diff and no Create MR button, although the work was there and ready. The branch is now inspected before concluding — if it already carries the work, the session picks up where it was, diff and MR button included. A branch that really is empty still gets the explicit message, with the AI's own answer in it.
- The agent could fail with "no stdin data received in 3s". Every agent process was started with an open standard input that nobody ever wrote to or closed, so the CLI waited for data, warned about it, and that warning ended up masking the real reason in the failure message — when it did not make the process exit outright. Standard input is now closed on launch, which is exactly the
< /dev/nullthe CLI itself suggests. - Relaunching a failed session left its error badges on screen. The previous failure was only cleared when the job actually started, so between the click and the start — minutes, behind a busy queue — the card still read error and nothing told you the click had been taken. Asking for the work again clears the failure right away, on the session and on each of its projects, and the list refreshes without waiting for the next poll. Same for off-repo sessions.
- A job finishing next to another one refreshed nothing. Since several jobs can run at once, the end-of-queue refresh never fired while any other job was still running, so a card kept its old state — stale error badge included. Lists now refresh as soon as the object they show stops being worked on.
1.1.0
Added
- GitHub support — full parity with GitLab. Repositories are now handled forge by forge: pull requests are discovered, reviewed, scored, commented (general, inline and replies) and merged exactly like GitLab merge requests. Coding sessions create the PR, convergence runs on it, and the Git tab (refs, preview, restorable deletions, branch explorer, ref finder) works on both. Settings gained a GitHub connection (URL for GitHub Enterprise, token, Test button), and the repository list a Bulk add from GitHub button. A repository is unique per (forge, path), so the same path can exist on both forges.
- Off-repo coding: the AI reports back, and you can ask for a fix. Each folder now exposes AI output — what the agent says it did, which is the only window on its work when the folder did not change — and a session offers Request a fix: another pass over the same folders that resumes each agent session, so the AI keeps the context of what it just produced.
- Docker → Compose: find a container. A search field (service, container or project name) and a Only show state filter (running, stopped/not created, unhealthy, restarting, drifted) narrow the view service by service. A project with no matching service disappears entirely. Both settings are persisted and applied client-side, without querying Docker again.
- Docker logs are readable again — and can be colourful on request. An application running in a container usually colours its output,
docker logsrelays those escape bytes untouched, and the browser is not a terminal: every line came through buried under[34mdebug[39mand a control glyph. Lines are shown as plain text by default, which is also the lighter rendering when the stream bursts. A Show colours checkbox next to Wrap lines renders what the application meant — the blue of debug, the red of an error, the green of a 200 — and remembers your choice. Ticking it replays what is already on screen rather than restarting the stream, and the include / exclude filters keep matching on the plain text either way. Background colours are deliberately left out: they assume a terminal whose contrast you control, not a light and a dark theme. - Accents no longer break in the log stream. A multi-byte character landing on a network chunk boundary was decoded as two invalid halves and shown as a replacement character. The stream is decoded properly now. The job log panel also strips escape sequences, which can reach it from an agent or from git.
- "Not running" was three different situations. The Compose state filter lumped them together under Stopped / not created, although Docker tells them apart and they call for different actions: a container that ran and exited wants restarting, one that was created but never started usually failed to start, and a service with no container at all has never been brought up. Each is now its own choice, and Not running (all) stays as the catch-all. The Actions sub-tab offers exactly the same list — the two "Only show" menus are now built from one definition, so they cannot drift apart.
- The Docker badge counts stopped containers too. Its red number only covered containers that were broken — restarting or dead — so a service that had simply exited stayed invisible from every other tab, although from the outside it serves just as little. Exited containers are now part of the red count. The two are still told apart where it matters: hovering the number reads "1 container in error (restarting/dead) · 1 stopped container (exited)".
- Docker menu badges explain themselves. Hovering the red or amber count in the Docker tab now shows what it counts ("1 container in error (restarting/dead)"), using the app's own tooltip.
- Search across sessions. A search field filters coding sessions, off-repo sessions and explorations by prompt, project, branch or folder. It resets when switching sub-tab, so it never contradicts the totals shown on the tabs.
- Every iteration of a coding session is kept. A session iterates (initial run, Request a fix, answers to the AI's questions, convergence passes); each pass now keeps the prompt actually sent and its own AI answer, instead of only the last output. An iteration picker appears in AI output from the second pass on, and shows the request next to the answer — reading an answer without knowing what it answered teaches nothing. Applies to off-repo coding too, folder by folder, and to explorations, where a follow-up question used to overwrite the previous answer.
- Review reports keep the change requests that produced them. The Ask the AI for a change section now lists the requests already made on a report, with their date, and opens the report version each one produced.
- Merging asks for confirmation, with options. A modal recalls the MR and its target branch and offers squash and delete the source branch, pre-checked from what was chosen when the MR was created. Creating an MR uses the same modal family (title + the two options) instead of a native browser prompt. GitLab keeps both at creation time; GitHub cannot express them there, so Mergerie remembers them and applies them at merge — the modal says so.
- A tag recreated on another commit no longer blocks Git operations. The safety fetch that precedes every deletion did not force tag updates, so a tag deleted then recreated elsewhere made it fail with
would clobber existing tag— and the whole action was lost although the repository was fine. It now forces them, like every other fetch on the tool's own clones. Repositories you own (Git → Navigation) are deliberately left untouched: there, a local tag must never be silently overwritten. - The convergence dialog says what it will converge. It named "the MR" even when started from a session — where the AI first codes and opens the MR. Title and opening line now follow the context, and the dialog shares the layout of the other confirmation modals.
- Every confirmation now uses the app's own dialog. The sixteen remaining native
confirm()boxes (delete a repository, a rule, a session, a report; stop a job; git deletions and restores; Dockerdown…) share one styled modal: themed, translated, and with a button that names the action instead of a mute "OK". Irreversible actions are recognisable at rest, not only on hover.
- Out-of-repo coding sessions can be edited. They were the only kind you could not correct: a typo in the prompt or a wrong folder meant deleting the session and writing it again. The pencil is now on their cards too, and it reopens the same dialog. Editing only the prompt leaves the folders exactly as they were — their status, the AI's report and its session are kept, so a one-word fix does not throw away work already done. Change which folders are targeted and those do start over, which is the point.
- Out-of-repo coding can be prepared and run later. Its dialog only offered Start coding, which created the session and launched it on the spot — writing one down for later meant not writing it at all. It now also offers Create without running, next to it: the session is created in the "to run" state and its card carries a Run button, like every other session. Coding sessions and explorations already worked this way — their main button saves without launching.
- See what is queued, and jump the queue when it is safe. The log panel said "+3 waiting" without saying what. A Queued button now opens the list — what each job is, how much it has to do — and offers Start in parallel on any job that can run alongside the current one. The queue stays sequential by default; promoting a job is a deliberate act, and at most three run at once — past that you stop gaining time and start making them fight for the machine. When more than one is running, the banner says how many, since it can only describe one of them. Jobs that would touch the same repositories or folders are refused, not merely discouraged, and the line says which running job is in the way: two agents in one clone corrupt it, and waiting your turn is cheaper than repairing that. The queue obeys the same rule as it drains: it holds a job back rather than starting it next to a parallel job it would collide with, and it keeps its order instead of quietly skipping ahead. A queued job can also simply be removed.
- A job that did not finish can be restarted from where you are. The banner said "stopped" and left you to work out where to click. A Restart button now sits next to it and replays the same action on the same object. A review picks up where it stopped rather than redoing what is done: what is remembered is the intent, not the list, and the list is recomputed from the state of the merge requests. Git operations are deliberately left out — replaying "delete these twelve branches" from a small button, skipping the preview, is exactly what should not be one click away.
- Stopping a Git or Docker job no longer looks like a failure. Every other kind of job told a requested stop apart from an error; those two did not, so your own Stop came back in red with "stopped by the user" as the error message. They now end as stopped, like the rest.
- The log panel gets a tab per running job. Each keeps its own output and its own scroll position; switching tabs shows the other one rather than replaying anything. A tab stays after its job ends, carrying a dot for how it ended — green finished, red failed, grey stopped — and keeps its log until a new batch of jobs starts: the moment a job ends is exactly when you want to read it, especially if it failed. The tab bar only appears when there is more than one job — a lone tab teaches nothing and costs a line. Each tab of a running job carries its own stop, which leaves the others and the queue alone; the panel's Stop remains "stop everything" and now says so once more than one job is running, instead of claiming to stop "the running job".
- A new session can continue an existing one. Creating a coding session, an out-of-repo coding session or an exploration now offers an optional Resume an existing agent session field. Fill it in and no new session is opened: the work happens inside that one, so the AI still has everything it worked out earlier — its reading of the code, the decisions already made, what it already tried. Leave it empty and nothing changes. The id is the one shown by Resume in terminal on an existing session, and that button now appears on a session pointed at a supplied id too — without the
cd, since where that session came from is not ours to know. The field is also there when editing a session, pre-filled with the current id, which is the only way to move a session onto another one after the fact; clearing it never wipes anything, so a form merely submitted cannot lose a session. A session belongs to one working directory, so if resuming is refused the usual fallback opens a fresh session with the context re-injected rather than losing the run. - Explorations show their resume command too. They gained a resumable session, but their card never offered Resume in terminal — the button only existed per project, and an exploration has a single session shared by all of its repositories, working from the clone root rather than any one repository. It now sits with the card's own actions, where it belongs, rather than being repeated identically on every line.
- Explorations remember, instead of being reminded. A follow-up question used to paste the previous answer back into the prompt — but an answer is a summary, not the reasoning that produced it, so the AI had to work out again what it had already read. Explorations now run in a resumable session like coding sessions do, and a follow-up simply continues it. Pasting the previous answer back remains as the fallback, for dry-run and for the case where resuming fails.
- Picking a branch no longer means scrolling. In Git → Actions the source branch was a plain dropdown listing every branch of the repository, in whatever order the forge returned them — on a busy repository that is hundreds of entries. It is now a field you type into, like the repository picker next to it. The two other places where branches are chosen got a filter as well: the list of branches (or tags) to delete, and the branch table of the explorer. Both filters only hide rows — tick a branch, search for another, tick it too, then delete them together.
- Your own review comments can be edited. A typo, a wrong line number, a sentence you'd rather rephrase: an Edit link now appears on the comments you wrote — on a line in the code viewer as well as on the merge request itself. The editor opens in place, pre-filled with the original Markdown, and the change goes to GitLab or GitHub. Comments written by other people carry no such link: Mergerie compares each comment's author with the account behind your token, and if it cannot work out who you are, nothing is offered as editable.
- The demo has comments now. The review screen used to show "comments unavailable" in demo mode, since those routes went straight to the forge. A short fictional thread — one comment of yours, one from a colleague — makes the whole bottom half of a report worth looking at, and shows which comments you may edit.
- Finished sessions can be tidied away. Coding, off-repo coding and exploration sessions each gain a hide button: the session leaves the list without being deleted — its diffs, its AI passes and its merge request stay exactly where they were. A Show hidden sessions checkbox above the list brings them back, dimmed and dashed so you can tell them apart, and its state is remembered. When the box is unchecked, a count beside it says how many sessions are being kept out of the way: a session that vanished without a trace would be assumed deleted, and recreated.
- A long prompt is no longer cut off in the list. It used to stop dead at 220 characters, which is enough to lose the point of a detailed instruction, with no way to read the rest short of opening the session. The prompt is now folded to three lines with a Show more link, and the whole text is in the page — so the browser's own search finds it even while folded.
- The log panel says how long the job has been running. A review over thirty merge requests can run for a quarter of an hour; until now nothing told you whether it had been going for ten seconds or ten minutes. A counter next to the status ticks while the job runs and freezes on the total once it ends. It is computed from the server's start time, so a tab opened halfway through a job still shows the true elapsed time.
- Two guard rails where there were none. Running a free git command on several repositories now asks for confirmation — but only when the command can destroy unpushed work (
reset --hard,clean -fd,push --force,branch -D…); agit fetchstill runs on one click, because a confirmation you always accept teaches nothing. Docker's bulk action does the same forstopandrecreate, listing the services it is about to interrupt, and its button turns red as soon as such a verb is picked. Stopping a single compose service is not guarded: it offers Undo instead, which costs nothing when the stop was intended. - Start a coding session straight from a Jira ticket. The ticket detail gains a Let the AI code it button that opens the coding session modal already filled in: ticket content at the top of the prompt, suggested branch name and commit message from the key and summary, ticket number set. You pick the repository and add your own instructions — nothing is launched until you say so.
- Mergerie has a face now. The product mark — an
Mdrawn as a commit graph, its two branches meeting on a green merge commit — sits in the header (one drawing per theme, since only the ink changes) and became the browser tab icon. The tab icon still carries the job state as its background: blue at rest, amber while running, red on error. - The interface got calmer, and a little more alive. A study of what makes the tool pleasant to live in — it runs all day — turned into a batch of changes that share one rule: nothing is added that does not carry information.
- Lists stop blinking. A refresh that changes nothing no longer rebuilds the list, so the page holds still while you read it. When a list really does load, its cards arrive in a short cascade — once, on load, not on every filter keystroke.
- The job log stops eating the browser. A long run used to pile up tens of thousands of lines until scrolling stuttered; the panel now keeps the last few thousand and says so at the top.
- You can see how long it has been running, and roughly how long is left. The remaining time only appears once it can be honest — several units done, at least twenty seconds in — and disappears rather than lie when the pace changes.
- Reading a report survives a refresh. Scroll position, the tab you were on and the version you were comparing are kept while the report itself has not changed; when it does change, you land at the top of the new one.
- What is running is shown on the thing that is running — the merge request or the session itself carries a soft pulsing marker, one object at a time. It stops when the tab is in the background and stays still (but visible) if you asked the system for less motion.
- New comments landing on a report announce themselves discreetly, and a resolved discussion fades out instead of vanishing between two renders.
Ctrl/Cmd+Kopens a command palette: jump to a tab, a stage, a merge request or a session by typing part of its name.j/kmove through the current list,Enteropens,Escapereleases.?shows the whole list of shortcuts.- The tool reopens where you left it — same tab, same review stage. Nothing else is restored: a stale modal or a stale report is worse than a clean start.
- The report panel opens on what changed since your last visit — arrivals, departures, and the one that has been waiting longest. At most three lines, and nothing at all when nothing moved.
- A finished job says so once, even if you were looking elsewhere.
Changed
- Action buttons follow one rule now. A study of every screen found the same three problems everywhere, and they are fixed: a destructive button is recognisable at rest and not only on hover (
Merge,Stop,Deletecarry a red outline all the time); one strong-emphasis button per row, card or dialog, so the recommended path is unambiguous — the seven Makefile Run buttons,Convergein the new-session dialog andDismiss without reviewall went back to neutral; and Cancel is always on the left, the action on the right, in dialogs and in inline forms alike.Dismiss without reviewalso lost its green tick — it means "not now", not "approved" — for an archive icon. - Action rows are grouped by intent, and the grouping no longer depends on the language. A merge request card and a report's detail panel line up their buttons in three declared groups — consult (view diff, context), act (converge, have the AI fix it, re-run) and close (mark done, merge, delete). Until now the groups were whatever the row happened to wrap into, so the same buttons clustered differently in French and in English. A group now stays whole: only the space between groups breaks.
Delete the reportmoved where it belongs. It used to be the only button on the cards of the left-hand list, which put a housekeeping action on the same footing as the whole review journey. It now sits last among the report's own actions, in the detail panel, still red and still asking for confirmation.- The Dev AI columns stopped moving. In coding, out-of-repo and exploration sessions the action column now has a fixed width, and the actions on the record (edit, delete) sit below a separator, right-aligned. The ✕ is at the same place on all three sub-tabs, whatever buttons the card shows.
- Coding sessions:
DiffbecameSee the diffand opens the same full-screen viewer as merge requests — file tree, whole file with the changes in place, change navigation and minimap — with the AI's report on the left instead of the review report. The server routes behind both viewers are now shared, so there is a single implementation to maintain. .env.exampleis in English, documents the GitHub TLS variables (GITHUB_CA_CERT,GITHUB_INSECURE_TLS) and makes clear that forge API tokens are not set there — they live in Settings. It also carries a ready-to-uncommentNO_PROXY/no_proxypair listing the hosts the agent CLI calls, with the two error messages that tell you it is time to uncomment them.
Fixed
- The ticket and forge links were being cut off. On a merge request to review, they came last on the identity line — after the project path, the author and the date — and that line is truncated to the width of the card, so they were the first thing to vanish behind the ellipsis. The longer the project path, the more certain it was. They now have their own line, where they wrap instead of being cut, each with an icon telling the ticket from the merge request. A card with neither link does not pay for an empty line. What stays on the identity line — project, author, date — can still be truncated on a very long project path, so hovering it now shows the full text; the tooltip only appears when the text really is cut, and goes away when the window is widened.
- A card could keep showing stale details. The check that decides whether a list needs redrawing did not look at the project, the author, the date, the branches or the ticket, so a renamed repository, a ticket attached after the fact or a changed target branch stayed on screen in their old form until a full reload. The check now covers everything the card shows.
- "t is not a function" instead of "Session not found". Six routes named their local variable after the translation helper, so asking for a session that no longer exists — a stale tab, a bookmarked link, a deleted session — answered with an internal error message that told the user nothing. They now say what happened.
- A network failure no longer masquerades as a login problem. The Copilot CLI says "authentication" in two very different situations: when the token is missing, and when it found a token but could not reach GitHub to validate it. Mergerie only looked for the word, so a machine behind a corporate proxy was told its authentication was missing and sent off to run
/login— which fixes nothing. Transport-level signals (network fetch failed,ECONNRESET,tunnel error, DNS failures…) are now recognised first and produce their own message, naming the hosts to allow and theNO_PROXYentry to add. The authentication message is unchanged when it really applies. - Labels name the right forge. On a GitHub repository, the inline comment button said "Send to GitLab"; the same applied to the MR comment section, the merge and "already merged" tooltips. Every user-facing label now follows the repository's forge, and the ones that span all repositories (fetch MRs, restore safety note) no longer name a single forge. The inline comment editor was also still hardcoded in French — it is translated now.
- Search fields no longer rebuild their list on every keystroke. The session and Docker Compose searches are debounced: typing an 8-character query now rebuilds the list once instead of eight times.
- Statuses update as soon as a job starts. Launching an iteration left the card on its previous status ("pushed") until the page was reloaded: the lists were only refreshed when a job ended. They now refresh when one starts too, so the badge switches to "running" on its own.
- The follow-up form closes once the request is sent. Asking for a fix (coding session, off-repo coding or exploration) left the text box open with its content, which read as if nothing had been submitted — the form now clears and closes on success.
- The score shown in the list is the one from the latest review. A re-review usually recalls the previous score in its opening summary ("6.4 → 7.8"); the extractor read the report from the top and returned that older score, so the list stayed stuck on the first review's result. It now reads the score that concludes the report. Scores already stored in the database are left untouched and are refreshed the next time each merge request is reviewed.
- GitHub URL and token are actually saved. Both fields were displayed and accepted input but silently dropped on submit, because the settings form saves through an explicit whitelist they were missing from. A static check now fails when a form field is not wired to that list.
1.0.0
First public release — see the README for what the tool does.