AMS deployment guide
Deploy @loopover/miner in laptop mode (single machine, zero Docker) or fleet mode (containerized workers) -- both 100% client-side, credentials never baked into images.
Two form factors for running @loopover/miner: laptop mode (single machine, zero Docker) and
fleet mode (containerized workers with a shared data volume). Both are 100% client-side for
core operation — the miner never uploads source and never requires a hosted LoopOver callback to
boot. Credentials (GitHub tokens, etc.) stay on the operator's machine or in their own secret
store; nothing is baked into images.
- Laptop mode
- Best for one contributor machine or local experimentation. Needs only Node.js >=22.13.0. State is SQLite files under ~/.config/loopover-miner/ (override with LOOPOVER_MINER_CONFIG_DIR). Setup is npm install -g @loopover/miner or a workspace build — one Node process, local disk for ledgers/queues.
- Fleet mode
- Best for many parallel miner attempts on a host or small cluster. Needs Docker (or a compatible runtime) + the miner image. Same SQLite layout, but on a mounted /data (or LOOPOVER_MINER_CONFIG_DIR) volume. Setup is docker build + docker run with env and a volume — one container per worker, scale horizontally by adding containers.
Coding-agent provider configuration
For provider selection and the CLI-specific model/timeout overrides, see Coding-agent driver.
Laptop mode walkthrough
Install Node.js and the package
npm install -g @loopover/miner@latest
# or from a checkout:
npm install && npm --workspace @loopover/miner run buildbashInspect the install and local state
status and doctor stay offline; init --verify-token is optional and makes one authenticated
GitHub call up front:
loopover-miner status
loopover-miner doctor
loopover-miner init --verify-token # optional: validate GITHUB_TOKEN once before attempts
loopover-miner init --interactive # optional: guided prompt for GITHUB_TOKEN + provider, writes a starter .env, then reruns doctorbashinit --interactive offers "Authorize with GitHub" (device flow — visit a URL, enter a short
code, no token to copy or paste) as its first option once the miner's GitHub App OAuth client is
configured; the original pasted-PAT prompt stays available as option 2, and is what the wizard
falls back to automatically on any device-flow failure. Unconfigured, the wizard is
byte-identical to the pasted-token-only prompt. Either way, the resulting GITHUB_TOKEN acts as
your own GitHub account — there is no separate bot identity.
Expected layout after first use
Sixteen SQLite stores default into one directory (default paths shown):
~/.config/loopover-miner/
laptop-state.sqlite3 # laptop-mode setup state, created by `init`
portfolio-queue.sqlite3 # prioritized work backlog across tracked repos
claim-ledger.sqlite3 # soft issue claims
plan-store.sqlite3 # persisted MCP plan DAGs
run-state.sqlite3 # per-repo run state (idle/discovering/planning/preparing)
event-ledger.sqlite3 # append-only miner-loop event audit trail
governor-ledger.sqlite3 # append-only governor allow/deny/throttle decisions
governor-state.sqlite3 # governor cross-attempt counters/state
attempt-log.sqlite3 # per-attempt coding-agent driver event trace
worktree-allocator.sqlite3 # git-worktree-per-attempt allocation bookkeeping
prediction-ledger.sqlite3 # predicted-gate verdicts, for later self-improve scoring
replay-snapshot.sqlite3 # frozen historical-replay target snapshots
policy-doc-cache.sqlite3 # ETag cache for discovery's policy-doc fetches
policy-verdict-cache.sqlite3 # cache of resolved AI-usage-policy verdicts
deny-hook-synthesis.sqlite3 # synthesized PreToolUse deny-hook proposals
orb-export.sqlite3 # opt-in anonymized Orb telemetry export stateNot every file appears immediately: laptop-state is written by init, and each of the others is
created the first time its subsystem actually runs (an attempt, a discovery pass, a replay, an Orb
export, …), so a fresh install that has only run status/doctor shows a subset. Override the
directory for every store at once with LOOPOVER_MINER_CONFIG_DIR or XDG_CONFIG_HOME; every
store except laptop-state.sqlite3 (directory only) also honors its own
LOOPOVER_MINER_<NAME>_DB path override to relocate an individual file. doctor's
store-integrity:* checks report the persistent stores, so it is the quickest way to confirm what
exists and is readable on disk.
Optional per-repo miner goals
Copy .loopover-miner.yml.example (repo root) to a target repo as .loopover-miner.yml. See the
MinerGoalSpec field reference.
Fleet mode walkthrough
Build the fleet image from the monorepo root (the Dockerfile needs the full workspace on disk
before npm ci):
docker build -f packages/loopover-miner/Dockerfile -t loopover-miner:latest .bashRun a disposable worker with persistent SQLite state on a mounted volume. Inject secrets at runtime (never bake them into the image):
docker run --rm -it \
-e LOOPOVER_MINER_CONFIG_DIR=/data/miner \
-e GITHUB_TOKEN \
-v miner-data:/data/miner \
loopover-miner:latest \
doctorbashThe image entrypoint is loopover-miner; pass subcommands after the image name (status,
doctor, claim, …).
- /data/miner volume
- Holds all SQLite state (claim-ledger.sqlite3, plan-store.sqlite3, etc.) so containers are disposable. Defaults to LOOPOVER_MINER_CONFIG_DIR=/data/miner in the image.
- GITHUB_TOKEN
- Supplied by the operator at run time; the image contains no credentials.
- Scale
- Launch additional containers with the same volume (or partitioned config dirs) for parallel attempts.
A plain -e GITHUB_TOKEN value is visible in plaintext via docker inspect/docker compose config and any full-env dump of the running container. For Docker Swarm/Kubernetes-managed
secrets (mounted as a file, e.g. at /run/secrets/github_token), set GITHUB_TOKEN_FILE to that
mount path instead — the miner reads and trims the file's contents at startup and uses it exactly
as if GITHUB_TOKEN had been set directly. If both are set, the plain GITHUB_TOKEN value
always wins. A missing or unreadable GITHUB_TOKEN_FILE fails the container fast with a clear
error naming the file path, rather than silently proceeding with no credential.
docker run --rm -it \
-e LOOPOVER_MINER_CONFIG_DIR=/data/miner \
-e GITHUB_TOKEN_FILE=/run/secrets/github_token \
-v miner-data:/data/miner \
-v /path/to/your/secret:/run/secrets/github_token:ro \
loopover-miner:latest \
doctorbashThe repo-root docker-compose.yml documents the self-hosted review stack (the LoopOver
API/Orb), not the miner CLI. Miners are clients of that stack (or of github.com directly) and do
not require it to run locally.
Docker Compose (fleet mode)
Instead of a hand-assembled docker run,
docker-compose.miner.yml
defines a long-lived miner service (built from this package's Dockerfile,
restart: unless-stopped, state on a named miner-data volume). Credentials come from an env
file, never inlined:
cp .loopover-miner.env.example .loopover-miner.env # fill in GITHUB_TOKEN (+ optional provider keys)
docker compose -f docker-compose.miner.yml up -d --buildbashdocker compose -f docker-compose.miner.yml up -d --scale miner=N gives every replica the
same miner-data volume — and the miner's SQLite ledgers are not safe for concurrent
access, so N replicas on one volume will contend/corrupt. To run N isolated workers, give
each its own state: run N separate compose projects (docker compose -p miner-1 …, -p miner-2 … — -p namespaces the volume) or point each at a distinct LOOPOVER_MINER_CONFIG_DIR on its
own mount. For built-in isolated horizontal scaling, use the Kubernetes StatefulSet in
k8s/ (per-pod volumes).
Bridging AMS state with ORB observability
Running fleet mode alongside ORB's self-hosted observability profile needs one extra step so the Grafana AMS panels actually populate — the fleet miner's named Docker volume and the host directory ORB's exporter reads don't line up on their own. See Running ORB and AMS together for the full walkthrough.
Bare-host (systemd, no Docker)
To run the miner continuously on a plain Linux host without Docker, supervise loopover-miner loop — the autonomous discover → attempt → manage daemon — with systemd.
systemd/loopover-miner.service.example
is a ready-to-adapt persistent unit; its header carries the full install steps:
npm install -g @loopover/miner
loopover-miner init --verify-token # optional: validate GITHUB_TOKEN before discovery/attempt runs
sudo cp systemd/loopover-miner.service.example /etc/systemd/system/loopover-miner.service
sudo $EDITOR /etc/systemd/system/loopover-miner.service # set User / WorkingDirectory / ExecStart / secrets
sudo systemctl daemon-reload
sudo systemctl enable --now loopover-miner.servicebashBecause loop is a long-running daemon that schedules its own cycles, it is a persistent
Type=simple service (with Restart=on-failure) — not a oneshot unit driven by a .timer.
Keep GITHUB_TOKEN (and any coding-agent credentials) in a root-owned 0600 EnvironmentFile,
never in the unit file. Follow the loop with journalctl -u loopover-miner -f; systemctl stop
sends SIGTERM, which the loop handles cleanly at its next kill-switch check.
Want the dashboard too?
systemd/loopover-miner-ui.service.example
is a companion unit that serves apps/loopover-miner-ui persistently over the same local state.
Invariants
- Core miner bookkeeping (claims, plans, queues, ledgers) works offline after install.
loopover-miner statusandloopover-miner doctormake no network calls.- Discovery/ranking primitives that touch GitHub only run when explicitly invoked and only perform documented GETs unless a future command says otherwise.
- Operators own secret injection; images and packages ship without embedded tokens.
- AMS works against any GitHub repository — it does not require ORB installed, gittensor
registration, or a
.loopover.ymlfile on the target repo to function.
loopover-miner init, doctor, and discover <owner/repo> were run end to end against real
public GitHub repositories with no .loopover.yml and no gittensor registration, using only a
plain GITHUB_TOKEN — every step worked as documented, including correctly returning zero
candidates on a repo with no open issues and ranking real issues on repos that had them. The
loopover-mcp login device-flow session path (a separate mechanism from AMS's own credential
resolution) currently has a known reliability issue independent of AMS itself — see the linked
issue tracker for status before relying on it for unattended AMS setups.
For operational scenarios (ledger corruption, two miners on one state dir, post-upgrade schema migration) see the AMS operations runbook, and for measured CPU/RAM/disk sizing see Resource sizing.
Optional hosted discovery plane (opt-in)
The hosted discovery-index is off by default — unlike Orb fleet export (ORB_AIR_GAP is the
only opt-out). Operators who want cross-fleet metadata queries or soft-claim coordination must opt
in explicitly. See the hosted discovery plane operator guide.