> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modelcode.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Daemon Administration

> Install, network access, certificates, registry mirrors, upgrades, and troubleshooting for the self-hosted ModelDaemon

export const ProductName = "The Morph Platform";

export const productName = "the Morph Platform";

This page is for whoever installs and looks after the ModelDaemon — usually a platform or IT team. For what the daemon is and why you would use one, start with [Self-hosted Daemon](/setup/build-environment/self-hosted-daemon).

## Prerequisites

* A machine on your network that can reach your private services
* A {productName} account with an active project
* Outbound HTTPS from that machine (see [Network access](#network-access)). No inbound ports are required.
* A supported operating system

You do **not** need to preinstall language runtimes (Python, Node, Java, Ruby, Go) or package managers (pip, npm, maven, gem). {ProductName} declares what each project needs and installs it into an isolated environment.

On **Windows**, the installer also installs the Microsoft Visual C++ Redistributable if it is missing. On a locked-down host that blocks the download, install it beforehand.

## Supported operating systems

| Platform                                                                                               | Architectures     |
| ------------------------------------------------------------------------------------------------------ | ----------------- |
| **Linux** — Ubuntu, Debian, RHEL, Amazon Linux, SUSE, Alpine, and other POSIX-compatible distributions | Intel/AMD and ARM |
| **macOS** — Apple Silicon or Intel                                                                     | Intel/AMD and ARM |
| **Windows** — Windows 10/11 or Windows Server 2019+                                                    | Intel/AMD only    |

Windows on ARM is not supported. The installer detects it and stops before making any changes.

Install each daemon on an operating system matching its pool's platform. A pool only routes work to machines that match.

<Note>
  In {productName}'s platform vocabulary, macOS belongs to the **Linux** family, because what the platform choice really decides is whether generated commands are written for a POSIX shell or for PowerShell. A macOS machine joins a Linux pool.
</Note>

## Network access

All connections are outbound and initiated by the daemon.

More than the daemon needs network access, and they do not all talk to the same place. Your exact hostnames are shown in the daemon's `config.toml` and in the install command the UI generates — read them from there rather than assuming, because the model and result-reporting hosts can differ from the main one:

| Destination                                                                                                        | Needed by                             | For                                                       |
| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------- | --------------------------------------------------------- |
| `*.modelcode.ai` — your `job_server_url`                                                                           | the daemon                            | receiving work, reporting status                          |
| Your model-proxy host — the `llm_proxy` value in `config.toml`                                                     | the AI agent                          | model traffic, proxied by {productName}                   |
| Your {productName} web host — the same host you sign in to                                                         | the AI agent                          | reporting test results back                               |
| `pixi.sh`, `prefix.dev`, and the conda-forge CDN                                                                   | installer and every environment build | the isolated toolchain                                    |
| `registry.npmjs.org`, `pypi.org`                                                                                   | environment build                     | base packages — see [Registry mirrors](#registry-mirrors) |
| Cloud object storage — the download URLs redirect here, so follow redirects rather than allowlisting the first hop | installer                             | the daemon binary and install scripts                     |
| `aka.ms`                                                                                                           | Windows installer only                | Visual C++ Redistributable                                |

<Warning>
  The two AI agent rows above are worth allowlisting carefully. If the daemon can reach {productName} but the agent cannot reach the result-reporting host, **the daemon looks perfectly healthy and test results silently go missing** — you get no error pointing at the network. If frontend test results are absent for no visible reason, check this first.
</Warning>

If your network only permits outbound traffic through an explicit proxy, contact [support@modelcode.ai](mailto:support@modelcode.ai) before you begin so we can confirm the configuration with you.

## Installing

Run the command the UI generates for you — it already contains your API key, your pool name, and the right download for the machine's platform.

Two names are involved, and they are not the same thing:

| UI field        | Install variable | What it is                                                                              |
| --------------- | ---------------- | --------------------------------------------------------------------------------------- |
| **Pool name**   | `POOL_NAME`      | The pool this machine joins. Every machine in a pool shares it.                         |
| **Daemon name** | `RUNNER_NAME`    | This machine's own name within the pool. Optional — defaults to the machine's hostname. |

<Warning>
  If you are following an older runbook, check which variable it passes. `RUNNER_NAME` used to mean the pool; it now means this machine. A runbook that still puts the pool name in `RUNNER_NAME` will register the machine under its own one-machine pool instead of joining yours.
</Warning>

Two related behaviors worth knowing:

* A `POOL_NAME` set in the daemon's environment **overrides the value in `config.toml`** every time it starts, so the file can disagree with reality. Run `mcode config show` to see the pool actually in effect.
* **Re-running the installer without `POOL_NAME` does not clear the existing pool.** "Reinstall to fix it" quietly keeps the old one.

The installer detects the machine's operating system and architecture itself. If you are copying an older command that specifies them explicitly, those values are now ignored — harmless, but they will not override anything.

### Verifying the install

```
mcode version      # confirms the binary is present
mcode config show  # shows the pool name in effect
mcode logs         # follows recent activity
```

Then click **Verify & Continue** in the UI.

On **Windows**, open a new PowerShell window first so the updated `PATH` is picked up.

## Running as a service

Run `mcode install-service` followed by `mcode start` so the daemon returns after a reboot.

| Platform    | Notes                                                                                                                                                                                                                                                                                    |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Linux**   | Installs a user-level service. If the machine has no user login session — common in containers — it falls back to a simpler supervision mode **with no automatic restart**. If you need restart-on-failure there, ask an administrator to enable user session lingering for the account. |
| **macOS**   | Installs a launch agent that restarts on failure.                                                                                                                                                                                                                                        |
| **Windows** | Installs a Windows service named **ModelDaemon**. Requires an elevated (Run as administrator) PowerShell session. If you cannot run as administrator, use `mcode run` in the foreground instead.                                                                                         |

Service logs are written to `logs/build_agent.log` next to the daemon binary. `mcode logs` follows that file.

## Corporate certificates and TLS-inspecting proxies

If your network terminates and re-signs TLS with an internal certificate authority, the daemon needs to trust it. Two settings in the daemon's `config.toml` cover this:

| Setting               | Purpose                                                                                                                                                                            |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pixi_tls_root_certs` | Trust store used when installing the isolated toolchain. Defaults to your host's own trust store, so a corporate root already installed on the machine is picked up automatically. |
| `ca_cert_bundle`      | A certificate bundle for the package managers and tools the agent uses (npm, pip, git, curl, and others).                                                                          |

There is a platform difference that matters:

* **On Linux**, the host trust store is complete, so the daemon configures the tooling automatically and merges any bundle you supply.
* **On Windows**, the host trust store is populated lazily and cannot be relied on. To cover pip, git, curl, Python and Rust you must supply a **complete** bundle and set `ca_cert_bundle_complete = true`.

A bundle containing no valid certificate is rejected when the daemon starts, rather than failing later in a confusing way.

## Registry mirrors

When installing its base dependencies, the daemon uses public registries:

| Source                                      | Used for                                    |
| ------------------------------------------- | ------------------------------------------- |
| [npm registry](https://registry.npmjs.org/) | Global npm packages in the base environment |
| [PyPI](https://pypi.org/)                   | The {productName} agent package             |

Many enterprise deployments cannot use those defaults — an air-gapped network with no public route, or a policy requiring all third-party artifacts to come from an approved internal registry.

Point the daemon at your own mirrors by adding a `[registries]` table to `config.toml`:

```toml theme={null}
[registries]
npm = "https://artifactory.example.com/artifactory/api/npm/npm-virtual/"
pip = "https://artifactory.example.com/artifactory/api/pypi/simple"
```

<Note>
  Registry overrides apply only to **npm** and **pip** during base dependency setup. They do not affect how your own application's dependencies are fetched.
</Note>

If your mirror requires authentication, configure credentials on the host the way you would for manual `npm` or `pip` use — `.npmrc`, `pip.conf`, or a network policy that allows the daemon's subnet through.

## Keeping the daemon up to date

Run `mcode update` on the host. It downloads the current version, verifies it, replaces the binary, and restarts the service. There is no automatic update.

`mcode update --check` reports whether an update is available or required, without installing anything.

{ProductName} enforces a minimum version. If every machine in a pool is below it, work stops with a message naming the pool and telling you to run `mcode update`. A single out-of-date machine is quietly skipped instead — so if one machine never seems to pick up work, check its version.

## Where things live

|                                       | Linux / macOS                         | Windows                                 |
| ------------------------------------- | ------------------------------------- | --------------------------------------- |
| Binary, `config.toml`, encryption key | `~/.local/share/modelcode/`           | `%USERPROFILE%\.local\share\modelcode\` |
| Command on `PATH`                     | `~/.local/bin/mcode`                  | `%USERPROFILE%\.local\bin\mcode.exe`    |
| Per-job workspaces                    | `~/.local/share/modelcode/workspace/` | `%LOCALAPPDATA%\modelcode\workspace\`   |
| Logs                                  | `<install dir>/logs/build_agent.log`  | `<install dir>\logs\build_agent.log`    |

The daemon generates an encryption key pair on first run and keeps it in its data directory. Only the public half ever leaves the machine. `mcode uninstall` deletes it along with everything else — use `--keep-data` if you want the configuration preserved.

<Note>
  **Disk space** grows with the number of projects on the machine and the number of separate environments each one declares, plus a package cache. A small single-project host needs a few GB; a monorepo with one environment per service needs considerably more. For a firm figure for capacity planning, contact [support@modelcode.ai](mailto:support@modelcode.ai).
</Note>

## Command reference

| Command                                       | What it does                                   |
| --------------------------------------------- | ---------------------------------------------- |
| `mcode run`                                   | Run in the foreground                          |
| `mcode install-service` / `uninstall-service` | Register or remove the background service      |
| `mcode start` / `stop`                        | Start or stop the service                      |
| `mcode update [--check]`                      | Update the daemon, or check for updates        |
| `mcode config show` / `edit`                  | Show effective configuration, or edit the file |
| `mcode logs`                                  | Follow the log file                            |
| `mcode version`                               | Print the version                              |
| `mcode refresh-path`                          | Re-capture the host `PATH` (see below)         |
| `mcode uninstall [--keep-data]`               | Remove the daemon                              |

## Troubleshooting

### When a daemon shows as offline

Start with the UI: the project's **Daemon pool** section and the pool details page show each machine's last-known state, which usually tells you whether this is one machine or the whole pool.

If the setup step cannot confirm the daemon, you will see this:

<div align="center">
  <img src="https://mintcdn.com/modelcodeai/z4bfn18uMstRYiEm/images/self-hosted-daemon/daemon-verify-failed.png?fit=max&auto=format&n=z4bfn18uMstRYiEm&q=85&s=14018eddece905e8968b8803e0e0fbc2" alt="Could not verify that ModelDaemon is running. Make sure you started it with the command above and try again." width="80%" data-path="images/self-hosted-daemon/daemon-verify-failed.png" />
</div>

On the host, in order:

1. **Is it running?** Start it again with `mcode start` (service) or `mcode run` (foreground).
2. **Can it reach the network?** Check firewall, proxy, and VPN changes against [Network access](#network-access).
3. **What do the logs say?** `mcode logs` — look for connection or authentication errors.

Common causes:

* The host rebooted and `mcode install-service` was never run, so nothing restarts the daemon
* A VPN disconnect or firewall change blocked outbound HTTPS
* The API key was rotated in the UI but not updated on the host

### When a daemon is running but gets no work

* **Platform mismatch.** A machine whose OS does not match its pool's platform registers and looks healthy, but receives nothing. Check the pool's platform on the pool details page.
* **Architecture pin.** If the pool pins an architecture, machines on other architectures are not sent work.
* **Version too old.** A machine below the minimum version is skipped silently. Run `mcode update`.

### When registration is refused

The daemon reports the reason in its log. Some refusals are permanent — the daemon will disable its own service and exit cleanly rather than retrying forever, so a clean exit is a signal rather than a crash:

| Reason                                          | Retries? | What to do                                                                                              |
| ----------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| The pool name does not match a pool that exists | No       | Correct the pool name, or create the pool in the UI first.                                              |
| The machine's platform does not match the pool  | No       | Install on a matching OS, or use a different pool.                                                      |
| The pool is at capacity                         | Yes      | Wait for a machine to leave the pool, or ask your administrator whether the pool's limit can be raised. |
| The daemon was deleted in the UI                | No       | Reinstall to re-register this machine.                                                                  |

Deleting a daemon in the UI is a real deletion: the machine clears its own registration, stops its service, and stays down until reinstalled.

### "Command not found" after installing new tools

The daemon captures the host `PATH` when it is installed as a service. If you install new tools afterwards, run `mcode refresh-path` and restart the daemon.

### Authentication failures ("Unauthorized", "Authentication failed")

Check that the API key in `config.toml` matches the one shown in the UI. If it was rotated, update the file and run `mcode start` again.

### Build, run, or health-check failures

These are usually about the application rather than the daemon. The [Validation Hub](/migration/functional-testing) shows which script failed and its output.

* **Build fails** — most often a dependency only available on your private network, or a command that needs a different working directory. Verify it by hand on the same machine as the same user.
* **Application does not start** — check the port is free, and that required services are reachable from this host.
* **Health check times out** — confirm the URL and port, check the application binds to `0.0.0.0` or `localhost` rather than a specific interface, and allow more time if startup is slow.

## Migrating from V1

Older "V1" daemons are deprecated but have not been switched off.

* **Existing V1 projects keep working.** There is no forced migration and no deadline.
* **New projects require the current daemon.** A new project cannot attach to a V1 daemon.

<Warning>
  **V1 and the current daemon cannot coexist on one machine.** Both install to the same location, so running the current installer on a V1 host **replaces the V1 daemon** and its projects stop running jobs.

  If you still have active V1 projects, install the current daemon on a **different machine** with the same network and credential reach. Replace V1 on the original host once those projects are finished.
</Warning>

The practical differences: dependencies and lifecycle commands are now discovered for you instead of being installed and written by hand, each job runs in its own isolated workspace, and encryption keys are managed by the daemon.
