Sync the self-hosting stack
This commit is contained in:
+313
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user