Skip to content

Laptop client guide

The winner client sends a developer's coding-agent sessions to their team's Winner AI deployment, from the repos they choose and no others. This page takes a developer from nothing to a laptop that pushes, on macOS or on Ubuntu or Debian: install, sign in, choose the repos, and what to expect afterwards. Client reference holds the detail behind each step.

Supported systems

System Versions Architectures
macOS 13 (Ventura) or later Apple Silicon and Intel (one universal binary)
Ubuntu 20.04 or later amd64 and arm64
Debian 11 or later; 12 on amd64 is the one validated amd64 and arm64

On Linux the installer refuses, before downloading anything, a machine whose C library is older than glibc 2.28 (the client's session collector, agentsview, needs it, and its project publishes no musl or static build), so Ubuntu 18.04 and Alpine are refused. It also needs ssh-keygen from OpenSSH 8.1 or later (the openssh-client package; ssh -V shows the version) to check the release signature. Requirements has the rest.

winner login and winner repos list the laptop's repos with git 2.36 or newer (git --version shows yours). The stock git of Ubuntu 20.04 and 22.04 and Debian 11 is older, and a Mac without the Command Line Tools has none. Those systems stay supported, so the installer warns and installs anyway; until git is updated, the first login on a newly enrolled laptop with coding sessions in a project folder says, for example, "Could not list this laptop's repos (git 2.25.1 found; listing repos needs git 2.36 or newer), so none are chosen and nothing is sent." Requirements says how to get git 2.36 or newer on each system and what to run after.

Windows is not supported in this release: the installer stops with "Windows builds are not published yet."

Install on macOS

Open Terminal and run the installer your team's control plane serves. Replace <control-plane-host> with the hostname your team's control plane runs at; whoever deployed it can give you the line with it filled in. Left as written the shell reads < and > as redirection and installs nothing.

curl -fsSL --proto '=https' --proto-redir '=https' https://<control-plane-host>/install.sh | bash

The two --proto flags keep the fetch on https from end to end: -L follows redirects, and without them a redirect to plain http would pipe unverified bytes straight into bash. A trial of the server serves plain http on loopback, which those flags refuse; for one, the line is curl -fsS --noproxy localhost http://localhost:4180/install.sh | bash, run on the trial machine itself. Any other laptop first needs the tunnel in A trial from the bundle, with port 4180 and the trial's POSTGRES_PORT free on it (not held by a stack of its own).

It needs no sudo and no GitHub account. It installs winner, and the session collector (agentsview) at the version the control plane runs when the laptop has none, into ~/.local/bin. It checks winner against checksums signed with the Winner AI release key, and the collector against its project's own checksums, which no one signs (Requirements). It records the control plane in ~/.agentsview/fleetview-control-url. If that folder is not on your PATH it prints the export PATH=... line to run; it ends by printing the winner login line to run next.

Run it in Terminal, not by downloading winner with a browser. A file a browser downloads is quarantined, and macOS refuses to run it; curl sets no such flag. If you did download it that way, clear the flag:

xattr -d com.apple.quarantine ~/.local/bin/winner

Running the installer again on a laptop that is already enrolled is safe: it replaces the binary and keeps the enrolment, the repo choice and the background push. Its "Next step" line can be ignored there.

What you see: the unsigned build

The macOS binary of this release is not signed with a Developer ID; that comes in a later release. Gatekeeper does not stop it, because the installer's download carries no quarantine flag. What you notice is the name: after winner login, macOS shows a "Background Items Added" notification named after the binary, "winner", rather than Winner AI.

The login installs three background items, listed under System Settings > General > Login Items > Allow in the Background:

Item (launch agent label) What it does
com.getwinner.push The background push: sends the sessions of your chosen repos as they change
com.getwinner.update The daily update: runs winner update at login and every day at noon
dev.winner.reporter The hourly reporter: tells the control plane the names this laptop pushes under, and the start commit of recent sessions in your chosen repos; sends the name and state of each repo and applies the choices made on the web page

Switching an item off there stops that job; switching off the push stops sending. On the current release winner login does not ask macOS for access to Desktop or Documents: the binary carries no signature macOS checks, so sessions in those folders are recorded without a start commit. A signed build changes this. It asks once, for the reporter: Folder access on macOS says what that reads. It asks only when a recent session ran in one of them, through a fourth, one-shot launch agent, dev.winner.folder-access, that login installs, runs and removes within the two minutes it waits for your answer; it is not one of the standing items. Whether macOS also announces it with a "Background Items Added" notification of its own has not been checked.

For IT: allowing the items with an MDM

The approved install path is the one above: each developer runs the curl installer, which installs to ~/.local/bin with no sudo. An MDM can then keep the three items on. A Managed Login Items policy (the com.apple.servicemanagement payload; JumpCloud offers it for macOS 13 and later) with three Label rules, one per label in the table above, approves them, and once applied users cannot switch them off. The one-shot dev.winner.folder-access job needs no rule: login removes it as soon as the folder-access question is answered or times out. A single Label Prefix rule cannot cover all three, because the reporter's label starts with dev.winner. and the other two with com.getwinner..

Check also that no endpoint security or binary allow-listing tool blocks unsigned executables in users' home folders.

Untested: that a Label rule approves an unsigned item has not been tried on a JumpCloud-enrolled Mac. Until it has, check it on one Mac before rolling the policy out.

Install on Ubuntu or Debian

Run the same installer line as on macOS (Install on macOS), in a terminal, with no sudo. It installs the static winner binary for your architecture, and the collector when the machine has none, into ~/.local/bin, under the same checksum checks as on macOS. On a default Ubuntu a new login shell puts ~/.local/bin on PATH once it exists, but the shell you installed from does not: run the export PATH=... line the installer printed, or open a new shell, before winner login.

Login installs a systemd user unit and two user timers in ~/.config/systemd/user/ (or under XDG_CONFIG_HOME when you set it): winner-push.service (the background push), winner-update.timer (the daily update) and winner-reporter.timer (the hourly reporter).

Machines with no login session

The push and both timers belong to your login session, which a laptop gives them. A machine you only reach over SSH starts no session at boot, so they wait until you log in unless you let your user manager linger. That needs no sudo on Ubuntu:

loginctl enable-linger "$USER"

Name the user: a bare loginctl enable-linger with no login session fails with "No such device or address".

A Linux machine that does not run systemd (WSL without systemd=true, most containers) gets no background push. Login warns that the push was not installed, and prints crontab lines for the daily update and the hourly reporter for you to add with crontab -e.

Sign in

winner login

--control-url https://<control-plane-host> is optional on a laptop the installer set up: login uses the flag, then FLEETVIEW_CONTROL_URL, then the control plane the installer recorded. Against a trial of the server it is --control-url http://localhost:4180.

Login first checks this laptop's collector version against the control plane's (The collector version ceiling). It then prints a code and the full address of the control plane's approval page. Open that address in any browser, on this laptop or on another machine, sign in with your work account and approve the code. Nothing listens on the laptop for the answer.

On a control plane that serves its own sign-in, the laptop talks only to the control plane; your browser is what visits your company's identity provider. A control plane without its own sign-in is the exception (What the laptop sends, and where).

Login then installs the background push and the two scheduled jobs, and, on a laptop with no repo choice yet, asks which repos to send (next section). winner login --no-service enrolls without installing any of them.

Choose which repos send

A laptop sends the sessions of the repos its developer chose, and nothing is chosen for you. A laptop that already has a choice keeps it, and login says "Repo selection kept: ..." without asking. Otherwise, at a terminal, login lists the repos this laptop's coding sessions ran in, with none ticked:

  • numbers and ranges tick and untick rows: 1 3 5-7;
  • a ticks all the repos shown except shared or separated names, n none of them;
  • /text shows only the repos matching text, / shows all again;
  • Enter goes on to one last question, what happens to a repo found later (1 ask, 2 block; Enter keeps the one shown), and the choice is saved after it; q quits without saving, and nothing is sent. Ending the input at either question quits the same way.

A login with no terminal chooses nothing and says so: "No terminal to ask on, so no repos are chosen and nothing is sent. Choose them with: winner repos pick". On a fresh machine where no coding agent has run yet there is nothing to list: "agentsview lists no repos on this laptop yet; nothing is sent. Choose them later with: winner repos pick". Use your coding agent once in a repo, then run winner repos pick. Where the collector or git cannot list the repos, login says "Could not list this laptop's repos (...), so none are chosen and nothing is sent. Choose them with: winner repos pick", with the reason in the brackets. Where a saved choice cannot be read, login says so, then "Choose your repos again with: winner repos pick".

The list comes from the collector, which the background push starts, so winner login --no-service usually cannot ask: unless a collector you started yourself is running, it ends with "agentsview is not running yet, so no repos are chosen and nothing is sent. Once it runs, choose them with: winner repos pick".

To see or change the choice later:

winner repos                    # every repo, grouped by what happens to it
winner repos list web           # only those whose name, path or remote holds "web"
winner repos pick               # the same list as at login, from your current choice
winner repos allow web-app      # send it, earlier sessions included
winner repos allow --all        # send every repo listed, except shared or separated names
winner repos block web-app      # stop sending its new sessions; those already sent stay
winner repos block --all        # stop sending any repo's new sessions
winner repos separate api       # give each checkout behind a shared name its own name
winner repos mode ask           # or block: what happens to a repo found later
winner repos apply              # re-apply ~/.agentsview/fleetview-repos.json after a hand edit
winner repos help               # the commands, then what is sent and what cannot be withdrawn

winner repos list reads from the collector, so it needs the collector running, as it is while the background push runs.

The first time it starts, the collector reads every coding session already on the laptop before it answers, which takes a while on a long history; the background push waits for that and pushes once it ends. Until then winner repos says agentsview is still starting and how far it has got, as the collector reports it (for example "initial sync: 300/321 sessions (93%) ยท 5120 messages"); run it again once it finishes.

winner repos allow --all leaves out a name that several checkouts share and a name that was separated, and prints "Skipped ..." for each, saying why; allow those by name.

A repo first seen after you chose is handled by the mode:

  • ask, the default: "New repos wait for you until you allow them; winner repos lists them as waiting."
  • block: "New repos are blocked and nothing asks you about them; winner repos still lists them."

What the client says of the repos you do not choose is: "Sessions from repos you don't choose stay on this laptop, unless one of them carries the name of a repo you chose." A Cursor session is named after its folder, not its repository root, so a folder that reads as a chosen repo's name is sent under it.

What was sent stays. Blocking a repo, or unticking it, stops its new sessions only: "Sessions already sent stay with your team." Nothing the client does deletes what was sent, and deleting sent sessions is not in this release. Allowing a repo works the other way: it sends that repo's earlier sessions too, not only new ones.

A repo's name is recorded from its folder name: the basename of the git root, with every - read as _ and case kept, so web-app and web_app are one repo. When two checkouts share a name, allowing it would send both, so the list and the picker never allow it and name the checkouts. winner repos separate <repo>, or winner repos allow <repo> at a terminal, asks for a new name for each checkout, suggesting owner/repo from its remote, before anything is sent; the new name is what your team sees. A shared name that was already sent cannot be separated: what was sent stays merged under it.

No winner command renames a repo already sent: the sessions sent stay under that name, because a rename would make the next push delete them from your team's server. winner repos rename <repo> only says so and changes nothing. A rename in the collector's own interface is not covered; see limit 3 below. A separation that stops partway keeps a folder rule under the name you chose for a checkout once that name was sent, or when the record of sent repos cannot be read, and says which and why: removing it would move that folder's sessions out of the name as surely as making one, so its new sessions go under that name. Blocking a repo already sent always works, and what was sent stays.

The collector's search index reads every session on the laptop, chosen or not, and sends its text to the embeddings endpoint its config names. By default that is the laptop's own localhost:11434, so nothing leaves the laptop, and no vector of a repo you did not choose reaches your team's database. If the endpoint is set to another host, the text of unchosen repos goes there too: the picker and winner repos help then name that host. The index cannot be switched off for one repo, only for the whole laptop.

The choice is kept on the laptop in ~/.agentsview/fleetview-repos.json, and only the laptop writes it; the names of its repos, unchosen ones included, do leave it (Choices made on the web page). A reinstall that removes ~/.agentsview removes it, and nothing is sent until repos are chosen again.

A laptop enrolled before repo selection existed sent every repo. Its next winner login, or its first winner update after the client that added selection is installed (the daily update runs it), allows every repo the collector lists then and records them as chosen, so it keeps sending what it sent and repos found from then on wait for you. If that cannot be done safely, the laptop keeps sending every repo, says why, and checks again at the next update or login; until then winner repos changes nothing and says so. The reasons: agentsview is not on PATH; it has not finished a push since it was installed or updated, or no push log shows one; its names cannot all be read, or its answers cannot be used as they are; or it holds sessions under a name the list would leave out. winner update tries only on a run that changed nothing: a run that replaced winner or the collector, or was due to, has not pushed with the new version yet.

A laptop with no background push, one enrolled with --no-service, is checked only after a winner login without --no-service.

Choices made on the web page

The web page is Your repos, at https://<control-plane-host>/repos, linked from a Member's Home page on the server.

On a laptop holding a laptop pass, with the background push installed, the hourly reporter also sends the control plane the name of every repo the collector lists here, chosen or not, each with its state: allowed, blocked, waiting for you, or shared by several checkouts. Nothing else about a repo leaves: no remote, no file name, and no path beyond what the name itself holds, which for Cursor is built from the folder's path. The control plane answers with the choices you made on the web page, and the laptop applies each one itself, exactly as winner repos allow or winner repos block would, stopping the push, writing the list and starting it again; the control plane never writes the list. A choice takes effect at the reporter's next run, which is within the hour on macOS and on Linux (winner-reporter.timer), later while the laptop sleeps or while the collector is not running here, and the page shows it as pending until then.

A choice is refused, with its reason sent back, for a name several checkouts share, a name that was separated, a name this laptop does not have, or a shared name this laptop has already sent. The reporter opens no session folder and runs no git to list them, so each folder a repo's sessions ran in counts as a checkout of its own: a repo whose sessions also ran in a subfolder or a linked worktree shows as shared on the page and is refused there, and winner repos allow is the way to allow it.

Each choice is applied once: a change you make with winner repos after the laptop took a choice wins over it, and the ids of the choices applied are kept in ~/.agentsview/fleetview-repo-choices.json until the control plane stops sending them. A choice carries no time, so a change you made before the laptop took it does not win: an allow clicked on the page and then blocked with winner repos block before the reporter's next run is still applied, and that repo's earlier sessions are sent, which cannot be withdrawn. Blocking it on the page replaces an allow still pending. A push stopped with winner push stop stays stopped and takes the new list at winner push start. A control plane that cannot be reached, or answers anything but the list of choices, changes nothing here, and a choice the list could not be written for, or that a push still running on the old list would not follow, because it did not stop or the collector's own push service could not be removed, stays pending; the next run tries again. Until a run, or a winner repos change, sees every push on the new list, ~/.agentsview/fleetview-repo-choices-old-list marks the laptop, and each run stops and restarts the push to try again. winner repos apply says what held it: a push that did not stop (winner push status), or the collector's own push service, which goes once agentsview is on PATH or after agentsview pg service uninstall.

A laptop enrolled with --no-service, one still on a sign-in token from before the laptop pass, or a Linux machine without systemd collects nothing from the page: use winner repos there. Nor does a laptop enrolled before repo selection that still sends every repo: it sends no list until winner update or winner login has kept the repos it sends, and the page's choices wait until then.

Known limits of this release

None of these is fixed in this release.

  1. Cursor spend is missing from laptops. No Cursor usage rows leave a laptop whose push is filtered, and every laptop with repo selection filters, so the Dashboard has no Cursor spend from laptops.
  2. A later checkout under an allowed name is sent. A second clone of an allowed repo, a linked worktree made later, or a Cursor folder that reads as an allowed name, is sent under that name without asking.
  3. A rename in the collector's own interface deletes stored sessions. Renaming a project in the collector's own interface (the agentsview app or its local web page) makes the next push delete the rows stored under the old name on your team's server.
  4. The laptop's database login can delete stored rows. Its credentials are in ~/.agentsview/config.toml, and with them plain SQL can delete that laptop's rows on the server. Backups are the answer (Back up, restore and uninstall); narrowing it is being looked at for a later release.

Not yet tested, and so a known limit: a long time off the VPN followed by the catch-up.

What the laptop sends, and where

A laptop contacts its own deployment and nothing else of Winner AI's:

  • the control plane, over https: the installer and the winner binary, the configuration winner login reads, the sign-in and enrolment, the hourly report (with the name and state of each repo, Choices made on the web page), and the report of a failed winner login or winner update (When winner fails);
  • the deployment's Postgres, on 5432, over TLS the laptop verifies against the system trust store (sslmode=verify-full): every push of session data goes there.

On a control plane that serves its own sign-in, the laptop never contacts the identity provider; your browser does, while you sign in. On a control plane without its own sign-in (its configuration names an Auth0 tenant instead), the laptop itself does: winner login runs Auth0's device flow from the laptop, and the hourly reporter refreshes its token at the Auth0 tenant. So does the reporter of a laptop whose last winner login signed in that way, until a winner login against its own sign-in. The embeddings endpoint stays on the laptop (localhost:11434) unless its config names another host (above).

Two kinds of traffic carry no session data:

  • github.com, and the githubusercontent.com host it redirects release downloads to, for the collector's own release (agentsview, unmodified), which the installer and winner update download;
  • raw.githubusercontent.com and openrouter.ai, where the collector refreshes its model prices. The collector offers no switch for that refresh.

The collector's anonymous usage ping and its check for a newer version of itself are switched off: every service winner installs sets AGENTSVIEW_TELEMETRY_ENABLED=0 and AGENTSVIEW_DISABLE_UPDATE_CHECK=1, and the config enrolment writes sets disable_update_check = true. A daemon you start yourself afterwards, from the agentsview desktop app or a shell, carries your own environment instead.

On a private deployment

When your deployment answers only on a private network, the laptop pushes only while it is on the VPN. Off it, pushes fail and the push keeps retrying; sessions wait on the laptop and catch up about a minute after the network returns, none lost. A network change in the middle of a push, such as joining the VPN, can hold the next push back for about two minutes, until the server's keepalive settings drop the old connection; winner push status shows nothing wrong meanwhile. winner login, winner update and the hourly report also wait for the VPN. Home shows a laptop Stale after 24 hours without a push, so during a pilot connect to the VPN at least once a day. A full-tunnel VPN works too, where the private network's own internet access reaches the identity provider and the hosts above: sign-in and updates then go through it. A Mac on a full-tunnel AWS Client VPN has been tested and pushed every session over it. A laptop off the VPN has the detail.

Day to day

winner push status      # running or stopped, repeated push failures, and when it last wrote to its log
winner push logs -f     # follow what it pushes (-n N for the last N lines; 50 by default)
winner push stop        # stops it, across reboots too, and on macOS any running collector
winner push start       # resumes

During an outage the push service itself keeps running, so status still says running, and adds that "the last N pushes failed" with the newest failure's reason once two or more pushes in a row have failed. No warning is not proof that pushes land: status reads only the failures the collector records.

A stop holds across reboots, but the next winner login re-enables the push: run winner push stop again after a re-login if you want it off.

If you signed in before your coding agent had ever run on the laptop, your first sessions can arrive up to 15 minutes late, until the push restarts (a reboot, an update that changes a binary, or winner push stop and start). After that a session arrives within about 30 seconds of changing.

The client updates itself daily at noon: on macOS also at each login, and a noon the Mac slept through becomes one run when it wakes; on Linux a noon the machine was off for becomes one run at its next start. winner update runs the same thing by hand, bringing winner and the collector to the versions the control plane runs, in either direction. It restarts the push only when it replaced the collector, replaced the collector's own push service, or rewrote a push service set up before the collector's opt-outs:

winner update --check   # report what would change; install nothing
winner update           # converge now
winner update --force   # also replace a winner the installer did not place, or an agentsview whose version cannot be read

winner update and Running on its own cover its rules and logs. For support, winner diagnostics writes one file to read and attach (Collecting diagnostics).

Uninstall

Uninstalling deletes nothing already sent: what the laptop pushed stays with your team.

On macOS (these steps have not been run end to end on a Mac yet):

winner push uninstall
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.getwinner.update.plist
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/dev.winner.reporter.plist
rm ~/Library/LaunchAgents/com.getwinner.update.plist ~/Library/LaunchAgents/dev.winner.reporter.plist
rm ~/.local/bin/winner

On Ubuntu or Debian:

winner push uninstall
systemctl --user disable --now winner-update.timer winner-reporter.timer
units="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
rm "$units/winner-update.timer" "$units/winner-update.service" \
   "$units/winner-reporter.timer" "$units/winner-reporter.service"
systemctl --user daemon-reload
rm ~/.local/bin/winner

If FLEETVIEW_BIN_DIR named another folder at install, remove winner from there instead of ~/.local/bin. On a machine without systemd, remove the crontab lines login printed with crontab -e instead of the timers. winner push uninstall removes only the background push, and keeps its logs.

None of this ends the laptop's access on the server: its database login and its laptop pass stay valid there. Ask a manager to press Revoke beside the laptop on Admin, which ends both.

~/.agentsview/ holds your local session history beside Winner AI's files and the laptop's database login (~/.agentsview/config.toml) and pass, so removing it removes those credentials from the laptop; removing it, and the collector (agentsview) itself, is your choice.