Claude Skill

cherry-electron-dev

Develop, fix, and profile Cherry Studio in a tracked Electron instance. Use for everyday implementation, UI and interaction work, bug fixing, runtime debugging, DevTools inspection, lag or jank investigation, CPU and memory monitoring, leak checks, and startup-performance analysi

LLM Mart · 0 points · 21 views 36 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download cherryhq-cherry-studio-.agents_skills_cherry-electron-dev-1f7c409.zip · 8 KB
Part of cherryhq/cherry-studio — 22 skills
This skill couldn't be refreshed from GitHub on the last check — you're seeing the last imported snapshot.

Install

skills CLI npx skills add https://github.com/CherryHQ/cherry-studio/tree/main/.agents/skills/cherry-electron-dev
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install cherryhq-cherry-studio@llmmart
Git git clone https://github.com/CherryHQ/cherry-studio.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole cherryhq/cherry-studio collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Cherry Studio Development

Use this skill for ongoing work in the current checkout. Do not use it to check out or report on PRs; use cherry-pr-test for that workflow.

Required runtime workflow

Before reading or controlling Electron UI, read Electron Instance Management and use its persistent policy.

That reference is the only authority for instance discovery, instance.json, CDP target selection, launching, replacement, shutdown, and troubleshooting. Do not reproduce those procedures here or substitute generic Electron app control.

Development loop

  1. State the requested behavior and the evidence that will prove it.
  2. Read the relevant code and nearby README files.
  3. Verify and reuse the tracked instance through the runtime reference.
  4. Reproduce or inspect the current behavior before editing when practical.
  5. Capture the smallest useful evidence: UI state, DOM, console/network output, main-process logs, persisted state, or performance metrics.
  6. Trace the responsible code path and make only the requested change.
  7. Keep Electron running. Use HMR for renderer changes and verify in the same window.
  8. Repeat the same scenario and compare before/after evidence.

Inspect the real window at the relevant size and theme for UI work. Check both renderer and main-process evidence for renderer failures.

Restart only for a non-reloadable layer, crash, unreliable runtime state, or startup profiling. Use the reference's exact-instance replacement procedure, refresh instance.json, and keep the replacement running.

Run the narrowest relevant validation and follow current user and repository instructions for lint, formatting, and tests.

Performance and DevTools

For lag, jank, high CPU, memory growth, leaks, slow startup, or explicit DevTools use, read Performance Debugging.

Store temporary logs, screenshots, and profiles under .context/cherry-electron-dev/. Compare a quiet baseline with the same bounded scenario before and after a fix. Detach profiling sessions afterward; do not close the CDP browser, page, or Electron process.

Handoff

Leave reused user-owned and healthy agent-launched instances running after the instruction. Stop one only when the user asks, a required restart is part of the task, or the instance is unhealthy and blocks progress.

Report the verified PID, whether it remains running, CDP port, tracking file, evidence paths, reproduction, and verification.

Files (cherry-studio)
  • references
    • electron-instance.md 7.9 KB
      # Electron Instance Management
      
      Use this as the single runtime procedure for both `cherry-electron-dev` and
      `cherry-pr-test`.
      
      ## Contents
      
      - Session policy and scratch data
      - Verify or discover an instance
      - Bind CDP to the exact target
      - Gracefully replace an instance
      - Start and track a debug instance
      - Finish or recover
      - Troubleshooting
      
      ## Session policy and scratch data
      
      Choose the caller's policy before touching Electron:
      
      | Policy | Use | Finish |
      | --- | --- | --- |
      | `persistent` | Ongoing development | Leave a healthy instance running |
      | `ephemeral` | A bounded PR test | Stop only the instance started by this test |
      
      Treat pre-existing processes as user-owned. Preserve `userData`, databases,
      caches, and preferences unless the user explicitly requests a reset.
      
      Use `.context/cherry-electron-dev/` for runtime state and artifacts. The
      repository ignores this path, and `mkdir -p` creates it in Conductor and
      ordinary clones:
      
      ```bash
      mkdir -p .context/cherry-electron-dev
      ```
      
      Track the active instance in `.context/cherry-electron-dev/instance.json` with:
      
      - workspace path and Git HEAD at launch
      - `persistent` or `ephemeral` policy and `user` or `agent` ownership
      - `launch_purpose` (`development`, `pr-test:<number>`, or `external`)
      - `workflow_relation` (`started` or `borrowed`)
      - Electron PID, runner PID/session, and process group
      - CDP and main-process inspector ports
      - exact main-window target URL
      - development profile suffix
      - launch command, log path, and start time
      
      The file is a hint, not proof. Revalidate it before every UI operation.
      At the start of a new workflow, an already-running instance is `borrowed` even
      when the same agent launched it during an earlier instruction.
      
      ## Verify or discover an instance
      
      Reuse the record only when all checks pass:
      
      1. The Electron PID is alive.
      2. Its cwd is the exact current workspace.
      3. The recorded CDP listener belongs to that PID.
      4. `/json/list` contains the recorded Cherry Studio target.
      5. When exact checked-out code matters, the launch Git HEAD matches current
         HEAD; otherwise restart instead of relying on HMR for main-process changes.
      
      ```bash
      lsof -a -p <ELECTRON_PID> -d cwd -Fn
      lsof -nP -a -p <ELECTRON_PID> -iTCP:<CDP_PORT> -sTCP:LISTEN
      curl -fsS http://127.0.0.1:<CDP_PORT>/json/version | jq .
      curl -fsS http://127.0.0.1:<CDP_PORT>/json/list | \
        jq '.[] | {id, type, title, url}'
      ```
      
      If the record is missing or stale, discover before launching:
      
      ```bash
      ps -axo pid=,ppid=,pgid=,command= | \
        rg -i 'Cherry Studio|CherryStudio|electron-vite|remote-debugging-port'
      lsof -nP -iTCP -sTCP:LISTEN | rg 'Electron|Cherry|:9222|:5173'
      lsof -a -p <ELECTRON_PID> -d cwd -Fn
      ps -o pid=,ppid=,pgid=,command= -p <PID>,<PARENT_PID>
      ```
      
      Ignore candidates that cannot be tied to this workspace. A packaged app and
      another checkout are not interchangeable. Never infer ownership from an open
      port alone.
      
      If a candidate passes every applicable check, adopt it immediately instead of
      launching:
      
      1. Attach to its verified CDP endpoint.
      2. Write or refresh `instance.json` with its live identity and
         `workflow_relation: borrowed`.
      3. Preserve a trustworthy existing policy and ownership. Without a trustworthy
         record, treat a pre-existing process as `user` owned and `persistent`.
      4. End the launch path. Start another instance only when no suitable candidate
         exists or replacement is required.
      
      ## Bind CDP to the exact target
      
      Use the verified CDP endpoint exclusively. List targets and match URL and
      title; never assume target index `0`. The normal main target is titled
      `Cherry Studio` and uses:
      
      ```text
      http://localhost:5173/windows/main/index.html
      ```
      
      If the dev server selects another port, require the same
      `/windows/main/index.html` path and record the exact URL. Re-list after windows
      open or close. Do not navigate a target unless navigation is part of the test.
      
      Use Playwright/CDP or optional `agent-browser`. Do not install a global CLI just
      for a task, and do not launch another instance because one controller is
      unavailable.
      
      Never pass `Electron`, `com.github.Electron`, or a `node_modules` Electron.app
      path to Computer Use or another app-control API. Shared Electron identifiers
      can launch or select the wrong checkout.
      
      ## Gracefully replace an instance
      
      Replace only when current-workspace code or required CDP access is unavailable.
      Before replacing a user-owned process, explain why and record its PID, command,
      cwd, parent/runner, PGID, and ports.
      
      Send `SIGTERM` to the exact Electron main PID and wait up to eight seconds:
      
      ```bash
      kill -TERM <ELECTRON_PID>
      for _ in $(seq 1 16); do
        kill -0 <ELECTRON_PID> 2>/dev/null || break
        sleep 0.5
      done
      kill -0 <ELECTRON_PID> 2>/dev/null && echo "still running"
      ```
      
      If Electron exits but its verified same-workspace runner remains, terminate
      that PID separately. Never use broad `pkill`, kill arbitrary port owners, or
      signal a process group before inspecting every member.
      
      Do not escalate automatically to `SIGKILL`. Report the remaining PID and logs
      and ask before forcing a process that may be migrating, backing up, or
      preventing quit. Verify the old PID and ports are gone before replacement.
      
      ## Start and track a debug instance
      
      Read `package.json` for the current debug command. If its default CDP or
      inspector port belongs to an unrelated process, choose free ports and change
      only those arguments; do not kill the owner.
      
      Prefer a managed terminal session. With a terminal tool such as
      `exec_command`, request a PTY and short initial yield, retain its returned
      session ID, and let this command continue:
      
      ```bash
      pnpm debug 2>&1 | tee .context/cherry-electron-dev/electron.log
      ```
      
      Do not run that command as an ordinary blocking call. If no managed-session
      tool exists, use a recorded background runner:
      
      ```bash
      nohup pnpm debug >.context/cherry-electron-dev/electron.log 2>&1 &
      echo $!
      ```
      
      Immediately record the returned runner PID. Resolve and record the real
      Electron PID and PGID after launch.
      
      Keep the existing development profile for `persistent` work. For an isolated
      PR test, set a distinct `CS_DEV_USER_DATA_SUFFIX` and record it.
      
      Wait for the selected CDP endpoint, then identify and record the exact target:
      
      ```bash
      for _ in $(seq 1 60); do
        curl -fsS http://127.0.0.1:<CDP_PORT>/json/version >/dev/null && break
        sleep 0.5
      done
      curl -fsS http://127.0.0.1:<CDP_PORT>/json/list | \
        jq '.[] | {id, type, title, url}'
      ```
      
      Write `instance.json` only after PID, cwd, listener ownership, and target checks
      pass. Give a new instance `workflow_relation: started`; never reclassify a
      borrowed instance as newly started.
      
      ## Finish or recover
      
      For `persistent`, leave healthy user-owned and agent-owned instances running.
      For `ephemeral`, stop an instance only when all of these are true:
      
      1. Its verified record has `workflow_relation: started`.
      2. Its verified record still says `ephemeral` and `agent` owned.
      3. Its PID, cwd, and launch purpose still match the current test.
      
      Leave every borrowed instance running, regardless of whether its existing
      ownership is `user` or `agent`.
      
      If an unexpected window or PID appears:
      
      1. Stop UI actions.
      2. Identify only the new PID by command and cwd.
      3. Gracefully stop that verified unexpected PID.
      4. Revalidate the tracked PID, cwd, CDP listener, and target.
      5. Resume only through the tracked CDP endpoint.
      
      Never close all Electron processes to recover from a targeting mistake.
      
      ## Troubleshooting
      
      | Symptom | Action |
      | --- | --- |
      | CDP works but the page is missing | Re-list targets and match URL/title; splash, migration, settings, detached tabs, and mini-apps are separate targets. |
      | Debug launch exits | Inspect the recorded log for a profile lock, native rebuild, database/startup failure, or port collision; confirm the old PID exited. |
      | Splash or migration is stuck | Read startup logs and wait; do not bypass, reset, or force-close without understanding its phase. |
      | CDP automation is unavailable | Use logs/source when sufficient. If UI evidence is essential, explain why and use the replacement procedure; never fall back to generic Electron control. |
      
    • performance-debugging.md 6.3 KB
      # Performance Debugging
      
      Use this reference for Cherry Studio lag, jank, CPU, memory, leak, startup, and
      DevTools investigations.
      
      ## Contents
      
      - Bind safely and choose a profile
      - Quick renderer metrics
      - Interaction trace
      - Memory and allocation
      - Process and main-process checks
      - Startup analysis
      - Interpretation and reporting
      
      ## Bind safely and choose a profile
      
      First read [Electron Instance Management](electron-instance.md) and complete
      its PID, workspace, CDP, and target checks. Never find or open a development
      instance through the macOS application name `Electron`.
      
      Connect Playwright to the recorded CDP port and exact main target:
      
      ```js
      var { chromium } = await import("playwright")
      var browser = await chromium.connectOverCDP("http://127.0.0.1:<CDP_PORT>")
      var page = browser
        .contexts()
        .flatMap((context) => context.pages())
        .find((candidate) => candidate.url() === "<MAIN_TARGET_URL>")
      if (!page || (await page.title()) !== "Cherry Studio") {
        throw new Error("Bound Cherry Studio main target not found")
      }
      var cdp = await page.context().newCDPSession(page)
      ```
      
      Never call `browser.close()`, `page.close()`, or an Electron quit action.
      Detach only the profiling `CDPSession`. For visible DevTools, open the selected
      target's frontend without replacing the bound session:
      
      ```text
      http://127.0.0.1:<CDP_PORT><devtoolsFrontendUrl>
      ```
      
      Choose the smallest profile:
      
      | Question | Profile |
      | --- | --- |
      | Renderer load or memory level? | Quick metrics |
      | Cause of a visible stall? | 5-30 second trace |
      | Memory growth after repetition? | Repeated checkpoints |
      | Allocation source? | Allocation sampling |
      | Main/helper resource use? | Process sampling |
      | Slow startup? | Restart-aware startup analysis |
      
      Collect a quiet idle baseline. Keep action, duration, window size, route, data,
      and visible-DevTools state identical between comparisons.
      
      ## Quick renderer metrics
      
      ```js
      await cdp.send("Performance.enable")
      var beforeRaw = await cdp.send("Performance.getMetrics")
      var before = Object.fromEntries(
        beforeRaw.metrics.map(({ name, value }) => [name, value])
      )
      // Run one bounded scenario.
      var afterRaw = await cdp.send("Performance.getMetrics")
      var after = Object.fromEntries(
        afterRaw.metrics.map(({ name, value }) => [name, value])
      )
      ```
      
      Compare deltas for cumulative counters: `TaskDuration`, `ScriptDuration`,
      `LayoutDuration`, `LayoutCount`, `RecalcStyleDuration`, `RecalcStyleCount`, and
      `V8CompileDuration`. Treat `JSHeapUsedSize`, `JSHeapTotalSize`, `Nodes`,
      `Documents`, `Frames`, and `JSEventListeners` as point-in-time gauges.
      
      Approximate renderer main-thread utilization for a window of
      `elapsedSeconds`:
      
      ```text
      100 * delta(TaskDuration) / elapsedSeconds
      ```
      
      This is orientation, not complete CPU usage. Repeat identical scenarios and
      compare medians when differences are small.
      
      ## Interaction trace
      
      Trace one reproducible action for 5-30 seconds:
      
      ```js
      var traceDone = new Promise((resolve) =>
        cdp.once("Tracing.tracingComplete", resolve)
      )
      await cdp.send("Tracing.start", {
        categories: [
          "devtools.timeline",
          "v8",
          "blink.user_timing",
          "disabled-by-default-devtools.timeline"
        ].join(","),
        transferMode: "ReturnAsStream"
      })
      // Perform the action.
      await cdp.send("Tracing.end")
      var { stream } = await traceDone
      var chunks = []
      while (true) {
        var part = await cdp.send("IO.read", { handle: stream })
        chunks.push(Buffer.from(part.data, part.base64Encoded ? "base64" : "utf8"))
        if (part.eof) break
      }
      await cdp.send("IO.close", { handle: stream })
      var fs = await import("node:fs/promises")
      await fs.writeFile("<TRACE_PATH>.json", Buffer.concat(chunks))
      ```
      
      Correlate long tasks with script stacks, layout, paint, GC, and user timing.
      Keep raw traces under `.context`; they may contain private UI content or URLs.
      
      ## Memory and allocation
      
      For leak suspicion, record heap/nodes/documents/listeners at idle, repeat the
      same action a fixed number of times, return to the same idle state, and record
      again across multiple cycles. One larger heap value is not proof; V8 may defer
      GC. Do not force GC unless a post-GC comparison is explicitly needed.
      
      For bounded allocation attribution:
      
      ```js
      await cdp.send("HeapProfiler.enable")
      await cdp.send("HeapProfiler.startSampling", { samplingInterval: 32768 })
      // Perform one bounded scenario.
      var { profile } = await cdp.send("HeapProfiler.stopSampling")
      var fs = await import("node:fs/promises")
      await fs.writeFile("<PROFILE_PATH>.json", JSON.stringify(profile))
      ```
      
      Use a full heap snapshot only when sampling and gauges are insufficient. Warn
      first: it can pause the renderer, be large, and contain private data.
      
      ## Process and main-process checks
      
      Sample the tracked process group several times before, during, and after:
      
      ```bash
      ps -axo pid=,ppid=,pgid=,%cpu=,rss=,command= | \
        awk '$3 == <TRACKED_PGID>'
      ```
      
      Separate Electron main, renderer/helper, Vite, and runner costs. If renderer
      metrics are quiet while main is busy, verify and attach to the recorded Node
      inspector target, normally port `9229`. Use a bounded CPU profile and correlate
      it with application logs. Do not confuse it with renderer CDP `9222`.
      
      ## Startup analysis
      
      Startup profiling requires a restart:
      
      1. Explain and record the current instance/scenario.
      2. Gracefully stop only the tracked instance.
      3. Start the same debug command and profile.
      4. Preserve startup logs and timestamps.
      5. Measure navigation milestones such as `NavigationStart`,
         `DomContentLoaded`, and `FirstMeaningfulPaint`.
      6. Update `instance.json` and keep the replacement running.
      
      Separate native rebuild, main bootstrap, database migration, service startup,
      renderer load, and first interactive UI. Do not treat the whole `pnpm debug`
      duration as app startup.
      
      ## Interpretation and reporting
      
      - Script-heavy `TaskDuration` suggests JavaScript/React work.
      - Layout/style deltas suggest DOM measurement or CSS invalidation.
      - Repeated long trace tasks identify likely jank sources.
      - Heap plus node/listener growth after identical idle cycles suggests a leak.
      - Quiet renderer plus high main CPU points to services or IPC.
      - High helper/GPU CPU without renderer task growth points to media, canvas,
        GPU, or embedded web content.
      
      Report exact PID/target/route/scenario/duration, baseline and scenario deltas,
      artifact paths, strongest evidence, uncertainty, and before/after comparison
      for a fix. Keep Electron running after collection unless restart was explicitly
      part of the profile.
      
  • SKILL.md 2.9 KB
    ---
    name: cherry-electron-dev
    description: Develop, fix, and profile Cherry Studio in a tracked Electron instance. Use for everyday implementation, UI and interaction work, bug fixing, runtime debugging, DevTools inspection, lag or jank investigation, CPU and memory monitoring, leak checks, and startup-performance analysis; reuse a verified workspace instance across instructions and launch or replace one only when required.
    ---
    
    # Cherry Studio Development
    
    Use this skill for ongoing work in the current checkout. Do not use it to check
    out or report on PRs; use `cherry-pr-test` for that workflow.
    
    ## Required runtime workflow
    
    Before reading or controlling Electron UI, read
    [Electron Instance Management](references/electron-instance.md) and use its
    `persistent` policy.
    
    That reference is the only authority for instance discovery, `instance.json`,
    CDP target selection, launching, replacement, shutdown, and troubleshooting.
    Do not reproduce those procedures here or substitute generic Electron app
    control.
    
    ## Development loop
    
    1. State the requested behavior and the evidence that will prove it.
    2. Read the relevant code and nearby README files.
    3. Verify and reuse the tracked instance through the runtime reference.
    4. Reproduce or inspect the current behavior before editing when practical.
    5. Capture the smallest useful evidence: UI state, DOM, console/network output,
       main-process logs, persisted state, or performance metrics.
    6. Trace the responsible code path and make only the requested change.
    7. Keep Electron running. Use HMR for renderer changes and verify in the same
       window.
    8. Repeat the same scenario and compare before/after evidence.
    
    Inspect the real window at the relevant size and theme for UI work. Check both
    renderer and main-process evidence for renderer failures.
    
    Restart only for a non-reloadable layer, crash, unreliable runtime state, or
    startup profiling. Use the reference's exact-instance replacement procedure,
    refresh `instance.json`, and keep the replacement running.
    
    Run the narrowest relevant validation and follow current user and repository
    instructions for lint, formatting, and tests.
    
    ## Performance and DevTools
    
    For lag, jank, high CPU, memory growth, leaks, slow startup, or explicit
    DevTools use, read
    [Performance Debugging](references/performance-debugging.md).
    
    Store temporary logs, screenshots, and profiles under
    `.context/cherry-electron-dev/`. Compare a quiet baseline with the same bounded
    scenario before and after a fix. Detach profiling sessions afterward; do not
    close the CDP browser, page, or Electron process.
    
    ## Handoff
    
    Leave reused user-owned and healthy agent-launched instances running after the
    instruction. Stop one only when the user asks, a required restart is part of
    the task, or the instance is unhealthy and blocks progress.
    
    Report the verified PID, whether it remains running, CDP port, tracking file,
    evidence paths, reproduction, and verification.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related