diff --git a/RESOLVER.md b/RESOLVER.md index 9281ac7..411463e 100644 --- a/RESOLVER.md +++ b/RESOLVER.md @@ -82,6 +82,7 @@ | "recoup-internal" + account-health / account-status snapshot for a Recoup account | `recoup-internal-account-health-report` | | "recoup-internal" + audit scheduled-task email health (what tasks emailed, how many empties the guard blocked) over a window | `recoup-internal-task-email-audit` | | "recoup-internal" + draft/ship/measure LinkedIn or X posts | `recoup-internal-social-ship-posts` | +| "recoup-internal" + FaceTime-call style AI video ad (Grok Imagine 1.5 native-speech clips) | `recoup-internal-video-grok-1.5-imagine-facetime` | --- diff --git a/resolver-eval.jsonl b/resolver-eval.jsonl index 43bfb1d..49a878a 100644 --- a/resolver-eval.jsonl +++ b/resolver-eval.jsonl @@ -59,6 +59,7 @@ {"intent": "recoup-internal work the valuation funnel and advance this Attio lead", "expected": "recoup-internal-funnel-valuation-pipeline"} {"intent": "recoup-internal account health snapshot for this account", "expected": "recoup-internal-account-health-report"} {"intent": "recoup-internal draft and ship a launch post for LinkedIn and X", "expected": "recoup-internal-social-ship-posts"} +{"intent": "recoup-internal make a FaceTime-call style AI video ad with Grok Imagine", "expected": "recoup-internal-video-grok-1.5-imagine-facetime", "not": ["recoup-content-make-video"]} # --- gating invariant: WITHOUT the recoup-internal keyword, internal skills must NOT fire --- # Only the internal skills with a plausible customer-facing collision get a negative; the dev/eval diff --git a/scripts/check_resolvable.py b/scripts/check_resolvable.py index 2537be2..620d26d 100644 --- a/scripts/check_resolvable.py +++ b/scripts/check_resolvable.py @@ -25,7 +25,8 @@ DEFAULT_PLUGIN = REPO_ROOT # A skill reference in RESOLVER.md is a backtick-wrapped slug: `recoup-foo-bar`. -SKILL_TOKEN = re.compile(r"`(recoup-[a-z0-9-]+)`") +# Dots are allowed mid-slug (e.g. `recoup-internal-video-grok-1.5-imagine-facetime`). +SKILL_TOKEN = re.compile(r"`(recoup-[a-z0-9-]+(?:\.[a-z0-9-]+)*)`") def skill_dirs(plugin: Path) -> set[str]: diff --git a/scripts/run_resolver_eval.py b/scripts/run_resolver_eval.py index 3b53cea..36d77af 100644 --- a/scripts/run_resolver_eval.py +++ b/scripts/run_resolver_eval.py @@ -48,7 +48,8 @@ # Co-located with the plugin root (NOT under tests/, which is gitignored) so the # fixtures ship and CI can run them on a fresh checkout. FIXTURES = PLUGIN / "resolver-eval.jsonl" -SKILL_TOKEN = re.compile(r"`(recoup-[a-z0-9-]+)`") +# Dots are allowed mid-slug (e.g. `recoup-internal-video-grok-1.5-imagine-facetime`). +SKILL_TOKEN = re.compile(r"`(recoup-[a-z0-9-]+(?:\.[a-z0-9-]+)*)`") def skill_dirs() -> set[str]: diff --git a/skills/recoup-internal-social-ship-posts/SKILL.md b/skills/recoup-internal-social-ship-posts/SKILL.md index 290ef92..11967f5 100644 --- a/skills/recoup-internal-social-ship-posts/SKILL.md +++ b/skills/recoup-internal-social-ship-posts/SKILL.md @@ -12,7 +12,7 @@ Authenticate to the Recoup API with an `x-api-key` (`RECOUP_API_KEY`) or `Author ## The loop 1. **Learn** — pull how recent posts performed, so copy is grounded in evidence, not vibes. -2. **Draft** — write topic-first copy that fits the platform and the goal. +2. **Draft** — write topic-first copy that fits the platform, the goal, and the account's story canon. 3. **Decide the CTA** — comment-gate for leads, or direct link for reach. 4. **Publish** — via the connector where supported, or hand off for manual posting. 5. **Log & re-measure** — record what went out; re-pull performance ~48h later. @@ -65,6 +65,8 @@ Read the top performer against the flatliners and name the differences (framing, ## Step 2 — Draft +**Check the story canon first.** If the account workspace has a `NARRATIVE.md` (story bible: premise, recurring cast, storylines), read it and name **which arc and which character this post serves** before writing a word. A post that serves no arc is an ad — reframe it into the story or drop it. Serialized rules live in the canon itself (recurring catchphrases, who may be fictionalized vs. who gets only verified numbers, cliffhanger beats); follow them over generic copy instincts. If the workspace has no `NARRATIVE.md`, note that to the account owner — the account is posting without a story. + Write to the brief from step 1 plus the principles above. Structure that travels well: ``` @@ -113,7 +115,7 @@ Native video works, but the bytes can't go inline: `media` won't fetch a URL, an ## Step 5 — Log and re-measure -Record each post immediately: account, platform, the post id/URN, UTC time, the CTA used, and the copy. Then **re-pull performance ~48h later**: one bulk scrape (step 1) covers all four platforms; add `LINKEDIN_LIST_REACTIONS` only when you need reactor identities, and read gated posts' comment bodies manually. Compare week-over-week — report deltas, not all-time totals. Feed the result back into step 1 for the next post. +Record each post immediately: account, platform, the post id/URN, UTC time, the CTA used, the copy, and — when the account has a `NARRATIVE.md` — **the arc and character the post served** (continuity is what makes the next episode land; an unlogged arc breaks the serial). Then **re-pull performance ~48h later**: one bulk scrape (step 1) covers all four platforms; add `LINKEDIN_LIST_REACTIONS` only when you need reactor identities, and read gated posts' comment bodies manually. Compare week-over-week — report deltas, not all-time totals. Feed the result back into step 1 for the next post. ## Producing a demo video?