Skip to content

feat!: eliminate root SKILL.md + root references/ — skills are now independent#79

Merged
kenchung merged 1 commit into
masterfrom
feat/eliminate-root-skill-md
Apr 27, 2026
Merged

feat!: eliminate root SKILL.md + root references/ — skills are now independent#79
kenchung merged 1 commit into
masterfrom
feat/eliminate-root-skill-md

Conversation

@eve-builds
Copy link
Copy Markdown
Collaborator

Summary

Eliminate root SKILL.md and root references/. Each skill (heygen-avatar, heygen-video) is now fully independent with its own self-contained bundle. Net -1940 deletions, +149 modifications.

Follow-up to #77 — completes the architectural cleanup we agreed on (@kchung Slack thread, link).

Why

After #77 made each skill bundle self-contained for gh skill install, the repo had three copies of most reference docs (root + heygen-avatar + heygen-video) with an explicit sync gate. That's residual coupling from the pre-split architecture.

The cleanest end-state: two skills, two bundles, no shared root. If the docs drift between skills, that's fine — each skill is internally consistent and authored independently. Drift is a feature, not a bug, when the skills serve different concerns (avatar creation vs video generation).

What's deleted (1940 lines)

  • SKILL.md (root, 292 lines) — the "meta/router" skill. Its content (API mode detection, UX rules, language awareness, first-look, files & paths) migrated into both heygen-avatar/SKILL.md and heygen-video/SKILL.md. Each skill now stands alone.
  • references/ (9 files, ~1450 lines) — the shared canonical copies. Each skill already owned the references it actually links to after feat: make heygen-avatar + heygen-video install cleanly via gh skill #77; root copies were redundant.
  • scripts/sync-references.sh (107 lines) — no longer needed; nothing to sync.
  • scripts/update-check.sh (162 lines) — duplicate; heygen-video/scripts/update-check.sh is the live copy.

What's added/migrated (~149 lines)

heygen-avatar/SKILL.md gets:

  • Files & Paths section — what the skill reads/writes (SOUL.md, IDENTITY.md, AVATAR-*.md, role symlinks, /tmp/openclaw/uploads/, HeyGen uploads)
  • Language Awareness section — user_language detection + voice selection rules
  • UX Rules section — adapted from root (concise, no jargon, one-or-two-questions-per-phase, read workspace files first, etc.)

Net +33 lines. Stays under the 500-line CONTRIBUTING.md ceiling.

heygen-video/SKILL.md gets:

  • v3-only STOP banner (was at root, must be present in every video-side SKILL.md)
  • Files & Paths section
  • UX Rules section (full 9-rule version — polling-is-silent, deliver-clean, etc.)
  • Language Awareness section
  • First Look section — the first-run avatar check (AVATAR-*.md + role symlinks scan, avatar readiness gate, Quick Shot exception). Previously only at root.

Net +51 lines.

Updated peripherals

  • INSTALL_FOR_AGENTS.md — drop root SKILL.md from canonical URLs; mode-detection-ladder pointers rewritten to point at the per-skill SKILL.md
  • CLAUDE.md — rewrite Architecture diagram (no more root SKILL.md / references/), add explicit note that drift between skills is acceptable, update 300-line rule pointer text
  • CONTRIBUTING.md — drop sync-references.sh editor checklist, replace References-layout section with a simpler "edit the skill that owns the file" guidance
  • release-please-config.json — drop root SKILL.md from extra-files (only per-skill SKILL.md files get version-bumped now)
  • .github/workflows/validate-skills.yml — drop the references-in-sync job, drop root path triggers, add a references/ parent-dir-ref check on each skill's in-tree refs (catches ../../ paths in references/*.md before install)

Empirical verification

$ gh skill install ./_ghskill_test heygen-avatar --from-local --scope project
✓ heygen-avatar/
    ├── SKILL.md
    └── references/
        ├── asset-routing.md
        ├── avatar-creation.md
        └── troubleshooting.md

$ gh skill install ./_ghskill_test heygen-video --from-local --scope project
✓ heygen-video/
    ├── SKILL.md
    ├── references/  (8 files)
    └── scripts/update-check.sh

# Self-containment + orphan check:
✓ heygen-avatar: no ../ refs, all references/ links resolve, no orphans
✓ heygen-video:  no ../ refs, all references/ links resolve, no orphans

# update-check.sh from inside installed bundle:
$ HEYGEN_SKILLS_STATE=/tmp/x bash heygen-video/scripts/update-check.sh --force
UPGRADE_AVAILABLE 2.3.0 2.3.1

Codex plugin manifest's "skills": "./" still discovers both subdirs via the */SKILL.md agentskills.io convention. Cursor + Claude Code plugin manifests are unaffected (they reference ./heygen-avatar/ and ./heygen-video/ explicitly).

Breaking change

Direct-clone consumers who had root SKILL.md cached lose access to the meta-router skill. Contents migrated into both per-skill SKILL.md files so the skills remain fully functional standalone — git pull picks up the new layout cleanly. Bumping minor (2.3.x → 2.4.0) is appropriate; release-please will handle the actual version bump on merge.

Sequencing

This is the architectural follow-up Ken signed off in Slack right after merging #77. Sequencing matters because:

…dependent

Two skills, two bundles, no shared root. Each skill owns its references
and ships independently to gh skill install / ClawHub / OpenClaw plugin /
direct git clone.

Migrations into per-skill SKILL.md before deleting root:

heygen-avatar/SKILL.md: + Files & Paths, Language Awareness, UX Rules
heygen-video/SKILL.md:  + Files & Paths, UX Rules, Language Awareness,
                        First Look (first-run avatar check), v3-only
                        warning banner

Deleted (1940 lines):
- SKILL.md (the root meta-skill)
- references/ (the canonical shared references — each skill now owns its copy)
- scripts/sync-references.sh + scripts/update-check.sh (no longer needed
  at root; heygen-video/scripts/update-check.sh is the live copy)

Updated peripherals:
- INSTALL_FOR_AGENTS.md: drop root SKILL.md from canonical URLs and
  rewrite mode-detection-ladder pointers to per-skill SKILL.md
- CLAUDE.md: rewrite Architecture diagram + 300-line rule pointers,
  add explicit note that drift between skills is acceptable
- CONTRIBUTING.md: drop sync-references.sh editor checklist + section,
  replace with simpler "edit the skill that owns the file" guidance
- release-please-config.json: drop root SKILL.md from extra-files
- validate-skills.yml: drop references-in-sync job, drop root path
  triggers, add per-skill ../ check on the in-tree references/ dirs
  to catch parent-dir paths before install

Verified empirically (gh 2.91.0):
- gh skill install heygen-com/skills heygen-{avatar,video} --from-local
  produces fully self-contained bundles
- Codex plugin manifest "skills": "./" still discovers both subdirs via
  */SKILL.md convention
- update-check.sh (heygen-video/scripts/) reads version from frontmatter
  fallback when no repo-root VERSION is reachable
- No orphans, no broken references, no parent-dir paths

BREAKING CHANGE: Direct-clone consumers who cached root SKILL.md
will lose access to the meta-router skill. Contents migrated into both
heygen-avatar/SKILL.md and heygen-video/SKILL.md so the skills remain
fully functional standalone. Re-clone or git pull picks up the new layout.
@eve-builds eve-builds requested a review from kenchung as a code owner April 27, 2026 23:04
Copy link
Copy Markdown
Contributor

@kenchung kenchung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve

feat!: eliminate root SKILL.md + root references/ — verified at 6c45464. Architecture is now: 2 fully self-contained skills, no shared root state.

Verified Evidence
Root SKILL.md deleted -292 lines
Root references/ (9 files) deleted -1450 lines
Root scripts/sync-references.sh deleted (Option B — no sync gate) -107 lines
Root scripts/update-check.sh deleted; copy in heygen-video/scripts/ retained (6043 bytes confirmed at head) heygen-avatar doesn't reference scripts, so no copy needed there
heygen-avatar/SKILL.md self-contained All references/ paths sibling-relative, zero ../ (lines 241, 270, 453)
heygen-video/SKILL.md self-contained All references/ paths + scripts/update-check.sh sibling-relative, zero ../ (lines 37, 133, 186, 377, 483, 497, 498, 499, 562, 666)
release-please-config.json extra-files: only sub-skill SKILL.md files Root SKILL.md entry removed
INSTALL_FOR_AGENTS.md no longer cites root SKILL.md raw URL Diff confirms removal
validate-skills.yml drops references-in-sync job + root path triggers Workflow simplified
CLAUDE.md architecture diagram updated, drift-between-skills note added

Migrated meta-content

  • heygen-avatar/SKILL.md (+33 lines): Files & Paths, Language Awareness, UX Rules adapted for avatar.
  • heygen-video/SKILL.md (+51 lines): v3-only STOP banner, Files & Paths, full UX Rules, Language Awareness, First Look (first-run avatar check + readiness gate).

Worth calling out (good)

  • Net -1856 lines. Genuine simplification.
  • Both skills install cleanly via gh skill install (CI green on self-containment + advisory spec validation).
  • Codex plugin manifest's "skills": "./" still discovers both subdirs via */SKILL.md convention — verified earlier in this PR series.
  • feat!: correctly signals breaking change; release-please will bump 2.3.x → 2.4.0 on merge.

Minor follow-up (non-blocking)

  • Direct-clone consumers with cached root SKILL.md lose the meta-router. Migration is documented but worth surfacing in CHANGELOG / release notes.

Good to merge.

@kenchung kenchung merged commit d70bfc4 into master Apr 27, 2026
3 checks passed
@kenchung kenchung deleted the feat/eliminate-root-skill-md branch April 27, 2026 23:13
@github-actions github-actions Bot mentioned this pull request Apr 27, 2026
eve-builds added a commit that referenced this pull request May 13, 2026
* feat: add heygen-translate skill (video translation / dubbing)

Adds a third skill, heygen-translate/, for translating and dubbing existing
videos into 175+ languages with voice cloning and lip-sync. Built on the
same independent-skill structure as heygen-avatar and heygen-video.

What:
- heygen-translate/SKILL.md (4-phase workflow: Discovery → Pre-flight →
  Submit+Poll → Deliver) with the same API Mode Detection ladder as
  heygen-video (OpenClaw plugin → CLI w/ HEYGEN_API_KEY → MCP → CLI
  fallback). All operations shown with MCP and CLI side-by-side, no raw
  curl.
- heygen-translate/references/troubleshooting.md (errors → action map,
  polling patterns, harness-specific notes for Claude Code / OpenClaw /
  Cursor)
- heygen-translate/references/language-locale-guide.md (regional variant
  defaults, formality registers, RTL caption collisions, tonal
  compression/expansion table, lip-sync ceiling per language)
- heygen-translate/references/proofreads-workflow.md (the high-stakes
  review-edit-render path: extract SRT → glossary discipline → register
  fixes → upload edited SRT → final render)
- heygen-translate/references/asset-routing.md (URL vs asset_id vs local
  upload routing, HEAD-check pattern, auth-walled URL fallbacks, 32 MB
  limit handling)

Replaces PR #46 with the new repo structure (independent skills, no root
SKILL.md, references inside the skill, validate-skills.yml self-contained
checks, MCP+CLI transport not raw API).

Why:
- PR #46's SKILL.md frontmatter declared 'allowed-tools: mcp__heygen__*'
  but every example used raw curl against api.heygen.com. Mismatch fixed
  here by using the heygen video-translate CLI (with MCP fallthrough)
  per the established pattern in heygen-avatar/heygen-video.
- PR #46 was authored against the pre-#79 structure (root SKILL.md +
  shared references/). Repo restructured 24h ago — each skill now owns
  its own SKILL.md and references/. This PR matches.
- PR #46 lacked embedded translation expertise. This SKILL.md adds:
  speaker-count discipline, source-quality triage, locale-pair gotchas
  (formality registers in ja/ko/de/th/hi, RTL caption collisions,
  tonal compression for en→zh/ja/ko, regional variants for es/pt/zh),
  lip-sync ceiling, captions burned-in vs sidecar, audio-only as a
  different deliverable not a workaround, cost/time math, and a
  failure-mode decoder.
- PR #46 used 'video-translate/' breaking the heygen-avatar/heygen-video
  prefix pattern. Renamed to 'heygen-translate/' for consistency in ls
  output and plugin manifest paths.
- Adds a true proofreads workflow (extract SRT → user/agent edits →
  upload corrected SRT → render) — this is the missing high-stakes path
  that distinguishes the skill from API docs.

Plumbing:
- .claude-plugin/marketplace.json registers heygen:translate
- .claude-plugin/plugin.json updates description + keywords
- .codex-plugin/plugin.json updates description, keywords, longDescription,
  defaultPrompt
- .cursor-plugin/plugin.json adds heygen-translate to skills array, plus
  keywords/tags
- .github/workflows/validate-skills.yml adds heygen-translate to path
  filter and runs the same self-contained-bundle checks as the other two
  skills
- release-please-config.json adds heygen-translate/SKILL.md as a
  release-please extra-files target so the version bumps in lockstep
- README.md, INSTALL.md, INSTALL_FOR_AGENTS.md, CLAUDE.md, CONTRIBUTING.md
  all updated to reference the third skill

Out of scope (followups):
- platforms/nanoclaw/heygen-translate/ NanoClaw container variant
- Eval scenarios for heygen-translate (mirror of R17-R23 pattern from
  heygen-video)
- gh skill / agentskills.io spec compliance check (handled by the
  spec-validate-soft job already in validate-skills.yml)
- Mark PR #46 as superseded once this lands

Refs: PR #46 (predecessor), #79 (independent-skills restructure), #77
(gh skill install path)

* docs(heygen-translate): document what the proofread CLI actually performs

Per Ken's ask in #tmp-vt-skill: rewrite proofreads-workflow.md (and the
Phase 3 proofread snippet in SKILL.md) against verified live behavior of
the heygen video-translate proofreads commands, not assumed/inferred
behavior.

Verified against the live API + CLI on Apr 27 with two real proofread
sessions (b84c8e8d... silent-source failure, 8ce0fba6c... Spanish
Sintel-trailer success).

Now documented:

- Five subcommands mapped to real REST endpoints:
    create     POST /v3/video-translations/proofreads
    get        GET  /v3/video-translations/proofreads/{id}
    srt get    GET  /v3/video-translations/proofreads/{id}/srt
    srt update PUT  /v3/video-translations/proofreads/{id}/srt
    generate   POST /v3/video-translations/proofreads/{id}/generate
- What the engine actually does between create and completed (downloads
  source, runs ASR for original_srt_url, translates to srt_url, no
  render yet).
- Real response shapes for create / get / srt get / srt update / generate
  with verified JSON examples and field-by-field meanings.
- Real status enum: processing | completed | failed (NOT pending|running
  — that's the translation-render endpoint, which is a different state
  machine the resource graduates into after generate).
- Polling cadence verified empirically: 3-5 min for SRT extraction on a
  50-second source. Hard timeout 30 min for stuck sessions.
- SRT format: standard SRT (UTF-8), well-formed timecodes, editable by
  hand or sed.
- File naming: <title>_proofread.srt and <title>_proofread_original.srt.
- original_srt_url is auto-populated source-language transcription, not
  a copy of any user-provided SRT. Useful as ground truth, never
  re-uploaded as target-language SRT.

Critical correction: heygen asset create does NOT accept SRT files.

The CLI exposes both URL and asset_id shapes for srt update, but the
asset_id upload path is currently BLOCKED:

    {"error":{"code":"invalid_parameter",
              "message":"Content type not supported application/x-subrip"}}

heygen asset create only accepts png/jpeg/mp4/webm/mp3/wav/pdf.
Renaming .srt to .txt or .mp3 does not bypass it (server sniffs content,
not extension). The asset_id route is in the request schema for forward
compatibility but cannot currently be exercised through the standard
upload path.

Use the URL route. The reference now documents practical hosts that
work (gist raw URLs, GitHub raw URLs, S3 public-read, presigned
URLs >=2h, Vercel/static).

Two new failure_message strings added to troubleshooting.md from real
API responses:
- 'Failed to download video from url, please check the url is valid or
   the video is public' (instant-fail on bad/auth-walled source URL)
- 'Your video's audio is missing or corrupted, please try with another
   video' (~30s fail when source has no speech)

Other documented quirks:
- proofreads create returns proofread_ids (plural, one per language)
  plus a session-level status — per-id status comes from proofreads get.
- After generate, polling shifts from proofreads get to
  video-translate get because the resource graduates from proofread
  to translation.
- Captions on generate are independent of the proofread session's SRT —
  --captions controls whether the FINAL video burns captions in.
- Proofread session TTL ~24h.

Out of scope for this commit (still in followup queue):
- NanoClaw platform variant
- Eval scenarios for heygen-translate
- File issue/PR upstream re: SRT asset upload (worth surfacing to HeyGen
  CLI team — the asset_id route in the schema can't be reached today)

* fix(heygen-translate): auth gate, duration question, open-ended language input

Three improvements from dogfooding:

- Add auth verification step before Phase 1: runs `heygen auth status` in CLI
  mode, asks for API key and persists via `heygen auth login` if missing.
  One-time setup that survives across sessions.
- Add duration flexibility question to Phase 1 discovery: asks whether output
  must match source length, explains quality tradeoff, controls
  `enable_dynamic_duration` flag instead of hardcoding true.
- Make target language question explicitly open-ended: no picker, no
  pre-assigned choices. User types freely, validation in Phase 2.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(heygen-translate): align dynamic_duration references with Phase 1 question

SKILL.md:335 and references/language-locale-guide.md:49 both said "Always
enable_dynamic_duration: true", contradicting the new Phase 1 duration
flexibility question. Updated both to reference the user's choice and warn
about quality degradation on high-compression pairs when fixed-length is chosen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: David Chou <david.chou@heygen.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants