Sync the self-hosting stack

This commit is contained in:
2026-08-24 13:02:29 +02:00
parent 4fa9cabefb
commit 0674e550f1
4 changed files with 818 additions and 108 deletions
+313
View File
@@ -9,6 +9,319 @@ one of them changed. An entry says which artefact and which version, so `web 0.1
Every version published to a channel appears here. Nothing is written from memory afterwards: a build
cannot be published without its entry.
## 2026-08-24 — Losing your database no longer puts your instance up for grabs `api 0.88.0` `web 0.111.0`
**If your database is ever lost or replaced, your instance was claimable by whoever loaded the page
first.** From the outside it looked exactly like a brand-new deployment — no accounts, no completed
setup — so the install screen opened its 30-minute window and offered a super-admin account. Except
it was not a new deployment: it was yours, on a hostname already in DNS, already in people's browser
history, and already dialled by every agent you have enrolled.
We found this the way these things get found. A `docker compose down -v` meant for a throwaway test
stack landed on a production one, because the compose file that had been copied into that directory
carried its own project name. The database went. What was left was an instance offering itself to the
internet.
**What changes.** An instance that cannot prove it is new still opens the window — you need a way back
in — but creating the first administrator now costs the last characters of your vault master key.
You have it, in your `.env` or on the `jarvis_secrets` volume you were told to back up separately.
Nobody else does.
**A genuine first installation is never asked for it**, and neither is a restart during a slow one.
The test is the age of the vault key at the moment your database first saw it: seconds on a real
first boot, months on a replacement. It is recorded once, so restarting the api to re-open a window
does not change the answer.
**Nothing to do.** No new variable, no migration step. Instances that upgrade into this keep working
exactly as they are — the rule only ever applies to an instance with an empty database, which yours
is not.
## 2026-08-24 — A friendlier install, and a vault key you can only be handed once `api 0.87.0` `web 0.110.0`
**The install screen leads with Jarvis now.** The mark, the name and a welcome come before anything
is asked of you — the first thing this product ever showed a new deployer used to be a password
field with no explanation attached. Ten steps, about five minutes, and the road map on the first
screen is honest about which ones you can skip.
**Only the address really needs you.** The model step used to refuse to continue without a model id
_and_ a key, which trapped anybody evaluating Jarvis without a provider key in hand — on a product
whose remote terminal, agent fleet and vault all work perfectly well without one. An untouched form
now continues and saves nothing. A half-filled one still refuses: that is a mistake rather than a
decision.
**The wizard now asks who may create an account.** Self-registration defaults to open, and nothing
in the install had ever mentioned it — so an instance on a public hostname would accept an account
from anybody who found it, the moment you finished. It is a switch on the address step, beside the
field that decides who can reach the sign-in page at all. Change it later under **Settings →
Platform → Sign-in**.
**The vault key is shown, and downloadable, exactly once.** The install screen hands you the file
rather than telling you to go and run `docker compose exec` — that command is a wall for anybody
deploying through Coolify, Portainer or a managed host, and what is behind the wall is the one value
no backup can reconstruct. The screen says so before you click. Afterwards, and any time later, the
key is on the host:
```sh
docker compose exec api cat /var/lib/jarvis/secrets/vault-master-key
```
### Fixed
- **An interrupted install could not be finished.** Coming back to the wizard after the organization
step showed you an empty form and demanded a name, and the request behind it could only fail —
the community edition allows one organization and you already had it. There was no way forward and
no way around. It now recognises the organization you already have and moves on.
- **A first boot with no configuration printed a red `ERROR` about `JARVIS_UNATTENDED`** on
instances where it was not set. Cosmetic, but it was the first thing a new deployer read in
`docker compose logs`.
- **`JARVIS_ADMIN_EMAIL` and `JARVIS_ADMIN_PASSWORD` alone would install the instance silently**,
with no `JARVIS_UNATTENDED=on`, and skip the wizard entirely. Those variables are what an
unattended install needs _in addition to_ the flag, never a second way of asking for one. If you
keep them in a shared shell or a fleet template, this is the release where they stop acting on
their own.
- **Installing in German or French left you in an English console** — the account the wizard creates
now records the language you installed in.
### Changed
- `JWT_ACCESS_TTL` and `JWT_REFRESH_TTL` are read from `.env` like every other tuning value
instead of being fixed in the compose file. `.env.example` documents what each actually does —
the refresh one is an idle timeout, not the session lifetime its name suggests.
- `PUBLIC_URL` is gone. It was a second variable for the same address as `WEB_ORIGIN` and had not
been read by anything for two releases; it is the stored instance address now, on a settings
screen. Remove it from your `.env` if it is still there — nothing breaks either way.
### New in the manual
The published README grew the procedures it was missing: restoring the vault key onto a new host
(**do it before the first `up -d`** — a generated key is never overwritten, so bringing the stack up
first makes yours unusable), getting back in when you are locked out of the only administrator
account, moving an instance to a new address and what that does to enrolled agents, and which
generated secrets can be rotated.
## 2026-08-24 — `JARVIS_TELEMETRY=off` did not work, and now does
**If you set `JARVIS_TELEMETRY=off` in `.env`, your instance has been reporting anyway.** We are
sorry. The variable never reached the container: compose reads `.env` to fill in `${...}`
placeholders inside the compose file, it does not hand that file to the services, and the `api`
service never listed this one. So the API saw nothing, applied its documented default of "on", and
checked in — while the README, the changelog and `.env.example` all told you that one line was
enough.
What was sent is what the README has always listed and nothing more: your instance id and public
key, the version and contract hash it runs, its public address, and counts of organizations, users,
agents and assets. No names, no conversation content, nothing about the machines you administer.
**The fix is in the compose file, not in the application**, so pulling this repository again is the
whole of it:
```sh
git pull # or re-download docker-compose.yml
docker compose up -d
```
Then confirm it took, from the instance itself:
```sh
docker compose exec api printenv JARVIS_TELEMETRY
```
No output means the fix has not landed yet; `off` means you are silent. **Settings → Licence** says
the same thing on screen, and that is the answer to trust — it reads what the API actually resolved
rather than what a file claims.
If you would like the entries a silenced instance should never have created removed from our side,
write to <antoine@luxit.be> and quote the instance id from that screen.
## web 0.109.0 — 2026-08-24
**The welcome now comes before the account.** The very first thing anybody saw of Jarvis was a form
asking for a password — no name, no explanation, no idea what they were about to be given
administrator rights over. The introduction needs no account, so it goes first, and creating the
administrator is step two with a way back to it.
**Mail and the licence are two steps.** They shared a page and have nothing to do with each other —
one is an app registration in your Entra tenant, the other a key from your supplier — which made one
long screen out of two short questions. The licence step now leads with the thing most people need
to hear: you almost certainly do not need a key, and the community edition is perpetual.
## web 0.108.0 — 2026-08-24
**The install opens on a welcome rather than on a checklist.** It used to begin with "Checks:
database, Redis, vault key" — which tells somebody who has just deployed a product they have never
run that they are already in the middle of something. The first screen now introduces Jarvis, says
what the next steps will ask for, roughly how long it takes, and which of them you can skip.
**The checks moved to the end, and that is a correction rather than a preference.** Run first, they
had nothing to look at: your public address had not been chosen, so there was no URL to probe and no
hostname to judge security keys against — three of the six findings were about a deployment that did
not exist yet. They now run immediately before the screen that commits the install, against the one
you have just described.
**Reporting has a step of its own.** It shared a page with mail and the licence, where a question
about what leaves your network sat underneath two forms. It is the only decision in the wizard we
benefit from, which is exactly why it gets a page you cannot scroll past.
**The step markers no longer collide.** Eight labels never fit the wizard column at any screen width
and ran into each other. The strip is markers now — filled where you are, ticked behind you — with
the step named in full underneath and the whole road laid out on the welcome screen.
## api 0.86.0 · web 0.107.0 — 2026-08-24
**Mail and the licence are configured IN the wizard now, not somewhere else.** That step used to
show two paragraphs whose only affordance was a link to the settings screens — and those links could
not work: an instance that has not finished installing sends every other address back to the install
screen, so clicking one opened a tab that bounced straight back. The real forms are on the step now,
the same ones you meet under Settings afterwards, and nothing on it is required.
**You can decide there whether this instance reports to us.** Reporting used to be an environment
variable and nothing else, so a fresh install had no way to answer the question without editing a
compose file. It is a switch on that step and on Settings → Licence.
`JARVIS_TELEMETRY=off` keeps its authority: an instance whose host has switched reporting off shows
the control locked and says why. Deciding what leaves your network stays with whoever runs the host,
which is exactly why it was a variable in the first place — the switch adds the case where the person
installing the instance IS that person, and the case where you want to fall silent later without a
restart.
**Your vault key is a download.** The last step used to print `docker compose exec api cat …` and ask
you to go and run it. If you deployed through Coolify, Portainer or a managed host, that was a wall
in front of the one thing here that no backup can reconstruct. Now the key is shown on the page with
a button that saves it as a file, and the command is still underneath for anyone who would rather
take it off the host.
That view exists only while the install is unfinished. Once you press Finish it is refused for good,
and every time it was used is in the audit trail.
**Unattended installation, for fleets and for CI.** Set `JARVIS_UNATTENDED=on` with
`JARVIS_ADMIN_EMAIL` and `JARVIS_ADMIN_PASSWORD` and the instance installs itself at boot from the
variables you already provide, and never shows the wizard. Everything else stays optional.
If those credentials are missing or the password is under twelve characters it says so loudly and
leaves the install UNFINISHED rather than completing. An instance marked installed with no account
is one nobody can ever get into, and no restart recovers it — falling through to the ordinary install
screen is strictly better.
## web 0.106.3 — 2026-08-24
**The install screen tells you where you are.** Its step list was six labels in a row where the
current one differed by a font weight — and the difference did not even arrive, because the class
meant to dim the others named a colour this console does not define. Every label rendered
identically, so the one screen whose whole job is to walk you through six steps could not say which
of them you were on.
The stepper now carries that three ways at once, none of them colour alone: a tick for what is done
and a filled number for where you are, connectors that fill in behind you, and a line that names the
step — "Step 3 of 6 · The model" — which is also what makes it readable on a phone, where the labels
step aside.
The same missing colour had flattened the rest of the wizard: hints and explanations rendered as
bright as the headings above them, error messages were not red, and the boxes around the warnings
had no edge. All of it reads properly now.
## api 0.85.3 — 2026-08-24
**An instance still being installed no longer reports itself.** It used to check in thirty seconds
after boot, before anybody had chosen its address — so a fresh install announced itself as
`http://localhost:3000`, with every count at zero. That is worse than silence: the address exists in
the report so that your provider can tell one installation from another, and a list of identical
localhost entries answers nothing.
It now waits until the install screen is finished, then reports normally with the address you chose.
Nothing is lost, only deferred. `JARVIS_TELEMETRY=off` still silences it entirely.
## web 0.106.2 — 2026-08-23
**A language picker on the install screen.** Every other page that can be reached without an account
has one — the sign-in page, a shared transcript — and the install wizard, which is the longest piece
of reading this product puts in front of somebody who has not yet decided to trust it, did not.
It follows your browser as before; the picker is for the case the browser is wrong, which is
routinely: installing from a colleague's laptop, or on a server whose locale nobody set. Before the
first account exists the choice is remembered in this browser; after it, it is saved to your account
as well — so it also corrects the language the claim guessed.
## api 0.85.2 · web 0.106.1 — 2026-08-23
**Installing in German now ends in a German console.** The install screen has always followed your
browser, in English, French or German — but the account it created took the database default of
English, and the console adopted that the moment the wizard handed over. Somebody who had just read
seven screens in their own language was greeted in another and left to find the language switcher.
The account now records the language the wizard was read in. Change it whenever you like under
Settings → Profile; this only decides where you start.
## api 0.85.1 — 2026-08-23
**A fresh install no longer stores an address nobody chose.** api 0.85.0 wrote
`http://localhost:3000` as the public address of any instance that started with no configuration —
the schema default for `WEB_ORIGIN`, saved as though somebody had decided it. The boot banner then
told an operator on a remote host to open a URL that leads nowhere.
The address is now left unset until you choose it, which is what the install screen already assumed:
it fills the field from the address you are reading it at, and the checks say plainly that nothing is
set yet. The banner names the path and not the host — you know how you reach the machine, you were
only missing `/install`.
Nothing to do if you set `WEB_ORIGIN` yourself: it is still read, once, exactly as before.
## api 0.85.0 · web 0.106.0 — 2026-08-23
**Installing Jarvis no longer starts with a text editor.**
```sh
docker compose up -d
```
Then open it in a browser. An install screen creates the first administrator, checks the deployment
and asks for the rest. **The `.env` step is gone** — it demanded six values before the stack would
start, four of them secrets you had to generate with `openssl`, and the whole file is optional now.
**A wrong model key is a message instead of a crash loop.** This is the change underneath all the
others. The api validated its configuration at boot and called `process.exit(1)` when anything was
missing — so a mistyped key, an account out of credit or an endpoint that had moved presented as a
container that would not stay up, with the actual reason on line 40 of a log you had no reason to
open. An unconfigured instance now starts, says what it needs, and the model screen has a **test
button that asks the model for a token before saving**, showing the provider's own words when it
refuses.
**A brand-new instance can be claimed for 30 minutes, and this closes a real hole.** Jarvis used to
accept exactly one registration on an instance with no users and make that account super-admin — so
a freshly deployed instance reachable from the internet belonged to whoever found it first, on a
product that holds SSH keys and opens shells on your clients' servers. The install screen shows a
countdown; `docker compose restart api` opens another window if you miss it.
**Everything the wizard asks has a permanent screen.** Settings → Platform gained two tabs: **Model**
— endpoint, key, model and thinking level, with the same test button the wizard uses — and
**Address**, for your public address and proxy-hop count. The wizard is a first-run convenience, not
the only way in: an instance whose OpenAI key has been rotated, or whose hostname has moved, says so
on a settings page rather than being re-installed.
**The proxy setting is now something you are shown rather than asked to guess.** `TRUST_PROXY_HOPS`
decided which address landed in your audit trail, and nobody can know it in advance. The install
screen displays the `X-Forwarded-For` chain your own request actually carried and the address the
API resolved from it, and you confirm what you see.
**Your secrets are generated for you, into a new `jarvis_secrets` volume.** Back it up, **separately
from the database** — the vault key lives there and nowhere else, and a database backup holds only
ciphertext. The install screen will not finish until you have read the key and typed its last
characters back. The key never leaves the server: there is deliberately no endpoint that returns it.
### Upgrading from an earlier build? There is nothing to do
Leave your `.env` exactly as it is. Your secrets are **adopted** into the new volume rather than
replaced, so the vault is untouched. `WEB_ORIGIN` becomes the stored public address, your `OPENAI_*`
values become the stored model settings, and an instance that already has an administrator is marked
installed by a backfill — **you will never see the install screen**. Everything those variables used
to govern is now a settings page; the variables still seed a fresh install and are otherwise ignored.
One thing did change for you: **`PUBLIC_URL` is no longer read.** It was a second variable for the
same address. There is one now, seeded from `WEB_ORIGIN` and edited under Settings → Platform.
**Changing your public address orphans enrolled passkeys.** It always did — a passkey is bound to the
hostname it was created under — but it was previously a variable nobody edited twice. Now that it is
a field on a screen, the screen warns you before it saves.
## api 0.84.0 · web 0.105.0 — 2026-08-21
**Ask for a licence from inside Jarvis.** Settings → Licence has a form: your company, somebody to