Start a server, stop it, run it at login, keep it updated, and let a browser on another machine reach it — the pages for users, backups and settings all start from a running one. The server is yours: it runs on your machine, holds one SQLite file and a directory of screenshots, and answers the browser extension and any AI agents you point at it. It makes no call that leaves your machine, and nobody else can reach it unless you arrange for them to.
Prerequisites
- The server installed. Setting one up from nothing, on this computer or on another machine, starts at Install a server.
Install with a package manager
Take this way when you want the package manager to own the install and the updates. It needs Node 24 or later and any of the four package managers; npm comes with Node, so if you have Node you already have one.
-
Point the
@commentware-privatescope at the package registry,https://registry.commentware.com, so that your package manager fetches the server from it rather than from npm. Run the command for your package manager, or for yarn and bun write the file it shows:pnpm config set @commentware-private:registry=https://registry.commentware.com/It writes ~/.npmrc, the file the install below reads. No flag: that is where this command goes by default.
npm config set @commentware-private:registry=https://registry.commentware.com/It writes ~/.npmrc, the file the install below reads. No flag: that is where this command goes by default.
In
~/.yarnrc.ymlnpmScopes: commentware-private: npmRegistryServer: "https://registry.commentware.com/"Yarn 2 and later ignores .npmrc. `yarn config set … --home` writes this file, but only from yarn 2 and later: yarn 1 takes the same command, says it worked, and writes somewhere yarn 2 never reads.
In
~/.npmrc@commentware-private:registry=https://registry.commentware.com/bun reads ~/.npmrc and has no command that writes it. npm's command above produces exactly this line.
The command writes
~/.npmrc, which is where this has to go. Yarn and bun get the file instead of a command, and it is the one in your home directory — not one in a project. Learn more about why it is the home directory, not a project. -
Install and start the server with your package manager:
pnpm add -g @commentware-private/cli-backend commentware startpnpm needs `pnpm setup` run once before it will install a global command. It refuses with that instruction if you have not.
npm install -g @commentware-private/cli-backend commentware startnpm install -g @commentware-private/cli-backend commentware startYarn 2 and later has no global install. npm comes with Node, so it is already on this machine.
bun add -g @commentware-private/cli-backend commentware startbun installs it and then tells you to put its global bin directory on PATH. Until you do, `commentware` is not found.
It binds
7042on127.0.0.1and then runs in the background until you stop it. -
Press Enter at each of its three questions to take the default.
-
The start prints no connection string, so mint one for
adminand copy it. Keys are stored hashed, so this is the only moment it is legible:commentware users generate 1
The installer refuses a first install while this commentware is on
PATH, so use one way per machine. Learn more about how the install
works.
Start the server
-
Run the start command:
commentware start -
On a first start, answer its three questions, or press Enter for each default.
At a terminal, the server runs in the background: the command prints what the
server printed while it started, then its process id and its log, and gives
you the terminal back. If it cannot start — another server holds its database,
or the port is taken — the command says why and exits with an error.
commentware logs prints what a background server has written since, and -f
keeps printing.
If you want to watch it in the terminal instead, pass --foreground. A start
that is not at a terminal stays in the foreground on its own, so a service
manager, a container or a script that runs commentware start keeps the
process it started. A tool that gives its tasks a terminal of their own, such
as a task runner with a full-screen view, needs --foreground passed
explicitly.
Stop the server
-
Run:
commentware stop
stop stops the server this directory addresses — the one the directory’s config
file names, or the machine’s own
server when there is none. It asks the server to stop and waits while it
finishes the requests it is already answering, then prints the address and
process id of the server it stopped. A server kept in the foreground also stops
on Ctrl+C, the same way.
On Windows the server stops at once, so a request it was answering is cut. The database is not harmed.
Run it at login
A background server keeps running until you stop it or the machine restarts.
To have it start at login and come back after a crash, hand it to your
system’s service manager — systemd on Linux, launchd on macOS. Windows has no
service install; there, start the server with commentware start after each
login.
-
In the directory whose server should start at login, stop that server if it is running, because the service starts its own and a second server on one database is refused:
commentware stop -
Install the service:
commentware service install
The service starts the server for the database this directory addresses, with
the config file in force named outright, and writes its output to the same log
commentware logs reads. After your next login, commentware servers lists
it. commentware stop still stops it, and it stays stopped until the next login
or until you run commentware start.
At a terminal without --foreground, commentware start starts the service
instead of a second server beside it. That start refuses --port, --host,
--name and --public-origin, because the service runs with the arguments it
was installed with. To change one, run commentware service uninstall, then
commentware start with the flag. commentware service uninstall stops the
service and removes it.
On Linux, systemd stops your services when you log out. If you want it running
while you are logged out, run loginctl enable-linger once.
What the first start does
It asks three questions, once, on the run that brings a server into existence: where your comments should live — this machine, or this directory — which port to serve on, and what the server should call itself. Each has a default, so three returns is a complete answer, and it writes what you said into a config file.
It asks only when all three of these are true: nothing is configured anywhere
yet, there is no database at the path it resolved, and you are at a terminal.
Anything scripted therefore never sees a prompt. --no-setup turns the
questions off explicitly, for a terminal that is interactive but unattended.
-p and -n are answers, not overrides. commentware start -p 8080 on a
first run does not ask about the port, and 8080 is what goes into the config
file — so the run you started and every run after it agree, and a connection
string you paste into the extension keeps working. -H is deliberately not one
of them: binding wider than loopback is a decision you make per run, not a
setting a first run writes down for you.
Then, in this order: opens the database, migrates it, takes its locks, creates two users if there are none, runs the retention purge, and binds.
Then it prints where everything is — the address, the discovery URL, the database, the screenshots, the config file in force, the MCP endpoint, and the change channel. Those lines are the fastest answer to “which server am I actually talking to”.
The two users it creates are admin and agent, and neither holds a key
yet. A start prints no key at all: its output goes to a log, a service
manager’s journal or an agent’s shell, and a key written there is a disclosure
nobody chose. It names each user’s id instead, and the command that mints
admin’s connection string:
Created the default users: admin (id 1), agent (id 2)
Get admin's connection string with "commentware users generate 1".See Manage users and access keys.
Where the data goes
Two paths, and the second follows the first:
- The database, a single SQLite file.
- The screenshots and attachments, a directory beside it.
With nothing configured, they are yours rather than this directory’s — one
server that every commentware command on the machine reaches, wherever you are
standing when you run it.
| Your system | Database and screenshots |
|---|---|
| Linux | $XDG_DATA_HOME/commentware/, or ~/.local/share/commentware/ |
| macOS | ~/Library/Application Support/Commentware/ |
| Windows | %LOCALAPPDATA%\Commentware\ |
That is the default and not a rule. A directory can have a server of its own — a client project whose comments should not mix with everything else, a checkout a whole team shares — and that is what the config file is for.
Give a directory its own server
If you want a directory’s comments kept apart from everything else, such as a
client project or a checkout a team shares, give the directory a config file.
Every commentware command run in it, or below it, then addresses its server.
Learn more about how a command finds its server.
-
In the directory, write the config file. Give it a port no other server on this machine uses, since the machine’s own server takes
7042; the example uses 7100.-nsets the name, and--forcereplaces a file that is already there:commentware init -p 7100 -n "Design review"It writes
commentware.config.json, with the database under.tmp/comments/, and starts nothing:Wrote /home/alex/review/commentware.config.json database /home/alex/review/.tmp/comments/data.db blobs /home/alex/review/.tmp/comments/blobs port 7100 name Design review Start the server with "commentware start". -
Start the server:
commentware start -
Optional: commit
commentware.config.json, so your teammates’ and your agents’ commands in the checkout reach the same server. Add.tmp/to the checkout’s.gitignorefirst, or the database is committed with it.
To change what every directory without a file of its own reaches, run
commentware init -g instead. It writes your own config file.
Run commentware where in the directory, or any directory below it, to see
which file is in force and which database it names. Every key the file may hold
is in commentware.config.json.
Choose the port and the interface
The default is 7042 on 127.0.0.1, which is reachable from this
machine and nowhere else.
-
Pass the port, and the interface if not loopback, to
start:commentware start --port 7100 --host 0.0.0.0
Binding anything but loopback prints a warning, and the warning is the point: everything this server accepts crosses the network in plaintext. If it is reachable from anywhere but your own machine, put TLS in front of it.
Reach it from another browser
Two ways, and the first is usually right. Either way the server cannot know the address you reach it at unless you tell it, and which of the two you did decides how.
- Choose a way in:
- Forward a port, over SSH or whatever tunnel you already use. The server stays on loopback and nothing is exposed.
- Bind an interface and put a reverse proxy with TLS in front of it. The same binary is meant to run this way.
- Tell it the address: behind a proxy, set
publicOriginonce; over a forwarded port, pass--portto the command that prints the address. Both are below.
Behind a reverse proxy, tell the server once: set publicOrigin in
commentware.config.json, or pass --public-origin to start. That is the
only route that reaches the addresses the server writes down rather than the
ones a command happens to print — every comment permalink an agent is handed,
and the OAuth issuer its tokens are bound to. It is also what the server
answers to: a request whose Host names an address it was never told is
refused, so a proxied server reached at a public name, or any server reached at
an mDNS .local, container or tailnet name, answers 403 to the extension’s
first call until you set it. See the
publicOrigin
key.
Over a forwarded port or a tunnel there is nothing to tell it, because the
address is yours rather than the deployment’s and the next person forwards a
different one. Tell the command instead: --port, on users new and on mcp.
Neither binds anything, and neither is read by the running server — on a
deployment that set publicOrigin the printed address is that one and the
command says the flag was not used. See An address your browser can reach.
Update the server
If ~/Commentware/server exists, you installed with the installer. Otherwise
you installed with a package manager.
-
If you installed with the installer, run the install command again:
macOS and Linux
curl -fsSL https://commentware.com/install/server.sh | shIt lands in ~/Commentware/bin, which it adds to your PATH. Open a new terminal afterwards. Run this command again to update the server.
Windows
iwr -useb https://commentware.com/install/server.ps1 | iexPowerShell 5.1, which is what Windows ships. It lands in %USERPROFILE%\Commentware\bin, which it adds to your Path. Open a new terminal afterwards.
If this computer has the extension, the run updates it too: follow the page the installer opens in Chrome. Learn more about what a run installs and updates.
-
If you installed with a package manager, run its install again:
pnpm add -g @commentware-private/cli-backendpnpm needs `pnpm setup` run once before it will install a global command. It refuses with that instruction if you have not.
npm install -g @commentware-private/cli-backendnpm install -g @commentware-private/cli-backendYarn 2 and later has no global install. npm comes with Node, so it is already on this machine.
bun add -g @commentware-private/cli-backendbun installs it and then tells you to put its global bin directory on PATH. Until you do, `commentware` is not found.
The package manager replaces the server’s files in place, so the pages of the running server can fail to load until the restart. Restart right away.
-
Restart the server, so that it runs the newly installed version:
commentware restartA server that an older version started cannot be restarted: stop it with
commentware stop, then start it again the way you started it, with the same--hostand--public-origin.
restart keeps the settings the server started with, and under a service it
goes through the service. Learn more about running it at login.
An update that changes the database’s shape backs the database up before it runs, and refuses to run if it cannot. Learn more about the backup a migration writes.
Run one server per database
start takes a lock on the database and another on the screenshot directory, and
refuses to be the second server on either. The refusal names the process holding
it and the address that process bound.
A server that crashed leaves its lock files behind, and the next start takes them: the operating system releases a server’s lock when the server’s process ends, however it ends. A lock written by an older version is judged by its process id instead, and the refusal names that lock file, to delete if the process is long gone.
There is no --force. Two servers writing one SQLite file is data loss with no
error attached, and the screenshots are locked separately because two servers
with different databases can still be pointed at one directory of blobs — where
each one’s purge would delete the other’s screenshots.
commentware stop releases both locks on the way out, after the server has
finished what it was doing.
commentware lists every command and the options it
takes, for the newest release. commentware --help lists the commands your
version has, and every command takes --help of its own.
Check that it worked
The start prints where everything is: the address, the discovery URL, the
database, the screenshots, the config file in force when there is one, the MCP
endpoint and the change channel. commentware servers lists every server
running on this machine, wherever it was started, and this one among them.
From another machine, the extension connects with a connection string that
names the address you reach the server at.
Next steps
- Manage users and access keys: mint a connection string for another person or an agent.
- Back up and restore: back the database up, and put a backup back.