LO

lora-manager-e2e

Performs E2E validation of LoRa Manager, including server orchestration and frontend-to-backend integration testing.

Install

mkdir -p .claude/skills/lora-manager-e2e && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/6933" && unzip -o skill.zip -d .claude/skills/lora-manager-e2e && rm skill.zip

Installs to .claude/skills/lora-manager-e2e

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

End-to-end testing and validation for LoRa Manager features. Use when performing automated E2E validation of LoRa Manager standalone mode, including starting/restarting the server, using Chrome DevTools MCP to interact with the web UI at http://127.0.0.1:8188/loras, and verifying frontend-to-backend functionality. Covers workflow validation, UI interaction testing, and integration testing between the standalone Python backend and the browser frontend.
455 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Start LoRa Manager standalone server
  • Automate UI form interactions
  • Verify frontend-to-backend API calls
  • Capture UI snapshots
  • Monitor console messages

How it works

It uses Chrome DevTools MCP to programmatically interact with the LoRa Manager web UI and verify backend responses.

Inputs & outputs

You give it
UI interaction commands
You get back
Test snapshots or API verification results

When to use lora-manager-e2e

  • Start LoRa Manager standalone server
  • Validate UI form interactions
  • Perform E2E test snapshots
  • Test integration between backend and browser

About this skill

LoRa Manager E2E Testing

This skill provides workflows and utilities for end-to-end testing of LoRa Manager using Chrome DevTools MCP.

Conventions Used in This Document

  • {PORT}: The server port. The default candidate is 8188, but 8188 is commonly occupied by a live ComfyUI process and MUST NOT be assumed to be free. Always check availability first (see Port Selection) and use a free port (e.g. 8199) for the E2E run. Substitute the actual port for every {PORT} in the commands below.
  • <repo-root>: The repository/worktree root. Always run commands from the repo or worktree root; never assume a specific absolute path (paths such as /home/<user>/... differ per machine). The E2E scripts resolve the project root themselves, but fixture/settings paths are relative to <repo-root>.

SANDBOX (MANDATORY)

Read this section before running anything. Every E2E run MUST target a throwaway sandbox, never the real user data. A fresh subagent that skips this section WILL permanently mutate real user recipes.

  1. Portable settings: create <repo-root>/settings.json (gitignored) with "use_portable_settings": true plus sandboxed folder_paths (lora/checkpoint roots) and recipes_path. This keeps the configuration inside the repo instead of the real user config dir (~/.config/ComfyUI-LoRA-Manager/settings.json).
  2. Sandboxed paths: point folder_paths / recipes_path / example_images_path at disposable dirs — e.g. under /tmp/opencode/<plan-name>-e2e/ (or worktree-local dirs). NEVER point the E2E at the real library (~/models/...), real recipe dir, or real settings.
  3. Never touch the real config: the real user config at ~/.config/ComfyUI-LoRA-Manager/settings.json and the real recipe dir must remain byte-identical before and after the run.
  4. Record real-data protection proof before starting and after finishing:
    # BEFORE: snapshot real config + recipe library state
    sha256sum ~/.config/ComfyUI-LoRA-Manager/settings.json > /tmp/opencode/<plan>-e2e/settings.before.sha256
    ls ~/models/recipes/*.recipe.json 2>/dev/null | wc -l > /tmp/opencode/<plan>-e2e/recipes-count.before.txt
    find ~/models/recipes -name '*.recipe.json' -newermt "$(date -Iseconds)" | head   # expect empty after run
    # AFTER: record again, then diff the two snapshots. Any change = the run leaked into real data.
    
    Also confirm <repo-root>/git status stays clean for settings.json/cache/ (both are gitignored).

Portable Settings Example

{
  "use_portable_settings": true,
  "folder_paths": {
    "loras": ["/tmp/opencode/<plan>-e2e/models/loras"],
    "checkpoints": ["/tmp/opencode/<plan>-e2e/models/checkpoints"],
    "unet": ["/tmp/opencode/<plan>-e2e/models/checkpoints"],
    "diffusers": []
  },
  "recipes_path": "/tmp/opencode/<plan>-e2e/recipes",
  "example_images_path": "/tmp/opencode/<plan>-e2e/example_images"
}

The scanner computes and persists model hashes during the library scan, so the sandbox model dirs just need the model files + .metadata.json sidecars (see Fixture + Fresh-State Guidance).

Time Budgets & Abort Guidance

A fresh subagent should complete a sandboxed standalone E2E in well under 30 minutes. Budget each phase:

PhaseExpected durationAbort if
Port check + sandbox setup< 2 min
Server start (detached) + readiness< 30 s> 60 s (2x) → stop
Chrome DevTools MCP connect< 1 min> 2 min → stop
Per entry-point run (after fixtures ready)< 5 min> 10 min (2x) → stop
Fixture reset + cache clear between runs< 1 min> 2 min → stop

Abort rule: if a phase exceeds ~2x its budget, OR any single tool call fails/retries 3+ times in a row, STOP. Do not loop or retry blindly. Report BLOCKED with: the phase, the last observed state (server PID + ss -tlnp output, page snapshot, last API response), and the suspected cause. Record the partial state as evidence; a clean BLOCKED report is more valuable than an hour of retries.

Prerequisites

  • LoRa Manager project cloned and dependencies installed (pip install -r requirements.txt) — run everything from <repo-root>
  • Chrome browser available for debugging
  • Chrome DevTools MCP connected
  • ss (or lsof/netstat) available for port checks: ss -tlnp

Port Selection

8188 is only the default candidate. Verify it is actually free before every run:

# Is anything listening on 8188?
ss -tlnp | grep ':8188' || echo "8188 is free"
  • If a process holds 8188 (e.g. a live ComfyUI — pid 6575 on this machine), pick a different free port, e.g. 8199:
    ss -tlnp | grep ':8199' || echo "8199 is free"
    
  • Never kill a process you did not start for this E2E. The live ComfyUI is off-limits. Pick a free port instead.
  • Use your chosen port for all subsequent commands (server, Chrome launch, browser URLs).

Quick Start Workflow (sandboxed)

1. Prepare the sandbox

cd <repo-root>                       # ALWAYS run from the repo/worktree root
mkdir -p /tmp/opencode/<plan>-e2e/models/{loras,checkpoints}
mkdir -p /tmp/opencode/<plan>-e2e/{recipes,example_images,recipes-before}
# write <repo-root>/settings.json per the portable-settings example above
# record real-data protection proof (see SANDBOX section)

2. Check port availability

ss -tlnp | grep ':{PORT}' || echo "port {PORT} is free"

If {PORT} is occupied by an unrelated process, pick a free one and use it everywhere below. When in doubt use 8199.

3. Start LoRa Manager Standalone (detached)

The standalone server dies with the shell unless launched fully detached — a plain background & from the bash tool is killed when the tool call returns. Launch via the helper script:

python .agents/skills/lora-manager-e2e/scripts/start_server.py --port {PORT} --wait --timeout 30 --detach

Or manually (equivalent detached form):

setsid nohup python standalone.py --port {PORT} --host 127.0.0.1 < /dev/null \
  >> /tmp/opencode/<plan>-e2e/server.log 2>&1 &
echo "started"   # record the printed/pidfile PID for cleanup

Verify it is listening before proceeding (readiness poll is not a substitute for this):

ss -tlnp | grep ':{PORT}'

Record the server PID for cleanup: the helper script writes it to /tmp/lora-manager-e2e-server-{PORT}.pid; a manual setsid launch has no pidfile, so capture it explicitly (e.g. from ss -tlnp).

4. Open Chrome Debug Mode

# Chrome with remote debugging on port 9222 (note the {PORT} URL)
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-lora-manager http://127.0.0.1:{PORT}/loras

5. Connect Chrome DevTools MCP

Ensure the MCP server is connected to Chrome at http://localhost:9222. Verify with list_pages — if it fails with "browser is already running", see Chrome DevTools MCP Troubleshooting.

6. Navigate and Interact

Use Chrome DevTools MCP tools to:

  • Take snapshots: take_snapshot
  • Click elements: click
  • Fill forms: fill or fill_form
  • Evaluate scripts: evaluate_script
  • Wait for elements: wait_for

Common E2E Test Patterns

Pattern: Full Page Load Verification

# Navigate to LoRA list page
navigate_page(type="url", url="http://127.0.0.1:{PORT}/loras")

# Wait for page to load
wait_for(text="LoRAs", timeout=10000)

# Take snapshot to verify UI state
snapshot = take_snapshot()

Pattern: Restart Server for Configuration Changes

# Stop current server (if running), start with new configuration.
# --restart only kills the E2E server this script started before (via its pidfile);
# it refuses to blindly kill unrelated processes on the port.
python .agents/skills/lora-manager-e2e/scripts/start_server.py --port {PORT} --restart --wait --detach

# Wait and refresh browser
navigate_page(type="reload", ignoreCache=True)
wait_for(text="LoRAs", timeout=15000)

Pattern: Verify Backend API via Frontend

# Execute script in browser to call backend API
result = evaluate_script(function="""
async () => {
  const response = await fetch('/loras/api/list');
  const data = await response.json();
  return { count: data.length, firstItem: data[0]?.name };
}
""")

Pattern: Form Submission Flow

# Fill a form (e.g., search or filter)
fill_form(elements=[
    {"uid": "search-input", "value": "character"},
])

# Click submit button
click(uid="search-button")

# Wait for results
wait_for(text="Results", timeout=5000)

# Verify results via snapshot
snapshot = take_snapshot()

Pattern: Modal Dialog Interaction

# Open modal (e.g., add LoRA)
click(uid="add-lora-button")

# Wait for modal to appear
wait_for(text="Add LoRA", timeout=3000)

# Fill modal form
fill_form(elements=[
    {"uid": "lora-name", "value": "Test LoRA"},
    {"uid": "lora-path", "value": "/path/to/lora.safetensors"},
])

# Submit
click(uid="modal-submit-button")

# Wait for success message or close
wait_for(text="Success", timeout=5000)

Fixture + Fresh-State Guidance

For rematch/repair E2E runs, seed the sandboxed recipes_path with hand-written fixture recipes. Rules (validated by the task-8 E2E):

  1. Filename constraint: each file MUST be named f"{id}.recipe.json" and the in-JSON id field MUST equal the filename. Discovery accepts any *.recipe.json, but persistence resolves the path via get_recipe_json_path and _save_recipe_persistently returns False on a mismatch → the fixture would be counted as an error.
    • recipe-a.recipe.json → in-JSON "id": "recipe-a"
  2. File format: mirror an existing recipe JSON — top-level id, file_path, title, loras, fingerprint, gen_params; lora entries per the persistence conventions (hash, file_name, modelVersionId, isDeleted, ..

Content truncated.

When not to use it

  • Testing non-web interfaces
  • Validating production deployment environments

Prerequisites

LoRa Manager projectChrome browserChrome DevTools MCP

Limitations

  • Requires Chrome remote debugging
  • Limited to LoRa Manager standalone mode

How it compares

It enables automated end-to-end testing of the UI and backend integration rather than manual browser-based verification.

Compared to similar skills

lora-manager-e2e side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
lora-manager-e2e (this skill)16moReviewAdvanced
dev26moReviewAdvanced
examples-auto-run23moReviewIntermediate
migrate15moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry