Hatch Pet

SkillMedia

Lets your agent turn character art or screenshots into animated pet spritesheets it can validate and preview.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Hatch Pet skill

About this capability

Create, repair, validate, visually QA, and package Codex-compatible animated pets and pet spritesheets from character art, generated images, company or prospect brand cues, or visual references. Use when a user wants a lightweight-worker Codex pet workflow, a non-pixel custom pet style, a prospect o

What this skill tells your AI

The instructions your AI receives, as published by openai/skills in skills/.curated/hatch-pet/SKILL.md and read by ahel’s review.

Overview

Create a Codex-compatible animated pet from a concept, brand cue, company/prospect name, one or more reference images, or any combination of those inputs. This workflow keeps the deterministic hatch-pet pipeline for atlas geometry, validation, visual QA, and packaging, while using concise state-specific prompts and allowing any pet-safe visual style.

User-facing inputs are optional. If the user omits a pet name, infer one from the concept, brand, company, or reference filenames; if that is not possible, choose a short friendly name. If the user omits a description, infer one from the concept or references. If the user omits reference images, generate the base pet from text first, then use that base as the canonical reference for every animation row.

Generation Delegation

Use $imagegen for all normal visual generation.

Before generating base art, row strips, or repair rows, load and follow the installed image generation skill:

${CODEX_HOME:-$HOME/.codex}/skills/.system/imagegen/SKILL.md

Do not call the Image API, image CLI, or any other image-generation path directly. Let $imagegen choose its own built-in-first path and fallback rules. If $imagegen says a fallback requires confirmation, ask the user before continuing.

When invoking $imagegen, pass the generated pet prompt as the authoritative visual spec. Pet prompts should stay concise, state-specific, sprite-production oriented, and grounded in the listed input images. Keep longer policy and QA rules in this skill and the deterministic review scripts rather than expanding them into every image prompt. Do not wrap prompts in the generic $imagegen shared prompt schema.

Use this skill's scripts for deterministic image work only: preparing layout guides and prompts, mirroring approved running-left, extracting frames, validating rows, composing the final atlas, and creating contact-sheet plus motion-preview QA media. Parent-owned shell/jq steps handle manifest updates, packaging, and cleanup.

Storage Controls

The built-in $imagegen path stores generated PNG bytes in the rollout that invokes it, even when it also writes a file under ${CODEX_HOME:-$HOME/.codex}/generated_images. Deleting files later reduces filesystem use, but it does not shrink an already-written rollout. Keep image generation isolated and bounded:

  • Use one lightweight generation worker per visual job. Do not batch multiple base/row jobs into the same worker.
  • Workers must return only selected_source=... and qa_note=...; they must not include Markdown image previews, base64, or extra visual attachments in their final response.
  • The parent must not open every generated PNG visually. Use worker QA for each job and inspect only the final contact sheet.
  • After copying the selected generated output into decoded/, remove the selected original from ${CODEX_HOME:-$HOME/.codex}/generated_images when it lives there, then remove its now-empty generation directory if possible.
  • For storage-sensitive full runs, ask the user whether to use the $imagegen CLI fallback when available. That path requires local API credentials and explicit user confirmation, but it can avoid built-in image payloads being embedded in rollout events.

Brand Discovery

If the user provides a brand, company, product, or prospect name rather than a concrete avatar description or reference image, run a lightweight discovery subagent before preparing the pet run. The discovery worker must use web search and prefer official sources such as the brand site, product pages, docs, about pages, press pages, or brand pages. Use reputable secondary sources only when official pages are too thin. Keep the search narrow: enough to extract visual and personality cues, not a market-research brief.

Skip discovery when the user already provides a concrete mascot/avatar description or reference images, unless the user explicitly asks for brand research.

Discovery worker responsibilities:

  • search the web for 2-4 relevant sources, preferring official pages
  • write an adaptive markdown brief rather than a rigid field dump
  • cover identity/category, audience/use context, visual system, personality/tone, product/domain motifs, mascot translation cues, avoidances, and evidence/confidence
  • mark mascot guidance that is inferred from sources as inference
  • avoid copying logos, readable marks, UI screenshots, slogans, or text
  • end with a compact Generation handoff section containing only brand_name, brand_brief, avatar_seed, avoid, and brand_sources
  • do not generate images, prepare run folders, or edit unrelated files

Use this discovery worker prompt:

Research a brand for hatch-pet mascot creation.

Brand/product/prospect: <brand name>
User context: <short user request>
Output file: <absolute path to brand-discovery.md>

Use web search. Prefer official brand, product, docs, about, press, or brand pages. Use reputable secondary sources only if official sources are too thin. Write an adaptive markdown brief to the output file. Headings may flex by brand, but the brief must cover:
- identity/category: canonical name, product type, what it does
- audience/use context: who it serves and where it appears
- visual system: palette, shapes, line quality, materials, typography feel, iconography, patterns
- personality/tone: emotional traits, energy, formality, playfulness
- product/domain motifs: objects, workflows, verbs, metaphors, environments
- mascot translation cues: candidate forms, signature traits, props, what must read at pet size
- avoidances: logos/text, trademark-sensitive elements, misleading cues, competitor confusion, poor mascot fits
- evidence/confidence: source URLs plus notes where evidence is weak or inferred

Do not copy logos, readable marks, UI screenshots, slogans, or text. Clearly label mascot guidance that is inferred rather than directly sourced.

End the brief with a `Generation handoff` section containing exactly:
- brand_name=<canonical brand/product name>
- brand_brief=<one sentence, max 45 words, covering palette/tone/domain motifs/personality>
- avatar_seed=<short mascot-safe visual idea, no logo copying>
- avoid=<short comma-separated list>
- brand_sources=<comma-separated source URLs>

Return exactly:
brand_discovery_file=<absolute output file path>
brand_name=<canonical brand/product name>
brand_brief=<same compact sentence from Generation handoff>
avatar_seed=<same short seed from Generation handoff>
avoid=<same short avoid list from Generation handoff>
brand_sources=<same comma-separated URLs from Generation handoff>

The parent should save the markdown brief before preparing the run, then pass it to prepare_pet_run.py as --brand-discovery-file together with --brand-name, --brand-brief, repeated --brand-source, and a concise --pet-notes value based on avatar_seed when the user did not provide a better avatar description. Keep the full brief for review; only the compact handoff fields should shape prompts. If web search is unavailable and the user gave only a bare brand name, ask for brand cues before generating.

For a normal pet run, expect up to 10 visual generation jobs: 1 base pet plus 9 row-strip jobs. The Codex app contract currently uses all 9 states: idle, running-right, running-left, waving, jumping, failed, waiting, running, and review. The only deterministic visual derivation is running-left, which may be produced by mirroring running-right only after running-right has been generated, visually inspected, and explicitly approved as safe to mirror. If mirroring is not appropriate, generate running-left as a normal grounded $imagegen row.

After selecting a visual output, the parent agent copies that exact image into the job's decoded/ path and marks the job complete in imagegen-jobs.json. Do not write helper scripts that populate row outputs. The deterministic Python scripts may only process already-generated visual outputs.

Only the base job may be prompt-only. Every row-strip job generated through $imagegen must use the input images listed in imagegen-jobs.json, including the canonical base reference created after the selected base output is copied. Treat any row generation without attached grounding images as invalid.

Pet-Safe Styles

Default style is auto: infer the pet's style from the user's prompt and references, then preserve that style across every row. If the user names a style, honor it. Supported style presets include pixel, plush, clay, sticker, flat-vector, 3d-toy, painterly, brand-inspired, and auto.

Any style is acceptable when it remains pet-safe:

  • compact whole-body silhouette readable inside a 192x208 cell
  • consistent face, proportions, material, palette, and props across all rows
  • clean removable chroma-key background
  • details large enough to read at pet size
  • no text, labels, UI, or readable logos unless the user explicitly provides approved reference art and asks for them

Non-pixel styles are first-class. Plush, clay, sticker, vector, 3D toy, painterly mascot, ink, and brand-inspired looks should be accepted when they satisfy the atlas and readability constraints.

Transparency And Effects

Pet rows are processed into transparent 192x208 cells, so every generated pixel must either belong to the pet sprite or be cleanly removable chroma-key background. Prefer pose, expression, and silhouette changes over decorative effects.

The deterministic raster pipeline owns the transparency invariant: pixels that become fully transparent are normalized so they do not retain hidden RGB residue, and atlas validation should fail if exported files violate that invariant. Do not paper over colored halos or transparent-pixel residue by accepting visually inconsistent outputs.

Allowed effects must satisfy all of these conditions:

  • The effect is state-relevant and helps explain the animation.
  • The effect is physically attached to, touching, or overlapping the pet silhouette, not floating nearby.
  • The effect is inside the same frame slot as the pet and does not create a separate sprite component.
  • The effect is opaque, hard-edged enough for clean extraction, and uses non-chroma-key colors.
  • The effect is small enough to remain readable at 192x208 without clutter.

Avoid these by default because they usually break transparent-background cleanup or component extraction:

  • wave marks, motion arcs, speed lines, action streaks, afterimages, blur, or smears
  • detached stars, loose sparkles, floating punctuation, floating icons, falling tear drops, separated smoke clouds, or loose dust
  • cast shadows, contact shadows, drop shadows, oval floor shadows, floor patches, landing marks, impact bursts, glow, halo, aura, or soft transparent effects
  • text, labels, frame numbers, visible grids, guide marks, speech bubbles, thought bubbles, UI panels, code snippets, checkerboard transparency, white backgrounds, black backgrounds, or scenery
  • chroma-key-adjacent colors in the pet, prop, effects, highlights, or shadows
  • stray pixels, disconnected outline bits, speckle/noise, cropped body parts, overlapping poses, or any pose that crosses into a neighboring frame slot

State-specific guidance:

  • idle: keep this calm and low-distraction. Use only subtle breathing, a tiny blink, a slight head or body bob, a very small material sway, or another quiet persona-preserving motion. The loop must still contain visible micro-variation; do not accept six effectively identical copies. Do not show waving, walking, running, jumping, talking, working, reviewing, emotional reactions, large gestures, item interactions, or new props.
  • waving: show the wave through paw, hand, wing, or limb pose only. Do not draw wave marks, motion arcs, lines, sparkles, symbols, or floating effects around the gesture.
  • jumping: show vertical motion through body position only. Do not draw shadows, dust, landing marks, impact bursts, bounce pads, or floor cues.
  • failed: tears, attached smoke puffs, or attached stars are allowed if they obey the allowed-effects rules; do not use red X marks, floating symbols, detached smoke, detached stars, or separate tear droplets.
  • waiting: show that Codex needs approval, help, or user input through an expectant asking pose. Keep it distinct from ordinary idle and review.
  • running: show active task work, processing, thinking, scanning, typing, or focused effort. Do not show literal foot-running, jogging, sprinting, treadmill motion, raised knees, long steps, pumping arms, directional travel, speed lines, dust clouds, floor shadows, motion trails, or detached motion effects.
  • review: show focus through lean, blink, eyes, head tilt, or paw/hand position. Do not add magnifying glasses, papers, code, UI, punctuation, symbols, or other new props unless they already exist in the base pet identity.
  • running-right and running-left: show directional drag movement through body, limb, and prop movement only. running-right must face and travel right; running-left must face and travel left. Their cadence must visibly alternate across the loop rather than repeating one nearly static stride. Do not draw speed lines, dust clouds, floor shadows, motion trails, or detached motion effects.

Visible Progress Plan

For every pet run, keep a visible checklist so the user can see where the work is up to. Create the checklist before starting, keep one step active at a time, and update it as each step finishes.

Use this checklist for a normal pet run, replacing <Pet> with the pet's name or your pet:

  1. Getting <Pet> ready.
  2. Imagining <Pet>'s main look.
  3. Picturing <Pet>'s poses.
  4. Hatching <Pet>.

What each step means:

  • Getting <Pet> ready. Choose or confirm the pet name, description, source images, style preset, style notes, and working folder. For bare brand/product/company requests, first run the brand discovery worker and capture the compact brand brief, source URLs, and avatar seed.
  • Imagining <Pet>'s main look. Generate the pet's main reference image. This becomes the visual source of truth.
  • Picturing <Pet>'s poses. Generate pose rows through lightweight workers, starting with idle and running-right to confirm identity and gait. Only mirror running-left if running-right clearly works when flipped.
  • Hatching <Pet>. Turn the approved poses into final pet files, review the contact sheet, previews, and validation results, fix any broken parts, save pet.json and spritesheet.webp, then report the output paths.

Only mark a step complete when the real file, image, or decision exists. If this is a repair run, start from the first relevant step instead of restarting the whole checklist.

Default Workflow

  1. Prepare a pet run folder and imagegen job manifest:
SKILL_DIR="${CODEX_HOME:-$HOME/.codex}/skills/hatch-pet"
python "$SKILL_DIR/scripts/prepare_pet_run.py" \
  --pet-name "<Name>" \
  --description "<one sentence>" \
  --reference /absolute/path/to/reference.png \
  --output-dir /absolute/path/to/run \
  --pet-notes "<stable pet description>" \
  --brand-discovery-file /absolute/path/to/brand-discovery.md \
  --brand-name "<optional researched brand name>" \
  --brand-brief "<optional compact researched brand cue sentence>" \
  --brand-source "https://example.com/source" \
  --style-preset auto \
  --style-notes "<optional freeform style notes>" \
  --force

All arguments above are optional except any flags needed to express user constraints. For text-only requests, pass the concept through --pet-notes and omit --reference; prepare_pet_run.py will infer a name, description, chroma key, and output directory as needed. For brand-only requests, run the discovery worker first, save the markdown brief, then pass the brief path through --brand-discovery-file, avatar_seed through --pet-notes, brand_name through --brand-name, brand_brief through --brand-brief, and each source URL through repeated --brand-source.

  1. Inspect imagegen-jobs.json for the next ready $imagegen jobs. A job is ready when its status is not complete and every id in depends_on is already complete. Prefer reading the manifest directly with jq or the editor instead of adding helper scripts for status display:
jq '.jobs[] | {id, kind, status, depends_on, prompt_file, retry_prompt_file, input_images, output_path, derivation_policy}' /absolute/path/to/run/imagegen-jobs.json
  1. Generate visual jobs with lightweight workers by default:
  • Generate and copy base first, using a lightweight base worker.
  • Generate and copy idle and running-right next as the identity and gait check, using one lightweight worker per row.
  • Inspect running-right; mirror running-left only when visual identity, prop placement, markings, lighting, and direction semantics remain correct.
  • Generate running-left normally with a lightweight worker when mirroring would change meaning or identity.
  • Generate the remaining rows with lightweight workers, using every input image listed for each job.

For each ready visual job, invoke $imagegen with the prompt file listed in imagegen-jobs.json, every listed input image with its role label, and the default built-in image_gen path unless $imagegen itself routes otherwise. The parent agent must keep its own image handling minimal: do not open every generated base or row in the parent rollout. Workers return only the selected source path and a one-sentence QA note; the parent records the selected source path in the manifest.

prepare_pet_run.py creates 9 row-specific layout guide images under references/layout-guides/, one per animation state. Row jobs attach the matching guide as a layout-only input so the model can follow the correct frame count, spacing, centering, and safe padding. Treat these guides as invisible construction references: the generated row strip must not include visible boxes, borders, center marks, labels, guide colors, or the guide background.

When generating row strips, keep the identity lock in the row prompt authoritative. Preserve the same style, face, markings, palette, materials, prop design, body proportions, and silhouette from the canonical base. Row jobs attach the layout guide and canonical base by default; the decoded base is kept in the run folder for deterministic processing rather than sent as a redundant generation input.

If $imagegen returns a transport-level Bad Request for a row, retry that same row once with its generated retry_prompt_file. The retry prompt preserves the row id, frame count, chroma key, canonical-base identity, and state action. Keep the canonical base attached. If the retry still fails, stop and report the failing row and prompt paths instead of switching to any other generation path.

  1. After selecting a generated output for a job, copy it into the decoded output path and mark the job complete. For base, also create the canonical identity reference:
RUN_DIR=/absolute/path/to/run
JOB_ID=<job-id>
SOURCE=/absolute/path/to/generated-output.png
OUTPUT_REL=$(jq -r --arg id "$JOB_ID" '.jobs[] | select(.id == $id) | .output_path' "$RUN_DIR/imagegen-jobs.json")
mkdir -p "$(dirname "$RUN_DIR/$OUTPUT_REL")"
cp "$SOURCE" "$RUN_DIR/$OUTPUT_REL"
if [ "$JOB_ID" = "base" ]; then mkdir -p "$RUN_DIR/references"; cp "$RUN_DIR/$OUTPUT_REL" "$RUN_DIR/references/canonical-base.png"; fi
UPDATED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
TMP_MANIFEST=$(mktemp)
jq --arg id "$JOB_ID" --arg source "$SOURCE" --arg at "$UPDATED_AT" '(.jobs[] | select(.id == $id)) += {status: "complete", source_path: $source, completed_at: $at}' "$RUN_DIR/imagegen-jobs.json" > "$TMP_MANIFEST"
mv "$TMP_MANIFEST" "$RUN_DIR/imagegen-jobs.json"

If the copied source is under ${CODEX_HOME:-$HOME/.codex}/generated_images, delete the original generated file after the decoded copy exists:

GENERATED_ROOT="${CODEX_HOME:-$HOME/.codex}/generated_images"
case "$SOURCE" in
  "$GENERATED_ROOT"/*)
    rm -f "$SOURCE"
    rmdir "$(dirname "$SOURCE")" 2>/dev/null || true
    ;;
esac
  1. Derive running-left only when it is visually safe:
python "$SKILL_DIR/scripts/derive_running_left_from_running_right.py" \
  --run-dir /absolute/path/to/run \
  --confirm-appropriate-mirror \
  --decision-note "<why mirroring preserves this pet's identity>"

That script mirrors each generated frame slot in place so the leftward row preserves the rightward row's temporal order. Do not replace it with a whole-strip mirror that reverses animation timing.

  1. When all jobs are complete, run the image-processing scripts directly:
RUN_DIR=/absolute/path/to/run
mkdir -p "$RUN_DIR/final" "$RUN_DIR/qa"
python "$SKILL_DIR/scripts/extract_strip_frames.py" \
  --decoded-dir "$RUN_DIR/decoded" \
  --output-dir "$RUN_DIR/frames" \
  --states all \
  --method auto
python "$SKILL_DIR/scripts/inspect_frames.py" \
  --frames-root "$RUN_DIR/frames" \
  --json-out "$RUN_DIR/qa/review.json" \
  --require-components
python "$SKILL_DIR/scripts/compose_atlas.py" \
  --frames-root "$RUN_DIR/frames" \
  --output "$RUN_DIR/final/spritesheet.png" \
  --webp-output "$RUN_DIR/final/spritesheet.webp"
python "$SKILL_DIR/scripts/validate_atlas.py" \
  "$RUN_DIR/final/spritesheet.webp" \
  --json-out "$RUN_DIR/final/validation.json"
python "$SKILL_DIR/scripts/make_contact_sheet.py" \
  "$RUN_DIR/final/spritesheet.webp" \
  --output "$RUN_DIR/qa/contact-sheet.png"
python "$SKILL_DIR/scripts/render_animation_previews.py" \
  --frames-root "$RUN_DIR/frames" \
  --output-dir "$RUN_DIR/qa/previews"

If the preview GIFs show size popping or baseline jumps caused by per-frame fit-to-cell extraction, and the original row strip itself had stable scale and placement, rerun frame extraction with the explicit row-stability mode and then re-run inspection, atlas composition, validation, contact sheet generation, and previews:

python "$SKILL_DIR/scripts/extract_strip_frames.py" \
  --decoded-dir "$RUN_DIR/decoded" \
  --output-dir "$RUN_DIR/frames" \
  --states all \
  --method stable-slots
python "$SKILL_DIR/scripts/inspect_frames.py" \
  --frames-root "$RUN_DIR/frames" \
  --json-out "$RUN_DIR/qa/review.json" \
  --require-components \
  --allow-stable-slots

Use stable-slots as a deliberate QA-driven correction, not the default. It should reduce extraction-induced motion pops without hiding clipped wide poses or bad source strips.

Expected output before cleanup:

run/
  pet_request.json
  imagegen-jobs.json
  prompts/
  decoded/
  frames/frames-manifest.json
  final/spritesheet.webp
  final/validation.json
  qa/contact-sheet.png
  qa/previews/*.gif
  qa/review.json
  qa/run-summary.json

Package output is written outside the run directory by default. If CODEX_HOME is set, use it; otherwise use $HOME/.codex.

${CODEX_HOME:-$HOME/.codex}/pets/<pet-name>/
  pet.json
  spritesheet.webp

Package with shell and jq:

RUN_DIR=/absolute/path/to/run
PET_ID=$(jq -r '.pet_id' "$RUN_DIR/pet_request.json")
DISPLAY_NAME=$(jq -r '.display_name' "$RUN_DIR/pet_request.json")
DESCRIPTION=$(jq -r '.description' "$RUN_DIR/pet_request.json")
PET_DIR="${CODEX_HOME:-$HOME/.codex}/pets/$PET_ID"
mkdir -p "$PET_DIR"
cp "$RUN_DIR/final/spritesheet.webp" "$PET_DIR/spritesheet.webp"
jq -n --arg id "$PET_ID" --arg displayName "$DISPLAY_NAME" --arg description "$DESCRIPTION" '{id: $id, displayName: $displayName, description: $description, spritesheetPath: "spritesheet.webp"}' > "$PET_DIR/pet.json"

Write qa/run-summary.json after packaging:

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
27k
Forks
2k
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
hatch-pet
Source
github.com/openai/skills