feat(skill-catalog): U8-5 — convert gather (declarative → context authoring guidance)#540
Merged
Conversation
…thoring guidance) Fifth of the U8 per-slug migration series. With this PR the declarative bucket is empty too. The only remaining U8 work is smoke-package-only, which stays parked in the smoke-probe bucket until U6 retires composition_runner alongside it. - skill.yaml: execution declarative → context, mode: tool. Dropped `invocable_from: composition` (no composition runner post-U6). Version 0.1.0 → 1.0.0. Empty triggers + requires_skills since this is pure authoring guidance, not a runnable orchestrator. - SKILL.md: rewritten as documentation for the parallel-fan-out pattern other skills reference. Describes how the model should invoke each sub-skill via Skill() when an enclosing SKILL.md says "gather in parallel" — critical vs optional semantics, error handling, output shape. Cites sales-prep v2.0.0 as a concrete example. - standalone_invocation_error message updated: gather is authoring guidance, not a runnable skill. - Audit test: done ≥ 20, composition = 0, declarative = 0, smoke-probe stays at 1. U8 series status: - done: 20 - composition: 0 - declarative: 0 - smoke-probe: 1 (smoke-package-only, blocked on U6) Zero production impact: 0 enabled agent_skills rows. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 tasks
ericodom
added a commit
that referenced
this pull request
Apr 24, 2026
…n primitives (#547) * fix(skill-catalog): bootstrap sync hardening + stale-builtin cleanup Carries forward the fixes from the still-open #544 and adds a post-upsert cleanup pass so retired builtin slugs disappear from skill_catalog on every deploy (needed because the next commit retires the composition-era primitives and leaving stale rows would let them resurface in the admin Capabilities page). * Defensive `toStringArray` helper so one authoring mistake (like the `triggers: {}` empty-map that took down #540/#542's Bootstrap) can no longer blow up the entire sync loop. * Accept `slug:` OR `id:` as the catalog key. Deliverable-shape skills use `id:` per the census convention; without this coercion sales-prep / account-health-review / renewal-prep / customer-onboarding-reconciler silently skipped the sync and never landed in skill_catalog. * Drop the dead `execution` + `mode` fields from the insert row (removed by #542's migration 0029). * After upserts, DELETE from skill_catalog WHERE source='builtin' AND slug NOT IN (<active slugs>). Tenant-uploaded rows are untouched. * feat(db): migration 0030 — retire composition-era primitive skills Deletes agent_skills, tenant_skills, and skill_catalog rows for the four composition-era primitives (frame, synthesize, gather, compound) that the pure-skill-spec rewrite retires. Adds a marker view so the db-migrate-manual drift reporter can confirm the migration applied. The YAML directories + S3 artifacts for the retired slugs are removed in the matching commits. sync-catalog-db.ts also scrubs stale builtin rows on every deploy as defense-in-depth, but this migration cleans the first-apply stage explicitly. * refactor(skill-catalog): delete composition-era primitive skills * frame — prompt/frame.md starts with "You are the frame step of a composition" * synthesize — prompt/synthesize.md starts with "You are the synthesize step of a composition" * gather — declarative-to-context stub that never actually executed anything * compound — "Learnings loop for compositions" — redundant with the container's native Hindsight recall/reflect tools All four were orchestration primitives the retired composition_runner invoked between deliverable steps. With the runner deleted in plan §U6 their SKILL.md bodies described a paradigm that no longer exists and the prompts/*.md templates were orphaned (nothing renders them post-U6). The deliverable skills that used to call Skill("frame", ...), etc. now inline the equivalent framing + synthesis guidance directly in their own SKILL.md bodies — a pure Claude-spec skill pattern with no harness-specific indirection. See the next commit. Net: 4 directories, ~1,600 LOC removed. * refactor(skill-catalog): rewrite deliverable SKILL.md as pure Claude-spec Rewrites the four deliverable-shape skill bodies (sales-prep, account-health-review, renewal-prep, customer-onboarding-reconciler) as pure Claude-spec Agent Skills — a markdown instruction doc the model reads and executes, with: * Proper frontmatter (name, description, license, metadata, allowed-tools). * Inline framing + synthesis guidance (no more Skill("frame") / Skill("synthesize") / Skill("gather") hops — the model does those natively as part of its turn). * Direct `recall` / `reflect` calls for the memory loop (Hindsight's native tools are already on the agent; no wrapper skill needed). * Only genuine tool calls remain: `Skill("package", ...)` for the deterministic template render, and the real connector Skills (crm_account_summary, web_search, etc.) for data gathering. Each deliverable's skill.yaml.requires_skills is narrowed to the actual tool-call dependencies (package + connectors) — the retired primitives drop off the session allowlist automatically. Also deletes the orphan customer-onboarding-reconciler/sub-skills/act/ sub-module; task-creation logic lives inline in the reconciler's rewritten SKILL.md now. * feat(bootstrap): S3 cleanup for retired slugs + regen every agent's workspace map Two things the deploy pipeline needs to do cleanly when a skill is retired from the catalog, neither of which it did before: 1. **Remove the retired slug's S3 prefix.** Plain `aws s3 sync` wouldn't delete objects that used to be there. The container's install_skill_from_s3 would still happily sync them onto warm runtimes on cold starts. Fix: per-slug sync is now `--delete` (so stacking stale files on a rewritten SKILL.md stops happening), and an explicit `aws s3 rm --recursive` clears frame/synthesize/gather/ compound prefixes as a belt-and-suspenders pass. 2. **Regenerate AGENTS.md for every existing agent.** The workspace-map- generator only runs on setAgentSkills mutations. When a deploy adds or retires a slug, existing agents' AGENTS.md files keep listing the old set until someone re-saves their skills. Fix: new `packages/api/scripts/regen-all-workspace-maps.ts` loops every agent and invokes regenerateWorkspaceMap. Bootstrap calls it after catalog sync. Per-agent failure is caught + logged; a single bad workspace cannot wedge the deploy. With these two steps running on every deploy, the on-disk workspace of every agent reflects the canonical skill list within one reconcile cycle — no manual intervention needed when slugs change. * test(skill-catalog): adjust u8-status expectations for the cleanup * Lower the `done` floor from 20 → 16 now that frame/synthesize/ gather/compound have been retired. * sales-prep's requires_skills assertion flips from "contains frame/synthesize/package" → "contains package, does NOT contain frame/synthesize/gather" since framing + synthesis happen inline in the rewritten SKILL.md body.
ericodom
added a commit
that referenced
this pull request
May 5, 2026
…+ id-only slugs
Two root causes for the admin Capabilities page rendering "No results"
on dev this afternoon:
1. `gather/skill.yaml` declared `triggers: {}` (empty YAML map) but the
skill_catalog.triggers column is text[]. The sync script naively
cast `(y.triggers as string[]) || []` — `{}` is truthy so the
fallback never fired, and Drizzle's PgArray.mapToDriverValue blew
up with `value.map is not a function` the first time `gather` hit
the sync loop. That tripped the Bootstrap job for #540, #542, and
every other skill-catalog PR whose deploy actually ran Bootstrap
(others skipped it via path filter and masked the regression).
2. The U8 deliverable-shape skills (sales-prep, account-health-review,
renewal-prep, customer-onboarding-reconciler) declare `id:` not
`slug:` as the catalog key, matching the census script's convention.
The sync script only looked at `slug:` and silently dropped those
four skills from skill_catalog — the admin catalog page has been
missing them since the U8 series landed.
Fix:
- `gather/skill.yaml`: `triggers: {}` → `triggers: []`.
- `sync-catalog-db.ts`: defensive `toStringArray` helper coerces
non-array values to [] so one authoring mistake can't blow up the
whole bootstrap again.
- `sync-catalog-db.ts`: accept `slug:` OR `id:` as the catalog key,
matching census.ts.
- Removes the dead `execution` + `mode` fields from the insert row
(those columns were dropped in #542's migration 0029; Drizzle was
silently ignoring them post-deploy but the comment was misleading).
ericodom
added a commit
that referenced
this pull request
May 5, 2026
…thoring guidance) (#540) Fifth of the U8 per-slug migration series. With this PR the declarative bucket is empty too. The only remaining U8 work is smoke-package-only, which stays parked in the smoke-probe bucket until U6 retires composition_runner alongside it. - skill.yaml: execution declarative → context, mode: tool. Dropped `invocable_from: composition` (no composition runner post-U6). Version 0.1.0 → 1.0.0. Empty triggers + requires_skills since this is pure authoring guidance, not a runnable orchestrator. - SKILL.md: rewritten as documentation for the parallel-fan-out pattern other skills reference. Describes how the model should invoke each sub-skill via Skill() when an enclosing SKILL.md says "gather in parallel" — critical vs optional semantics, error handling, output shape. Cites sales-prep v2.0.0 as a concrete example. - standalone_invocation_error message updated: gather is authoring guidance, not a runnable skill. - Audit test: done ≥ 20, composition = 0, declarative = 0, smoke-probe stays at 1. U8 series status: - done: 20 - composition: 0 - declarative: 0 - smoke-probe: 1 (smoke-package-only, blocked on U6) Zero production impact: 0 enabled agent_skills rows. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ericodom
added a commit
that referenced
this pull request
May 5, 2026
…n primitives (#547) * fix(skill-catalog): bootstrap sync hardening + stale-builtin cleanup Carries forward the fixes from the still-open #544 and adds a post-upsert cleanup pass so retired builtin slugs disappear from skill_catalog on every deploy (needed because the next commit retires the composition-era primitives and leaving stale rows would let them resurface in the admin Capabilities page). * Defensive `toStringArray` helper so one authoring mistake (like the `triggers: {}` empty-map that took down #540/#542's Bootstrap) can no longer blow up the entire sync loop. * Accept `slug:` OR `id:` as the catalog key. Deliverable-shape skills use `id:` per the census convention; without this coercion sales-prep / account-health-review / renewal-prep / customer-onboarding-reconciler silently skipped the sync and never landed in skill_catalog. * Drop the dead `execution` + `mode` fields from the insert row (removed by #542's migration 0029). * After upserts, DELETE from skill_catalog WHERE source='builtin' AND slug NOT IN (<active slugs>). Tenant-uploaded rows are untouched. * feat(db): migration 0030 — retire composition-era primitive skills Deletes agent_skills, tenant_skills, and skill_catalog rows for the four composition-era primitives (frame, synthesize, gather, compound) that the pure-skill-spec rewrite retires. Adds a marker view so the db-migrate-manual drift reporter can confirm the migration applied. The YAML directories + S3 artifacts for the retired slugs are removed in the matching commits. sync-catalog-db.ts also scrubs stale builtin rows on every deploy as defense-in-depth, but this migration cleans the first-apply stage explicitly. * refactor(skill-catalog): delete composition-era primitive skills * frame — prompt/frame.md starts with "You are the frame step of a composition" * synthesize — prompt/synthesize.md starts with "You are the synthesize step of a composition" * gather — declarative-to-context stub that never actually executed anything * compound — "Learnings loop for compositions" — redundant with the container's native Hindsight recall/reflect tools All four were orchestration primitives the retired composition_runner invoked between deliverable steps. With the runner deleted in plan §U6 their SKILL.md bodies described a paradigm that no longer exists and the prompts/*.md templates were orphaned (nothing renders them post-U6). The deliverable skills that used to call Skill("frame", ...), etc. now inline the equivalent framing + synthesis guidance directly in their own SKILL.md bodies — a pure Claude-spec skill pattern with no harness-specific indirection. See the next commit. Net: 4 directories, ~1,600 LOC removed. * refactor(skill-catalog): rewrite deliverable SKILL.md as pure Claude-spec Rewrites the four deliverable-shape skill bodies (sales-prep, account-health-review, renewal-prep, customer-onboarding-reconciler) as pure Claude-spec Agent Skills — a markdown instruction doc the model reads and executes, with: * Proper frontmatter (name, description, license, metadata, allowed-tools). * Inline framing + synthesis guidance (no more Skill("frame") / Skill("synthesize") / Skill("gather") hops — the model does those natively as part of its turn). * Direct `recall` / `reflect` calls for the memory loop (Hindsight's native tools are already on the agent; no wrapper skill needed). * Only genuine tool calls remain: `Skill("package", ...)` for the deterministic template render, and the real connector Skills (crm_account_summary, web_search, etc.) for data gathering. Each deliverable's skill.yaml.requires_skills is narrowed to the actual tool-call dependencies (package + connectors) — the retired primitives drop off the session allowlist automatically. Also deletes the orphan customer-onboarding-reconciler/sub-skills/act/ sub-module; task-creation logic lives inline in the reconciler's rewritten SKILL.md now. * feat(bootstrap): S3 cleanup for retired slugs + regen every agent's workspace map Two things the deploy pipeline needs to do cleanly when a skill is retired from the catalog, neither of which it did before: 1. **Remove the retired slug's S3 prefix.** Plain `aws s3 sync` wouldn't delete objects that used to be there. The container's install_skill_from_s3 would still happily sync them onto warm runtimes on cold starts. Fix: per-slug sync is now `--delete` (so stacking stale files on a rewritten SKILL.md stops happening), and an explicit `aws s3 rm --recursive` clears frame/synthesize/gather/ compound prefixes as a belt-and-suspenders pass. 2. **Regenerate AGENTS.md for every existing agent.** The workspace-map- generator only runs on setAgentSkills mutations. When a deploy adds or retires a slug, existing agents' AGENTS.md files keep listing the old set until someone re-saves their skills. Fix: new `packages/api/scripts/regen-all-workspace-maps.ts` loops every agent and invokes regenerateWorkspaceMap. Bootstrap calls it after catalog sync. Per-agent failure is caught + logged; a single bad workspace cannot wedge the deploy. With these two steps running on every deploy, the on-disk workspace of every agent reflects the canonical skill list within one reconcile cycle — no manual intervention needed when slugs change. * test(skill-catalog): adjust u8-status expectations for the cleanup * Lower the `done` floor from 20 → 16 now that frame/synthesize/ gather/compound have been retired. * sales-prep's requires_skills assertion flips from "contains frame/synthesize/package" → "contains package, does NOT contain frame/synthesize/gather" since framing + synthesis happen inline in the rewritten SKILL.md body.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fifth of the U8 per-slug migration series (prior: #534 sales-prep, #536 account-health-review, #537 customer-onboarding-reconciler, #538 renewal-prep). With this PR the declarative bucket is empty too — only
smoke-package-onlyremains, and it's parked in the smoke-probe bucket until U6 retirescomposition_runneralongside it.skill.yaml:execution: declarative→context,mode: tool. Droppedinvocable_from: composition(no composition runner post-U6). Version0.1.0 → 1.0.0. Emptytriggers+requires_skills— this is pure authoring guidance, not a runnable orchestrator.SKILL.md: rewritten as documentation for the parallel-fan-out pattern other skills reference. Describes how the model should invoke each sub-skill viaSkill()when an enclosing SKILL.md says "gather in parallel" — critical vs optional semantics, error handling, output shape. Citessales-prepv2.0.0 as a concrete example.standalone_invocation_errormessage updated:gatheris authoring guidance, not a runnable skill.done ≥ 20,composition = 0,declarative = 0, smoke-probe stays at 1.Zero production impact: 0 enabled
agent_skillsrows per U1 census.U8 series status (post this PR)
smoke-package-only, blocked on U6)U8 is effectively complete — the only remaining slug is the smoke probe for composition_runner itself, which retires alongside the runner in U6.
Test plan
pnpm --filter @thinkwork/skill-catalog test→ green (25 tests).pnpm exec tsx packages/skill-catalog/scripts/u8-status.tsshowsgatherasdone+ composition/declarative buckets empty.🤖 Generated with Claude Code