Closes mort#1522. 23% of all code_exec calls across two production runs (9 of 39) failed on gifsmith API misuse, hitting 7 of 14 workers. The recovery was always the same shape: another round trip spent printing gifsmith's own source — or, in one case, running `dir(gifsmith)` — to learn what the module contains. Three distinct causes, three fixes. **Unguessable re-exports → `__all__`, plus the two that were missing.** The module exported SOME matplotlib artists and not others, and the only way to find out which was to fail: two workers wrote `from gifsmith import PathPatch` and got an ImportError while `FancyBboxPatch` beside it worked. `PathPatch` and `Path` are now exported, on the rule "the drawing vocabulary, whole". `__all__` states the surface — and it also fixes what made self-service expensive: `dir(gifsmith)` returned 24 names of which nine were incidental imports (glob, os, shutil, subprocess, sys, traceback...), several being things a scene author should never touch. SKILL.md now carries the same list, so the question should not arise. **Near-miss constructor kwargs → an error that names the miss.** `background=` is accepted as an alias for `bg` (it is the obvious synonym, and an agent reached for it). `force=` is rejected with the reason it was tempting — `render(force="mp4")` really does take it, which makes it read like an Animation-level setting. Anything else gets a difflib near-match and the valid list. Both failures were one round trip each, and both are the kind a message fixes for free. **Scenes fail at render time → dry-run every scene at t=0 first.** A NameError in scene 4 used to surface only after scenes 0-3 were fully rendered, and with a streaming pipe open, after frames had gone into the encoder. Two workers lost a whole render each to `RuntimeError: every scene failed`, learning one broken name per attempt. One frame per scene now reports EVERY broken scene in a single pass, before any scratch dir or ffmpeg pipe exists. Per-scene isolation is preserved exactly: a scene that fails the dry run is marked and skipped rather than re-run to fail identically, the others still ship, and only an all-scenes-broken program raises early — which is precisely the case that was paying for a full setup to learn nothing. Verified against the production failures: `Animation(background=…)` now works, `Animation(force=…)` explains itself, `Animation(backgrnd=…)` suggests `background`, every name in `__all__` resolves, no incidental import leaks into it, and the dry run marks exactly the broken scenes while leaving the good ones untouched. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
executus-skills
Skill packs for executus
harnesses (mort, gadfly, …), in the SKILL.md "agent-skills" format. Each pack is
its own subfolder with a SKILL.md manifest plus any bundled helper files.
executus-skills/
gif/
SKILL.md # instructions the agent loads on demand
scripts/encode.py # bundled helper the agent runs in its sandbox
Packs
gif— make a funny animated GIF or MP4 for Discord from a description. Plans scenes, keeps recurring people/props consistent via a reusable cast, renders frames in Python, and lets a bundledencode.pypick the format: a GIF for short loops, or an H.264 MP4 (that Discord plays inline) for long bits or when a GIF comes out too big. Adapted from mort's builtinanimateskill. Handles multi-minute pieces.
Using a pack from mort
Each subfolder is a separate subscription (pinned by content digest):
.set skillpacks.enabled true # then restart mort (boot-read)
.set skillpacks.allowed_sources git:https://gitea.stevedudenhoeffer.com/steve/
.skillpack subscribe git https://gitea.stevedudenhoeffer.com/steve/executus-skills subpath=gif ref=main
Then attach the pack to an agent that already has the tools the pack uses (the
pack supplies instructions, not tools). For gif, the agent needs
code_exec, image_describe, send_attachments, file_get_metadata, and
think in its toolset, a generous max_runtime with critic_enabled: true
(long renders run for minutes), and a sandbox image with ffmpeg (plus
gifski/gifsicle for nicer GIFs). Add it in the agent's YAML:
low_level_tools: [code_exec, image_describe, send_attachments, file_get_metadata, think]
skill_packs: [gif]
When the pack is updated upstream, .skillpack check reports it and
.skillpack apply gif re-pins — nothing an agent runs changes until you apply.