feat(ultraplan-local): M1 — profile recommendation flow in ultrabrief

Adds the profile recommendation step to /ultrabrief-local Phase 4. The
brief stays universal (same questions, same template); the new step is
purely a processing-decision layer that records which profile downstream
commands should apply.

What lands:
- agents/profile-recommender.md — new sonnet agent that scores available
  profiles against the finalized brief (keyword + NFR-signal matching,
  axis bumps, hallucination gate that forbids inventing profile names).
  Emits a fenced JSON block with ranked entries.
- templates/ultrabrief-template.md — frontmatter gains
  recommended_profile, profile_match, profile_rationale (default values
  applied when only `default` is available — true at M1).
- commands/ultrabrief-local.md — Phase 4 gains Step 4h with explicit
  branches: short-circuit when only `default` exists; AskUserQuestion
  confirmation when top score ≥ 0.7; explicit fallback message when below
  threshold; manual selection sub-question on user override. Persists the
  three frontmatter fields to brief.md after user confirmation. JSON
  parser failure falls back to `default` with `profile_match: fallback`
  rather than blocking — silent fallback is the worst outcome, but a
  *visible* fallback is acceptable.
- scripts/profile-loader.mjs — adds selectRecommendation(ranked, opts) +
  RECOMMENDATION_THRESHOLD=0.7 export. Single source of truth for the
  threshold logic so the command spec and the helper agree.
- scripts/profile-loader.test.mjs — 10 new tests for selectRecommendation
  (default-only, empty/malformed input, above/below threshold, custom
  threshold, max-by-score, missing fields). Total now 36/36.
- README.md / CLAUDE.md / marketplace landing — docs reflect M0 + M1
  shipped, M2 + M3 still pending.

In practice nothing changes for users at M1 because only `default` is
available — Step 4h takes the short-circuit path and writes
`profile_match: default-only`. M2 ships the additional profiles that
make the recommender meaningful.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-04-30 14:21:54 +02:00
commit 7e2d9e151e
8 changed files with 609 additions and 15 deletions

View file

@ -272,7 +272,7 @@ Output:
`--brief` or `--project` is **required**. `/ultraplan-local` with no brief exits with an error and a pointer to `/ultrabrief-local`.
#### Profiles (M0 — foundation)
#### Profiles (M0/M1 — foundation + recommendation flow)
A *profile* describes which exploration/review agents to spawn, which
catalog filter to apply, and which adversarial regime to use. Profiles
@ -280,13 +280,26 @@ live in `profiles/*.yaml` and are loaded via
`scripts/profile-loader.mjs` (null-deps Node, limited-subset YAML
parser, validates that every referenced agent exists).
M0 ships only the `default` profile, which mirrors the current
hardcoded Phase 5/9 agent set — so existing flows are unaffected. M1
(coming next) lets `/ultrabrief-local` recommend a profile based on
brief content; M2 ships additional built-in profiles (`quick`,
`bugfix`, `feature`, `refactor`, `security-deep`, `research-heavy`)
and replaces the hardcoded Phase 5 agent table. M3 adds
user-extensible profiles in `.claude/ultraplan-profiles/`.
M0 (shipped) introduced the loader and the `default` profile. M1
(shipped) adds the recommendation flow: `/ultrabrief-local` Phase 4
gains a Step 4h that loads available profiles, spawns the
`profile-recommender` agent (sonnet, single-shot), and writes
`recommended_profile`/`profile_match`/`profile_rationale` to the
brief frontmatter. When the top score is `≥ 0.7`, the user is asked
to confirm; otherwise the fallback to `default` is surfaced
explicitly with the option to choose manually. When only `default`
is available (still the case at M1), Step 4h short-circuits and
records `profile_match: default-only` — no AskUserQuestion.
The brief stays universal — the same questions, the same template,
no domain-specific branching. The profile is a *processing
decision* layered on top of universal data capture.
M2 (next) ships additional built-in profiles (`quick`, `bugfix`,
`feature`, `refactor`, `security-deep`, `research-heavy`) and
replaces the hardcoded Phase 5 agent table with profile-driven
selection. M3 adds user-extensible profiles in
`.claude/ultraplan-profiles/`.
```bash
# Inspect available profiles