Agent skill

Acp Live Diagnose

by jrhubott in jrhubott/adaptive-cover-pro

Root-cause a misbehaving Adaptive Cover Pro cover on a RUNNING Home Assistant install by pulling live diagnostics over the HA MCP, correlating against the recorder, proving the mechanism with a…

MITAuto-check passedDevelopment

Install Acp Live Diagnose

skills CLI
$ npx skills add jrhubott/adaptive-cover-pro --skill acp-live-diagnose -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install jrhubott/adaptive-cover-pro acp-live-diagnose --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/jrhubott/adaptive-cover-pro.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/acp-live-diagnose .claude/skills/acp-live-diagnose && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
acp-live-diagnose
GitHub stars
176
Token cost
~3.8k tokens
SKILL.md length
1,759 words
Files
1
Skills in repo
4
Repo updated
First seen
Licence
MIT

At a glance

Root-cause a misbehaving Adaptive Cover Pro cover on a RUNNING Home Assistant install by pulling live diagnostics over the HA MCP, correlating against the recorder, proving the mechanism with a…

  • Works in 10 steps: Session Startup → Resolve the Target → Pull Live Diagnostics → …
  • The user describes live misbehavior in the present tense and names a cover
  • SKILL.md covers Step 0 — Session Startup, Step 1 — Resolve the Target, Step 2 — Pull Live Diagnostics and Step 3 — Corroborate Against…, plus 9 more sections
  • Calls git, python and gh

What it does

Acp Live Diagnose is an agent skill from jrhubott/adaptive-cover-pro. Root-cause a misbehaving Adaptive Cover Pro cover on a RUNNING Home Assistant install by pulling live diagnostics over the HA MCP, correlating against the recorder, proving the mechanism with a reproduction test in the local checkout, then drafting a GitHub issue for approval and offering handoff to implement-issue. Use when the user describes live misbehavior in the present tense and names a cover or entity — "figure out why the minimum floor is overriding a manual position on X", "why does X keep reopening", "X…

Its SKILL.md is about 3.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Development, covering Root cause analysis. It works with GitHub, Home Assistant and Model Context Protocol. The repository describes itself as: Adaptive sun-tracking cover control for Home Assistant: blinds, awnings, and venetian tilts with climate-aware positioning and a priority override pipeline. The licence is MIT.

When your agent uses it

  • The user describes live misbehavior in the present tense and names a cover
  • Entity — figure out why the minimum floor is overriding a manual position on X
  • Why does X keep reopening
  • My cover bounces back

Example prompts

  • “figure out why the minimum floor is overriding a manual position on X”
  • “why does X keep reopening”
  • “t moving”
  • “/acp-live-diagnose”

Requirements

  • Python 3

Workflow steps

10 steps, taken from the step headings in SKILL.md.

  1. Session Startup
  2. Resolve the Target
  3. Pull Live Diagnostics
  4. Corroborate Against the Recorder
  5. Root-Cause Against the Local Checkout
  6. Prove It With a Reproduction
  7. Verdict Before Filing
  8. Draft the Issue
  9. Show the Draft, Then Create
  10. Offer the Handoff

What it can do on your machine

Read from SKILL.md and the folder at commit c03d682. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • git
    • python
    • gh

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use git and gh, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Acp Live Diagnose loads about 3.8k tokens when it runs. Until then it costs about 195 tokens; SKILL.md has 1,759 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~195
When it runs · the whole SKILL.md, loaded when a task matches
~3.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from jrhubott/adaptive-cover-pro at commit c03d682, republished under its MIT licence (© jrhubott). 1,759 words, ~3,844 tokens.

Download SKILL.mdSave it as .claude/skills/acp-live-diagnose/SKILL.md (or your agent's skills folder).
name
acp-live-diagnose
description
Root-cause a misbehaving Adaptive Cover Pro cover on a RUNNING Home Assistant install by pulling live diagnostics over the HA MCP, correlating against the recorder, proving the mechanism with a reproduction test in the local checkout, then drafting a GitHub issue for approval and offering handoff to implement-issue. Use when the user describes live misbehavior in the present tense and names a cover or entity — "figure out why the minimum floor is overriding a manual position on X", "why does X keep reopening", "X isn't moving", "my cover bounces back", "diagnose X on my install" — or asks to investigate a live symptom and file an issue about it. NOT for a downloaded diagnostics JSON (use acp-diagnose) or a GitHub issue number (use acp-issue-diagnose).

ACP Live Diagnose

Turn "my cover is doing something wrong right now" into a filed, root-caused GitHub issue.

The three ACP diagnosis skills differ only in where the evidence comes from:

InputSkill
Downloaded diagnostics.jsonacp-diagnose
GitHub issue numberacp-issue-diagnose
Running HA install (MCP)this skill

The distinguishing value here is that the install is live: the recorder can be queried, the code is checked out locally, and the mechanism can be proven by execution rather than argued from reading. Do not skip that proof.


Step 0 — Session Startup

bash
git status && git log --oneline -5

Recent commits often name work in the same subsystem, which is exactly the context that turns "this looks wrong" into "this regressed in #NNNN." When a symptom looks like a known trap rather than a new defect, HANDOFF.md is worth a read — it carries the unfiled gotchas and the "not hotfixable to main" table, and nothing else.


Step 1 — Resolve the Target

Each ACP cover is its own config entry. Match on the title the user used:

ha_get_integration(query="<cover name fragment>")

Zero matches → widen with ha_get_integration(query="adaptive") and show the list. Multiple matches → ask which one; do not guess.

Record the entry_id and, from entry.options, the config that bears on the symptom. Options are the reporter's actual configuration — read them before forming any hypothesis. Watch for keys stored as null that fall back to a DEFAULT_* constant (custom_position_priority_N → DEFAULT_CUSTOM_POSITION_PRIORITY); the effective value is what matters, and it is not in the dump.


Step 2 — Pull Live Diagnostics

ha_get_integration(entry_id=..., include_diagnostics=True,
                   diagnostics_data_path="data.diagnostics",
                   diagnostics_truncate_at_bytes=1200)

That returns available_fields — the section list. Drill in one section at a time:

ha_get_integration(entry_id=..., include_diagnostics=True,
                   diagnostics_data_path="data.diagnostics.<section>",
                   diagnostics_fields=["data"])

⚠️ Always pass diagnostics_fields=["data"] on drill-in calls. Without it every response re-echoes the entire entry.options blob, which is several hundred tokens per call and adds nothing after Step 1.

Sections that carry the most signal, roughly in order:

  • decision_trace — the pipeline chain with each handler's match/reason/priority. The starting point for almost every symptom.
  • event_timeline — chronological pipeline_evaluated / cover_command_sent / cover_command_skipped records. Paginated, ~250 entries, and the interesting part is nearly always the tail. Probe diagnostics_data_limit=25, diagnostics_data_offset=0 to learn total, then jump to offset=total-30.
  • manual_override_history / manual_override_state — engage/reject/reset records with the threshold reasoning.
  • cover_commands — per-entity target_call, wait_for_target, retry_count, gave_up.
  • last_cover_action, last_skipped_action — the most recent dispatch and the most recent suppression.
  • meta — integration_version, cover_type. Always capture; the issue needs it and a develop/alpha build changes what "latest" means.

Diagnostics timestamps are UTC. The HA MCP converts recorder timestamps to the install's local zone. Never compare the two without converting, and state which zone any timestamp in the issue is in.


Step 3 — Corroborate Against the Recorder

Diagnostics say what ACP believed. The recorder says what the hardware did. A root cause is not established until both agree.

ha_get_history(entity_ids="cover.<target>",
               start_time="<UTC iso>", end_time="<UTC iso>",
               minimal_response=False, order="asc")

Bracket the window around the timestamps found in Step 2, plus a few minutes either side. minimal_response=False is required — current_position lives in the attributes.

This step routinely rewrites the hypothesis. It is what distinguishes "ACP computed 40" from "ACP drove the cover from 0 back to 40 thirteen seconds after the user closed it," and only the second is a bug report.

Where relevant, also pull the states of the entities that gate the behavior — trigger input_booleans, sensors named in options, the other covers in a group.


Step 4 — Root-Cause Against the Local Checkout

Read the actual code. Never infer a mechanism from a diagnostics reason string — those strings are rendered from reason_i18n.py templates and can lag or describe a different frame than the value beside them.

Work from the decision trace inward: the winning handler, then the registry composition pass that post-processes the winner, then whatever seam dispatched. CLAUDE.md's architecture map names the layer for each.

Note for shell searches: quote globs, since zsh expands them first.

bash
grep -rn "pattern" --include="*.py" custom_components/    # not --include=*.py

Two recurring shapes worth checking explicitly, because both have produced real defects:

  • The same rule stated at two seams. A user-command path and a pipeline path that each independently decide the same question. If one is priority-gated and the other is not, the gated one is defeated one cycle later. Read both; do not assume the one you found first is the only one.
  • Values that are not what their name suggests. current_cover_position is the mean across every cover in the entry (_compute_mean_cover_position), not the position of the cover being commanded. Confirm the arithmetic against the observed number before building an argument on it.

Then check whether the behavior is already pinned by a test. If two tests assert opposite contracts for the same input and both pass, that pair is the finding — cite both with file:line.


Step 5 — Prove It With a Reproduction

Mandatory for any defect claim. Reconstruct the live numbers using the existing test fixtures and run it.

Find a test module that already builds the relevant snapshot (for pipeline work, tests/test_pipeline/test_floor_composition.py and its make_snapshot / _cp_state / _registry_with_custom helpers), import those helpers, substitute the values observed on the install, and print the result fields.

⚠️ The scratch test must live inside tests/. Running it from the scratchpad fails on enable_event_loop_debug — the autouse fixtures come from tests/conftest.py. Write it to tests/<subdir>/test_zz_scratch_repro.py, run it, then delete it.

bash
cp <scratchpad>/test_repro.py tests/test_pipeline/test_zz_scratch_repro.py
venv/bin/python -m pytest tests/test_pipeline/test_zz_scratch_repro.py -q -s
rm tests/test_pipeline/test_zz_scratch_repro.py
git status --short          # must be clean before moving on

Use venv/bin/python -m pytest, never source venv/bin/activate. In a linked worktree there is no venv/ — pass the main checkout's absolute interpreter path.

Paste the real printed output into the issue. Do not paraphrase it, and do not write the repro without running it.


Step 6 — Verdict Before Filing

Classify before drafting. Not every live symptom is a defect:

VerdictAction
DefectProceed to Step 7.
MisconfigurationExplain the option that produces the behavior and what to change. Do not file. Offer to file a docs/UX issue if the config was reasonably misread.
DuplicateReport the existing issue number and what it does or does not already cover. Ask before filing anything new.
Works as designed, badlyFile as enhancement, not bug, and say so.
UnprovenSay the mechanism is unconfirmed and name what would confirm it. Do not file a guess.

Search the tracker before filing, both states:

bash
gh issue list --repo jrhubott/adaptive-cover-pro --state all --limit 200 \
  --search "<symptom keywords>" --json number,title,state

Read the bodies of the close matches, not just their titles. A closed issue whose fix introduced the current behavior is the most valuable context an issue can carry, and its reporter's configuration usually explains why the fix was written the way it was. An open issue covering the same contract may mean the right move is a comment rather than a new issue — raise that with the user.


Show full SKILL.md (713 more words)Show less

Step 7 — Draft the Issue

Invoke the writing skill before drafting. Voice: first person ("I"), matching the maintainer's tone across the repo. No filler openers, no ceremonial closers.

Follow .github/ISSUE_TEMPLATE/bug.yml's section headings so the issue looks native (### Adaptive Cover Pro version, ### Home Assistant version, ### Cover type, ### Describe the issue, ### Reproduction steps), then add the analysis sections. Structure that works:

  1. What I observed — one paragraph, present tense, on the real install. Then the effective config as a short code block, resolving any null to its constant.
  2. Recorder evidence — a small table of state/position transitions with times. This is the part a reader believes.
  3. Reproduction steps — numbered, generalized away from the specific install, with explicit Expected and Actual.
  4. Determination — the mechanism, one seam at a time, each with a file.py:line citation and the smallest quoted snippet that shows it. Include the repro's printed output verbatim. If contradictory tests exist, cite both.
  5. Secondary findings — anything real but distinct from the main defect, clearly labelled as separate.
  6. Relationship to existing issues — what each related issue covers and where the boundary is.
  7. Suggested direction — where the fix goes and what must not change with it. Name the tests that will have to move.

Keep every factual claim traceable to something pulled in Steps 2-5. If a number is not in the diagnostics, the recorder, or the repro output, do not put it in the issue.


Step 8 — Show the Draft, Then Create

⚠️ Always show the full drafted issue to the user before creating it. Filing to GitHub is outward-facing and shared; a draft shown after the fact is not a review.

Write the body to the scratchpad, show it, and ask one question:

Create this issue as-is, edit it first, or hold off?

Only on explicit approval in the same turn:

bash
gh issue create --repo jrhubott/adaptive-cover-pro \
  --title "<title>" --label bug \
  --body-file "<scratchpad>/issue_body.md"

Title rule: name the mechanism, not the symptom. "Min-mode floor below manual-override priority still raises a manual position via the held-position clamp" beats "cover reopens by itself" — the tracker is searched by maintainers, not by symptom.

Do not assign, milestone, or close anything. Do not comment on related issues; the cross-reference in the body already creates a backlink.


Step 9 — Offer the Handoff

After the issue is created, report its number and URL, then ask:

Want me to run implement-issue on #NNNN to plan and build the fix?

Wait for an answer. On yes, invoke the implement-issue skill with the new issue number. On no, stop — do not start a branch, write code, or open a PR.

If the verdict in Step 6 was anything other than Defect, skip this step; there is nothing to implement.


Output Format (skill-final report to user)

ACP live diagnose — <cover title> (<entry_id>)
ACP <integration_version> · <cover_type>

Symptom:   <one line, as observed>
Verdict:   <defect | misconfiguration | duplicate | enhancement | unproven>
Mechanism: <one or two sentences, with the seam named>
Proof:     <repro test result, one line>

--- DRAFT ISSUE ---
<full markdown body>
--- END DRAFT ---

Create this issue as-is, edit it first, or hold off?

After creation, replace the trailing question with the issue URL and the Step 9 handoff question.


Safety Rules

  • Never create the issue without showing the draft and getting approval in the same turn. Approval for a previous issue does not carry over.
  • Never claim a mechanism that was not executed. A repro that was written but not run is not evidence.
  • Read-only against Home Assistant. This skill queries; it does not call services, change options, or move covers. If moving a cover would confirm a hypothesis, ask the user to do it.
  • Leave the working tree clean. Delete every scratch test and verify with git status --short.
  • Do not edit HANDOFF.md or CLAUDE.md as part of this workflow — both are excluded from the repo and synced from a source of truth outside it, so an edit to the copy here is silently discarded. HANDOFF.md is written only by ~/.claude/references/handoff-update.md, after a merged run.
  • Report contradictions rather than smoothing them. If the recorder disagrees with the diagnostics, that gap is the finding.

Notes for Future Maintenance

  • The MCP diagnostics payload lives under data → config_options + diagnostics; the triage view is {"options": config_options, **diagnostics} — the same data scripts/triage_json.py runs over. If a section is renamed, available_fields from the Step 2 probe is self-describing; no list in this file needs updating.
  • Some hardware pins current_position until travel completes and only publishes opening/closing in between (ZVIDAR shades do this). Position-delta reasoning is blind to those covers — check the recorder's state column, not just current_position.
  • Skills under .claude/skills/ are repo-tracked (.gitignore has !.claude/skills/). Changes here go through a PR like any other source change.

© jrhubott, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/acp-live-diagnose of jrhubott/adaptive-cover-pro.

Open the folder on GitHubat commit c03d682

Compare with similar skills

Acp Live Diagnose next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Acp Live Diagnose compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Acp Live Diagnose this skilljrhubott/adaptive-cover-pro176—~3.8kAutomated safety check: PassMIT
Octocode Code Researchbgauryy/octocode949—~1.5kAutomated safety check: PassMIT
Triagearcee-ai/nac281—~2kAutomated safety check: PassApache-2.0
My PR Checkerhomeassistant-ai/ha-mcp5k—~1.2kAutomated safety check: NotesMIT
Demonstrate Issueshmislk/hmis236—~4.8kAutomated safety check: NotesGPL-3.0
Fix Issueyonatangross/orchestkit292—~6.2kAutomated safety check: NotesMIT

Similar skills

  • Octocode Code Research

    bgauryy/octocode

    Researches code with evidence: traces callers, imports and cross-repo links, diagnoses failures and reports findings with exact file and line references and a confidence label.

    949 GitHub stars~1.5k tokensUpdated 2 days ago
    DevelopmentAuto-check passed
  • Triage

    arcee-ai/nac

    Triage a GitHub repository's open issues by finding exact duplicates, rejecting evidenceably off-base requests, requesting concrete clarification, applying only existing labels, and opening a linked…

    281 GitHub stars~2k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • My PR Checker

    homeassistant-ai/ha-mcp

    Manage your own GitHub pull requests — check CI status, inline review comments, PR-level comments, resolve review threads, fix issues, and iterate until all checks pass and threads are resolved.

    5k GitHub stars~1.2k tokensUpdated today
    DevelopmentAuto-check: notes
  • Run a live bug-demonstration capture session before filing GitHub issues.

    236 GitHub stars~4.8k tokensUpdated yesterday
    DevelopmentAuto-check: notes
  • Fix Issue

    yonatangross/orchestkit

    Fixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection.

    292 GitHub stars~6.2k tokensUpdated yesterday
    DevelopmentAuto-check: notes
  • Prior Art Scout

    n1m21n/Infinite

    Find publicly documented solutions (peer repos, GitHub, forums) to bugs, platform quirks, dependency gotchas or architectural patterns, respecting the copyleft discussions-only rule.

    271 GitHub stars~1.3k tokensUpdated yesterday
    Legal & ComplianceAuto-check passed

More from jrhubott/adaptive-cover-pro

  • Acp Diagnose

    jrhubott/adaptive-cover-pro

    Analyze an Adaptive Cover Pro diagnostics JSON file and produce a triage report.

    176 GitHub stars~958 tokensUpdated 2 days ago
    Auto-check passed
  • Acp Issue Diagnose

    jrhubott/adaptive-cover-pro

    Triage an Adaptive Cover Pro GitHub issue end-to-end — fetch the attached diagnostics file (or take a local path), run a Sonnet-powered diagnosis, and draft a reply ready to post on the issue.

    176 GitHub stars~2.8k tokensUpdated 2 days ago
    Auto-check passed
  • Acp Translate

    jrhubott/adaptive-cover-pro

    Sync DE/FR translations with en.json, add a new language, drop a language, or check translation status for the Adaptive Cover Pro integration.

    176 GitHub stars~5.8k tokensUpdated 2 days ago
    Auto-check passed

Categories

Questions about Acp Live Diagnose

What does Acp Live Diagnose do?

Root-cause a misbehaving Adaptive Cover Pro cover on a RUNNING Home Assistant install by pulling live diagnostics over the HA MCP, correlating against the recorder, proving the mechanism with a…. Acp Live Diagnose is an agent skill from jrhubott/adaptive-cover-pro. Root-cause a misbehaving Adaptive Cover Pro cover on a RUNNING Home Assistant install by pulling live diagnostics over the HA MCP, correlating against the recorder, proving the mechanism with a reproduction test in the local checkout, then drafting a GitHub issue for approval and offering handoff to implement-issue.

When should I use Acp Live Diagnose?

Acp Live Diagnose fits situations like: the user describes live misbehavior in the present tense and names a cover; entity — figure out why the minimum floor is overriding a manual position on X; why does X keep reopening; my cover bounces back.

How do I install Acp Live Diagnose in Claude Code?

Run `npx skills add jrhubott/adaptive-cover-pro --skill acp-live-diagnose -a claude-code`. Or copy the skill folder (.claude/skills/acp-live-diagnose in jrhubott/adaptive-cover-pro) into .claude/skills/acp-live-diagnose in your project. Claude Code loads it when a task matches its description.

How do I install Acp Live Diagnose in Codex?

Run `npx skills add jrhubott/adaptive-cover-pro --skill acp-live-diagnose -a codex`. Or copy the skill folder (.claude/skills/acp-live-diagnose in jrhubott/adaptive-cover-pro) into .agents/skills/acp-live-diagnose in your project. Codex loads it when a task matches its description.

Can I use Acp Live Diagnose in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add jrhubott/adaptive-cover-pro --skill acp-live-diagnose -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/acp-live-diagnose, .gemini/skills/acp-live-diagnose, .github/skills/acp-live-diagnose and .opencode/skills/acp-live-diagnose in your project.

What does Acp Live Diagnose need to run?

Going by SKILL.md and its folder, Acp Live Diagnose needs the command-line tools its instructions call (git, python and gh). Our summary lists: Python 3.

Does Acp Live Diagnose access the network?

SKILL.md contains no URLs. Its commands use git and gh, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Acp Live Diagnose safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Acp Live Diagnose use?

Acp Live Diagnose is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Acp Live Diagnose use?

About 3.8k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Acp Live Diagnose?

Skills that share tags, products or a category with Acp Live Diagnose: Octocode Code Research (bgauryy/octocode, 949 stars), Triage (arcee-ai/nac, 281 stars), My PR Checker (homeassistant-ai/ha-mcp, 5k stars) and Demonstrate Issues (hmislk/hmis, 236 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Acp Live Diagnose?

jrhubott (a GitHub user) maintains it in jrhubott/adaptive-cover-pro, which has 176 GitHub stars. The repository holds 4 skills in this directory. The repository was last updated on October 9, 2026.

Source: jrhubott/adaptive-cover-pro on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.