Skip to content

feat: populate comparison page with 53 competitor entries#1000

Merged
Aureliolo merged 8 commits intomainfrom
feat/populate-comparison-data
Apr 2, 2026
Merged

feat: populate comparison page with 53 competitor entries#1000
Aureliolo merged 8 commits intomainfrom
feat/populate-comparison-data

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

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

  • 54 total entries (53 competitors + SynthOrg) across all 7 categories:
    • Multi-Agent Frameworks (20): CrewAI, AutoGen, LangGraph, OpenAI Agents SDK, Semantic Kernel, Google ADK, PydanticAI, CAMEL, smolagents, AG2, Agno, Letta, Agency Swarm, Mastra, Langroid, Strands Agents, BeeAI Framework, Haystack, SuperAGI, Inngest AgentKit
    • Virtual Org Simulators (3): ChatDev, MetaGPT, GPT Pilot
    • Workflow Engines (10): Temporal, n8n, Dify, Restack, Flyte, Flowise, Langflow, ControlFlow, Motia, Julep
    • Commercial Platforms (6): LangSmith, Amazon Bedrock Agents, Vertex AI Agent Builder, Agentforce, Relevance AI
    • Developer Tools (9): LlamaIndex Workflows, Composio, E2B, OpenHands, Rivet, Vercel AI SDK, Llama Stack, Atomic Agents
    • Research (3): Generative Agents (Stanford), AgentVerse, BabyAGI, AutoGPT
    • Protocols (3): MCP, A2A, Agent Protocol
  • Each entry has all 14 dimensions evaluated (full/partial/planned/none) with sourced notes
  • Every competitor was web-searched individually for current capabilities (docs, GitHub, release notes)

New metadata fields

  • pricing: free | free-restrictive | depends | open-core | paid
  • self_hosted: true | false | partial

Honest SynthOrg self-assessment

  • production_ready: partial with note: "Docker + CI/CD + cosign + SLSA provenance; pre-alpha, API unstable, no production deployments yet"
  • memory note updated: "Mem0 backend (sole implementation); pluggable architecture, 5 memory types"
  • Same evaluation rubric applied to SynthOrg as every competitor

FAQ updates (site/src/components/ComparisonFAQ.astro)

Research methodology

  • 59 parallel research agents (1 per competitor + 3 discovery + 3 pricing/hosting)
  • Evaluation rubric: same bar for SynthOrg and every competitor
  • Code over marketing: evaluated what's shipped, not landing page claims
  • Commercial add-ons rated as "partial" for the open-source project

Test plan

  • uv run python scripts/generate_comparison.py produces clean Markdown with zero warnings
  • All pre-commit hooks pass (YAML validation, gitleaks, em-dash check)
  • Landing page table renders correctly with full dataset (54 entries, 7 categories)

Review coverage

  • Auto-detected as non-substantive code changes (YAML data + Astro static component)
  • All pre-commit and pre-push hooks passed

Closes #993

Copilot AI review requested due to automatic review settings April 2, 2026 14:49
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 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: 65fc227f-e921-4d34-8445-7fa164f01137

📥 Commits

Reviewing files that changed from the base of the PR and between 4761740 and bfea687.

📒 Files selected for processing (1)
  • scripts/generate_comparison.py

Walkthrough

Updated 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 pricing and self_hosted fields and substantially expanded data/competitors.yaml. Extended generator script to map and output Pricing and Self-Hosted columns. UI and CSS changes: column picker, full-width mode, scroll hint, toolbar, and SynthOrg "pinned" behavior.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: populate comparison page with 53 competitor entries' directly and accurately summarizes the main change—adding 53 new competitor entries to the comparison page data.
Description check ✅ Passed The description is well-structured and directly related to the changeset, covering data population, metadata fields, FAQ updates, research methodology, and test plan.
Linked Issues check ✅ Passed The PR fulfills all coding objectives from issue #993: 54 total entries (exceeding 40+ requirement), all 14 dimensions evaluated with sourced notes, new pricing/self_hosted metadata fields, consistent evaluation rubric applied to SynthOrg and competitors, documented research methodology, and verification that scripts/generate_comparison.py produces clean output with correct landing page rendering.
Out of Scope Changes check ✅ Passed All changes are within scope: competitor data population, metadata field additions, evaluation notes, and FAQ content updates directly support the objectives of issue #993 with no extraneous modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% 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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 2, 2026

Dependency Review

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

Snapshot Warnings

⚠️: No snapshots were found for the head SHA bfea687.
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

@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 `@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

📥 Commits

Reviewing files that changed from the base of the PR and between 2a189c2 and b92fad0.

📒 Files selected for processing (2)
  • data/competitors.yaml
  • site/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.yaml entry (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.

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 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.

Comment on lines +24 to +25
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.",
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

There are two minor inaccuracies in this entry:

  1. Branding: Salesforce's platform is branded as Agentforce (lowercase 'f'), which is correctly reflected in the YAML data but capitalized as 'AgentForce' here.
  2. 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.",
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 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.",

Comment on lines 35 to 38
{
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.",
},
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

This new FAQ entry is largely redundant with the existing "Is SynthOrg production-ready?" question at line 12. Both entries mention the same technical stack (Docker, Chainguard, SLSA, etc.) and the pre-alpha status. Consider merging these into a single, comprehensive entry to keep the FAQ concise.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 new pricing and self_hosted metadata fields.
  • Updates ComparisonFAQ.astro with 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.

Comment on lines +25 to +29
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.",
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

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).

Suggested change
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.",

Copilot uses AI. Check for mistakes.
- name: "LangSmith"
slug: langsmith
url: "https://smith.langchain.com"
repo: "none"
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
repo: "none"
repo: ""

Copilot uses AI. Check for mistakes.
Comment on lines +943 to +947
- 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"
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
- name: "Relevance AI"
slug: relevance-ai
url: "https://relevanceai.com"
repo: "none"
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
repo: "none"
repo: ""

Copilot uses AI. Check for mistakes.
description: "TypeScript framework for multi-agent networks with state-based routing and durable execution"
license: "Apache-2.0"
language: "TypeScript"
category: multi_agent_framework
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
category: multi_agent_framework
category: workflow_engine

Copilot uses AI. Check for mistakes.
- 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)
@Aureliolo Aureliolo force-pushed the feat/populate-comparison-data branch from b92fad0 to 11dcf15 Compare April 2, 2026 15:30
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 2, 2026 15:31 — with GitHub Actions Inactive
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: 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 | 🔵 Trivial

SynthOrg 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

📥 Commits

Reviewing files that changed from the base of the PR and between b92fad0 and 11dcf15.

📒 Files selected for processing (5)
  • data/competitors.yaml
  • scripts/generate_comparison.py
  • site/src/components/ComparisonFAQ.astro
  • site/src/components/islands/ComparisonTable.css
  • site/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 use from __future__ import annotations -- Python 3.14 has PEP 649
Use except 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), 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 frozen Pydantic models for config and identity; use separate mutable-via-copy models (using model_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); adopt allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields at validation time
Use @computed_field for derived values instead of storing and validating redundant fields (e.g., TokenUsage.total_tokens)
Use NotBlankStr (from core.types) for all identifier and name fields -- including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants -- instead of manual whitespace validators
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
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 print and deferred imports

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.py
  • site/src/components/ComparisonFAQ.astro
  • site/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_LABELS mapping provides clear display labels for all pricing values mentioned in the PR objectives with a sensible fallback.


42-46: The implementation is correct. All self_hosted values in competitors.yaml are quoted strings ("true", "false", "partial"), which match the string keys in SELF_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 Competitor interface includes pricing and self_hosted as 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
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 2, 2026 15:48 — with GitHub Actions Inactive
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

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 | 🔵 Trivial

Note: 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 | 🟡 Minor

Remove 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.support interface (line 20) includes "planned"
  • SUPPORT_ORDER, SUPPORT_ICONS, and SUPPORT_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

📥 Commits

Reviewing files that changed from the base of the PR and between 11dcf15 and 2993b87.

📒 Files selected for processing (4)
  • data/competitors.yaml
  • scripts/generate_comparison.py
  • site/src/components/islands/ComparisonTable.css
  • site/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
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 2, 2026 16:02 — with GitHub Actions Inactive
…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
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)
data/competitors.yaml (1)

72-86: ⚠️ Potential issue | 🟠 Major

Dataset 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 for docs/reference/comparison.md (generated by scripts/generate_comparison.py) and site/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 | 🟡 Minor

Section 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 their category values. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 2993b87 and 678eacb.

📒 Files selected for processing (2)
  • data/competitors.yaml
  • scripts/generate_comparison.py

Comment on lines 106 to +119
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" }
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 | 🟠 Major

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.

Comment on lines +226 to 230
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", {})
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 | 🟠 Major

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.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 2, 2026 16:06 — with GitHub Actions Inactive
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 `@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

📥 Commits

Reviewing files that changed from the base of the PR and between 678eacb and e3c085d.

📒 Files selected for processing (2)
  • data/competitors.yaml
  • site/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)
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 2, 2026 16:15 — with GitHub Actions Inactive
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.

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 | 🔵 Trivial

Enum validation implemented correctly for optional fields.

The validation now properly checks that pricing and self_hosted, when present, contain valid enum values. This addresses the prior review feedback while keeping the fields optional (matching the pricing?: string and self_hosted?: string declarations in the TSX interface).

Minor nit: name is 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

📥 Commits

Reviewing files that changed from the base of the PR and between e3c085d and 4761740.

📒 Files selected for processing (2)
  • scripts/generate_comparison.py
  • site/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 use from __future__ import annotations -- Python 3.14 has PEP 649
Use except 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), 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 frozen Pydantic models for config and identity; use separate mutable-via-copy models (using model_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); adopt allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields at validation time
Use @computed_field for derived values instead of storing and validating redundant fields (e.g., TokenUsage.total_tokens)
Use NotBlankStr (from core.types) for all identifier and name fields -- including optional (NotBlankStr | None) and tuple (tuple[NotBlankStr, ...]) variants -- instead of manual whitespace validators
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
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 print and deferred imports

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.py
  • site/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 pricing and self_hosted YAML fields. The Self-Hosted icons align with the existing SUPPORT_ICONS pattern.


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 pricing and self_hosted fields match the data model in data/competitors.yaml and 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 useEffect dependencies are correctly specified.


188-220: Filter bypass for is_synthorg entries 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 has is_synthorg: true, so this bypass is appropriately scoped.


254-256: Filter state consolidation addressed.

The duplicate hasFilters variable from a prior review has been consolidated into hasActiveFilter, 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-expanded state, and the full-width toggle has appropriate aria-label and title attributes. The SVG icons are inline and appropriately sized.


413-434: Click-outside handler now closes the column picker.

The pickerRef is attached to the dropdown container and the mousedown listener correctly closes the picker when clicking outside. This addresses the prior review feedback.


586-586: Detail row colSpan and 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 all dimensions to 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 canScrollRight and 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 visibleDimensions in the mobile grid maintains consistency with the desktop table's column picker state.

@Aureliolo Aureliolo merged commit 5cb232d into main Apr 2, 2026
23 of 25 checks passed
@Aureliolo Aureliolo deleted the feat/populate-comparison-data branch April 2, 2026 16:23
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 2, 2026 16:23 — with GitHub Actions Inactive
Aureliolo added a commit that referenced this pull request Apr 3, 2026
🤖 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>
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.

feat: populate comparison page with 40+ competitor entries

2 participants