Best for
- User asks to add one or more new partners (with or without a logo URL).
- User asks to standardize / normalize a logo (sizing wrong, white-on-white, etc.).
- User provides a local file and asks to replace an existing partner's logo.
lovstudio/skills/skills/maintain-partners/SKILL.md
Maintain the Skill Publisher website's partners section AND align partner logo rows on event posters / hero strips: reuse lov-find-logo for brand logo discovery, normalize collected logos to a 240px-tall content canvas (retina-ready), rasterize SVGs via rsvg-convert before normalizing (so SVG viewBox padding gets cropped), strip embedded background rects from icon-style SVGs, composite icon + wordmark when only an icon is available (using brand fonts), wrap logos in a fixed-size grid box (96×30
Decision brief
Maintains the configured website repo. Resolve the path from --repo, SKILLMAINTAINPARTNERSSITEROOT, or the shared user profile. The partners strip usually lives in app/(main)/(home)/PartnersGrid.tsx as a PARTNERS: Partner[] array; older sites may still keep it in app/(main)/(hom…
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/lovstudio/skills --skill "skills/maintain-partners"Inspect the Agent Skill "lov-maintain-partners" from https://github.com/lovstudio/skills/blob/8f250b126bb7e7eb6db0203c97d8279f75ae152d/skills/maintain-partners/SKILL.md at commit 8f250b126bb7e7eb6db0203c97d8279f75ae152d. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
1. Ask the user for the brand name + homepage URL via AskUserQuestion. 2. Collect the logo with lov-find-logo:
Before touching files, resolve:
lov-find-logo is required for all logo discovery. This skill must
User asks to add one or more new partners (with or without a logo URL).
Logo canvas: 80px content height for the website partners strip
Permission review
The documentation asks the agent to run terminal commands or scripts.
python3 "$SKILL_ROOT/lov-find-logo/scripts/find_logo.py" \The documentation asks the agent to run terminal commands or scripts.
python3 "$SKILL_DIR/scripts/normalize_logo.py" \The documentation includes network, browsing, or remote request actions.
export https_proxy=http://127.0.0.1:7890 \The documentation includes network, browsing, or remote request actions.
http_proxy=http://127.0.0.1:7890 \Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 91/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 64 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Maintains the configured website repo. Resolve the path from --repo,
SKILL_MAINTAIN_PARTNERS_SITE_ROOT, or the shared user profile. The partners
strip usually lives in app/(main)/(home)/PartnersGrid.tsx as a PARTNERS: Partner[] array; older sites may still keep it in
app/(main)/(home)/WorkshopDispatch.tsx. Logos live in
public/partners/<slug>/logo.png; taglines in
src/i18n/messages/{zh-CN,en,ja,th}.json under dispatch.partner*Tagline.
Before touching files, resolve:
SKILL_ROOT="${SKILL_SKILLS_INSTALL_DIR:?Set SKILL_SKILLS_INSTALL_DIR}"
SKILL_DIR="${SKILL_DIR:-$SKILL_ROOT/lov-maintain-partners}"
WEB_ROOT="${SKILL_MAINTAIN_PARTNERS_SITE_ROOT:?Set this or pass --repo}"
PARTNERS_TSX="${SKILL_MAINTAIN_PARTNERS_FILE:-app/(main)/(home)/PartnersGrid.tsx}"
Use this precedence for the website root:
--repo <path> on add_partner.py / audit_partners.py.SKILL_MAINTAIN_PARTNERS_SITE_ROOT.${SKILL_PROFILE_PATH:-$HOME/.skill-publisher/skills/profile.json}.SKILL_WEB_ROOT and PARTNERS_SITE_ROOT are accepted as legacy aliases,
but should not be the public contract for reusable skills.
Use this precedence for the partners TSX file:
--partners-file <path>.SKILL_MAINTAIN_PARTNERS_FILE.sites.partners_file, skill-publisher.partners_file,
partners.file, or workspace.partners_file.app/(main)/(home)/PartnersGrid.tsx, then legacy
app/(main)/(home)/WorkshopDispatch.tsx.SKILL_PARTNERS_FILE and PARTNERS_FILE are accepted as legacy aliases,
but should not be the public contract for reusable skills.
For details and supported profile keys, read references/user-config.md.
lov-find-logo is required for all logo discovery. This skill must
not scrape homepages itself or keep a separate fallback crawler.depends_on frontmatter field to declare skill-level dependencies.
This mirrors the depends_on field in lov-general-skills/skills.yaml;
unknown frontmatter keys are expected to be ignored by agents that do not
consume dependency metadata.height: 32px ≈ 2.5× density, sharp enough),
240px for event posters or any retina export at scale: 2 or higher.--show-name
when adding so the brand name renders next to the icon.<品牌名> · <一句话定位> in Chinese; mirror style in en/ja/th.AskUserQuestion.lov-find-logo:
python3 "$SKILL_ROOT/lov-find-logo/scripts/find_logo.py" \
--name "<显示名>" --url <URL> --slug <slug> --json
Use the archived primary asset under
~/.skill-publisher/logo-collection/<slug>/logo.<ext>. If find_logo.py returns
no candidates, stop and ask the user for a better official URL / press-kit
URL, then rerun find_logo.py. Do not call a local scraper from this skill.rsvg-convert -h 240 ~/.skill-publisher/logo-collection/<slug>/logo.svg \
-o /tmp/<slug>-raw.png
Use the rasterized /tmp/<slug>-raw.png as --src. For non-SVG sources,
use the archived primary asset directly.python3 "$SKILL_DIR/scripts/normalize_logo.py" \
--src <archived-or-rasterized-logo> \
--dst "$WEB_ROOT/public/partners/<slug>/logo.png" \
--invert auto
python3 "$SKILL_DIR/scripts/add_partner.py" \
--repo "$WEB_ROOT" \
--partners-file "$PARTNERS_TSX" \
--name "<显示名>" --href "<URL>" \
--logo "/partners/<slug>/logo.png" \
--key partner<Slug>Tagline \
--category community \
--zh "..." --en "..." --ja "..." --th "..." \
[--show-name]
python3 "$SKILL_DIR/scripts/normalize_logo.py" \
--src public/partners/<slug>/logo.png \
--dst public/partners/<slug>/logo.png \
--invert auto
Re-read after to verify.
Ask for the source file path directly, or read it from the user's configured workspace/profile. Do not assume a private partners folder.
python3 "$SKILL_DIR/scripts/normalize_logo.py" \
--src "<user-provided path>" \
--dst "$WEB_ROOT/public/partners/<slug>/logo.png" \
--invert auto
JPEG inputs auto-strip near-white background to transparent before crop.
python3 "$SKILL_DIR/scripts/audit_partners.py" \
--repo "$WEB_ROOT" \
--partners-file "$PARTNERS_TSX"
# add --probe to also HTTP-check every href (slow, requires proxy)
Reports: missing logo files, missing i18n keys per locale, dead URLs.
When: putting 3+ partner logos in a single horizontal strip and they look
different sizes despite having the same CSS height. Common in event posters,
hero sections, "联办 / co-host" rows.
Root cause: each source file has different internal padding (designer
canvas margin), so two PNGs both set to height: 24px render at different
visible heights because their content occupies different fractions of the
canvas. Per-logo CSS height tweaks based on eyeballed content ratios are
unstable—different displays / scaling will diverge again.
Reliable fix — trim at file level, uniform CSS box:
Normalize every logo to identical content height. Default raster file
target is 240px (3× density for retina poster export at scale: 2;
80px gives only 1.7× and looks soft after PNG export). Use --invert off
if the source is already light-on-transparent (don't double-invert):
for f in lujiazui juanyi citic-bookstore citic-thinker-lab; do
python3 "$SKILL_DIR/scripts/normalize_logo.py" \
--src "<configured-partners-source>/<brand>/<file>.png" \
--dst <event-assets>/partners/$f.png \
--height 240 --invert auto
done
Always normalize from the original source, never from a previously normalized 80px file (upscaling = blurry — burned by this on juanyi).
For SVG sources, rasterize first. normalize_logo.py operates on
raster pixels and cannot crop SVG viewBox padding. Without this step
an SVG always renders smaller than rasterized PNG siblings:
rsvg-convert -h 720 brand.svg -o /tmp/brand-raw.png # 3× of 240
python3 "$SKILL_DIR/scripts/normalize_logo.py" \
--src /tmp/brand-raw.png --dst <event-assets>/partners/brand.png \
--height 240 --invert off
rsvg-convert ships with librsvg (brew install librsvg).
For SVG with embedded background rect (icon wrapped in a black/colored
rounded square — common in app-icon-style SVGs from find-logo), strip
the background before rasterizing, otherwise filter brightness(0) invert(1) flattens it into a solid white block that hides the icon:
# Drop the outer <rect fill="#000"...> wrapper
sed -E 's|<rect[^/]*fill="#0+"[^/]*/>||' brand.svg > /tmp/brand-clean.svg
rsvg-convert -h 720 /tmp/brand-clean.svg -o /tmp/brand-raw.png
Wrap each logo in a fixed-size box (recommended over auto-width flex):
<span class="ps-logo-box"><img src="..." class="ps-logo"></span>
.ps-logo-box {
width: 96px; height: 30px; /* fixed grid cell */
display: inline-flex;
align-items: center; justify-content: center;
border: 1px solid rgba(255,255,255,0.10);
border-radius: 4px;
padding: 3px 6px;
box-sizing: border-box;
}
.ps-logo { max-width: 100%; max-height: 100%; width: auto; height: auto; display: block; }
Fixed boxes give a stable matrix look — narrow logos (icon-only) and wide logos (icon + wordmark) all occupy the same footprint, with the asset scaled to fit. Auto-width flex (the older recipe) makes per-row total widths unpredictable as logos get added/removed.
Dark-background unification — when the row sits on a dark canvas (e.g. event poster), most brand logos are designed for white BG and look inconsistent (some have black text, some have brand-colored marks). The stable recipe:
.ps-logo { filter: brightness(0) invert(1) opacity(0.88); }
/* logos already white-on-transparent — opt out of inversion */
.ps-logo.ps-logo-original { filter: opacity(0.88); }
brightness(0) flattens all colors to black, then invert(1) produces
uniform white at the configured opacity. The .ps-logo-original escape
hatch is for source files that are already white-on-transparent (white
SVG variants from a brand kit) so you don't double-process them into
invisible black-on-dark.
Icon-only SVG → composite icon + wordmark — if the brand SVG only has an icon (no "BrandName" wordmark beside it), don't ship just the icon in a 96×30 box (it'll look like an unidentified mark). Compose the wordmark with PIL using the brand's own font when possible:
from PIL import Image, ImageDraw, ImageFont, ImageOps
# 1. rasterize cleaned SVG, invert white→black so default filter works
icon = Image.open('/tmp/brand-icon.png').convert('RGBA')
r, g, b, a = icon.split()
inv = Image.merge('RGB', (ImageOps.invert(r), ImageOps.invert(g), ImageOps.invert(b)))
icon = Image.merge('RGBA', (*inv.split(), a))
icon = icon.crop(icon.getbbox())
target_h = 240
icon = icon.resize((int(icon.width * target_h / icon.height), target_h), Image.LANCZOS)
# 2. render wordmark in brand font (find-logo bundles fonts/ when found)
font = ImageFont.truetype('partners/<brand>/fonts/<Family>.ttf', 150)
# 3. compose icon + gap + text on transparent canvas
The PNG goes through the same brightness(0) invert(1) filter as raster
logos — match colors with all other entries automatically. Use the brand's
own font (often shipped under <brand>/fonts/ by the find-logo skill);
fall back to system SF / Helvetica only if no brand font is available.
Anti-pattern — do not try to fix alignment by setting per-logo
heights like .ps-logo-juanyi { height: 26px }. It's brittle (every new
logo needs another magic number), unstable across browsers, and breaks
the moment a designer reships the source asset with different padding.
| Flag | Default | Notes |
|---|---|---|
--src | required | input image (PNG/JPG/rasterized SVG) |
--dst | required | output PNG path; parent dirs auto-created |
--height | 80 | target content height. Use 240 for retina poster export (scale: 2) — 80 looks soft after 2× downscale. |
--invert | auto | auto / off / full / selective (selective preserves colored icons) |
| Flag | Notes |
|---|---|
--repo | website repo root; defaults to SKILL_MAINTAIN_PARTNERS_SITE_ROOT, profile JSON, or legacy SKILL_WEB_ROOT / PARTNERS_SITE_ROOT |
--partners-file | PARTNERS TSX file; defaults to SKILL_MAINTAIN_PARTNERS_FILE, profile JSON, legacy SKILL_PARTNERS_FILE / PARTNERS_FILE, PartnersGrid.tsx, or WorkshopDispatch.tsx |
--name | display name (CJK ok) |
--href | brand URL |
--logo | path under /public, e.g. /partners/foo/logo.png |
--key | i18n key, e.g. partnerFooTagline |
--category | compute / peer / invest / media / community; default community |
--zh / --en / --ja / --th | tagline strings (all required) |
--show-name | render name next to icon for narrow logos |
| Flag | Notes |
|---|---|
--repo | website repo root; defaults to SKILL_MAINTAIN_PARTNERS_SITE_ROOT, profile JSON, or legacy SKILL_WEB_ROOT / PARTNERS_SITE_ROOT |
--partners-file | PARTNERS TSX file; defaults to SKILL_MAINTAIN_PARTNERS_FILE, profile JSON, legacy SKILL_PARTNERS_FILE / PARTNERS_FILE, PartnersGrid.tsx, or WorkshopDispatch.tsx |
--probe | HTTP-probe every href (slow, needs proxy env vars) |
Sandbox child processes don't inherit the system ClashX proxy. Before
fetching logos with lov-find-logo or probing partner URLs, export:
export https_proxy=http://127.0.0.1:7890 \
http_proxy=http://127.0.0.1:7890 \
all_proxy=socks5://127.0.0.1:7891
audit_partners.py already injects these for curl invocations.
git clone https://example.com/skills/find-logo-skill \
"${SKILL_SKILLS_INSTALL_DIR:?Set SKILL_SKILLS_INSTALL_DIR}/lov-find-logo"
python3 -m pip install Pillow
brew install librsvg # for SVG logo sources
运行前读取本 Skill 包的 skill.yaml,由宿主提供 skill-runtime/v1 上下文。字段解析顺序为:当前请求、项目上下文、个人 Preferences、品牌 Profile、通用默认值。
required: true 字段缺失时,按 Manifest 的问题配置向用户提出一个聚焦问题;用户明确同意后再保存回答。context_id、字段路径与来源,诊断内容避开秘密、完整私人路径和原始配置。用户在 Skill 驱动任务中提出修改意见时,继续当前产物前必须执行:
task-specific(仅本次)还是 reusable(可跨任务复用)。task-specific 只修改当前任务,不改 Skill。reusable 先确定作用域:领域规则先更新对应 canonical Skill;适用于所有 Skill 的规则先更新共享规范。reusable 修改会使此前的“确认”“继续”“发吧”失效;完成当前产物修改和回读后必须停下,等待用户下一步指示,不自动进入发布、提交或其他外部写入。Frequently asked questions
Maintains the configured website repo. Resolve the path from --repo, SKILLMAINTAINPARTNERSSITEROOT, or the shared user profile. The partners strip usually lives in app/(main)/(home)/PartnersGrid.tsx as a PARTNERS: Partner[] array; older sites may still keep it in app/(main)/(hom…
The source record exposes this install command: npx skills add https://github.com/lovstudio/skills --skill "skills/maintain-partners". Inspect the command and pinned source before running it.
Static rules flagged exec-script, network in the source; the page lists the matching lines and excerpts.
Alternatives
respira-press/agent-skills-wordpress
Use when the user says 'build a design system for my site', 'extract design tokens', 'capture my brand', or 'build my style guide', or after a rebrand. Reads representative pages, theme files, and media to extract logo, colors, typography, spacing, and components, then writes a visible style-guide page.
MoizIbnYousaf/marketing-cli
Use when the user wants to generate an image or video via Higgsfield AI. Covers 30+ models: Soul V2, Seedance 2.0, Kling 3.0, Veo 3.1, GPT Image 2, Nano Banana 2. Also covers Marketing Studio — branded ad video/image with avatars and products. Use whenever: "generate an image", "make a video", "animate this photo", "image-to-video", "img2vid", "edit this image with AI", "produce a clip", "create an ad", "make a UGC video", "marketing video", "brand video", "TV spot", "import product from URL", "
KerberosClaw/kc_ai_skills
Use when the user wants to turn a Markdown report into a presentation-quality .pptx via interactive design decisions and a reusable hand-coded build script. Drives pre-analysis, global style choices, optional per-slide layout dialogue, python-pptx composition, and optional LibreOffice render self-check. NOT a generic auto-converter, NOT for PDF output, and NOT a fixed brand-template pipeline — brand integration is handled ad hoc through helper primitives.
maquina-app/rails-claude-code
Create comprehensive MVP documentation for Rails applications. Use this skill whenever a user describes a new app idea, wants to explore a SaaS concept, needs competitor research, or is starting a new project from scratch — even if they don't explicitly say "MVP". Triggers on "I have an idea for...", "I want to build...", "help me plan...", "research competitors for...", "create a business plan for...", "design a brand for my app", "set up Claude for my Rails project", "bootstrap an app", or any