docs/runbooks/install.md

Install or Update Refine

Refine is an agentic software delivery system that runs locally against a user's application repository. It coordinates agents and humans through Goals, workflow state, provider CLIs, local processes, and a browser UI so software changes can move from request to implementation to human review.

Use this document when an agent is responsible for installing or updating Refine. Follow the steps in order, ask the user only the questions needed for the chosen path, confirm where Refine should be installed when you cannot infer it, and do not claim installation succeeded until the CLI reports a healthy running system or you have reported the exact blocker.

Prerequisites

  • Run on Linux, macOS, or Ubuntu/WSL. Windows users should open Ubuntu through WSL first.
  • Use a bash shell with network access.
  • Determine which dependency sources are available on this host before installing anything: system package managers, existing corporate mirrors, preinstalled toolchains, or manual user setup.
  • Make sure the user can approve dependency installation from the available source or choose to install missing dependencies manually.
  • Install or repair required dependencies before cloning or updating Refine: curl, git, a C compiler/linker, and Rust Cargo.
  • If using a real provider, make sure the user can complete that provider's CLI authentication on this host.

Ask If You Cannot Infer

Ask only when the answer is not clear from the user's environment, prior conversation, or existing files. Keep defaults unless the user has given a reason to choose otherwise.

  • Which agent provider should Refine use: claude, codex, gemini, or copilot?
  • Where should Refine be installed? Default: $HOME/refine.
  • Which UI port should Refine use? Default: 8082.
  • Which available dependency source should the agent use for missing tools?
  • Should missing provider CLI installation or provider authentication happen now, or should the user complete it later?

Install Refine

  1. Resolve the Refine checkout path before running install commands. If an existing Refine checkout or a user preference is not clear, ask where to install Refine and use $HOME/refine as the default.
  2. Check for required tools, identify reachable dependency sources, and install missing dependencies only from a source the user approves; the agent should make dependency choices explicitly.
curl --version
git --version
cc --version
cargo --version
  1. If Refine is already installed, follow the Update Refine section instead of a fresh clone, then continue with provider configuration below.
  2. For a fresh install, copy the latest published release files without a .git directory:
latest="$(
  git ls-remote --tags --refs https://github.com/buwilliams/refine.git \
    | awk -F/ '/refs\/tags\/[0-9]+\.[0-9]+\.[0-9]+$/ { print $NF }' \
    | sort -t. -k1,1n -k2,2n -k3,3n \
    | tail -n 1
)"
tmp="$(mktemp -d)"
git clone --depth 1 --branch "$latest" https://github.com/buwilliams/refine.git "$tmp/refine"
mkdir -p <refine-checkout>
tar -C "$tmp/refine" --exclude .git -cf - . | tar -C <refine-checkout> -xf -
rm -rf "$tmp"
  1. Register Refine's OS service for the selected port. Copying the release into the product home installs Refine; service registration is a separate host operation. This command assumes the prerequisites above are available, bootstraps the locked release binary when it is missing, atomically publishes it as bin/refine, marks the checkout as deployed, and only then registers and activates the port-scoped systemd or launchd service. It does not fetch or update Refine source:
cd <refine-checkout>
./r system service-install --port <port>
  1. Configure the selected provider:
cd <refine-checkout>
./r agent configure --provider <provider>
./r agent detect
  1. If the selected provider CLI is missing, install or authenticate it only after the user approves. Treat Refine installation and provider readiness separately.
  2. Use Refine's provider adapter when the user approves authentication now, then diagnose the same provider. This avoids baking provider-specific login syntax into the installation contract:
./r agent auth --provider <provider>
./r agent diagnose --provider <provider>

Do not offer smoke-ai during installation. It is reserved for deterministic tests.

Product and runtime ownership

The directory selected above is the product home. ./r always runs the stable production binary <refine-checkout>/bin/refine — never a debug build. ./r system start and ./r system build create or refresh that binary (rebuilding only when the source has changed since the last production build) and say so on stdout. ./r system service-install bootstraps the binary only when it is missing; it does not rebuild an existing binary as a side effect of service registration. Every other command requires it to already exist. The base runtime is <refine-checkout>/run, and port <port> owns only <refine-checkout>/run/<port>. ./r anchors the invocation to that product home; the directory from which a user launches it is not an ownership signal. Do not configure HOME, XDG, platform support directories, or a neighboring checkout as the runtime root.

Manage the production binary directly with:

./r system build   # rebuild bin/refine from source
./r system clean   # remove bin/refine and the deployed marker

These are checkout-launcher operations, not refine system subcommands, so they are intentionally absent from refine system --help and refine commands. Use ./r system build --help or ./r system clean --help for their direct help.

A published installation is intentionally gitless and is identified by .refine-deployed plus bin/refine. It supports ordinary daemon, web, MCP, provider, and published-update operations. Source status and source promotion require an actual Git checkout and will fail closed for a gitless product home.

Installing the product files, publishing the production binary, and managing the OS service are distinct operations. ./r system build publishes the production binary without changing service registration. ./r system service-install is the registration boundary; it also bootstraps a missing binary so first registration does not require a separate build. Current service registrations launch the checkout-local binary with the exact port and checkout-local runtime and use the checkout as their working directory. The current targets are macos_daemon, windows_daemon, and linux_cli_web. The historical JSON values mac_os_app_bundle and windows_installer are accepted only when reading migration-era state; new state is always written with current names.

Remove a selected port's OS service registration with:

./r system service-uninstall --port <port>

This stops and removes the port-scoped systemd or launchd registration. It is not a source update command and does not remove the Refine checkout or its published production binary.

Ordinary service registration/status reports a conflicting legacy external runtime or registration without changing it. ./r system repair --port <port> is the explicit migration boundary: it leaves external runtime and binary trees untouched, stores the exact original registration bytes, SHA-256, parsed identity, and final outcome under run/<port>/installation-migrations/, then atomically publishes only the new registration. If activation or byte verification fails, Refine restores the exact original registration and retains the journal.

Update Refine

./r system update is the deterministic one-command source update for a Git checkout. It is distinct from installing the product files and from registering or removing the OS service. It first fetches and checks the configured upstream. If there are no new upstream commits, it exits without stopping Refine or modifying the checkout. When an update is available, it runs these commands in order and stops immediately if any command fails:

./r system stop
git stash && git pull
./r system build
./r system start

The stash is not reapplied automatically. Because this path intentionally uses plain git stash, untracked files are not included. The command uses the default daemon port and runtime root and accepts no arguments.

The web UI's Controls > Management > Update Refine control remains a separate, restart-safe source-promotion workflow with durable progress and recovery.

The steps below remain for gitless published installations (a checkout without a usable .git directory), where the Git commands in ./r system update cannot succeed.

  1. Stop the running daemons first:
cd <refine-checkout>
./r system stop --port <port>
  1. Fetch the latest release and copy it over the checkout without a .git directory:
latest="$(
  git ls-remote --tags --refs https://github.com/buwilliams/refine.git \
    | awk -F/ '/refs\/tags\/[0-9]+\.[0-9]+\.[0-9]+$/ { print $NF }' \
    | sort -t. -k1,1n -k2,2n -k3,3n \
    | tail -n 1
)"
tmp="$(mktemp -d)"
git clone --depth 1 --branch "$latest" https://github.com/buwilliams/refine.git "$tmp/refine"
tar -C "$tmp/refine" --exclude .git -cf - . | tar -C <refine-checkout> -xf -
rm -rf "$tmp"
  1. Rebuild the release binary and mark the checkout as deployed:
cd <refine-checkout>
./r system build
  1. Restart Refine and verify it is healthy:
./r system start --port <port>
./r system status --port <port>

After Install

  1. Start and check Refine:
cd <refine-checkout>
./r system start --port <port>
./r system status --port <port>
./r system doctor --repo-root .
  1. Open the UI at http://localhost:<port>. The default is http://localhost:8082.
  2. Attach or create the target app if the target is already clear:
./r project attach /path/to/app
./r project clone <remote-url> /path/to/app --make-current
  1. If creating a new app, run the user-approved starter command in the new app directory, make the initial git commit, then attach the app.
  2. Finish with the Refine checkout path, UI URL, selected provider, target app status, and summaries from ./r system status and ./r system doctor.
  3. If no target app is clear, leave Refine running without one and report that the target app still needs to be selected.
  4. Ask only the app guidance needed to continue: should Refine update an existing local app, clone an existing remote app, create a new app, or wait with no target app yet?

CLI Management

Use ./r --help and ./r <group> --help as the source of truth for production-binary management commands, plus the direct launcher help described above for system build and system clean. There is no generic ./r status; use the specific command group.

Core management commands:

cd <refine-checkout>
./r system status --port <port>
./r system doctor --repo-root .
./r project status
./r project doctor
./r agent detect
./r agent diagnose --provider <provider>

Runtime lifecycle commands:

./r system start --port <port>
./r system stop --port <port>
./r system restart --port <port>
./r system repair --port <port>
./r system update

OS service registration commands:

./r system service-install --port <port>
./r system service-uninstall --port <port>

Use --runtime-root run only as compatibility syntax for this checkout's canonical run directory. Any other relative value, or an absolute path that is not the exact canonical runtime of the invoked product home, is rejected.

Target app commands:

./r project attach /path/to/app
./r project switch <registered-project>
./r project detach
./r project register <name> /path/to/app
./r project clone <remote-url> /path/to/app

Workflow and Goal commands:

./r goal create "Describe the product goal"
./r goal list
./r goal show <goal-id>
./r workflow pause
./r workflow resume

Distributed/node commands:

./r node list
./r node settings <node-id>
./r fleet list
./r fleet maintenance
./r fleet distribute [--to <node-id>] [--converge] [--dry-run]

Refine publishes durable state automatically on the dedicated refine/state branch without touching application branches. Its live projection and isolated state worktree live under the target repository's Git common directory as refine-live-state/ and refine-state-worktree/; do not assume that directory is <app>/.git when the app is a linked worktree. <app>/.refine never exists in the primary target-app worktree. Goal logs under refine-live-state/runtime/goals/ are node-local and are not published. The Target App Git remote setting controls both state and Goal-branch publication and defaults to origin. If that remote is unavailable, Refine still initializes and commits local state; it simply cannot publish it. Use project sync or the Node screen's Sync state now action when a state handoff must happen immediately; fleet sync invokes the same shared capability for the current node. Manual sync is queued in a supervised runner process, and the UI reports its progress and any terminal error without blocking the daemon.

Refine-owned durable state

Beyond refine-live-state/ and refine-state-worktree/, Refine keeps these artifacts under the target repository's Git common directory and runtime root. Each is normal to encounter; only the first is safe to delete by hand.

  • refine-integration/target (in the Git common directory): a permanent detached worktree where integration porcelain runs, so the shared human checkout never has to be clean for an integration. It is invisible to git status, appears in git worktree list locked with reason "refine integration workspace", and persists between integrations because recreating a large checkout is expensive. Safe to purge when Refine is not integrating: it self-recreates on the next integration.
  • refine-checkout-sync-pending.json (in the Git common directory): records a checkout sync that a working-tree collision (or other sync failure) skipped. While it exists, the target branch ref already points at the integrated commit but the checkout's index and files still hold the pre-integration content, so the checkout shows the integration delta as staged-reverse — this file is the explanation. Do not delete it: it encodes the unapplied ref delta, and Refine retries the sync and clears the record once the colliding files are committed, stashed, or restored.
  • refine-integrated-target-transaction.json (in the Git common directory): marks an integrated-target transaction in progress so an interrupted one is recovered on the next pass. Do not delete it: it encodes which Goal owns the interruption. Recovery recreates the Refine-owned integration worktree instead of quarantining its residue, replays any pending checkout sync, and appends what it did to refine-integrated-target-recoveries.jsonl alongside it; only legacy shared-checkout markers still quarantine residue to a stash.

Worker machine creation is agent-operated rather than part of the Refine binary. Follow docs/runbooks/manage-fleet.md when a fleet needs another worker.

Operating Refine after install

If you are an agent operating Refine for a user (not just installing it), three entry points make the surface self-navigating — prefer them over reading source code:

  • ./r next — recommends the next operations from current project and fleet state, each with the exact command. Call it whenever you are deciding what to do next.
  • ./r commands — machine-readable JSON catalog of supported user-facing production-binary commands with descriptions. Load once instead of exploring --help per subcommand.
  • docs/runbooks/ — task-oriented guides (manage the fleet, distribute and converge work) with preconditions, user questions, verification, and undo steps.

When a command fails, report the exact command, exit code, stdout/stderr summary, and any relevant log path. Prefer CLI evidence over guessing from browser state.