Kiteyard guided installation for agents#

Last reviewed: 23 September 2026. Stable source: https://setup.kiteyard.com/agents.md.

This runbook installs the canonical Kiteyard core: Headquarters, Agent Manager, and PostgreSQL with pgvector. It is for a fresh, single-customer installation on a Linux server. It is not an upgrade or migration runbook.

Scope and safety boundary#

  • Install the root compose.yml through deploy/core/install.mjs. Do not hand-author a replacement Compose stack.
  • Install the canonical Headquarters + Agent Manager core only. Use the reviewed release's root Compose definition and shipped automation library; do not add unrelated services or packs.
  • Treat Portainer as a separate, optional provider for Agent Manager Environment Management. Do not make it a prerequisite for the core.
  • Do not deploy or co-host this setup website as part of the product installation. It is public documentation, not a Kiteyard core service.
  • Use a reviewed release tag or full commit for production. Do not silently install from a moving branch.
  • Do not print /root/kiteyard.env, /opt/kiteyard/.env, MCP tokens, GitHub tokens, Portainer tokens, or ChatGPT device credentials.
  • Do not use docker compose down --volumes, broad Docker prune commands, or host-wide cleanup.
  • One Kiteyard core installation should own its Docker daemon. A different Compose project name does not isolate Agent Manager's daemon-wide managed-worker discovery.

The core server runs these long-lived services:

  • PostgreSQL 16 with pgvector;
  • Headquarters, including browser authentication and the /mcp endpoint;
  • Agent Manager's private API, UI service, and worker manager;
  • manager-created Agent Manager workers.

Only Headquarters publishes a host port by default: loopback 127.0.0.1:3001. It serves Headquarters and the authenticated Agent Manager UI at /agent-manager/. Do not publish the private Agent Manager API or UI containers.

Inputs: ask just in time#

Required before the core install:

  • A dedicated linux/amd64 server with root or passwordless sudo access.
  • Docker Engine, the Docker CLI, and Docker Compose 2.20 or newer.
  • Node.js 24 and Git.
  • An exact private HTTPS origin such as https://kiteyard.example.com.
  • DNS and a TLS-terminating reverse proxy or private-network ingress for that origin.
  • A login-capable initial administrator email.
  • A unique initial administrator password of at least 12 characters, entered directly on the host.
  • GitHub access that can clone the private Kiteyard/Kiteyard repository.
  • GHCR access that can pull the private application packages ghcr.io/kiteyard/headquarters and ghcr.io/kiteyard/agent-manager. The separate public portable worker runtime is ghcr.io/kiteyard/agent-manager-worker-runtime.

Required before real Agent Manager Codex jobs:

  • A ChatGPT account and active plan with Codex access. Authentication uses the device flow in Agent Manager; it is separate from the OpenAI API.
  • Repository credentials for any private repositories that workers must clone or push. Add these later in Agent Manager, with only the required repository scope.

Recommended production choices:

  • A dedicated host with a practical starting capacity of at least 4 vCPU, 8 GiB RAM, and 40 GiB SSD, then sized for builds, artifacts, images, and concurrency. The repository does not define a universal CPU or RAM minimum.
  • More than 5 GiB free after images and data. Agent Manager's default retained-workspace admission floor is 5 GiB; it is not a total disk quota.
  • Reviewed, compatible image tags or digests instead of the moving headquarters:latest and agent-manager:edge defaults.
  • Off-host backups for the retained environment file, PostgreSQL, worker volumes, and optional Portainer data.
  • Private routing or an encrypted private network between Agent Manager workers and optional Portainer MCP endpoints.

Optional inputs, requested only if the operator enables the feature:

  • An OpenAI API project key with billing for Headquarters document embeddings and semantic vector search. The default embedding model is text-embedding-3-large.
  • A separate Portainer server or an existing Portainer installation, two private MCP routes, a generated MCP gate token, and a dedicated Portainer API access token.
  • Kiteyard MCP client onboarding after the product is working.

The canonical installer provisions PostgreSQL and pgvector. Do not ask the operator to pre-create an external database for this installation path.

Stage 0 — Confirm the fresh-install plan#

Ask for these non-secret decisions and nothing else:

  1. Confirm that the target is a fresh installation, not an upgrade, migration, or recovery.
  2. Confirm the target server and whether the operator can use sudo.
  3. Ask for the intended Kiteyard HTTPS hostname.
  4. Ask whether the first pass is core-only or whether Portainer should be considered after the core is verified. Recommend core-first.
  5. Ask which reviewed Kiteyard release tag or full commit to install. If the operator has no reviewed release reference, explain that the repository/image defaults move and require an explicit production-risk decision.

Stop and use the relevant private upgrade runbook if an existing /opt/kiteyard/.env, kiteyard-shared Compose project, or prior Kiteyard database is present. Do not treat it as fresh.

Stage 1 — Read-only host preflight#

Run read-only checks before installing packages or changing configuration:

uname -m
uname -sr
command -v git
git --version
command -v node
node --version
command -v docker
docker --version
docker compose version --short
sudo test -S /var/run/docker.sock
sudo docker info --format '{{.ServerVersion}} {{.OSType}}/{{.Architecture}}'
sudo stat -c '%g %n' /var/run/docker.sock
df -h /var/lib/docker /
sudo ss -ltnp

Pass criteria:

  • uname -m is x86_64 and Docker reports linux/amd64.
  • Node reports major version 24.
  • Docker Engine is reachable through /var/run/docker.sock.
  • Docker Compose is 2.20 or newer.
  • Git is present.
  • Port 3001 can remain bound to loopback, or the operator has deliberately selected another unused Headquarters host port.
  • The host has capacity for the images, database, workspaces, and expected builds.
  • Outbound HTTPS can reach GitHub, GHCR, ChatGPT/OpenAI authentication, and the OpenAI API if embeddings will be enabled.

If a prerequisite is missing, identify the host distribution and propose its supported installation method. Obtain confirmation before installing system packages. Re-run the complete preflight afterward. Do not replace an existing Docker installation or reverse proxy without an explicit operator decision.

Stage 2 — Authenticate private source and packages#

Ask the operator which existing GitHub authentication method to use for the private repository: SSH is preferred for cloning, while HTTPS credential-manager access is also acceptable. Do not put a personal access token in a clone URL.

Clone and pin the reviewed source:

git clone git@github.com:Kiteyard/Kiteyard.git kiteyard-source
cd kiteyard-source
git checkout --detach <reviewed-release-tag-or-full-commit>
git status --short
git rev-parse HEAD

If SSH is unavailable, use the normal HTTPS clone URL and the host's credential manager:

git clone https://github.com/Kiteyard/Kiteyard.git kiteyard-source

For GHCR, a classic GitHub personal access token with at least read:packages is the documented package-read credential. The PAT authenticates pulls of the private application packages ghcr.io/kiteyard/headquarters and ghcr.io/kiteyard/agent-manager; it must belong to an identity allowed to read both packages and may need organization SSO authorization. The separate public portable worker runtime, ghcr.io/kiteyard/agent-manager-worker-runtime, does not require this PAT. Repository-clone access is a separate permission; use the narrowest credentials that satisfy both operations.

Have the operator enter the GHCR token in the terminal without echoing it or placing it in shell history:

read -rsp 'GHCR package-read token: ' GHCR_TOKEN; echo
printf '%s' "$GHCR_TOKEN" | docker login ghcr.io -u '<github-username>' --password-stdin
unset GHCR_TOKEN

Do not continue until the checkout is clean and authenticated image access is available. Do not record the GitHub token in the Kiteyard environment file.

Stage 3 — Prepare origin, TLS, and administrator input#

Verify that the selected value is an exact HTTPS origin with no path, query, fragment, embedded credentials, or trailing slash:

https://kiteyard.example.com

Confirm that DNS resolves to the intended ingress. Preserve an existing reverse proxy. It must forward the full origin to http://127.0.0.1:3001, preserve Host, set X-Forwarded-Proto to the original scheme, and allow streaming requests. Expose only the HTTPS ingress; do not expose host port 3001 publicly.

A minimal Caddy site block, when Caddy is already the selected proxy, is:

kiteyard.example.com {
  reverse_proxy 127.0.0.1:3001
}

Ask for the initial administrator email. Then create a protected input file and ask the operator to enter the password directly in the editor. The password must be unique and at least 12 characters.

sudo install -m 600 /dev/null /root/kiteyard.env
sudoedit /root/kiteyard.env

The first-run file needs only these operator-selected values:

SEED_USER_EMAIL=operator@example.com
SEED_USER_PASSWORD=<enter-directly-on-host>
KITEYARD_PUBLIC_URL=https://kiteyard.example.com

When reviewed compatible image references are available, add them now:

HEADQUARTERS_IMAGE=ghcr.io/kiteyard/headquarters:<reviewed-tag-or-digest>
RUNNER_IMAGE=ghcr.io/kiteyard/agent-manager:<reviewed-tag-or-digest>

Do not ask for generated database passwords, authentication secrets, encryption keys, deployment IDs, browser gateway tokens, or the Agent Manager admin token. The installer generates distinct values and retains them in /opt/kiteyard/.env.

Do not ask for OPENAI_API_KEY or Portainer credentials yet unless the operator explicitly chose to configure that optional feature in the first pass.

Confirm the input file is private without printing it:

sudo chmod 600 /root/kiteyard.env
sudo stat -c '%a %U:%G %n' /root/kiteyard.env

Stage 4 — Install the canonical core#

From the pinned, clean repository root, run:

sudo node deploy/core/install.mjs install --env-file /root/kiteyard.env

The installer must be run as root on Linux. It will:

  • validate Docker Compose and the local Docker socket;
  • generate distinct database, authentication, encryption, gateway, and integration credentials;
  • write /opt/kiteyard/.env with mode 0600;
  • copy the canonical compose.yml and installer to /opt/kiteyard;
  • pull the selected private application images and public pgvector image;
  • create the persistent Agent Manager worker volumes;
  • bootstrap and migrate the identity, headquarters, and agent_manager schemas;
  • start the core services and verify that every long-running service is running.

The successful command prints a small JSON result with "status":"ready". It does not print generated credentials. On failure, inspect the named phase and targeted service logs without dumping either environment file.

Do not replace the installer with a manual docker compose up sequence. Do not copy source files into /opt/kiteyard by hand.

Stage 5 — Verify fresh-install defaults#

Run the installed, source-independent verification and inspect all services:

sudo node /opt/kiteyard/install.mjs verify
sudo docker compose \
  --project-name kiteyard-shared \
  --env-file /opt/kiteyard/.env \
  --file /opt/kiteyard/compose.yml \
  ps -a
curl --fail --silent --show-error --output /dev/null http://127.0.0.1:3001/auth

Required service state:

  • postgres, headquarters, runner-api, runner-ui, and runner-manager are running.
  • bootstrap, headquarters-migrate, and agent-manager-migrate completed successfully with exit code 0.
  • Headquarters is the only browser-facing service and listens on the configured loopback port.
  • The generated /opt/kiteyard/.env remains mode 0600 and is not shown in output.

Complete or reload the HTTPS reverse proxy now that the upstream is live, then verify the public route:

curl --fail --silent --show-error --output /dev/null https://kiteyard.example.com/auth

Ask the operator to complete these browser checks:

  1. Open the exact KITEYARD_PUBLIC_URL and sign in with the seed administrator.
  2. Confirm public sign-up is unavailable.
  3. Open /agent-manager/ from the product switcher. The Headquarters session must carry through; there is no Agent Manager admin-token login in the combined installation.
  4. Confirm Managed default worker exists with desired count 1.
  5. Confirm Default (legacy) exists under Global Settings → ChatGPT Authentication Profiles and is not yet treated as authenticated unless device login was completed.
  6. Confirm the built-in Environment Operator pipeline exists. Without Portainer it is present but environment operations are not ready.
  7. Confirm the installed services, routes, and built-in automation content match the reviewed release; do not add extra components during setup.

The combined deployment automatically pairs every current and future Headquarters workspace with its co-deployed Agent Manager. Do not look for a connection URL, callback secret, or connection selector in Headquarters.

If any check fails, stop. Record the failing command, HTTP status, or exact service state, then investigate that boundary. Do not continue into optional configuration to hide a core failure.

Stage 6 — Optional OpenAI embeddings#

Ask whether the operator wants Headquarters document embeddings and semantic vector search now. This OpenAI API project key is independent of the ChatGPT subscription used by Agent Manager workers. API billing must be enabled for the project.

If the operator declines, leave OPENAI_API_KEY empty. The core remains usable, but OpenAI-backed embeddings and semantic vector search are unavailable.

If the operator accepts, have them add the key directly to the retained private file:

sudoedit /opt/kiteyard/.env

Set exactly one value without printing it:

OPENAI_API_KEY=<enter-directly-on-host>

From the matching pinned source checkout, converge the installation and verify it again:

sudo node deploy/core/install.mjs install
sudo node /opt/kiteyard/install.mjs verify

Do not confuse OPENAI_API_KEY with Agent Manager's ChatGPT/Codex login. Do not place this API key in a worker, repository, browser prompt, or MCP client configuration unless a separate workflow explicitly requires it.

Stage 7 — Authenticate Agent Manager with ChatGPT#

This stage is required before real built-in Codex jobs. Ask the operator to confirm that the intended ChatGPT account has Codex access and sufficient usage for the planned workload.

Use the browser, not a copied auth.json file:

  1. Open Agent Manager at /agent-manager/ through the authenticated Headquarters session.
  2. Open Workers, disable Managed default worker, and wait until its managed instances have drained and stopped.
  3. Open Global Settings → ChatGPT Authentication Profiles.
  4. Select Default (legacy) for the first identity, or create a clearly named profile for a separate subscription.
  5. Select Start Login.
  6. Follow the displayed Codex device-code URL and code in the operator's own browser. Do not paste ChatGPT credentials or the device code into chat.
  7. Refresh until the profile shows a completed login.
  8. Re-enable the worker and wait until its instance reports idle/ready.

Each profile stores ChatGPT/Codex OAuth material in its own Docker volume; tokens are not stored in PostgreSQL or worker JSON. Disable and drain every consumer of a profile before signing in again later. Never delete .kiteyard-auth.lock or manually copy an auth.json into managed worker homes.

Private repository credentials for actual jobs are configured separately in Agent Manager. Give a pipeline only the repository and push authority it needs.

Stage 8 — Optional Portainer and environment VPS#

Offer this stage only after the core passes verification. Portainer may run on the same physical server or on a separate environment VPS, but it remains a separate Compose project and lifecycle.

The environment VPS needs Docker Engine and Compose. Agent Manager worker containers must be able to reach two private HTTPS MCP URLs ending exactly in /mcp. Never expose plaintext MCP to the public internet.

On the environment server, use the same reviewed repository revision:

cd kiteyard-source/deploy/portainer
cp .env.example .env
chmod 600 .env
openssl rand -hex 32

Ask the operator to place the generated 32-byte value in PORTAINER_MCP_AUTH_TOKEN inside this protected .env. Do not print or transmit it in chat.

For a fresh Portainer installation, start Portainer CE plus the managed and read-only official MCP processes:

docker compose --profile server config --quiet
docker compose --profile server pull
docker compose --profile server up -d
docker compose --profile server ps

For an existing Portainer installation, set PORTAINER_URL to an address reachable from the MCP containers and run the same commands without --profile server.

Then:

  1. Open Portainer through a private route and complete its one-time administrator setup.
  2. Create a dedicated Portainer identity or access token under My account → Access tokens.
  3. Limit that identity with Portainer RBAC to the intended endpoints and resources.
  4. Put private TLS or an encrypted private network in front of the managed listener (default loopback 17717) and read-only listener (default loopback 17718).
  5. Configure PORTAINER_MCP_ALLOWED_HOSTS, trusted proxy TLS, and the proxy's exact IP/CIDR when TLS terminates at a proxy.
  6. Keep the official Portainer and Portainer MCP minor versions matched.

Retain these four values in the operator's password manager:

PORTAINER_MCP_URL=https://portainer-mcp.example.com/mcp
PORTAINER_MCP_READ_ONLY_URL=https://portainer-mcp-read.example.com/mcp
PORTAINER_MCP_AUTH_TOKEN=<generated-mcp-gate-token>
PORTAINER_API_KEY=<dedicated-portainer-access-token>

The MCP gate token protects the MCP front door. The Portainer API key authorizes operations through Portainer and applies its RBAC. They are different credentials.

On the core server, add all four values together to /opt/kiteyard/.env, then converge from the matching source checkout:

sudoedit /opt/kiteyard/.env
sudo node deploy/core/install.mjs install
sudo node /opt/kiteyard/install.mjs verify

Do not configure only some of the four values. The installer rejects partial Portainer configuration.

Verify conservatively in Agent Manager:

  1. Open Environments and create Portainer connectivity.
  2. Choose observed, provider portainer, and deployment instructions that only list endpoints and stacks.
  3. Run Inspect and confirm live Portainer data appears in the normal job record.
  4. Change an environment to managed only after the read-only inspection succeeds and its deployment/rollback rules are explicit.

Managed environments receive the write MCP endpoint. Observed environments receive the strict read-only endpoint. Catalogued environments never launch jobs. For a target that will deploy a complete Kiteyard clone, Portainer endpoint policy must allow bind mounts because that target's Agent Manager runner manager mounts its Docker socket. Relax that setting only on a dedicated or isolated endpoint.

Stage 9 — Record operations and backup boundaries#

Before handing over the installation:

  • Record the exact source commit and selected image references without recording credentials.
  • Store ADMIN_ACCESS_TOKEN from /opt/kiteyard/.env in the operator's password manager without pasting or printing the full file.
  • Protect and back up /opt/kiteyard/.env; its stable encryption/authentication values are required to read existing data.
  • Arrange custom-format PostgreSQL backups for the kiteyard database.
  • Back up kiteyard_codex-home, kiteyard_retained-workspaces, and kiteyard_artifact-secrets.
  • Back up the separate kiteyard_portainer_data volume if Portainer is installed.
  • Keep verified backups off-host.

Before upgrades, pause Headquarters automation, drain/disable Agent Manager workers, back up the database and volumes, retain current image digests, and use the release's upgrade runbook. Never use docker compose down --volumes as an update command.

The original /root/kiteyard.env can be retained with mode 0600 or removed by the operator after confirming the retained configuration and backups. Do not delete it automatically.

Stage 10 — Optional Kiteyard MCP onboarding#

Finish by offering, not forcing, MCP onboarding. This is for an external Codex or Claude Code client to work in one Headquarters workspace. It is separate from the ChatGPT profile that authenticates Agent Manager workers.

Create an Agent user and token#

Ask the administrator to use the Kiteyard UI:

  1. Open Settings → Users → Add User.
  2. Choose account type Agent.
  3. Enter a clear name. Email is optional; an Agent receives no password and cannot sign in to the web app.
  4. Choose the least-privileged role needed, usually No role for a workspace MCP actor, then select Create Agent.
  5. Review the user's workspace access. New users default to all current and future workspaces unless an administrator narrows it.
  6. Switch to the workspace the client should use, then open Settings → MCP.
  7. Select the Agent user and leave Agent Manager tools off for ordinary Headquarters planning/backlog access.
  8. Select Create Token, then Copy. Store the token in the client's secret manager.

Agent Manager MCP grants are installation-wide operational authority and are off by default. They can be attached only to a token whose owner is an Administrator with unrestricted access to all current and future workspaces. Do not grant them to a routine planning agent.

The endpoint is the single public Kiteyard origin plus /mcp:

https://kiteyard.example.com/mcp

Configure Codex#

Make the token available to the Codex process through the user's secret manager or launcher. Keep it out of repositories and shared shell files. Then add the streamable HTTP server:

export KITEYARD_MCP_TOKEN='<token-from-settings>'
codex mcp add kiteyard \
  --url https://kiteyard.example.com/mcp \
  --bearer-token-env-var KITEYARD_MCP_TOKEN
codex mcp list
codex mcp get kiteyard --json

The equivalent ~/.codex/config.toml entry is:

[mcp_servers.kiteyard]
url = "https://kiteyard.example.com/mcp"
bearer_token_env_var = "KITEYARD_MCP_TOKEN"

Restart the Codex client after making its environment persistent. In Codex, use /mcp to confirm the server and its tools are available. The CLI, IDE extension, and Codex desktop app share the host's Codex MCP configuration.

Configure Claude Code#

For a user-scoped Claude Code connection, keep the token out of shell history by reading it silently, then use the current HTTP transport command:

read -rsp 'Kiteyard MCP token: ' KITEYARD_MCP_TOKEN; echo
claude mcp add --transport http kiteyard --scope user \
  https://kiteyard.example.com/mcp \
  --header "Authorization: Bearer $KITEYARD_MCP_TOKEN"
unset KITEYARD_MCP_TOKEN
claude mcp list
claude mcp get kiteyard

Claude Code stores user-scoped servers in ~/.claude.json. Protect that file because this command stores the resolved authorization header. In Claude Code, run /mcp and confirm kiteyard is connected.

Official client references:

Verify and hand off#

Start a fresh client session so it receives the current Kiteyard MCP server instructions. Ask it to perform a read-only workspace query before any mutation. Confirm that results belong to the intended workspace and are attributed to the Agent user.

If the client receives 401, verify that the token is enabled, copied exactly, and available to the client process. If it receives a workspace-access error, repair the Agent user's workspace grant in Headquarters rather than creating a broader token. Regenerating a token invalidates the old value; update every client that used it.

End with a concise installation record containing:

  • exact source commit and image references;
  • public Kiteyard origin;
  • core verification result and service state;
  • whether embeddings, ChatGPT login, Portainer, and MCP onboarding were completed or deferred;
  • backup locations and unresolved operator actions;
  • no secret values.