Skip to content

feat: setup wizard UX -- template filters, card metadata, provider form reuse#910

Merged
Aureliolo merged 12 commits intomainfrom
feat/improve-ux-setup-wizard
Mar 29, 2026
Merged

feat: setup wizard UX -- template filters, card metadata, provider form reuse#910
Aureliolo merged 12 commits intomainfrom
feat/improve-ux-setup-wizard

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Template step: Add search/category/size filter bar, split into Recommended and Other Templates sections, show agent count, department count, autonomy level, and workflow on each card with icons
  • Provider step: Fix 0-models bug (pass probe-detected URL when creating from auto-detect), replace simplified ProviderAddForm with full ProviderFormDrawer from Settings (supports subscription auth, custom base URLs, custom providers)
  • Backend: Expand TemplateInfoResponse with agent_count, department_count, autonomy_level (now AutonomyLevel enum), workflow (now NotBlankStr); fix SetupAgentSummary field types to use proper nullable types
  • Cleanup: Delete dead ProviderAddForm.tsx, update design spec, add test coverage for new store methods

Test plan

  • uv run ruff check src/ tests/ -- passes
  • uv run mypy src/ tests/ -- passes (1232 files)
  • uv run python -m pytest tests/ -m unit -n auto -k "template or setup" -- 490 passed
  • npm --prefix web run type-check -- passes
  • npm --prefix web run lint -- passes (zero warnings)
  • npm --prefix web run test -- 1930 passed (4 new tests added)
  • Pre-commit and pre-push hooks pass

Review coverage

Pre-reviewed by 7 agents (docs-consistency, code-reviewer, frontend-reviewer, api-contract-drift, type-design-analyzer, conventions-enforcer, test-quality-reviewer). 16 findings addressed across type safety, dead code removal, a11y, design spec accuracy, and test coverage.

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 28, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2adba8bd-730b-476b-b387-ba1e5b1aa1c3

📥 Commits

Reviewing files that changed from the base of the PR and between b0456f8 and 44bb31e.

📒 Files selected for processing (1)
  • web/src/pages/setup/TemplateStep.tsx

Walkthrough

Documentation, backend, and frontend were changed to add structural template metadata (agent_count, department_count, autonomy_level, workflow) and expose templates in a searchable, filterable grid grouped into Recommended and Other. Template loader and API responses now populate those fields. Setup agent summaries allow nullable level, model_provider, and model_id. DTOs validate optional base_url. Provider creation flows and the setup store support probe-detected and manual base URLs and both full and custom creation paths. UI changes include a ProviderFormDrawer overrides prop and removal of ProviderAddForm. Tests were added and updated.

Suggested labels

autorelease: tagged

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately summarizes the main PR changes: template filters, card metadata, and provider form reuse across setup wizard.
Description check ✅ Passed Description comprehensively covers all major changes including template step UX, provider step fixes, backend type updates, and test coverage additions.
Docstring Coverage ✅ Passed Docstring coverage is 47.73% which is sufficient. The required threshold is 40.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 28, 2026 21:15 — with GitHub Actions Inactive
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 28, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 44bb31e.
Ensure that dependencies are being submitted on PR branches. Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice.

Scanned Files

None

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the setup wizard by introducing structural metadata for templates—including agent counts, department counts, autonomy levels, and workflow types—and displaying this information in the UI. The template selection step now features a searchable grid with category and size filters. Additionally, the provider setup has been refactored to use a unified form drawer, supporting both preset-based and custom provider configurations. Review feedback focuses on preventing race conditions where refreshing the provider list could inadvertently clear error messages from failed model discovery, reducing code duplication in the template loading logic, and improving the search implementation to support multi-keyword matching.

Comment on lines 90 to 92
await createProviderFromPreset(presetName, presetName, undefined, detectedUrl)
// Refresh provider list to get updated model counts
await fetchProviders()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There's a potential race condition here. If createProviderFromPreset succeeds in creating the provider but fails during the subsequent model discovery, it will set an error in the store but won't throw. This handleAddPreset function will then immediately call fetchProviders(), which clears the error state, preventing the user from seeing the discovery error message.

To fix this, you should check for an error in the store before refreshing the provider list.

      await createProviderFromPreset(presetName, presetName, undefined, detectedUrl)
      // Refresh provider list only if no error occurred during creation/discovery.
      if (!useSetupWizardStore.getState().providersError) {
        await fetchProviders()
      }

Comment on lines +108 to +117
onCreateFromPreset: async (data) => {
const result = await createProviderFromPresetFull(data)
if (result) await fetchProviders()
return result
},
[createProviderFromPreset, fetchProviders],
)
onCreateProvider: async (data) => {
const result = await createProviderCustom(data)
if (result) await fetchProviders()
return result
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to the issue in handleAddPreset, there's a race condition here. If createProviderFromPresetFull or createProviderCustom succeeds but a subsequent operation within them (like model discovery) fails and sets an error, fetchProviders() is still called, which will immediately clear the error message from the UI.

You should check for an error in the store before calling fetchProviders to ensure discovery errors are displayed to the user.

    onCreateFromPreset: async (data) => {
      const result = await createProviderFromPresetFull(data)
      if (result && !useSetupWizardStore.getState().providersError) {
        await fetchProviders()
      }
      return result
    },
    onCreateProvider: async (data) => {
      const result = await createProviderCustom(data)
      if (result && !useSetupWizardStore.getState().providersError) {
        await fetchProviders()
      }
      return result
    },

Comment on lines 134 to 146
seen[name] = TemplateInfo(
name=name,
display_name=meta.name,
description=meta.description,
source="builtin",
tags=meta.tags,
skill_patterns=meta.skill_patterns,
variables=loaded.template.variables,
variables=tmpl.variables,
agent_count=len(tmpl.agents),
department_count=len(tmpl.departments),
autonomy_level=tmpl.autonomy.get("level", "semi"),
workflow=tmpl.workflow,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve maintainability and reduce code duplication, you could extract the logic for creating a TemplateInfo instance into a helper function. This logic is repeated in _collect_user_templates on lines 167-179.

A helper function could look like this:

def _create_template_info_from_loaded(
    name: str, loaded: LoadedTemplate, source: Literal["builtin", "user"]
) -> TemplateInfo:
    meta = loaded.template.metadata
    tmpl = loaded.template
    return TemplateInfo(
        name=name,
        display_name=meta.name,
        description=meta.description,
        source=source,
        tags=meta.tags,
        skill_patterns=meta.skill_patterns,
        variables=tmpl.variables,
        agent_count=len(tmpl.agents),
        department_count=len(tmpl.departments),
        autonomy_level=tmpl.autonomy.get("level", "semi"),
        workflow=tmpl.workflow,
    )

Then you can call it here and in _collect_user_templates.

Comment on lines +181 to +184
if (query) {
const haystack = `${t.display_name} ${t.description} ${t.tags.join(' ')}`.toLowerCase()
if (!haystack.includes(query)) return false
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current search implementation performs a simple substring match. To enhance the user experience, you could improve it to support multiple keywords. For example, a search for "dev shop" should match templates that contain both "dev" and "shop".

You can achieve this by splitting the search query into keywords and checking if all of them are present in the template's searchable content.

Suggested change
if (query) {
const haystack = `${t.display_name} ${t.description} ${t.tags.join(' ')}`.toLowerCase()
if (!haystack.includes(query)) return false
}
const keywords = query.split(' ').filter(Boolean);
if (keywords.length > 0) {
const haystack = `${t.display_name} ${t.description} ${t.tags.join(' ')}`.toLowerCase()
if (!keywords.every(kw => haystack.includes(kw))) return false
}

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 28, 2026

Codecov Report

❌ Patch coverage is 83.67347% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.15%. Comparing base (81372bf) to head (44bb31e).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/synthorg/api/dto.py 75.00% 4 Missing and 2 partials ⚠️
src/synthorg/templates/loader.py 86.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #910      +/-   ##
==========================================
- Coverage   92.16%   92.15%   -0.02%     
==========================================
  Files         596      596              
  Lines       31401    31438      +37     
  Branches     3040     3043       +3     
==========================================
+ Hits        28942    28971      +29     
- Misses       1939     1945       +6     
- Partials      520      522       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/pages/setup/ProvidersStep.tsx (1)

88-95: ⚠️ Potential issue | 🟠 Major

Stop re-fetching immediately after preset-based creation.

createProviderFromPreset() / createProviderFromPresetFull() already update state.providers and may set providersError when discovery fails or still returns zero models. The immediate fetchProviders() here clears that error first, so the warning disappears before the user can see it.

✂️ Proposed fix
 const handleAddPreset = useCallback(
   async (presetName: string, detectedUrl?: string) => {
     await createProviderFromPreset(presetName, presetName, undefined, detectedUrl)
-    // Refresh provider list to get updated model counts
-    await fetchProviders()
   },
-  [createProviderFromPreset, fetchProviders],
+  [createProviderFromPreset],
 )
 
 const drawerOverrides: ProviderFormOverrides = useMemo(() => ({
   presets,
   presetsLoading,
   presetsError,
   onFetchPresets: fetchPresets,
-  onCreateFromPreset: async (data) => {
-    const result = await createProviderFromPresetFull(data)
-    if (result) await fetchProviders()
-    return result
-  },
+  onCreateFromPreset: createProviderFromPresetFull,
   onCreateProvider: async (data) => {
     const result = await createProviderCustom(data)
     if (result) await fetchProviders()
     return result
   },
 }), [presets, presetsLoading, presetsError, fetchPresets, createProviderFromPresetFull, createProviderCustom, fetchProviders])

Also applies to: 103-112

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/setup/ProvidersStep.tsx` around lines 88 - 95, The code
re-fetches providers immediately after calling
createProviderFromPreset/createProviderFromPresetFull which already update
state.providers and set providersError; this immediate await fetchProviders()
clears providersError prematurely. Remove the immediate await fetchProviders()
calls from handleAddPreset and the analogous handler (lines ~103-112) so
creation relies on the state updates returned by
createProviderFromPreset/createProviderFromPresetFull; if a forced refresh is
still required, call fetchProviders() only conditionally after those calls
succeed and providersError is falsy (e.g., based on the returned result or
state), not unconditionally.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/organization.md`:
- Around line 342-344: Update the "Providers" paragraph to explicitly state that
provider configuration supports both probe-detected (auto-detection) base URLs
and manually entered custom base URLs in addition to API key / subscription /
custom provider options; mention where this deviates from prior spec and briefly
note the rationale (e.g., support local instances and manual endpoints) so
readers know implementation details and expected behavior when auto-detection
fails or is overridden in the Providers section (refer to the existing
"Providers" text that lists auto-detection and full provider form).

In `@web/src/__tests__/stores/setup-wizard.test.ts`:
- Around line 353-396: Add a new test for the zero-model discovery path in
createProviderFromPresetFull: mock createFromPreset to resolve to a provider
object with models: [], then mock discoverModels to resolve (or resolve to a
discovered model list) and mock getProvider to return the refreshed provider
with models populated; call
useSetupWizardStore.getState().createProviderFromPresetFull(...) and assert that
discoverModels and getProvider were invoked, the function returns the refreshed
provider, useSetupWizardStore.getState().providers stores that provider under
the given name, and providersError remains null (or appropriate). Ensure you
reference createProviderFromPresetFull, createFromPreset, discoverModels,
getProvider and useSetupWizardStore.getState().providers in the test.

In `@web/src/pages/providers/ProviderFormDrawer.tsx`:
- Around line 73-81: The effect in ProviderFormDrawer re-runs whenever the
entire overrides object changes, causing duplicate preset fetches; extract the
fetch handler and depend only on that instead of the whole overrides object:
inside the component get a stable reference like const fetchPresets =
overrides?.onFetchPresets ?? useProvidersStore.getState().fetchPresets, then
update the useEffect to call fetchPresets when open && mode === 'create' and
list fetchPresets (and open, mode) in the dependency array; ensure you reference
the symbols useEffect, open, mode, overrides, onFetchPresets, and
useProvidersStore.getState().fetchPresets so the drawer open triggers only a
single presets request.

In `@web/src/stores/setup-wizard.ts`:
- Around line 634-654: After creating a provider and auto-discovering models in
the full-form path, ensure we preserve the "no models discovered" warning by
checking the refreshed provider returned by getProvider() for zero models and
setting providersError (same message as createProviderFromPreset) instead of
treating it as a clean success; refactor the post-create discovery+warning logic
used around discoverModels, getProvider and set into a shared helper (e.g.,
postCreateProviderCheck or handleProviderDiscovery) and call it from both the
full-form branch and createProviderFromPreset so the zero-model warning cannot
drift.

---

Outside diff comments:
In `@web/src/pages/setup/ProvidersStep.tsx`:
- Around line 88-95: The code re-fetches providers immediately after calling
createProviderFromPreset/createProviderFromPresetFull which already update
state.providers and set providersError; this immediate await fetchProviders()
clears providersError prematurely. Remove the immediate await fetchProviders()
calls from handleAddPreset and the analogous handler (lines ~103-112) so
creation relies on the state updates returned by
createProviderFromPreset/createProviderFromPresetFull; if a forced refresh is
still required, call fetchProviders() only conditionally after those calls
succeed and providersError is falsy (e.g., based on the returned result or
state), not unconditionally.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4bed3cb7-d9e4-4d7f-b68e-e6104ae2ecea

📥 Commits

Reviewing files that changed from the base of the PR and between ee964c4 and ff33fa8.

📒 Files selected for processing (18)
  • docs/design/organization.md
  • src/synthorg/api/controllers/setup.py
  • src/synthorg/api/controllers/setup_agents.py
  • src/synthorg/api/controllers/setup_models.py
  • src/synthorg/templates/loader.py
  • tests/unit/api/controllers/test_setup.py
  • tests/unit/templates/test_loader.py
  • web/src/__tests__/stores/setup-wizard.test.ts
  • web/src/__tests__/utils/template-categories.test.ts
  • web/src/api/types.ts
  • web/src/pages/providers/ProviderFormDrawer.tsx
  • web/src/pages/setup/ProviderAddForm.tsx
  • web/src/pages/setup/ProviderProbeResults.tsx
  • web/src/pages/setup/ProvidersStep.tsx
  • web/src/pages/setup/SetupAgentCard.tsx
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/stores/setup-wizard.ts
💤 Files with no reviewable changes (1)
  • web/src/pages/setup/ProviderAddForm.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Dashboard Test
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones. Do not recreate status dots inline, build card-with-header layouts from scratch, create metric displays manually, render initials circles manually, create complex (>8 line) JSX inside .map() blocks, or use rgba() with hardcoded values instead of design token variables.

Files:

  • web/src/pages/setup/SetupAgentCard.tsx
  • web/src/__tests__/utils/template-categories.test.ts
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/api/types.ts
  • web/src/pages/setup/ProviderProbeResults.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/__tests__/stores/setup-wizard.test.ts
  • web/src/stores/setup-wizard.ts
  • web/src/pages/providers/ProviderFormDrawer.tsx
  • web/src/pages/setup/ProvidersStep.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use design token rules: colors via Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger) or CSS variables (var(--so-accent)), typography via font-sans or font-mono, spacing via density-aware tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind, shadows/borders via token variables (var(--so-shadow-card-hover), border-border, border-bright). Never hardcode hex values, set fontFamily directly, or hardcode pixel values for layout spacing.

Files:

  • web/src/pages/setup/SetupAgentCard.tsx
  • web/src/__tests__/utils/template-categories.test.ts
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/api/types.ts
  • web/src/pages/setup/ProviderProbeResults.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/__tests__/stores/setup-wizard.test.ts
  • web/src/stores/setup-wizard.ts
  • web/src/pages/providers/ProviderFormDrawer.tsx
  • web/src/pages/setup/ProvidersStep.tsx
web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use property-based testing with fast-check (fc.assert + fc.property). Run tests with npm --prefix web run test for Vitest with --detect-async-leaks flag.

Files:

  • web/src/pages/setup/SetupAgentCard.tsx
  • web/src/__tests__/utils/template-categories.test.ts
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/api/types.ts
  • web/src/pages/setup/ProviderProbeResults.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/__tests__/stores/setup-wizard.test.ts
  • web/src/stores/setup-wizard.ts
  • web/src/pages/providers/ProviderFormDrawer.tsx
  • web/src/pages/setup/ProvidersStep.tsx
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: No from __future__ import annotations -- Python 3.14+ has PEP 649 native lazy annotations. Use except A, B: (no parentheses) per PEP 758 except syntax as enforced by ruff.
All public functions and classes require type hints and Google-style docstrings (enforced by ruff D rules). Use mypy strict mode.
Functions must be less than 50 lines, files less than 800 lines. Handle errors explicitly, never silently swallow. Validate at system boundaries (user input, external APIs, config files).

Files:

  • src/synthorg/api/controllers/setup_agents.py
  • tests/unit/templates/test_loader.py
  • tests/unit/api/controllers/test_setup.py
  • src/synthorg/api/controllers/setup.py
  • src/synthorg/templates/loader.py
  • src/synthorg/api/controllers/setup_models.py
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Every module with business logic must have: from synthorg.observability import get_logger then logger = get_logger(__name__). Use event name constants from synthorg.observability.events.<domain> modules (e.g., API_REQUEST_STARTED, TOOL_INVOKE_START). Always use structured kwargs: logger.info(EVENT, key=value). Log all error paths at WARNING or ERROR with context before raising, all state transitions at INFO, and DEBUG for object creation and key function flow. Pure data models, enums, and re-exports do not need logging.
Use immutability patterns: create new objects instead of mutating existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction plus MappingProxyType wrapping for read-only enforcement. For dict/list fields in frozen Pydantic models, use copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization).
Use Pydantic v2 models (BaseModel, model_validator, computed_field, ConfigDict). Use @computed_field for derived values instead of storing redundant fields (e.g., TokenUsage.total_tokens). Use NotBlankStr from core.types for all identifier/name fields (including optional NotBlankStr | None and tuple variants) instead of manual whitespace validators.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations (e.g., multiple tool invocations, parallel agent calls) in new code instead of bare create_task. Favor structured concurrency.
Separate frozen Pydantic models for config/identity from mutable-via-copy models for runtime state that evolves (e.g., agent execution state, task progress). Never mix static config fields with mutable runtime fields in one model.
Never use import logging or logging.getLogger() in application code. Exception: observability/setup.py and observability/sinks.py may use stdlib logging and print(..., file=sys.stderr) for bootst...

Files:

  • src/synthorg/api/controllers/setup_agents.py
  • src/synthorg/api/controllers/setup.py
  • src/synthorg/templates/loader.py
  • src/synthorg/api/controllers/setup_models.py
src/synthorg/api/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use RFC 9457 errors in the REST API. Implement role-based access control (RBAC) guards in the API layer.

Files:

  • src/synthorg/api/controllers/setup_agents.py
  • src/synthorg/api/controllers/setup.py
  • src/synthorg/api/controllers/setup_models.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Line length: 88 characters (ruff enforces).

Files:

  • src/synthorg/api/controllers/setup_agents.py
  • src/synthorg/api/controllers/setup.py
  • src/synthorg/templates/loader.py
  • src/synthorg/api/controllers/setup_models.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow. Maintain 80% minimum coverage. Use asyncio_mode = 'auto' (no manual @pytest.mark.asyncio). Set 30-second global timeout per test. Run tests with -n auto for parallelism via pytest-xdist; never run sequentially. Use Hypothesis for property-based testing with @given and @settings, HYPOTHESIS_PROFILE env var (ci=50 examples, dev=1000 examples). Never skip flaky tests -- fix them fundamentally by mocking time.monotonic(), asyncio.sleep(), or using asyncio.Event().wait() for blocking operations.
Use vendor-agnostic names in tests: test-provider, test-small-001, large/medium/small aliases instead of real vendor names (Anthropic, OpenAI, Claude, GPT, etc.). Vendor names appear only in operations design page, .claude/ files, third-party imports, and provider presets.

Files:

  • tests/unit/templates/test_loader.py
  • tests/unit/api/controllers/test_setup.py
**/*.{md,mdx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always read the relevant docs/design/ page before implementing any feature or planning any issue. The design spec is the starting point for architecture, data models, and behavior. If implementation deviates from spec, alert the user and explain why -- user decides whether to proceed or update the spec. Never silently diverge. When approved deviations occur, update the relevant docs/design/ page to reflect the new reality.

Files:

  • docs/design/organization.md
docs/design/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Design spec pages are mandatory reading before implementing features. Design specs pages are the starting point for architecture, data models, and behavior. When implementation deviates from spec, alert the user with reasoning. Update the relevant design page when approved deviations occur.

Files:

  • docs/design/organization.md
🧠 Learnings (32)
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).

Applied to files:

  • src/synthorg/api/controllers/setup_agents.py
📚 Learning: 2026-03-28T18:10:43.542Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T18:10:43.542Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Do not recreate status dots inline, build card-with-header layouts from scratch, create metric displays manually, render initials circles manually, create complex (>8 line) JSX inside `.map()` blocks, or use `rgba()` with hardcoded values instead of design token variables.

Applied to files:

  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/pages/setup/ProvidersStep.tsx
📚 Learning: 2026-03-28T18:10:43.543Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T18:10:43.543Z
Learning: Applies to web/src/components/ui/*.{ts,tsx} : New shared components in `web/src/components/ui/` must have a corresponding `.stories.tsx` file with all states (default, hover, loading, error, empty), exported props as a TypeScript interface, design tokens exclusively (no hardcoded colors, fonts, or spacing), and use `cn()` from `@/lib/utils` for conditional class merging.

Applied to files:

  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/pages/setup/ProvidersStep.tsx
📚 Learning: 2026-03-28T18:10:43.543Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T18:10:43.543Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use design token rules: colors via Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, `text-success`, `bg-danger`) or CSS variables (`var(--so-accent)`), typography via `font-sans` or `font-mono`, spacing via density-aware tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind, shadows/borders via token variables (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`). Never hardcode hex values, set fontFamily directly, or hardcode pixel values for layout spacing.

Applied to files:

  • web/src/pages/setup/TemplateCard.tsx
📚 Learning: 2026-03-28T18:10:43.543Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T18:10:43.543Z
Learning: Applies to tests/**/*.py : Use vendor-agnostic names in tests: `test-provider`, `test-small-001`, `large`/`medium`/`small` aliases instead of real vendor names (Anthropic, OpenAI, Claude, GPT, etc.). Vendor names appear only in operations design page, `.claude/` files, third-party imports, and provider presets.

Applied to files:

  • tests/unit/api/controllers/test_setup.py
  • web/src/__tests__/stores/setup-wizard.test.ts
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/templates/**/*.py : Templates: pre-built company templates, personality presets, and builder.

Applied to files:

  • src/synthorg/api/controllers/setup.py
  • src/synthorg/templates/loader.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/hr/**/*.py : HR package (hr/): hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping)

Applied to files:

  • src/synthorg/api/controllers/setup.py
  • web/src/__tests__/stores/setup-wizard.test.ts
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/hr/**/*.py : HR engine must provide: hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, trend detection), promotion/demotion

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-26T15:18:16.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-26T15:18:16.848Z
Learning: Applies to src/synthorg/api/**/*.py : Litestar API must include setup wizard, auth/, auto-wiring, and lifecycle management

Applied to files:

  • src/synthorg/api/controllers/setup.py
  • docs/design/organization.md
📚 Learning: 2026-03-28T18:10:43.543Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T18:10:43.543Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Use event name constants from `synthorg.observability.events.<domain>` modules (e.g., `API_REQUEST_STARTED`, `TOOL_INVOKE_START`). Always use structured kwargs: `logger.info(EVENT, key=value)`. Log all error paths at WARNING or ERROR with context before raising, all state transitions at INFO, and DEBUG for object creation and key function flow. Pure data models, enums, and re-exports do not need logging.

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/security/**/*.py : Security module includes SecOps agent, rule engine (soft-allow/hard-deny), audit log, output scanner, risk classifier, autonomy levels (4 strategies), timeout policies.

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import `from synthorg.observability import get_logger` and define `logger = get_logger(__name__)`

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-20T11:18:48.128Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T11:18:48.128Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have `from synthorg.observability import get_logger` followed by `logger = get_logger(__name__)`.

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-28T18:10:43.543Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T18:10:43.543Z
Learning: Applies to src/synthorg/api/**/*.py : Use RFC 9457 errors in the REST API. Implement role-based access control (RBAC) guards in the API layer.

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/api/**/*.py : REST API: Litestar framework, controllers with guards, channels for WebSocket, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint. RFC 9457 structured errors (ErrorCategory, ErrorCode, ErrorDetail, ProblemDetail, CATEGORY_TITLES, category_title, category_type_uri, content negotiation).

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-18T21:23:23.586Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T21:23:23.586Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from the domain-specific module under synthorg.observability.events (e.g., API_REQUEST_STARTED from events.api, TOOL_INVOKE_START from events.tool). Import directly from synthorg.observability.events.<domain>.

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-28T18:10:43.543Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T18:10:43.543Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 models (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`). Use `computed_field` for derived values instead of storing redundant fields (e.g., `TokenUsage.total_tokens`). Use `NotBlankStr` from `core.types` for all identifier/name fields (including optional `NotBlankStr | None` and tuple variants) instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-17T11:41:02.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T11:41:02.964Z
Learning: Applies to src/**/*.py : Models: Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`). Use `computed_field` for derived values instead of storing + validating redundant fields. Use `NotBlankStr` for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to **/*.py : Models: Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict). Use computed_field for derived values instead of storing + validating redundant fields. Use NotBlankStr (from core.types) for all identifier/name fields — including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants — instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-26T15:18:16.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-26T15:18:16.848Z
Learning: Applies to src/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. Use `computed_field` for derived values instead of storing redundant fields. Use `NotBlankStr` for all identifier/name fields.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 with adopted conventions: use computed_field for derived values instead of storing + validating redundant fields; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/core/**/*.py : Core module must contain shared domain models, base classes, resilience config (RetryConfig, RateLimiterConfig)

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/providers/**/*.py : Providers: LLM provider abstraction (LiteLLM adapter), auth types (api_key/oauth/custom_header/none), presets (PROVIDER_PRESETS), runtime CRUD (ProviderManagementService with asyncio.Lock serialization), hot-reload via AppState swap.

Applied to files:

  • web/src/stores/setup-wizard.ts
🔇 Additional comments (15)
web/src/pages/setup/SetupAgentCard.tsx (1)

66-66: LGTM!

The conditional rendering of the Level pill when agent.level is truthy and the defensive nullish coalescing to empty strings for model_provider and model_id correctly handle the newly nullable fields. The AgentModelPicker component already treats empty strings as "no selection" (per AgentModelPicker.tsx line 34), so this integration is sound.

Also applies to: 80-81

src/synthorg/api/controllers/setup_agents.py (2)

453-455: LGTM!

The normalization logic correctly converts empty/whitespace-only values to None, aligning with the nullable field types in SetupAgentSummary. This ensures the API returns null rather than empty strings, which the frontend now handles appropriately.


282-282: No action required — PEP 758 except syntax is correct for this project.

The except MemoryError, RecursionError: syntax (without parentheses) is valid for this codebase, which targets Python 3.14+ per requires-python = ">=3.14" in pyproject.toml. This syntax follows PEP 758 and is enforced by ruff (target-version = "py314").

tests/unit/templates/test_loader.py (1)

124-131: LGTM!

The test comprehensively validates the new structural metadata fields. The autonomy level values match the AutonomyLevel enum definition, and the assertions appropriately check type and range constraints.

tests/unit/api/controllers/test_setup.py (1)

56-70: LGTM!

The test assertions correctly validate the new template metadata fields returned by the API, ensuring the contract between the backend and frontend is properly enforced. The allowed autonomy_level values align with the AutonomyLevel enum.

web/src/__tests__/utils/template-categories.test.ts (1)

18-21: LGTM!

The test helper correctly includes the new structural metadata fields with sensible defaults that match the backend (autonomy_level: 'semi', workflow: 'agile_kanban'). The ...overrides placement allows tests to override these values as needed.

web/src/pages/setup/TemplateCard.tsx (2)

80-98: LGTM!

The structural metadata grid is well-implemented:

  • Uses design tokens (text-muted-foreground, text-accent, grid-cols-2)
  • Provides accessible title attributes for icons
  • Gracefully falls back to raw values for unknown autonomy/workflow types
  • Correct pluralization logic for counts

8-20: WORKFLOW_LABELS has complete coverage of all template values.

The AUTONOMY_LABELS keys correctly match the AutonomyLevel enum values. Verification confirms that WORKFLOW_LABELS covers all workflow values used in builtin templates (agile_kanban and kanban). The object also includes event_driven and waterfall for extensibility, and the fallback || template.workflow_type handles any future values gracefully.

web/src/api/types.ts (2)

1226-1229: LGTM!

The new template metadata fields are correctly typed. Using string for autonomy_level and workflow (rather than union types) is pragmatic since the backend returns these as strings and the frontend uses lookup maps with fallback behavior.


1253-1255: LGTM!

Making level, model_provider, and model_id nullable correctly reflects the backend change where these fields can be None when values are missing or empty.

src/synthorg/templates/loader.py (4)

79-96: LGTM!

The TemplateInfo dataclass extension is well-documented and uses sensible defaults that match the schema defaults (autonomy_level="semi", workflow="agile_kanban"). The field descriptions in the docstring are clear and helpful.


133-145: LGTM!

The template metadata extraction is clean and correctly accesses the new fields. Using tmpl.autonomy.get("level", "semi") is safe since CompanyTemplate.autonomy is guaranteed to be a dict via default_factory (per schema.py line 351-354).


166-178: LGTM!

User template collection mirrors the builtin template logic correctly, ensuring consistent metadata extraction across both template sources.


514-514: PEP 758 except syntax is compatible. The except TypeError, ValueError: syntax is correct for Python 3.14+, and pyproject.toml explicitly requires Python 3.14+. No changes needed.

src/synthorg/api/controllers/setup_models.py (1)

182-184: Nice API contract cleanup.

Using NotBlankStr | None here is much cleaner than sentinel empty strings and lines up with the setup UI's conditional rendering.

Aureliolo and others added 4 commits March 28, 2026 23:06
…vider form reuse

Template step: add search/category/size filter bar, split into Recommended
and Other Templates sections, show agent count, department count, autonomy
level, and workflow on each card. Backend TemplateInfoResponse now exposes
these structural fields from the template YAML.

Provider step: fix 0 models bug by passing the probe-detected base URL when
creating from auto-detected presets (was falling back to preset default URL
which fails from Docker). Replace simplified ProviderAddForm with the full
ProviderFormDrawer from Settings, decoupled via an overrides prop -- now
supports subscription auth (Claude Max), custom base URLs (remote Ollama),
and custom providers in the wizard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…, a11y

Pre-reviewed by 7 agents, 16 findings addressed:

- Use AutonomyLevel enum for autonomy_level field (was bare str)
- Use NotBlankStr for workflow field in TemplateInfoResponse
- Fix SetupAgentSummary: level -> SeniorityLevel|None, model_provider/model_id -> NotBlankStr|None
- Delete dead ProviderAddForm.tsx (replaced by ProviderFormDrawer)
- Add locked to AUTONOMY_LABELS in TemplateCard
- Log discovery errors in createProviderFromPresetFull (was silently swallowed)
- Add aria-label and focus:ring to template filter inputs for a11y
- Update design spec to describe new template step UX
- Add tests for createProviderFromPresetFull and createProviderCustom
- Add assertions for new template structural fields in Python and TS tests
- Add createProvider to setup-wizard test mock
- Condense create_company function to stay under 50-line limit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical: AutonomyLevel enum conversion in loader.py with fallback for
invalid user template values. Major: fix empty catch blocks, add
try/catch to probe methods, prevent fetchProviders from clearing
discovery errors, fix useEffect overrides dependency, add no-models
warning to createProviderFromPresetFull, replace raw HTML inputs with
shared InputField/SelectField, multi-keyword template search, stale
docstrings, TemplateInfo strong types, extract _template_info_from_loaded
helper, base_url scheme validation on provider DTOs, fix clear_api_key
edit logic. Docs: update user_guide and organization.md. Tests: add
SetupAgentSummary nullable/blank validation, agent_dict_to_summary
empty-to-None, zero-model discovery path. Split test_setup.py (1800
lines) into 5 files under 800 lines each. Accessibility: aria-hidden
on decorative Lucide icons.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/unit/api/controllers/conftest.py`:
- Around line 23-26: The test mock for the management service is too permissive;
replace mock_mgmt = MagicMock() with a spec-constrained mock of
ProviderManagementService (e.g., MagicMock(spec=ProviderManagementService) or
use unittest.mock.create_autospec(ProviderManagementService, instance=True)) so
only real methods exist, then set mock_mgmt.list_providers =
AsyncMock(return_value={"test-provider": mock_provider_config}) as before;
ensure ProviderManagementService is imported in the test file so the spec is
applied.

In `@tests/unit/api/controllers/test_setup_dtos.py`:
- Around line 18-26: The test currently passes a lowercase personality_preset so
it doesn't confirm normalization; update the SetupAgentRequest instantiation to
use a mixed-case preset (e.g., "Visionary_Leader" or "Visionary_Leader") and
then assert that req.personality_preset equals the lowercase normalized value
"visionary_leader" to lock in the normalization behavior for the
SetupAgentRequest validator.

In `@tests/unit/templates/test_loader.py`:
- Around line 124-131: In test_structural_metadata_populated, replace the
string-literal check of autonomy_level with comparisons against the
AutonomyLevel enum to match TemplateInfo.autonomy_level typing: import
AutonomyLevel and assert t.autonomy_level in (AutonomyLevel.FULL,
AutonomyLevel.SEMI, AutonomyLevel.SUPERVISED, AutonomyLevel.LOCKED) (or use a
membership check against set(AutonomyLevel)); keep other assertions the same so
the test verifies enum-backed values, referencing the test function name
test_structural_metadata_populated and the TemplateInfo.autonomy_level field.

In `@web/src/pages/setup/TemplateCard.tsx`:
- Around line 94-96: The displayed workflow fallback is showing raw storage keys
(template.workflow) instead of a human-friendly label; update the rendering in
TemplateCard to format the fallback via a small helper (e.g., humanizeWorkflow)
rather than echoing template.workflow directly. Implement
humanizeWorkflow(template.workflow) to replace underscores/hyphens with spaces,
trim, and Title Case or capitalize each word, then use
WORKFLOW_LABELS[template.workflow] ?? humanizeWorkflow(template.workflow) in the
span so unknown workflows are shown prettified.

In `@web/src/pages/setup/TemplateStep.tsx`:
- Around line 290-296: The onChange handler for InputField is using an
unnecessary type assertion "(e.target as HTMLInputElement).value", indicating a
mismatch between InputField's declared onChange type and the actual event;
update InputField's props to type its onChange as (e:
React.ChangeEvent<HTMLInputElement>) => void (or provide a separate
onValueChange: (value: string) => void) so callers like the one using
setSearchQuery can simply do onChange={e => setSearchQuery(e.target.value)}
without casting; locate the InputField component/props definition and adjust the
event signature (or add the value callback) and update usages including this
TemplateStep onChange to remove the cast.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e7cd2dd1-3c5c-48bd-9f82-13af3d8bb7cf

📥 Commits

Reviewing files that changed from the base of the PR and between ff33fa8 and ee6b6b4.

📒 Files selected for processing (25)
  • docs/design/organization.md
  • docs/user_guide.md
  • src/synthorg/api/controllers/setup.py
  • src/synthorg/api/controllers/setup_agents.py
  • src/synthorg/api/controllers/setup_models.py
  • src/synthorg/api/dto.py
  • src/synthorg/templates/loader.py
  • tests/unit/api/controllers/conftest.py
  • tests/unit/api/controllers/test_setup.py
  • tests/unit/api/controllers/test_setup_agent_ops.py
  • tests/unit/api/controllers/test_setup_dtos.py
  • tests/unit/api/controllers/test_setup_locales.py
  • tests/unit/api/controllers/test_setup_personality.py
  • tests/unit/templates/test_loader.py
  • web/src/__tests__/stores/setup-wizard.test.ts
  • web/src/__tests__/utils/template-categories.test.ts
  • web/src/api/types.ts
  • web/src/pages/providers/ProviderFormDrawer.tsx
  • web/src/pages/setup/ProviderAddForm.tsx
  • web/src/pages/setup/ProviderProbeResults.tsx
  • web/src/pages/setup/ProvidersStep.tsx
  • web/src/pages/setup/SetupAgentCard.tsx
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/stores/setup-wizard.ts
💤 Files with no reviewable changes (1)
  • web/src/pages/setup/ProviderAddForm.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Dashboard Test
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones. When a component is needed that is not in the existing inventory, place it in web/src/components/ui/ with a descriptive kebab-case filename, create a .stories.tsx file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Files:

  • web/src/pages/setup/SetupAgentCard.tsx
  • web/src/__tests__/utils/template-categories.test.ts
  • web/src/pages/setup/ProvidersStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/api/types.ts
  • web/src/pages/setup/ProviderProbeResults.tsx
  • web/src/__tests__/stores/setup-wizard.test.ts
  • web/src/stores/setup-wizard.ts
  • web/src/pages/providers/ProviderFormDrawer.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors. Never hardcode hex values or rgba() with hardcoded values in .tsx/.ts files.
Use font-sans or font-mono classes for typography (mapping to Geist tokens). Never set fontFamily directly in component code.
Use density-aware tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.
Use token variables (var(--so-shadow-card-hover), border-border, border-bright) for shadows and borders. Never hardcode shadow or border values.
TypeScript 6.0: remove deprecated baseUrl from tsconfig; paths entries are relative to the tsconfig directory. Remove explicit "esModuleInterop": true (always true in TS 6). List needed types explicitly (e.g., "types": ["vitest/globals"]). DOM.Iterable is merged into DOM. Use "bundler" or "nodenext" for moduleResolution.

Files:

  • web/src/pages/setup/SetupAgentCard.tsx
  • web/src/__tests__/utils/template-categories.test.ts
  • web/src/pages/setup/ProvidersStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/api/types.ts
  • web/src/pages/setup/ProviderProbeResults.tsx
  • web/src/__tests__/stores/setup-wizard.test.ts
  • web/src/stores/setup-wizard.ts
  • web/src/pages/providers/ProviderFormDrawer.tsx
web/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Do NOT recreate status dots inline—use <StatusBadge>. Do NOT build card-with-header layouts from scratch—use <SectionCard>. Do NOT create metric displays with text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map() — extract to a shared component.

Files:

  • web/src/pages/setup/SetupAgentCard.tsx
  • web/src/pages/setup/ProvidersStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/pages/setup/ProviderProbeResults.tsx
  • web/src/pages/providers/ProviderFormDrawer.tsx
**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Documentation must follow Markdown conventions: use consistent heading levels, link to relevant sections, include code examples where appropriate, and keep content up-to-date with implementation changes.

Files:

  • docs/user_guide.md
  • docs/design/organization.md
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Use PEP 758 except syntax: except A, B: (no parentheses) on Python 3.14. Do NOT use from __future__ import annotations—Python 3.14 has PEP 649 native lazy annotations.
All public functions and classes must have type hints. Use mypy strict mode. Google-style docstrings are required on all public classes and functions (enforced by ruff D rules).
Every module with business logic must include: from synthorg.observability import get_logger then logger = get_logger(__name__). Always use constants from domain-specific modules under synthorg.observability.events (e.g., API_REQUEST_STARTED from events.api). Use structured kwargs: logger.info(EVENT, key=value) — never logger.info("msg %s", val). Never use import logging or print() in application code.
Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict). Use @computed_field for derived values instead of storing redundant fields. Use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Create new objects rather than mutating existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction and wrap with MappingProxyType for read-only enforcement. For dict/list fields in frozen Pydantic models, use copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization).
Use frozen Pydantic models for config/identity. Use separate mutable-via-copy models (via model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Keep functions under 50 lines and files under 800 lines. Handle errors exp...

Files:

  • src/synthorg/api/controllers/setup_agents.py
  • src/synthorg/api/dto.py
  • src/synthorg/api/controllers/setup.py
  • src/synthorg/api/controllers/setup_models.py
  • src/synthorg/templates/loader.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use markers @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow. Maintain 80% minimum code coverage (enforced in CI). Always run pytest with -n auto for parallel execution. Use @pytest.mark.parametrize for testing similar cases. Use asyncio_mode = "auto" (no manual @pytest.mark.asyncio needed).
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in tests or project code—use generic names like test-provider, test-small-001, example-provider, example-large-001, large/medium/small. Vendor names may only appear in: (1) Operations design page, (2) .claude/ files, (3) third-party import paths, (4) provider presets.
Never skip, dismiss, or ignore flaky tests—always fix them fundamentally. For timing-sensitive tests, mock time.monotonic() and asyncio.sleep() instead of widening margins. For tasks that must block indefinitely until cancelled, use asyncio.Event().wait() instead of asyncio.sleep(large_number).

Files:

  • tests/unit/templates/test_loader.py
  • tests/unit/api/controllers/conftest.py
  • tests/unit/api/controllers/test_setup_dtos.py
  • tests/unit/api/controllers/test_setup.py
  • tests/unit/api/controllers/test_setup_personality.py
  • tests/unit/api/controllers/test_setup_agent_ops.py
  • tests/unit/api/controllers/test_setup_locales.py
docs/design/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Before implementing any feature or planning any issue, always read the relevant docs/design/ page referenced in DESIGN_SPEC.md. The design spec is the starting point for architecture, data models, and behavior. If implementation deviates from the spec, alert the user and explain why—user decides whether to proceed or update the spec. When approved deviations occur, update the relevant docs/design/ page to reflect the new reality.

Files:

  • docs/design/organization.md
🧠 Learnings (32)
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.tsx : Do NOT recreate status dots inline—use `<StatusBadge>`. Do NOT build card-with-header layouts from scratch—use `<SectionCard>`. Do NOT create metric displays with `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()` — extract to a shared component.

Applied to files:

  • web/src/pages/setup/SetupAgentCard.tsx
  • web/src/pages/setup/ProvidersStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. For derived values use `computed_field` instead of storing + validating redundant fields. Use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/dto.py
  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`). Use `computed_field` for derived values instead of storing redundant fields. Use `NotBlankStr` from `core.types` for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/dto.py
  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 BaseModel, model_validator, computed_field, ConfigDict.

Applied to files:

  • src/synthorg/api/dto.py
  • src/synthorg/api/controllers/setup_models.py
  • src/synthorg/templates/loader.py
📚 Learning: 2026-03-15T18:42:17.990Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:42:17.990Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`

Applied to files:

  • src/synthorg/api/dto.py
  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/providers/**/*.py : Providers: LLM provider abstraction (LiteLLM adapter), auth types (api_key/oauth/custom_header/none), presets (PROVIDER_PRESETS), runtime CRUD (ProviderManagementService with asyncio.Lock serialization), hot-reload via AppState swap.

Applied to files:

  • tests/unit/api/controllers/conftest.py
  • web/src/__tests__/stores/setup-wizard.test.ts
  • web/src/stores/setup-wizard.ts
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/api/**/*.py : API package (api/): Litestar REST + WebSocket with controllers, guards, channels, JWT + API key + WS ticket auth, approval gate integration, coordination endpoint, collaboration endpoint, settings endpoint, provider management endpoint (CRUD + test + presets), backup endpoint, RFC 9457 structured errors, AppState hot-reload slots, service auto-wiring (Phase 1 at construction, Phase 2 on startup), lifecycle helpers

Applied to files:

  • tests/unit/api/controllers/conftest.py
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/templates/**/*.py : Templates: pre-built company templates, personality presets, and builder.

Applied to files:

  • src/synthorg/api/controllers/setup.py
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/hr/**/*.py : HR package (hr/): hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping)

Applied to files:

  • src/synthorg/api/controllers/setup.py
  • web/src/__tests__/stores/setup-wizard.test.ts
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/components/ui/**/*.tsx : Each new shared component in `web/src/components/ui/` must have a corresponding `.stories.tsx` file with all states (default, hover, loading, error, empty). Export props as a TypeScript interface and use design tokens exclusively (no hardcoded colors, fonts, or spacing).

Applied to files:

  • web/src/pages/setup/ProvidersStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Property-based testing: Python uses Hypothesis (given + settings). Hypothesis profiles: ci (200 examples, default) and dev (1000 examples), controlled via HYPOTHESIS_PROFILE env var. Run dev profile: HYPOTHESIS_PROFILE=dev uv run python -m pytest tests/ -m unit -n auto -k properties.

Applied to files:

  • tests/unit/api/controllers/test_setup.py
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.

Applied to files:

  • web/src/pages/setup/TemplateCard.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. When a component is needed that is not in the existing inventory, place it in `web/src/components/ui/` with a descriptive kebab-case filename, create a `.stories.tsx` file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-17T11:41:02.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T11:41:02.964Z
Learning: Applies to src/**/*.py : Models: Pydantic v2 (`BaseModel`, `model_validator`, `computed_field`, `ConfigDict`). Use `computed_field` for derived values instead of storing + validating redundant fields. Use `NotBlankStr` for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple (`tuple[NotBlankStr, ...]`) variants — instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to **/*.py : Models: Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict). Use computed_field for derived values instead of storing + validating redundant fields. Use NotBlankStr (from core.types) for all identifier/name fields — including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants — instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-26T15:18:16.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-26T15:18:16.848Z
Learning: Applies to src/**/*.py : Use Pydantic v2 conventions: `BaseModel`, `model_validator`, `computed_field`, `ConfigDict`. Use `computed_field` for derived values instead of storing redundant fields. Use `NotBlankStr` for all identifier/name fields.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use Pydantic v2 with adopted conventions: use computed_field for derived values instead of storing + validating redundant fields; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/core/**/*.py : Core module must contain shared domain models, base classes, resilience config (RetryConfig, RateLimiterConfig)

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; separate mutable-via-copy models (using `model_copy(update=...)`) for runtime state

Applied to files:

  • src/synthorg/api/controllers/setup_models.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Documentation source in `docs/` (Markdown, built with Zensical). Design spec in `docs/design/` (7 pages: index, agents, organization, communication, engine, memory, operations). Architecture in `docs/architecture/` (overview, tech-stack, decision log). Roadmap in `docs/roadmap/`. Security in `docs/security.md`. Licensing in `docs/licensing.md`. Reference in `docs/reference/`. REST API reference in `docs/rest-api.md`. Library reference in `docs/api/` (auto-generated from docstrings). Custom templates in `docs/overrides/`. Config in `mkdocs.yml`.

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to docs/** : Docs source in docs/ (Markdown, built with Zensical); design spec in docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to docs/design/**/*.md : Before implementing any feature or planning any issue, always read the relevant `docs/design/` page referenced in `DESIGN_SPEC.md`. The design spec is the starting point for architecture, data models, and behavior. If implementation deviates from the spec, alert the user and explain why—user decides whether to proceed or update the spec. When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-21T11:08:01.542Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T11:08:01.542Z
Learning: When implementation deviates from the spec (better approach found, scope evolved, etc.), alert the user and explain why — user decides whether to proceed or update the spec. Do NOT silently diverge — every deviation needs explicit user approval.

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to the 7 design pages (index, agents, organization, communication, engine, memory, operations).

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : Handle errors explicitly, never silently swallow. Validate at system boundaries (user input, external APIs, config files).

Applied to files:

  • src/synthorg/templates/loader.py
📚 Learning: 2026-03-17T06:43:14.114Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:43:14.114Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions. Pure data models, enums, and re-exports do NOT need logging.

Applied to files:

  • src/synthorg/templates/loader.py
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, entry/exit of key functions.

Applied to files:

  • src/synthorg/templates/loader.py
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and key function entry/exit

Applied to files:

  • src/synthorg/templates/loader.py
🔇 Additional comments (33)
src/synthorg/api/dto.py (2)

532-543: LGTM! Clean base URL validation.

The helper correctly validates that base_url uses http/https schemes and includes a host. The None-passthrough ensures optional fields work correctly.


584-588: Consistent validator wiring across DTOs.

Good use of a shared helper function to avoid duplication. The validator is correctly applied to all three DTOs that accept base_url.

tests/unit/api/controllers/conftest.py (1)

9-31: Helper structure is appropriate for test mocking.

The pattern of returning the original for restoration is clean. The docstring could be more descriptive about when to use this helper.

src/synthorg/templates/loader.py (4)

113-138: Well-structured helper for template metadata extraction.

The helper properly handles:

  • Fallback to AutonomyLevel.SEMI on invalid values
  • Centralized construction of TemplateInfo for both builtin and user templates
  • Consistent field mapping from LoadedTemplate to TemplateInfo

79-95: TemplateInfo fields and defaults align with schema.

The defaults (0, 0, AutonomyLevel.SEMI, "agile_kanban") match CompanyTemplate schema defaults, ensuring consistency when fields are missing.


519-526: LGTM! Correct PEP 758 except syntax.

The except TypeError, ValueError: syntax follows the coding guidelines for Python 3.14.


159-163: Consistent helper usage in template listing.

Both list_templates() and _collect_user_templates() correctly use the helper with appropriate source literals.

docs/design/organization.md (1)

339-354: Design spec properly updated to reflect implementation.

The Company Builder section now accurately documents:

  • Template grid with category/size filters and recommended/others grouping
  • Structural metadata cards (agent count, departments, autonomy level, workflow)
  • Provider auto-detection with probe-detected base URLs
  • Full provider form supporting API key, subscription, custom configurations, and manual base URLs

This addresses the past review comment about documenting custom base URL support.

docs/user_guide.md (1)

77-79: User guide updates align with design spec.

The Template and Providers step descriptions now accurately reflect the new UX:

  • Searchable grid with filters and grouping
  • Structural metadata cards
  • Auto-detection with re-scan capability
  • Full provider form supporting multiple auth types
web/src/pages/setup/SetupAgentCard.tsx (2)

66-66: Correct nullable handling for level field.

Conditionally rendering the Level StatPill only when agent.level is truthy properly handles the backend change where level is now nullable.


80-81: Proper nullish coalescing for picker props.

Using ?? '' correctly converts nullable model_provider and model_id to empty strings expected by AgentModelPicker.

src/synthorg/api/controllers/setup_agents.py (2)

453-457: Nullable field normalization is correct.

The pattern (x or "").strip() or None properly normalizes empty/whitespace values to None. The # type: ignore[arg-type] on line 453 is acceptable since the expression technically returns str | None while the field expects NotBlankStr | None, but the logic ensures non-empty strings at runtime.


282-283: Correct PEP 758 syntax and appropriate exception handling.

Re-raising MemoryError and RecursionError is the right approach—these should not be silently handled.

web/src/pages/setup/ProvidersStep.tsx (1)

104-124: Nice consolidation onto the shared provider drawer.

Reusing ProviderFormDrawer here removes the setup-only form divergence and keeps advanced auth/base URL behavior in one path.

Also applies to: 201-206

web/src/api/types.ts (1)

1226-1229: ...

web/src/pages/setup/TemplateStep.tsx (3)

71-102: LGTM!

The TemplateGrid component is well-extracted, avoiding complex JSX inside .map() as per coding guidelines. Props are cleanly typed and the grid layout uses proper semantic Tailwind classes (gap-grid-gap).


27-43: LGTM!

The SIZE_OPTIONS constant and matchesSize helper are clear and correctly implement agent-count bucket filtering with proper boundary handling.


175-206: LGTM!

The filtering and recommended/others split logic is correctly memoized with appropriate dependencies. The multi-keyword search implementation using every() provides intuitive AND-matching behavior.

src/synthorg/api/controllers/setup_models.py (2)

127-144: LGTM!

The new template metadata fields are well-typed with appropriate constraints (ge=0 for counts), use the AutonomyLevel enum for type safety, and NotBlankStr for the workflow field as per coding guidelines.


182-184: LGTM!

Changing level, model_provider, and model_id to nullable types (SeniorityLevel | None, NotBlankStr | None) correctly models the domain where these values may not be specified. This aligns with the normalization logic in agent_dict_to_summary.

web/src/pages/setup/ProviderProbeResults.tsx (2)

77-88: LGTM!

Good improvement to error handling - logging errors before they're swallowed prevents silent failures during preset addition. The detectedUrl parameter is correctly forwarded through the callback chain.


111-124: LGTM!

Extracting probeResult before the JSX improves readability and ensures consistent reference within the rendered component.

web/src/stores/setup-wizard.ts (3)

626-669: LGTM!

The createProviderFromPresetFull action correctly implements zero-model detection after auto-discovery (lines 642-650), addressing the prior review concern. The error messaging is consistent with createProviderFromPreset.


697-721: LGTM!

Wrapping probe operations in try/catch/finally ensures probing is always reset, preventing the UI from getting stuck in a loading state if runProbeAll throws unexpectedly.


671-684: Add model auto-discovery to createProviderCustom for consistency with preset-based creation.

createProviderCustom lacks the auto-discovery logic present in createProviderFromPresetFull. The preset flow explicitly discovers models when provider.models.length === 0, with comments noting this is needed for local providers with auth_type: 'none' where discovery can be slow. Custom providers created with similar configurations would have the same issue—they could return 0 models on creation without attempting discovery, leaving users with non-functional providers.

Consider adding the same discovery logic (check provider.models.length === 0, call discoverModels, refresh, handle errors) to match the preset flow, or document why custom providers intentionally skip this step.

tests/unit/api/controllers/test_setup_personality.py (1)

15-129: LGTM!

Comprehensive test coverage for personality preset operations including edge cases (invalid preset, out-of-range, post-completion). The try/finally pattern properly restores state, and the tests use generic provider names per guidelines.

tests/unit/api/controllers/test_setup_locales.py (2)

189-276: LGTM!

Thorough unit tests for check_has_name_locales covering database presence, source verification, and error handling paths. The mock restoration in try/finally blocks prevents test pollution.


279-463: LGTM!

Excellent coverage of read_name_locales edge cases including JSON decode errors, non-list JSON, invalid locale filtering, and the resolve=True/False behavior. Tests correctly verify the sentinel-to-concrete-locales resolution path.

tests/unit/api/controllers/test_setup_agent_ops.py (2)

117-176: LGTM!

These unit tests for agent_dict_to_summary directly verify the empty/whitespace-to-None normalization behavior documented in the helper function, ensuring the nullable field contract is maintained.


74-114: LGTM!

The happy-path test correctly mocks the provider management layer and verifies all expected response fields. The try/finally pattern ensures proper cleanup.

web/src/pages/providers/ProviderFormDrawer.tsx (3)

53-53: LGTM!

Extracting fetchPresetsFn and depending on it (rather than the entire overrides object) correctly fixes the refetch loop identified in the prior review. The dependency array is now minimal and stable.

Also applies to: 74-78


18-27: LGTM!

The ProviderFormOverrides interface is well-designed for dependency injection, with optional callbacks for create/update operations while requiring the preset-related props that are always needed in create mode.


202-214: No issue—the clearing logic is intentional and safe.

The backend validator explicitly rejects simultaneous credential set and clear (api_key and clear_api_key are mutually exclusive). When the auth type switches, the frontend sends clear_api_key: true with api_key: undefined, which passes validation. The backend's _apply_credential_updates() then respects the change: it clears old credentials when the new auth type doesn't support them. This is the intended behavior—stale credentials should not persist across auth type changes.

			> Likely an incorrect or invalid review comment.

Comment on lines +23 to +26
mock_mgmt = MagicMock()
mock_mgmt.list_providers = AsyncMock(
return_value={"test-provider": mock_provider_config},
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider using spec or spec_set for the mock.

The mock only explicitly implements list_providers(). If any controller method calls other ProviderManagementService methods (e.g., get_provider(), create_provider()), tests will silently pass with MagicMock return values instead of raising AttributeError.

Using spec=ProviderManagementService would make the mock safer by restricting it to actual service methods.

♻️ Proposed improvement
+from synthorg.providers.management.service import ProviderManagementService
+
 def setup_mock_providers(
     test_client: TestClient[Any],
 ) -> tuple[Any, Any]:
     """Wire up mock providers on the app state. Returns (app_state, original)."""
     # ... model setup ...
 
-    mock_mgmt = MagicMock()
+    mock_mgmt = MagicMock(spec=ProviderManagementService)
     mock_mgmt.list_providers = AsyncMock(
         return_value={"test-provider": mock_provider_config},
     )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mock_mgmt = MagicMock()
mock_mgmt.list_providers = AsyncMock(
return_value={"test-provider": mock_provider_config},
)
from synthorg.providers.management.service import ProviderManagementService
def setup_mock_providers(
test_client: TestClient[Any],
) -> tuple[Any, Any]:
"""Wire up mock providers on the app state. Returns (app_state, original)."""
# ... model setup ...
mock_mgmt = MagicMock(spec=ProviderManagementService)
mock_mgmt.list_providers = AsyncMock(
return_value={"test-provider": mock_provider_config},
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/api/controllers/conftest.py` around lines 23 - 26, The test mock
for the management service is too permissive; replace mock_mgmt = MagicMock()
with a spec-constrained mock of ProviderManagementService (e.g.,
MagicMock(spec=ProviderManagementService) or use
unittest.mock.create_autospec(ProviderManagementService, instance=True)) so only
real methods exist, then set mock_mgmt.list_providers =
AsyncMock(return_value={"test-provider": mock_provider_config}) as before;
ensure ProviderManagementService is imported in the test file so the spec is
applied.

Comment on lines +18 to +26
req = SetupAgentRequest(
name="Alice",
role="CEO",
personality_preset="visionary_leader",
model_provider="test-provider",
model_id="model-001",
)
# Validator normalizes to lowercase
assert req.personality_preset == "visionary_leader"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

This doesn't verify the lowercase normalization.

Line 21 already passes a lowercase preset, so the assertion on Line 26 would still pass if the validator stopped normalizing and only validated membership. Feed a mixed-case value here to lock the behavior down.

🧪 Tighten the normalization assertion
         req = SetupAgentRequest(
             name="Alice",
             role="CEO",
-            personality_preset="visionary_leader",
+            personality_preset="Visionary_Leader",
             model_provider="test-provider",
             model_id="model-001",
         )
         # Validator normalizes to lowercase
         assert req.personality_preset == "visionary_leader"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/api/controllers/test_setup_dtos.py` around lines 18 - 26, The test
currently passes a lowercase personality_preset so it doesn't confirm
normalization; update the SetupAgentRequest instantiation to use a mixed-case
preset (e.g., "Visionary_Leader" or "Visionary_Leader") and then assert that
req.personality_preset equals the lowercase normalized value "visionary_leader"
to lock in the normalization behavior for the SetupAgentRequest validator.

Comment on lines +290 to 296
<InputField
label="Search"
value={searchQuery}
onChange={(e) => setSearchQuery((e.target as HTMLInputElement).value)}
placeholder="Search templates..."
className="pl-8 pr-8"
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Type assertion suggests potential type mismatch with InputField onChange.

The cast (e.target as HTMLInputElement).value suggests InputField's onChange may not provide a typed event. If InputField uses a standard React.ChangeEvent<HTMLInputElement>, this cast is unnecessary. If the signature differs, consider updating InputField to expose a properly typed event or a direct value callback.

♻️ Suggested simplification if InputField provides standard events
 <InputField
   label="Search"
   value={searchQuery}
-  onChange={(e) => setSearchQuery((e.target as HTMLInputElement).value)}
+  onChange={(e) => setSearchQuery(e.target.value)}
   placeholder="Search templates..."
   className="pl-8 pr-8"
 />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/setup/TemplateStep.tsx` around lines 290 - 296, The onChange
handler for InputField is using an unnecessary type assertion "(e.target as
HTMLInputElement).value", indicating a mismatch between InputField's declared
onChange type and the actual event; update InputField's props to type its
onChange as (e: React.ChangeEvent<HTMLInputElement>) => void (or provide a
separate onValueChange: (value: string) => void) so callers like the one using
setSearchQuery can simply do onChange={e => setSearchQuery(e.target.value)}
without casting; locate the InputField component/props definition and adjust the
event signature (or add the value callback) and update usages including this
TemplateStep onChange to remove the cast.

…, a11y

- Test DTO normalization with mixed-case preset input to verify lowering
- Use AutonomyLevel enum in loader test assertion (matches new field type)
- Add humanizeWorkflow fallback for unknown workflow display values
- Add onValueChange prop to InputField, remove type cast in TemplateStep
- Revert spec-constrained mock (ProviderManagementService init is too
  complex for spec-based mocking, causes xdist worker crashes)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/pages/setup/TemplateStep.tsx (1)

129-135: ⚠️ Potential issue | 🟠 Major

Filtering can hide the active selection.

selectedTemplate still marks the step complete even when that card drops out of filteredTemplates, so the wizard can proceed with a template the user can no longer see or review. Please either keep the selected card visible, show a “selected template hidden by filters” notice with a clear-filters action, or clear the selection when filters exclude it.

Also applies to: 175-192, 341-393

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/setup/TemplateStep.tsx` around lines 129 - 135, The effect that
marks the template step complete uses selectedTemplate without verifying it is
still present in filteredTemplates; update the logic so if selectedTemplate
exists but is not included in filteredTemplates you clear the selection (e.g.
call setSelectedTemplate(null)) and call markStepIncomplete('template');
otherwise keep the existing behavior (markStepComplete when selectedTemplate is
present in filteredTemplates). Apply the same fix to the other places that tie
selection to filters (the similar blocks referenced around the other ranges) so
selection is cleared whenever filters exclude the selected card.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/unit/templates/test_loader.py`:
- Around line 125-132: The current test_structural_metadata_populated uses
default-valid TemplateInfo values, so change it to assert that each listed
template's structural fields actually match the source template data by loading
the full template and comparing: for each t in list_templates() call
load_template(t.name) and compare t.agent_count, t.department_count,
t.autonomy_level, and t.workflow against the corresponding values on the
loaded_template.template (or the Template object returned by load_template),
ensuring you reference TemplateInfo and the loader path implemented by
_template_info_from_loaded to validate the mapping rather than relying on
defaults.

In `@web/src/pages/setup/TemplateStep.tsx`:
- Line 288: Replace the hardcoded min-w-[200px] on the filter container with a
tokenized/standard Tailwind spacing class: locate the div with className
containing "relative flex-1 min-w-[200px] max-w-xs" and change min-w-[200px] to
a density-aware token or standard Tailwind size (for example use min-w-52 or the
repo's density token like min-w-p-card if available) so the component
(TemplateStep) follows the project's spacing conventions.

---

Outside diff comments:
In `@web/src/pages/setup/TemplateStep.tsx`:
- Around line 129-135: The effect that marks the template step complete uses
selectedTemplate without verifying it is still present in filteredTemplates;
update the logic so if selectedTemplate exists but is not included in
filteredTemplates you clear the selection (e.g. call setSelectedTemplate(null))
and call markStepIncomplete('template'); otherwise keep the existing behavior
(markStepComplete when selectedTemplate is present in filteredTemplates). Apply
the same fix to the other places that tie selection to filters (the similar
blocks referenced around the other ranges) so selection is cleared whenever
filters exclude the selected card.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d49cbe88-75aa-4812-9074-d70802059a5b

📥 Commits

Reviewing files that changed from the base of the PR and between ee6b6b4 and b6c6618.

📒 Files selected for processing (5)
  • tests/unit/api/controllers/test_setup_dtos.py
  • tests/unit/templates/test_loader.py
  • web/src/components/ui/input-field.tsx
  • web/src/pages/setup/TemplateCard.tsx
  • web/src/pages/setup/TemplateStep.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Dashboard Test
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (5)
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use markers @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow. Maintain 80% minimum code coverage (enforced in CI). Always run pytest with -n auto for parallel execution. Use @pytest.mark.parametrize for testing similar cases. Use asyncio_mode = "auto" (no manual @pytest.mark.asyncio needed).
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in tests or project code—use generic names like test-provider, test-small-001, example-provider, example-large-001, large/medium/small. Vendor names may only appear in: (1) Operations design page, (2) .claude/ files, (3) third-party import paths, (4) provider presets.
Never skip, dismiss, or ignore flaky tests—always fix them fundamentally. For timing-sensitive tests, mock time.monotonic() and asyncio.sleep() instead of widening margins. For tasks that must block indefinitely until cancelled, use asyncio.Event().wait() instead of asyncio.sleep(large_number).

Files:

  • tests/unit/templates/test_loader.py
  • tests/unit/api/controllers/test_setup_dtos.py
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones. When a component is needed that is not in the existing inventory, place it in web/src/components/ui/ with a descriptive kebab-case filename, create a .stories.tsx file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Files:

  • web/src/components/ui/input-field.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors. Never hardcode hex values or rgba() with hardcoded values in .tsx/.ts files.
Use font-sans or font-mono classes for typography (mapping to Geist tokens). Never set fontFamily directly in component code.
Use density-aware tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.
Use token variables (var(--so-shadow-card-hover), border-border, border-bright) for shadows and borders. Never hardcode shadow or border values.
TypeScript 6.0: remove deprecated baseUrl from tsconfig; paths entries are relative to the tsconfig directory. Remove explicit "esModuleInterop": true (always true in TS 6). List needed types explicitly (e.g., "types": ["vitest/globals"]). DOM.Iterable is merged into DOM. Use "bundler" or "nodenext" for moduleResolution.

Files:

  • web/src/components/ui/input-field.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
web/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Do NOT recreate status dots inline—use <StatusBadge>. Do NOT build card-with-header layouts from scratch—use <SectionCard>. Do NOT create metric displays with text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map() — extract to a shared component.

Files:

  • web/src/components/ui/input-field.tsx
  • web/src/pages/setup/TemplateStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
web/src/components/ui/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Each new shared component in web/src/components/ui/ must have a corresponding .stories.tsx file with all states (default, hover, loading, error, empty). Export props as a TypeScript interface and use design tokens exclusively (no hardcoded colors, fonts, or spacing).

Files:

  • web/src/components/ui/input-field.tsx
🧠 Learnings (5)
📚 Learning: 2026-03-15T18:28:13.207Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:28:13.207Z
Learning: Applies to tests/**/*.py : Tests must use test-provider, test-small-001, etc. for vendor-agnostic test data.

Applied to files:

  • tests/unit/api/controllers/test_setup_dtos.py
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to tests/**/*.py : Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in tests or project code—use generic names like `test-provider`, `test-small-001`, `example-provider`, `example-large-001`, `large`/`medium`/`small`. Vendor names may only appear in: (1) Operations design page, (2) `.claude/` files, (3) third-party import paths, (4) provider presets.

Applied to files:

  • tests/unit/api/controllers/test_setup_dtos.py
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/components/ui/**/*.tsx : Each new shared component in `web/src/components/ui/` must have a corresponding `.stories.tsx` file with all states (default, hover, loading, error, empty). Export props as a TypeScript interface and use design tokens exclusively (no hardcoded colors, fonts, or spacing).

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.tsx : Do NOT recreate status dots inline—use `<StatusBadge>`. Do NOT build card-with-header layouts from scratch—use `<SectionCard>`. Do NOT create metric displays with `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()` — extract to a shared component.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
  • web/src/pages/setup/TemplateCard.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.

Applied to files:

  • web/src/pages/setup/TemplateCard.tsx
🔇 Additional comments (3)
web/src/components/ui/input-field.tsx (3)

8-9: Well-documented convenience prop.

The JSDoc comment clearly explains the purpose, and the type signature is appropriately simple.


41-49: Handler implementation is correct.

The type casts are necessary here due to the discriminated union pattern—TypeScript can't narrow onChange to the specific element handler type within these functions. The leading semicolons correctly prevent ASI from treating the expression as a chained call.


65-66: Props spreading correctly excludes onChange.

Since onChange is destructured separately on line 25, it's already excluded from ...props at runtime. The type casts help TypeScript understand this, and the pattern correctly prevents duplicate onChange props on the elements.

Also applies to: 76-77

…token spacing

- Test structural metadata against loaded template data (not just defaults)
- Replace hardcoded min-w-[200px] with standard Tailwind min-w-52
- Track step completion against filteredTemplates so selecting a template
  then filtering it out correctly marks the step incomplete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/unit/templates/test_loader.py`:
- Around line 133-141: The test should assert that t.autonomy_level is an actual
AutonomyLevel enum member and that workflow is non-empty: add an isinstance
check (isinstance(t.autonomy_level, AutonomyLevel)) and ensure the workflow
string is not blank (e.g., assert isinstance(t.workflow, str) and
t.workflow.strip() != "") in addition to the existing equality/assertions;
reference the AutonomyLevel type and the attributes t.autonomy_level, t.workflow
and tmpl.workflow when adding these assertions to strengthen contract
validation.

In `@web/src/pages/setup/TemplateStep.tsx`:
- Around line 187-193: The effect that marks the template step complete is
running while templates are still loading, causing false negatives; update the
useEffect that reads selectedTemplate and filteredTemplates to early-return when
templatesLoading is true and add templatesLoading to the dependency array, so
the existing logic that calls markStepComplete('template') or
markStepIncomplete('template') only runs after templates have finished loading
(referencing useEffect, selectedTemplate, filteredTemplates, templatesLoading,
markStepComplete, markStepIncomplete).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 69718db0-d5fd-4efd-8e5e-13da3f258e4e

📥 Commits

Reviewing files that changed from the base of the PR and between b6c6618 and e5de269.

📒 Files selected for processing (2)
  • tests/unit/templates/test_loader.py
  • web/src/pages/setup/TemplateStep.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Dashboard Test
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use markers @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow. Maintain 80% minimum code coverage (enforced in CI). Always run pytest with -n auto for parallel execution. Use @pytest.mark.parametrize for testing similar cases. Use asyncio_mode = "auto" (no manual @pytest.mark.asyncio needed).
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in tests or project code—use generic names like test-provider, test-small-001, example-provider, example-large-001, large/medium/small. Vendor names may only appear in: (1) Operations design page, (2) .claude/ files, (3) third-party import paths, (4) provider presets.
Never skip, dismiss, or ignore flaky tests—always fix them fundamentally. For timing-sensitive tests, mock time.monotonic() and asyncio.sleep() instead of widening margins. For tasks that must block indefinitely until cancelled, use asyncio.Event().wait() instead of asyncio.sleep(large_number).

Files:

  • tests/unit/templates/test_loader.py
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones. When a component is needed that is not in the existing inventory, place it in web/src/components/ui/ with a descriptive kebab-case filename, create a .stories.tsx file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors. Never hardcode hex values or rgba() with hardcoded values in .tsx/.ts files.
Use font-sans or font-mono classes for typography (mapping to Geist tokens). Never set fontFamily directly in component code.
Use density-aware tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.
Use token variables (var(--so-shadow-card-hover), border-border, border-bright) for shadows and borders. Never hardcode shadow or border values.
TypeScript 6.0: remove deprecated baseUrl from tsconfig; paths entries are relative to the tsconfig directory. Remove explicit "esModuleInterop": true (always true in TS 6). List needed types explicitly (e.g., "types": ["vitest/globals"]). DOM.Iterable is merged into DOM. Use "bundler" or "nodenext" for moduleResolution.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Do NOT recreate status dots inline—use <StatusBadge>. Do NOT build card-with-header layouts from scratch—use <SectionCard>. Do NOT create metric displays with text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map() — extract to a shared component.

Files:

  • web/src/pages/setup/TemplateStep.tsx
🧠 Learnings (6)
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-*)`) for colors. Never hardcode hex values or rgba() with hardcoded values in `.tsx`/`.ts` files.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use token variables (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`) for shadows and borders. Never hardcode shadow or border values.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.tsx : Do NOT recreate status dots inline—use `<StatusBadge>`. Do NOT build card-with-header layouts from scratch—use `<SectionCard>`. Do NOT create metric displays with `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()` — extract to a shared component.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. When a component is needed that is not in the existing inventory, place it in `web/src/components/ui/` with a descriptive kebab-case filename, create a `.stories.tsx` file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/components/ui/**/*.tsx : Each new shared component in `web/src/components/ui/` must have a corresponding `.stories.tsx` file with all states (default, hover, loading, error, empty). Export props as a TypeScript interface and use design tokens exclusively (no hardcoded colors, fonts, or spacing).

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx

…uring load

- Assert autonomy_level is AutonomyLevel instance (not just string member)
- Assert workflow is a non-blank string before equality check
- Skip step completion effect while templatesLoading to prevent false
  negatives from empty filteredTemplates during initial fetch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/pages/setup/TemplateStep.tsx`:
- Around line 188-195: The effect that toggles wizard step state uses
filteredTemplates to decide if selectedTemplate is valid, which incorrectly
marks the step incomplete when UI filters hide the selection; update the check
to verify selectedTemplate exists in the full templates array (replace
filteredTemplates.some(...) with templates.some(...)) and adjust the effect
dependencies to include templates (and remove filteredTemplates if no longer
used) while keeping the templatesLoading guard; keep
markStepComplete('template') and markStepIncomplete('template') logic unchanged.
- Around line 122-126: The useEffect currently uses templates.length as the "not
loaded yet" signal which causes repeated refetches when an empty array is a
valid successful response; update the logic in TemplateStep.tsx to track initial
load with a stable flag instead (e.g., import and use React.useRef to add an
"hasFetchedTemplates" ref or use an existing store-level loaded/initialized
boolean) and change the effect to only call fetchTemplates() when
hasFetchedTemplates.current is false and templatesLoading is false and
templatesError is false; after the first fetch, set hasFetchedTemplates.current
= true (or rely on the store flag) so an empty templates array does not trigger
subsequent fetches.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2ee8ad95-d608-46d0-a032-83f9046baf54

📥 Commits

Reviewing files that changed from the base of the PR and between e5de269 and fbc0086.

📒 Files selected for processing (2)
  • tests/unit/templates/test_loader.py
  • web/src/pages/setup/TemplateStep.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Dashboard Test
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use markers @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow. Maintain 80% minimum code coverage (enforced in CI). Always run pytest with -n auto for parallel execution. Use @pytest.mark.parametrize for testing similar cases. Use asyncio_mode = "auto" (no manual @pytest.mark.asyncio needed).
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in tests or project code—use generic names like test-provider, test-small-001, example-provider, example-large-001, large/medium/small. Vendor names may only appear in: (1) Operations design page, (2) .claude/ files, (3) third-party import paths, (4) provider presets.
Never skip, dismiss, or ignore flaky tests—always fix them fundamentally. For timing-sensitive tests, mock time.monotonic() and asyncio.sleep() instead of widening margins. For tasks that must block indefinitely until cancelled, use asyncio.Event().wait() instead of asyncio.sleep(large_number).

Files:

  • tests/unit/templates/test_loader.py
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones. When a component is needed that is not in the existing inventory, place it in web/src/components/ui/ with a descriptive kebab-case filename, create a .stories.tsx file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors. Never hardcode hex values or rgba() with hardcoded values in .tsx/.ts files.
Use font-sans or font-mono classes for typography (mapping to Geist tokens). Never set fontFamily directly in component code.
Use density-aware tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.
Use token variables (var(--so-shadow-card-hover), border-border, border-bright) for shadows and borders. Never hardcode shadow or border values.
TypeScript 6.0: remove deprecated baseUrl from tsconfig; paths entries are relative to the tsconfig directory. Remove explicit "esModuleInterop": true (always true in TS 6). List needed types explicitly (e.g., "types": ["vitest/globals"]). DOM.Iterable is merged into DOM. Use "bundler" or "nodenext" for moduleResolution.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Do NOT recreate status dots inline—use <StatusBadge>. Do NOT build card-with-header layouts from scratch—use <SectionCard>. Do NOT create metric displays with text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map() — extract to a shared component.

Files:

  • web/src/pages/setup/TemplateStep.tsx
🧠 Learnings (6)
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-*)`) for colors. Never hardcode hex values or rgba() with hardcoded values in `.tsx`/`.ts` files.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use token variables (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`) for shadows and borders. Never hardcode shadow or border values.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.tsx : Do NOT recreate status dots inline—use `<StatusBadge>`. Do NOT build card-with-header layouts from scratch—use `<SectionCard>`. Do NOT create metric displays with `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()` — extract to a shared component.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. When a component is needed that is not in the existing inventory, place it in `web/src/components/ui/` with a descriptive kebab-case filename, create a `.stories.tsx` file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/components/ui/**/*.tsx : Each new shared component in `web/src/components/ui/` must have a corresponding `.stories.tsx` file with all states (default, hover, loading, error, empty). Export props as a TypeScript interface and use design tokens exclusively (no hardcoded colors, fonts, or spacing).

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
🔇 Additional comments (3)
tests/unit/templates/test_loader.py (2)

9-9: Good import addition for enum contract assertions.

This import is necessary for the strengthened autonomy_level type/value checks in the new test.


125-143: Strong metadata-mapping test; this now verifies real loader behavior.

Great improvement: assertions now validate agent_count, department_count, enum typing/fallback for autonomy_level, and non-blank/equal workflow against loaded template data.

web/src/pages/setup/TemplateStep.tsx (1)

71-102: Nice extraction of the grid item map.

Pulling the card body into TemplateGridItem/TemplateGrid keeps the render tree readable and avoids a long inline JSX block inside .map().

As per coding guidelines, web/src/**/*.tsx: Do NOT create complex (>8 line) JSX inside .map() — extract to a shared component.

…etch

- Step completion checks templates (full list) instead of
  filteredTemplates so UI filters don't invalidate the selection
- Replace templates.length === 0 fetch guard with useRef flag to prevent
  refetch when the API legitimately returns an empty template list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/pages/setup/TemplateStep.tsx`:
- Around line 176-180: The keyword haystack in TemplateStep.tsx currently builds
from t.display_name, t.description and t.tags but omits the newly surfaced
metadata (workflow and autonomy_level), so include those fields when composing
haystack (e.g., append t.workflow and t.autonomy_level, converting them to
strings or joining their subfields if they are objects/arrays) before calling
.toLowerCase() so the existing keywords.every((kw) => haystack.includes(kw))
check will match templates by those metadata values as well.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2c1f3c89-2f7d-404b-84cc-27604afb631e

📥 Commits

Reviewing files that changed from the base of the PR and between fbc0086 and 75d5e57.

📒 Files selected for processing (1)
  • web/src/pages/setup/TemplateStep.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Dashboard Test
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones. When a component is needed that is not in the existing inventory, place it in web/src/components/ui/ with a descriptive kebab-case filename, create a .stories.tsx file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors. Never hardcode hex values or rgba() with hardcoded values in .tsx/.ts files.
Use font-sans or font-mono classes for typography (mapping to Geist tokens). Never set fontFamily directly in component code.
Use density-aware tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.
Use token variables (var(--so-shadow-card-hover), border-border, border-bright) for shadows and borders. Never hardcode shadow or border values.
TypeScript 6.0: remove deprecated baseUrl from tsconfig; paths entries are relative to the tsconfig directory. Remove explicit "esModuleInterop": true (always true in TS 6). List needed types explicitly (e.g., "types": ["vitest/globals"]). DOM.Iterable is merged into DOM. Use "bundler" or "nodenext" for moduleResolution.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Do NOT recreate status dots inline—use <StatusBadge>. Do NOT build card-with-header layouts from scratch—use <SectionCard>. Do NOT create metric displays with text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map() — extract to a shared component.

Files:

  • web/src/pages/setup/TemplateStep.tsx
🧠 Learnings (6)
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-*)`) for colors. Never hardcode hex values or rgba() with hardcoded values in `.tsx`/`.ts` files.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use token variables (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`) for shadows and borders. Never hardcode shadow or border values.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.tsx : Do NOT recreate status dots inline—use `<StatusBadge>`. Do NOT build card-with-header layouts from scratch—use `<SectionCard>`. Do NOT create metric displays with `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()` — extract to a shared component.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. When a component is needed that is not in the existing inventory, place it in `web/src/components/ui/` with a descriptive kebab-case filename, create a `.stories.tsx` file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/components/ui/**/*.tsx : Each new shared component in `web/src/components/ui/` must have a corresponding `.stories.tsx` file with all states (default, hover, loading, error, empty). Export props as a TypeScript interface and use design tokens exclusively (no hardcoded colors, fonts, or spacing).

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
🔇 Additional comments (2)
web/src/pages/setup/TemplateStep.tsx (2)

187-197: Nice fix: completion no longer depends on transient filters.

Validating selectedTemplate against the full templates list and skipping the check while loading keeps the wizard state stable when filters hide the selected card.


122-128: Move fetch guard state to store; useRef resets on step remount.

TemplateStep is conditionally mounted via AnimatedPresence in WizardShell.tsx (line 120). When the user navigates away and back to the template step, the component remounts and hasFetchedRef resets. An empty-result response will trigger fetchTemplates() again on return, reintroducing the refetch loop.

The setup store has no persistent templatesLoaded flag. Add one to web/src/stores/setup-wizard.ts (e.g., templatesInitialized: boolean), set it in fetchTemplates() after a successful fetch, and use it in the effect guard instead of the component-local ref.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/pages/setup/TemplateStep.tsx`:
- Around line 322-328: The SelectField in TemplateStep currently passes
options={[...SIZE_OPTIONS]} which allocates a new array every render; fix by
avoiding the spread: either expose a module-level mutable array (e.g.,
SIZE_OPTIONS_MUTABLE) and use options={SIZE_OPTIONS_MUTABLE} or remove the `as
const` on SIZE_OPTIONS so its type matches SelectField and use
options={SIZE_OPTIONS} directly, or memoize the options once (useMemo) and pass
that memoized value to SelectField (identify usages by SIZE_OPTIONS,
SelectField, sizeFilter and setSizeFilter in TemplateStep).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3b5d4aeb-782a-4746-ac2d-6d4118c9819b

📥 Commits

Reviewing files that changed from the base of the PR and between 75d5e57 and b202309.

📒 Files selected for processing (1)
  • web/src/pages/setup/TemplateStep.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dashboard Test
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Socket Security: Pull Request Alerts
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones. When a component is needed that is not in the existing inventory, place it in web/src/components/ui/ with a descriptive kebab-case filename, create a .stories.tsx file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors. Never hardcode hex values or rgba() with hardcoded values in .tsx/.ts files.
Use font-sans or font-mono classes for typography (mapping to Geist tokens). Never set fontFamily directly in component code.
Use density-aware tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.
Use token variables (var(--so-shadow-card-hover), border-border, border-bright) for shadows and borders. Never hardcode shadow or border values.
TypeScript 6.0: remove deprecated baseUrl from tsconfig; paths entries are relative to the tsconfig directory. Remove explicit "esModuleInterop": true (always true in TS 6). List needed types explicitly (e.g., "types": ["vitest/globals"]). DOM.Iterable is merged into DOM. Use "bundler" or "nodenext" for moduleResolution.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Do NOT recreate status dots inline—use <StatusBadge>. Do NOT build card-with-header layouts from scratch—use <SectionCard>. Do NOT create metric displays with text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map() — extract to a shared component.

Files:

  • web/src/pages/setup/TemplateStep.tsx
🧠 Learnings (6)
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-*)`) for colors. Never hardcode hex values or rgba() with hardcoded values in `.tsx`/`.ts` files.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use token variables (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`) for shadows and borders. Never hardcode shadow or border values.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.tsx : Do NOT recreate status dots inline—use `<StatusBadge>`. Do NOT build card-with-header layouts from scratch—use `<SectionCard>`. Do NOT create metric displays with `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()` — extract to a shared component.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. When a component is needed that is not in the existing inventory, place it in `web/src/components/ui/` with a descriptive kebab-case filename, create a `.stories.tsx` file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/components/ui/**/*.tsx : Each new shared component in `web/src/components/ui/` must have a corresponding `.stories.tsx` file with all states (default, hover, loading, error, empty). Export props as a TypeScript interface and use design tokens exclusively (no hardcoded colors, fonts, or spacing).

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
🔇 Additional comments (7)
web/src/pages/setup/TemplateStep.tsx (7)

27-43: LGTM — Size filter constants and predicate are well-structured.

The SIZE_OPTIONS tuple with as const provides strong type inference for SizeFilter, and matchesSize cleanly handles all boundary conditions with explicit range checks.


71-102: LGTM — Good extraction of TemplateGrid as a reusable internal component.

The component properly uses the gap-grid-gap density token and responsive breakpoints. Extracting TemplateGridItem keeps the .map() body simple, adhering to the guideline against complex JSX inside iteration callbacks.


122-128: LGTM — Fetch-once guard correctly prevents refetch loops.

Using hasFetchedRef instead of templates.length === 0 as the trigger condition ensures an empty template array (valid response) doesn't cause repeated fetches.


168-185: LGTM — Filter logic correctly indexes all card metadata.

The haystack now includes workflow and autonomy_level alongside display_name, description, and tags, ensuring users can search by any visible metadata. The multi-keyword AND semantics (every()) provide intuitive results.


187-197: LGTM — Step completion validation is now resilient.

The effect correctly guards against the loading state and validates selectedTemplate against the full templates array rather than the filtered view, preventing filters from incorrectly invalidating the wizard step.


290-312: LGTM — Search input with accessibility and semantic styling.

The search wrapper correctly uses min-w-52 (standard Tailwind), semantic color classes, and includes proper accessibility attributes (aria-hidden on decorative icon, aria-label on the clear button). The onValueChange prop cleanly passes the value without type assertions.


363-398: LGTM — Recommended/Other sections cleanly separated with reusable grid.

The split logic efficiently partitions templates, and TemplateGrid is reused for both sections. The conditional "Other Templates" heading (only when recommended exists) provides good UX hierarchy.

Type SIZE_OPTIONS as readonly to match SelectField's props directly,
eliminating the [...SIZE_OPTIONS] spread that allocated on every render.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/pages/setup/TemplateStep.tsx`:
- Around line 27-35: Change SIZE_OPTIONS to use the more specific SizeFilter
type for its value property so the constant is self-documenting: replace the
current { value: string; label: string } typing with { value: SizeFilter; label:
string } while keeping the readonly array cast. Note that you should still cast
the SelectField onChange value to SizeFilter at the usage site (the SelectField
component's onChange handler that currently casts e.target.value) because
SelectField's onChange provides a string. Update references to SIZE_OPTIONS and
maintain the existing cast in the SelectField onChange callback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c83a2aa4-ac2e-4440-b6d2-9b61c031e388

📥 Commits

Reviewing files that changed from the base of the PR and between b202309 and 8bb3204.

📒 Files selected for processing (1)
  • web/src/pages/setup/TemplateStep.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build Backend
  • GitHub Check: Dashboard Test
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones. When a component is needed that is not in the existing inventory, place it in web/src/components/ui/ with a descriptive kebab-case filename, create a .stories.tsx file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors. Never hardcode hex values or rgba() with hardcoded values in .tsx/.ts files.
Use font-sans or font-mono classes for typography (mapping to Geist tokens). Never set fontFamily directly in component code.
Use density-aware tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.
Use token variables (var(--so-shadow-card-hover), border-border, border-bright) for shadows and borders. Never hardcode shadow or border values.
TypeScript 6.0: remove deprecated baseUrl from tsconfig; paths entries are relative to the tsconfig directory. Remove explicit "esModuleInterop": true (always true in TS 6). List needed types explicitly (e.g., "types": ["vitest/globals"]). DOM.Iterable is merged into DOM. Use "bundler" or "nodenext" for moduleResolution.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Do NOT recreate status dots inline—use <StatusBadge>. Do NOT build card-with-header layouts from scratch—use <SectionCard>. Do NOT create metric displays with text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map() — extract to a shared component.

Files:

  • web/src/pages/setup/TemplateStep.tsx
🧠 Learnings (6)
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-*)`) for colors. Never hardcode hex values or rgba() with hardcoded values in `.tsx`/`.ts` files.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use token variables (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`) for shadows and borders. Never hardcode shadow or border values.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.tsx : Do NOT recreate status dots inline—use `<StatusBadge>`. Do NOT build card-with-header layouts from scratch—use `<SectionCard>`. Do NOT create metric displays with `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()` — extract to a shared component.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. When a component is needed that is not in the existing inventory, place it in `web/src/components/ui/` with a descriptive kebab-case filename, create a `.stories.tsx` file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/components/ui/**/*.tsx : Each new shared component in `web/src/components/ui/` must have a corresponding `.stories.tsx` file with all states (default, hover, loading, error, empty). Export props as a TypeScript interface and use design tokens exclusively (no hardcoded colors, fonts, or spacing).

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
🔇 Additional comments (7)
web/src/pages/setup/TemplateStep.tsx (7)

1-17: LGTM!

Imports are well-organized, reusing existing UI components from @/components/ui/ as per coding guidelines.


71-102: LGTM!

TemplateGrid is well-extracted with proper prop typing. The use of gap-grid-gap follows density token conventions, and the .map() body correctly delegates to TemplateGridItem per coding guidelines.


122-128: LGTM!

The hasFetchedRef pattern correctly prevents re-fetch loops when the templates array is legitimately empty.


187-197: LGTM!

The completion effect correctly validates against the full templates list (not filtered), with proper guarding during loading. This ensures UI filters don't inadvertently invalidate the selection.


290-344: LGTM!

Filter bar uses semantic color classes (text-muted-foreground, text-accent), standard Tailwind spacing (min-w-52), and proper accessibility attributes (aria-hidden, aria-label). Previous review concerns about hardcoded pixels and type assertions have been addressed.


363-398: LGTM!

Template sections are well-structured with semantic styling (bg-accent/10, text-accent). The recommended/others split logic is clean and the conditional heading for "Other Templates" correctly appears only when both sections are visible.


346-361: LGTM!

Good UX distinction between "no templates match" (filters applied) and "no templates available" (empty data). The action to clear filters is helpful.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/pages/setup/TemplateStep.tsx`:
- Line 294: The Search icon uses vertical centering (className includes "top-1/2
-translate-y-1/2") but the Clear button uses a fixed offset ("bottom-2.5"),
causing misalignment; update the Clear button element in TemplateStep (the
clear/X button rendered next to the input) to use the same centering classes
("top-1/2 -translate-y-1/2") instead of "bottom-2.5" so both icons align
vertically within the input.
- Around line 302-311: The clear button currently uses bottom-2.5 which
misaligns it with the input; update the JSX for the clear button (the button
rendered when searchQuery is truthy, using setSearchQuery and the X icon) to use
vertical centering like the search icon: replace the absolute positioning
classes (bottom-2.5) with top-1/2 and add -translate-y-1/2 so the button
vertically centers relative to the input container; ensure the container remains
position:relative so the absolute centering applies.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a0e29a4e-2573-49dc-9415-9c560fe9a98b

📥 Commits

Reviewing files that changed from the base of the PR and between 8bb3204 and b0456f8.

📒 Files selected for processing (1)
  • web/src/pages/setup/TemplateStep.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Dashboard Test
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones. When a component is needed that is not in the existing inventory, place it in web/src/components/ui/ with a descriptive kebab-case filename, create a .stories.tsx file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors. Never hardcode hex values or rgba() with hardcoded values in .tsx/.ts files.
Use font-sans or font-mono classes for typography (mapping to Geist tokens). Never set fontFamily directly in component code.
Use density-aware tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.
Use token variables (var(--so-shadow-card-hover), border-border, border-bright) for shadows and borders. Never hardcode shadow or border values.
TypeScript 6.0: remove deprecated baseUrl from tsconfig; paths entries are relative to the tsconfig directory. Remove explicit "esModuleInterop": true (always true in TS 6). List needed types explicitly (e.g., "types": ["vitest/globals"]). DOM.Iterable is merged into DOM. Use "bundler" or "nodenext" for moduleResolution.

Files:

  • web/src/pages/setup/TemplateStep.tsx
web/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Do NOT recreate status dots inline—use <StatusBadge>. Do NOT build card-with-header layouts from scratch—use <SectionCard>. Do NOT create metric displays with text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map() — extract to a shared component.

Files:

  • web/src/pages/setup/TemplateStep.tsx
🧠 Learnings (6)
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/components/ui/**/*.tsx : Each new shared component in `web/src/components/ui/` must have a corresponding `.stories.tsx` file with all states (default, hover, loading, error, empty). Export props as a TypeScript interface and use design tokens exclusively (no hardcoded colors, fonts, or spacing).

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing for layout. Never hardcode pixel values for layout spacing.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-*)`) for colors. Never hardcode hex values or rgba() with hardcoded values in `.tsx`/`.ts` files.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use token variables (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`) for shadows and borders. Never hardcode shadow or border values.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to web/src/**/*.tsx : Do NOT recreate status dots inline—use `<StatusBadge>`. Do NOT build card-with-header layouts from scratch—use `<SectionCard>`. Do NOT create metric displays with `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()` — extract to a shared component.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
📚 Learning: 2026-03-28T21:29:12.755Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T21:29:12.755Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. When a component is needed that is not in the existing inventory, place it in `web/src/components/ui/` with a descriptive kebab-case filename, create a `.stories.tsx` file with all states, export props as a TypeScript interface, and use design tokens exclusively.

Applied to files:

  • web/src/pages/setup/TemplateStep.tsx
🔇 Additional comments (11)
web/src/pages/setup/TemplateStep.tsx (11)

1-17: LGTM!

Imports are well-organized, appropriately scoped, and correctly reuse existing UI components (InputField, SelectField) from the shared component library.


27-43: LGTM!

The SizeFilter type and SIZE_OPTIONS constant are well-typed, and matchesSize correctly implements the agent-count bucket logic with proper boundary handling.


45-69: LGTM!

Clean extraction of card rendering into a dedicated component, following the guideline to avoid complex JSX inside .map().


71-102: LGTM!

The TemplateGrid component correctly uses density-aware tokens (gap-grid-gap) and properly wires selection and compare handlers to child cards.


122-128: LGTM!

The hasFetchedRef guard correctly prevents refetch loops when an empty templates array is a valid response, addressing the prior review concern.


153-166: LGTM!

availableCategories correctly filters to only categories present in templates while maintaining the canonical order from CATEGORY_ORDER.


187-197: LGTM!

The step completion effect correctly validates against the full templates array (not filteredTemplates) and guards against the loading state, ensuring wizard progress isn't affected by transient filter changes.


213-244: LGTM!

Handlers are properly memoized with correct dependencies, and the compare-limit toast provides clear user feedback.


248-279: LGTM!

Loading, error, and empty states are handled cleanly, reusing the EmptyState component and maintaining consistent grid layout in the skeleton.


363-398: LGTM!

The recommended and other templates sections are cleanly structured with appropriate conditional rendering, and the TemplateGrid component is properly reused for both sections.


400-409: LGTM!

The TemplateCompareDrawer is correctly wired with proper handlers for selection and removal, opening only when at least 2 templates are being compared.

…ntering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo merged commit 7f04676 into main Mar 29, 2026
10 of 12 checks passed
@Aureliolo Aureliolo deleted the feat/improve-ux-setup-wizard branch March 29, 2026 09:56
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 29, 2026 09:56 — with GitHub Actions Inactive
Aureliolo added a commit that referenced this pull request Mar 30, 2026
🤖 I have created a release *beep* *boop*
---
#MAJOR CHANGES; We got a somewhat working webui :)

##
[0.5.0](v0.4.9...v0.5.0)
(2026-03-30)


### Features

* add analytics trends and budget forecast API endpoints
([#798](#798))
([16b61f5](16b61f5))
* add department policies to default templates
([#852](#852))
([7a41548](7a41548))
* add remaining activity event types (task_started, tool_used,
delegation, cost_incurred)
([#832](#832))
([4252fac](4252fac))
* agent performance, activity, and history API endpoints
([#811](#811))
([9b75c1d](9b75c1d))
* Agent Profiles and Detail pages (biography, career, performance)
([#874](#874))
([62d7880](62d7880))
* app shell, Storybook, and CI/CD pipeline
([#819](#819))
([d4dde90](d4dde90))
* Approvals page with risk grouping, urgency indicators, batch actions
([#889](#889))
([4e9673d](4e9673d))
* Budget Panel page (P&L dashboard, breakdown charts, forecast)
([#890](#890))
([b63b0f1](b63b0f1))
* build infrastructure layer (API client, auth, WebSocket)
([#815](#815))
([9f01d3e](9f01d3e))
* CLI global options infrastructure, UI modes, exit codes, env vars
([#891](#891))
([fef4fc5](fef4fc5))
* CodeMirror editor and theme preferences toggle
([#905](#905),
[#807](#807))
([#909](#909))
([41fbedc](41fbedc))
* Company page (department/agent management)
([#888](#888))
([cfb88b0](cfb88b0))
* comprehensive hint coverage across all CLI commands
([#900](#900))
([937974e](937974e))
* config system extensions, per-command flags for
init/start/stop/status/logs
([#895](#895))
([32f83fe](32f83fe))
* configurable currency system replacing hardcoded USD
([#854](#854))
([b372551](b372551))
* Dashboard page (metric cards, activity feed, budget burn)
([#861](#861))
([7d519d5](7d519d5))
* department health, provider status, and activity feed endpoints
([#818](#818))
([6d5f196](6d5f196))
* design tokens and core UI components
([#833](#833))
([ed887f2](ed887f2))
* extend approval, meeting, and budget API responses
([#834](#834))
([31472bf](31472bf))
* frontend polish -- real-time UX, accessibility, responsive,
performance ([#790](#790),
[#792](#792),
[#791](#791),
[#793](#793))
([#917](#917))
([f04a537](f04a537))
* implement human roles and access control levels
([#856](#856))
([d6d8a06](d6d8a06))
* implement semantic conflict detection in workspace merge
([#860](#860))
([d97283b](d97283b))
* interaction components and animation patterns
([#853](#853))
([82d4b01](82d4b01))
* Login page + first-run bootstrap + Company page
([#789](#789),
[#888](#888))
([#896](#896))
([8758e8d](8758e8d))
* Meetings page with timeline viz, token bars, contribution formatting
([#788](#788))
([#904](#904))
([b207f46](b207f46))
* Messages page with threading, channel badges, sender indicators
([#787](#787))
([#903](#903))
([28293ad](28293ad))
* Org Chart force-directed view and drag-drop reassignment
([#872](#872),
[#873](#873))
([#912](#912))
([a68a938](a68a938))
* Org Chart page (living nodes, status, CRUD, department health)
([#870](#870))
([0acbdae](0acbdae))
* per-command flags for remaining commands, auto-behavior wiring,
help/discoverability
([#897](#897))
([3f7afa2](3f7afa2))
* Providers page with backend rework -- health, CRUD, subscription auth
([#893](#893))
([9f8dd98](9f8dd98))
* scaffold React + Vite + TypeScript + Tailwind project
([#799](#799))
([bd151aa](bd151aa))
* Settings page with search, dependency indicators, grouped rendering
([#784](#784))
([#902](#902))
([a7b9870](a7b9870))
* Setup Wizard rebuild with template comparison, cost estimator, theme
customization ([#879](#879))
([ae8b50b](ae8b50b))
* setup wizard UX -- template filters, card metadata, provider form
reuse ([#910](#910))
([7f04676](7f04676))
* setup wizard UX overhaul -- mode choice, step reorder, provider fixes
([#907](#907))
([ee964c4](ee964c4))
* structured ModelRequirement in template agent configs
([#795](#795))
([7433548](7433548))
* Task Board page (rich Kanban, filtering, dependency viz)
([#871](#871))
([04a19b0](04a19b0))


### Bug Fixes

* align frontend types with backend and debounce WS refetches
([#916](#916))
([134c11b](134c11b))
* auto-cleanup targets newly pulled images instead of old ones
([#884](#884))
([50e6591](50e6591))
* correct wipe backup-skip flow and harden error handling
([#808](#808))
([c05860f](c05860f))
* improve provider setup in wizard, subscription auth, dashboard bugs
([#914](#914))
([87bf8e6](87bf8e6))
* improve update channel detection and add config get command
([#814](#814))
([6b137f0](6b137f0))
* resolve all ESLint warnings, add zero-warnings enforcement
([#899](#899))
([079b46a](079b46a))
* subscription auth uses api_key, base URL optional for cloud providers
([#915](#915))
([f0098dd](f0098dd))


### Refactoring

* semantic analyzer cleanup -- shared filtering, concurrency, extraction
([#908](#908))
([81372bf](81372bf))


### Documentation

* brand identity and UX design system from
[#765](#765) exploration
([#804](#804))
([389a9f4](389a9f4))
* page structure and information architecture for v0.5.0 dashboard
([#809](#809))
([f8d6d4a](f8d6d4a))
* write UX design guidelines with WCAG-verified color system
([#816](#816))
([4a4594e](4a4594e))


### Tests

* add unit tests for agent hooks and page components
([#875](#875))
([#901](#901))
([1d81546](1d81546))


### CI/CD

* bump actions/deploy-pages from 4.0.5 to 5.0.0 in the major group
([#831](#831))
([01c19de](01c19de))
* bump astral-sh/setup-uv from 7.6.0 to 8.0.0 in
/.github/actions/setup-python-uv in the all group
([#920](#920))
([5f6ba54](5f6ba54))
* bump codecov/codecov-action from 5.5.3 to 6.0.0 in the major group
([#868](#868))
([f22a181](f22a181))
* bump github/codeql-action from 4.34.1 to 4.35.0 in the all group
([#883](#883))
([87a4890](87a4890))
* bump sigstore/cosign-installer from 4.1.0 to 4.1.1 in the
minor-and-patch group
([#830](#830))
([7a69050](7a69050))
* bump the all group with 3 updates
([#923](#923))
([ff27c8e](ff27c8e))
* bump wrangler from 4.76.0 to 4.77.0 in /.github in the minor-and-patch
group ([#822](#822))
([07d43eb](07d43eb))
* bump wrangler from 4.77.0 to 4.78.0 in /.github in the all group
([#882](#882))
([f84118d](f84118d))


### Maintenance

* add design system enforcement hook and component inventory
([#846](#846))
([15abc43](15abc43))
* add dev-only auth bypass for frontend testing
([#885](#885))
([6cdcd8a](6cdcd8a))
* add pre-push rebase check hook
([#855](#855))
([b637a04](b637a04))
* backend hardening -- eviction/size-caps and model validation
([#911](#911))
([81253d9](81253d9))
* bump axios from 1.13.6 to 1.14.0 in /web in the all group across 1
directory ([#922](#922))
([b1b0232](b1b0232))
* bump brace-expansion from 5.0.4 to 5.0.5 in /web
([#862](#862))
([ba4a565](ba4a565))
* bump eslint-plugin-react-refresh from 0.4.26 to 0.5.2 in /web
([#801](#801))
([7574bb5](7574bb5))
* bump faker from 40.11.0 to 40.11.1 in the minor-and-patch group
([#803](#803))
([14d322e](14d322e))
* bump https://github.com/astral-sh/ruff-pre-commit from v0.15.7 to
0.15.8 ([#864](#864))
([f52901e](f52901e))
* bump nginxinc/nginx-unprivileged from `6582a34` to `f99cc61` in
/docker/web in the all group
([#919](#919))
([df85e4f](df85e4f))
* bump nginxinc/nginx-unprivileged from `ccbac1a` to `6582a34` in
/docker/web ([#800](#800))
([f4e9450](f4e9450))
* bump node from `44bcbf4` to `71be405` in /docker/sandbox
([#827](#827))
([91bec67](91bec67))
* bump node from `5209bca` to `cf38e1f` in /docker/web
([#863](#863))
([66d6043](66d6043))
* bump picomatch in /site
([#842](#842))
([5f20bcc](5f20bcc))
* bump recharts 2-&gt;3 and @types/node 22-&gt;25 in /web
([#802](#802))
([a908800](a908800))
* Bump requests from 2.32.5 to 2.33.0
([#843](#843))
([41daf69](41daf69))
* bump smol-toml from 1.6.0 to 1.6.1 in /site
([#826](#826))
([3e5dbe4](3e5dbe4))
* bump the all group with 3 updates
([#921](#921))
([7bace0b](7bace0b))
* bump the minor-and-patch group across 1 directory with 2 updates
([#829](#829))
([93e611f](93e611f))
* bump the minor-and-patch group across 1 directory with 3 updates
([#841](#841))
([7010c8e](7010c8e))
* bump the minor-and-patch group across 1 directory with 3 updates
([#869](#869))
([548cee5](548cee5))
* bump the minor-and-patch group in /site with 2 updates
([#865](#865))
([9558101](9558101))
* bump the minor-and-patch group with 2 updates
([#867](#867))
([4830706](4830706))
* consolidate Dependabot groups to 1 PR per ecosystem
([06d2556](06d2556))
* consolidate Dependabot groups to 1 PR per ecosystem
([#881](#881))
([06d2556](06d2556))
* improve worktree skill with full dep sync and status enhancements
([#906](#906))
([772c625](772c625))
* remove Vue remnants and document framework decision
([#851](#851))
([bf2adf6](bf2adf6))
* update web dependencies and fix brace-expansion CVE
([#880](#880))
([a7a0ed6](a7a0ed6))
* upgrade to Storybook 10 and TypeScript 6
([#845](#845))
([52d95f2](52d95f2))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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