BUILDMENDER / DOCUMENTATION / 0.2

Run & test guide

Product branding: BuildMender. Existing commands and configuration retain the ci-resolve name.

BuildMender 0.2: detailed run and testing guide

Updated: 4 November 2026 Application: BuildMender 0.2.0 (existing package: ci-resolve) Workspace path: /Users/subashthiruppathy/Documents/projects/ci-resolve Product name: BuildMender; see naming notes. The website and dashboard use BuildMender. The application directory, package, environment variables, repair branches and commands still use ci-resolve for compatibility.

Product website: / includes interactive platform and workflow sections. Browser-readable guides are under /guides/; the application remains at /app. See website deployment and testing for the standalone static build.

This guide covers one-time installation, running the dashboard, running automated tests, connecting unattended operation, testing a real repair, observing results, troubleshooting, and maintaining a background service.

Normal operation after setup: collect → reproduce → repair → verify → publish → observe CI/merge → resolve. Manual log uploads and per-failure commands are optional diagnostic tools, not requirements for the automated path.

Contents

  1. Choose what you want to run
  2. Prerequisites
  3. Open the project and check the installation
  4. Run a preview without live automation
  5. Run the automated test suite
  6. Enable browser tests
  7. Run selected tests
  8. Understand what the tests prove
  9. Connect a target repository once
  10. Configure credentials once
  11. Configure the execution policy
  12. Start unattended operation
  13. Perform a real GitHub canary test
  14. Read the dashboard and API
  15. Interpret workflow states
  16. Test rejection and recovery behavior
  17. Optional manual diagnostic commands
  18. Run automatically after macOS login
  19. Stop, restart, and change configuration
  20. Back up and restore local state
  21. Troubleshoot common problems
  22. Current support limits
  23. Acceptance checklist
  24. Quick command reference
  25. References

1. Choose what you want to run

GoalGitHub/model credentialsDockerBrowser dependencyStarting section
View the dashboard and labeled sampleNoNoYour normal browserSection 4
Run core, API, CLI and automation testsNoNoNoSection 5
Include automated desktop/mobile browser testsNoNoPython Playwright + ChromiumSection 6
Run unattended repairs against GitHubYesYes for default backendOptionalSections 9–13
Run a trusted-local controlled pilotYes for live servicesNoOptionalSection 11

The test suite uses temporary local repositories and simulated external responses. It does not need access to your GitHub repositories, a paid model account, or a running Docker daemon.

Live automation can create repair branches, PRs and merges in the repositories you configure. Use a dedicated canary repository for the first live test.

2. Prerequisites

Required for the application and core tests

There are no npm runtime dependencies. SQLite is provided through Node's built-in node:sqlite module.

Additional requirements for live automation

Additional requirement for browser tests

A supported Python 3 installation, the Python playwright package, and its Chromium browser. These are development-test dependencies, not application runtime dependencies.

The command examples use macOS/Linux shell syntax. Native Windows service installation and Windows execution recipes are not covered.

3. Open the project and check the installation

Open Terminal and run:

cd /Users/subashthiruppathy/Documents/projects/ci-resolve
export CI_GUIDE_APP="$PWD"
node --version
npm --version
git --version

Expected: Node reports v24.x or newer; npm and Git print their versions.

The variables above belong to that terminal session. In a new terminal, rerun the absolute cd command and export CI_GUIDE_APP="$PWD" before using the variable-based examples.

Check JavaScript syntax:

npm run check

Expected: exit status zero with no syntax errors.

A dependency installation is not required to start this version. If you want npm to verify the lockfile state, run:

npm ci --ignore-scripts

Run commands from the application directory unless a section explicitly switches to the target repository. The application directory and the repository being repaired are different concepts.

4. Run a preview without live automation

4.1 Create isolated preview state

This makes the preview independent of any existing live policy or database:

cd "$CI_GUIDE_APP"
CI_GUIDE_PREVIEW="$(mktemp -d)"
CI_RESOLVE_CONFIG="$CI_GUIDE_PREVIEW/no-automation.json" \
CI_RESOLVE_DB="$CI_GUIDE_PREVIEW/preview.sqlite" \
npm start

Do not create no-automation.json; its absence intentionally disables the worker for this preview. These environment assignments apply only to this command.

Expected terminal message:

CI Resolve: http://127.0.0.1:4310/app

4.2 Open the application

On macOS, from a second terminal:

open http://127.0.0.1:4310/app

Expected dashboard: empty investigation inbox and Connect once. Resolve automatically.

4.3 Explore the labeled sample

Click Explore a sample run. Inspect Diagnosis, Occurrences, Verification and Activity. You can assign an owner, add a note, start an investigation and use the filters.

The sample is fictional. It is explicitly labeled, cannot receive real verification evidence and cannot demonstrate live repair or merge.

4.4 Check HTTP responses

While the preview is running, use another terminal:

curl --fail --silent --show-error http://127.0.0.1:4310/api/health
curl --fail --silent --show-error http://127.0.0.1:4310/api/automation

Expected health fields include ok: true, version: "0.2.0", and mode: "local". Automation reports configured: false for this preview.

4.5 Stop the preview

Press Control-C in its terminal. The preview database remains in the temporary directory; it does not replace .data/ci-resolve.sqlite.

If port 4310 is occupied, choose another port:

PORT=4311 npm start

Use http://127.0.0.1:4311/app for that process. A bare npm start uses the normal default policy/database, so keep the isolated assignments from step 4.1 if you still want preview-only mode.

5. Run the automated test suite

From the application folder:

cd "$CI_GUIDE_APP"
npm test

The current version defines 56 tests, including two optional browser tests:

Browser configurationExpected result for the current source
No configured Python Playwright interpreter54 pass, 2 explicitly skipped, 0 failures
Working configured Python Playwright + Chromium56 pass, 0 skipped, 0 failures
Interpreter configured but package/browser missingBrowser tests fail; fix that dependency

The count may change with future code updates. The decisive result is zero unexpected failures and successful execution of the test groups you intended to run.

The suite starts its own temporary HTTP servers on available ports. You do not need to leave the app running. It also creates and removes temporary Git fixtures; it does not intentionally patch your registered repository.

The existing .private/browser-python file can enable browser tests even when you did not set an environment variable in this shell.

6. Enable browser tests

6.1 Create a Python environment

cd "$CI_GUIDE_APP"
python3 -m venv .private/browser-venv
.private/browser-venv/bin/python -m pip install playwright
.private/browser-venv/bin/python -m playwright install chromium

On Linux, Playwright may also require OS browser dependencies; follow its official installation guidance. Network access is required to install the package/browser. The current test scripts use the Playwright Python library directly, not pytest.

6.2 Run all tests with this interpreter

CI_RESOLVE_BROWSER_PYTHON="$PWD/.private/browser-venv/bin/python" npm test

Expected: all 56 tests pass, including:

6.3 Persist the interpreter choice locally

Optional one-time convenience:

printf '%s\n' "$PWD/.private/browser-venv/bin/python" > .private/browser-python
npm test

.private/ is Git-ignored. The environment variable takes precedence over the local file.

6.4 View generated screenshots

Browser tests write these files under artifacts/:

For example, on macOS:

open artifacts/autopilot-desktop.png
open artifacts/autopilot-mobile.png

Screenshots are local test artifacts and are not committed by default.

7. Run selected tests

Use the Node test runner directly when selecting files or names. Put runner options before file paths.

Core diagnostic and persistence tests

node --test test/core.test.js

HTTP/API tests

node --test test/server.test.js

CLI and local command verification

node --test test/cli.test.js test/verify.test.js

Full unattended automation tests

node --test test/automation.test.js

Provider, model-contract and policy tests

node --test test/providers.test.js

Browser tests only

CI_RESOLVE_BROWSER_PYTHON="$PWD/.private/browser-venv/bin/python" \
node --test test/browser.test.js

One complete unattended-flow test

node --test \
  --test-name-pattern='unattended failure collection' \
  test/automation.test.js

Expected: the matching test passes; nonmatching tests may be omitted or reported skipped depending on runner output.

8. Understand what the tests prove

StageWhat runs for real in the test suiteWhat is simulated
Source fixtureTemporary Git repository and committed failing sourceNo customer repository
ReproductionReal Node process executes a failing testRemote CI acquisition responses
Repair proposalPatch contract, path restrictions and exact edit applicationThe model's generated response
VerificationReal test execution against candidate source; original tests preservedNo live model quality claim
PR publicationClient request shape and ambiguous-response recoveryGitHub remote state/network responses
Merge and final CIState machine evaluates required checks and merge identityGitHub merge/check responses
BrowserReal Chromium on desktop/mobile viewportsFixture account/repository data
DockerExecution command/policy code existsReal Docker runtime is not exercised by the current suite

A green suite validates implemented behavior under these conditions. It does not establish live credentials, Docker readiness, a production deployment, or the model's repair success rate on your repositories.

During development, 56 tests passed with Chromium enabled. Live GitHub/model/Docker validation remains a separate acceptance step.

9. Connect a target repository once

Use an existing supported repository, or first create the disposable canary from section 13.

In your terminal:

export CI_GUIDE_TARGET=/absolute/path/to/your/repository

git -C "$CI_GUIDE_TARGET" remote get-url origin

Supported origins look like:

https://github.com/your-org/your-repo.git
[email protected]:your-org/your-repo.git

GitHub Enterprise hosts, custom SSH aliases and a checkout without an origin are not supported by this version.

Check the target's test command:

cd "$CI_GUIDE_TARGET"
npm test
cd "$CI_GUIDE_APP"

Start Docker Desktop or the Docker service, then verify:

docker version
docker info

Expected: both client and server details are available. A client binary alone is insufficient.

Generate the policy:

node bin/ci-resolve.js setup --cwd "$CI_GUIDE_TARGET"

Setup pulls node:24, resolves an immutable image digest, detects npm scripts and writes .private/automation.json. It does not create GitHub/model credentials or change repository review rules.

Expected output contains configured: true, the target repository and the policy filename. This means the local policy was generated, not that live authentication has passed.

If you already have an appropriate pinned image:

CI_GUIDE_IMAGE="$(docker image inspect node:24 --format '{{index .RepoDigests 0}}')"
node bin/ci-resolve.js setup --cwd "$CI_GUIDE_TARGET" --image "$CI_GUIDE_IMAGE"

Setup refuses to overwrite an existing policy. For additional repositories, edit its repositories array once; do not repeatedly run setup against the same policy file.

10. Configure credentials once

10.1 Create a private environment file

cd "$CI_GUIDE_APP"
mkdir -p .private
chmod 700 .private
touch .private/automation.env
chmod 600 .private/automation.env

Edit .private/automation.env using your editor. Put real values into that private file, not into a tracked document or a pasted terminal command. Do not overwrite an existing credential file while following this guide.

10.2 GitHub token option

The application reads this exact variable:

CI_RESOLVE_GITHUB_TOKEN=YOUR_SCOPED_GITHUB_TOKEN

Choose only the intended repository access. Permissions needed by the implemented flow include Actions read, Checks read, Commit statuses read, Contents read/write, Pull requests read/write and Metadata read. Organization policies or App installation settings may further restrict access.

gh auth login configures GitHub CLI; it does not automatically populate CI_RESOLVE_GITHUB_TOKEN for this application.

10.3 GitHub App option

Instead of a token, configure:

CI_RESOLVE_GITHUB_APP_ID=YOUR_NUMERIC_APP_ID
CI_RESOLVE_GITHUB_INSTALLATION_ID=YOUR_NUMERIC_INSTALLATION_ID
CI_RESOLVE_GITHUB_PRIVATE_KEY_FILE=/absolute/private/path/to/app-key.pem

Install the App on the chosen repositories and grant the required permissions. The private key remains on the service host; the client obtains and refreshes installation tokens.

If both options are set, CI_RESOLVE_GITHUB_TOKEN takes precedence. Use the option you intend rather than leaving an old token configured accidentally.

10.4 Repair model

CI_RESOLVE_ANTHROPIC_KEY=YOUR_MODEL_API_KEY
CI_RESOLVE_ANTHROPIC_MODEL=YOUR_AVAILABLE_MODEL_ID

Use a model available to your API account. The adapter uses the Claude Messages API, requires a structured JSON repair response, and has a bounded context/output budget.

Model calls send bounded source excerpts, protected test context and redacted diagnostic evidence. GitHub/model credentials are not passed into worker subprocess environments. Redaction is best effort; avoid placing secrets in source and logs.

10.5 Check presence without printing values

node --env-file-if-exists=.private/automation.env --input-type=module <<'JS'
console.log({
  githubToken: Boolean(process.env.CI_RESOLVE_GITHUB_TOKEN),
  githubApp: Boolean(
    process.env.CI_RESOLVE_GITHUB_APP_ID &&
    process.env.CI_RESOLVE_GITHUB_INSTALLATION_ID &&
    process.env.CI_RESOLVE_GITHUB_PRIVATE_KEY_FILE
  ),
  modelKey: Boolean(process.env.CI_RESOLVE_ANTHROPIC_KEY),
  modelId: Boolean(process.env.CI_RESOLVE_ANTHROPIC_MODEL)
});
JS

Expected: at least one GitHub option and both model fields are true. Presence is not proof that the credentials have valid permissions or billing.

11. Configure the execution policy

Inspect the generated policy locally:

node --input-type=module <<'JS'
import { loadConfig } from './src/automation/config.js';
const config = loadConfig();
console.log(config ? {
  repositories: config.repositories.map(r => ({
    repository: r.repository,
    backend: r.backend,
    commands: r.commands,
    allowPaths: r.allowPaths,
    autoMerge: r.autoMerge
  })),
  pollIntervalMs: config.pollIntervalMs,
  concurrency: config.concurrency
} : { configured: false });
JS

Important fields

FieldCurrent behavior
versionMust be 1
pollIntervalMsDefault 60,000; allowed 1,000–3,600,000
concurrencyDefault 2; allowed 1–8
repositoryExact GitHub owner/name
checkoutAbsolute local source-cache checkout
backenddocker, or explicitly opted-in trusted-local
imageRequired Docker image digest; mutable tags rejected
installPreparation commands as arrays, not shell strings
installNetworknone or bridge; setup initially chooses bridge
commandsFirst command reproduces/tests; all commands verify candidates
allowPathsEditable source globs; protected paths stay prohibited
jobsOptional exact job-name allowlist
requiredChecksAdditional exact check names alongside the failed source job
autoMergeDefaults true; requests a native merge where permitted
timeoutMsDefault 120,000; allowed 100–600,000

A command is represented as ["npm", "test"], not "npm test". Shell operators such as && are not parsed in an argument array.

Setup's initial editable patterns are src/**/*.js, src/**/*.ts, and lib/**/*.js. If your source uses .cjs, .mjs, .tsx or app/, add the appropriate bounded source patterns during setup. This does not allow modifications to tests, fixtures, snapshots or package configuration.

The first command must expose the supported test inventory and the failing behavior. A build-only command or a test command that always exits zero will not satisfy the normal reproduction contract.

Fully unattended merge prerequisites

The service can merge a ready repair via GitHub's merge endpoint or request native auto-merge while waiting for repository policy. It does not disable review requirements or required checks.

For a completely unattended canary, its repository policies must permit the scoped service identity to merge verified repairs without an additional human review. Keep your real repository's desired governance rules; configure the intended policy once rather than treating a blocked review as an application test failure.

CI must produce the required check names on both the repair head and the merged commit. Otherwise the task remains in observe and cannot claim resolution.

Trusted-local alternative

For code you already trust to execute as your local user, an explicitly configured policy can use:

{
  "backend": "trusted-local",
  "trustedLocalExecution": true
}

These are fields within a complete repository policy, not a complete configuration file. This backend does not provide Docker/network/OS isolation. It is useful for controlled local environments; the automatic test fixture uses it.

Restart the service after policy or environment changes. Existing tasks retain their original policy digest. A changed policy is not silently applied to already queued work.

12. Start unattended operation

Dashboard and workers together

cd "$CI_GUIDE_APP"
npm start

When .private/automation.json exists, this loads .private/automation.env and starts the collector/workers with the server.

Worker without a dashboard

npm run automate

One collection/processing cycle

node --env-file-if-exists=.private/automation.env \
  bin/ci-resolve.js automate --mode once

A single cycle may leave a PR waiting for CI/merge. It is not a promise that an asynchronous remote repair completes in one invocation. The continuous service performs later reconciliation.

Also, exit code zero alone does not mean live readiness: collector errors can be represented in the returned health data. Inspect that output or the dashboard.

Use explicit state paths for a service

CI_RESOLVE_CONFIG="$PWD/.private/automation.json" \
CI_RESOLVE_DB="$PWD/.data/ci-resolve.sqlite" \
PORT=4310 npm start

All processes sharing work should use the same absolute database path and the same application working directory. The execution work root is .data/automation relative to that working directory, not relative to the database filename.

The default reconciliation interval is 60 seconds; the browser refreshes approximately every eight seconds when you are not editing a form. Collection, execution and remote CI add their own time. Use section 18 for automatic launch after login.

13. Perform a real GitHub canary test

This is an optional live acceptance test in a dedicated disposable repository. It creates actual remote commits and can create/merge an automatic repair. Do not introduce the intentional defect into a production repository.

13.1 Prepare an empty canary repository

Create a private test repository on GitHub and clone it into a separate directory. Set CI_GUIDE_TARGET to that checkout. Keep CI_GUIDE_APP pointing to the CI Resolve application.

Create these files in the canary checkout:

`package.json`

{
  "name": "ci-resolve-canary",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --test --test-reporter=tap"
  }
}

`src/add.js`

export function add(a, b) {
  return a + b;
}

`test/add.test.js`

import test from 'node:test';
import assert from 'node:assert/strict';
import { add } from '../src/add.js';

test('adds two positive numbers', () => {
  assert.equal(add(2, 3), 5);
});

`.github/workflows/ci.yml`

name: Canary CI
on:
  push:
  pull_request:
permissions:
  contents: read
jobs:
  test:
    name: Unit tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: '24'
          package-manager-cache: false
      - run: npm test

The action versions follow the official repositories' examples checked on the guide date. Follow your organization's action-version pinning policy for a production workflow.

There are no package dependencies, so this fixture does not require a lockfile or dependency-install step.

13.2 Establish a passing baseline

In the canary checkout:

cd "$CI_GUIDE_TARGET"
npm test
git add package.json src/add.js test/add.test.js .github/workflows/ci.yml
git commit -m "test(canary): add passing automation fixture"
git push

Confirm that GitHub Actions reports Unit tests passing. Ensure the checkout is on a normal branch name, such as main, rather than ci-resolve/...; the collector intentionally excludes its own repair branches.

Register this repository using sections 9–11, configure its credential access and start the unattended service. If a different repository policy already exists, add this canary as a separate policy entry rather than overwriting the existing file.

13.3 Introduce one source defect

Change only the source implementation:

export function add(a, b) {
  return a - b;
}

Confirm the local test fails, then create the intentionally failing canary commit:

cd "$CI_GUIDE_TARGET"
npm test
git add src/add.js
git commit -m "test(canary): introduce intentional addition regression"
git push

Do not edit the expected assertion. Leave the remote source branch at this commit while the automation investigates it; an additional push can supersede that evidence.

13.4 Observe the automatic repair

The configured service should:

  1. Discover the failed Unit tests job.
  2. Reproduce adds two positive numbers failing in a disposable workspace.
  3. Request a source repair from the configured model.
  4. Reject any proposed test modification.
  5. Verify the candidate against the original test inventory.
  6. Publish a ci-resolve/<task-id> branch and repair PR targeting the failing branch.
  7. Confirm original CI checks on the repair head.
  8. Merge/request auto-merge if native policy permits.
  9. Observe Unit tests on the merged commit.
  10. Mark the investigation resolved automatically.

A model may abstain or produce an invalid candidate; the expected correct behavior then is a recorded stop/exhaustion, not fabricated success. The acceptance test demonstrates live success only when an actual correct repair completes.

13.5 Record acceptance evidence

Retain the source workflow/run/attempt/job IDs, source commit, task ID, repair PR/head SHA, verification results, merged SHA and resulting CI result. The original tests must remain unchanged.

The service does not patch the registered checkout's working files. After remote merge, refresh your checkout through your normal Git workflow if you want to inspect the merged repair locally.

A failing check on a merged commit is recorded as blocked; version 0.2 does not implement automatic rollback. Do not infer rollback from the presence of merge reconciliation.

14. Read the dashboard and API

Dashboard

For automated cases, resolution is owned by the worker. The legacy Mark resolved action is not the normal automated path.

Read-only API inspection

While the server is running:

curl --fail --silent --show-error http://127.0.0.1:4310/api/automation
curl --fail --silent --show-error http://127.0.0.1:4310/api/cases

To pretty-print without installing another tool:

curl --fail --silent --show-error http://127.0.0.1:4310/api/automation \
  | python3 -m json.tool

Use an actual case ID for details:

curl --fail --silent --show-error \
  http://127.0.0.1:4310/api/cases/REPLACE_WITH_CASE_ID

configured: true means a policy was loaded. Read health and task error/phase to determine actual progress. The overview lists the newest 200 tasks; per-case details retain that case's workflow evidence.

15. Interpret workflow states

Task phaseMeaningNormal next behavior
queuedImported failed job has a durable taskSource revision check
prepareDisposable checkout/environment preparationReproduction
reproduceRun the first configured commandRequire a comparable failing symptom/test inventory
repairRequest/validate a structured source proposalCandidate verification or bounded retry
verifyRun protected tests and all configured checksPublish only if verification succeeds
publishCreate/reconcile deterministic repair branch and PRRemote CI observation
observeWait for checks, native merge and merged-commit checksAutomatic resolution when all required evidence exists
resolvedRequired evidence and merge checks acceptedTerminal success
unreproducedOriginal supported failure not reproducedTerminal; no repair claimed
supersededSource, repair head or newer occurrence invalidated workTerminal obsolete task
blockedExplicit unsupported condition, rejected remote CI or unavailable policyTerminal recorded stop
failedGeneric retry budget exhaustedTerminal error
exhaustedCandidate or lifetime budget exhaustedTerminal; no repair claimed

An investigation's legacy status is separate from its task phase. For example, investigating can accompany a stopped automatic task; inspect the task's exact phase and evidence.

Transient errors use bounded retries. Missing repair-model setup parks the current phase for a later retry. The service must be restarted to load edited environment-file values. Terminal tasks are not automatically reset by editing SQL or restarting; create fresh provider evidence after correcting setup rather than altering recorded evidence by hand.

16. Test rejection and recovery behavior

The following automated tests already cover negative paths without modifying a real repository:

node --test test/automation.test.js test/providers.test.js

Important cases include:

Test scenarioExpected result
Proposal edits a protected testRejected; no publication
Source patch still fails testsAnother bounded candidate or exhausted outcome
Model returns no changesRecorded abstention/blocked outcome
Reproduced failure differs from imported symptomUnreproduced outcome
Source branch advancesOld task superseded
Repair head changesOld evidence rejected; obsolete observed PR closed where possible
Original CI rejects repairNo successful resolution
Merged-commit checks are missingStay in observation
Response is lost after PR creationReconcile existing PR instead of blindly duplicating it
Worker lease expiresStale worker cannot commit a checkpoint
Model setup is temporarily missingRetry later without inventing repair evidence

For a restart experiment in a live canary, stop the service with Control-C during observation and restart it using the same policy, database and application directory. It should resume reconciliation rather than generate another repair simply because the process restarted. A workspace lost before verification requires reproduction/re-verification, which is intentional.

17. Optional manual diagnostic commands

These help with ad hoc inspection and backward compatibility. They are not required for daily unattended operation.

cd "$CI_GUIDE_APP"
node bin/ci-resolve.js --help
node bin/ci-resolve.js list
node bin/ci-resolve.js show --case REPLACE_WITH_CASE_ID

Import the fictional fixture into a separate diagnostic database:

CI_RESOLVE_DB="$PWD/.private/manual-demo.sqlite" \
node bin/ci-resolve.js import --file examples/failed-run.json

Use that same database setting for subsequent list/show commands if inspecting the fixture. A manual import does not automatically become provider-authenticated evidence or enqueue a live repair task.

For a real manual investigation, an explicitly chosen local command can be recorded:

node bin/ci-resolve.js verify \
  --case REPLACE_WITH_CASE_ID \
  --cwd "$CI_GUIDE_TARGET" \
  -- npm test

Sample cases reject real verification. The local command runs with your user permissions; it is not the Docker automation path. A passing manual command is not full CI-equivalence proof.

18. Run automatically after macOS login

This optional one-time setup keeps the dashboard and workers running without opening Terminal each day. It is for a local macOS installation, not a production hosting deployment.

First complete a foreground live canary. Stop any foreground CI Resolve process before installing the login service so the two do not fight for port 4310. Docker Desktop must also be available after login if the policy uses Docker.

The following command creates a user LaunchAgent under your home folder and points it at this application. It does not change repository code or install a system-wide daemon.

cd "$CI_GUIDE_APP"
export CI_GUIDE_APP="$PWD"
python3 <<'PY'
import os
import pathlib
import plistlib
import shutil

app = pathlib.Path(os.environ['CI_GUIDE_APP']).resolve()
node = shutil.which('node')
if not node:
    raise SystemExit('Node is not available in PATH.')
node = pathlib.Path(node).resolve()
private = app / '.private'
private.mkdir(exist_ok=True)
agent = pathlib.Path.home() / 'Library/LaunchAgents/in.spekra.ci-resolve.plist'
agent.parent.mkdir(parents=True, exist_ok=True)
if agent.exists():
    raise SystemExit('LaunchAgent already exists; inspect it instead of overwriting.')
path = ':'.join([str(node.parent), '/opt/homebrew/bin', '/usr/local/bin', '/usr/bin', '/bin'])
payload = {
    'Label': 'in.spekra.ci-resolve',
    'ProgramArguments': [
        str(node),
        '--env-file-if-exists=' + str(private / 'automation.env'),
        str(app / 'src/server.js'),
    ],
    'WorkingDirectory': str(app),
    'EnvironmentVariables': {'PATH': path},
    'RunAtLoad': True,
    'KeepAlive': True,
    'StandardOutPath': str(private / 'service.stdout.log'),
    'StandardErrorPath': str(private / 'service.stderr.log'),
}
with agent.open('wb') as stream:
    plistlib.dump(payload, stream)
print(agent)
PY

Register it:

launchctl bootstrap "gui/$(id -u)" \
  "$HOME/Library/LaunchAgents/in.spekra.ci-resolve.plist"

Check it:

launchctl print "gui/$(id -u)/in.spekra.ci-resolve"
curl --fail --silent --show-error http://127.0.0.1:4310/api/health

The service loads credentials from .private/automation.env; it does not inherit arbitrary exports from your current Terminal. The resolved Node executable must remain installed at that path. Regenerate the service definition deliberately if its Node installation is removed or relocated.

The LaunchAgent example is an operator setup recipe, not a service installed or validated by this development session. On Linux, use your normal user/system service manager with the same working directory, Node executable and environment-file arguments.

19. Stop, restart, and change configuration

Foreground process

Press Control-C, then use npm start again. Let the shutdown finish before starting another process against the same state.

macOS LaunchAgent

Restart after editing a one-time environment/policy setting:

launchctl kickstart -k "gui/$(id -u)/in.spekra.ci-resolve"

Remove the running registration:

launchctl bootout "gui/$(id -u)" \
  "$HOME/Library/LaunchAgents/in.spekra.ci-resolve.plist"

The plist remains on disk. If you intend to disable launch after future logins, move that specific plist out of ~/Library/LaunchAgents as well. Do not delete application evidence to stop a service.

Change policy carefully

Stop/restart to load the edited policy. Existing tasks are bound to their previous digest and can stop with a policy-changed result. After correcting a recipe, rerun the canary workflow to produce a fresh provider attempt or create a new canary commit. Restarting alone does not re-enqueue an already terminal task.

20. Back up and restore local state

Application state includes .data/ci-resolve.sqlite, SQLite companion/WAL files where present, and any retained execution workspaces under .data/automation/. Configuration and credentials are separate in .private/.

For a simple filesystem backup, first stop all app/worker instances, including any LaunchAgent. Then:

cd "$CI_GUIDE_APP"
CI_GUIDE_BACKUP="$PWD/.private/backups/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$CI_GUIDE_BACKUP"
cp -R .data "$CI_GUIDE_BACKUP/data"
cp .private/automation.json "$CI_GUIDE_BACKUP/automation.json"

The policy copy assumes live setup exists. Back up credential material separately using your chosen secret-management procedure; do not add it to a shared support archive.

To restore, keep every instance stopped, preserve the existing .data directory under another name, and restore the selected backup to the original state path. Confirm the policy checkout paths still exist before restarting. Do not copy only the main SQLite file from an actively writing process and assume its WAL-backed state was captured.

Execution workspaces can contain private source. Treat backups and evidence as sensitive application data.

21. Troubleshoot common problems

SymptomLikely causeWhat to check/do
node:sqlite unavailableWrong Node versionRun Node 24+ from the same shell/service PATH
EADDRINUSEAnother process owns the portStop the intended previous service or choose another PORT
listen EPERMTerminal/agent socket restrictionUse a normal terminal that permits localhost listeners
Docker client exists, server missing/deniedDocker daemon or socket unavailableStart Docker and run docker info as the service user
Setup says configuration existsOverwrite protectionInspect/edit the existing policy; do not discard it blindly
Setup rejects originMissing/custom/enterprise originUse a supported standard github.com checkout
GitHub 401/403/404Invalid token, wrong installation, insufficient access, policy, or unavailable resourceCheck selected repositories, permissions and organization requirements
Dashboard says setup required despite gh auth loginApp-specific variables absentConfigure the exact CI Resolve credential variables
API shows configured: true but no tasksNo eligible failure, filters, or connection errorInspect health, job allowlist and provider run age/conclusion
Browser tests skipNo configured interpreterSet CI_RESOLVE_BROWSER_PYTHON or .private/browser-python
Browser tests fail on importWrong Python environmentInstall Playwright into the exact configured interpreter
Browser executable missingChromium not installed for that environmentRun that interpreter's -m playwright install chromium
unreproducedDifferent symptom, missing environment, empty inventory or skipped testsInspect baseline output and verify the supported recipe
Preparation modifies tracked inputsInstall/build step changes protected filesPrepare the appropriate image/recipe; do not bypass the integrity check
Repair rejected for pathSource extension outside allowlist or protected fileReview one-time bounded source patterns; tests/config remain protected
Model credentials missingKey/model unset or wrong environment fileSet both model fields and restart; parked tasks can retry
Model HTTP error/incomplete JSONAccount/model/API issue or truncated responseInspect task error and model access; no patch should be accepted
PR exists but task stays in observeMissing checks, policy requirements or merge waitingInspect exact required names and PR/merged-commit checks
Merged PR never resolvesNo matching CI on the merged commitConfigure CI to run the required jobs on pushes/merged revisions
Source/repair head changedEvidence became staleExpected superseded behavior; inspect the newer revision/task
More than 1000 provider list recordsCurrent reconciliation list budget exceededThis workload needs narrower collection/product support; changing the job allowlist alone does not reduce the run-list query
Tasks appear in one process but not anotherDifferent DB or working directoryUse the same absolute DB/config paths and application directory
Terminal task does not resumeTerminal outcome is retainedCorrect setup, then produce fresh provider evidence; do not rewrite recorded results
GitHub push fails DNS/authenticationPublication environment unavailableRestore network and configured GitHub authentication; local commits remain available

The collector looks at failed workflows created in the preceding 24 hours, not every historical failure or every recently rerun old workflow. Workflows created earlier may be excluded even if retried recently.

Forks, ci-resolve/... repair branches and merge-group source events are excluded intentionally. The original failed job's name is always required during reconciliation; requiredChecks adds checks rather than replacing it.

22. Current support limits

These limits do not require per-failure manual action for the supported happy path. They define when automation should stop with evidence instead of claiming success.

23. Acceptance checklist

Local application/test readiness

Live unattended readiness

Only a completed live canary establishes live readiness; green simulated-service tests alone do not.

24. Quick command reference

TaskCommand from the application directory
Syntax checksnpm run check
Full suitenpm test
Unattended-flow testsnode --test test/automation.test.js
Provider/policy testsnode --test test/providers.test.js
Browser testsnode --test test/browser.test.js with a configured interpreter
One-time target setupnode bin/ci-resolve.js setup --cwd /absolute/target/path
Dashboard + configured workersnpm start
Worker-only servicenpm run automate
One live cyclenode --env-file-if-exists=.private/automation.env bin/ci-resolve.js automate --mode once
CLI helpnode bin/ci-resolve.js --help
List investigationsnode bin/ci-resolve.js list
Inspect casenode bin/ci-resolve.js show --case ACTUAL_CASE_ID
Healthcurl --fail http://127.0.0.1:4310/api/health
Automation statuscurl --fail http://127.0.0.1:4310/api/automation

25. References

Commands were checked against version 0.2 source and local tests. External dependency installation, the live canary, the LaunchAgent recipe and remote credentials require their respective environments and have not been executed as part of writing this guide.

Guide validation: the 25 sections and contents anchors, relative links, tables, JSON examples and all 46 shell examples were checked. The documented local canary passed with correct source and failed after introducing the source defect. The full 56-test application suite also passed, including both Chromium workflows. Live account, Docker and LaunchAgent setup remain environment-dependent steps.


Explore all guides · Back to top