# Installation

> Install the published CLI globally, bootstrap a development checkout, and verify the background service starts with expected ports and data directories.

- Repository: RhysSullivan/executor
- GitHub: https://github.com/RhysSullivan/executor
- Human docs: https://grok-wiki.com/public/docs/rhyssullivan-executor-564383868052
- Complete Markdown: https://grok-wiki.com/public/docs/rhyssullivan-executor-564383868052/llms-full.txt

## Source Files

- `apps/docs/local/cli.mdx`
- `apps/cli/package.json`
- `apps/cli/bin/executor.ts`
- `apps/cli/src/installation.ts`
- `scripts/bootstrap.ts`
- `RUNNING.md`

---

---
title: "Installation"
description: "Install the published CLI globally, bootstrap a development checkout, and verify the background service starts with expected ports and data directories."
---

The published `executor` npm package ships a Node.js launcher plus a per-platform compiled binary. `executor install` registers an OS-supervised background daemon that binds loopback, writes a `server.json` manifest under the data directory, and survives reboots. Development checkouts use `bun run bootstrap` and run the CLI from source instead of the global binary.

## Prerequisites

| Audience | Requirement |
| --- | --- |
| CLI users | Node.js 20 or newer (`engines.node` on the published package) |
| Contributors | [Bun](https://bun.sh) 1.3.x (repo `packageManager`: `bun@1.3.11`) |

<Note>
The global CLI resolves a platform binary from npm `optionalDependencies`. Supported targets are `darwin`/`linux`/`win32` on `x64` and `arm64` (Linux also publishes `musl` variants). If install reports it cannot locate a platform binary, your OS/CPU combination is not in the published matrix.
</Note>

## Install the published CLI

<Tabs>
  <Tab title="npm">
    ```bash
    npm install -g executor
    ```
  </Tab>
  <Tab title="pnpm">
    ```bash
    pnpm add -g executor
    ```
  </Tab>
  <Tab title="bun">
    ```bash
    bun add -g executor
    ```
  </Tab>
  <Tab title="yarn">
    ```bash
    yarn global add executor
    ```
  </Tab>
</Tabs>

Confirm the launcher resolves:

```bash
executor --help
```

A successful install prints subcommand help without `could not locate a platform binary` or `ENOENT`.

## Start the background service

`executor install` is an alias for `executor service install`. Both register the supervised daemon and wait up to 45 seconds for a reachable `server.json` manifest.

<Steps>
  <Step title="Install and start the service">
    ```bash
    executor install
    ```

    On success, output includes the service manager name, web UI origin, data directory, and log path. The command is idempotent: if the service is already running at the requested port with the current binary version, it prints the running origin and exits.

    <Warning>
    On Windows, run `executor install` from an **Administrator** PowerShell. Task Scheduler registration requires elevation.
    </Warning>
  </Step>

  <Step title="Open the web UI">
    ```bash
    executor web
    ```

    This reads the active `server.json` manifest and opens the browser to the running origin, including a `?_token=` query when a bearer token is available. For a throwaway foreground server instead of the supervised service, use `executor web --foreground`.
  </Step>

  <Step title="Verify health and status">
    ```bash
    executor service status
    ```

    Expect `Registered: yes`, `Running: yes`, and a `Serving:` line with the live origin.

    Probe liveness without credentials:

    ```bash
    curl -s http://127.0.0.1:4789/api/health
    ```

    <ResponseExample>
    ```text
    ok
    ```
    </ResponseExample>

    If the supervised daemon uses a non-default port, substitute that port in the URL. Clients discover the live port from `server.json`, not from a fixed default.
  </Step>
</Steps>

## Ports and service managers

| Surface | Default port | Bind address | Notes |
| --- | --- | --- | --- |
| `executor install` / `executor service install` | `4789` | `127.0.0.1` | OS-supervised daemon (`sh.executor.daemon`) |
| `executor daemon run` (auto-start, foreground) | `4788` | `127.0.0.1` | Ephemeral or detached daemon, not OS-supervised |
| `executor web --foreground` | `4788` | `127.0.0.1` | Temporary in-terminal server |

Override the supervised port:

```bash
executor install --port 4790
```

<ParamField body="port" type="integer">
Port the supervised daemon binds. Defaults to `4789`. Loopback only.
</ParamField>

| Platform | Service manager | Service label / task |
| --- | --- | --- |
| macOS | launchd LaunchAgent | `sh.executor.daemon` |
| Linux | systemd `--user` + linger | `sh.executor.daemon.service` |
| Windows | Task Scheduler (S4U / AtStartup) | `ExecutorDaemon` |

<Tip>
On Linux, `executor service status` warns when user lingering is off. Without linger, the daemon starts on login but not at boot. Run `loginctl enable-linger $USER` to fix it.
</Tip>

## Data directory layout

By default, local state lives in `~/.executor`. Override with `EXECUTOR_DATA_DIR`.

:::files
~/.executor/
├── data.db                 # SQLite integrations, connections, policies
├── server-control/
│   ├── auth.json           # Stable bearer token (mode 0600)
│   ├── server.json         # Active server manifest (origin, auth, pid)
│   └── startup.lock        # In-flight startup guard
├── logs/
│   ├── daemon.log
│   └── daemon.error.log
├── daemon-localhost-<port>.json
└── daemon-active-localhost-<scope-hash>.json
:::

<ParamField body="EXECUTOR_DATA_DIR" type="string">
Root directory for database, auth, manifests, and logs. Default: `~/.executor`.
</ParamField>

<ParamField body="EXECUTOR_SCOPE_DIR" type="string">
Scope directory for tool execution context. The supervised service sets this to `EXECUTOR_DATA_DIR` when unset. Foreground daemons default to the current working directory.
</ParamField>

The supervised unit never embeds secrets. The daemon mints or loads the bearer token from `server-control/auth.json` on boot; `server.json` carries a copy for clients.

## Bootstrap a development checkout

Contributors clone the monorepo and run bootstrap before dev servers or tests.

<Steps>
  <Step title="Clone and bootstrap">
    ```bash
    git clone https://github.com/RhysSullivan/executor.git
    cd executor
    bun run bootstrap
    ```

    Bootstrap is idempotent. It runs `bun install` (whose `prepare` hook builds `@executor-js/vite-plugin` and `packages/react`, artifacts Vite dev servers require) and installs Playwright Chromium for e2e.
  </Step>

  <Step title="Run the CLI from source">
    ```bash
    bun run dev:cli -- --help
    ```

    This sets `EXECUTOR_DEV=1` and `EXECUTOR_DATA_DIR=apps/local/.executor-dev` by default.

    <Warning>
    `executor install` and `executor service install` require the **compiled** binary. In a dev checkout they fail with a message to use `bun run apps/cli/src/main.ts daemon run --foreground` instead.
    </Warning>
  </Step>

  <Step title="Start a foreground daemon for local work">
    ```bash
    bun run dev:cli -- daemon run --foreground
    ```

    Default port is `4788`. Open the UI against the running manifest:

    ```bash
    bun run dev:cli -- web
    ```
  </Step>

  <Step title="Run the full dev stack (optional)">
    ```bash
    bun run dev
    ```

    Starts turbo dev servers for apps and packages (excluding desktop and cloud by default). See the develop-locally page for package boundaries, targeted tests, and e2e boot recipes.
  </Step>
</Steps>

## Verification checklist

| Signal | Expected result |
| --- | --- |
| `executor --help` | Exit 0, subcommand list |
| `executor install` | Prints origin like `http://127.0.0.1:4789`, data dir, logs path |
| `executor service status` | `Registered: yes`, `Running: yes`, `Serving:` with origin |
| `GET /api/health` on the serving origin | Body exactly `ok`, no auth header |
| `~/.executor/server-control/server.json` | Exists after first successful boot |
| `~/.executor/logs/daemon.error.log` | Empty or only startup lines on clean boot |

If install times out after 45 seconds, check `~/.executor/logs/daemon.error.log` and re-run `executor service status`. Version drift (running binary older than CLI) is flagged in status output; re-run `executor install` to repoint the unit and restart.

## Common failure modes

<AccordionGroup>
  <Accordion title="Port already in use">
    Another process may hold the default port. Pick a free port with `executor install --port <n>`, or stop the conflicting listener and reinstall. On Windows, orphaned `executor.exe` listeners can survive a stopped scheduled task; `executor service uninstall` attempts cleanup.
  </Accordion>
  <Accordion title="Dev checkout cannot run executor install">
    Expected. OS service managers need the compiled binary path (`process.execPath`). Use `daemon run --foreground` from the dev CLI, or build a local binary with `bun run --cwd apps/cli build` and install from `apps/cli/dist/executor`.
  </Accordion>
  <Accordion title="Fresh worktree Vite errors about @executor-js/vite-plugin">
    Run `bun run bootstrap` from the repo root. Skipping bootstrap leaves dev servers without the prepare-built artifacts.
  </Accordion>
  <Accordion title="Linux daemon stops after logout">
    Enable lingering: `loginctl enable-linger $USER`. Without it, the user systemd manager (and the daemon) stops when you log out.
  </Accordion>
</AccordionGroup>

<Info>
Self-hosted Docker uses port `17888` and a different runtime (`apps/host-selfhost`). That path is not the local CLI daemon described here.
</Info>

## Next

<CardGroup>
  <Card title="Quickstart" href="/quickstart">
    Run `executor install`, open the web UI, add a first integration, and call a tool.
  </Card>
  <Card title="CLI reference" href="/cli-reference">
    All `executor` subcommands, flags, and auto-start behavior.
  </Card>
  <Card title="Configuration reference" href="/configuration-reference">
    Environment variables, paths, ports, and client overrides.
  </Card>
  <Card title="Develop locally" href="/develop-locally">
    Monorepo bootstrap, turbo dev, Vitest, and e2e for contributors.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Port conflicts, stale manifests, OAuth behind proxies, and recovery commands.
  </Card>
</CardGroup>
