Skip to content

Operations Guide

This guide covers the parts of LoopTroop you deal with after the first run: startup maintenance, runtime storage, project-local Git hygiene, worktree cleanup, diagnostics, and common local service issues.

Quick Reference

TaskStart here
Start the full local stacknpm run dev
Start once without dependency/audit mutationLOOPTROOP_DEV_SKIP_DEPS=1 npm run dev
Skip only the local OpenCode CLI upgradeLOOPTROOP_DEV_SKIP_OPENCODE_UPGRADE=1 npm run dev
Force all startup maintenance nowLOOPTROOP_DEV_FORCE_MAINTENANCE=1 npm run dev
Show raw maintenance output and full startup diagnosticsLOOPTROOP_DEV_VERBOSE=1 npm run dev
Diagnose slow UI or ticket refresh stallsnpm run diagnose:stall
Clean tracked LoopTroop runtime paths from a projectgit rm --cached -r .looptroop inside the attached project

Runtime Storage

LoopTroop deliberately separates app-level state from project-level runtime state.

LocationContentsNotes
~/.config/looptroop/app.sqliteApp settings, profiles, and attached-project registryOverride with LOOPTROOP_CONFIG_DIR or LOOPTROOP_APP_DB_PATH
<project>/.looptroop/db.sqliteProject tickets, phase artifacts, attempts, sessions, status history, and error occurrencesProject-local operational database
<project>/.looptroop/worktrees/<ticket>/Ticket-owned Git worktree and .ticket/** runtime artifactsOne worktree per ticket
<ticket-worktree>/.ticket/runtime/Execution logs, stream state, locks, session records, temporary files, and state projectionPreserved or cleaned according to ticket outcome and cleanup choice

LoopTroop adds /.looptroop/ to the repository-local .git/info/exclude file when a project is attached. That keeps runtime state out of normal Git status without modifying the project's committed .gitignore.

Startup Maintenance

npm run dev starts the frontend, backend, docs server, and OpenCode watcher stack. Before those services launch, LoopTroop runs a dev preflight that:

  • verifies required local dev binaries exist, using npm ci when dependencies need to be restored
  • checks direct dependencies against npm publish metadata
  • updates stale direct dependencies only to stable releases that are newer than the current installed version and at least 7 days old
  • holds newer releases that are still inside that 7-day delay, and installs the newest eligible older release when one exists
  • previews npm audit fix lockfile changes and runs the fix only when every proposed npm package version has passed the same 7-day delay
  • upgrades the local opencode CLI to the latest available version when the binary is installed
  • checks and reclaims only stale LoopTroop-owned processes on configured ports
  • prints concise startup summaries by default, including held dependency and audit package releases with their next eligible times or reasons, while audit finding details, raw npm install output, socket snapshots, and the full service plan remain available through LOOPTROOP_DEV_VERBOSE=1

npm run dev also resolves the local OpenCode server endpoint before the dev services launch:

  • Reuse: if the configured address is already responding to authenticated requests, npm run dev reuses that running instance.
  • Port fallback: if the default port (4096) is occupied by a non-OpenCode process, npm run dev scans for the next free port and starts OpenCode there instead.
  • Ephemeral auth: if OPENCODE_SERVER_PASSWORD is not set and a new local OpenCode server is about to start, npm run dev generates a random credential and sets OPENCODE_SERVER_USERNAME to opencode. This credential is propagated automatically to all child processes — backend and watcher — for the duration of the session.
  • Ephemeral API token: if LOOPTROOP_API_TOKEN is not set, npm run dev generates one for the backend and Vite dev proxy so local same-origin /api/* calls are protected without embedding the token in the frontend bundle.

That means npm run dev can intentionally mutate local dependency files when aged direct dependency updates or audit fixes are available. The expensive networked maintenance work is daily-gated during normal startup. Direct dependency sync, npm audit remediation, and OpenCode CLI upgrade checks run on the first local dev start of the day. If package.json or package-lock.json changes later the same day, the affected maintenance step runs again immediately.

The 7-day release delay applies to direct npm package updates selected by dependency sync and to all npm package versions proposed by audit remediation. Audit remediation is all-or-nothing: if npm proposes any package version that is too fresh or whose publish time cannot be verified, LoopTroop holds the entire npm audit fix attempt and reports the held packages plus their next eligible times, or the reason a time is unavailable, during normal startup. Use LOOPTROOP_DEV_VERBOSE=1 to add known audit finding notes and other low-level diagnostics. OpenCode is exempt: the local OpenCode CLI and the direct @opencode-ai/sdk package update immediately when their normal maintenance path runs.

Maintenance Commands

Run the individual maintenance steps directly when you need tighter control:

bash
npm run deps:sync
npm run audit:remediate
npm run opencode:upgrade

Use one-run startup flags when you want to change npm run dev behavior:

bash
LOOPTROOP_DEV_SKIP_DEPS=1 npm run dev
LOOPTROOP_DEV_SKIP_OPENCODE_UPGRADE=1 npm run dev
LOOPTROOP_DEV_FORCE_MAINTENANCE=1 npm run dev
LOOPTROOP_DEV_VERBOSE=1 npm run dev

Scripts Reference

All scripts are available with npm run <name>.

Development Stack

ScriptPurpose
devFull stack: frontend, backend, docs server, OpenCode watcher, and dev preflight. Standard start command.
dev:appFrontend and backend only — no docs server, no OpenCode watcher. Use when OpenCode is already running externally and docs are not needed locally.
dev:frontendVite dev server only.
dev:backendBackend Express server only.
dev:opencodeOpenCode watcher only.
docs:devVitePress docs server only.

Build And Preview

ScriptPurpose
buildType-check and produce a production frontend bundle (tsc -b && vite build).
previewServe the last production build locally for inspection.
docs:buildBuild the static VitePress docs site.
docs:previewServe the last static docs build locally.

Tests And Code Quality

ScriptPurpose
testRun all test projects once and exit.
test:clientClient tests only (client-dom and client-node projects).
test:serverServer tests only (server-pure and server-integration projects).
test:watchRun all tests in watch mode. Useful during active development.
typecheckType-check the full project with tsc --noEmit.
lintLint the full project with ESLint.

vitest.config.ts defines four test projects:

  • client-dom — React component tests that require a JSDOM environment
  • client-node — client-side logic tests that do not need a DOM
  • server-pure — server unit tests with no I/O or database
  • server-integration — server integration tests running against a real local SQLite instance

Run test:client and test:server separately when you only want to validate one layer. Run test to validate both together.

Database Schema Tools

ScriptPurpose
db:generateGenerate app DB migration artifacts for external tooling review. Alias for db:generate:app; normal app schema changes still need server/db/schema.ts and runtime bootstrap updates in server/db/init.ts.
db:generate:appGenerate app DB migration artifacts from the configured app database target. Verify output against server/db/schema.ts before committing.
db:generate:projectGenerate project DB migration artifacts from LOOPTROOP_PROJECT_DB_PATH.
db:pushApp DB push command retained for ad-hoc local experiments only; do not use as the normal app schema-change workflow.
db:push:appSame as db:push; avoid for normal app schema changes because runtime bootstrap owns app DB creation/evolution.
db:push:projectPush schema changes directly to the project database target from LOOPTROOP_PROJECT_DB_PATH.

The app database is runtime-bootstrapped by server/db/init.ts. The committed migration directory is not the source of truth for live app startup. Project DB work should use the explicit project scripts.

Environment Variables

VariablePurpose
LOOPTROOP_FRONTEND_PORTOverride frontend port; also drives the default frontend origin when LOOPTROOP_FRONTEND_ORIGIN is unset
LOOPTROOP_FRONTEND_ORIGINOverride full frontend origin URL, for example http://my-server:5173; a valid explicit origin takes precedence over LOOPTROOP_FRONTEND_PORT, while an invalid value falls back to the default origin
LOOPTROOP_BACKEND_HOSTBackend bind host; defaults to 127.0.0.1
LOOPTROOP_BACKEND_PORTOverride backend port
LOOPTROOP_ALLOW_REMOTE_API=1Required before binding the backend to a non-loopback host; remote binds still require LOOPTROOP_API_TOKEN
LOOPTROOP_ALLOW_UNAUTHENTICATED=1Permit unauthenticated /api/* access only when no LOOPTROOP_API_TOKEN is configured; intended for local-only troubleshooting, not remote exposure
LOOPTROOP_API_TOKENOptional token required by /api/*; npm run dev generates an ephemeral value when unset and the Vite dev proxy forwards it server-side
LOOPTROOP_TRUST_PROXY=1Trust x-forwarded-for / x-real-ip for rate-limit buckets; leave unset unless a trusted proxy owns those headers
LOOPTROOP_ENABLE_DEV_EVENT=1Enable the development-only ticket event injection route when paired with LOOPTROOP_DEV_EVENT_TOKEN
LOOPTROOP_DEV_EVENT_TOKENRequired secret for the dev-event route when it is enabled
LOOPTROOP_DOCS_PORTOverride docs port
LOOPTROOP_DOCS_ORIGINOverride full docs origin URL, for example http://my-server:5174; takes precedence over LOOPTROOP_DOCS_PORT
LOOPTROOP_OPENCODE_BASE_URLPoint LoopTroop at a specific OpenCode server
LOOPTROOP_CONFIG_DIROverride the app config directory
LOOPTROOP_APP_DB_PATHOverride the app database path directly
LOOPTROOP_PROJECT_DB_PATHProject database target for explicit Drizzle project DB commands
LOOPTROOP_DEV_VERBOSE=1Print full dependency, audit, npm install, service-plan, and process details during dev preflight
LOOPTROOP_DEV_SKIP_DEPS=1Skip automatic dependency sync and audit remediation during npm run dev
LOOPTROOP_DEV_SKIP_OPENCODE_UPGRADE=1Skip the automatic local OpenCode CLI upgrade during npm run dev
LOOPTROOP_DEV_FORCE_MAINTENANCE=1Bypass the once-per-day maintenance gate and force all startup maintenance checks now
LOOPTROOP_OPENCODE_MODESet to mock to use the mock adapter instead of the real SDK adapter
CHOKIDAR_USEPOLLINGSet to 1 to force chokidar polling for file watching; auto-set on mounted WSL drives, but can be overridden manually
OPENCODE_SERVER_USERNAMEBasic auth username for the local OpenCode dev server; defaults to opencode when OPENCODE_SERVER_PASSWORD is also set
OPENCODE_SERVER_PASSWORDBasic auth password for the local OpenCode dev server; auto-generated as an ephemeral random credential by npm run dev if not set and a new local OpenCode server is about to start

Default local service addresses:

ServiceAddress
Frontendhttp://localhost:5173
Backendhttp://127.0.0.1:3000
Docshttp://localhost:5174
OpenCodehttp://127.0.0.1:4096

When LOOPTROOP_FRONTEND_ORIGIN is not explicitly set, LoopTroop derives the frontend origin from LOOPTROOP_FRONTEND_PORT, defaulting to http://localhost:5173. If LOOPTROOP_FRONTEND_ORIGIN is set but cannot be parsed as a URL origin, LoopTroop ignores it and falls back to that derived default.

API Rate Limits

The backend applies a global per-client rate limit to /api/* routes. Read requests, normal write actions, and UI-state autosaves use separate buckets so frequent draft saves do not exhaust the workflow-action budget. Defaults are 200 reads/minute, 120 normal writes/minute, and 300 autosaves/minute per client. If a client exceeds a limit, the API returns 429 with a Retry-After response header in seconds. Wait for that interval before retrying requests or refreshing aggressively.

Forwarded client IP headers are ignored unless LOOPTROOP_TRUST_PROXY=1 is set. This keeps local clients from bypassing limits by spoofing x-forwarded-for.

Project Git Hygiene

If .looptroop was already tracked before the project was attached, ticket startup is blocked with INIT_LOOPTROOP_TRACKED. This prevents nested or stale LoopTroop worktree data from being checked out into every new ticket worktree.

Clean that repository from the attached project root:

bash
git rm --cached -r .looptroop
git commit -m "Stop tracking LoopTroop runtime data"

This removes LoopTroop runtime paths from the Git index without deleting the local runtime files from disk.

After cleanup, git status --short .looptroop should not show tracked .looptroop entries. Runtime files may still exist locally, but they should be ignored by the repo-local exclude.

Other ticket initialization errors from the Git hygiene check:

  • INIT_LOOPTROOP_EXCLUDE_FAILED — LoopTroop could not write the .looptroop/ exclusion to .git/info/exclude. Check that the project's .git directory is writable.
  • INIT_LOOPTROOP_TRACKED_CHECK_FAILED — The git ls-files check itself failed. Verify that the attached project path is a valid, accessible Git repository.

Worktree Disk Cleanup

Over time .looptroop/worktrees/ can grow large as completed and canceled tickets leave behind code checkouts, execution logs, and generated file artifacts.

Use the UI cleanup flow:

  1. Open Settings -> Projects and click Edit on the project you want to clean up.
  2. Click Free Disk Space... at the bottom-left, next to Delete Project.
  3. Click Calculate Size to see how much space can be freed.
  4. Click Delete Worktrees to remove worktrees for completed and canceled tickets.

Deleted: temporary directories at .looptroop/worktrees/<ticket>/ for tickets in the Completed or Canceled column, including code checkouts, execution logs, and AI-generated file artifacts.

Preserved:

  • project source code and normal repository files
  • active, queued, and draft ticket worktrees
  • ticket records in the dashboard, including title, description, and status

Diagnostics

If the UI feels slow, tickets disappear after refresh, or the app appears to stall, run the diagnostic command while npm run dev is still running:

bash
npm run diagnose:stall

The report is saved under tmp/diagnostics/ and includes endpoint latency, backend/frontend/OpenCode activity, whole-system CPU/RSS/I/O consumers, pressure-stall metrics, SQLite/WAL state, attached project health, active sessions, Git responsiveness, and a likely-causes summary.

Useful options:

bash
npm run diagnose:stall -- --sample-ms 5000
npm run diagnose:stall -- --timeout-ms 8000
npm run diagnose:stall -- --trend-ms 120000 --trend-interval-ms 1000

For the full report guide, see Runtime Diagnostics.

OpenCode Reachability

Symptoms:

  • the model list in the UI is empty
  • ticket logs show connection errors
  • phases that need a model block before drafting, setup, or execution

Checks:

When using npm run dev, port resolution and basic auth are handled automatically. The checks below apply when OpenCode is still unreachable after startup or when running the backend outside of npm run dev.

  1. Ensure OpenCode is running: opencode serve.
  2. Ping the backend health endpoint: curl http://127.0.0.1:3000/api/health/opencode. If you configured LOOPTROOP_API_TOKEN, include -H "X-LoopTroop-Token: $LOOPTROOP_API_TOKEN".
  3. If OpenCode is on a non-default port, set LOOPTROOP_OPENCODE_BASE_URL, for example export LOOPTROOP_OPENCODE_BASE_URL=http://127.0.0.1:4097.
  4. If you started OpenCode outside of npm run dev, ensure OPENCODE_SERVER_PASSWORD and OPENCODE_SERVER_USERNAME match the values LoopTroop is using. A credential mismatch causes silently failed requests.

Watcher and Filesystem Notes

The backend watcher prefers native file watching on normal local filesystems. Under WSL, mounted-drive workspaces such as /mnt/... can be slower and may need polling. LoopTroop auto-enables chokidar polling for those mounted-drive workspaces.

If your environment still misses file changes, force polling for the run:

bash
CHOKIDAR_USEPOLLING=1 npm run dev

Audit Warnings

npm audit --omit=dev should be clean. A full npm audit can still report dev-only moderate findings through transitive dev-server tooling:

  • drizzle-kit stable still depends on deprecated @esbuild-kit/*, which brings an older esbuild. The upstream issue is tracked here: drizzle-team/drizzle-orm#3067.
  • vitepress stable still brings its own older Vite/esbuild line. The current audit path reports the esbuild development-server advisory GHSA-67mh-4wv8-2f99.

Do not run npm audit fix --force as routine maintenance for these warnings. The current forced fix path proposes a breaking drizzle-kit downgrade and does not represent a safe application hardening change.

LoopTroop documentation for the current runtime.