Skip to content

feat(skill-catalog): U8-5 — convert gather (declarative → context authoring guidance)#540

Merged
ericodom merged 1 commit into
mainfrom
feat/v1-u8-gather
Apr 24, 2026
Merged

feat(skill-catalog): U8-5 — convert gather (declarative → context authoring guidance)#540
ericodom merged 1 commit into
mainfrom
feat/v1-u8-gather

Conversation

@ericodom
Copy link
Copy Markdown
Contributor

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-only remains, and it's parked in the smoke-probe bucket until U6 retires composition_runner alongside it.

  • skill.yaml: execution: declarativecontext, mode: tool. Dropped invocable_from: composition (no composition runner post-U6). Version 0.1.0 → 1.0.0. Empty triggers + 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 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.

Zero production impact: 0 enabled agent_skills rows per U1 census.

U8 series status (post this PR)

State Count
done 20
composition 0
declarative 0
smoke-probe 1 (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.ts shows gather as done + composition/declarative buckets empty.

🤖 Generated with Claude Code

…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>
@ericodom ericodom merged commit bc1526c into main Apr 24, 2026
4 checks passed
@ericodom ericodom deleted the feat/v1-u8-gather branch April 24, 2026 16:36
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant