---
reliability: 4.0 # 5 − restore (image edit) .2 − upscale .2 − gentle i2v .6 (OPTIONAL — skip it and this is a 4.6 run); caption/side-by-side deterministic; correspondence gate is the quality backstop
---

# Photo restoration + gentle animation — agent playbook

> Paste this whole file (with the BRIEF filled in) into Claude cowork, chat, or Code. The agent walks through it with you and stops for your approval at every step that matters.

## What you'll get

A complete restoration + gentle animation package from a single old family photo. This is what MyHeritage / Remini charge $14/mo for — one playbook, premium quality, plus the gentle-animation step they don't do well.

- **3-version restoration** — conservative / balanced / vivid via `kontext-edit` (+ `flux-erase` first for heavy damage). You pick the one that honors the subject. The agent doesn't decide for you.
- **Upscaled 4x master** — the chosen restoration boosted via `topaz-upscale` to print-resolution.
- **Gentle 5-second animation loop** — subtle breath, blink, and gaze movement (the "Living Memory" effect). Optional but transformative.
- **Memorial-quality caption version** — a clean lower-third with family caption text, palette-matched to the photo's era.
- **Then/now side-by-side** — the original next to the restored, divided by a thin frame. The asset everyone wants to share first.

**Time**: ~12 minutes wall clock. **Your attention**: about 3 minutes across 5 approvals. **Cost**: $0.80 – $1.80 end to end.

## Tell the agent about the photo

```yaml
photo_url:                # the original — upload via /upload first. JPG / PNG / scan all fine. Even phone-photo-of-print works. LOCAL file? Host it first: `scripts/host-local-file.sh <path>` -> use the returned public URL (auto-deletes ~2 days). See CLAUDE.md "GCS ingest".
photo_year_approx:        # roughly when was it taken? e.g. 1947 · 1962 · "early 70s" · "around 1985"
photo_subject_description: # who / what is in it. e.g. "my grandmother and her sister, standing in front of the house in Lisbon" · "Dad's first car, summer 1968"
restoration_target:       # "color restoration" (b&w → color) · "color correction" (faded color → vivid) · "scratch removal" (preserve original tone, fix damage) · "sepia preservation" (keep era tone, fix damage)
animation_style:          # "none" (no animation) · "gentle" (subtle breath + eye movement, ~5s loop) · "subtle parallax" (camera drift only, ~5s) · "memorial" (very slow, very small motion)
include_caption:          # OPTIONAL — text to overlay as a lower-third. e.g. "Maria & Conceição · Lisbon, 1947"
photo_slug:               # kebab-case, e.g. grandma-lisbon-1947
recipient_name:           # OPTIONAL — for the deliverables card, e.g. "for Mom's birthday" / "Dad's eulogy"
```

## Quality controls (new — auto-applied)

This playbook leverages the closed quality loop. The agent applies these by default; you don't have to ask:

- **Cost upfront.** Before any multi-step batch fires, the agent calls `submit_plan` with `confirm:false` and shows you the proposed steps + total cost. Nothing runs until you approve.
- **Auto-retry on weak shots.** The server default is `quality_threshold: 0.7`. For the restoration outputs the playbook step tells the agent to pass `quality_threshold: 0.85` so a low-confidence first try gets one auto-retry before you see it.
- **Critic verdict on the result.** When a multi-shot step finishes, the agent reads the `critique` field on the response (verdict: ship / iterate, plus issues / missing items) and surfaces it for your review.
- **One-click recovery.** If a step fails, `get_plan` returns a `recovery` hint pointing at `replan({plan_id})` — the agent classifies the failure and proposes a recovery plan you can approve.
- **End-of-project scorecard.** The final wrap-up calls `get_scorecard({project_id})` with succeeded count, mean quality score, critic verdict, total cost, and wall time.

You can override any of these per step: pass `quality_gate: false` on cost-sensitive tries, or `submit_plan({plan_id, confirm:true})` to skip the cost-preview pause when you trust the chain.

## The correspondence gate (read this first — non-negotiable)

Restoration is **editing the SAME photograph** — repair, colorize, upscale, gently animate. It is **never** a new generation. Every output must be unmistakably the same photo as `photo_url`: the same number of subjects, every subject's identity and face, the same composition, crop, and framing, the same left/right positions, the same props (veils, bouquets, hats, objects). The only thing that changes is the damage, the color, the resolution, or a faint motion.

Hard rules:

- **Always `action: "restyle"` (edit) with `source_url` = the original.** Never `action: "generate"` / text-to-image for a restoration step — that produces a brand-new picture of different people, which is the single worst failure mode of this playbook.
- **Chain edits off the previous edit.** Colorize takes the restored output as `source_url`; upscale takes the chosen restoration; the animation's `source_url` **must** be the restored/upscaled original, never a fresh render.
- **The verification step REJECTS on any drift of composition, crop, subject count, or identity — not only "face altered."** If the people changed, the sides swapped, the crop tightened, a subject disappeared, or a prop (bouquet, veil) went missing, the output is WRONG. Retry with a stricter preserve-prompt, or fall back to `nano-banana` / `gpt-image-edit` (strong subject preservation). Do not ship a mismatch.

## How the agent should run this (interaction contract)

1. **CONFIRM (one message, ≤1 question):** restate in 1 line ("restore <photo>, pick-of-3 → 4x print master → gentle 5s animation, ~$0.80–1.80, ~12 min") + real choices: restoration target (colorize vs correct vs scratch-fix vs sepia-preserve) · animation: none / gentle / parallax / memorial. The one question worth asking: animation or not — it's the only expensive stage.
2. **PREVIEW CHECKPOINT — the Step 1 pick-of-3 IS the gold gate.** Three restorations (~$0.60) land side-by-side and the USER picks (never the agent — it's an emotional call); nothing more expensive (upscale, animation) fires until a version passes the correspondence gate: same people, same crop, same props, faces unaltered.
3. **NARRATE:** per stage: "running 3 restorations in parallel (~3 min)…", "upscaling your pick (~2 min)…", "animating (~3 min, job …)"; poll `get_create_media` every 10–15s; never silent >2 min.
4. **FAIL GRACEFULLY:** kontext-edit drifts faces/composition → stricter preserve-prompt → `nano-banana` → `gpt-image-edit` (strongest subject preservation), ≤2 retries — NEVER fall back to `action:"generate"` (a new photo of different people is the worst failure); animation drifts mid-clip → near-zero motion prompt → `ltx-q-i2v` minimal-motion → ship un-animated with the print master (partial beats nothing).
5. **DELIVER:** master + then/now split + one honest line ("faces verified against the original; heavy-damage regions are reconstructions, not recovered detail") + ONE next step ("print the 4x master 8×10, or run the next shoebox photo").

## How this works

Five gates. The most important rule, after correspondence: **preserve faces**. Every restoration prompt explicitly tells the model not to alter facial features. People restoring old photos want their grandmother to still look like their grandmother — not "a generic 40s woman with a similar haircut."

## The steps

### Step 0 — Confirm the brief

The agent reads back the BRIEF and previews `photo_url` inline at large size so you can spot upload errors or low-resolution scans before any inference fires.

**STOP**: "Brief looks right? Photo loads at full quality? (approve / edit [field] [new value])"

### Step 1 — Three-version restoration (~3 min, ~$0.60)

The agent calls `create_media` action: `restyle`, capability: `kontext-edit`, three times in parallel — same `source_url`, three different restoration intensity prompts:

1. **Conservative** — "Restore color and clarity. **Preserve all facial features exactly.** Remove dust and scratches gently. Maintain the photograph's era and warmth. Do not romanticize or modernize."
2. **Balanced** — "Restore color and clarity. **Preserve all facial features exactly.** Remove damage. Increase contrast and sharpness moderately. Clean composition."
3. **Vivid** — "Fully restore. **Preserve all facial features exactly.** Boost color saturation, sharpen detail, clean every imperfection. Studio-quality finish."

You see all three side-by-side and pick the one that matches what the subject deserves. The agent never picks for you — this is an emotional decision.

> **For the agent**: pass `quality_threshold: 0.85` on each restoration. Use `action: "restyle"` with `kontext-edit` and `source_url` = the original — never `action: "generate"`, which would synthesize a different photo. `kontext-edit` respects source structure far better than text-to-image for restoration. When the photo has heavy localized damage (tears, big scratches, stains, a missing corner), run `flux-erase` FIRST on the damaged regions to remove + reconstruct them cleanly, THEN `kontext-edit` for tone/color — this two-pass order beats asking kontext-edit to both repair and recolor at once. Apply the **correspondence gate**: reject any version where composition, crop, subject count, left/right positions, props, or identities changed — not only "face altered." If the cap drifts, retry with a stricter preserve-prompt or fall back to `nano-banana` / `gpt-image-edit`. The "preserve all facial features exactly" clause is non-negotiable.

**STOP**: "Three versions shown. Which honors the photo? (1 conservative / 2 balanced / 3 vivid)"

### Step 2 — Upscale to print resolution (~2 min, ~$0.20)

The agent calls `topaz-upscale` (4x by default) on the chosen restoration from Step 1. Output: high-resolution master suitable for printing 8×10 or 11×14. This is the artifact that hangs on a wall.

> **For the agent**: pass `quality_threshold: 0.85`. `topaz-upscale` is the AI-based super-resolution capability — does much better on faces than naive bicubic upscaling.

**STOP**: "Upscale approved? (approve / restart from chosen version)"

### Step 3 — Gentle animation (~3 min, ~$0.40)

Only fires if `animation_style != "none"`.

The agent calls `create_media` action: `animate`, capability: `seedance-i2v` (most restrained motion; pass `resolution: "auto"`), with the upscaled restoration from Step 2 as `source_url` and a motion prompt explicitly tuned for restraint:

- **"gentle"** → "subtle breathing motion, very slow eye blink, faint hair movement from a gentle breeze, camera completely still, 5 second loop, no dramatic motion"
- **"subtle parallax"** → "no character motion. Slow gentle camera dolly forward 2cm. 5 second loop. Photographic feel."
- **"memorial"** → "almost imperceptible motion. Subject is dignified and still. Slight light shift across the face. 5 second loop."

The agent runs the chosen style and shows the result.

> **For the agent**: the animation's `source_url` **must** be the upscaled restored original from Step 2 — never a fresh render. Pass `quality_threshold: 0.75` (animation drift is acceptable here; the goal is restraint, not photo-fidelity). Extract a frame and confirm it is the same restored couple in the same composition before shipping. If any subject's face distorts during motion, the user will reject — surface the first frame next to a mid-clip frame as part of the preview so they can spot face drift before approving.

**STOP** (only if animation_style != "none"): "Animation approved? (approve / redo with [less / more] motion / skip animation)"

### Step 4 — Memorial caption version + then/now side-by-side (~2 min, ~$0.10)

**If `include_caption` is set**: the agent calls `hyperframes-lower-third` to overlay the caption text at the bottom of the upscaled restoration, palette-matched to the photo's era (sepia tones for pre-1960; muted color for 60s-80s; clean modern for newer). Font: a dignified serif. No drop shadows, no flourishes — this is memorial work.

**Then/now**: the agent calls `ffmpeg-overlay` to compose the original photo on the left and the upscaled restoration on the right, divided by a thin black frame. If a recipient_name was supplied, a small caption underneath reads "Restored {today's date} for {recipient_name}."

> **For the agent**: 1:1 composition, original left half, restored right half. The original is shown at its raw quality (don't pre-restore the "before" side — the contrast is the whole point).

**STOP**: "Caption + side-by-side approved? (approve / refine)"

### Final step — scorecard wrap-up

Call `get_scorecard({project_id: ...})` — paste output to your channel.

```
Scorecard for cjob_xxx
N/N steps shipped — critic: SHIP
Title: {photo_slug}
Steps: N/N succeeded (100%)
Quality: mean X.XX · M/N passed · K retries
Cost: $X.XX actual (est $Y.YY) · Ts wall time
Viewer: <project URL>
```

## When you're done

```
✅ Restored 4x master (printable): <URL>
✅ Memorial caption version: <URL>
✅ Animation loop (if generated): <URL>
✅ Then/now side-by-side: <URL>

Total spent: $X.XX
Total wall-clock: MM:SS
```

## What to do next

Send the then/now side-by-side first — it's the most emotionally affecting and the fastest to share. Family group chats explode for these. Print the upscaled master for a frame; gift it. Use the animation loop on memorial slideshows, anniversary posts, or in a family-history video.

Run this playbook on every photo in the shoebox. Cost per photo is $1-2, vs. professional restoration shops at $50-150 each. Save the `restoration_target` preference once and your second restoration runs in 12 minutes from upload to deliverables.

For genealogists and family historians: pair this with a brief sidebar telling the photo's story. The restored image + caption + 3-sentence history becomes a card for a family tree visualizer or a printed book.

For funeral / memorial work: the "memorial" animation style is what makes it: subtle motion that reminds the room of a loved one's quiet presence, projected on a screen during a service. Don't over-animate — the dignity is in the restraint.

---

## Notes for the agent (only read if a step fails)

**On `kontext-edit` face distortion**: the most common failure mode for restoration is the model "improving" the face into a generic version of the era. The "preserve all facial features exactly" prompt clause helps but isn't perfect. If the user rejects all three Step 1 outputs, try `nano-banana` (subject-preservation strong) as a fallback. As a last resort, ask the user for a higher-resolution scan of the original.

**Animation rejection**: if user wants animation but every attempt drifts the face, reduce the motion prompt to almost nothing ("very faint breathing, no other motion, photograph-still"). `seedance-i2v` is already the most conservative i2v; if it still drifts, try `ltx-q-i2v` with the same minimal-motion prompt.

**Photos with multiple subjects**: ask the user to confirm before Step 1 — multi-subject restoration risks one subject's face drifting while another stays sharp. Surface a per-face critic in the Step 1 verdict.
