The box updates itself
A box installed with curl -fsSL https://v-code.dev/install | sh checks for a
new signed release every hour. It installs it only while no thread is working.
The shell panel keeps running through the update. It goes
back to the old version if the new one does not come up and stay up.
Why you would use it
You want new versions on the box without logging in to it, and without an update cutting off a turn the agent is in the middle of, or a command you left running in the shell panel.
How to use it
There is nothing to turn on. The installer enables v-code-update.timer.
- To see when the next check runs:
systemctl --user list-timers v-code-update.timer. - To check now:
~/.local/share/v-code/current/install.sh update. It runs the same updater the timer does, with the same rules. - To read what it did:
journalctl --user -u v-code-update.
A box installed from a git clone has no timer. Update it with update-the-install.
On a Mac (install-on-macos) the timer is the launch
agent dev.v-code.update, which runs the same updater every hour, starting an
hour after it is loaded. To check now: the same install.sh update. What it
did is in ~/Library/Logs/v-code/update.log. Where these pages say systemd,
the Mac asks launchd: launchctl print gui/<uid>/dev.v-code.server for whether
VCode runs, its runs count in place of NRestarts, and
launchctl kickstart -k to restart onto the new version.
What you see
Nothing in the app. The updater writes to the journal, each line starting with
v-code::
| Line | Meaning |
|---|---|
up to date: <installed> (the newest release is <v>) |
Nothing newer. |
a thread is busy; <v> waits for the next run |
A thread has work. It tries again in an hour. |
a command runs in the shell panel (<command>); <v> waits for the next run |
A pane in the shell panel runs something other than a shell. It tries again in an hour. |
a command has run in the shell panel (<command>) for 86400 s or more; updating anyway |
The shell panel has been busy for a day. The update goes ahead and the restart ends that command. |
VCode on 127.0.0.1:<port> did not answer; <v> waits for the next run |
The unit is active but did not answer. |
VCode did not answer and systemctl --user did not either, so this run cannot tell whether VCode is running; <v> waits for the next run |
Neither VCode nor the user manager answered. The run counts the box as busy. |
VCode is not running, so no turn can be cut off |
systemd says the unit is not running. It goes ahead. |
updating <old> to <new> |
Downloading, then switching. |
updated to <new> |
The new version answered and stayed up. |
<old> is still the version running: <new> was never started; switched back to <old>; <new> is tried again next run |
The restart never reached the new version. It is not rejected. |
<new> did not come up within 30 s, and VCode was down before the switch; switched back to <old>; <new> is tried again next run |
The box was already down, so the release is not blamed. It is not rejected. |
<v> was rolled back before; waiting for a newer release |
That version failed here once and is never tried again. |
another install or update is running; trying again next run |
Another run holds the lock. |
A rollback exits 1, so systemctl --user status v-code-update shows it failed:
<new> did not report itself running within 30 s; rolled back to <old>, and <new> will not be tried again,
or <new> came up but did not stay up; … when it answered once and then did
not answer 5 s later, reported another version, or systemd restarted it in between.
A switch back that does not reject the release exits 1 too.
Options and settings
| Option | Default | What it changes |
|---|---|---|
OnBootSec |
2min |
First check after boot. A timer started later than that fires at once, so a fresh install checks right away |
OnUnitActiveSec |
1h |
Time between checks |
RandomizedDelaySec |
5min |
Spreads boxes out so they do not all fetch in the same minute |
TimeoutStartSec |
30min |
A hung download is stopped, so later runs are not held back |
Limits and known gaps
- The updater needs
AUTH_TOKENin~/.config/v-code/envto ask VCode whether it is busy, and reads the port fromVCODE_PORTthere. Without the token the run stops:no AUTH_TOKEN in <env file>, so VCode cannot be asked whether it is busy. Without the file it stops too:no env file at ~/.config/v-code/env: run ~/.local/share/v-code/current/install.sh install. - A box installed before the rename to VCode keeps its old updater, which
reads
latest.json. That pointer stays at the last release before the rename, so the box stays on it until you run the install command once (install-on-linux). That install moves the box to the new names and puts this updater in its place.install.sh install --from-updatenever does the move: on a box that still has an old name it stops withthis box still has names from before the rename to VCode: run curl -fsSL https://v-code.dev/install | sh first. - A box whose threads are always busy never updates.
- On Linux VCode starts the shell panel's tmux in a systemd scope of its own
(
systemd-run --user --scope), so a restart leaves the panel and whatever runs in it alone, and holds nothing back. A panel whose tmux was started inside the unit is different: a version before 2026.09.28 started it there, and so does a box wheresystemd-runfails, and on a Mac VCode cannot tell. There a pane left invim,less,htopor a server holds updates back until you quit it, or for 24 hours, whichever comes first. After that the update restarts VCode and the command ends with it. A pane at the prompt ofbash,zsh,sh,fish,dash,ksh,tcsh,csh,nu,elvishorxonshholds nothing back. - The route answers 403 on a server with no
AUTH_TOKEN:the updater needs AUTH_TOKEN set on the server. - Run from inside a VCode thread,
install.sh updatefinds that thread busy and waits for the next run. - It never moves to an older or equal version, and never to one in
rejected. - A new version that answers but reports a busy thread is not rolled back until
its threads are idle:
…; <new> will not be tried again, and the rollback to <old> waits until no thread is busy. - A download slower than 1 KiB/s for 60 s is given up on, and the run tries again next hour.
- After a first install whose
install.shdid not finish, it does not update:the install of <v> has not finished; run ~/.local/share/v-code/current/install.sh install. Not updating. - The phone's cached app shell still needs its own refresh (update-to-a-new-build).
Related
- install-on-linux — the install that sets this up
- install-on-macos — the same on a Mac, with a launch agent
- update-the-install — updating a box installed from a git clone
- logs-and-troubleshooting — reading the journal