> For the complete documentation index, see [llms.txt](https://docs.we360.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.we360.ai/deployment-and-it-ops/deploy/agent-deployment-hub/installation-update-architecture.md).

# Installation & Update

This page explains **how the desktop agent installs and updates itself** on Windows and macOS — what runs, in what order, where files land, and how updates are triggered and applied. It is a reference for IT/security teams who need to understand the moving parts behind the step-by-step deployment guides.

There are two flavours of the agent:

* **Standard** (`MyZenV2`) — visible, interactive app.
* **Stealth** (`zs`) — headless. A background **service monitor** (`svcmonitor`) supervises the tracker, applies admin commands, and performs updates.

Both flavours share the same Go tooling and the same per-tenant key configuration (`zs.json`, the tenant id + key the installer is bound to).

***

## Windows — installation

### Primary path: self-contained installer (`zs-setup.exe`)

The recommended installer is a single self-contained executable with the entire application payload embedded inside it, so it installs **fully offline** with no download step.

1. **Resolve the tenant key config.** The installer determines which tenant it belongs to from (in order) an `installer-sources.json` beside it, an installer text marker, the executable's own (encoded) filename, or an existing `C:\Windows\System32\zs.json`.
2. **Elevate to administrator** (UAC prompt if not already elevated).
3. **Write the key config** to the canonical path `C:\Windows\System32\zs.json` so the agent and service always read the current tenant binding (this happens on update/repair too, replacing a stale config).
4. **Extract & validate the payload**, with a short settle delay so antivirus can inspect files before they're used.
5. **Place files atomically with rollback** (stage `.new`, move current to `.old`, rename into place; restore on failure) — resilient to AV locks/quarantine.
6. **Register and start the Windows service** (`svcmonitor`) with crash-recovery, write install registry keys, and add outbound firewall rules.

### Legacy path: MSI (Advanced Installer)

An MSI (`zs.msi` / `MyZenV2.msi`) is still produced for enterprise deployment via Group Policy / SCCM / Intune. It lays down the same file layout and service. New deployments should prefer the self-contained `zs-setup.exe` for offline/air-gapped scenarios. (The `configure_user.exe` helper is **no longer shipped** in either path — onboarding now runs in-process in the app.)

### Windows services

| Service                                      | Role                                                                                                                                                |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| **svcmonitor** (`C:\Windows\svcmonitor.exe`) | Supervises the tracker, polls the server for admin commands, performs updates, ships logs on request. Auto-start, with `sc failure` crash recovery. |
| **svcrunner** (`C:\Windows\svcrunner.exe`)   | Companion that keeps svcmonitor alive across sessions/crashes.                                                                                      |

***

## macOS — installation

The agent ships as a signed, **notarized** `.pkg`, built per architecture (`amd64` and `arm64` — no universal binary, intentionally). Gatekeeper acceptance, stapling, and signature integrity are verified at build time.

The package installs the app bundle and runs a **postinstall** script that:

1. Stops any existing app/processes.
2. Resolves and writes the tenant key config to `/Library/Preferences/zs.json` (stealth uses a `keyconfig_check` helper that reads the tenant from the package's own name).
3. Renders **launchd** job definitions from templates and bootstraps them for the system and logged-in GUI users.

### launchd jobs

| Job                        | Flavour  | Type                   | Purpose                                          |
| -------------------------- | -------- | ---------------------- | ------------------------------------------------ |
| `ai.we360.MyZenV2`         | Standard | LaunchAgent (per user) | Starts the interactive app at login              |
| `ai.we360.MyZenV2-updater` | Standard | LaunchDaemon (system)  | Hourly update check                              |
| `ai.zs.zs`                 | Stealth  | LaunchAgent/Daemon     | Starts/keeps `svcmonitor` running                |
| `ai.zs.zs-updater`         | Stealth  | LaunchDaemon (system)  | Runs `svcmonitor updater` to check/apply updates |

***

## File locations

|                              | Windows                                                           | macOS                                                                  |
| ---------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------- |
| **Stealth app**              | `C:\Program Files\zs\zs\`                                         | `/usr/local/zs/zs.app`                                                 |
| **Standard app**             | `C:\Program Files\…` (MSI)                                        | `/Applications/MyZenV2.app`                                            |
| **Service binaries**         | `C:\Windows\svcmonitor.exe`, `svcrunner.exe`                      | inside the app bundle (`…/Contents/MacOS/svcmonitor`), run via launchd |
| **Tenant key config**        | `C:\Windows\System32\zs.json` (fallback `…\zs\zs\keyconfig.json`) | `/Library/Preferences/zs.json` (fallback `/etc/zs.json`)               |
| **Version file**             | `…\zs\zs\version.txt`                                             | `…/Contents/MacOS/version.txt`                                         |
| **Per-user config (tokens)** | `%APPDATA%\ai.zs\zs.ini`                                          | `~/.config/ai.zs/zs.ini`                                               |
| **App data / logs**          | `%APPDATA%\ai.zs\zs\`                                             | `~/Library/Application Support/ai.zs/zs`                               |

> A custom key-config path can be supplied via the `ZS_KEY_CONFIG` environment variable (used by always-on mode); it overrides the platform default path.

***

## Updates

Updates are **server-led and per-tenant**, with a build-time fallback URL. The agent never auto-downgrades by accident.

### Agent update flow

The updater begins with the installed version and returns to that current state after every check, whether it applies a newer release or leaves the installation unchanged.

```mermaid
flowchart TD
    current["Installed / current version"]
    check["Run scheduled check or UPDATE command"]
    source["Resolve tenant URL or fallback"]
    policy{"Auto-update enabled and no skip marker?"}
    version{"Published version is higher?"}
    download["Download package"]
    integrity{"MD5 matches version sidecar?"}
    unchanged["Keep installed version unchanged"]
    apply["Apply update"]
    updated["Updated version is current"]
    rollback["Restore previous Windows files"]
    restored["Previous Windows version is current"]

    current --> check
    check --> source
    source --> policy
    policy -- No --> unchanged
    policy -- Yes --> version
    version -- No --> unchanged
    version -- Yes --> download
    download --> integrity
    integrity -- No --> unchanged
    integrity -- Yes --> apply
    apply -- Success --> updated
    apply -- "Windows atomic file swap fails" --> rollback
    rollback --> restored
```

In short, policy and version gates produce a safe no-op when an update is not eligible, integrity failure aborts before installation, and a successful apply—or the documented Windows rollback—returns the agent to an installed current version.

| Process stage                           | What is observable                                                                                                          | What causes progression                                                                 | Operator action                                                                                             |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| **Installed / current version**         | The installed version is recorded in `version.txt`.                                                                         | An hourly or timer-based check, or an on-demand `UPDATE` command for the stealth agent. | None for scheduled checks; an administrator can issue `UPDATE` for an on-demand stealth check.              |
| **Policy and version gates**            | The tenant response supplies `auto_update` and the latest version; a local skip marker can hold the update.                 | Updates continue only when they are allowed and the published version is higher.        | No action is required; the configured policy or hold determines whether the installation remains unchanged. |
| **Download and integrity verification** | No separate administrator-facing status is documented; the package MD5 is checked against the published `.version` sidecar. | A match starts installation; a mismatch aborts it.                                      | No operator procedure is specified on this page.                                                            |
| **Applying the update**                 | Windows reruns its installer or MSI; macOS installs the per-architecture package system-wide.                               | Successful installation makes the applied version current.                              | No action is required during the automatic apply.                                                           |
| **Integrity failure**                   | Installation is aborted and the installed version remains unchanged.                                                        | A later scheduled or requested check starts the flow again.                             | No operator procedure is specified on this page.                                                            |
| **Windows apply failure / rollback**    | If the atomic file swap fails, the installer restores the previous Windows files.                                           | Restoration returns the device to its previous installed version.                       | Rollback is automatic; no separate action is documented.                                                    |

### How an update is decided

1. **Resolve the installer URL** for this tenant: `GET https://origin.in.we360.ai/discover/v1/tenant/<id>/download-urls/` (cached in-process). If unavailable, fall back to the per-brand build-time base URL.
2. **Check the auto-update gate** (`auto_update` per tenant). If disabled, the updater no-ops.
3. **Compare versions** with a strict semver gate — an update installs only when the published version is **higher** than the installed one. (Intentional rollbacks require publishing a new build with the older bits.)
4. **Verify integrity** — the download's MD5 is checked against the published `.version` sidecar; a mismatch aborts the install.

### How an update is applied

* **Windows:** `svcmonitor` re-runs the self-contained `zs-setup.exe` (downloaded for this tenant), which stops the service, performs the same atomic file swap as a fresh install, and recreates/starts the service. MSI assets are applied via `msiexec /i … /qn /norestart`.
* **macOS:** the `*-updater` launchd job runs the updater, which downloads the per-arch `.pkg` and installs it system-wide via `/usr/sbin/installer -pkg … -target /`. The stealth updater encodes the tenant key config into the package path so postinstall can re-bind the tenant.

### Cadence & triggers

* **Standard (macOS):** hourly via the updater LaunchDaemon.
* **Stealth (both OS):** `svcmonitor` checks on a timer (only while a user session is active) and also honours an on-demand **`UPDATE`** admin command delivered through the service-state channel.
* **Skip markers:** developer/opt-out markers on disk cause the updater to no-op (used for dev machines and temporary holds).

***

## Related

* Step-by-step install guides: **Manual Installation** (Windows/macOS, standard/stealth).
* Mass deployment: **Mass Deployment** (GPO, Intune, MDM, command-line MSI).
* Network behaviour & endpoints: **Network & Security Hardening → Stealth App — Server Communication (v4.13+)**.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.we360.ai/deployment-and-it-ops/deploy/agent-deployment-hub/installation-update-architecture.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
