feat: populate comparison page with 53 competitor entries#1000
feat: populate comparison page with 53 competitor entries#1000
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughUpdated FAQ content: revised comparison answers, explicit "Not yet" production status plus upgrade criteria, BUSL-1.1 licensing FAQ (auto-converts to Apache 2.0 after three years), commercial managed-agent trade-offs, accuracy/research methodology, and added structured-logging redaction wording. Added 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure 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 FilesNone |
There was a problem hiding this comment.
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 `@site/src/components/ComparisonFAQ.astro`:
- Around line 27-30: Update the FAQ entry in ComparisonFAQ.astro that has
question "What license is SynthOrg under and what does it mean?" so it correctly
states the conversion mechanism and current change date: replace the hardcoded
line "converts to Apache 2.0 on February 27, 2030" with text explaining that
each released version converts to Apache 2.0 automatically three years after its
individual release, and note the current version's Change Date is April 2, 2029
(as in LICENSE); keep examples for small orgs but remove the single fixed
conversion date claim so future releases can have different conversion dates.
🪄 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: b916e32a-39fe-4e78-91b5-9bac0fd7627f
📒 Files selected for processing (2)
data/competitors.yamlsite/src/components/ComparisonFAQ.astro
📜 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: Deploy Preview
- GitHub Check: Agent
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T13:12:42.085Z
Learning: Comparison data: `data/competitors.yaml` -- shared YAML source for `docs/reference/comparison.md` (generated by `scripts/generate_comparison.py`) and `site/src/pages/compare.astro`
📚 Learning: 2026-04-02T13:12:42.085Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T13:12:42.085Z
Learning: Comparison data: `data/competitors.yaml` -- shared YAML source for `docs/reference/comparison.md` (generated by `scripts/generate_comparison.py`) and `site/src/pages/compare.astro`
Applied to files:
site/src/components/ComparisonFAQ.astro
🔇 Additional comments (3)
site/src/components/ComparisonFAQ.astro (3)
24-26: LGTM!The FAQ presents a balanced view of commercial platform trade-offs (managed infrastructure vs. vendor lock-in) and honestly acknowledges when native platforms may be the pragmatic choice.
31-38: LGTM!Both FAQs are well-crafted:
- The accuracy methodology FAQ is transparent about research process and invites corrections
- The production readiness explanation aligns with
data/competitors.yamlentry (pre-alpha, API unstable, no production deployments) and demonstrates intellectual honesty over marketing
5-5: No issues found. The statement that "AutoGen is now in maintenance mode as Microsoft merges it into the Agent Framework" is accurate and properly reflects the project's current status based on official Microsoft communications and the AutoGen GitHub repository.
There was a problem hiding this comment.
Code Review
This pull request updates the FAQ component to provide more nuanced comparisons with other agent frameworks and adds new sections regarding commercial platforms, licensing, and production readiness. Feedback identifies branding and terminology inaccuracies regarding Agentforce and the source-available nature of the BUSL-1.1 license. Additionally, it is noted that the claim about a last updated date is currently inaccurate as the metadata is not rendered, and one new FAQ entry is redundant with existing content.
| question: "What about commercial platforms like Bedrock, Vertex, or AgentForce?", | ||
| answer: "Cloud platforms like Amazon Bedrock Agents, Google Vertex AI Agent Builder, and Salesforce AgentForce offer managed infrastructure, enterprise compliance, and deep ecosystem integration. The trade-off is vendor lock-in and less control. SynthOrg is self-hosted and open-source (BUSL-1.1), giving you full control over your infrastructure, data, and agent behavior -- but you manage the ops yourself. If your organization already lives in AWS, GCP, or Salesforce, their native agent platform may be the pragmatic choice.", |
There was a problem hiding this comment.
There are two minor inaccuracies in this entry:
- Branding: Salesforce's platform is branded as Agentforce (lowercase 'f'), which is correctly reflected in the YAML data but capitalized as 'AgentForce' here.
- Terminology: The BUSL-1.1 license is technically "source-available" rather than "open-source" due to its commercial use restrictions. Given the PR's emphasis on "honesty over marketing," using the precise term is recommended.
question: "What about commercial platforms like Bedrock, Vertex, or Agentforce?",
answer: "Cloud platforms like Amazon Bedrock Agents, Google Vertex AI Agent Builder, and Salesforce Agentforce offer managed infrastructure, enterprise compliance, and deep ecosystem integration. The trade-off is vendor lock-in and less control. SynthOrg is self-hosted and source-available (BUSL-1.1), giving you full control over your infrastructure, data, and agent behavior -- but you manage the ops yourself. If your organization already lives in AWS, GCP, or Salesforce, their native agent platform may be the pragmatic choice.",
| }, | ||
| { | ||
| question: "Is this comparison data accurate?", | ||
| answer: "We research each competitor by reviewing their official documentation, GitHub repository, and recent release notes. Evaluations follow a consistent rubric (full, partial, planned, none) applied equally to SynthOrg and every competitor. That said, frameworks evolve quickly and we may occasionally lag behind. If you spot an inaccuracy, please open a GitHub issue -- we will correct it promptly. Last updated date is shown at the top of the comparison.", |
There was a problem hiding this comment.
The FAQ states that the "Last updated date is shown at the top of the comparison," but the site/src/pages/compare.astro page does not currently pass the last_updated metadata from the YAML to any component for rendering. This sentence should be removed, or the page should be updated to actually display the date.
answer: "We research each competitor by reviewing their official documentation, GitHub repository, and recent release notes. Evaluations follow a consistent rubric (full, partial, planned, none) applied equally to SynthOrg and every competitor. That said, frameworks evolve quickly and we may occasionally lag behind. If you spot an inaccuracy, please open a GitHub issue -- we will correct it promptly.",
| { | ||
| question: "Why does SynthOrg show 'partial' for production readiness?", | ||
| answer: "Honesty matters more than marketing. SynthOrg has Docker images (Chainguard distroless), CI/CD with cosign signing and SLSA provenance, backup/restore, and structured logging with redaction. But the API is not yet stable (pre-alpha), there are no known production deployments, and the framework has not been battle-tested at scale. We will upgrade to 'full' when those conditions are met.", | ||
| }, |
There was a problem hiding this comment.
There was a problem hiding this comment.
Pull request overview
Populates the comparison dataset used by both the docs generator (scripts/generate_comparison.py) and the Astro comparison page, and updates the Comparison FAQ content to reflect a more balanced positioning.
Changes:
- Replaces the small proof-of-concept competitor list with a much larger, categorized set of competitor entries in
data/competitors.yaml, including newpricingandself_hostedmetadata fields. - Updates
ComparisonFAQ.astrowith new/rewritten FAQs (commercial platforms, licensing, methodology, production readiness).
Reviewed changes
Copilot reviewed 1 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
data/competitors.yaml |
Expands the comparison dataset substantially; adds pricing and self_hosted; updates SynthOrg notes and adds many competitor entries. |
site/src/components/ComparisonFAQ.astro |
Rewrites/extends FAQ answers to be more nuanced and adds licensing/methodology/production-readiness FAQs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| answer: "Cloud platforms like Amazon Bedrock Agents, Google Vertex AI Agent Builder, and Salesforce AgentForce offer managed infrastructure, enterprise compliance, and deep ecosystem integration. The trade-off is vendor lock-in and less control. SynthOrg is self-hosted and open-source (BUSL-1.1), giving you full control over your infrastructure, data, and agent behavior -- but you manage the ops yourself. If your organization already lives in AWS, GCP, or Salesforce, their native agent platform may be the pragmatic choice.", | ||
| }, | ||
| { | ||
| question: "What license is SynthOrg under and what does it mean?", | ||
| answer: "SynthOrg uses the Business Source License 1.1 (BUSL-1.1). You can freely use it in production for any purpose that does not compete with SynthOrg as a product. Small organizations building internal tools, automations, or custom agents are free to use it without restriction. The license converts to Apache 2.0 on February 27, 2030, at which point it becomes fully permissive with no conditions.", |
There was a problem hiding this comment.
The FAQ describes SynthOrg as “open-source (BUSL-1.1)” and hardcodes an Apache-2.0 conversion date (Feb 27, 2030), but the repository’s licensing docs explicitly describe BSL 1.1 as “source available” (not OSI open source) and the current LICENSE Change Date is April 2, 2029. Please align this answer with LICENSE/docs/licensing.md (ideally avoid hardcoding a date that can drift).
| answer: "Cloud platforms like Amazon Bedrock Agents, Google Vertex AI Agent Builder, and Salesforce AgentForce offer managed infrastructure, enterprise compliance, and deep ecosystem integration. The trade-off is vendor lock-in and less control. SynthOrg is self-hosted and open-source (BUSL-1.1), giving you full control over your infrastructure, data, and agent behavior -- but you manage the ops yourself. If your organization already lives in AWS, GCP, or Salesforce, their native agent platform may be the pragmatic choice.", | |
| }, | |
| { | |
| question: "What license is SynthOrg under and what does it mean?", | |
| answer: "SynthOrg uses the Business Source License 1.1 (BUSL-1.1). You can freely use it in production for any purpose that does not compete with SynthOrg as a product. Small organizations building internal tools, automations, or custom agents are free to use it without restriction. The license converts to Apache 2.0 on February 27, 2030, at which point it becomes fully permissive with no conditions.", | |
| answer: "Cloud platforms like Amazon Bedrock Agents, Google Vertex AI Agent Builder, and Salesforce AgentForce offer managed infrastructure, enterprise compliance, and deep ecosystem integration. The trade-off is vendor lock-in and less control. SynthOrg is self-hosted and distributed under a source-available Business Source License 1.1 (BUSL-1.1), giving you full control over your infrastructure, data, and agent behavior -- but you manage the ops yourself. If your organization already lives in AWS, GCP, or Salesforce, their native agent platform may be the pragmatic choice.", | |
| }, | |
| { | |
| question: "What license is SynthOrg under and what does it mean?", | |
| answer: "SynthOrg uses the Business Source License 1.1 (BUSL-1.1), a source-available license. You can freely use it in production for any purpose that does not compete with SynthOrg as a product. Small organizations building internal tools, automations, or custom agents are generally free to use it without restriction. After the Change Date specified in the LICENSE file, the code is scheduled to be made available under the Apache License 2.0, at which point it becomes fully permissive with no additional license-specific conditions.", |
data/competitors.yaml
Outdated
| - name: "LangSmith" | ||
| slug: langsmith | ||
| url: "https://smith.langchain.com" | ||
| repo: "none" |
There was a problem hiding this comment.
repo: "none" is a non-empty string, so scripts/generate_comparison.py will treat it as a real repo URL and emit a broken [Repository](none) link in the generated “Project Links” section. Omit repo or set it to an empty string/null when there is no repository.
| repo: "none" | |
| repo: "" |
| - name: "Amazon Bedrock Agents" | ||
| slug: bedrock-agents | ||
| url: "https://aws.amazon.com/bedrock/agents/" | ||
| repo: "none" | ||
| description: "AWS managed service for building and orchestrating autonomous AI agents on serverless infrastructure" |
There was a problem hiding this comment.
repo: "none" is a non-empty string, so scripts/generate_comparison.py will include it as a repository link ([Repository](none)) in the generated docs. Please remove the repo key (or make it empty) for SaaS-only entries without a public repo.
data/competitors.yaml
Outdated
| - name: "Relevance AI" | ||
| slug: relevance-ai | ||
| url: "https://relevanceai.com" | ||
| repo: "none" |
There was a problem hiding this comment.
repo: "none" is truthy and will render as a broken repository link ([Repository](none)) in docs generation. Prefer omitting repo (or setting it to empty) when no GitHub repo exists.
| repo: "none" | |
| repo: "" |
data/competitors.yaml
Outdated
| description: "TypeScript framework for multi-agent networks with state-based routing and durable execution" | ||
| license: "Apache-2.0" | ||
| language: "TypeScript" | ||
| category: multi_agent_framework |
There was a problem hiding this comment.
This entry is under the # Workflow Engines section header, but its category is multi_agent_framework. For readability/maintenance, either move it into the Multi-Agent Frameworks section or change its category so headings and category keys stay consistent.
| category: multi_agent_framework | |
| category: workflow_engine |
- Add 53 competitor entries across 7 categories (multi-agent frameworks, virtual org simulators, workflow engines, commercial platforms, developer tools, research projects, protocols/standards) - Add pricing and self_hosted metadata fields to every entry - Update SynthOrg entry with honest production_ready and memory notes - Update FAQs: soften CrewAI/AutoGen comparison, add license/commercial platform/data accuracy/production honesty FAQs, remove generic FAQ Each entry has all 14 dimensions evaluated against a consistent rubric (full/partial/planned/none) with sourced notes. Web-searched each competitor for current capabilities. Closes #993
- SynthOrg always visible regardless of active filters (pinned) - SynthOrg category changed to virtual_org (was multi_agent_framework) - SynthOrg CLI changed to partial (container management only) - Column visibility toggles: hide/show any dimension column - Full-width/maximize toggle (fixed overlay, disabled by default) - Scroll hint: pulsing arrow overlay when table overflows right - Toolbar with column picker dropdown and expand button
…, and Copilot - Fix license terminology: 'open-source' -> 'source-available' (BUSL-1.1) - Fix license conversion date (April 2, 2029) and per-version mechanism - Fix Agentforce branding (lowercase f) - Remove broken repo: 'none' on 3 commercial entries (LangSmith, Bedrock, Relevance AI) - Add pricing and self_hosted fields to ComparisonTable.tsx interface - Add Pricing and Self-Hosted columns to generate_comparison.py - Downgrade SynthOrg memory from full to partial (sole Mem0 backend) - Fix autonomy tier count: 5 -> 4 - Fix template note: 9 archetypes -> 9 templates, 23 presets, 5 packs - Remove 'last updated shown at top' claim from FAQ (not rendered) - Merge redundant production-readiness FAQs - Move Inngest AgentKit to Multi-Agent Frameworks section (matches category)
b92fad0 to
11dcf15
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
site/src/components/islands/ComparisonTable.tsx (1)
165-194: 🧹 Nitpick | 🔵 TrivialSynthOrg bypasses all filters — verify this is intentional.
SynthOrg is always included in results regardless of category, license, feature, or search filters. This appears intentional for the comparison page, but could surprise users who expect uniform filter behavior.
Consider adding a visual indicator or tooltip explaining that SynthOrg is always shown for comparison purposes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@site/src/components/islands/ComparisonTable.tsx` around lines 165 - 194, The current filtering (inside useMemo computing filtered in ComparisonTable) intentionally bypasses all filters for items with c.is_synthorg, which can confuse users; leave the filter behavior as-is but add a clear visual indicator (badge and hover tooltip) when rendering rows/items from the filtered array where c.is_synthorg is true so users know "SynthOrg is always shown for comparison"; update the rendering of the filtered list to check c.is_synthorg and attach an accessible badge/tooltip explaining the exception.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@site/src/components/islands/ComparisonTable.css`:
- Around line 255-258: The ct-scroll-pulse keyframes continue animating for
users who prefer reduced motion; add a prefers-reduced-motion override that
disables or neutralizes this animation: create an `@media`
(prefers-reduced-motion: reduce) block that either sets animation: none (or
animation-name: none) on the selectors that use ct-scroll-pulse and/or redefines
`@keyframes` ct-scroll-pulse to a no-op, and apply the same change for the other
ct-scroll-pulse occurrences noted (lines ~630-634) so the pulse stops when
reduced motion is requested.
In `@site/src/components/islands/ComparisonTable.tsx`:
- Around line 415-432: Add an Escape key handler so users can exit full-width
mode with the keyboard: when the fullWidth state is true (in the ComparisonTable
component) register a keydown listener (e.g., in a useEffect) that calls
setFullWidth(false) when event.key === "Escape", and remove the listener when
fullWidth becomes false or the component unmounts; ensure the listener is
added/removed only while fullWidth is true to avoid leaking handlers or
interfering with other keyboard shortcuts.
- Around line 392-413: The column picker never closes on outside clicks; add a
ref (e.g., pickerRef) to the ct-column-picker container inside the
ComparisonTable component and register a document mousedown/touchstart handler
in a useEffect that calls setShowColumnPicker(false) when the event target is
not contained in pickerRef.current (and optionally when Escape is pressed), and
remove the listener on cleanup; update the JSX to attach the ref to the div with
className "ct-column-picker" so clicks outside properly close the picker.
---
Outside diff comments:
In `@site/src/components/islands/ComparisonTable.tsx`:
- Around line 165-194: The current filtering (inside useMemo computing filtered
in ComparisonTable) intentionally bypasses all filters for items with
c.is_synthorg, which can confuse users; leave the filter behavior as-is but add
a clear visual indicator (badge and hover tooltip) when rendering rows/items
from the filtered array where c.is_synthorg is true so users know "SynthOrg is
always shown for comparison"; update the rendering of the filtered list to check
c.is_synthorg and attach an accessible badge/tooltip explaining the exception.
🪄 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: 7abd3392-92bd-4d1f-aa64-b7df613c7c62
📒 Files selected for processing (5)
data/competitors.yamlscripts/generate_comparison.pysite/src/components/ComparisonFAQ.astrosite/src/components/islands/ComparisonTable.csssite/src/components/islands/ComparisonTable.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). (2)
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Do NOT usefrom __future__ import annotations-- Python 3.14 has PEP 649
Useexcept A, B:syntax (no parentheses) for exception handling -- PEP 758 except syntax, enforced by ruff on Python 3.14
All public functions must have type hints; enforce with mypy strict mode
Use Google-style docstrings, required on public classes and functions; enforced by ruff D rules
Create new objects for immutability; never mutate existing objects. For non-Pydantic internal collections (registries,BaseTool), usecopy.deepcopy()at construction plusMappingProxyTypewrapping for read-only enforcement
Fordict/listfields in frozen Pydantic models, usecopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization)
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models (usingmodel_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model
Use Pydantic v2 (BaseModel,model_validator,computed_field,ConfigDict); adoptallow_inf_nan=Falsein allConfigDictdeclarations to rejectNaN/Infin numeric fields at validation time
Use@computed_fieldfor derived values instead of storing and validating redundant fields (e.g.,TokenUsage.total_tokens)
UseNotBlankStr(fromcore.types) for all identifier and name fields -- including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants -- instead of manual whitespace validators
Preferasyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls); prefer structured concurrency over barecreate_task
Maintain line length of 88 characters; enforced by ruff
Functions must be less than 50 lines; files must be less than 800 lines
Handle errors explicitly; never silently swallow exceptions
Validate at system boundaries (user input, external APIs, conf...
Files:
scripts/generate_comparison.py
scripts/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Scripts in
scripts/-- CI/build utilities with relaxed ruff rules allowing
Files:
scripts/generate_comparison.py
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T13:12:42.085Z
Learning: Comparison data: `data/competitors.yaml` -- shared YAML source for `docs/reference/comparison.md` (generated by `scripts/generate_comparison.py`) and `site/src/pages/compare.astro`
📚 Learning: 2026-04-02T13:12:42.085Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T13:12:42.085Z
Learning: Comparison data: `data/competitors.yaml` -- shared YAML source for `docs/reference/comparison.md` (generated by `scripts/generate_comparison.py`) and `site/src/pages/compare.astro`
Applied to files:
scripts/generate_comparison.pysite/src/components/ComparisonFAQ.astrosite/src/components/islands/ComparisonTable.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: Applies to {src,tests,web,cli,site}/**/*.{py,ts,tsx,go,astro} : Vendor-agnostic everywhere: NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001. Vendor names may only appear in: (1) Operations design page provider list (docs/design/operations.md), (2) .claude/ skill/agent files, (3) third-party import paths/module names.
Applied to files:
site/src/components/ComparisonFAQ.astro
📚 Learning: 2026-04-02T13:12:42.085Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T13:12:42.085Z
Learning: Applies to src/synthorg/**/*.py : NEVER use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples; use generic names like `example-provider`, `example-large-001`, `example-medium-001`, `large`/`medium`/`small` aliases; vendor names allowed only in: (1) Operations design page (`docs/design/operations.md`), (2) `.claude/` skill/agent files, (3) third-party import paths, (4) provider presets (`src/synthorg/providers/presets.py`); tests must use `test-provider`, `test-small-001`
Applied to files:
site/src/components/ComparisonFAQ.astro
📚 Learning: 2026-04-02T12:19:36.876Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: web/CLAUDE.md:0-0
Timestamp: 2026-04-02T12:19:36.876Z
Learning: Applies to web/src/components/ui/*.{ts,tsx} : Export component props as a TypeScript interface in new shared components
Applied to files:
site/src/components/islands/ComparisonTable.tsx
🔇 Additional comments (12)
scripts/generate_comparison.py (3)
256-265: LGTM!The header and separator rows correctly include the new Pricing and Self-Hosted columns with appropriate alignment (left for text labels, centered for icons).
32-39: LGTM!The
PRICING_LABELSmapping provides clear display labels for all pricing values mentioned in the PR objectives with a sensible fallback.
42-46: The implementation is correct. Allself_hostedvalues incompetitors.yamlare quoted strings ("true","false","partial"), which match the string keys inSELF_HOSTED_LABELS. The lookup will work as intended without any type mismatch.site/src/components/islands/ComparisonTable.css (2)
216-224: LGTM!The full-width overlay styling correctly uses fixed positioning with appropriate z-index and scroll handling.
157-214: LGTM!The column picker dropdown styling is well-structured with proper positioning, hover states, and accessibility considerations (accent-color for checkboxes).
site/src/components/ComparisonFAQ.astro (3)
27-30: License FAQ now correctly describes the conversion mechanism.The updated answer properly explains that each version converts to Apache 2.0 three years after its release, and correctly states April 2, 2029 as the current version's Change Date.
11-14: LGTM!The production-readiness FAQ is transparent about current status ("Not yet"), explains the "partial" rating, and sets clear criteria for "full" production readiness.
31-34: LGTM!The accuracy methodology FAQ aligns with the PR objectives and establishes trust by describing the research process and inviting corrections.
site/src/components/islands/ComparisonTable.tsx (4)
131-148: LGTM!The scroll hint detection effect properly handles scroll and resize events with correct cleanup. The 4px threshold prevents edge-case flicker.
560-594: LGTM!The detail row correctly spans the visible columns while showing notes for all dimensions (including hidden ones), providing complete information in the expanded view.
614-679: LGTM!Mobile card view correctly displays all dimensions regardless of the column picker state, which is appropriate since the column picker is a desktop table optimization.
33-34: These optional fields are defined but never used in the component.The
Competitorinterface includespricingandself_hostedas optional fields, but they are not rendered or referenced anywhere in the component. Test fixtures also don't include them. Either remove these unused fields or implement their rendering if they were intended to be displayed.> Likely an incorrect or invalid review comment.
…deRabbit - Remove 6 non-competitor entries (3 research, 3 protocol categories) - Move AutoGPT to Workflow Engines section (was misplaced in Research) - Remove 'planned' support value (unused after protocol removal) - Update entry count: 47 entries across 5 categories - Add prefers-reduced-motion override for scroll pulse animation - Add Escape key handler to exit full-width mode - Add outside-click handler to close column picker - Add 'pinned' badge on SynthOrg row when filters are active
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
site/src/components/islands/ComparisonTable.tsx (2)
685-700: 🧹 Nitpick | 🔵 TrivialNote: Mobile card view shows all dimensions regardless of column visibility.
The desktop table respects
visibleDimensions(hidden columns), but the mobile card view (lines 685-700) renders all dimensions. This may be intentional UX (mobile has more vertical space so hiding columns is less necessary), but worth confirming this is the desired behavior.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@site/src/components/islands/ComparisonTable.tsx` around lines 685 - 700, The mobile card rendering currently maps over dimensions unconditionally (in the block using dimensions.map and SupportIcon) which causes hidden columns to still appear on mobile; update that mapping to filter dimensions by the same visibleDimensions set used by the desktop table (e.g., replace dimensions.map(...) with dimensions.filter(d => visibleDimensions.has(d.key) || visibleDimensions.includes(d.key)).map(...)) so the mobile card view respects column visibility (ensure you reference the existing visibleDimensions variable/prop and keep SupportIcon, comp.features and feat?.note usage intact).
20-22:⚠️ Potential issue | 🟡 MinorRemove unused "planned" support value from interface, constants, and legend.
The YAML data no longer uses "planned" as a support value, but the TypeScript code still references it:
FeatureEntry.supportinterface (line 20) includes"planned"SUPPORT_ORDER,SUPPORT_ICONS, andSUPPORT_LABELS(lines 49-68) define "planned" mappings- The legend (lines 334-336) still displays the "Planned" icon
Remove these unused references to keep the code clean.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@site/src/components/islands/ComparisonTable.tsx` around lines 20 - 22, Remove the unused "planned" support value everywhere: update the FeatureEntry.support type to only "full" | "partial" | "none"; remove "planned" from SUPPORT_ORDER, SUPPORT_ICONS, and SUPPORT_LABELS constants (and any associated icon or label entries); and remove the "Planned" item from the legend rendering in ComparisonTable so it no longer references the removed value. Ensure any code that iterates or indexes into these constants (e.g., where SUPPORT_ORDER is used) is still valid after the removal.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@data/competitors.yaml`:
- Around line 696-720: The YAML entries for "Inngest AgentKit", "ControlFlow",
and "Motia" are placed under incorrect human-readable section comments; reorder
each entry to sit under the comment that matches its category value (e.g., move
the "Inngest AgentKit" block so it appears within the Multi Agent Framework
section and move "ControlFlow" and "Motia" into the Workflow Engine section) or
remove/update the surrounding section comment headers so they reflect the actual
items; locate entries by their name fields ("Inngest AgentKit", "ControlFlow",
"Motia") and their category: values to perform the adjustment.
---
Outside diff comments:
In `@site/src/components/islands/ComparisonTable.tsx`:
- Around line 685-700: The mobile card rendering currently maps over dimensions
unconditionally (in the block using dimensions.map and SupportIcon) which causes
hidden columns to still appear on mobile; update that mapping to filter
dimensions by the same visibleDimensions set used by the desktop table (e.g.,
replace dimensions.map(...) with dimensions.filter(d =>
visibleDimensions.has(d.key) || visibleDimensions.includes(d.key)).map(...)) so
the mobile card view respects column visibility (ensure you reference the
existing visibleDimensions variable/prop and keep SupportIcon, comp.features and
feat?.note usage intact).
- Around line 20-22: Remove the unused "planned" support value everywhere:
update the FeatureEntry.support type to only "full" | "partial" | "none"; remove
"planned" from SUPPORT_ORDER, SUPPORT_ICONS, and SUPPORT_LABELS constants (and
any associated icon or label entries); and remove the "Planned" item from the
legend rendering in ComparisonTable so it no longer references the removed
value. Ensure any code that iterates or indexes into these constants (e.g.,
where SUPPORT_ORDER is used) is still valid after the removal.
🪄 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: 61e48bbc-9cdb-41da-86f2-235c80ef983d
📒 Files selected for processing (4)
data/competitors.yamlscripts/generate_comparison.pysite/src/components/islands/ComparisonTable.csssite/src/components/islands/ComparisonTable.tsx
Each dimension checked against open GitHub issues: - full (3): org_structure, task_delegation, template_system -- no open issues - planned (10): multi_agent (#242,#848), memory (#266,#850), tool_use (#212-214), human_in_loop (#847), budget_tracking (#806), security_model (#671,#701), observability (#849), web_dashboard (#247,#979), production_ready (#210), workflow_types (#973,#976) -- open issues working toward full - partial (1): cli -- intentionally scoped to container management
…ility - Remove ControlFlow (archived, merged into Marvin), GPT Pilot (abandoned, pivoted to commercial Pythagora), SuperAGI (abandoned since Jan 2024) - Move Motia to Workflow Engines section (was misplaced after Developer Tools) - Fix mobile card view to respect hidden columns (use visibleDimensions) - Update entry count: 44 competitors + SynthOrg across 5 categories
There was a problem hiding this comment.
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)
data/competitors.yaml (1)
72-86:⚠️ Potential issue | 🟠 MajorDataset scope in file does not match this PR’s stated target.
Line 72 through Line 83 defines 5 categories and Line 85 states 47 entries, but this PR objective targets 54 total entries across 7 categories (including Research and Protocols). Please reconcile the YAML (or PR objective) before merge.
Based on learnings: "Comparison data:
data/competitors.yaml-- shared YAML source fordocs/reference/comparison.md(generated byscripts/generate_comparison.py) andsite/src/pages/compare.astro."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@data/competitors.yaml` around lines 72 - 86, The YAML header is inconsistent with the PR target: update the categories block and summary count so the file matches the intended 54 entries across 7 categories; specifically add the two missing category entries (e.g., keys "research" and "protocols" with appropriate labels) into the categories list and update the comment line "# Competitors (47 entries across 5 categories)" to reflect the correct count and category number (e.g., "# Competitors (54 entries across 7 categories)"), or alternatively if the PR intends 47/5 then remove the extra PR targets — ensure the top-level "categories" list and the summary comment are reconciled with the actual number of competitor entries in the file.
♻️ Duplicate comments (1)
data/competitors.yaml (1)
697-705:⚠️ Potential issue | 🟡 MinorSection headers still don’t match some entry categories.
Line 697 (
Inngest AgentKit) and Line 1304/Line 1330 (ControlFlow,Motia) are still under mismatched human-readable section blocks relative to theircategoryvalues. This is a maintainability/documentation mismatch.Also applies to: 1304-1338
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@data/competitors.yaml` around lines 697 - 705, The YAML file has entries whose human-readable section headers do not match their category fields (e.g., the entries "Inngest AgentKit", "ControlFlow", and "Motia"); update the document so each entry appears under the correct section header that corresponds to its category value (or change the entry's category to match the current section if that was intended). Locate the entries by the name fields "Inngest AgentKit", "ControlFlow", and "Motia" and either move those blocks into the section matching their category (e.g., multi_agent_framework, etc.) or rename the surrounding section headers to reflect the category values, ensuring consistency and keeping YAML indentation and ordering intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@data/competitors.yaml`:
- Around line 106-119: Inline YAML mappings (e.g., org_structure, multi_agent,
task_delegation, memory, tool_use, human_in_loop, budget_tracking,
security_model, observability, web_dashboard, cli, production_ready,
workflow_types, template_system) use extra spaces immediately inside braces and
violate the `braces` lint rule; fix by normalizing each inline mapping to remove
the space after "{" and before "}" (and keep consistent spacing after commas),
e.g. change "{ support: full, note: ... }" to "{support: full, note: ...}" for
every occurrence in the file.
In `@scripts/generate_comparison.py`:
- Around line 226-230: The code currently masks missing/invalid pricing and
self_hosted fields by defaulting to empty strings; update the validation in the
block that reads pricing_raw = comp.get("pricing", "") and self_hosted_raw =
comp.get("self_hosted", "") so it fails fast: require these keys exist (do not
default to ""), verify the values are members of PRICING_LABELS and
SELF_HOSTED_LABELS respectively, and raise a clear exception (e.g., ValueError)
with the competitor identifier when missing or when the value is not an allowed
enum; keep using PRICING_LABELS.get(...) / SELF_HOSTED_LABELS.get(...) only
after validation so the code doesn’t silently accept invalid inputs.
---
Outside diff comments:
In `@data/competitors.yaml`:
- Around line 72-86: The YAML header is inconsistent with the PR target: update
the categories block and summary count so the file matches the intended 54
entries across 7 categories; specifically add the two missing category entries
(e.g., keys "research" and "protocols" with appropriate labels) into the
categories list and update the comment line "# Competitors (47 entries across 5
categories)" to reflect the correct count and category number (e.g., "#
Competitors (54 entries across 7 categories)"), or alternatively if the PR
intends 47/5 then remove the extra PR targets — ensure the top-level
"categories" list and the summary comment are reconciled with the actual number
of competitor entries in the file.
---
Duplicate comments:
In `@data/competitors.yaml`:
- Around line 697-705: The YAML file has entries whose human-readable section
headers do not match their category fields (e.g., the entries "Inngest
AgentKit", "ControlFlow", and "Motia"); update the document so each entry
appears under the correct section header that corresponds to its category value
(or change the entry's category to match the current section if that was
intended). Locate the entries by the name fields "Inngest AgentKit",
"ControlFlow", and "Motia" and either move those blocks into the section
matching their category (e.g., multi_agent_framework, etc.) or rename the
surrounding section headers to reflect the category values, ensuring consistency
and keeping YAML indentation and ordering intact.
🪄 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: 7f251929-116a-4376-b648-5004f6b346ed
📒 Files selected for processing (2)
data/competitors.yamlscripts/generate_comparison.py
| org_structure: { support: full, note: "Departments, hierarchy, 8 seniority levels, reporting lines, HR" } | ||
| multi_agent: { support: full, note: "Auction, role-based, load-balanced assignment; conflict resolution" } | ||
| task_delegation: { support: full, note: "DAG decomposition, 6 routing strategies, delegation chains" } | ||
| memory: { support: full, note: "5 memory types, pluggable backends, cross-lifecycle persistence" } | ||
| tool_use: { support: full, note: "MCP protocol, sandbox isolation, invocation tracking" } | ||
| human_in_loop: { support: full, note: "Approval gates, review workflows, 5 autonomy tiers" } | ||
| budget_tracking: { support: full, note: "Per-token, per-agent, hierarchical cascades, CFO optimization" } | ||
| security_model: { support: full, note: "Rule engine + LLM evaluator, progressive trust, audit trail" } | ||
| observability: { support: full, note: "Structured logging, correlation tracking, log shipping, redaction" } | ||
| web_dashboard: { support: full, note: "React 19 real-time dashboard with org chart, tasks, budgets" } | ||
| cli: { support: full, note: "Go binary with cosign verification, cross-platform" } | ||
| production_ready: { support: partial, note: "Docker images, CI/CD, cosign + SLSA; API not yet stable (pre-alpha)" } | ||
| workflow_types: { support: full, note: "Sequential, parallel, Kanban, Agile sprints, velocity tracking" } | ||
| template_system: { support: full, note: "9 archetypes, personality presets, locale-aware name generation" } | ||
| multi_agent: { support: planned, note: "6 assignment strategies, conflict resolution; working toward multi-project support and formal coordination models" } | ||
| task_delegation: { support: full, note: "DAG decomposition, 6 assignment strategies, delegation chains" } | ||
| memory: { support: planned, note: "Pluggable architecture with sole Mem0 backend; 5 memory types; working toward composite backends and alternative storage engines" } | ||
| tool_use: { support: planned, note: "MCP protocol, sandbox isolation, invocation tracking; 5 built-in tool types; working toward web, DB, terminal, email, analytics, design, deployment tools" } | ||
| human_in_loop: { support: planned, note: "Approval gates, review workflows, 4 autonomy tiers; working toward two-stage safety classifier" } | ||
| budget_tracking: { support: planned, note: "Per-token, per-agent, hierarchical cascades, CFO optimization; working toward risk-unit action budgets" } | ||
| security_model: { support: planned, note: "Rule engine + LLM evaluator, progressive trust, audit trail; working toward hallucination detection and self-healing SSRF" } | ||
| observability: { support: planned, note: "Structured logging, correlation tracking, log shipping, redaction; working toward notification sink for operator alerts" } | ||
| web_dashboard: { support: planned, note: "React 19 dashboard with org chart, tasks, budgets; working toward visual workflow editor and ceremony policy UI" } | ||
| cli: { support: partial, note: "Go binary for container management and verification; not used for agent orchestration" } | ||
| production_ready: { support: planned, note: "Docker + CI/CD + cosign + SLSA provenance; pre-alpha, API unstable; working toward PostgreSQL persistence backend" } | ||
| workflow_types: { support: planned, note: "Sequential, parallel, Kanban, Agile sprints, velocity tracking; working toward throughput-adaptive and milestone-driven strategies" } | ||
| template_system: { support: full, note: "9 company templates, 23 personality presets, 5 team packs, locale-aware name generation" } |
There was a problem hiding this comment.
YAMLlint braces rule violations are present in inline feature mappings.
The inline mappings at Line 106 onward use brace spacing that static analysis flags repeatedly (too many spaces inside braces). This pattern appears throughout the file and should be normalized to pass lint reliably.
🧹 Example normalization
- org_structure: { support: full, note: "Departments, hierarchy, 8 seniority levels, reporting lines, HR" }
+ org_structure: {support: full, note: "Departments, hierarchy, 8 seniority levels, reporting lines, HR"}🧰 Tools
🪛 YAMLlint (1.38.0)
[error] 106-106: too many spaces inside braces
(braces)
[error] 106-106: too many spaces inside braces
(braces)
[error] 107-107: too many spaces inside braces
(braces)
[error] 107-107: too many spaces inside braces
(braces)
[error] 108-108: too many spaces inside braces
(braces)
[error] 108-108: too many spaces inside braces
(braces)
[error] 109-109: too many spaces inside braces
(braces)
[error] 109-109: too many spaces inside braces
(braces)
[error] 110-110: too many spaces inside braces
(braces)
[error] 110-110: too many spaces inside braces
(braces)
[error] 111-111: too many spaces inside braces
(braces)
[error] 111-111: too many spaces inside braces
(braces)
[error] 112-112: too many spaces inside braces
(braces)
[error] 112-112: too many spaces inside braces
(braces)
[error] 113-113: too many spaces inside braces
(braces)
[error] 113-113: too many spaces inside braces
(braces)
[error] 114-114: too many spaces inside braces
(braces)
[error] 114-114: too many spaces inside braces
(braces)
[error] 115-115: too many spaces inside braces
(braces)
[error] 115-115: too many spaces inside braces
(braces)
[error] 116-116: too many spaces inside braces
(braces)
[error] 116-116: too many spaces inside braces
(braces)
[error] 117-117: too many spaces inside braces
(braces)
[error] 117-117: too many spaces inside braces
(braces)
[error] 118-118: too many spaces inside braces
(braces)
[error] 118-118: too many spaces inside braces
(braces)
[error] 119-119: too many spaces inside braces
(braces)
[error] 119-119: too many spaces inside braces
(braces)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@data/competitors.yaml` around lines 106 - 119, Inline YAML mappings (e.g.,
org_structure, multi_agent, task_delegation, memory, tool_use, human_in_loop,
budget_tracking, security_model, observability, web_dashboard, cli,
production_ready, workflow_types, template_system) use extra spaces immediately
inside braces and violate the `braces` lint rule; fix by normalizing each inline
mapping to remove the space after "{" and before "}" (and keep consistent
spacing after commas), e.g. change "{ support: full, note: ... }" to "{support:
full, note: ...}" for every occurrence in the file.
| pricing_raw = comp.get("pricing", "") | ||
| pricing_val = PRICING_LABELS.get(pricing_raw, pricing_raw) | ||
| self_hosted_raw = comp.get("self_hosted", "") | ||
| self_hosted_val = SELF_HOSTED_LABELS.get(self_hosted_raw, self_hosted_raw) | ||
| features = comp.get("features", {}) |
There was a problem hiding this comment.
Validate new YAML fields instead of silently defaulting to empty values.
Line 226 and Line 228 currently default missing pricing / self_hosted to "", which masks schema regressions in data/competitors.yaml. Please fail fast in validation for required presence and enum values.
🔧 Proposed fix
def _validate_competitors(competitors: list[Any]) -> None:
"""Validate required fields on each competitor entry."""
- required_keys = {"name", "slug", "category"}
+ required_keys = {"name", "slug", "category", "pricing", "self_hosted"}
+ allowed_pricing = {"free", "free-restrictive", "depends", "open-core", "paid"}
+ allowed_self_hosted = {"true", "false", "partial"}
for i, comp in enumerate(competitors):
if not isinstance(comp, dict):
msg = f"Competitor at index {i} is not a mapping"
raise TypeError(msg)
missing = required_keys - set(comp.keys())
if missing:
name = comp.get("name", f"<index {i}>")
msg = f"Competitor '{name}' is missing required keys: {missing}"
raise ValueError(msg)
+ if comp["pricing"] not in allowed_pricing:
+ name = comp.get("name", f"<index {i}>")
+ msg = f"Competitor '{name}' has invalid pricing value: {comp['pricing']}"
+ raise ValueError(msg)
+ if comp["self_hosted"] not in allowed_self_hosted:
+ name = comp.get("name", f"<index {i}>")
+ msg = (
+ f"Competitor '{name}' has invalid self_hosted value: "
+ f"{comp['self_hosted']}"
+ )
+ raise ValueError(msg)As per coding guidelines: "Validate at system boundaries (user input, external APIs, config files)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/generate_comparison.py` around lines 226 - 230, The code currently
masks missing/invalid pricing and self_hosted fields by defaulting to empty
strings; update the validation in the block that reads pricing_raw =
comp.get("pricing", "") and self_hosted_raw = comp.get("self_hosted", "") so it
fails fast: require these keys exist (do not default to ""), verify the values
are members of PRICING_LABELS and SELF_HOSTED_LABELS respectively, and raise a
clear exception (e.g., ValueError) with the competitor identifier when missing
or when the value is not an allowed enum; keep using PRICING_LABELS.get(...) /
SELF_HOSTED_LABELS.get(...) only after validation so the code doesn’t silently
accept invalid inputs.
There was a problem hiding this comment.
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 `@data/competitors.yaml`:
- Around line 12-23: The reviewers note that typos in pricing/self_hosted
silently pass through because scripts/generate_comparison.py uses .get(key,
default); update _validate_competitors in scripts/generate_comparison.py to
explicitly validate each competitor entry's pricing and self_hosted fields
against the allowed sets (pricing =
{"free","free-restrictive","depends","open-core","paid"} and self_hosted =
{"true","false","partial"}), and raise/throw a clear error (or log and abort
generation) identifying the competitor name and invalid value when a mismatch is
found so generation fails loudly instead of rendering corrupted labels.
In `@site/src/components/islands/ComparisonTable.tsx`:
- Around line 254-256: The file defines two equivalent booleans (hasActiveFilter
and hasFilters); consolidate them into a single variable (pick one name, e.g.,
hasFilters) and remove the duplicate. Update all usages that check for active
filters—specifically the SynthOrg "pinned" badge code that references
hasActiveFilter and the "Clear" button logic that references hasFilters—to use
the single variable, ensuring the condition includes the same operands
(categoryFilter || licenseFilter || featureFilter || search.trim()). Keep the
variable's computation in the same scope as the existing declarations so both UI
branches can reference it.
🪄 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: f84a7de9-3c4f-47c8-86b8-5f575655ff01
📒 Files selected for processing (2)
data/competitors.yamlsite/src/components/islands/ComparisonTable.tsx
… variable - Add pricing and self_hosted enum validation to _validate_competitors() (fails fast with clear error on invalid values) - Merge duplicate hasFilters into hasActiveFilter (same condition)
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
scripts/generate_comparison.py (1)
112-134: 🧹 Nitpick | 🔵 TrivialEnum validation implemented correctly for optional fields.
The validation now properly checks that
pricingandself_hosted, when present, contain valid enum values. This addresses the prior review feedback while keeping the fields optional (matching thepricing?: stringandself_hosted?: stringdeclarations in the TSX interface).Minor nit:
nameis computed identically at line 123 and again at line 126.,
♻️ Optional: Eliminate duplicate name lookup
for i, comp in enumerate(competitors): if not isinstance(comp, dict): msg = f"Competitor at index {i} is not a mapping" raise TypeError(msg) + name = comp.get("name", f"<index {i}>") missing = required_keys - set(comp.keys()) if missing: - name = comp.get("name", f"<index {i}>") msg = f"Competitor '{name}' is missing required keys: {missing}" raise ValueError(msg) - name = comp.get("name", f"<index {i}>") pricing = comp.get("pricing")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/generate_comparison.py` around lines 112 - 134, In _validate_competitors, avoid computing name twice by assigning name = comp.get("name", f"<index {i}>") once immediately after verifying comp is a mapping, then use that name variable in the missing-keys error and subsequent validation messages (replace the later name = ... and any other duplicate lookups), leaving the rest of the logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@scripts/generate_comparison.py`:
- Around line 112-134: In _validate_competitors, avoid computing name twice by
assigning name = comp.get("name", f"<index {i}>") once immediately after
verifying comp is a mapping, then use that name variable in the missing-keys
error and subsequent validation messages (replace the later name = ... and any
other duplicate lookups), leaving the rest of the logic unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: f3c3f82c-e25e-4043-a4a4-2280a646ef8d
📒 Files selected for processing (2)
scripts/generate_comparison.pysite/src/components/islands/ComparisonTable.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). (2)
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Do NOT usefrom __future__ import annotations-- Python 3.14 has PEP 649
Useexcept A, B:syntax (no parentheses) for exception handling -- PEP 758 except syntax, enforced by ruff on Python 3.14
All public functions must have type hints; enforce with mypy strict mode
Use Google-style docstrings, required on public classes and functions; enforced by ruff D rules
Create new objects for immutability; never mutate existing objects. For non-Pydantic internal collections (registries,BaseTool), usecopy.deepcopy()at construction plusMappingProxyTypewrapping for read-only enforcement
Fordict/listfields in frozen Pydantic models, usecopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization)
Use frozen Pydantic models for config and identity; use separate mutable-via-copy models (usingmodel_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model
Use Pydantic v2 (BaseModel,model_validator,computed_field,ConfigDict); adoptallow_inf_nan=Falsein allConfigDictdeclarations to rejectNaN/Infin numeric fields at validation time
Use@computed_fieldfor derived values instead of storing and validating redundant fields (e.g.,TokenUsage.total_tokens)
UseNotBlankStr(fromcore.types) for all identifier and name fields -- including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants -- instead of manual whitespace validators
Preferasyncio.TaskGroupfor fan-out/fan-in parallel operations in new code (e.g., multiple tool invocations, parallel agent calls); prefer structured concurrency over barecreate_task
Maintain line length of 88 characters; enforced by ruff
Functions must be less than 50 lines; files must be less than 800 lines
Handle errors explicitly; never silently swallow exceptions
Validate at system boundaries (user input, external APIs, conf...
Files:
scripts/generate_comparison.py
scripts/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Scripts in
scripts/-- CI/build utilities with relaxed ruff rules allowing
Files:
scripts/generate_comparison.py
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T13:12:42.085Z
Learning: Comparison data: `data/competitors.yaml` -- shared YAML source for `docs/reference/comparison.md` (generated by `scripts/generate_comparison.py`) and `site/src/pages/compare.astro`
📚 Learning: 2026-04-02T13:12:42.085Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T13:12:42.085Z
Learning: Comparison data: `data/competitors.yaml` -- shared YAML source for `docs/reference/comparison.md` (generated by `scripts/generate_comparison.py`) and `site/src/pages/compare.astro`
Applied to files:
scripts/generate_comparison.pysite/src/components/islands/ComparisonTable.tsx
📚 Learning: 2026-04-02T12:19:36.876Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: web/CLAUDE.md:0-0
Timestamp: 2026-04-02T12:19:36.876Z
Learning: Applies to web/src/components/ui/*.{ts,tsx} : Export component props as a TypeScript interface in new shared components
Applied to files:
site/src/components/islands/ComparisonTable.tsx
🔇 Additional comments (12)
scripts/generate_comparison.py (3)
32-46: LGTM!The label maps are well-structured and provide consistent display values for the new
pricingandself_hostedYAML fields. The Self-Hosted icons align with the existingSUPPORT_ICONSpattern.
237-252: Column generation correctly handles optional fields.The fallback to raw value via
PRICING_LABELS.get(pricing_raw, pricing_raw)gracefully handles empty strings when the field is absent, which aligns with the optional field design. The Markdown row structure is correct for the expanded column set.
267-276: Table header and separator alignment looks correct.The center-alignment (
:---:) for Self-Hosted makes sense since it displays single-character icons. The column count in the separator matches the header.site/src/components/islands/ComparisonTable.tsx (9)
1-1: Interface extension aligns with YAML schema.The new optional
pricingandself_hostedfields match the data model indata/competitors.yamland the label mappings in the Python generator.Also applies to: 33-34
124-177: Well-implemented state management and side effects.The scroll hint detection, Escape key handler, and click-outside handler are all properly implemented with appropriate cleanup in the effect return functions. The
useEffectdependencies are correctly specified.
188-220: Filter bypass foris_synthorgentries implements the "pinned" behavior correctly.The logic ensures SynthOrg is always visible regardless of active filters, which matches the UI's "pinned" badge indication. Per the YAML data (line ~104 in
data/competitors.yaml), only one entry hasis_synthorg: true, so this bypass is appropriately scoped.
254-256: Filter state consolidation addressed.The duplicate
hasFiltersvariable from a prior review has been consolidated intohasActiveFilter, which is now used consistently for both the "Clear" button visibility (line 384) and the "pinned" badge rendering.
391-454: Toolbar UI is accessible and functional.The column picker includes proper
aria-expandedstate, and the full-width toggle has appropriatearia-labelandtitleattributes. The SVG icons are inline and appropriately sized.
413-434: Click-outside handler now closes the column picker.The
pickerRefis attached to the dropdown container and themousedownlistener correctly closes the picker when clicking outside. This addresses the prior review feedback.
586-586: Detail rowcolSpanand dimension iteration are intentionally different.The
colSpan={4 + visibleDimensions.length}correctly spans all visible table columns (expand button + Framework + Category + License + visible dimensions). Meanwhile, the detail content iterates over alldimensionsto show notes even for hidden columns—this is a sensible UX choice since users may want to see full details regardless of column visibility.Also applies to: 607-620
631-637: Scroll hint provides good horizontal overflow discoverability.The conditional rendering based on
canScrollRightand the passive scroll listener ensure minimal performance impact while guiding users to horizontally scroll on narrower viewports.
681-695: Mobile card view respects column visibility.Using
visibleDimensionsin the mobile grid maintains consistency with the desktop table's column picker state.
🤖 I have created a release *beep* *boop* --- ## [0.5.8](v0.5.7...v0.5.8) (2026-04-03) ### Features * auto-select embedding model + fine-tuning pipeline wiring ([#999](#999)) ([a4cbc4e](a4cbc4e)), closes [#965](#965) [#966](#966) * ceremony scheduling batch 3 -- milestone strategy, template defaults, department overrides ([#1019](#1019)) ([321d245](321d245)) * five-pillar evaluation framework for HR performance tracking ([#1017](#1017)) ([5e66cbd](5e66cbd)), closes [#699](#699) * populate comparison page with 53 competitor entries ([#1000](#1000)) ([5cb232d](5cb232d)), closes [#993](#993) * throughput-adaptive and external-trigger ceremony scheduling strategies ([#1003](#1003)) ([bb5c9a4](bb5c9a4)), closes [#973](#973) [#974](#974) ### Bug Fixes * eliminate backup service I/O from API test lifecycle ([#1015](#1015)) ([08d9183](08d9183)) * update run_affected_tests.py to use -n 8 ([#1014](#1014)) ([3ee9fa7](3ee9fa7)) ### Performance * reduce pytest parallelism from -n auto to -n 8 ([#1013](#1013)) ([43e0707](43e0707)) ### CI/CD * bump docker/login-action from 4.0.0 to 4.1.0 in the all group ([#1027](#1027)) ([e7e28ec](e7e28ec)) * bump wrangler from 4.79.0 to 4.80.0 in /.github in the all group ([#1023](#1023)) ([1322a0d](1322a0d)) ### Maintenance * bump github.com/mattn/go-runewidth from 0.0.21 to 0.0.22 in /cli in the all group ([#1024](#1024)) ([b311694](b311694)) * bump https://github.com/astral-sh/ruff-pre-commit from v0.15.8 to 0.15.9 in the all group ([#1022](#1022)) ([1650087](1650087)) * bump node from `71be405` to `387eebd` in /docker/sandbox in the all group ([#1021](#1021)) ([40bd2f6](40bd2f6)) * bump node from `cf38e1f` to `ad82eca` in /docker/web in the all group ([#1020](#1020)) ([f05ab9f](f05ab9f)) * bump the all group in /web with 3 updates ([#1025](#1025)) ([21d40d3](21d40d3)) * bump the all group with 2 updates ([#1026](#1026)) ([36778de](36778de)) * enable additional eslint-react rules and fix violations ([#1028](#1028)) ([80423be](80423be)) --- 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>
Summary
Populates the comparison page data file (
data/competitors.yaml) with 53 competitor entries across 7 categories, replacing the original 5 proof-of-concept entries. Updates the FAQ component with more honest, balanced content.Data population
New metadata fields
pricing: free | free-restrictive | depends | open-core | paidself_hosted: true | false | partialHonest SynthOrg self-assessment
production_ready: partialwith note: "Docker + CI/CD + cosign + SLSA provenance; pre-alpha, API unstable, no production deployments yet"memorynote updated: "Mem0 backend (sole implementation); pluggable architecture, 5 memory types"FAQ updates (
site/src/components/ComparisonFAQ.astro)Research methodology
Test plan
uv run python scripts/generate_comparison.pyproduces clean Markdown with zero warningsReview coverage
Closes #993