Skip to content

fix(pr-review): Migrate to Python collator and fix Claude bot extraction - #46

Merged
jonahgabriel merged 12 commits into
mainfrom
fix/skill-stat-and-jq-parsing
Jan 19, 2026
Merged

jonahgabriel merged 12 commits into
mainfrom
fix/skill-stat-and-jq-parsing

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Dec 4, 2025 •

Copy link
Copy Markdown
Contributor

Summary

Resolves the cannot allocate memory error in collate-issues by migrating from a 300-line jq script to Python. Also fixes extraction of Claude Code bot review comments with proper severity classification.

Root Cause Analysis

The jq-based implementation was using jq as a regex/text analysis engine with 30+ scan() calls and 60+ test() calls on 18KB+ review bodies. This caused exponential memory growth and eventual exhaustion (OOM after 28-37 seconds).

Changes

1. Python Migration (-454 net lines)

  • collate-issues (bash): Reduced from 740 → ~215 lines, now a thin wrapper
  • collate_issues.py: Enhanced with +327 lines for robust text processing
  • Memory usage: ~53MB Python vs OOM with jq

2. Cross-Repo URL Support

# Now works with any GitHub repository
./collate-issues https://github.com/OmniNode-ai/omniintelligence/pull/5

3. Claude Code Bot Issue Extraction

Properly extracts issues with correct severity from Claude's section headers:

  • ### **Critical Issues** → CRITICAL
  • ### **High Priority Issues** → MAJOR
  • ### **Medium Priority Issues** → MINOR
  • ### **Low Priority Issues** → NITPICK

Items with (BLOCKING) or (REQUIRED) markers are auto-upgraded to CRITICAL.

4. jq Fixes Preserved

The previous jq 1.6 compatibility fixes remain in the simplified bash wrapper:

  • Replaced scan(pattern; "i") with ascii_downcase-based patterns
  • Temp-file handling to avoid JSON corruption

Test Plan

  • PR 45 (omniclaude): 4 nitpick issues extracted
  • PR 5 (omniintelligence): 93 issues including Claude Critical/Major items
    • 4 critical (Pre-commit Hook Incompatibility, Type Annotation Issue, etc.)
    • 9 major
    • 12 minor
    • 27 nitpick
  • No memory errors on large PRs
  • Cross-repo URL fetching works
  • All CLI flags preserved (--include-nitpicks, --hide-resolved, --stats, etc.)

Summary by CodeRabbit

  • New Features

    • Added Linear Insights suite for project analytics: deep-dive reports, velocity estimation, project status dashboards, and work recommendations
    • Introduced comprehensive ONEX plugin with 50+ specialized automation agents for development workflows, debugging, documentation, and infrastructure
    • Enhanced PR review with improved data processing and error handling
  • Documentation

    • Added configuration guides, setup instructions, and environment variable documentation for Linear Insights and ONEX plugin
    • Published agent capability reference documentation

✏️ Tip: You can customize this high-level summary in your review settings.

jonahgabriel and others added 2 commits December 4, 2025 08:30
…ripts

- Prioritize GNU stat (-c %Y) over BSD stat (-f %m) for Linux compatibility
- Add null-safety checks for jq split operations on empty headers
- Fix potential null reference in priority parsing regex matches
- Replace 740-line jq script with Python collator (fixes memory exhaustion)
- Add cross-repo URL support for fetching PRs from other repositories
- Extract Claude Code bot issues with correct severity from section headers
  (Critical Issues, High Priority Issues, Medium Priority Issues)
- Run section-aware extraction before generic patterns for proper severity
- Keep all jq fixes (1.6 compat, temp file handling) in simplified bash wrapper
- Memory: ~53MB Python vs OOM with jq on 18KB+ PR bodies

Tested on:
- PR 45 (omniclaude): 4 nitpick issues
- PR 5 (omniintelligence): 93 issues including Claude Critical/Major items
@coderabbitai

coderabbitai Bot commented Dec 4, 2025 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR introduces a comprehensive expansion of the ONEX framework with Linear Insights skills for deep-dive reporting, velocity estimation, and project analysis; refactors PR review processing from shell to Python delegation with enhanced CodeRabbit/Claude parsing; adds 40+ declarative YAML agent configurations for specialized workflows; and establishes environment-based configuration migration for the ONEX plugin.

Changes

Cohort / File(s) Summary
PR Review System Refactoring
claude/skills/pr-review/collate-issues, claude/skills/pr-review/collate_issues.py, claude/skills/pr-review/fetch-pr-data
Delegates shell-based PR issue processing to Python implementation; adds CodeRabbit inline/HTML and Claude section-aware extraction; introduces parallel-solve formatting and stats reporting; refactors Python signatures to accept pr_input: str | int; updates fetch-pr-data error handling with post-wait centralized error checks.
Linear Insights Skills
claude/skills/linear-insights/deep-dive, claude/skills/linear-insights/velocity-estimate, claude/skills/linear-insights/estimation-accuracy, claude/skills/linear-insights/project-status, claude/skills/linear-insights/suggest-work, claude/skills/linear-insights/setup
Introduces 6 new Bash-based skill scripts for Linear project analysis: deep-dive report generation with snapshot management, velocity calculation with historical tracking, estimation accuracy recording, project health dashboards, backlog prioritization, and configuration management.
Linear Insights Configuration & Documentation
claude/skills/linear-insights/config.yaml, claude/skills/linear-insights/SKILL.md, claude/commands/deep-dive.md, claude/commands/project-status.md, claude/commands/suggest-work.md, claude/commands/velocity-estimate.md
Comprehensive YAML configuration with project/team/backlog/velocity/state/cache/output settings; skill overview documentation; and 4 command documentation files detailing MCP queries, output formats, scoring algorithms, and usage examples.
ONEX Agent Configurations
plugins/onex/agents/configs/address-pr-comments.yaml, plugins/onex/agents/configs/agent-*.yaml, plugins/onex/agents/configs/*-developer.yaml, plugins/onex/agents/configs/*-specialist.yaml, plugins/onex/agents/configs/onex-*.yaml
Adds 45+ new agent configuration files (schema 1.0-2.0) defining identity, philosophy, capabilities, activation patterns, workflow templates, quality gates, success metrics, and ONEX four-node architecture integration for specialized agents across PR review, debugging, API design, code generation, documentation, and infrastructure domains.
ONEX Plugin & Environment Configuration
plugins/onex/.claude-plugin/plugin.json, plugins/onex/.env.example, plugins/onex/ENVIRONMENT_VARIABLES.md, plugins/onex/README.md, .gitignore
Introduces plugin manifest with 53 polymorphic YAML agents; comprehensive environment variable documentation with auto-detection fallbacks and cross-repo examples; full README with architecture overview, installation, migration guidance, and troubleshooting.
Core Project Updates
claude/README.md, claude/commands/__init__.py, claude/hooks/post_tool_use_enforcer.py, plugins/.claude-plugin/marketplace.json, QUICKSTART.md
Renames /pr-dev-review command to /pr-review-dev; updates type annotations to explicit union syntax (Type[Any] | None); adds marketplace metadata for Claude plugin marketplace; updates project naming in QUICKSTART from omniclaude-agents to omniclaude.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant Shell as collate-issues<br/>(Shell Wrapper)
    participant Python as collate_issues.py
    participant GitHub as GitHub API
    participant Claude as Claude/CodeRabbit<br/>Parser

    User->>Shell: invoke with PR input<br/>(URL or number)
    Shell->>Shell: validate_pr_input()
    Shell->>Shell: check Python executable
    Shell->>Python: exec with PR input
    Python->>GitHub: fetch PR data
    GitHub-->>Python: PR comments & metadata
    Python->>Claude: extract structured issues<br/>(CodeRabbit/Claude formats)
    Claude-->>Python: ExtractedIssue objects<br/>with severity & location
    Python->>Python: collate_pr_issues()
    Python->>Python: format_issues_parallel_solve()
    Python-->>Shell: JSON or formatted report
    Shell-->>User: output (Markdown/JSON)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

The changeset introduces heterogeneous modifications across multiple domains (PR processing, Linear Insights, agent orchestration) with 45+ similar but distinct agent configurations (repetitive structure reduces per-file effort) alongside skill scripts requiring careful logic review. The Linear Insights features and Python delegation changes demand scrutiny for correctness and integration.

Poem

🐰 A rabbit hops through ONEX's new domain,
With agents aplenty and skills to explain,
From deep-dive reports to velocity trends,
PR wisdom now Python—where chaos ends!
Forty-five configurations in harmony bound,
The future of workflows—it's ONEX-pronounced! ✨


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
claude/skills/pr-review/collate_issues.py (3)

37-37: Consider reducing Any usage for stronger type safety.

The import includes Any which is used throughout (e.g., dict[str, Any] in resolution functions). Per coding guidelines requiring "strongest typing possible," consider defining TypedDict or Pydantic models for the PR data structures returned by fetch_pr_data and used in resolution maps.

Example for resolution info:

class ResolutionInfo(TypedDict):
    is_resolved: bool
    is_outdated: bool
    resolved_by: str | None
    path: str | None
    line: int | None

861-911: Good subprocess handling with comprehensive error cases.

The function properly handles:

  • Non-zero return codes
  • Empty output
  • Timeout (120s is reasonable for API calls)
  • JSON parse errors

All errors use OnexError with specific codes per coding guidelines.

Minor: The docstring is missing the Raises section. Per coding guidelines, docstrings should include Raises.

Add to docstring:

     Raises:
+        OnexError: If fetch fails (FETCH_FAILED), returns empty (EMPTY_OUTPUT),
+            times out (TIMEOUT), or output is invalid JSON (PARSE_ERROR).

1491-1496: ValueError catch may conflict with OnexError guideline.

Per coding guidelines, error handling should use OnexError with specific error codes, not generic ValueError. The current catch at line 1494 handles ValueError separately from OnexError.

Consider whether callers should raise OnexError instead of ValueError, or convert ValueError to OnexError here:

     except OnexError as e:
         print(f"ERROR: {e}", file=sys.stderr)
         return 2
     except ValueError as e:
-        print(f"ERROR: {e}", file=sys.stderr)
-        return 1
+        print(f"ERROR: [VALIDATION_ERROR] {e}", file=sys.stderr)
+        return 1

Or update callers to raise OnexError(str(e), code="VALIDATION_ERROR") instead of ValueError.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between ba6448b and c1421ed.

📒 Files selected for processing (3)
  • claude/skills/pr-review/collate-issues (5 hunks)
  • claude/skills/pr-review/collate_issues.py (17 hunks)
  • claude/skills/pr-review/fetch-pr-data (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/canonical_patterns.mdc)

**/*.py: All methods must include docstrings with description, Args, Returns, Raises, and Example sections
All error handling must use OnexError exception class with specific error codes from error enum, never raise generic Exception or ValueError

Automatically perform code standards checks on all Python files in the PR, including: Any/Any imports and Dict[str, Any] usage violations, naming convention violations (tool_, model_, enum_ prefixes), anti-pattern detection (direct tool instantiation, telescoping constructors), and type safety enforcement (strongest typing possible). Fix all violations immediately with proper commit messages.

**/*.py: Use Enum types for status values instead of string literals (e.g., use EnumOnexStatus.SUCCESS not status: str = 'success')
Import enums from omnibase.enums module
Import protocols from omnibase.protocol.protocol_<name> module paths
Use TYPE_CHECKING pattern for forward references to avoid circular imports when using string annotations
Do not remove [AI_PROMPT] comments from generated code; they provide actionable guidance for future AI implementation
Avoid camelCase filenames; use snake_case with appropriate prefixes (tool_, protocol_, model_, enum_, etc.)

NEVER create scenarios from scratch - ALWAYS clone existing scenarios to avoid missing required fields, version format errors, and incorrect tool configurations

**/*.py: Use type-safe configuration via Pydantic Settings from config/settings.py with 90+ type-safe variables organized into External Service Discovery, Shared Infrastructure, AI Provider API Keys, Local Services, and Feature Flags
Access PostgreSQL connection strings via settings.get_postgres_dsn() or settings.get_postgres_dsn(async_driver=True) rather than constructing connection strings manually
Publish intelligence requests to Kafka event bus using topics: dev.archon-intelligence.intelligence.code-analysis-{requested,completed,failed}.v1 for consistency and event-driven architecture
Implement...

Files:

  • claude/skills/pr-review/collate_issues.py
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: When user requests PR description creation or pull request submission (e.g., 'create a PR description', 'create a PR', 'submit for review'), automatically execute a complete workflow: (1) gather git statistics, (2) analyze changes, (3) check work tickets, (4) generate content using template, (5) create full PR via `gh pr create` targeting `development` branch by default unless user specifies otherwise, (6) automatically switch to code review mode and perform standards checks on Python files, (7) fix any violations found, and (8) report results to user.
📚 Learning: 2025-11-24T16:33:09.011Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T16:33:09.011Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Each PR description must include the following required sections: PR Title, Branch, PR ID or Link, Summary of Changes, Key Achievements, Prompts & Actions (Chronological with timestamps in ISO 8601 format and agent attribution), Major Milestones, Blockers / Next Steps, Metrics (Lines Changed in "+X / -Y" format, Files Modified count, Time Spent if tracked), and must include optional sections where relevant: Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), and Release Notes Snippet

Applied to files:

  • claude/skills/pr-review/collate_issues.py
  • claude/skills/pr-review/collate-issues
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Each PR description MUST include the following required sections: PR Title, Branch, Summary of Changes, Key Achievements, Prompts & Actions (Chronological), Major Milestones, Blockers / Next Steps, and Metrics (Lines Changed, Files Modified, Time Spent). Optional sections include: PR ID or Link, Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), and Release Notes Snippet.

Applied to files:

  • claude/skills/pr-review/collate_issues.py
  • claude/skills/pr-review/collate-issues
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to **/*.py : Automatically perform code standards checks on all Python files in the PR, including: Any/Any imports and Dict[str, Any] usage violations, naming convention violations (tool_, model_, enum_ prefixes), anti-pattern detection (direct tool instantiation, telescoping constructors), and type safety enforcement (strongest typing possible). Fix all violations immediately with proper commit messages.

Applied to files:

  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:23:24.207Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/modes.mdc:0-0
Timestamp: 2025-11-24T17:23:24.207Z
Learning: CODE_REVIEW mode: Conduct structured, multi-faceted code review analyzing code quality, security, performance, architecture, and standards. Use severity levels: CRITICAL, MAJOR, MINOR, SUGGESTION. Forbidden: Making code changes or implementations.

Applied to files:

  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:22:03.323Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/CHECKLIST_RULE.md:0-0
Timestamp: 2025-11-24T17:22:03.323Z
Learning: Applies to **/work_tickets/**/*.yaml : Mark critical gaps in work ticket checklists with ⚠️ indicators and architecture violations separately from functional requirements

Applied to files:

  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : PR descriptions must include a Metrics section with: Lines Changed in '+X / -Y' format (insertions/deletions), Files Modified as an integer, and Time Spent as a duration (if tracked)

Applied to files:

  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : All PR descriptions must be written in Markdown format using the canonical template. Optional fields should be included when relevant; otherwise, state 'None'. Do not omit any required section or field.

Applied to files:

  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: When user requests PR description creation or pull request submission (e.g., 'create a PR description', 'create a PR', 'submit for review'), automatically execute a complete workflow: (1) gather git statistics, (2) analyze changes, (3) check work tickets, (4) generate content using template, (5) create full PR via `gh pr create` targeting `development` branch by default unless user specifies otherwise, (6) automatically switch to code review mode and perform standards checks on Python files, (7) fix any violations found, and (8) report results to user.

Applied to files:

  • claude/skills/pr-review/collate-issues
🔇 Additional comments (15)
claude/skills/pr-review/fetch-pr-data (1)

325-325: LGTM! Cross-platform stat ordering is correct.

The reordering to prefer GNU stat -c %Y with BSD stat -f %m fallback is appropriate. GNU stat is more common in CI/server environments (Linux), while BSD stat covers macOS development machines. The || operator ensures graceful fallback.

claude/skills/pr-review/collate-issues (5)

80-100: Well-structured Python executable detection with proper fallbacks.

The function correctly:

  1. Checks for Poetry availability
  2. Validates the Poetry environment executable exists and is executable (-x)
  3. Falls back to system python3
  4. Returns empty string if neither is available (handled by caller)

103-122: LGTM! Dependency validation is thorough.

The function correctly validates both the Python script file and interpreter availability before proceeding. Setting PYTHON_EXEC in this function for later use is practical.


124-138: Good URL/number validation with context preservation.

The function correctly:

  • Validates GitHub URL format and passes the full URL through to preserve repo context for cross-repo fetching
  • Accepts plain numeric PR numbers
  • Provides clear error messaging

206-208: Clean delegation to Python via exec.

Using exec to replace the shell process with Python is efficient and avoids orphaned processes. The "${python_args[@]}" expansion correctly handles empty arrays (expands to nothing when empty).

One consideration: since exec replaces the current process, any cleanup code after line 208 would never execute. This is fine here since there's no cleanup needed.


176-179: Backward compatibility for legacy options is appropriate.

Silently ignoring --include-praise and --unfinished-only maintains backward compatibility for existing scripts or user aliases. Consider adding a deprecation warning in the future if these should be formally removed.

claude/skills/pr-review/collate_issues.py (9)

74-100: LGTM! Well-structured OnexError implementation.

The custom exception class properly implements:

  • Error code for categorization
  • Context dict for debugging information
  • Formatted __str__ output
  • Comprehensive docstring with Args and Example

This aligns with the coding guideline requiring OnexError for error handling.


187-228: LGTM! Severity classification with proper priority order.

The function correctly:

  • Checks patterns in priority order (CRITICAL → MAJOR → MINOR → NITPICK)
  • Uses case-insensitive matching
  • Returns enum values (not string literals, per coding guidelines)
  • Has comprehensive docstring

486-534: Well-designed dual-path filtering with location override.

The add_issue helper correctly:

  • Trusts structured patterns (only applies minimal 2-word check)
  • Applies full noise/actionable filtering for unstructured content
  • Uses location override when provided, falling back to source
  • Deduplicates by normalized summary

657-686: LGTM! Claude Code section-aware extraction with severity mapping.

The implementation correctly:

  • Maps Claude Code headers to severity levels (Critical → CRITICAL, High Priority → MAJOR, etc.)
  • Upgrades items with (BLOCKING) or (REQUIRED) to CRITICAL
  • Cleans the title after token detection
  • Marks items as trusted structured patterns

1008-1024: Critical fix: AI reviewer comments bypass noise filtering.

This correctly ensures Claude Code and CodeRabbit structured comments are never filtered as noise. The structured content extraction (extract_issues_from_body) will handle parsing their format.

Minor: Line 1018 uses line_text which avoids shadowing the outer line variable (good), but the loop variable is checking body content, not line numbers.


1146-1158: LGTM! Proper extraction of PR metadata from fetched data.

Using pr_data.get("pr_number") and pr_data.get("repository") ensures the actual resolved values are used (important for cross-repo URL input). The get_repo_name() fallback provides resilience.


1308-1368: LGTM! Clean parallel-solve output formatting.

The function produces a structured list format suitable for /parallel-solve consumption:

  • Clear severity headers with emojis
  • Consistent - prefix for list items
  • Location and description per issue
  • Helpful warning for UNMATCHED section

42-66: LGTM! Robust import fallback for standalone execution.

The try/except pattern with sys.path manipulation allows the script to run both as a module and standalone. This is a practical approach for CLI tools.


586-608: The section membership logic correctly handles non-standard section ordering.

The position-based detection with intervening-section checks actively handles variable ordering: each section check verifies that no other section headers appear between the section header and the file position. This defensive approach correctly classifies files regardless of whether sections appear in standard order, making the stated edge case concern invalid.

Comment on lines +1475 to +1488
# Show stats if requested
if args.stats:
print("")
print("Statistics:")
print(f" Critical: {len(issues.critical)}")
print(f" Major: {len(issues.major)}")
print(f" Minor: {len(issues.minor)}")
print(f" Nitpick: {len(issues.nitpick)}")
print(f" Unclassified: {len(issues.unclassified)}")
print(f" Total: {issues.total_count}")
if issues.resolved_count > 0:
print(f" Resolved: {issues.resolved_count}")
print(f" Open: {issues.open_count}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Stats output after JSON breaks JSON validity.

When --stats is combined with --json, the statistics are printed after the JSON object, resulting in invalid JSON output (e.g., {"pr_number": 40, ...}\n\nStatistics:\n...).

Consider either:

  1. Skip stats output when --json is specified
  2. Include stats within the JSON object
  3. Document that --stats and --json are mutually exclusive
         # Show stats if requested
-        if args.stats:
+        if args.stats and not args.json:
             print("")
             print("Statistics:")
📝 Committable suggestion

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

Suggested change
# Show stats if requested
if args.stats:
print("")
print("Statistics:")
print(f" Critical: {len(issues.critical)}")
print(f" Major: {len(issues.major)}")
print(f" Minor: {len(issues.minor)}")
print(f" Nitpick: {len(issues.nitpick)}")
print(f" Unclassified: {len(issues.unclassified)}")
print(f" Total: {issues.total_count}")
if issues.resolved_count > 0:
print(f" Resolved: {issues.resolved_count}")
print(f" Open: {issues.open_count}")
# Show stats if requested
if args.stats and not args.json:
print("")
print("Statistics:")
print(f" Critical: {len(issues.critical)}")
print(f" Major: {len(issues.major)}")
print(f" Minor: {len(issues.minor)}")
print(f" Nitpick: {len(issues.nitpick)}")
print(f" Unclassified: {len(issues.unclassified)}")
print(f" Total: {issues.total_count}")
if issues.resolved_count > 0:
print(f" Resolved: {issues.resolved_count}")
print(f" Open: {issues.open_count}")
🤖 Prompt for AI Agents
In claude/skills/pr-review/collate_issues.py around lines 1475-1488, printing
statistics unconditionally after the JSON output breaks JSON validity when
--json is used; update the code so stats are skipped when args.json is true
(i.e., wrap the entire stats block in an if not args.json condition), or
alternatively enforce mutual exclusivity by adding an argparse conflict/error if
both flags are passed—implement the first option (skip stats with --json) by
checking args.json before printing and keep existing behavior otherwise.

@claude

claude Bot commented Dec 4, 2025

Copy link
Copy Markdown

PR Review: Python Migration for collate-issues

Completed a thorough review of PR #46. This is an excellent refactoring that addresses a critical memory issue.


✅ Strengths

1. Strong Architecture & Problem Solving

  • Root cause analysis is spot-on: jq was using regex inefficiently (30+ scan() calls on 18KB+ bodies)
  • Python migration is the right choice: eliminates exponential memory growth
  • Pydantic models: Excellent type-safe data structures (PRIssue, CollatedIssues, etc.)

2. Code Quality

  • Well-documented with comprehensive docstrings
  • ONEX compliance with structured error handling (OnexError)
  • Clean separation of concerns
  • Test coverage exists (test_models.py)

3. Features & Functionality

  • Cross-repo URL support works correctly
  • Claude Code bot detection with (BLOCKING) marker handling (lines 657-685)
  • Multiple bot formats: CodeRabbit HTML and Claude markdown
  • Resolution tracking via GitHub threads

🔴 Critical Issues

1. Security: Subprocess Timeout Vulnerability

Location: collate_issues.py:878-883

The 120-second timeout may be insufficient for large PRs or cross-repo fetches with network latency.

Recommendation:

  • Increase to 300 seconds (5 minutes)
  • Add FETCH_TIMEOUT_SECONDS env var override
  • Log warnings at 60 seconds

2. Bot Detection Edge Case

Location: collate_issues.py:1008-1010

May not account for variations like claude-code[bot] (hyphenated), anthropic-bot, future bots.

Recommendation: Verify models.py patterns are comprehensive or document why current patterns suffice.

3. Data Loss Risk: Comment ID Type Conversion

Location: collate_issues.py:1044-1050

GraphQL node IDs like IC_kwDOABC123 are silently dropped (set to None), making correlation impossible.

Recommendation:

  • Change PRIssue.comment_id to str | int | None
  • Update Pydantic validator
  • Add migration note

🟠 Major Issues

4. Regex Performance: Potential ReDoS

Location: collate_issues.py:625

Pattern [^*]+ can cause catastrophic backtracking with malformed markdown.

Recommendation: Use bounded quantifier [^*]{1,500}

5. Missing Error Context in Resolution Map

Location: collate_issues.py:793-823

Malformed resolved_threads data is silently skipped without warnings.

Recommendation: Add debug logging or raise OnexError with context.

6. Test Coverage Gap

Location: test_models.py

Need tests for:

  • extract_issues_from_body() with real Claude/CodeRabbit examples
  • Edge cases: empty bodies, malformed markdown, Unicode
  • Resolution filtering (hide_resolved, show_resolved_only)

Recommendation: Add integration tests with fixture data.


🟡 Minor Issues

7. Hardcoded Magic Numbers

Magic number 10 (min summary length) at line 1077 should be MIN_DESCRIPTION_LENGTH constant.

8. Inconsistent Line Number Validation

Lines 1054 and 1107 duplicate line number validation logic. Extract to helper function.


📊 Test Plan

Validated claims:

  • ✅ PR 45: 4 nitpicks extracted
  • ✅ PR 5: 93 issues (4 critical, 9 major, 12 minor, 27 nitpick)
  • ✅ No memory errors
  • ✅ Cross-repo support

Recommendation: Add as CI integration tests.


🎯 Summary

Overall Assessment: APPROVE with reservations ✅

High-quality refactoring solving a real problem. Python implementation is well-structured, type-safe, and maintainable.

Must address before merge:

  1. Increase subprocess timeout + configurability
  2. Verify bot detection completeness
  3. Preserve GraphQL node IDs

Actions Before Merge:

  1. Fix critical issues 1-3
  2. Add integration tests
  3. Verify memory usage <100MB on PR 5 (93 issues)

Net Impact:

  • ✅ Fixes OOM crashes
  • ✅ -454 lines (740 → 215 bash + 327 Python)
  • ✅ Type safety with Pydantic
  • ⚠️ Test coverage improvement needed

Metrics: 3 files, -454 lines ✅

Great work! Migration from jq to Python is exactly the right solution.


Reviewed by: Claude Code (Sonnet 4.5)
Date: 2025-12-04

…ction

Two critical fixes for the collate-issues script:

1. Claude Bot Comment Extraction (collate_issues.py:687-742)
   - Fixed regex to capture emoji indicators and status labels after **Title**
   - Added severity mapping: ⚠️ (Non-Blocking) → MAJOR, ✅ (Safe) → MINOR
   - Strips 12 common emoji indicators from final titles
   - Removes status labels in parentheses: (BLOCKING), (SAFE), etc.

   Before: Claude comments ended up in UNMATCHED section
   After: Properly categorized by severity with clean titles

2. Python Environment Detection (collate-issues:81-124)
   - Searches upward 5 levels for pyproject.toml to find project root
   - Runs 'poetry env info' from project root, not script directory
   - Added Docker container path fallback (/workspace/omniclaude)

   Before: ModuleNotFoundError: No module named 'pydantic'
   After: Uses Poetry venv with all dependencies available

Tested with:
- PR #110 (omnibase_core): Extracts 2 MAJOR + 2 MINOR correctly
- PR #5 (this repo): Correctly reports "No issues found"
- Works from both project directory and ~/.claude/skills path
@claude

claude Bot commented Dec 4, 2025

Copy link
Copy Markdown

Code Review - PR #46: Python Migration for PR Review Collator

Summary

This PR successfully resolves the critical OOM issue by migrating from jq to Python with Pydantic models. Well-executed with significant improvements in memory efficiency, type safety, and maintainability.

Overall Assessment: ✅ Approve with Minor Suggestions


Strengths 🌟

  1. Excellent Problem Resolution: Root cause analysis is spot-on - jq regex caused exponential memory growth
  2. Strong Type Safety: Comprehensive Pydantic models provide excellent validation
  3. Clean Architecture: Clear separation of concerns, ONEX-compliant error handling
  4. Robust Pattern Matching: Comprehensive and maintainable severity detection
  5. Excellent Documentation: Thorough docstrings with examples and type hints
  6. Cross-Repo Support: Full GitHub URL support is valuable

Critical Issues 🔴

1. Potential Import Failure (collate_issues.py:42-66)
Fallback import logic could fail silently if models.py has missing dependencies. Add error handling with proper error messages and exit code.

2. Boolean Logic Error (collate_issues.py:587-604)
Section detection logic has overly complex conditions that could misidentify sections. Refactor using a helper function to find the active section.


High Priority 🟠

3. Missing Input Validation (collate_issues.py:905) - Add validation for empty strings, invalid URLs, negative PR numbers

4. Integer Conversion (collate_issues.py:1094-1095) - Check line is not None explicitly before str conversion

5. Poetry Detection (collate-issues:82-121) - Validate pydantic is available after finding poetry executable


Medium Priority 🟡

  1. Extract repeated section extraction logic to helper function
  2. Standardize error message formats
  3. Replace magic numbers with named constants

Low Priority ⚪

  1. Group NOISE_PATTERNS into sub-lists
  2. Add return type to validate_pr_input
  3. Consistent bash quoting

Testing & Documentation 📋

12. Test Coverage - Add unit tests for Claude/CodeRabbit extraction, severity classification, section detection

13. Migration Guide - Document changes for users depending on old jq output


Security 🔒

✅ No issues - proper input validation, safe subprocess calls, no hardcoded secrets

Performance ⚡

✅ Excellent: 99%+ memory reduction (53MB vs OOM), -454 lines, strong type safety


Conclusion

High-quality PR solving a critical issue. Well-architected with strong type safety and excellent documentation.

Recommendation: ✅ Approve and merge after addressing critical issues #1-2.

Great work! 🎉

Jonah Gabriel added 3 commits December 4, 2025 23:15
…matting

Add section-aware extraction for Claude bot "Suggestions for Improvement"
and "Observations & Suggestions" sections that use plain text formatting
instead of bold markdown.

Problem:
- Claude reviews include actionable suggestions in format: ### 1. Title
- Previous extraction required bold format: ### 1. **Title**
- Suggestions like "Consider Adding helper method" were missed

Solution (collate_issues.py:687-748):
- Added section-aware extraction for Suggestions/Observations sections
- Handles both plain text (### 1. Title) and bold (#### 1. **Title**)
- Intelligent severity classification from keywords:
  - CRITICAL: "critical", "must", "required"
  - MAJOR: "should", "important"
  - MINOR: "consider", "potential", "enhancement" (default)
- Filters items <3 words to avoid false positives
- Removes emoji indicators for clean titles

Results:
- PR #3 (omniagent): Now extracts 4 MINOR (was 1)
  - "Potential Enhancement: Comparison/Ordering for Confidence Levels"
  - "Consider Adding `from_value()` Helper for Agent Colors"
  - "Type Safety: Consider Using `Literal` Types"
- PR #110 (omnibase_core): Still works correctly (2 MAJOR, 2 MINOR)
- Praise items correctly remain in UNMATCHED section
Add support for CodeRabbit inline comments from pulls/{pr}/comments endpoint.
These use a different format than the main review comments:

Format A (with analysis chain):
  _⚠️ Potential issue_ | _🔴 Critical_
  <details>analysis</details>
  **Issue title**

Format B (direct suggestion):
  _🛠️ Refactor suggestion_ | _🟠 Major_
  **Issue title**
  <details>AI prompt</details>

The fix detects the severity indicator pattern and correctly extracts
the issue title based on whether there's a <details> block immediately
following the severity line (Format A) or directly after (Format B).
… detection

Add support for Claude's "Areas for Improvement" section pattern and inline
severity hints in parentheses:

- Add section pattern: ### 🔍 Areas for Improvement
- Detect (Minor), (Major), (Critical), (Very Minor), (Nitpick) hints
- Detect (Security Best Practice), (Potential Bug), (Bug) as critical/major
- Strip severity hints from displayed titles after classification

This ensures issues like "Mypy Cache (Minor)" are correctly classified as
minor instead of unclassified.
@claude

claude Bot commented Dec 5, 2025

Copy link
Copy Markdown

Code Review for PR #46: Python Migration of collate-issues

Summary

This PR successfully migrates the collate-issues script from a 300-line jq-based implementation to Python with Pydantic models, resolving critical memory exhaustion issues and adding proper Claude Code bot comment extraction.

✅ Strengths

  1. Problem Resolution: Addresses jq exponential memory growth (30+ scan(), 60+ test() calls)
  2. Type Safety: Excellent Pydantic models (PRIssue, CollatedIssues, CommentSeverity, CommentStatus)
  3. Code Quality: Well-structured with clear separation of concerns
  4. Documentation: Comprehensive docstrings with examples
  5. Cross-Repo Support: Handles GitHub URLs for cross-repository PR reviews
  6. Bot Detection: Robust Claude Code and CodeRabbit comment parsing
  7. Testing: Verified with PR 45 (4 issues) and PR 5 (93 issues)

🔴 Critical Issues

1. Python Executable Detection May Fail (collate-issues:76-119)
Hardcoded fallback to /workspace/omniclaude assumes Docker container structure.
Fix: Add error handling when no Python executable is found.

2. Security: Subprocess Injection Risk (collate_issues.py:1082-1086)
User input passed to subprocess without validation.
Fix: Add input validation for PR URLs/numbers before subprocess execution.

🟠 Major Issues

3. Missing Test Coverage
No tests for extract_issues_from_body() (450+ lines), classify_severity(), or cross-repo URLs.
Fix: Add pytest unit tests.

4. Type Annotation Inconsistency (collate_issues.py:89)
Mixed use of dict|None vs Optional[dict].
Fix: Standardize on one style.

5. Poetry Detection Error Handling (collate-issues:76-92)
Silent fallback to system python3 without warning.
Fix: Add diagnostic stderr output.

🟡 Minor Issues

  1. Long Function: extract_issues_from_body() is 490 lines
  2. Noise Patterns: 90+ hardcoded regexes - consider config file
  3. Docstring Examples: Update emoji format

⚪ Nitpicks

  1. TypedDict import may be unused (line 30)
  2. PARALLEL_SOLVE_FORMAT could be PARALLEL_FORMAT
  3. MAX_DESCRIPTION_LENGTH = 200 could be CLI argument

🔒 Security

Overall: Low risk, needs input sanitization

📊 Performance

Excellent improvements:

  • Memory: ~53MB Python vs OOM (jq)
  • Time: <2s vs 28-37s OOM
  • Cross-repo: Native URL support
    Optimization: Compile regex patterns at module level

✅ Approval: Approve with minor revisions

Merge Checklist:

📈 Metrics

  • Lines: +587/-813 = -226 net ✅
  • Files: 3 modified
  • Type Safety: Full Pydantic validation
  • Maintainability: Significant improvement

Great work! The jq to Python migration is the right decision. Address the critical input validation and this will be ready to merge.

🤖 Generated with Claude Code (https://claude.com/claude-code)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
claude/skills/pr-review/collate_issues.py (1)

487-535: ExtractedIssue.location is never propagated into PRIssue, losing CodeRabbit file/line-range context.

The new extraction paths correctly compute rich locations (e.g., "[file.py:305-312]") and store them on ExtractedIssue.location, but collate_pr_issues ignores this when instantiating PRIssue:

  • Line [530] sets issue_location = location if location else source on the ExtractedIssue.
  • Lines [699-705] build location overrides like "[{file_path}:{line_range}]" for CodeRabbit HTML sections.
  • Lines [1257-1265] construct PRIssue using only path and line, never consulting item["location"].
  • Lines [1321-1328] deduplicate by f"{issue.location}|{issue.description}", where issue.location comes from PRIssue.location, which is derived purely from file_path/line_number (see models.PRIssue.location), so the richer override is lost.

Consequences:

  • CodeRabbit HTML/summary comments that don't populate path/line on the PR comment will end up with empty locations, despite the extractor computing accurate [file:line-range] data.
  • Deduplication and the new /parallel-solve formatter will not benefit from the per-issue locations the PR summary describes.

Consider wiring the override through when constructing PRIssue, for example by parsing item["location"] into file_path and line_number (e.g., use the first line from a range), or by extending PRIssue to accept an explicit location_override that location can prefer.

Also applies to: 699-717, 1244-1267, 1321-1328

♻️ Duplicate comments (1)
claude/skills/pr-review/collate_issues.py (1)

1679-1692: Stats output with --stats still breaks JSON when combined with --json.

When both --json and --stats are supplied:

  • Lines [1660-1661] print the JSON payload.
  • Lines [1679-1692] then append human-readable statistics.

This reproduces the previously reported problem where stats after the JSON make the output invalid JSON (e.g., {"pr_number": 40, ...}\n\nStatistics:\n...). Consider skipping stats when JSON is requested:

-        # Show stats if requested
-        if args.stats:
+        # Show stats if requested (but never after JSON, to keep output valid)
+        if args.stats and not args.json:
             print("")
             print("Statistics:")
             print(f"  Critical: {len(issues.critical)}")
             print(f"  Major: {len(issues.major)}")
             print(f"  Minor: {len(issues.minor)}")
             print(f"  Nitpick: {len(issues.nitpick)}")
             print(f"  Unclassified: {len(issues.unclassified)}")
             print(f"  Total: {issues.total_count}")
             if issues.resolved_count > 0:
                 print(f"  Resolved: {issues.resolved_count}")
                 print(f"  Open: {issues.open_count}")
🧹 Nitpick comments (2)
claude/skills/pr-review/collate_issues.py (1)

1512-1572: New /parallel-solve formatter matches the intended grouping and uses locations appropriately.

format_issues_parallel_solve cleanly mirrors the human formatter’s grouping (CRITICAL → UNMATCHED) and includes issue.location when present, which is exactly what a /parallel-solve consumer needs. The include_nitpicks toggle is respected as well.

If you end up propagating richer locations (e.g., from CodeRabbit HTML), this function will benefit automatically without changes.

claude/skills/pr-review/collate-issues (1)

10-32: Wrapper delegation, Python discovery, and PR input validation look solid.

The bash wrapper is now a thin, robust delegator:

  • get_python_executable sensibly prefers a Poetry env discovered via pyproject.toml, handles the /workspace/omniclaude container path, and finally falls back to python3.
  • check_dependencies verifies both collate_issues.py and a usable Python interpreter before proceeding.
  • validate_pr_input correctly accepts either a numeric PR or a github.com/.../pull/<n> URL and passes the URL through so the Python side can retain repo context for cross-repo PRs.
  • Flag parsing cleanly forwards supported options (--include-nitpicks, --parallel-solve-format, --hide-resolved, --show-resolved-only, --stats) to the Python CLI, while legacy options are ignored for backward compatibility.

Only very small nit: SHOW_STATS is no longer used in the shell logic (Python handles --stats), but that’s harmless and can be left as-is unless you’re cleaning up globals.

Also applies to: 80-124, 126-137, 148-162, 164-233

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between c1421ed and 93f0286.

📒 Files selected for processing (2)
  • claude/skills/pr-review/collate-issues (5 hunks)
  • claude/skills/pr-review/collate_issues.py (17 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/canonical_patterns.mdc)

**/*.py: All methods must include docstrings with description, Args, Returns, Raises, and Example sections
All error handling must use OnexError exception class with specific error codes from error enum, never raise generic Exception or ValueError

Automatically perform code standards checks on all Python files in the PR, including: Any/Any imports and Dict[str, Any] usage violations, naming convention violations (tool_, model_, enum_ prefixes), anti-pattern detection (direct tool instantiation, telescoping constructors), and type safety enforcement (strongest typing possible). Fix all violations immediately with proper commit messages.

**/*.py: Use Enum types for status values instead of string literals (e.g., use EnumOnexStatus.SUCCESS not status: str = 'success')
Import enums from omnibase.enums module
Import protocols from omnibase.protocol.protocol_<name> module paths
Use TYPE_CHECKING pattern for forward references to avoid circular imports when using string annotations
Do not remove [AI_PROMPT] comments from generated code; they provide actionable guidance for future AI implementation
Avoid camelCase filenames; use snake_case with appropriate prefixes (tool_, protocol_, model_, enum_, etc.)

NEVER create scenarios from scratch - ALWAYS clone existing scenarios to avoid missing required fields, version format errors, and incorrect tool configurations

**/*.py: Use type-safe configuration via Pydantic Settings from config/settings.py with 90+ type-safe variables organized into External Service Discovery, Shared Infrastructure, AI Provider API Keys, Local Services, and Feature Flags
Access PostgreSQL connection strings via settings.get_postgres_dsn() or settings.get_postgres_dsn(async_driver=True) rather than constructing connection strings manually
Publish intelligence requests to Kafka event bus using topics: dev.archon-intelligence.intelligence.code-analysis-{requested,completed,failed}.v1 for consistency and event-driven architecture
Implement...

Files:

  • claude/skills/pr-review/collate_issues.py
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: When user requests PR description creation or pull request submission (e.g., 'create a PR description', 'create a PR', 'submit for review'), automatically execute a complete workflow: (1) gather git statistics, (2) analyze changes, (3) check work tickets, (4) generate content using template, (5) create full PR via `gh pr create` targeting `development` branch by default unless user specifies otherwise, (6) automatically switch to code review mode and perform standards checks on Python files, (7) fix any violations found, and (8) report results to user.
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to **/*.py : Automatically perform code standards checks on all Python files in the PR, including: Any/Any imports and Dict[str, Any] usage violations, naming convention violations (tool_, model_, enum_ prefixes), anti-pattern detection (direct tool instantiation, telescoping constructors), and type safety enforcement (strongest typing possible). Fix all violations immediately with proper commit messages.
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: When user requests PR description creation or pull request submission (e.g., 'create a PR description', 'create a PR', 'submit for review'), automatically execute a complete workflow: (1) gather git statistics, (2) analyze changes, (3) check work tickets, (4) generate content using template, (5) create full PR via `gh pr create` targeting `development` branch by default unless user specifies otherwise, (6) automatically switch to code review mode and perform standards checks on Python files, (7) fix any violations found, and (8) report results to user.

Applied to files:

  • claude/skills/pr-review/collate-issues
📚 Learning: 2025-11-24T16:33:09.011Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T16:33:09.011Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Each PR description must include the following required sections: PR Title, Branch, PR ID or Link, Summary of Changes, Key Achievements, Prompts & Actions (Chronological with timestamps in ISO 8601 format and agent attribution), Major Milestones, Blockers / Next Steps, Metrics (Lines Changed in "+X / -Y" format, Files Modified count, Time Spent if tracked), and must include optional sections where relevant: Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), and Release Notes Snippet

Applied to files:

  • claude/skills/pr-review/collate-issues
  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Each PR description MUST include the following required sections: PR Title, Branch, Summary of Changes, Key Achievements, Prompts & Actions (Chronological), Major Milestones, Blockers / Next Steps, and Metrics (Lines Changed, Files Modified, Time Spent). Optional sections include: PR ID or Link, Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), and Release Notes Snippet.

Applied to files:

  • claude/skills/pr-review/collate-issues
  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:22:03.323Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/CHECKLIST_RULE.md:0-0
Timestamp: 2025-11-24T17:22:03.323Z
Learning: Applies to **/work_tickets/**/*.yaml : Mark critical gaps in work ticket checklists with ⚠️ indicators and architecture violations separately from functional requirements

Applied to files:

  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:23:24.207Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/modes.mdc:0-0
Timestamp: 2025-11-24T17:23:24.207Z
Learning: CODE_REVIEW mode: Conduct structured, multi-faceted code review analyzing code quality, security, performance, architecture, and standards. Use severity levels: CRITICAL, MAJOR, MINOR, SUGGESTION. Forbidden: Making code changes or implementations.

Applied to files:

  • claude/skills/pr-review/collate_issues.py
🧬 Code graph analysis (1)
claude/skills/pr-review/collate_issues.py (1)
claude/skills/pr-review/models.py (6)
  • CommentSeverity (132-168)
  • location (1286-1292)
  • severity_emoji (1295-1304)
  • classify_severity (571-592)
  • classify_severity (1597-1609)
  • is_ai_reviewer (234-236)
🔇 Additional comments (1)
claude/skills/pr-review/collate_issues.py (1)

1065-1115: pr_input plumbing and repository/PR resolution look correct.

Using pr_input: str | int throughout fetch_pr_data and collate_pr_issues, passing the original value to fetch-pr-data, and then deriving actual_pr_number / actual_repository from the fetched JSON (lines [1350-1355]) is a clean way to support both numeric PRs and cross-repo URLs while preserving accurate metadata. Error contexts including {"pr_input": str(pr_input)} are also helpful for debugging.

Also applies to: 1145-1159, 1350-1356

…tion

Add support for additional Claude review section patterns:
- ### 📝 Minor Suggestions (Non-Blocking)
- ### 💡 Future Optimization (Not Blocking)
- ### 💡 Recommendations
- ### 📋 Follow-ups

Also capture plain numbered lists (1. Item) and bullet items (- Item)
within these sections, not just markdown headers with ### prefix.

This ensures "Consider documenting..." style suggestions are captured.
@claude

claude Bot commented Dec 5, 2025

Copy link
Copy Markdown

PR Review - PR #46

Summary

This PR successfully resolves the memory exhaustion error by migrating from jq to Python (~53MB vs OOM). Net reduction of -454 lines with added cross-repo support and improved Claude bot extraction.

Code Quality ✅

Strengths:

  • Excellent architecture with clean bash/Python separation
  • Type-safe Pydantic models and ONEX-compliant error handling
  • Comprehensive docstrings and sophisticated bot format detection
  • Robust noise filtering preserving AI reviewer comments

Minor Issues:

  1. Type Safety (MINOR): Consider TypedDict for resolution data instead of dict[str, Any] (line 37)
  2. Missing Docstring (NITPICK): fetch_pr_data missing Raises section (line 1081)
  3. Error Handling (MINOR): Use OnexError instead of ValueError (line 1714)

Security & Performance ✅

Security: ✅ No hardcoded credentials, proper timeouts, safe JSON parsing, no injection vulnerabilities

Performance: ✅ Excellent - 53MB Python vs OOM jq, proper timeouts, efficient deduplication
⚠️ Minor: Consider profiling regex on 100KB+ PR bodies

Test Coverage ⚠️

Tested: PR 45 (4 issues), PR 5 (93 issues), PR 110 (4 issues), cross-repo URLs

Missing: Unit tests for classify_severity(), is_noise(), extract_issues_from_body(), error conditions

Recommendation: Add pytest tests for core functions

Best Practices ✅

Excellent:

  • Clean code organization
  • Poetry/python3 fallback with Docker support
  • Backward compatibility for legacy flags
  • Cross-platform stat compatibility
  • GitHub GraphQL resolution detection

Suggestions:

  1. Stats with JSON (MINOR): Skip stats when --json is used (invalid JSON output)
  2. Location Propagation (MODERATE): ExtractedIssue.location not propagated to PRIssue (lines 699-717, 1257-1265)

Architecture ✅

Strengths:

  • Kafka integration, separation of concerns, Pydantic models, extensible, ONEX-compliant

Improvement: Wire location overrides from ExtractedIssue to PRIssue for better CodeRabbit support

Overall: 9/10 - Excellent! 🎉

Before Merge (non-blocking):

  1. Add unit tests
  2. Fix --json + --stats interaction
  3. Consider TypedDict for resolution data
  4. Add missing docstring Raises sections

Recommendation: APPROVE ✅

Minor issues are non-blocking and can be addressed in follow-ups. Core functionality is solid and well-tested on real PRs.

Add comprehensive Linear insights skill suite with slash commands for:
- deep-dive: Daily work analysis with velocity/effectiveness scoring
- project-status: Project health dashboard with blockers and ETA
- suggest-work: Priority backlog recommendations with repo context
- velocity-estimate: Historical velocity analysis and ETA prediction

Includes caching layer, JSON output modes, and configurable project shortcuts.
@claude

claude Bot commented Dec 14, 2025

Copy link
Copy Markdown

PR Review: Fix collate-issues Memory Issues & Add Linear Insights Skill

Summary

This PR successfully addresses critical memory issues in the PR review tooling and adds a comprehensive Linear Insights skill suite. The migration from jq to Python for collate-issues is well-architected, and the new Linear Insights features demonstrate strong design patterns.

🟢 Strengths

1. Excellent Problem Solving (collate-issues Migration)

  • Root Cause Analysis: Clearly identified the jq regex explosion issue (30+ scan() calls causing OOM)
  • Performance Improvement: ~53MB Python vs OOM jq - dramatic improvement
  • Clean Architecture: Proper separation with Pydantic models, type safety, and ONEX-compliant error handling
  • Net Reduction: -454 lines despite adding functionality shows good refactoring

2. Robust Issue Extraction (collate_issues.py)

The extraction logic handles multiple bot formats elegantly:

  • Claude Code bot section-aware parsing (### **Critical Issues**)
  • CodeRabbit HTML format (<details> blocks with line references)
  • CodeRabbit inline format (_⚠️ Potential issue_ | _🔴 Critical_)
  • Proper severity classification with upgrade logic (BLOCKING → CRITICAL)
  • Smart noise filtering to exclude praise/metadata

3. Type Safety & Validation

  • Pydantic models throughout (PRIssue, CollatedIssues, CommentSeverity)
  • Type hints on all functions
  • ONEX-compliant error handling with context
  • Proper enum usage for bot types, severities, statuses

4. Linear Insights Design

The new skill suite follows excellent patterns:

  • Clear separation of concerns (setup, deep-dive, velocity, project-status, suggest-work)
  • Markdown command definitions for discoverability
  • Proper configuration via YAML
  • Snapshot-based architecture (canonical data sources)

5. Documentation Quality

  • Comprehensive command markdown files
  • Usage examples with multiple options
  • Clear expected output formats
  • Performance targets documented

🟡 Areas for Improvement

1. Code Duplication in Severity Detection (Minor)

Location: claude/skills/pr-review/collate_issues.py:187-228

The classify_severity() function has overlapping patterns that could be consolidated.

2. Noise Pattern Complexity (Minor)

Location: claude/skills/pr-review/collate_issues.py:235-325

The NOISE_PATTERNS list has 50+ regex patterns. Some are redundant. Grouping into semantic categories would reduce pattern count from 50+ to ~10 core patterns with better maintainability.

3. Magic Numbers (Very Minor)

Lines 393, 599, 823 use magic numbers like 10 and 3. Consider defining constants like MIN_TITLE_LENGTH = 10.

4. Linear Insights: Hardcoded Paths (Minor)

Location: claude/skills/linear-insights/config.yaml:152

The path /Users/jonah/Code/omni_save is user-specific. Consider using environment variable expansion.

5. Missing Unit Tests (Minor)

The PR adds 7,152 lines but no corresponding test files. Key functions that would benefit from tests:

  • classify_severity() - Test all severity patterns
  • extract_issues_from_body() - Test Claude/CodeRabbit formats
  • is_noise() / is_actionable_issue() - Test edge cases
  • build_resolution_map() - Test resolution detection

6. Error Handling Edge Case (Very Minor)

Location: claude/skills/pr-review/collate_issues.py:1268-1270, 1319

The safe comment ID conversion is repeated twice. Consider extracting to a helper function.

🟢 Security Review

No security concerns identified. The code:

  • ✅ Uses subprocess.run() with explicit args (no shell injection)
  • ✅ Has timeout protection (120s for fetch, 30s for git)
  • ✅ Validates input with Pydantic models
  • ✅ No credential exposure
  • ✅ Proper error handling with ONEX patterns

📊 Performance Considerations

Excellent improvements:

  • Memory: ~53MB Python vs OOM jq (99.5%+ improvement)
  • Complexity: O(n) parsing vs O(n²) regex explosions
  • Efficiency: Single-pass extraction with deduplication

Suggestion: The nested regex searches in extract_issues_from_body() could benefit from compilation at module level to avoid recompiling on every call.

🎯 Test Coverage

Current Coverage: PR description mentions testing on PR 45 (4 issues) and PR 5 (93 issues), which is good for integration testing.

Recommendation: Add unit tests for pattern matching edge cases, resolution status detection, noise filtering, cross-repo URLs, and skill parameter validation.

💡 Architecture Highlights

What I Love:

  1. Pydantic Model Design: The PRIssue and CollatedIssues models are clean and well-typed
  2. ONEX Compliance: Error handling with codes and context is excellent
  3. Bot Detection Pattern: Using detect_bot_type() from models for consistency
  4. Snapshot Architecture: Linear Insights using snapshots as canonical sources
  5. Configuration Management: YAML config with project shortcuts eliminates runtime lookups

✅ Recommendation

APPROVE with Minor Suggestions

This PR delivers exactly what it promises:

  • ✅ Fixes the OOM issue (critical)
  • ✅ Adds cross-repo support
  • ✅ Fixes Claude bot extraction
  • ✅ Preserves jq 1.6 compatibility fixes
  • ✅ Net -454 lines (excellent refactoring)

The Linear Insights skill suite is well-designed and follows established patterns from the codebase.

Before Merge (Optional)

  1. Add basic unit tests for classify_severity() and extract_issues_from_body()
  2. Extract magic numbers to constants
  3. Compile frequently-used regexes at module level

These are minor polish items that don't block the merge given the critical nature of the memory fix.


Great work on the migration! The Python implementation is significantly cleaner than the jq approach and sets a good foundation for future enhancements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

♻️ Duplicate comments (1)
claude/skills/pr-review/collate_issues.py (1)

1695-1708: Stats output after JSON breaks JSON validity.

When --stats is combined with --json, statistics are printed after the JSON object, resulting in invalid JSON output (e.g., {"pr_number": 40, ...}\n\nStatistics:\n...).

This issue was flagged in a previous review. The suggested fix of skipping stats when --json is specified should be applied:

         # Show stats if requested
-        if args.stats:
+        if args.stats and not args.json:
             print("")
             print("Statistics:")
🧹 Nitpick comments (15)
claude/skills/linear-insights/config.yaml (1)

152-152: Hardcoded absolute path reduces portability.

The path /Users/jonah/Code/omni_save is machine-specific. Consider using a relative path or environment variable reference for better portability.

🔎 Proposed fix
 output:
-  deep_dive_dir: "/Users/jonah/Code/omni_save"
+  deep_dive_dir: "${LINEAR_INSIGHTS_OUTPUT_DIR:-./omni_save}"
   snapshot_dir: ".cache/snapshots"
   default_format: "markdown"
claude/skills/linear-insights/suggest-work (1)

38-38: Redundant stderr redirection.

&>/dev/null already redirects both stdout and stderr; the additional 2>&1 is redundant.

🔎 Proposed fix
-    if git rev-parse --is-inside-work-tree &>/dev/null 2>&1; then
+    if git rev-parse --is-inside-work-tree &>/dev/null; then
claude/commands/deep-dive.md (1)

153-153: Hardcoded user-specific path in documentation.

Line 153 and 165 reference /Users/jonah/Code/omni_save which is machine-specific. Consider using environment variable placeholders in documentation.

claude/skills/linear-insights/setup (1)

442-443: Hardcoded path in configuration template.

The template outputs a hardcoded user-specific path. Consider using a placeholder or environment variable reference.

🔎 Proposed fix
     md_echo "output:"
-    md_echo '  deep_dive_dir: "/Users/jonah/Code/omni_save"'
+    md_echo '  deep_dive_dir: "${LINEAR_INSIGHTS_OUTPUT_DIR:-./omni_save}"'
     md_echo '  snapshot_dir: ".cache/snapshots"'
claude/skills/linear-insights/velocity-estimate (1)

546-563: Fragile multi-variable read from Python output.

The read command parsing 7 space-separated values from Python output is brittle. If the Python output format changes or contains unexpected spaces, parsing will break silently.

🔎 Consider JSON-based parsing for robustness

Instead of parsing space-separated output, consider using jq to parse the already-available JSON:

# Already have VELOCITY_RESULT_JSON, use jq consistently
if command -v jq &> /dev/null; then
    METRIC_GRADE=$(echo "$VELOCITY_RESULT_JSON" | jq -r '.grade // "signal"')
    CONFIDENCE_LEVEL=$(echo "$VELOCITY_RESULT_JSON" | jq -r '.confidence // "low"')
    # ... (already doing this above)
else
    # Fallback: use Python to output JSON fields directly
    METRIC_GRADE=$(python3 -c "import json; print(json.loads('''$VELOCITY_RESULT_JSON''').get('grade', 'signal'))")
    # etc.
fi

The current jq-based approach at lines 535-543 is the right pattern; the Python fallback at 546-563 could be simplified similarly.

claude/skills/linear-insights/deep-dive (4)

15-16: Hardcoded user-specific paths reduce portability.

The default path /Users/jonah/Code/omni_save is user-specific and will not work for other users or in CI environments.

🔎 Suggested fix
-DEFAULT_OUTPUT_DIR="/Users/jonah/Code/omni_save"
+DEFAULT_OUTPUT_DIR="${HOME}/Code/omni_save"

Or better, derive from the script's location:

DEFAULT_OUTPUT_DIR="${SCRIPT_DIR}/../../../omni_save"

183-189: Hardcoded absolute paths in embedded Python fragment the configuration.

The Python code searches hardcoded paths (/workspace/omniclaude, ~/Code/omniclaude) which duplicates the user-specific path problem. These should derive from environment variables or the script's location.

Consider passing SCRIPT_DIR to Python via environment variable:

SKILL_DIR="$SCRIPT_DIR" python3 - "$date_str" ...

Then in Python: skill_dir = os.environ.get("SKILL_DIR")


358-403: Manual JSON construction via printf is error-prone.

Building JSON with printf is fragile and risks producing invalid JSON if any variables contain special characters (quotes, newlines, backslashes). The script already uses Python for other tasks.

Consider using Python or jq for JSON generation to ensure validity:

python3 -c "
import json
print(json.dumps({
    'mode': 'generate',
    'target_date': '$TARGET_DATE',
    # ...
}, indent=2))
"

100-154: Missing validation for argument values requiring parameters.

If a user provides --date without a value (e.g., ./deep-dive --date --save), the script will use --save as the date value. Consider adding validation.

--date)
    if [[ -z "$2" || "$2" == --* ]]; then
        echo "Error: --date requires a value"
        exit 1
    fi
    TARGET_DATE="$2"
    shift 2
    ;;
claude/skills/linear-insights/estimation-accuracy (2)

11-12: Tracking file stored in script directory may cause permission issues.

Storing .estimation_history.json in SCRIPT_DIR assumes write access to the installation directory. This can fail if the script is installed in a read-only location (e.g., /usr/local/bin).

Consider using XDG data directory or a configurable location:

TRACKING_FILE="${XDG_DATA_HOME:-$HOME/.local/share}/linear-insights/.estimation_history.json"

323-327: ETA date validation is incomplete.

The regex ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ validates format but not validity (e.g., 2025-13-45 would pass). Consider adding a date parsing check.

# Validate date format and value
if ! date -d "$ETA" +%Y-%m-%d &>/dev/null 2>&1 && \
   ! date -j -f "%Y-%m-%d" "$ETA" +%Y-%m-%d &>/dev/null 2>&1; then
    echo "Error: --eta must be a valid date in YYYY-MM-DD format" >&2
    exit 1
fi
claude/skills/linear-insights/project-status (2)

340-342: Bash boolean to Python boolean conversion is incorrect.

The shell substitutions $( [[ "$SHOW_BLOCKERS" == "true" ]] && echo "True" || echo "False" ) output Python-style booleans (True/False) but they're embedded as unquoted values in a Python dict literal. If the shell command fails for any reason, this could produce syntax errors.

Consider using lowercase true/false and proper JSON boolean handling:

result = {
    # ...
    "flags": {
        "show_blockers": True if "$SHOW_BLOCKERS" == "true" else False,
        # ...
    }
}

Or pass as environment variables to Python.


94-113: YAML parsing with awk is fragile and won't handle complex YAML.

The awk-based YAML parsing assumes simple key-value pairs and specific indentation. It won't handle:

  • Quoted values with colons
  • Multi-line values
  • YAML anchors/aliases
  • Comments within values

Consider using a proper YAML parser. Python with PyYAML would be more robust:

get_project_id() {
    local project="$1"
    python3 -c "
import yaml
with open('$CONFIG_FILE') as f:
    cfg = yaml.safe_load(f)
print(cfg.get('projects', {}).get('$project', {}).get('id', ''))
"
}
claude/skills/pr-review/collate_issues.py (2)

660-663: Complex boolean logic for section detection is hard to follow.

The nested boolean conditions for determining section membership are difficult to read and verify. Consider extracting to a helper function.

🔎 Suggested refactor
def find_section_type(file_pos: int, sections: dict[str, int]) -> str | None:
    """Determine which section a file position belongs to.
    
    Returns 'nitpick', 'actionable', 'additional', or None.
    """
    # Find the closest section header that appears before file_pos
    best_section = None
    best_pos = -1
    
    for section_type, section_start in sections.items():
        if section_start >= 0 and section_start < file_pos and section_start > best_pos:
            best_section = section_type
            best_pos = section_start
    
    return best_section

# Usage:
sections = {
    'additional': additional_section_start,
    'nitpick': nitpick_section_start,
    'actionable': actionable_section_start,
}
section_type = find_section_type(file_pos, sections)
if section_type == 'additional':
    continue  # Skip positive acknowledgments

187-227: Standalone classify_severity function duplicates model method.

This function duplicates PRComment.classify_severity from models.py (per the relevant code snippets). While there's a comment about importing from models, maintaining two implementations creates divergence risk.

Consider using the model's method directly:

from models import classify_severity  # Already imported via the classify_severity wrapper at line 1596-1608 in models.py

Or document why a separate implementation is needed here.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between 93f0286 and 54c34c7.

📒 Files selected for processing (14)
  • claude/commands/deep-dive.md
  • claude/commands/project-status.md
  • claude/commands/suggest-work.md
  • claude/commands/velocity-estimate.md
  • claude/skills/linear-insights/SKILL.md
  • claude/skills/linear-insights/config.yaml
  • claude/skills/linear-insights/deep-dive
  • claude/skills/linear-insights/estimation-accuracy
  • claude/skills/linear-insights/project-status
  • claude/skills/linear-insights/setup
  • claude/skills/linear-insights/suggest-work
  • claude/skills/linear-insights/velocity-estimate
  • claude/skills/pr-review/collate_issues.py
  • claude/skills/pr-review/fetch-pr-data
✅ Files skipped from review due to trivial changes (2)
  • claude/commands/project-status.md
  • claude/skills/linear-insights/SKILL.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/canonical_patterns.mdc)

**/*.py: All methods must include docstrings with description, Args, Returns, Raises, and Example sections
All error handling must use OnexError exception class with specific error codes from error enum, never raise generic Exception or ValueError

Automatically perform code standards checks on all Python files in the PR, including: Any/Any imports and Dict[str, Any] usage violations, naming convention violations (tool_, model_, enum_ prefixes), anti-pattern detection (direct tool instantiation, telescoping constructors), and type safety enforcement (strongest typing possible). Fix all violations immediately with proper commit messages.

**/*.py: Use Enum types for status values instead of string literals (e.g., use EnumOnexStatus.SUCCESS not status: str = 'success')
Import enums from omnibase.enums module
Import protocols from omnibase.protocol.protocol_<name> module paths
Use TYPE_CHECKING pattern for forward references to avoid circular imports when using string annotations
Do not remove [AI_PROMPT] comments from generated code; they provide actionable guidance for future AI implementation
Avoid camelCase filenames; use snake_case with appropriate prefixes (tool_, protocol_, model_, enum_, etc.)

NEVER create scenarios from scratch - ALWAYS clone existing scenarios to avoid missing required fields, version format errors, and incorrect tool configurations

**/*.py: Use type-safe configuration via Pydantic Settings from config/settings.py with 90+ type-safe variables organized into External Service Discovery, Shared Infrastructure, AI Provider API Keys, Local Services, and Feature Flags
Access PostgreSQL connection strings via settings.get_postgres_dsn() or settings.get_postgres_dsn(async_driver=True) rather than constructing connection strings manually
Publish intelligence requests to Kafka event bus using topics: dev.archon-intelligence.intelligence.code-analysis-{requested,completed,failed}.v1 for consistency and event-driven architecture
Implement...

Files:

  • claude/skills/pr-review/collate_issues.py
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T16:33:09.011Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Each PR description must include the following required sections: PR Title, Branch, PR ID or Link, Summary of Changes, Key Achievements, Prompts & Actions (Chronological with timestamps in ISO 8601 format and agent attribution), Major Milestones, Blockers / Next Steps, Metrics (Lines Changed in "+X / -Y" format, Files Modified count, Time Spent if tracked), and must include optional sections where relevant: Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), and Release Notes Snippet
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Each PR description MUST include the following required sections: PR Title, Branch, Summary of Changes, Key Achievements, Prompts & Actions (Chronological), Major Milestones, Blockers / Next Steps, and Metrics (Lines Changed, Files Modified, Time Spent). Optional sections include: PR ID or Link, Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), and Release Notes Snippet.
📚 Learning: 2025-11-24T16:33:09.011Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T16:33:09.011Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Each PR description must include the following required sections: PR Title, Branch, PR ID or Link, Summary of Changes, Key Achievements, Prompts & Actions (Chronological with timestamps in ISO 8601 format and agent attribution), Major Milestones, Blockers / Next Steps, Metrics (Lines Changed in "+X / -Y" format, Files Modified count, Time Spent if tracked), and must include optional sections where relevant: Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), and Release Notes Snippet

Applied to files:

  • claude/commands/suggest-work.md
  • claude/commands/deep-dive.md
  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to **/.claude/agent-definitions/**/*.yaml : Store agent definitions as YAML configuration files in ~/.claude/agent-definitions/ directory with proper naming conventions

Applied to files:

  • claude/skills/linear-insights/config.yaml
📚 Learning: 2025-11-24T17:25:09.225Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/velocity_log.mdc:0-0
Timestamp: 2025-11-24T17:25:09.225Z
Learning: Applies to docs_private/dev_logs/**/velocity_log_*.md : Velocity logs must follow the canonical format with required sections: Date (ISO 8601), Velocity Report Title, Metadata Block (velocity_log_id, parent_log_id, Score, Lines Changed, Files Modified, Time Spent, Velocity Metric), Key Achievements, Prompts & Actions (Chronological), Major Milestones Today, Blockers/Next Steps, and optional sections (Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), Velocity Log Reference)

Applied to files:

  • claude/commands/velocity-estimate.md
  • claude/skills/linear-insights/velocity-estimate
📚 Learning: 2025-11-24T16:34:06.348Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/velocity_log.mdc:0-0
Timestamp: 2025-11-24T16:34:06.348Z
Learning: Applies to **/**/velocity/velocity_log_*.md : Velocity logs must be written in Markdown format with required sections: Date (ISO 8601), Velocity Report Title, Metadata Block (velocity_log_id, parent_log_id, Score, Lines Changed, Files Modified, Time Spent, Velocity Metric), Key Achievements, Prompts & Actions (Chronological), Major Milestones Today, Blockers / Next Steps, and optional sections (Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), Velocity Log Reference)

Applied to files:

  • claude/commands/velocity-estimate.md
  • claude/skills/linear-insights/velocity-estimate
📚 Learning: 2025-11-24T17:25:09.225Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/velocity_log.mdc:0-0
Timestamp: 2025-11-24T17:25:09.225Z
Learning: Applies to docs_private/dev_logs/**/velocity_log_*_to_*.md : Weekly velocity logs must include a 'Reproducibility' section at the end (after all day entries) with git commands for reproducing commit and change data: `git log --pretty=format`, `git diff --stat`, and `git diff` commands

Applied to files:

  • claude/commands/velocity-estimate.md
  • claude/commands/deep-dive.md
📚 Learning: 2025-11-24T17:25:09.225Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/velocity_log.mdc:0-0
Timestamp: 2025-11-24T17:25:09.225Z
Learning: Applies to docs_private/dev_logs/**/velocity_log_*.md : Velocity logs must be written in Markdown format and follow the prescribed template structure with sections in the specified order

Applied to files:

  • claude/commands/velocity-estimate.md
📚 Learning: 2025-11-24T17:25:09.225Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/velocity_log.mdc:0-0
Timestamp: 2025-11-24T17:25:09.225Z
Learning: Applies to docs_private/dev_logs/**/velocity_log_*_to_*.md : In weekly velocity logs, new day entries must be added in chronological order with the most recent day at the bottom. When adding a new day: use the previous day's velocity_log_id as parent_log_id, generate a new unique UUID for the new day's velocity_log_id, and obtain change metrics using `git diff --shortstat` and `git log --pretty=format` commands.

Applied to files:

  • claude/commands/velocity-estimate.md
  • claude/skills/linear-insights/velocity-estimate
📚 Learning: 2025-11-24T16:34:06.348Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/velocity_log.mdc:0-0
Timestamp: 2025-11-24T16:34:06.348Z
Learning: Applies to **/**/velocity/velocity_log_[0-9]{4}_[0-9]{2}_[0-9]{2}_to_[0-9]{4}_[0-9]{2}_[0-9]{2}.md : Include a 'Reproducibility' section at the end of weekly velocity logs with git commands to verify commit and change data

Applied to files:

  • claude/commands/velocity-estimate.md
📚 Learning: 2025-11-24T17:25:09.225Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/velocity_log.mdc:0-0
Timestamp: 2025-11-24T17:25:09.225Z
Learning: Applies to docs_private/dev_logs/**/velocity_log_*_to_*.md : For weekly velocity logs, cross-reference milestones and action items between days as appropriate, and update the Next Steps section on earlier days when items are completed in later days

Applied to files:

  • claude/commands/velocity-estimate.md
  • claude/skills/linear-insights/velocity-estimate
📚 Learning: 2025-11-24T17:25:09.225Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/velocity_log.mdc:0-0
Timestamp: 2025-11-24T17:25:09.225Z
Learning: Applies to docs_private/dev_logs/**/velocity_log_*.md : All required fields in velocity log entries must be included; optional fields should be included when relevant, otherwise marked as 'None'. Do not omit any required section or field.

Applied to files:

  • claude/commands/velocity-estimate.md
📚 Learning: 2025-11-24T16:34:06.348Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/velocity_log.mdc:0-0
Timestamp: 2025-11-24T16:34:06.348Z
Learning: When updating an existing weekly velocity log with a new day entry, use git commands to get detailed change metrics (git diff --shortstat), full commit list (git log), and examine individual commits (git show --stat)

Applied to files:

  • claude/commands/velocity-estimate.md
  • claude/skills/linear-insights/velocity-estimate
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : PR descriptions must include a Metrics section with: Lines Changed in '+X / -Y' format (insertions/deletions), Files Modified as an integer, and Time Spent as a duration (if tracked)

Applied to files:

  • claude/commands/velocity-estimate.md
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Each PR description MUST include the following required sections: PR Title, Branch, Summary of Changes, Key Achievements, Prompts & Actions (Chronological), Major Milestones, Blockers / Next Steps, and Metrics (Lines Changed, Files Modified, Time Spent). Optional sections include: PR ID or Link, Related Issues/Tickets, Breaking Changes, Migration/Upgrade Notes, Documentation Impact, Test Coverage, Security/Compliance Notes, Reviewer(s), and Release Notes Snippet.

Applied to files:

  • claude/commands/deep-dive.md
  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:23:24.207Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/modes.mdc:0-0
Timestamp: 2025-11-24T17:23:24.207Z
Learning: AUTONOMOUS_TASK mode: Run the full RESEARCH → REVIEW loop with no human input under pre-approved scope. Entry criteria: Approved plan with no open questions. Fail-fast ESCALATE on blockers.

Applied to files:

  • claude/commands/deep-dive.md
📚 Learning: 2025-11-24T16:32:37.719Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/modes.mdc:0-0
Timestamp: 2025-11-24T16:32:37.719Z
Learning: AUTONOMOUS_TASK mode: Run the full RESEARCH → REVIEW loop with no human input under pre-approved scope. Entry criteria: approved plan and no open questions. Use fail-fast ESCALATE on blockers.

Applied to files:

  • claude/commands/deep-dive.md
📚 Learning: 2025-11-24T17:22:03.323Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/CHECKLIST_RULE.md:0-0
Timestamp: 2025-11-24T17:22:03.323Z
Learning: Applies to **/work_tickets/**/*.yaml : Mark critical gaps in work ticket checklists with ⚠️ indicators and architecture violations separately from functional requirements

Applied to files:

  • claude/skills/pr-review/collate_issues.py
📚 Learning: 2025-11-24T17:23:24.207Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/modes.mdc:0-0
Timestamp: 2025-11-24T17:23:24.207Z
Learning: CODE_REVIEW mode: Conduct structured, multi-faceted code review analyzing code quality, security, performance, architecture, and standards. Use severity levels: CRITICAL, MAJOR, MINOR, SUGGESTION. Forbidden: Making code changes or implementations.

Applied to files:

  • claude/skills/pr-review/collate_issues.py
🧬 Code graph analysis (1)
claude/skills/pr-review/collate_issues.py (1)
claude/skills/pr-review/models.py (13)
  • CommentSeverity (132-168)
  • location (1286-1292)
  • severity_emoji (1295-1304)
  • classify_severity (571-592)
  • classify_severity (1597-1609)
  • priority_order (159-168)
  • is_ai_reviewer (234-236)
  • is_claude_bot (458-474)
  • is_claude_bot (725-727)
  • CollatedIssues (1399-1544)
  • total_count (1458-1460)
  • resolved_count (1468-1470)
  • open_count (1463-1465)
🔇 Additional comments (17)
claude/commands/velocity-estimate.md (1)

1-277: Documentation is comprehensive and well-structured.

The velocity-estimate command documentation covers all essential aspects including usage, arguments, output formats, scoring guidelines, and implementation notes. The examples are clear and actionable.

Note: Lines 141 and 189 contain a hardcoded user-specific path (/Users/jonah/Code/omni_save) in the example output. Consider using a placeholder like <OUTPUT_DIR> for documentation that may be shared.

claude/commands/suggest-work.md (1)

1-263: Documentation is complete and well-organized.

The suggest-work command documentation thoroughly covers usage patterns, CLI arguments, available projects, output formats, and implementation notes including caching and priority sorting. The examples are practical and actionable.

claude/commands/deep-dive.md (1)

1-308: Documentation is comprehensive.

The deep-dive command documentation is thorough, covering workflow steps, MCP tool calls, output formats, scoring guidelines, and implementation notes. The structure is clear and actionable.

claude/skills/linear-insights/setup (2)

545-551: Subshell variable scope in piped while loop.

The while read loop receiving input from a pipe runs in a subshell. While the local declarations are syntactically correct, any variable modifications inside the loop won't persist outside. This is fine here since you're only echoing output, but be aware of this pattern.


1-1113: Setup script is well-structured with good error handling.

The script properly validates operations, provides helpful error messages, and supports multiple output modes (markdown/JSON). The AWK-based YAML parsing is acceptable for the simple key-value structure used.

claude/skills/pr-review/fetch-pr-data (1)

413-413: Error signaling mechanism for parallel subshells is well-implemented.

The error_file approach is the correct pattern for propagating errors from parallel subshells back to the parent process. The implementation:

  1. Declares error_file in tmp directory (line 413)
  2. Writes error details on API failure (lines 538-542)
  3. Checks for error_file after wait, cleans up, and exits appropriately (lines 552-559)

This resolves the issue where subshell exits couldn't be detected by the parent.

Also applies to: 538-542, 552-559

claude/skills/linear-insights/velocity-estimate (3)

18-19: Environment variable override for path is good practice.

The default path has an environment variable override (LINEAR_INSIGHTS_DEEP_DIVE_DIR), which addresses portability concerns. Good pattern.


660-660: Cross-platform date arithmetic with fallback.

Good handling of platform differences between macOS (date -v+) and Linux (date -d). The fallback to "N/A" is appropriate.


1-819: Velocity-estimate script is comprehensive with good fallback handling.

The script demonstrates solid engineering practices:

  • Environment variable overrides for configurability
  • Cross-platform compatibility (macOS/Linux)
  • Graceful fallbacks when optional tools (bc, jq) are unavailable
  • Both markdown and JSON output modes
  • Integration with Python velocity_calculator library with fallback
claude/skills/linear-insights/estimation-accuracy (1)

1-492: LGTM on overall structure and fallback patterns.

The script has good structure with:

  • Clear mode separation (--show, --record, --analyze)
  • Proper jq -> Python fallback for JSON processing
  • Consistent error handling with exit codes
  • Helpful usage documentation
claude/skills/pr-review/collate_issues.py (7)

1286-1291: Variable line is shadowed in nested loop.

The variable line at line 1249 (from comment.get("line")) is shadowed by line_text being assigned to line in the pattern at line 1291. While this specific code uses line_text, the pattern is confusing.

Wait - looking more carefully, line 1291 uses line_text not line. Let me re-examine.

Actually, looking at lines 1288-1291:

for line_text in lines:
    line_text = line_text.strip()

This is fine - line_text is the loop variable. The outer line from line 1226 (line = comment.get("line")) is not shadowed here.


458-535: Function add_issue is well-structured with good documentation.

The nested add_issue function properly:

  • Documents parameters with docstring
  • Handles location override correctly
  • Applies appropriate filtering based on source
  • Prevents duplicates via seen_summaries

540-608: CodeRabbit inline comment extraction is comprehensive.

The pattern matching for CodeRabbit inline formats handles:

  • Severity indicators with emoji mapping
  • Format A (with analysis chain) and Format B (direct)
  • Title extraction after </details> blocks
  • AI prompt marker skipping

1228-1244: AI reviewer noise filtering bypass is correctly implemented.

The logic properly ensures Claude and CodeRabbit comments are never filtered as noise, addressing the PR objective. The check happens before noise filtering:

is_ai_reviewer = is_claude_bot(author) or is_coderabbit(author)
if not is_ai_reviewer:
    # ... noise filtering only for human comments

1528-1588: New format_issues_parallel_solve function is well-designed.

The function:

  • Has proper docstring with Args/Returns
  • Handles all severity levels consistently
  • Uses location information appropriately
  • Produces clean output format for /parallel-solve

74-99: OnexError implementation follows coding guidelines.

The custom exception class:

  • Provides structured error handling with error codes
  • Includes context dict for additional information
  • Has proper docstring with example

This aligns with the coding guideline: "All error handling must use OnexError exception class with specific error codes."


115-121: TypedDict for ExtractedIssue provides type safety.

Good use of TypedDict for the internal issue structure. The location field was added to support the new location propagation feature.

Comment on lines +18 to +22
user:
id: "7a850ce1-f95e-431f-b4e3-62f7449f04c0"
name: "Jonah Gray"
email: "jonah@omninode.ai"
displayName: "jonah"

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

PII exposure in configuration file.

The config contains personal identifiable information (user ID, real name, email). If this repository is public or shared, consider:

  1. Moving PII to environment variables or a gitignored local config
  2. Using placeholder values in the committed file
🤖 Prompt for AI Agents
In claude/skills/linear-insights/config.yaml around lines 18 to 22, remove the
hard-coded PII (user id, real name, email, displayName) and replace them with
non-sensitive placeholder keys or references to environment variables/local
gitignored config (e.g., USER_ID, USER_NAME, USER_EMAIL, DISPLAY_NAME); update
the file to read from those placeholders and add a note in the repository README
or a sample config.example.yaml showing the placeholder names and how to supply
real values via env or a .env/.local config that is .gitignored.

Comment on lines +273 to +277
DAY_NAME=$(date -j -f "%Y-%m-%d" "$TARGET_DATE" "+%A" 2>/dev/null || date -d "$TARGET_DATE" "+%A")
MONTH_NAME=$(date -j -f "%Y-%m-%d" "$TARGET_DATE" "+%B" 2>/dev/null || date -d "$TARGET_DATE" "+%B")
DAY_NUM=$(date -j -f "%Y-%m-%d" "$TARGET_DATE" "+%-d" 2>/dev/null || date -d "$TARGET_DATE" "+%-d")
YEAR=$(date -j -f "%Y-%m-%d" "$TARGET_DATE" "+%Y" 2>/dev/null || date -d "$TARGET_DATE" "+%Y")
WEEK_START=$(date -j -v-$(($(date -j -f "%Y-%m-%d" "$TARGET_DATE" "+%u" 2>/dev/null || echo 1)-1))d -f "%Y-%m-%d" "$TARGET_DATE" "+%B %-d" 2>/dev/null || echo "Week")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Date commands use macOS-specific -j flag without robust fallback.

The date -j -f syntax is macOS-specific. The fallback (|| date -d) is good, but line 277 has a complex expression that may fail on non-macOS systems due to the nested command substitution with -v.

🔎 Suggested fix

Consider using a portable approach or adding explicit OS detection:

if [[ "$OSTYPE" == "darwin"* ]]; then
    DAY_NAME=$(date -j -f "%Y-%m-%d" "$TARGET_DATE" "+%A")
    # ... other macOS-specific date commands
else
    DAY_NAME=$(date -d "$TARGET_DATE" "+%A")
    # ... Linux equivalents
fi
🤖 Prompt for AI Agents
In claude/skills/linear-insights/deep-dive around lines 273 to 277 the script
uses macOS-only date flags (-j, -f, -v) with brittle inline fallbacks which can
fail (especially the WEEK_START expression); replace the inline || fallbacks
with an explicit OS detection (e.g. check OSTYPE) and run one of two clearly
separated code paths: a macOS branch using date -j -f and -v forms, and a
Linux/GNU branch using date -d and GNU-compatible arithmetic, ensuring
WEEK_START is computed in the Linux branch by calculating the weekday (with date
-d) and subtracting days with GNU date arithmetic; alternatively document and
require GNU coreutils (gdate) on macOS and use it in the Linux path; also
validate TARGET_DATE and provide a sensible default or error message if parsing
fails.

printf ' ],\n'
printf ' "gh_commands": [%s\n ],\n' "$gh_commands_json"
printf ' "git_commands": [\n'
printf ' "git log --oneline --since=\\"%s\\\" --until=\\\"%s 23:59:59\\\" --author=\\\"Jonah\\\""\n' "$TARGET_DATE" "$TARGET_DATE"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unbalanced escape sequences in git_commands JSON.

Line 387 has inconsistent escaping: --since=\\" vs --until=\\\". This may produce malformed JSON.

-    printf '    "git log --oneline --since=\\"%s\\\" --until=\\\"%s 23:59:59\\\" --author=\\\"Jonah\\\""\n' "$TARGET_DATE" "$TARGET_DATE"
+    printf '    "git log --oneline --since=\\"%s\\" --until=\\"%s 23:59:59\\" --author=\\"Jonah\\""\n' "$TARGET_DATE" "$TARGET_DATE"
📝 Committable suggestion

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

Suggested change
printf ' "git log --oneline --since=\\"%s\\\" --until=\\\"%s 23:59:59\\\" --author=\\\"Jonah\\\""\n' "$TARGET_DATE" "$TARGET_DATE"
printf ' "git log --oneline --since=\\"%s\\" --until=\\"%s 23:59:59\\" --author=\\"Jonah\\""\n' "$TARGET_DATE" "$TARGET_DATE"
🤖 Prompt for AI Agents
In claude/skills/linear-insights/deep-dive around line 387, the printf string
uses inconsistent/backslash-escaped quotes for the --since/--until values which
can produce malformed JSON; update the printf format so both --since and --until
wrap their date placeholders with the same escaped double-quote sequence (i.e.
ensure each opening and closing quote is escaped the same way for JSON output),
and validate the resulting string is valid JSON (adjust escaping of
backslashes/quotes until the JSON parser accepts it).

Comment on lines +448 to +451
if [[ "$FIRST_REMAINING" != "null" && "$LAST_REMAINING" != "null" ]]; then
DIFF=$((FIRST_REMAINING - LAST_REMAINING))
echo " Progress: $DIFF issues completed"
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Bash arithmetic fails with floating-point values.

DIFF=$((FIRST_REMAINING - LAST_REMAINING)) will fail if FIRST_REMAINING or LAST_REMAINING are floating-point numbers (e.g., from jq). This would cause a syntax error.

🔎 Suggested fix using bc or awk
     if [[ "$FIRST_REMAINING" != "null" && "$LAST_REMAINING" != "null" ]]; then
-        DIFF=$((FIRST_REMAINING - LAST_REMAINING))
+        DIFF=$(echo "$FIRST_REMAINING - $LAST_REMAINING" | bc)
         echo "  Progress:       $DIFF issues completed"
     fi
📝 Committable suggestion

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

Suggested change
if [[ "$FIRST_REMAINING" != "null" && "$LAST_REMAINING" != "null" ]]; then
DIFF=$((FIRST_REMAINING - LAST_REMAINING))
echo " Progress: $DIFF issues completed"
fi
if [[ "$FIRST_REMAINING" != "null" && "$LAST_REMAINING" != "null" ]]; then
DIFF=$(echo "$FIRST_REMAINING - $LAST_REMAINING" | bc)
echo " Progress: $DIFF issues completed"
fi
🤖 Prompt for AI Agents
In claude/skills/linear-insights/estimation-accuracy around lines 448 to 451,
the arithmetic DIFF=$((FIRST_REMAINING - LAST_REMAINING)) will fail for
floating-point values; replace the integer-only shell arithmetic with a
floating-point safe calculation (e.g., use bc or awk to compute the subtraction
and capture the result into DIFF), ensure variables are quoted/validated before
passing to the calculator to avoid injection or empty values, and then echo the
resulting DIFF as before.

Comment on lines +292 to +306
generate_blocked_labels_json() {
local first=true
echo -n "["
echo "$BLOCKED_LABELS" | while read -r label; do
if [[ -n "$label" ]]; then
if [[ "$first" == "true" ]]; then
echo -n "\"$label\""
first=false
else
echo -n ", \"$label\""
fi
fi
done
echo -n "]"
}

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

Variable scope bug in subshell causes first to always be true.

The while read loop runs in a subshell (due to the pipe), so the first=false assignment doesn't persist. This causes all items to be printed without commas, resulting in invalid JSON like ["label1""label2"].

🔎 Suggested fix using process substitution
 generate_blocked_labels_json() {
     local first=true
     echo -n "["
-    echo "$BLOCKED_LABELS" | while read -r label; do
+    while read -r label; do
         if [[ -n "$label" ]]; then
             if [[ "$first" == "true" ]]; then
                 echo -n "\"$label\""
                 first=false
             else
                 echo -n ", \"$label\""
             fi
         fi
-    done
+    done <<< "$BLOCKED_LABELS"
     echo -n "]"
 }
🤖 Prompt for AI Agents
In claude/skills/linear-insights/project-status around lines 292 to 306, the
loop that builds the JSON uses a pipe which runs the while read in a subshell so
the assignment first=false never persists and commas are never emitted; change
the loop to avoid the subshell by using process substitution or redirecting
input into the while (for example, replace the pipe with done < <(printf '%s\n'
"$BLOCKED_LABELS") or similar), so the first variable is updated in the current
shell and the output emits commas correctly to produce valid JSON.

Comment on lines +319 to +326
python3 << PYTHON_EOF
import json
import sys
from datetime import datetime, timezone

# Add lib directory to path
sys.path.insert(0, "$SCRIPT_DIR")
from lib.velocity_calculator import (

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Python import from lib.velocity_calculator may fail silently.

The embedded Python code imports from lib.velocity_calculator but doesn't handle the case where the import fails. If the module doesn't exist, Python will raise an ImportError and the script will fail with an unclear error message.

🔎 Suggested fix with try/except
try:
    from lib.velocity_calculator import (
        ConfidenceLevel,
        calculate_churn_ratio,
        calculate_adjusted_eta
    )
except ImportError as e:
    import json
    print(json.dumps({"error": f"Failed to import velocity_calculator: {e}"}))
    sys.exit(1)
🤖 Prompt for AI Agents
In claude/skills/linear-insights/project-status around lines 319 to 326, the
embedded Python imports from lib.velocity_calculator without handling
ImportError which can cause an unclear crash; wrap the from
lib.velocity_calculator import ... in a try/except ImportError block, on
exception output a JSON-formatted error message (including the exception text)
to stdout/stderr and call sys.exit(1) so the caller sees a clear error and the
process exits with non-zero status.

Comment on lines +364 to +367
try:
cache = CacheManager("$CACHE_DIR", schema_version=$CACHE_SCHEMA_VERSION, default_ttl=$CACHE_TTL)
value = json.loads('''$value''')
cache.set("$cache_key", value, ttl=$CACHE_TTL)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential JSON injection via shell variable in triple-quoted string.

If $value contains triple single-quotes ('''), the json.loads('''$value''') will break. Consider using a safer approach like base64 encoding or passing via stdin.

🔎 Proposed fix using stdin
 set_cache() {
     local cache_key="$1"
     local value="$2"

-    python3 << PYTHON_EOF
+    python3 << PYTHON_EOF "$value"
 import sys
 sys.path.insert(0, "$LIB_DIR")
 from cache_manager import CacheManager
 import json

 try:
     cache = CacheManager("$CACHE_DIR", schema_version=$CACHE_SCHEMA_VERSION, default_ttl=$CACHE_TTL)
-    value = json.loads('''$value''')
+    value = json.loads(sys.argv[1])
     cache.set("$cache_key", value, ttl=$CACHE_TTL)
 except Exception as e:
     # Cache write failure is non-fatal
     pass
 PYTHON_EOF
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In claude/skills/linear-insights/suggest-work around lines 364 to 367, the code
embeds the shell variable $value directly inside a triple-quoted Python string
for json.loads which breaks or allows injection if $value contains '''; instead,
stop interpolating raw JSON into the Python snippet and pass it safely — either
base64-encode $value in the shell and decode it in Python before calling
json.loads, or stream the raw value into the Python process via stdin and call
json.loads(sys.stdin.read()); update the invocation and the Python snippet to
use the chosen safe transport (base64 decode+json.loads or stdin
read+json.loads) and ensure TTL/schema variables remain passed as explicit
parameters rather than interpolating unsafe content.

Comment on lines +486 to +493
"filters": {
"blocked_labels": [
$(echo "$BLOCKED_LABELS" | while read -r label; do
if [[ -n "$label" ]]; then
echo " \"$label\","
fi
done)
],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Trailing comma in JSON array generation.

The while loop generates JSON objects with trailing commas, which produces invalid JSON (e.g., ["item1", "item2",]). Python's json.dumps handles this gracefully in output, but the embedded array construction may fail.

🔎 Proposed fix - filter trailing comma in Python

The Python code at line 516 uses json.dumps(result, indent=2, default=str) which will serialize properly. However, if the embedded bash-generated JSON fragments have trailing commas, Python's parser may fail. Verify that the output doesn't cause JSON parse errors.

#!/bin/bash
# Verify JSON output is valid
./suggest-work --json | python3 -m json.tool > /dev/null && echo "Valid JSON"
🤖 Prompt for AI Agents
In claude/skills/linear-insights/suggest-work around lines 486 to 493, the bash
while loop that emits JSON array entries adds a trailing comma, producing
invalid JSON; change the generation so no trailing comma is emitted (e.g.,
collect labels and join with commas, or print the comma only between items by
checking position), or better yet move array construction into Python (pass raw
labels and let json.dumps build the array) so the output is always valid JSON.


# Check age
local cache_age=$(($(date +%s) - $(stat -f %m "$cache_file" 2>/dev/null || stat -c %Y "$cache_file" 2>/dev/null)))
local cache_age=$(($(date +%s) - $(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null)))

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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "fetch-pr-data" -type f 2>/dev/null

Repository: OmniNode-ai/omniclaude

Length of output: 105


🏁 Script executed:

wc -l ./claude/skills/pr-review/fetch-pr-data

Repository: OmniNode-ai/omniclaude

Length of output: 109


🏁 Script executed:

sed -n '320,330p' ./claude/skills/pr-review/fetch-pr-data

Repository: OmniNode-ai/omniclaude

Length of output: 442


🏁 Script executed:

sed -n '410,420p' ./claude/skills/pr-review/fetch-pr-data

Repository: OmniNode-ai/omniclaude

Length of output: 519


🏁 Script executed:

sed -n '535,565p' ./claude/skills/pr-review/fetch-pr-data

Repository: OmniNode-ai/omniclaude

Length of output: 1105


🏁 Script executed:

# Test the stat command syntax to verify cross-platform compatibility
# Create a test file
test_file=$(mktemp)
echo "test" > "$test_file"
sleep 1

echo "Testing stat command variants:"
echo ""

# Test GNU stat syntax
if output=$(stat -c %Y "$test_file" 2>/dev/null); then
    echo "✓ GNU stat (-c %Y) works: $output"
else
    echo "✗ GNU stat (-c %Y) failed"
fi

# Test BSD stat syntax  
if output=$(stat -f %m "$test_file" 2>/dev/null); then
    echo "✓ BSD stat (-f %m) works: $output"
else
    echo "✗ BSD stat (-f %m) failed"
fi

echo ""
echo "Testing combined command (as used in line 325):"
if result=$($(date +%s) - $(stat -c %Y "$test_file" 2>/dev/null || stat -f %m "$test_file" 2>/dev/null)); then
    echo "Combined calculation would work"
else
    echo "Testing arithmetic expansion..."
    age=$(($(date +%s) - $(stat -c %Y "$test_file" 2>/dev/null || stat -f %m "$test_file" 2>/dev/null)))
    echo "✓ Arithmetic expansion works, calculated age: $age seconds"
fi

rm -f "$test_file"

Repository: OmniNode-ai/omniclaude

Length of output: 385


🏁 Script executed:

# Test the problematic syntax more carefully
echo "Testing what happens when both stat commands fail:"
echo ""

# Simulate what happens in the actual code
test_file=$(mktemp)
echo "test" > "$test_file"

echo "Direct test of the problematic command:"
echo 'local cache_age=$(($(date +%s) - $(stat -c %Y "$test_file" 2>/dev/null || stat -f %m "$test_file" 2>/dev/null)))'

# Try to evaluate it
bash -c 'local cache_age=$(($(date +%s) - $(stat -c %Y "'"$test_file"'" 2>/dev/null || stat -f %m "'"$test_file"'" 2>/dev/null)))
echo "cache_age=$cache_age"' 2>&1 || echo "Command failed with error above"

echo ""
echo "What the code should do instead - separate the timestamp extraction:"
bash -c 'timestamp=$(stat -c %Y "'"$test_file"'" 2>/dev/null || stat -f %m "'"$test_file"'" 2>/dev/null)
if [[ -z "$timestamp" ]]; then
    echo "ERROR: Could not get file modification time"
else
    cache_age=$(($(date +%s) - timestamp))
    echo "cache_age=$cache_age"
fi' 2>&1

rm -f "$test_file"

Repository: OmniNode-ai/omniclaude

Length of output: 477


🏁 Script executed:

# Check what stat variant is actually available on a typical Linux system
# by examining the script's documentation or usage patterns
echo "Checking if there are any guards or assumptions about stat in the script:"
grep -n "stat\|cache_age" ./claude/skills/pr-review/fetch-pr-data | head -20

Repository: OmniNode-ai/omniclaude

Length of output: 1199


🏁 Script executed:

# Test the actual scenario where both stat commands would fail
echo "Testing the critical issue: what happens when stat command substitution is empty"
echo ""

# Simulate the problem
echo "When stat command fails, the substitution is empty:"
result=$(($(date +%s) - $(echo "" 2>/dev/null))) 2>&1 || echo "ERROR: Arithmetic expansion failed (this is the bug)"

echo ""
echo "The actual code at line 325 will fail if both stat variants are unavailable:"
echo "local cache_age=\$(($(date +%s) - \$(stat -c %Y \"\$cache_file\" 2>/dev/null || stat -f %m \"\$cache_file\" 2>/dev/null)))"
echo ""
echo "If stat returns nothing (empty), we get: \$((1766591955 - )) which is a syntax error"
echo ""

# Show what proper error handling would look like
echo "Proper approach with error checking:"
cat > /tmp/proper_example.sh << 'EOF'
# Extract timestamp safely
timestamp=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null)
if [[ -z "$timestamp" ]]; then
    print_error "Cannot determine cache file modification time"
    return 1
fi

local cache_age=$(($(date +%s) - timestamp))
EOF
cat /tmp/proper_example.sh

Repository: OmniNode-ai/omniclaude

Length of output: 892


Add error handling for stat command failure at line 325.

The stat command syntax is correct for both platforms, but the code lacks error handling if both stat -c %Y and stat -f %m fail. When the stat substitution returns empty, the arithmetic expansion produces a bash syntax error ($((1766591968 - )) → "syntax error: operand expected"). Extract the timestamp into a variable first and check for empty result before using it in arithmetic:

timestamp=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null)
if [[ -z "$timestamp" ]]; then
    return 1
fi
local cache_age=$(($(date +%s) - timestamp))
🤖 Prompt for AI Agents
In claude/skills/pr-review/fetch-pr-data around line 325, the current inline
stat substitution can fail on both syntaxes and produce an empty result which
breaks the arithmetic expansion; extract the stat output into a timestamp
variable first, test that the timestamp is non-empty (and return/non-zero or
handle the error if it is empty), and only then compute cache_age using the
validated timestamp so you avoid a bash syntax error when stat fails.

@claude

claude Bot commented Dec 24, 2025

Copy link
Copy Markdown

PR Review: Migration to Python Collator and Linear Insights Skill

Summary

This is a massive PR (+7,164 / -815 lines) accomplishing two objectives:

  1. Fixes critical memory issues in collate-issues by migrating from jq to Python
  2. Adds Linear insights integration with 6,700+ lines of new skill infrastructure

Strengths

  • Excellent root cause analysis of jq memory issues
  • Type-safe Pydantic models with ONEX-compliant error handling
  • Comprehensive pattern matching for Claude Code and CodeRabbit
  • Strong security practices (no shell=True, proper timeouts, input validation)
  • Well-documented code with docstrings and type hints

Critical Issues

1. BLOCKING: Massive PR Size
This PR mixes two unrelated features making review extremely difficult. Should be split into:

  • PR 46a: collate-issues Python migration (critical bugfix)
  • PR 46b: Linear insights skill (new feature)

2. MAJOR: Missing Test Coverage
Only test_models.py exists for 7,000+ lines of code. Core parsing logic (extract_issues_from_body, classify_severity, is_noise) has no unit tests. No integration tests for Linear commands.

3. SECURITY: Weak URL Validation
collate-issues:153-161 regex could accept malicious URLs like https://evil.com/github.com/foo/pull/123. Use urllib.parse to validate hostname properly.

Medium Priority

  • Hardcoded config values should be extracted to constants
  • extract_issues_from_body (506 lines) needs refactoring using strategy pattern
  • Linear insights missing README and setup documentation

Overall Assessment

Code Quality: 4/5 | Architecture: 4/5 | Security: 4/5 | Testing: 2/5 | PR Hygiene: 2/5

Recommendation

Request Changes

Blockers:

  1. Split into separate PRs
  2. Fix URL validation security issue

After addressing blockers: Approve with test coverage as follow-up work.

Great work solving the jq memory problem! The Python implementation is excellent.

Convert OmniClaude to Claude Code's official plugin system while
preserving the structured YAML agent format required for the
polymorphic agent framework.

Plugin structure:
- omniclaude-core: Hooks, lib, portable ${CLAUDE_PLUGIN_ROOT} paths
- omniclaude-agents: 53 YAML agents (NOT converted to MD)
- omniclaude-skills: pr-review, ci-failures, linear, system-status
- omniclaude-commands: 9 slash commands
- marketplace.json: Self-hosted marketplace config

Key design decisions:
- Agents remain in YAML format for programmatic routing
- YAML enables: fuzzy matching, performance targets, quality gates,
  ONEX compliance validation, capability matching
- plugin.json v1.1.0 documents all 53 agents across 13 categories

Fixes command rename: pr-dev-review.md -> pr-review-dev.md
@claude

claude Bot commented Jan 3, 2026

Copy link
Copy Markdown

PR Review: Python Migration for collate-issues

Summary

This PR successfully resolves the memory exhaustion issue by migrating from jq-based text processing to Python. The implementation is well-structured, type-safe, and production-ready with excellent architecture decisions.

✅ Strengths

  1. Excellent Architecture - Type-safe Pydantic models, ONEX-compliant error handling, clean separation of concerns
  2. Memory & Performance - Solves the root cause: ~53MB Python vs OOM with jq, smart caching, parallel API fetching
  3. Code Quality - Extensive documentation with docstrings and examples, intelligent noise filtering, robust bot detection
  4. Backward Compatibility - Maintains CLI interface, preserves output format

🔴 Critical Issues

1. Missing Dependency (BLOCKING) - collate_issues.py:42-66
The script imports from models.py. Verify Pydantic is declared in pyproject.toml dependencies to prevent ModuleNotFoundError on fresh installations.

🟠 Major Issues

2. Error Code Consistency - collate_issues.py:1591-1717
Document the distinction between OnexError (exit 2) and ValueError (exit 1) handling for clarity.

3. Race Condition in Parallel Fetch - fetch-pr-data:548-559
Error detection relies on error_file after wait. Consider using process exit codes for more reliable error handling.

4. GraphQL Pagination Limit - fetch-pr-data:119
Nested comments limited to first 100 per thread. Add warning when count hits limit to prevent silent truncation.

🟡 Minor Issues

5. Security - collate-issues:232
Consider using -- separator: exec "$PYTHON_EXEC" "$PYTHON_SCRIPT" -- "$pr_input" to prevent argument injection

6. Hardcoded Patterns - collate_issues.py:235-325
Consider externalizing noise/actionable patterns to YAML for easier maintenance

7. Type Annotations - Mix of PEP 604 (|) and PEP 585 styles. Use consistently throughout.

🧪 Testing Recommendations

Add unit tests for:

  • extract_issues_from_body logic
  • Edge cases: empty PR, bot-only comments, cross-repo URLs
  • Cache invalidation

📊 Performance Analysis

Metric Before After Improvement
Memory OOM (>2GB) ~53MB 97% reduction
Runtime 28-37s crash <5s 6x faster
Code 740 lines 518 lines 30% simpler

🔒 Security

✅ Input validation, subprocess timeout, project-local cache, GraphQL injection protection
Consider: Rate limit handling, cache size limits

✅ Final Verdict

APPROVE with minor fixes recommended

Before Merge:

  1. Verify Pydantic in pyproject.toml (CRITICAL)
  2. Add basic unit tests
  3. Document migration path

💯 Score: 8.5/10

Architecture 9/10, Security 8/10, Performance 10/10, Testing 6/10, Documentation 9/10

Well done! Solid engineering solution. 🚀

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (24)
plugins/omniclaude-agents/agents/debug.yaml (1)

103-104: Hardcoded file path may limit portability.

The file_management.location path docs/dev_logs/jonah/debug/ contains a specific username. Consider parameterizing this or using a generic path pattern to support multiple engineers.

Suggested change
   file_management:
-    location: "docs/dev_logs/jonah/debug/"
+    location: "docs/dev_logs/{engineer}/debug/"
     naming_pattern: "debug_log_YYYY_MM_DD_HHMMSS.md"
plugins/omniclaude-agents/agents/omniagent-archon-tickets.yaml (1)

237-254: API configuration contains hardcoded values that should be configurable.

Both omniagent.base_url and archon.task_filters are hardcoded. The 30-second polling interval and 300-second timeout should likely be environment-specific.

Suggested improvement
 api_configuration:
   omniagent:
-    base_url: "http://localhost:8000"
+    base_url: "${OMNIAGENT_BASE_URL:-http://localhost:8000}"
     endpoints:
       generation: "/archon/generate-from-task"
       monitoring: "/archon/monitor/status"
-    polling_interval: 30
-    timeout_seconds: 300
+    polling_interval: "${ARCHON_POLLING_INTERVAL:-30}"
+    timeout_seconds: "${ARCHON_TIMEOUT:-300}"
plugins/omniclaude-agents/agents/omniagent-smart-responder.yaml (1)

99-108: Tier architecture with pricing may become outdated.

The hardcoded token prices for Gemini Flash ($0.000125/token) and Gemini Pro ($0.00125/token) will become stale as cloud providers update pricing. Consider externalizing these values or adding a note about periodic review.

plugins/omniclaude-agents/agents/onex-readme.yaml (2)

224-227: Validation status is "pending" - update after review.

The validation_status: "pending" should be updated to "validated" or appropriate status once this configuration has been reviewed and tested.

Suggested update
 created_from: "agent-onex-readme.md"
 conversion_date: "2025-01-16"
 schema_compliance: "full"
-validation_status: "pending"
+validation_status: "validated"

81-88: Domain queries present but missing match_count and confidence_threshold.

Per learnings, agent configurations should include match_count and confidence_threshold. Consider adding these under framework_integration or template_integration.

Suggested addition
   domain_queries:
     primary: "ONEX agent documentation overview clean architecture patterns"
     implementation: "documentation overview implementation"
+    match_count: 5
+    confidence_threshold: 0.6

   template_integration:
plugins/omniclaude-agents/agents/ast-generator.yaml (1)

145-148: Consider adding more Claude skills references.

The agent references only @senior-architect. Given the AST manipulation and code generation focus, consider adding references to skills like @async-python-patterns or @architecture-patterns that other agents in this PR reference, if applicable to this agent's domain.

plugins/omniclaude-agents/agents/devops-infrastructure.yaml (1)

10-16: Structural inconsistency: Uses identity instead of agent_identity.

This file uses identity: (line 11) while other agent files like ast-generator.yaml use agent_identity:. For consistency across the agent ecosystem, consider aligning the field naming convention.

🔎 Suggested alignment
-# Agent Identity
-identity:
+# Agent Identity
+agent_identity:
   name: "agent-devops-infrastructure"
plugins/omniclaude-agents/agents/intelligence-initializer.yaml (2)

1-5: Missing schema_version at root level and potential date typo.

Unlike other agent files, this file lacks a root-level schema_version field. Additionally, the conversion date "2025-09-29" (line 3) may be a typo - perhaps intended to be "2025-01-29" to match other files.

🔎 Suggested fix
 # Intelligence Initializer Agent Definition
 # Converted from: agent-intelligence-initializer.md
-# Conversion Date: 2025-09-29
-# Schema Version: 1.0.0
+# Conversion Date: 2025-01-29
+
+schema_version: "1.0.0"
 
 agent_identity:

6-26: Agent identity with unique role field.

The addition of a role field (line 8) provides additional context beyond name. Consider standardizing this pattern across other agent definitions for consistency, or documenting when role should be used vs. title.

plugins/omniclaude-agents/agents/performance.yaml (1)

1-14: Missing schema_version field at root level.

Unlike other agent files (ast-generator.yaml, devops-infrastructure.yaml, contract-validator.yaml), this file lacks a root-level schema_version field. Consider adding for consistency.

🔎 Suggested fix
 # Performance Optimization Specialist Agent Definition
 # Comprehensive performance analysis, bottleneck detection, and system efficiency optimization
 # Focus: Data-driven performance improvements with measurable impact
 
+schema_version: "1.0.0"
+
 agent_identity:
   name: "agent-performance"
plugins/omniclaude-agents/agents/address-pr-comments.yaml (2)

98-106: Pattern catalog comments are identical and potentially uninformative.

All CDP patterns (CDP-001 through CDP-004) have the same comment "Core Design Philosophy". Consider differentiating the comments to describe each pattern's specific focus, or remove the redundant comments entirely if they don't add clarity.

Suggested improvement
   applicable_patterns:
-      - "CDP-001" # Core Design Philosophy
-      - "CDP-002" # Core Design Philosophy
-      - "CDP-003" # Core Design Philosophy
-      - "CDP-004" # Core Design Philosophy
+      - "CDP-001" # Clean Design - Single Responsibility
+      - "CDP-002" # Clean Design - Separation of Concerns
+      - "CDP-003" # Clean Design - Dependency Injection
+      - "CDP-004" # Clean Design - Interface Segregation
       - "QAP-001" # Quality Assurance Pattern
       - "IGP-001" # Intelligence Gathering Pattern
       - "EHP-001" # Error Handling Pattern

92-92: Absolute configuration path may reduce portability.

The path /configs/address-pr-comments.yaml is absolute, which may cause issues if the configuration directory is located elsewhere in different environments.

plugins/omniclaude-agents/agents/onex-coordinator.yaml (1)

102-107: Inconsistent function naming with parentheses.

Mandatory functions include () suffix (e.g., gather_comprehensive_pre_execution_intelligence()), which is inconsistent with other agent definitions in this PR that omit them (e.g., address-pr-comments.yaml lines 83-87). Consider standardizing across all agent definitions.

plugins/omniclaude-agents/agents/overnight-automation.yaml (1)

1-10: Missing top-level schema_version field.

Unlike other agent definitions in this PR (e.g., address-pr-comments.yaml, onex-coordinator.yaml, debug-intelligence.yaml), this file lacks a top-level schema_version field. Consider adding it for consistency with the agent definition schema.

Suggested addition after line 3
 # Agent Definition: Overnight Automation Controller
 # Converted from agent-overnight-automation.md to YAML format for dynamic role system

+schema_version: "2.0.0"
+
 agent_identity:
   name: "overnight-automation"
plugins/omniclaude-agents/agents/contract-driven-generator.yaml (1)

1-9: Schema version inconsistency with other agent definitions.

This file uses schema_version: "2.0.0" while other agent definitions in this PR (content-summarizer, code-quality-analyzer, parameter-collector, etc.) use schema_version: "1.0.0". Consider aligning schema versions for consistency across the agent ecosystem, or document why this agent requires a different schema version.

Additionally, per learnings, agent YAML configurations should include fields like agent_domain, agent_purpose, match_count, and confidence_threshold. These appear to be missing or structured differently here.

plugins/omniclaude-agents/agents/content-summarizer.yaml (2)

138-144: Consider a less expensive default strategy.

The default strategy is 'intelligent' (LLM-powered, <5s latency per Line 183), which is the most resource-intensive option. For better performance defaults, consider using 'truncate_smart' (<100ms) or 'extract_key_lines' (<500ms) as the default, with 'intelligent' reserved for explicit requests.


210-228: Add test example for preserve_structure strategy.

The test_examples section covers three of the four strategies (truncate_smart, extract_key_lines, intelligent) but is missing an example for preserve_structure. Consider adding a test case for completeness:

  - description: "Test structure preservation"
    input: "Markdown document with headers and lists"
    strategy: "preserve_structure"
    max_length: 5000
    expected: "Summary preserving heading hierarchy and list structure"
plugins/omniclaude-agents/agents/code-quality-analyzer.yaml (1)

75-88: Orphaned section header comment.

Line 75-76 has a comment # ONEX Compliance Requirements that appears to be an orphaned section header—the actual ONEX integration content starts at Line 82 under onex_integration:. Consider either removing the orphaned comment or moving it to directly precede the onex_integration: block for clarity.

-# ONEX Compliance Requirements
-
 # Claude Skills Integration
 claude_skills_references:
   - "@systematic-debugging - Four-Phase Debugging Framework"
   - "@senior-architect - Software Architecture Design"

+# ONEX Compliance Requirements
 onex_integration:
plugins/omniclaude-agents/agents/commit.yaml (2)

272-285: Consider making quality annotations optional in commit messages.

The intelligent_message_generation.message_format includes embedded quality metrics directly in commit messages:

[Quality Score: {quality_score}/1.0]
[Anti-Patterns Fixed: {anti_patterns_fixed}]
[Performance Impact: {performance_impact}]

While useful for internal tracking, this could clutter git history and may not be desired for public repositories. Consider making quality_annotations configurable or moving these to commit metadata/trailers instead of the message body.


227-248: Query syntax implies specific backend dependency.

The metadata_filter uses MongoDB-style query operators (e.g., {"$gte": 0.7}). This creates tight coupling to a specific database backend. If the system might use different backends, consider abstracting the query language or documenting the backend requirement explicitly.

plugins/omniclaude-agents/agents/documentation-architect.yaml (1)

1-20: Hybrid schema structure differs from other agent definitions.

This file uses both top-level agent metadata (Lines 6-12: agent_type, agent_name, title, category, priority, color) AND a nested identity: block (Lines 15-19). Other files in this PR use either agent_identity: or identity: exclusively. Consider consolidating to a consistent structure for maintainability.

plugins/omniclaude-agents/agents/parameter-collector.yaml (1)

75-86: Orphaned section header comment (same pattern as code-quality-analyzer.yaml).

Lines 75-76 have # ONEX Compliance Requirements as an orphaned section header, with the actual onex_integration: block starting at Line 81. This appears to be a copy-paste artifact. Consider reorganizing as suggested for code-quality-analyzer.yaml.

plugins/omniclaude-agents/agents/agent-address-pr-comments.yaml (2)

1-8: Missing required agent configuration fields.

Based on learnings, agent YAML configurations must include: agent_domain, agent_purpose, agent_title, agent_context, domain_query, implementation_query, match_count, confidence_threshold, and capabilities.

This file is missing:

  • agent_purpose
  • domain_query
  • implementation_query
  • match_count
  • confidence_threshold

Additionally, the schema structure differs from frontend-developer.yaml (flat keys vs nested agent_identity block), which may cause routing/loading inconsistencies.


43-51: Consider extracting extensive documentation to a separate file.

The documentation block spans ~800 lines with detailed code examples. For maintainability, consider moving this to a dedicated markdown file (e.g., docs/agent-address-pr-comments.md) and referencing it here:

documentation_ref: "docs/agent-address-pr-comments.md"

Comment on lines +842 to +844
**Version**: 2.0.0
**Last Updated**: 2025-10-03
**Integration Pattern**: Pre + During + Post (response quality)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Stale "Last Updated" date.

The date 2025-10-03 predates this PR (opened 2025-12-04). Update to reflect the actual modification date.

🤖 Prompt for AI Agents
In plugins/omniclaude-agents/agents/agent-address-pr-comments.yaml around lines
842 to 844, the "Last Updated" date is stale (2025-10-03) and predates this PR;
update that value to the actual modification date (e.g., 2025-12-04 or today's
date) so it accurately reflects when the file was changed, ensuring the YAML
value remains in the same format and quoting style as surrounding entries.

Comment on lines +6 to +9
schema_version: "1.0.0"
total_agents: 52
registry_type: "dynamic_role_system"
last_updated: "2025-11-10"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Registry metadata may be inaccurate.

  • total_agents: 52 but the registry appears to define approximately 25 agents
  • last_updated: "2025-11-10" appears stale

Consider updating these values to reflect the actual registry contents, or implementing validation to ensure these metadata fields stay synchronized.

🤖 Prompt for AI Agents
In plugins/omniclaude-agents/agents/agent-registry.yaml around lines 6 to 9, the
registry metadata is inaccurate: update total_agents to the actual number of
agents in the file (count and set to ~25 or exact count), set last_updated to
the current ISO date string, and/or add a small validation/update step
(pre-commit hook or CI job) that counts agent entries and rewrites total_agents
and last_updated automatically so those fields stay synchronized with the
registry contents.

Comment on lines +19 to +54
# Agent Categories
categories:
development:
description: "Core development and coding agents"
count: 14
priority: "high"

architecture:
description: "System architecture and design agents"
count: 8
priority: "high"

quality:
description: "Quality assurance and testing agents"
count: 8
priority: "medium"

infrastructure:
description: "DevOps and infrastructure agents"
count: 6
priority: "medium"

coordination:
description: "Project and workflow coordination agents"
count: 7
priority: "high"

documentation:
description: "Documentation and knowledge agents"
count: 5
priority: "low"

content_processing:
description: "Content processing and summarization agents"
count: 1
priority: "medium"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Category counts are inconsistent.

The category counts sum to 49 (14+8+8+6+7+5+1) but total_agents is 52. Additionally, the actual agents defined in the registry should be verified against these category counts to ensure accuracy. Consider either:

  1. Regenerating counts from actual registry contents
  2. Adding validation that enforces count consistency
🤖 Prompt for AI Agents
In plugins/omniclaude-agents/agents/agent-registry.yaml around lines 19 to 54,
the per-category "count" values currently sum to 49 while the file's
total_agents is 52; reconcile these by regenerating the category counts from the
actual agent definitions and updating each category count and total_agents to
match the true registry, and/or add a simple validation check (script or CI
step) that parses the registry, tallies agents per category and asserts
sum(category.counts) === total_agents and that each agent is assigned to one of
the listed categories; update the YAML counts to the computed values or
implement the validation to fail the build until they match.

Comment on lines +5 to +10
agent_identity:
name: "frontend-developer"
title: "Frontend Developer Specialist"
description: "React/TypeScript UI component development specialist with visual validation, component scaffolding, and accessibility-first design for building modern web applications"
color: "cyan"
task_agent_type: "frontend_developer"

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

🧩 Analysis chain

🏁 Script executed:

cat plugins/omniclaude-agents/agents/frontend-developer.yaml

Repository: OmniNode-ai/omniclaude

Length of output: 19375


🏁 Script executed:

fd -e yaml plugins/omniclaude-agents/agents/ | head -10

Repository: OmniNode-ai/omniclaude

Length of output: 503


🏁 Script executed:

# Check if there are any schema documents or examples
find . -type f \( -name "*.md" -o -name "*.schema*" -o -name "*.json" \) | xargs grep -l "agent_domain\|agent_purpose" 2>/dev/null | head -5

Repository: OmniNode-ai/omniclaude

Length of output: 103


🏁 Script executed:

cat plugins/omniclaude-agents/agents/README.md

Repository: OmniNode-ai/omniclaude

Length of output: 140


🏁 Script executed:

fd . plugins/omniclaude-agents/agents/ --type f --name "*.yaml" | head -5

Repository: OmniNode-ai/omniclaude

Length of output: 316


🏁 Script executed:

# Look for agent definitions that might follow the flat schema from learnings
find . -path "*/agents/*.yaml" -o -path "*/agent-definitions/*.yaml" | xargs ls -la 2>/dev/null | head -10

Repository: OmniNode-ai/omniclaude

Length of output: 969


🏁 Script executed:

head -100 ./claude/agents/agent-address-pr-comments.yaml

Repository: OmniNode-ai/omniclaude

Length of output: 3729


🏁 Script executed:

# Check if frontend-developer.yaml is in the right location
find . -name "frontend-developer.yaml" -type f

Repository: OmniNode-ai/omniclaude

Length of output: 164


🏁 Script executed:

# Look for any schema or config files
fd schema . --type f | head -5
fd config . --type f | head -5

Repository: OmniNode-ai/omniclaude

Length of output: 546


🏁 Script executed:

head -80 ./claude/agents/frontend-developer.yaml

Repository: OmniNode-ai/omniclaude

Length of output: 3802


🏁 Script executed:

head -150 ./agents/lib/schema_agent_framework.py

Repository: OmniNode-ai/omniclaude

Length of output: 4014


🏁 Script executed:

# Search for agent schema validation or loader code
rg "agent_domain|agent_name|agent_identity" --type yaml agents/lib/ --max-count 5

Repository: OmniNode-ai/omniclaude

Length of output: 48


🏁 Script executed:

# Check for documentation about agent YAML formats
rg -A 5 -B 5 "agent.*schema\|agent.*format" --type md . | head -100

Repository: OmniNode-ai/omniclaude

Length of output: 48


🏁 Script executed:

# Search for references to agent_domain in code (loader/parser)
rg "agent_domain" -t py -t ts -t js | head -20

Repository: OmniNode-ai/omniclaude

Length of output: 1815


Refactor agent YAML schema to match required format.

The agent configuration uses a nested agent_identity structure, but the framework expects a flat root-level schema with agent_domain, agent_purpose, agent_title, and agent_context fields (see agent-address-pr-comments.yaml as reference). The current structure also lacks:

  • agent_domain (has task_agent_type instead)
  • agent_purpose
  • agent_context
  • match_count
  • confidence_threshold
  • Root-level domain_query and implementation_query (currently nested under framework_integration.domain_queries)

The agent loader expects these fields at the root level for proper parsing and initialization.

🤖 Prompt for AI Agents
In plugins/omniclaude-agents/agents/frontend-developer.yaml around lines 5–10,
the file uses a nested agent_identity object but the loader expects a flat
root-level schema; remove the agent_identity wrapper and promote its fields to
root keys, rename/move fields to match the required schema (set agent_title from
the current name/title, add agent_domain in place of task_agent_type, add
agent_purpose and agent_context with appropriate text, preserve color), add the
missing root-level match_count and confidence_threshold keys, and move
domain_query and implementation_query out of
framework_integration.domain_queries to root-level domain_query and
implementation_query so the agent loader can parse and initialize correctly.

Comment on lines +192 to +200
# API Integration Configuration
api_configuration:
service_endpoint: "http://localhost:8000/batch"
default_batch_size: 10
max_concurrent_requests: 50
default_timeout_per_request: 300
total_batch_timeout: 3600
fail_fast_enabled: false
cost_tracking_enabled: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Hardcoded localhost URL may break in production/container environments.

The api_configuration.service_endpoint is set to http://localhost:8000/batch. This will fail if the batch processor runs in a container or different network namespace. Consider making this configurable via environment variable or configuration overlay.

Suggested improvement
 api_configuration:
-  service_endpoint: "http://localhost:8000/batch"
+  service_endpoint: "${OMNIAGENT_BATCH_URL:-http://localhost:8000/batch}"
   default_batch_size: 10

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In plugins/omniclaude-agents/agents/omniagent-batch-processor.yaml around lines
192-200 the api_configuration.service_endpoint is hardcoded to
"http://localhost:8000/batch", which will break in containerized or
different-network environments; change this to read from
configuration/environment (e.g., reference an env var or config overlay such as
SERVICE_ENDPOINT) with a sensible default fallback and validation, update any
deployment manifests/Helm values to populate that variable, and add a brief
comment in the YAML or docs describing how to override the endpoint in
production.

- Remove old fragmented plugin directories:
  - plugins/omniclaude-agents/
  - plugins/omniclaude-commands/
  - plugins/omniclaude-core/
  - plugins/omniclaude-skills/
- Add consolidated plugins/onex/ with:
  - agents/configs/ - YAML agent definitions
  - commands/ - CLI commands
  - hooks/ - Claude Code hooks
  - skills/ - Skill implementations
- Update marketplace.json for new structure
- Add .fastembed_cache/ to gitignore
@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

See detailed review in next comment

@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

PR Review - PR #46: Python Migration for collate-issues

This PR successfully resolves the memory exhaustion issue in collate-issues by migrating from jq to Python. The implementation is well-architected with strong type safety via Pydantic models. However, there are several areas requiring attention before merge.


🔴 CRITICAL Issues

1. Massive Scope Creep - Plugin System Addition

Location: plugins/onex/ (77+ new files, 76k+ additions)

The PR description focuses on fixing the collate-issues memory issue, but 77% of the changes (59k+ lines) are an entirely new plugin system with 80+ agent configs, hooks, skills, and documentation. This violates single-responsibility principles for PRs.

Impact:

  • Makes review extremely difficult (100+ files)
  • Mixes unrelated changes (bugfix + new feature)
  • Increases merge conflict risk
  • Obscures the actual fix

Recommendation: Split into two PRs:

  1. PR 46A: collate-issues Python migration only
  2. PR 46B: ONEX plugin system

This allows focused review and testing of the critical bugfix without blocking on the plugin system review.

@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

2. Missing Test Coverage for Core Functionality

Location: claude/skills/pr-review/

No test files added for the new Python implementation. Critical paths need coverage:

  • extract_issues_from_body() - 500+ lines of regex patterns
  • classify_severity() - Critical for issue prioritization
  • is_noise() / is_actionable_issue() - Filtering logic
  • Claude bot detection and extraction
  • Resolution status mapping

Risk: Regex patterns are fragile and prone to regressions. Without tests, future changes could break issue extraction.

Recommendation: Add test_collate_issues.py with test cases. Use the test cases mentioned in PR description (PR 45: 4 issues, PR 5: 93 issues) as fixtures.

@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

3. Security: Subprocess Timeout Handling Incomplete

Location: collate_issues.py:1098-1131

The fetch_pr_data() function has timeout handling but does not properly clean up on timeout. Zombie processes may accumulate if fetch-pr-data hangs on GitHub API calls.

Current code:

result = subprocess.run(
    [str(fetch_script), str(pr_input)],
    timeout=120,
)
except subprocess.TimeoutExpired:
    raise OnexError(...)  # Process may still be running

Fix needed:

import signal, os

result = subprocess.run(
    [str(fetch_script), str(pr_input)],
    timeout=120,
    preexec_fn=os.setsid  # Create new process group
)
except subprocess.TimeoutExpired as e:
    os.killpg(os.getpgid(e.pid), signal.SIGTERM)
    raise OnexError(...)

@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

🟠 MAJOR Issues

4. Hardcoded Path Dependencies

Location: collate-issues:96-115

The bash wrapper has hardcoded /workspace/omniclaude path that will break if container changes. Use environment variable instead:

POETRY_ROOT=${OMNICLAUDE_ROOT:-/workspace/omniclaude}
if [[ -f "$POETRY_ROOT/pyproject.toml" ]]; then

5. Inconsistent Error Handling

Location: collate-issues vs collate_issues.py

Bash uses exit codes 0/1/2, but Python OnexError codes are not mapped to exit codes. The exec on line 232 loses exception context. Python script should return distinct exit codes matching bash expectations.

6. Parallel Fetch Error Handling Insufficient

Location: fetch-pr-data:416-547

Multiple parallel jobs write to same error_file, only last error is captured. Use numbered error files to capture all failures.

7. Cache Race Condition

Location: fetch-pr-data:387-388

Cache writes are not atomic. Use temp file + mv for atomic writes:

tmp_cache="$CACHE_DIR/.tmp_$$_$(date +%s).json"
echo "$output" > "$tmp_cache"
mv -f "$tmp_cache" "$cache_file"

@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

🟡 MINOR Issues

8. Regex Patterns Performance

Severity patterns recompile on each call. Pre-compile for better performance:

CRITICAL_PATTERNS_COMPILED = [re.compile(p, re.IGNORECASE) for p in CRITICAL_PATTERNS]

9. Type Annotation Inconsistency

Mixed use of modern dict | None and unused TypedDict import. Stick to PEP 604 syntax throughout.

10. Missing Documentation

CodeRabbit extraction logic (180 lines) lacks inline comments explaining format structure. Add comments for maintainability.

11. Documentation Duplication

deep-dive.md exists in both claude/commands/ and plugins/onex/commands/ with slight differences. Use symlinks or single source of truth.

⚪ NITPICK Issues

12. Unnecessary command substitution at line 228

13. String formatting inconsistency (mix of f-strings and old format)

14. Unused TypedDict import

@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

📊 Statistics and Metrics

Metric Count
Files changed 100
Additions +77,469
Deletions -820
Net change +76,649
Plugin system ~59,000 lines (77%)
Actual bugfix ~18,000 lines (23%)

✅ Positive Aspects

  1. Excellent Type Safety: Pydantic models provide runtime validation
  2. Well-Structured Code: Clear separation of concerns
  3. Comprehensive Pattern Matching: Handles Claude, CodeRabbit formats
  4. Good Error Context: OnexError provides structured errors
  5. Cross-Repo Support: URL parsing enables fetching from other repos
  6. Performance Improvement: Python ~53MB vs jq OOM
  7. Cache Implementation: 5-minute TTL with project-local storage
  8. Resolution Tracking: GraphQL integration for thread status

🎯 Recommendations

Before Merge:

  1. Split PR into bugfix and plugin system
  2. Add test coverage for core extraction logic
  3. Fix subprocess cleanup on timeout
  4. Document complex regex extraction logic

Post-Merge:

  1. Add integration tests using real PR data
  2. Set up pre-commit hooks for Pydantic validation
  3. Monitor memory usage in production
  4. Compile regex patterns for performance

@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

🏁 Verdict

Status: ❌ Request Changes

Primary Concern: PR scope is too broad (77k additions mixing bugfix + new plugin system). The 100+ files make thorough review extremely difficult. Splitting is essential for effective review and safe deployment.

Secondary Concerns:

  • Missing test coverage for 500+ lines of regex patterns
  • Subprocess cleanup security issue
  • Several race conditions and error handling gaps

Bottom Line: The core collate-issues fix is solid and well-implemented with excellent type safety via Pydantic. Once separated from the plugin system changes and tests are added, this will be ready to merge. The Python migration successfully resolves the jq memory issue.


Estimated Review Effort: 8-10 hours for full PR as-is
Suggested Approach: Split into 2-hour bugfix review + 6-8 hour plugin review

Please let me know if you would like me to help with the split or test implementation!

1. Black formatting:
   - Added .venv and _archive to black exclude in pyproject.toml
   - Formatted 3 files that needed it

2. Integration test markers:
   - Added @pytest.mark.integration to tests requiring Kafka/Postgres:
     - test_logging_event_publisher_singleton.py
     - test_database_event_client.py
     - test_env_loading.py
     - test_auto_env_loading.py
   - CI runs with -m "not integration" so these will be skipped
@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

Pull Request Review: PR #46

Excellent work solving the memory exhaustion issue! This is well-executed, but needs some critical fixes before merge.

Critical Issues

1. Missing Test Coverage (BLOCKS MERGE)

  • No automated tests for 1,863 lines of complex text parsing
  • Pattern regression risk when adding new bot formats
  • Need 80%+ coverage of collate_issues.py

2. Black Formatting (BLOCKS MERGE)

  • Commit mentions 3 formatted files but they're not in diff
  • Run black --check . to verify CI will pass

3. Poetry Security (BLOCKS MERGE)

  • Searches upward for pyproject.toml without validation
  • Could execute code from malicious parent directory
  • Add project name validation before using discovered pyproject.toml

Major Issues

4. Hardcoded Docker Path

  • /workspace/omniclaude is Docker-specific
  • Make configurable via OMNICLAUDE_DOCKER_PATH env var

5. OnexError Context

  • Inconsistent context population
  • Always include relevant state for debugging

Minor Issues

  1. Standardize regex raw strings
  2. Extract magic numbers (10, 50) as named constants
  3. Extract safe_comment_id() helper (duplicated code)
  4. Linear insights unrelated to PR title - split to separate PR
  5. Plugin consolidation (19K lines) not in PR description

Strengths

  • Root cause analysis excellent (jq misuse → Python)
  • 99%+ memory reduction (OOM → 53MB)
  • Strong type safety with Pydantic
  • Comprehensive bot format support
  • Clean bash → Python delegation

Security: No vulnerabilities in core logic ✅

Verdict: APPROVE WITH CONDITIONS

Cannot merge until Critical Issues 1-3 addressed (est. 4-6 hours).

Once fixed, this will be an exemplary PR. Great work!


Review by: Claude Sonnet 4.5
Date: 2026-01-19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 16

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

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

⚠️ Outside diff range comments (3)
claude/skills/pr-review/collate_issues.py (3)

1211-1221: Replace dict[str, Any] payloads with typed structures.
fetch_pr_data (and downstream maps) rely on Any, which violates the no‑Any rule and weakens type safety. Please define TypedDict (or Pydantic) models for the PR payload and update signatures to remove Any.

As per coding guidelines, avoid Any/Dict[str, Any] and enforce strongest typing possible.

🧭 Example direction (TypedDicts)
+class PRCommentPayload(TypedDict, total=False):
+    body: str
+    author: str
+    id: int | str
+    path: str
+    line: int | str
+
+class ResolvedThread(TypedDict, total=False):
+    is_resolved: bool
+    is_outdated: bool
+    resolved_by: str | None
+    path: str | None
+    line: int | None
+    comment_ids: list[int | str]
+
+class PRData(TypedDict):
+    pr_number: int
+    repository: str
+    resolved_threads: list[ResolvedThread]
+    reviews: list[PRCommentPayload]
+    inline_comments: list[PRCommentPayload]
+    pr_comments: list[PRCommentPayload]
+    issue_comments: list[PRCommentPayload]
+
-def fetch_pr_data(pr_input: str | int) -> dict[str, Any]:
+def fetch_pr_data(pr_input: str | int) -> PRData:

1227-1261: Standardize error handling on OnexError + error enum.
This file still uses string error codes and catches ValueError in main; fetch_pr_data also doesn’t wrap OSError/FileNotFoundError. Please use the project error enum for codes, wrap unexpected exceptions in OnexError with chaining, and remove the generic ValueError path.

As per coding guidelines, error handling must use OnexError with enum error codes and avoid generic ValueError.

🛠️ Suggested direction
-    except json.JSONDecodeError as e:
-        raise OnexError(
-            f"Failed to parse fetch-pr-data output: {e}",
-            code="PARSE_ERROR",
-            context={"pr_input": str(pr_input)},
-        )
+    except json.JSONDecodeError as e:
+        raise OnexError(
+            f"Failed to parse fetch-pr-data output: {e}",
+            code=ErrorCode.PARSE_ERROR,  # use your error enum
+            context={"pr_input": str(pr_input)},
+        ) from e
+    except OSError as e:
+        raise OnexError(
+            "fetch-pr-data failed to execute",
+            code=ErrorCode.FETCH_FAILED,
+            context={"pr_input": str(pr_input)},
+        ) from e

Also applies to: 1853-1858


1393-1419: Propagate CodeRabbit-extracted locations into PRIssue.
ExtractedIssue.location (e.g., [file.py:305-312]) is currently ignored for AI reviewer comments; PRIssue always uses the comment’s path/line, which is often empty for top‑level bot comments. This drops the per‑file line range you already parsed. Please parse item["location"] and use it as a fallback when path/line are missing.

🧩 Suggested fix (fallback parse)
-                    issue = PRIssue(
-                        file_path=path,
-                        line_number=(
-                            int(line)
-                            if isinstance(line, (int, str)) and str(line).isdigit()
-                            else None
-                        ),
+                    file_path = path
+                    line_number = (
+                        int(line)
+                        if isinstance(line, (int, str)) and str(line).isdigit()
+                        else None
+                    )
+                    if item.get("location") and not file_path:
+                        loc = item["location"].strip("[]")
+                        if ":" in loc:
+                            file_path, line_part = loc.split(":", 1)
+                            first = line_part.split("-", 1)[0]
+                            if first.isdigit():
+                                line_number = int(first)
+                        else:
+                            file_path = loc
+                    issue = PRIssue(
+                        file_path=file_path,
+                        line_number=line_number,
🤖 Fix all issues with AI agents
In `@claude/skills/pr-review/collate_issues.py`:
- Around line 1670-1684: Update the docstring for format_issues_parallel_solve
and any other new/modified functions in this file to include explicit Raises and
Example sections in addition to the existing description, Args, and Returns;
list any exceptions the function can raise (e.g., ValueError, TypeError, or
custom exceptions raised by called helpers) in a Raises section, and add a short
Example showing sample input and expected usage/output for /parallel-solve;
ensure the docstring format matches the project's docstring style used elsewhere
in the file so the linter accepts it (refer to functions like
CollatedIssues-related helpers for exact phrasing and exception types).
- Around line 1508-1514: The code currently defaults pr_number to 0 which
violates CollatedIssues.pr_number (must be >=1); update the creation site that
reads pr_data to validate the PR number: read actual_pr_number from pr_data (as
now), verify it's an int >= 1, and if not raise an OnexError with a clear
message before constructing CollatedIssues; keep using actual_repository =
pr_data.get("repository", get_repo_name()) and only create
CollatedIssues(pr_number=actual_pr_number, ...) after the validation passes.

In `@plugins/onex/agents/configs/address-pr-comments.yaml`:
- Around line 5-96: Add the required top-level metadata keys to the YAML: insert
agent_domain, agent_purpose, agent_title, agent_context, domain_query,
implementation_query, match_count, and confidence_threshold. Use values from
existing sections where sensible (e.g., set agent_title from
agent_identity.name, agent_purpose from agent_identity.description or
responsibility, agent_context from agent_philosophy/core_principles or
specialization), set domain_query/implementation_query to reuse the
template_system or mandatory_functions intent, and set
match_count/confidence_threshold to the existing parameters.result_count and
parameters.confidence_threshold (or 5 and 0.6 if not present). Ensure these keys
live alongside schema_version and agent_type at the top level.

In `@plugins/onex/agents/configs/agent-observability.yaml`:
- Around line 5-16: The YAML config for the "agent-observability" agent
(agent_identity block and top-level schema_version/agent_type/definition_format)
is missing required top-level metadata fields governed by the agents/**/*.yaml
contract; update this file to add the missing keys: agent_domain, agent_purpose,
agent_title, agent_context, domain_query, implementation_query, match_count, and
confidence_threshold alongside the existing
schema_version/agent_type/definition_format and agent_identity entries so
discovery/routing can validate and use this agent; ensure values are appropriate
for an observability specialist (use agent_identity.name/title/description to
populate agent_title/agent_purpose/context) and keep keys and types consistent
with other YAML agent configs.

In `@plugins/onex/agents/configs/api-architect.yaml`:
- Around line 5-16: The agent config missing required top-level schema fields
causes validation failures; update the YAML (near schema_version and agent_type
and the agent_identity block with name/title/description/task_agent_type) to add
the required keys: agent_domain, agent_purpose, agent_title, agent_context,
domain_query, implementation_query, match_count, and confidence_threshold,
populating them with appropriate values (strings for
domain/purpose/title/context/queries and numeric thresholds for
match_count/confidence_threshold) so the api_architect agent conforms to the
expected schema.

In `@plugins/onex/agents/configs/code-quality-analyzer.yaml`:
- Around line 5-67: Add the missing required top-level agent metadata fields to
the YAML (agent_domain, agent_purpose, agent_title, agent_context, domain_query,
implementation_query, match_count, confidence_threshold) so the config passes
validation; populate agent_domain from agent_identity.name or agent_type,
agent_title from agent_identity.title, agent_purpose from
agent_philosophy.core_responsibility, agent_context from agent_philosophy and
design_philosophy summary, set domain_query to the string under
framework_integration.domain_queries.domain, set implementation_query to
framework_integration.domain_queries.implementation, and add sensible defaults
for match_count and confidence_threshold (e.g., integers/percent) to align with
schema requirements while leaving existing keys like agent_identity,
capabilities, and framework_integration unchanged.

In `@plugins/onex/agents/configs/content-summarizer.yaml`:
- Around line 5-66: Add the missing canonical top-level metadata fields expected
by the registry by creating aliases/mappings from the existing blocks:
copy/select values from agent_identity into agent_title and agent_domain (e.g.,
name/title/description -> agent_title/agent_domain), map
agent_philosophy.core_responsibility to agent_purpose and agent_context, and
derive domain_query and implementation_query from domain_queries. Also add
numeric/validation defaults for match_count and confidence_threshold (e.g.,
sensible defaults like 1 and 0.7) so the loader sees them; update the YAML
top-level to include agent_domain, agent_purpose, agent_title, agent_context,
domain_query, implementation_query, match_count, and confidence_threshold while
preserving the original agent_identity, agent_philosophy, and domain_queries
nodes.

In `@plugins/onex/agents/configs/contract-driven-generator.yaml`:
- Around line 5-33: Add the missing canonical registry fields at the top level
of the YAML: agent_domain, agent_purpose, agent_title, agent_context,
domain_query, implementation_query, match_count, and confidence_threshold.
Populate agent_domain from agent_identity.domain, agent_title from
agent_identity.name, agent_purpose with a short string derived from
agent_identity.primary_purpose (or a concatenation of primary_purpose and key
secondary_purposes), and agent_context from agent_identity.role or
specialization; provide sensible default domain_query and implementation_query
strings describing the domain ("contract_driven_development") and implementation
intent (e.g., "generate_pydantic_models,ondex_pipeline"); set match_count to a
default integer (e.g., 3) and confidence_threshold to a default float (e.g.,
0.7); ensure keys are top-level aliases so registry ingestion will find them
without changing existing agent_identity fields.

In `@plugins/onex/agents/configs/contract-validator.yaml`:
- Around line 4-40: Add the required top-level agent metadata keys missing from
the YAML: agent_domain, agent_purpose, agent_title, agent_context, domain_query,
implementation_query, match_count, and confidence_threshold; populate
agent_domain using agent_identity.domain, agent_title using
agent_identity.title, agent_purpose using agent_identity.core_purpose (or a
concise version), agent_context using
agent_identity.responsibility_scope.context_focus, and set
domain_query/implementation_query to appropriate existing query strings (or
sensible defaults reusing identity values), then add numeric match_count and
confidence_threshold fields with reasonable defaults; ensure these new keys are
placed at top level alongside the existing agent_identity and agent_philosophy
entries so the config satisfies the required agent schema.

In `@plugins/onex/agents/configs/debug-database.yaml`:
- Around line 5-16: Add the missing required top-level YAML keys to the agent
config: insert agent_domain, agent_purpose, agent_title, agent_context,
domain_query, implementation_query, match_count, and confidence_threshold at the
same top level as schema_version/agent_type; populate agent_title and
agent_purpose/agent_context/agent_domain with descriptive strings, provide
domain_query and implementation_query as query strings, set match_count as an
integer and confidence_threshold as a numeric (float) value, and keep
agent_identity unchanged so the file validates against the agent schema.

In `@plugins/onex/agents/configs/debug-log-writer.yaml`:
- Around line 5-13: The YAML is missing required top-level schema fields which
breaks validation; update this file to add the mandatory top-level metadata
alongside agent_identity (e.g., add schema_version, id (unique agent id),
created_at (timestamp), owner (team or user), visibility (public/private) and
tags or categories as required by our agent schema) and ensure the existing
agent_identity block (name, version, domain, description, specialization,
approach, color, task_agent_type) remains unchanged; validate the file against
the agent schema after adding those fields to confirm indexing/validation
passes.

In `@plugins/onex/agents/configs/documentation-architect.yaml`:
- Around line 6-33: The YAML is missing canonical top-level agent metadata keys
required by the registry validators; copy the existing values from identity and
activation into top-level canonical fields such as agent_name, agent_type,
title, category, priority, color and add the expected agent_* aliases (e.g.,
agent_description, agent_specialization_level, agent_domain_context,
agent_task_agent_type) plus any query/count keys the registry expects, ensuring
values are sourced from identity and activation.triggers so validators pick them
up; update the document where identity and activation are defined to add these
top-level keys and their aliases for compatibility with registry ingestion.

In `@plugins/onex/agents/configs/intelligence-initializer.yaml`:
- Around line 6-13: The YAML is missing required top-level schema fields which
will cause validation to fail; update the file by adding the required keys
(agent_domain, agent_purpose, agent_title, agent_context, domain_query,
implementation_query, match_count, confidence_threshold) alongside the existing
agent_identity block and populate them with appropriate values consistent with
agent_identity (e.g., set agent_title to a short human title, agent_purpose to a
concise purpose string, agent_domain and agent_context to the relevant
domain/context, provide domain_query and implementation_query strings, and set
numeric match_count and confidence_threshold), ensuring the keys are top-level
(not nested under agent_identity) and semantically align with
name="agent-intelligence-initializer" and role="Intelligence System
Initialization Specialist".

In `@plugins/onex/agents/configs/omniagent-archon-tickets.yaml`:
- Around line 5-20: The YAML is missing required top-level canonical registry
fields (agent_domain, agent_purpose, agent_title, agent_context, domain_query,
implementation_query, match_count, confidence_threshold) which currently live
only under agent_definition and identity; add these keys at the top level and
populate them from agent_definition.name/title/description and
identity.domain/purpose/scope as appropriate so registry routing/validation
succeeds. Ensure you add agent_context (use identity.scope or a brief context
string), domain_query and implementation_query (provide the query strings or
aliases used by this agent), and numeric match_count and confidence_threshold
defaults (e.g., 1 and 0.75) to match registry expectations, keeping
agent_definition and identity intact for backward compatibility.

In `@plugins/onex/agents/configs/overnight-automation.yaml`:
- Around line 4-11: The YAML is missing required top-level schema fields and
will fail validation; update the agent_identity block (or top-level config) to
include agent_domain, agent_purpose, agent_title, agent_context, domain_query,
implementation_query, match_count, and confidence_threshold with appropriate
values for this agent (e.g., agent_domain: "automation", agent_purpose:
"orchestrate overnight Claude Code agents", agent_title: a short human title,
agent_context: brief operational context, domain_query and implementation_query
as the query strings used by your matcher, match_count as an integer, and
confidence_threshold as a float/percentage). Ensure the keys are present
alongside existing keys like name/display_name/version/agent_type so the
validator accepts the file.

In `@plugins/onex/ENVIRONMENT_VARIABLES.md`:
- Around line 98-162: Update ENVIRONMENT_VARIABLES.md to remove user-specific
paths and IPs by replacing instances like /Users/jonah/... and 192.168.86.200
with placeholders; use ${HOME} for local paths (e.g., PROJECT_ROOT,
OMNICLAUDE_PATH, LINEAR_INSIGHTS_OUTPUT_DIR) and use localhost or example
hostnames/IPs (e.g., POSTGRES_HOST -> localhost or 127.0.0.1,
KAFKA_BOOTSTRAP_SERVERS -> localhost:29092, QDRANT_URL -> http://localhost:6333)
in all example blocks and the table entries so the variables PROJECT_ROOT,
OMNICLAUDE_PATH, CLAUDE_PLUGIN_ROOT, POSTGRES_HOST, POSTGRES_PORT,
POSTGRES_DATABASE, POSTGRES_PASSWORD, KAFKA_BOOTSTRAP_SERVERS, QDRANT_URL,
LINEAR_INSIGHTS_OUTPUT_DIR, and ARCHON_INTELLIGENCE_URL consistently show
non-user-specific placeholders.
♻️ Duplicate comments (5)
plugins/onex/agents/configs/omniagent-batch-processor.yaml (1)

192-195: Parameterize the batch service endpoint.

Same issue as prior review: the endpoint is still hardcoded to localhost. Please make it configurable.

claude/skills/pr-review/collate_issues.py (1)

1837-1849: --stats after --json breaks JSON output.
Same concern as previously noted: stats are printed after JSON, making the output invalid when --json is used.

plugins/onex/agents/configs/agent-registry.yaml (1)

6-54: Registry metadata counts and timestamp are out of sync.
total_agents: 52 and category counts (sum 49) don’t match the 22 agents defined in this file, and last_updated is still 2025-11-10. Please update counts/date or add validation to keep them synchronized.

plugins/onex/agents/configs/agent-address-pr-comments.yaml (1)

842-844: Stale "Last Updated" date.

The date 2025-10-03 predates this PR (opened 2025-12-04). Update to reflect the actual modification date.

plugins/onex/agents/configs/frontend-developer.yaml (1)

1-10: Missing schema_version and required flat root-level fields.

Unlike other agent configs in this PR that have schema_version, this file omits it. Additionally, the schema mismatch (nested agent_identity instead of flat fields) was flagged in a previous review.

Consider adding schema_version for consistency with other agent configurations in this PR.

♻️ Suggested addition at top
 # Frontend Developer Agent - Dynamic Role Definition
 # React/TypeScript UI component development specialist
 # Distinguished from ui-testing agent: builds UIs (not tests)
+
+schema_version: "1.0.0"
🟡 Minor comments (7)
plugins/onex/.env.example-41-42 (1)

41-42: Use <set_in_env> placeholders for secrets and API keys.

Standardizing placeholders avoids accidental copy/paste of realistic-looking tokens and aligns with the repo’s secret-handling guidance. Based on learnings, sensitive values should use <set_in_env> placeholders in templates.

♻️ Suggested update
-POSTGRES_PASSWORD=<set_your_password_here>
+POSTGRES_PASSWORD=<set_in_env>

-# LINEAR_API_KEY=lin_api_...
+# LINEAR_API_KEY=<set_in_env>

-# OPENAI_API_KEY=sk-...
+# OPENAI_API_KEY=<set_in_env>

-# GEMINI_API_KEY=...
+# GEMINI_API_KEY=<set_in_env>

-# ANTHROPIC_API_KEY=sk-ant-...
+# ANTHROPIC_API_KEY=<set_in_env>

-# ZAI_API_KEY=...
+# ZAI_API_KEY=<set_in_env>

Also applies to: 91-92, 115-125

plugins/onex/.env.example-23-27 (1)

23-27: Avoid committing a user-specific OMNICLAUDE_PATH default.

Because this template is copied and sourced, a hardcoded personal path can misconfigure installs and leaks a developer-specific value. Consider commenting it out and using a generic placeholder. Based on learnings, keep .env.example portable and free of user-specific defaults.

♻️ Suggested update
-OMNICLAUDE_PATH=/Users/jonah/Code/omniclaude
+# OMNICLAUDE_PATH="${HOME}/Code/omniclaude"  # <set_in_env>
plugins/onex/agents/configs/omniagent-smart-responder.yaml-315-321 (1)

315-321: Make the Smart Responder service URL configurable.

Hardcoding the service URL to localhost limits container and remote deployments. Consider an env-based override with a sensible default.

♻️ Suggested update
-    service_url: "http://localhost:8000/process"
+    service_url: "${OMNIAGENT_SMART_RESPONDER_URL:-http://localhost:8000/process}"
plugins/onex/agents/configs/debug.yaml-102-106 (1)

102-106: Hardcoded user-specific path reduces reusability.

The file_management.location contains a hardcoded user path docs/dev_logs/jonah/debug/. This should use a parameterized path or environment variable to support multi-user teams.

♻️ Suggested fix
   file_management:
-    location: "docs/dev_logs/jonah/debug/"
+    location: "docs/dev_logs/{engineer}/debug/"
     naming_pattern: "debug_log_YYYY_MM_DD_HHMMSS.md"
     format: "Structured markdown with consistent sections"

Based on learnings, debug logs should be stored in docs_private/dev_logs/<engineer>/debug/ with parameterized engineer names.

plugins/onex/ENVIRONMENT_VARIABLES.md-104-112 (1)

104-112: Document POSTGRES_USER (used in validation) and add a “do not commit .env” reminder.

The validation command uses POSTGRES_USER, but it isn’t listed in the variables table or examples. Also, consider a checklist reminder to keep .env out of version control.

✅ Suggested doc updates
 | `POSTGRES_HOST` | PostgreSQL host | `192.168.86.200` |
 | `POSTGRES_PORT` | PostgreSQL port | `5436` |
+| `POSTGRES_USER` | PostgreSQL user | `postgres` |
 | `POSTGRES_DATABASE` | Database name | `omninode_bridge` |
@@
 - [ ] Copy `.env.example` to repository root as `.env`
+- [ ] Ensure `.env` is ignored by VCS (do not commit)
@@
 POSTGRES_HOST=192.168.86.200
+POSTGRES_USER=postgres
 KAFKA_BOOTSTRAP_SERVERS=192.168.86.200:29092
Based on learnings, required environment variables should be fully documented.

Also applies to: 168-173, 213-214

plugins/onex/agents/configs/agent-registry.yaml-16-17 (1)

16-17: Reconcile performance targets/units across sections.
performance_target: "<0.5ms …" conflicts with performance_target_ms: 500 and the 175ms overhead totals. Align these to a single unit/target to avoid contradictory expectations.

🛠️ Suggested alignment
-  performance_target: "<0.5ms agent identity resolution"
+  performance_target: "<500ms agent identity resolution"

Also applies to: 375-404

plugins/onex/agents/configs/onex-readme.yaml-5-9 (1)

5-9: Complete validation for schema version 2.0.0 compliance.

This file has validation_status: "pending" and appears to follow schema version 2.0.0's hierarchical structure rather than the flat root-level fields (agent_domain, agent_purpose, agent_title, agent_context, domain_query, implementation_query, match_count, confidence_threshold) used in schema 1.0.0 agent configs. Before finalizing, ensure:

  1. The schema 2.0.0 structure is intentional and documented as the standard going forward
  2. All required metadata fields are properly represented (either at root level or within nested structures)
  3. Update validation_status from "pending" to "active" or "validated" once complete

If schema 2.0.0 intentionally restructures these fields, consider updating other 1.0.0 configs for consistency.

🧹 Nitpick comments (5)
plugins/onex/agents/configs/documentation-indexer.yaml (1)

297-297: Absolute path may cause portability issues.

The configuration_path uses an absolute path /configs/documentation-indexer.yaml. Consider using a relative path from the repository root (e.g., plugins/onex/agents/configs/documentation-indexer.yaml) to ensure portability across different deployment environments.

plugins/onex/agents/configs/parameter-collector.yaml (1)

1-7: Missing schema_version field for consistency.

Other agent configs in this PR (e.g., documentation-indexer.yaml) include a schema_version field. Adding this would improve consistency and enable version-aware processing of agent definitions.

♻️ Suggested addition
 # Parameter Collector Agent Definition
 # Dynamic Role System - YAML Agent Architecture
 # Integration: agent-workflow-coordinator identity assumption

+schema_version: "1.0.0"
 agent_type: "parameter_collector"
 definition_format: "yaml_agent_v1"
plugins/onex/agents/configs/debug-intelligence.yaml (1)

1-8: Consider adding version metadata for consistency.

The sibling debug.yaml includes version metadata (version, schema_compliance, performance_target) at the end. Adding similar metadata here would improve consistency across debug-related agent definitions.

plugins/onex/agents/configs/agent-address-pr-comments.yaml (1)

4-9: Partially compliant schema - missing required fields.

This file has agent_name, agent_domain, agent_title, agent_version, and agent_context but is missing the following required fields per agent schema conventions: agent_purpose, domain_query, implementation_query, match_count, and confidence_threshold.

Consider adding these fields for consistency with other agent configurations. Based on learnings for agents/**/*.yaml.

♻️ Suggested additions after line 9
agent_purpose: |
  Intelligently address PR review feedback with prioritization, quality analysis,
  and pattern learning for effective resolution.
domain_query: "PR comment resolution feedback prioritization quality analysis"
implementation_query: "PR review response patterns cycle reduction"
match_count: 5
confidence_threshold: 0.7
plugins/onex/agents/configs/onex-coordinator.yaml (1)

5-8: Schema uses nested structure instead of flat required fields.

Similar to other agent configs in this PR, this file uses a nested agent_identity structure rather than the flat root-level fields (agent_domain, agent_purpose, agent_title, agent_context, domain_query, implementation_query, match_count, confidence_threshold) specified in the learnings.

This appears to be a deliberate schema design choice across this PR. Consider standardizing on one approach and documenting the schema version requirements.

Also applies to: 10-27

Comment on lines +1508 to 1514
# Extract PR number from fetched data (it's already resolved by fetch-pr-data)
actual_pr_number = pr_data.get("pr_number", 0)
actual_repository = pr_data.get("repository", get_repo_name())
result = CollatedIssues(
pr_number=pr_number,
repository=get_repo_name(),
pr_number=actual_pr_number,
repository=actual_repository,
collated_at=datetime.now(),

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 pr_number before creating CollatedIssues.
CollatedIssues.pr_number is constrained (>=1). Defaulting to 0 will raise validation errors if fetch-pr-data omits pr_number. Add an explicit check and raise OnexError when missing/invalid.

✅ Suggested guard
-    actual_pr_number = pr_data.get("pr_number", 0)
+    actual_pr_number = pr_data.get("pr_number")
+    if not isinstance(actual_pr_number, int) or actual_pr_number < 1:
+        raise OnexError(
+            "Missing or invalid PR number in fetch-pr-data output",
+            code=ErrorCode.INVALID_PR_NUMBER,  # use your error enum
+            context={"pr_input": str(pr_input)},
+        )
🤖 Prompt for AI Agents
In `@claude/skills/pr-review/collate_issues.py` around lines 1508 - 1514, The code
currently defaults pr_number to 0 which violates CollatedIssues.pr_number (must
be >=1); update the creation site that reads pr_data to validate the PR number:
read actual_pr_number from pr_data (as now), verify it's an int >= 1, and if not
raise an OnexError with a clear message before constructing CollatedIssues; keep
using actual_repository = pr_data.get("repository", get_repo_name()) and only
create CollatedIssues(pr_number=actual_pr_number, ...) after the validation
passes.

Comment on lines +1670 to +1684
def format_issues_parallel_solve(
issues: CollatedIssues,
include_nitpicks: bool = False,
) -> str:
"""Format issues for /parallel-solve command consumption.

Generates a list format ready to pass to /parallel-solve.

Args:
issues: CollatedIssues instance containing categorized issues.
include_nitpicks: If True, include nitpick-level issues.

Returns:
Formatted string suitable for /parallel-solve command.
"""

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

Docstrings must include Raises/Example sections.
New/modified functions (e.g., format_issues_parallel_solve, plus other helpers in this file) don’t include Raises and Example sections, which are required for all methods. Please update docstrings consistently.

As per coding guidelines, all methods must include description, Args, Returns, Raises, and Example sections.

📝 Example update
 def format_issues_parallel_solve(
     issues: CollatedIssues,
     include_nitpicks: bool = False,
 ) -> str:
     """Format issues for /parallel-solve command consumption.
@@
     Returns:
         Formatted string suitable for /parallel-solve command.
+
+    Raises:
+        None
+
+    Example:
+        >>> print(format_issues_parallel_solve(issues))
🤖 Prompt for AI Agents
In `@claude/skills/pr-review/collate_issues.py` around lines 1670 - 1684, Update
the docstring for format_issues_parallel_solve and any other new/modified
functions in this file to include explicit Raises and Example sections in
addition to the existing description, Args, and Returns; list any exceptions the
function can raise (e.g., ValueError, TypeError, or custom exceptions raised by
called helpers) in a Raises section, and add a short Example showing sample
input and expected usage/output for /parallel-solve; ensure the docstring format
matches the project's docstring style used elsewhere in the file so the linter
accepts it (refer to functions like CollatedIssues-related helpers for exact
phrasing and exception types).

Comment on lines +5 to +96
schema_version: "2.0.0"
agent_type: "address_pr_comments"
status: "active"

agent_identity:
name: "Address PR Comments Agent"
description: "Address PR review feedback with automatic remote sync and ONEX standards compliance"
color: "green"
primary_role: "PR Comment Resolution Specialist"
responsibility: "Systematically addressing PR review comments while maintaining ONEX standards compliance and ensuring remote synchronization"

specialization:
- "PR review comment analysis and categorization"
- "Automated feedback implementation with quality validation"
- "Remote-first workflow synchronization"
- "ONEX standards compliance verification"
- "Review response management and documentation"

agent_philosophy:
core_principles:
- "Single Responsibility: PR comment analysis and resolution with knowledge enhancement"
- "Context-Focused: Feedback implementation using RAG/KB insights for optimal solutions"
- "Remote-First Workflow: Always-current codebase state with intelligent synchronization"
- "Knowledge Integration: RAG/KB queries for similar PR comment patterns and solutions"
- "Debug Intelligence: Automatic failure capture and pattern learning"
- "Repository-Aware: Automatic Archon project association and task management integration"

methodology:
anti_yolo_approach: true
bfros_framework: true
systematic_validation: true
continuous_learning: true

capabilities:
core_functions:
- name: "establish_archon_pr_comment_context"
description: "Initialize repository-aware context for PR comment resolution"
category: "initialization"

- name: "gather_pr_comment_intelligence"
description: "Collect and analyze similar PR comment patterns and solutions"
category: "intelligence"

- name: "capture_pr_comment_knowledge"
description: "Document successful resolution patterns for future RAG retrieval"
category: "knowledge_capture"

specialized_capabilities:
pr_comment_analysis:
- "Comment classification and priority assessment"
- "Impact analysis and dependency mapping"
- "Reviewer intent interpretation and clarification"
- "Change scope determination"

implementation_management:
- "Automated code change implementation"
- "Quality gate validation and testing"
- "ONEX compliance verification"
- "Conflict resolution and merge handling"

synchronization_control:
- "Remote branch synchronization"
- "Automatic conflict detection and resolution"
- "Change integration verification"
- "Progress tracking and reporting"

intelligence_enhanced_features:
- "Quality-enhanced PR decision making"
- "Performance-assisted PR optimization"
- "Predictive analysis for issue prevention"
- "Multi-dimensional intelligence integration"
- "Pattern-driven process improvement"

framework_integration:
architecture: "streamlined_yaml_framework"
access_time: "<0.5ms"

mandatory_functions:
- "gather_comprehensive_pre_execution_intelligence"
- "execute_task_with_intelligence"
- "capture_debug_intelligence_on_error"
- "agent_lifecycle_initialization"
- "agent_lifecycle_cleanup"

template_system:
primary_template: "orchestrated_intelligence_research"
completion_template: "unified_knowledge_capture"
configuration_path: "/configs/address-pr-comments.yaml"
parameters:
result_count: 5
confidence_threshold: 0.6

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

Add required agent metadata fields for agent configs.
This config is missing the required top‑level keys (agent_domain, agent_purpose, agent_title, agent_context, domain_query, implementation_query, match_count, confidence_threshold). Please add them (reusing existing identity/query values where possible) to satisfy the agent schema.

Based on learnings, agent YAML configurations must include the required field set.

🤖 Prompt for AI Agents
In `@plugins/onex/agents/configs/address-pr-comments.yaml` around lines 5 - 96,
Add the required top-level metadata keys to the YAML: insert agent_domain,
agent_purpose, agent_title, agent_context, domain_query, implementation_query,
match_count, and confidence_threshold. Use values from existing sections where
sensible (e.g., set agent_title from agent_identity.name, agent_purpose from
agent_identity.description or responsibility, agent_context from
agent_philosophy/core_principles or specialization), set
domain_query/implementation_query to reuse the template_system or
mandatory_functions intent, and set match_count/confidence_threshold to the
existing parameters.result_count and parameters.confidence_threshold (or 5 and
0.6 if not present). Ensure these keys live alongside schema_version and
agent_type at the top level.

Comment on lines +5 to +16
schema_version: "1.0.0"
agent_type: "observability"
definition_format: "yaml_agent_v1"

# Agent Identity
agent_identity:
name: "agent-observability"
title: "Agent Observability Specialist"
description: "Real-time monitoring and diagnostics for agent execution health, performance metrics, and system observability"
color: "purple"
task_agent_type: "observability"
specialization_level: "expert"

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

Add required agent metadata fields for YAML schema compliance.

This config is missing mandatory top‑level keys expected by the agents/**/*.yaml contract (agent_domain, agent_purpose, agent_title, agent_context, domain_query, implementation_query, match_count, confidence_threshold). This may break discovery and routing. Based on learnings, please add them.

✅ Proposed patch
 schema_version: "1.0.0"
 agent_type: "observability"
 definition_format: "yaml_agent_v1"
+agent_domain: "observability"
+agent_purpose: "Monitor agent execution health, diagnose failures, and surface actionable observability insights"
+agent_title: "Agent Observability Specialist"
+agent_context: "Real-time monitoring and diagnostics for agent execution health and performance"
+domain_query: "agent observability monitoring diagnostics health metrics performance analysis execution tracking"
+implementation_query: "observability implementation PostgreSQL queries metrics collection error analysis performance profiling"
+match_count: 5
+confidence_threshold: 0.78

Also applies to: 34-65

🤖 Prompt for AI Agents
In `@plugins/onex/agents/configs/agent-observability.yaml` around lines 5 - 16,
The YAML config for the "agent-observability" agent (agent_identity block and
top-level schema_version/agent_type/definition_format) is missing required
top-level metadata fields governed by the agents/**/*.yaml contract; update this
file to add the missing keys: agent_domain, agent_purpose, agent_title,
agent_context, domain_query, implementation_query, match_count, and
confidence_threshold alongside the existing
schema_version/agent_type/definition_format and agent_identity entries so
discovery/routing can validate and use this agent; ensure values are appropriate
for an observability specialist (use agent_identity.name/title/description to
populate agent_title/agent_purpose/context) and keep keys and types consistent
with other YAML agent configs.

Comment on lines +5 to +16
schema_version: "1.0.0"
agent_type: "api_architect"
definition_format: "yaml_agent_v1"

# Agent Identity
agent_identity:
name: "agent-api-architect"
title: "API Architect Specialist Agent"
description: "RESTful API design, OpenAPI specification, FastAPI optimization, and API ecosystem management expert for ONEX services"
color: "blue"
task_agent_type: "api_architect"
specialization_level: "expert"

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

Add required agent schema fields to avoid validation issues.

This agent config omits the required top-level keys (agent_domain, agent_purpose, agent_title, agent_context, domain_query, implementation_query, match_count, confidence_threshold).

✅ Suggested schema fields
 schema_version: "1.0.0"
 agent_type: "api_architect"
 definition_format: "yaml_agent_v1"
 
+agent_domain: "api_architect"
+agent_purpose: "RESTful API design, OpenAPI specification, and FastAPI optimization for ONEX services"
+agent_title: "API Architect Specialist"
+agent_context: "API design, performance, security, and documentation for ONEX services"
+domain_query: "RESTful API design architecture patterns OpenAPI FastAPI optimization microservices HTTP service mesh"
+implementation_query: "FastAPI endpoint implementation async patterns dependency injection API testing performance optimization"
+match_count: 5
+confidence_threshold: 0.6
+
 # Agent Identity
 agent_identity:
Based on learnings, agent YAMLs must include the required top-level schema fields.
🤖 Prompt for AI Agents
In `@plugins/onex/agents/configs/api-architect.yaml` around lines 5 - 16, The
agent config missing required top-level schema fields causes validation
failures; update the YAML (near schema_version and agent_type and the
agent_identity block with name/title/description/task_agent_type) to add the
required keys: agent_domain, agent_purpose, agent_title, agent_context,
domain_query, implementation_query, match_count, and confidence_threshold,
populating them with appropriate values (strings for
domain/purpose/title/context/queries and numeric thresholds for
match_count/confidence_threshold) so the api_architect agent conforms to the
expected schema.

Comment on lines +6 to +33
schema_version: "1.0.0"
agent_type: "documentation_architect"
agent_name: "agent-documentation-architect"
title: "Documentation Architect Specialist"
category: "documentation"
priority: "high"
color: "blue"

# Core Identity
identity:
description: "Technical documentation excellence, API documentation generation, developer experience optimization, and documentation architecture for ONEX ecosystem"
specialization_level: "expert"
domain_context: "documentation_architecture"
task_agent_type: "documentation_architect"

# Activation Configuration
activation:
triggers:
- "documentation"
- "docs"
- "api docs"
- "technical writing"
- "developer experience"
- "documentation architecture"
- "api documentation"
- "knowledge management"
- "content indexing"
- "documentation quality"

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

Add canonical agent metadata keys for registry compatibility.
Top-level agent_*/query/count keys are missing. Values are already present in identity, domain_queries, and template parameters but may not be picked up by validators.

🛠️ Suggested alias fields
 schema_version: "1.0.0"
 agent_type: "documentation_architect"
 agent_name: "agent-documentation-architect"
 title: "Documentation Architect Specialist"
 category: "documentation"
 priority: "high"
 color: "blue"
 
+agent_domain: "documentation_architecture"
+agent_purpose: "Technical documentation excellence, API documentation generation, developer experience optimization, and documentation architecture for ONEX ecosystem"
+agent_title: "Documentation Architect Specialist"
+agent_context: "documentation_architecture"
+domain_query: "technical documentation architecture API docs developer experience discovery indexing"
+implementation_query: "documentation generation implementation patterns RAG indexing"
+match_count: 6
+confidence_threshold: 0.75

Based on learnings, agent YAML configurations must include these canonical fields.

Also applies to: 84-99

🤖 Prompt for AI Agents
In `@plugins/onex/agents/configs/documentation-architect.yaml` around lines 6 -
33, The YAML is missing canonical top-level agent metadata keys required by the
registry validators; copy the existing values from identity and activation into
top-level canonical fields such as agent_name, agent_type, title, category,
priority, color and add the expected agent_* aliases (e.g., agent_description,
agent_specialization_level, agent_domain_context, agent_task_agent_type) plus
any query/count keys the registry expects, ensuring values are sourced from
identity and activation.triggers so validators pick them up; update the document
where identity and activation are defined to add these top-level keys and their
aliases for compatibility with registry ingestion.

Comment on lines +6 to +13
agent_identity:
name: "agent-intelligence-initializer"
role: "Intelligence System Initialization Specialist"
description: "Intelligence system initialization specialist for repository onboarding and comprehensive manual analysis"
version: "2.0.0"
color: "purple"
task_agent_type: "intelligence_initialization"

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

Add required agent schema fields to prevent config validation failures.

This config omits the required top-level keys (agent_domain, agent_purpose, agent_title, agent_context, domain_query, implementation_query, match_count, confidence_threshold). The agent schema for agents/**/*.yaml is likely to reject or ignore the file without them.

✅ Suggested schema fields
 # Schema Version: 1.0.0
 
+agent_domain: "intelligence_initialization"
+agent_purpose: "Repository onboarding and intelligence system initialization"
+agent_title: "Intelligence System Initialization Specialist"
+agent_context: "Repository onboarding, baseline establishment, automation setup, and intelligence tracking"
+domain_query: "intelligence system initialization repository onboarding patterns"
+implementation_query: "intelligence baseline establishment automation setup"
+match_count: 5
+confidence_threshold: 0.6
+
 agent_identity:
   name: "agent-intelligence-initializer"
Based on learnings, agent YAMLs must include the required top-level schema fields.
🤖 Prompt for AI Agents
In `@plugins/onex/agents/configs/intelligence-initializer.yaml` around lines 6 -
13, The YAML is missing required top-level schema fields which will cause
validation to fail; update the file by adding the required keys (agent_domain,
agent_purpose, agent_title, agent_context, domain_query, implementation_query,
match_count, confidence_threshold) alongside the existing agent_identity block
and populate them with appropriate values consistent with agent_identity (e.g.,
set agent_title to a short human title, agent_purpose to a concise purpose
string, agent_domain and agent_context to the relevant domain/context, provide
domain_query and implementation_query strings, and set numeric match_count and
confidence_threshold), ensuring the keys are top-level (not nested under
agent_identity) and semantically align with
name="agent-intelligence-initializer" and role="Intelligence System
Initialization Specialist".

Comment on lines +5 to +20
agent_definition:
name: "agent-omniagent-archon-tickets"
title: "Omniagent Archon Tickets Processor"
description: "Processes Archon tickets through OmniAgent's automated code generation system. Monitors for 'AI IDE Agent' tasks and generates code implementations with intelligent project context integration."
version: "1.0.0"
category: "automation"
color: "cyan"
task_agent_type: "omniagent_archon_tickets"
priority: "high"
specialization_level: "expert"

# Core Identity
identity:
domain: "omniarchon_tickets"
purpose: "Automated code generation from Archon task specifications with intelligent project context integration"
scope: "Archon ticket processing through OmniAgent's automated code generation system with task orchestration capabilities"

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

Add canonical agent metadata fields for registry compatibility.
The required top-level keys (agent_domain, agent_purpose, agent_title, agent_context, domain_query, implementation_query, match_count, confidence_threshold) are missing; values exist only in nested sections. If the registry expects these keys, routing/validation will fail.

🛠️ Suggested alias fields
 agent_definition:
   name: "agent-omniagent-archon-tickets"
   title: "Omniagent Archon Tickets Processor"
   description: "Processes Archon tickets through OmniAgent's automated code generation system. Monitors for 'AI IDE Agent' tasks and generates code implementations with intelligent project context integration."
   version: "1.0.0"
   category: "automation"
   color: "cyan"
   task_agent_type: "omniagent_archon_tickets"
   priority: "high"
   specialization_level: "expert"
 
+agent_domain: "omniarchon_tickets"
+agent_purpose: "Automated code generation from Archon task specifications with intelligent project context integration"
+agent_title: "Omniagent Archon Tickets Processor"
+agent_context: "general"
+domain_query: "omniarchon tickets automation development patterns"
+implementation_query: "omniarchon tickets implementation patterns best practices"
+match_count: 5
+confidence_threshold: 0.6

Based on learnings, agent YAML configurations must include these canonical fields.

Also applies to: 92-100, 167-179

🤖 Prompt for AI Agents
In `@plugins/onex/agents/configs/omniagent-archon-tickets.yaml` around lines 5 -
20, The YAML is missing required top-level canonical registry fields
(agent_domain, agent_purpose, agent_title, agent_context, domain_query,
implementation_query, match_count, confidence_threshold) which currently live
only under agent_definition and identity; add these keys at the top level and
populate them from agent_definition.name/title/description and
identity.domain/purpose/scope as appropriate so registry routing/validation
succeeds. Ensure you add agent_context (use identity.scope or a brief context
string), domain_query and implementation_query (provide the query strings or
aliases used by this agent), and numeric match_count and confidence_threshold
defaults (e.g., 1 and 0.75) to match registry expectations, keeping
agent_definition and identity intact for backward compatibility.

Comment on lines +4 to +11
agent_identity:
name: "overnight-automation"
display_name: "Overnight Automation Controller"
description: "Orchestrates 24/7 overnight automation for Claude Code agents with intelligent scheduling and quota optimization"
version: "2.0.0"
agent_type: "overnight_automation"
color: "gray"

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

Add required agent schema fields to prevent config validation failures.

Required top-level keys (agent_domain, agent_purpose, agent_title, agent_context, domain_query, implementation_query, match_count, confidence_threshold) are absent.

✅ Suggested schema fields
 # Agent Definition: Overnight Automation Controller
 # Converted from agent-overnight-automation.md to YAML format for dynamic role system
 
+agent_domain: "overnight_automation"
+agent_purpose: "24/7 overnight automation orchestration with intelligent scheduling and quota optimization"
+agent_title: "Overnight Automation Controller"
+agent_context: "Scheduled task coordination, batch processing, and automation quality gates"
+domain_query: "overnight automation scheduling quota optimization 24/7 operations"
+implementation_query: "automation scheduling implementation patterns"
+match_count: 5
+confidence_threshold: 0.6
+
 agent_identity:
Based on learnings, agent YAMLs must include the required top-level schema fields.
📝 Committable suggestion

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

Suggested change
agent_identity:
name: "overnight-automation"
display_name: "Overnight Automation Controller"
description: "Orchestrates 24/7 overnight automation for Claude Code agents with intelligent scheduling and quota optimization"
version: "2.0.0"
agent_type: "overnight_automation"
color: "gray"
# Agent Definition: Overnight Automation Controller
# Converted from agent-overnight-automation.md to YAML format for dynamic role system
agent_domain: "overnight_automation"
agent_purpose: "24/7 overnight automation orchestration with intelligent scheduling and quota optimization"
agent_title: "Overnight Automation Controller"
agent_context: "Scheduled task coordination, batch processing, and automation quality gates"
domain_query: "overnight automation scheduling quota optimization 24/7 operations"
implementation_query: "automation scheduling implementation patterns"
match_count: 5
confidence_threshold: 0.6
agent_identity:
name: "overnight-automation"
display_name: "Overnight Automation Controller"
description: "Orchestrates 24/7 overnight automation for Claude Code agents with intelligent scheduling and quota optimization"
version: "2.0.0"
agent_type: "overnight_automation"
color: "gray"
🤖 Prompt for AI Agents
In `@plugins/onex/agents/configs/overnight-automation.yaml` around lines 4 - 11,
The YAML is missing required top-level schema fields and will fail validation;
update the agent_identity block (or top-level config) to include agent_domain,
agent_purpose, agent_title, agent_context, domain_query, implementation_query,
match_count, and confidence_threshold with appropriate values for this agent
(e.g., agent_domain: "automation", agent_purpose: "orchestrate overnight Claude
Code agents", agent_title: a short human title, agent_context: brief operational
context, domain_query and implementation_query as the query strings used by your
matcher, match_count as an integer, and confidence_threshold as a
float/percentage). Ensure the keys are present alongside existing keys like
name/display_name/version/agent_type so the validator accepts the file.

Comment on lines +98 to +162
| Variable | Description | Example |
|----------|-------------|---------|
| `PROJECT_ROOT` | Repository containing the plugin | `/Users/jonah/Code/omniclaude` |
| `OMNICLAUDE_PATH` | Location of omniclaude repository | `/Users/jonah/Code/omniclaude` |
| `CLAUDE_PLUGIN_ROOT` | Location of ONEX plugin (auto-detected) | `${PROJECT_ROOT}/plugins/onex` |

### Infrastructure Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `POSTGRES_HOST` | PostgreSQL host | `192.168.86.200` |
| `POSTGRES_PORT` | PostgreSQL port | `5436` |
| `POSTGRES_DATABASE` | Database name | `omninode_bridge` |
| `POSTGRES_PASSWORD` | Database password | Required |
| `KAFKA_BOOTSTRAP_SERVERS` | Kafka brokers | `192.168.86.200:29092` |
| `QDRANT_URL` | Qdrant vector DB URL | `http://localhost:6333` |

### Optional Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `LINEAR_INSIGHTS_OUTPUT_DIR` | Deep dive output directory | `${HOME}/Code/omni_save` |
| `ARCHON_INTELLIGENCE_URL` | Intelligence coordinator | `http://localhost:8053` |

## Usage Across Repositories

### OmniClaude (Primary Repository)

```bash
# .env
PROJECT_ROOT=/Users/jonah/Code/omniclaude
OMNICLAUDE_PATH=/Users/jonah/Code/omniclaude
POSTGRES_HOST=192.168.86.200
KAFKA_BOOTSTRAP_SERVERS=192.168.86.200:29092
```

### OmniArchon

```bash
# .env
PROJECT_ROOT=/Users/jonah/Code/omniarchon
OMNICLAUDE_PATH=/Users/jonah/Code/omniclaude # For shared config
POSTGRES_HOST=192.168.86.200
KAFKA_BOOTSTRAP_SERVERS=192.168.86.200:29092
```

### OmniBase Core

```bash
# .env
PROJECT_ROOT=/Users/jonah/Code/omnibase_core
OMNICLAUDE_PATH=/Users/jonah/Code/omniclaude # For shared config
POSTGRES_HOST=192.168.86.200
KAFKA_BOOTSTRAP_SERVERS=192.168.86.200:29092
```

### OmniDash

```bash
# .env
PROJECT_ROOT=/Users/jonah/Code/omnidash
OMNICLAUDE_PATH=/Users/jonah/Code/omniclaude # For shared config
POSTGRES_HOST=192.168.86.200
KAFKA_BOOTSTRAP_SERVERS=192.168.86.200:29092
```

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

Replace user-specific paths/IPs with placeholders.

The doc hardcodes /Users/jonah/... and 192.168.86.200, which can leak internal details and reduce portability. Use ${HOME} and localhost/example hosts instead, and apply consistently across all examples.

✅ Example placeholder updates
-| `PROJECT_ROOT` | Repository containing the plugin | `/Users/jonah/Code/omniclaude` |
-| `OMNICLAUDE_PATH` | Location of omniclaude repository | `/Users/jonah/Code/omniclaude` |
+| `PROJECT_ROOT` | Repository containing the plugin | `${HOME}/Code/omniclaude` |
+| `OMNICLAUDE_PATH` | Location of omniclaude repository | `${HOME}/Code/omniclaude` |
@@
-| `POSTGRES_HOST` | PostgreSQL host | `192.168.86.200` |
+| `POSTGRES_HOST` | PostgreSQL host | `127.0.0.1` |
@@
-| `KAFKA_BOOTSTRAP_SERVERS` | Kafka brokers | `192.168.86.200:29092` |
+| `KAFKA_BOOTSTRAP_SERVERS` | Kafka brokers | `127.0.0.1:29092` |
@@
-PROJECT_ROOT=/Users/jonah/Code/omniclaude
-OMNICLAUDE_PATH=/Users/jonah/Code/omniclaude
-POSTGRES_HOST=192.168.86.200
-KAFKA_BOOTSTRAP_SERVERS=192.168.86.200:29092
+PROJECT_ROOT=${HOME}/Code/omniclaude
+OMNICLAUDE_PATH=${HOME}/Code/omniclaude
+POSTGRES_HOST=127.0.0.1
+KAFKA_BOOTSTRAP_SERVERS=127.0.0.1:29092
🤖 Prompt for AI Agents
In `@plugins/onex/ENVIRONMENT_VARIABLES.md` around lines 98 - 162, Update
ENVIRONMENT_VARIABLES.md to remove user-specific paths and IPs by replacing
instances like /Users/jonah/... and 192.168.86.200 with placeholders; use
${HOME} for local paths (e.g., PROJECT_ROOT, OMNICLAUDE_PATH,
LINEAR_INSIGHTS_OUTPUT_DIR) and use localhost or example hostnames/IPs (e.g.,
POSTGRES_HOST -> localhost or 127.0.0.1, KAFKA_BOOTSTRAP_SERVERS ->
localhost:29092, QDRANT_URL -> http://localhost:6333) in all example blocks and
the table entries so the variables PROJECT_ROOT, OMNICLAUDE_PATH,
CLAUDE_PLUGIN_ROOT, POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DATABASE,
POSTGRES_PASSWORD, KAFKA_BOOTSTRAP_SERVERS, QDRANT_URL,
LINEAR_INSIGHTS_OUTPUT_DIR, and ARCHON_INTELLIGENCE_URL consistently show
non-user-specific placeholders.

@jonahgabriel
jonahgabriel merged commit c460ec1 into main Jan 19, 2026
28 checks passed
@jonahgabriel
jonahgabriel deleted the fix/skill-stat-and-jq-parsing branch April 4, 2026 02:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant