Skip to content

feat(tools): wire RootConfig.git_clone to GitCloneTool instantiation#519

Merged
Aureliolo merged 5 commits intomainfrom
feat/wire-git-clone-config
Mar 17, 2026
Merged

feat(tools): wire RootConfig.git_clone to GitCloneTool instantiation#519
Aureliolo merged 5 commits intomainfrom
feat/wire-git-clone-config

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Add build_default_tools() factory that instantiates all 11 built-in workspace tools with config-driven parameters
  • Add build_default_tools_from_config() convenience wrapper that extracts RootConfig.git_clone and wires it to GitCloneTool(network_policy=)
  • Make YAML-configured hostname_allowlist functional by connecting config to tool instantiation
  • Update CLAUDE.md with new TOOL_FACTORY_BUILT event constant and factory.py in package structure

Closes #507

Test plan

  • 12 unit tests covering tool count, sorted order, custom/default policy wiring, workspace propagation, sandbox forwarding, permissive policy edge case, tuple return type, BaseTool isinstance, config wrapper policy/default/sandbox passthrough
  • 3 integration tests covering YAML→RootConfig→factory→GitCloneTool pipeline, empty git_clone defaults, ToolRegistry compatibility
  • All 8832 existing tests pass
  • 94.41% coverage (80% threshold)
  • mypy strict: 0 errors
  • ruff lint + format: clean

Review coverage

Pre-reviewed by 11 agents (docs-consistency, code-reviewer, python-reviewer, pr-test-analyzer, comment-analyzer, logging-audit, resilience-audit, conventions-enforcer, security-reviewer, test-quality-reviewer, issue-resolution-verifier). 10 findings addressed in a dedicated review-fix commit.

…Tool

Create build_default_tools() factory that instantiates all 11 built-in
workspace tools with config-driven parameters. The factory connects
RootConfig.git_clone (GitCloneNetworkPolicy) to GitCloneTool's
network_policy parameter, making YAML-configured hostname_allowlist
functional. A convenience wrapper build_default_tools_from_config()
extracts the policy from RootConfig automatically.
Pre-reviewed by 11 agents, 10 findings addressed:
- Add TOOL_FACTORY_BUILT to CLAUDE.md logging event catalogue
- Add factory.py to CLAUDE.md Package Structure tools/ line
- Use public .workspace property instead of ._workspace in tests
- Add sandbox passthrough test for build_default_tools_from_config
- Add block_private_ips=False edge case test
- Replace magic number 11 with _EXPECTED_TOOL_COUNT constant
- Assert literal values instead of comparing against fresh instance
- Rename yaml var to yaml_str to avoid stdlib shadowing
- Fix "End-to-end" -> "Integration:" in docstring
- Move deferred RootConfig imports to module level
- Simplify intermediate variable and normalize separator width
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 17, 2026

Dependency Review

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

Scanned Files

None

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 927b1347-3a8f-4a0e-a514-1e5f8140c051

📥 Commits

Reviewing files that changed from the base of the PR and between e7a7132 and 33cbd57.

📒 Files selected for processing (1)
  • CLAUDE.md
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Read relevant docs/design/ page before implementing features or planning issues. Design spec is the starting point for architecture, data models, and behavior.

Files:

  • CLAUDE.md
**/*.{md,py,ts,tsx,vue,go,yml,yaml,json,toml}

📄 CodeRabbit inference engine (CLAUDE.md)

Use conventional commits: <type>: <description> where types are feat, fix, refactor, docs, test, chore, perf, ci. Commits must be GPG/SSH signed on main branch.

Files:

  • CLAUDE.md
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/tools/**/*.py : Tool registry with built-in tools: file_system/, git (SSRF prevention via git_url_validator), sandbox/, code_runner. MCP bridge (mcp/). Role-based access. Approval tool (request_human_approval).
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Always use `logger` as the variable name (not `_logger`, not `log`). Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/tools/**/*.py : Tool registry with built-in tools: file_system/, git (SSRF prevention via git_url_validator), sandbox/, code_runner. MCP bridge (mcp/). Role-based access. Approval tool (request_human_approval).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/security/**/*.py : SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies: disabled/weighted/per-category/milestone), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to web/**/*.{ts,tsx,vue} : TypeScript Vue 3 dashboard with PrimeVue UI components, Tailwind CSS styling, Pinia state management, VueFlow for org charts, ECharts for charts, Axios for API calls. Structure: `components/` (feature-organized), `composables/` (reusable logic), `stores/` (Pinia), `router/` (Vue Router), `views/` (pages), `__tests__/` (Vitest), `utils/` (helpers), `api/` (endpoints).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to docs/**/*.md : Documentation in Markdown built with Zensical. Design spec: 7 pages under `docs/design/` (index, agents, organization, communication, engine, memory, operations). Architecture: `docs/architecture/`. Roadmap: `docs/roadmap/`. Security: `docs/security.md`. Licensing: `docs/licensing.md`. Reference: `docs/reference/`. REST API: `docs/rest-api.md` with generated Scalar UI. Library reference: `docs/api/` (auto-generated from docstrings via mkdocstrings + Griffe).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger` (not `_logger`, not `log`).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging`, `logging.getLogger()`, or `print()` in application code.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Structured kwargs in logging: always `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Always use structured kwargs for logging: `logger.info(EVENT, key=value)` — never use string interpolation like `logger.info('msg %s', val)`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Log all error paths at WARNING or ERROR with context before raising. Log all state transitions at INFO. Log object creation, internal flow, and entry/exit of key functions at DEBUG.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : All state transitions must log at INFO.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Do NOT use `import logging` or `logging.getLogger()`. Pure data models, enums, and re-exports do NOT need logging setup.

Applied to files:

  • CLAUDE.md
🪛 LanguageTool
CLAUDE.md

[style] ~199-~199: Since ownership is already implied, this phrasing may be redundant.
Context: ...RTfromevents.git). Each domain has its own module — see src/synthorg/observabilit...

(PRP_OWN)

🔇 Additional comments (2)
CLAUDE.md (2)

135-135: LGTM! Factory documentation added.

The tool factory functions are now properly documented in the package structure, accurately reflecting the new public APIs introduced in this PR.


199-199: LGTM! Event naming guidance clarified.

The updated guidance provides concrete examples from multiple domains and clearly points developers to the events directory for the full inventory. This addresses previous feedback about the mega-list while maintaining clarity.

The LanguageTool hint about "its own" being redundant is a false positive—the phrasing emphasizes the one-to-one relationship between domains and modules and is perfectly clear.


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a tool factory and a config-backed variant to produce a default set of workspace tools with configurable Git-clone policy and sandbox support.
  • Documentation

    • Clarified observability guidance and added factory-related event names for improved logging and importing guidance.
  • Tests

    • Added unit and integration tests covering factory behavior, config-driven policies, workspace validation, and sandbox propagation.

Walkthrough

Adds a new tools factory module with two public APIs to build built-in file-system and git tools (wiring RootConfig.git_clone and sandbox), exports those APIs, introduces three factory observability events, and adds unit and integration tests validating the wiring and composition.

Changes

Cohort / File(s) Summary
Tool Factory Implementation
src/synthorg/tools/factory.py
New module: build_default_tools and build_default_tools_from_config that validate absolute workspace, instantiate 5 file-system and 6 git tools, wire git_clone policy and sandbox, sort by name, and emit factory events.
Public API Exports
src/synthorg/tools/__init__.py
Exports the two new factory functions via __all__.
Observability Events
src/synthorg/observability/events/tool.py
Adds three new event constants: TOOL_FACTORY_BUILT, TOOL_FACTORY_CONFIG_ENTRY, and TOOL_FACTORY_ERROR.
Tests — Unit
tests/unit/tools/test_factory.py
New unit tests covering tool count/order, workspace validation, git policy propagation, sandbox forwarding, and config-based behavior.
Tests — Integration
tests/integration/tools/test_factory_integration.py
Integration tests verifying YAML git_clone config maps to GitCloneTool network_policy and produced tools form a valid registry.
Docs / Metadata
CLAUDE.md, manifest_file, requirements.txt, pyproject.toml
Documentation guidance updated for tool APIs and events; small manifest/metadata edits accompanying the new code and tests.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant Factory as build_default_tools_from_config()
    participant Config as RootConfig
    participant FileBuilder as _build_file_system_tools
    participant GitBuilder as _build_git_tools
    participant Logger as Event Logger

    Caller->>Factory: call(workspace, config, sandbox)
    Factory->>Config: read git_clone policy
    Factory->>FileBuilder: instantiate file-system tools
    FileBuilder-->>Factory: return file tools
    Factory->>GitBuilder: instantiate git tools (network_policy, sandbox)
    GitBuilder-->>Factory: return git tools
    Factory->>Factory: combine & sort tools
    Factory->>Logger: emit TOOL_FACTORY_CONFIG_ENTRY and TOOL_FACTORY_BUILT
    Factory-->>Caller: return sorted tuple of tools
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main objective: wiring RootConfig.git_clone to GitCloneTool instantiation, which is precisely what the PR accomplishes.
Description check ✅ Passed The description is directly related to the changeset, detailing factory functions, configuration wiring, YAML integration, and comprehensive testing.
Linked Issues check ✅ Passed The PR fully addresses all objectives from issue #507: passes RootConfig.git_clone to GitCloneTool instantiation, restores hostname_allowlist functionality, and includes integration tests for the configuration flow.
Out of Scope Changes check ✅ Passed All changes are within scope of issue #507: factory functions, network policy wiring, event constants, and tests validating the config→tool pipeline.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wire-git-clone-config
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/wire-git-clone-config
📝 Coding Plan
  • Generate coding plan for human review comments

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

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the configurability and robustness of tool instantiation by introducing a dedicated factory for built-in workspace tools. It allows for the dynamic creation of tools, particularly the GitCloneTool, with network policies directly derived from the application's root configuration. This change streamlines the setup of tools, improves security by properly wiring git clone SSRF prevention settings, and ensures that tool behavior is consistently driven by configuration.

Highlights

  • New Tool Factory Functions: Introduced build_default_tools() to instantiate all 11 built-in workspace tools with configurable parameters, and build_default_tools_from_config() as a convenience wrapper to extract RootConfig.git_clone.
  • Config-Driven GitCloneTool Instantiation: Enabled the GitCloneTool to be instantiated with network policies derived directly from the RootConfig.git_clone settings, making YAML-configured hostname_allowlist functional for SSRF prevention.
  • Observability and Documentation Updates: Added a new TOOL_FACTORY_BUILT event constant for logging tool factory activity and updated CLAUDE.md to reflect the new tool factory and its functions within the project structure.
  • Comprehensive Testing: Included extensive unit and integration tests to cover tool instantiation, configuration wiring, default policies, workspace propagation, sandbox forwarding, and ToolRegistry compatibility, ensuring robustness and correctness.
Changelog
  • CLAUDE.md
    • Updated the description of the tools/ directory to include the new tool factory functions.
    • Added TOOL_FACTORY_BUILT to the list of recognized event constants.
  • src/synthorg/observability/events/tool.py
    • Added the TOOL_FACTORY_BUILT constant for logging tool factory events.
  • src/synthorg/tools/init.py
    • Imported build_default_tools and build_default_tools_from_config from the new factory module.
    • Exported the new factory functions in the __all__ list.
  • src/synthorg/tools/factory.py
    • Added a new module containing build_default_tools for instantiating all built-in tools.
    • Added build_default_tools_from_config to facilitate tool creation from a RootConfig.
  • tests/integration/tools/test_factory_integration.py
    • Added integration tests to verify that YAML configuration for git_clone correctly propagates to GitCloneTool instances.
    • Included tests to ensure that the tool factory output can be successfully wrapped in a ToolRegistry.
  • tests/unit/tools/test_factory.py
    • Added unit tests for build_default_tools to confirm all expected tools are returned and correctly configured.
    • Included unit tests for build_default_tools_from_config to validate policy extraction from RootConfig and sandbox forwarding.
Activity
  • 12 unit tests were added, covering tool count, sorted order, custom/default policy wiring, workspace propagation, sandbox forwarding, permissive policy edge cases, tuple return type, BaseTool isinstance checks, and config wrapper policy/default/sandbox passthrough.
  • 3 integration tests were added, covering the YAML→RootConfig→factory→GitCloneTool pipeline, empty git_clone defaults, and ToolRegistry compatibility.
  • All 8832 existing tests passed successfully.
  • Code coverage is at 94.41%, exceeding the 80% threshold.
  • mypy strict checks reported 0 errors.
  • ruff lint and format checks were clean.
  • The pull request was pre-reviewed by 11 agents (docs-consistency, code-reviewer, python-reviewer, pr-test-analyzer, comment-analyzer, logging-audit, resilience-audit, conventions-enforcer, security-reviewer, test-quality-reviewer, issue-resolution-verifier), and 10 findings were addressed in a dedicated review-fix commit.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 17, 2026 10:05 — with GitHub Actions Inactive
Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a well-designed factory for instantiating the built-in tools, which is a great improvement for configurability. The new build_default_tools and build_default_tools_from_config functions are clear, and the core goal of wiring the RootConfig.git_clone settings to the GitCloneTool is achieved effectively. The accompanying unit and integration tests are comprehensive and provide excellent coverage for the new functionality. The code quality is high. I have one minor suggestion for improving the maintainability of the documentation.

CLAUDE.md Outdated
- **Never** use `import logging` / `logging.getLogger()` / `print()` in application code
- **Variable name**: always `logger` (not `_logger`, not `log`)
- **Event names**: always use constants from the domain-specific module under `synthorg.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`, `BUDGET_RECORD_ADDED` from `events.budget`, `CFO_ANOMALY_DETECTED` from `events.cfo`, `CONFLICT_DETECTED` from `events.conflict`, `MEETING_STARTED` from `events.meeting`, `MEETING_SCHEDULER_STARTED` from `events.meeting`, `MEETING_SCHEDULER_ERROR` from `events.meeting`, `MEETING_SCHEDULER_STOPPED` from `events.meeting`, `MEETING_PERIODIC_TRIGGERED` from `events.meeting`, `MEETING_EVENT_TRIGGERED` from `events.meeting`, `MEETING_PARTICIPANTS_RESOLVED` from `events.meeting`, `MEETING_NO_PARTICIPANTS` from `events.meeting`, `MEETING_NOT_FOUND` from `events.meeting`, `CLASSIFICATION_START` from `events.classification`, `CONSOLIDATION_START` from `events.consolidation`, `ORG_MEMORY_QUERY_START` from `events.org_memory`, `API_REQUEST_STARTED` from `events.api`, `API_REQUEST_COMPLETED` from `events.api`, `API_REQUEST_ERROR` from `events.api`, `API_ROUTE_NOT_FOUND` from `events.api`, `API_HEALTH_CHECK` from `events.api`, `API_COORDINATION_STARTED` from `events.api`, `API_COORDINATION_COMPLETED` from `events.api`, `API_COORDINATION_FAILED` from `events.api`, `API_COORDINATION_AGENT_RESOLVE_FAILED` from `events.api`, `API_CONTENT_NEGOTIATED` from `events.api`, `API_CORRELATION_FALLBACK` from `events.api`, `API_ACCEPT_PARSE_FAILED` from `events.api`, `API_WS_TICKET_ISSUED` from `events.api`, `API_WS_TICKET_CONSUMED` from `events.api`, `API_WS_TICKET_EXPIRED` from `events.api`, `API_WS_TICKET_INVALID` from `events.api`, `API_WS_TICKET_CLEANUP` from `events.api`, `CODE_RUNNER_EXECUTE_START` from `events.code_runner`, `DOCKER_EXECUTE_START` from `events.docker`, `MCP_INVOKE_START` from `events.mcp`, `SECURITY_EVALUATE_START` from `events.security`, `HR_HIRING_REQUEST_CREATED` from `events.hr`, `PERF_METRIC_RECORDED` from `events.performance`, `PERF_LLM_SAMPLE_STARTED` from `events.performance`, `PERF_LLM_SAMPLE_COMPLETED` from `events.performance`, `PERF_LLM_SAMPLE_FAILED` from `events.performance`, `PERF_OVERRIDE_SET` from `events.performance`, `PERF_OVERRIDE_CLEARED` from `events.performance`, `PERF_OVERRIDE_APPLIED` from `events.performance`, `PERF_OVERRIDE_EXPIRED` from `events.performance`, `TRUST_EVALUATE_START` from `events.trust`, `PROMOTION_EVALUATE_START` from `events.promotion`, `PROMPT_BUILD_START` from `events.prompt`, `MEMORY_RETRIEVAL_START` from `events.memory`, `MEMORY_BACKEND_CONNECTED` from `events.memory`, `MEMORY_ENTRY_STORED` from `events.memory`, `MEMORY_BACKEND_SYSTEM_ERROR` from `events.memory`, `MEMORY_RRF_FUSION_COMPLETE` from `events.memory`, `MEMORY_RRF_VALIDATION_FAILED` from `events.memory`, `AUTONOMY_ACTION_AUTO_APPROVED` from `events.autonomy`, `TIMEOUT_POLICY_EVALUATED` from `events.timeout`, `PERSISTENCE_AUDIT_ENTRY_SAVED` from `events.persistence`, `TASK_ENGINE_STARTED` from `events.task_engine`, `COORDINATION_STARTED` from `events.coordination`, `COORDINATION_FACTORY_BUILT` from `events.coordination`, `COMMUNICATION_DISPATCH_START` from `events.communication`, `COMPANY_STARTED` from `events.company`, `CONFIG_LOADED` from `events.config`, `CORRELATION_ID_CREATED` from `events.correlation`, `DECOMPOSITION_STARTED` from `events.decomposition`, `DELEGATION_STARTED` from `events.delegation`, `EXECUTION_LOOP_START` from `events.execution`, `CHECKPOINT_SAVED` from `events.checkpoint`, `PERSISTENCE_CHECKPOINT_SAVED` from `events.persistence`, `GIT_COMMAND_START` from `events.git`, `GIT_CLONE_URL_REJECTED` from `events.git`, `GIT_CLONE_SSRF_BLOCKED` from `events.git`, `GIT_CLONE_DNS_FAILED` from `events.git`, `GIT_CLONE_SSRF_DISABLED` from `events.git`, `PARALLEL_GROUP_START` from `events.parallel`, `PERSONALITY_LOADED` from `events.personality`, `QUOTA_CHECKED` from `events.quota`, `ROLE_ASSIGNED` from `events.role`, `ROUTING_STARTED` from `events.routing`, `SANDBOX_EXECUTE_START` from `events.sandbox`, `TASK_CREATED` from `events.task`, `TASK_ASSIGNMENT_STARTED` from `events.task_assignment`, `TASK_ROUTING_STARTED` from `events.task_routing`, `TEMPLATE_LOADED` from `events.template`, `TOOL_INVOKE_START` from `events.tool`, `TOOL_OUTPUT_WITHHELD` from `events.tool`, `WORKSPACE_CREATED` from `events.workspace`, `APPROVAL_GATE_ESCALATION_DETECTED` from `events.approval_gate`, `APPROVAL_GATE_ESCALATION_FAILED` from `events.approval_gate`, `APPROVAL_GATE_INITIALIZED` from `events.approval_gate`, `APPROVAL_GATE_RISK_CLASSIFIED` from `events.approval_gate`, `APPROVAL_GATE_RISK_CLASSIFY_FAILED` from `events.approval_gate`, `APPROVAL_GATE_CONTEXT_PARKED` from `events.approval_gate`, `APPROVAL_GATE_CONTEXT_PARK_FAILED` from `events.approval_gate`, `APPROVAL_GATE_PARK_TASKLESS` from `events.approval_gate`, `APPROVAL_GATE_RESUME_STARTED` from `events.approval_gate`, `APPROVAL_GATE_CONTEXT_RESUMED` from `events.approval_gate`, `APPROVAL_GATE_RESUME_FAILED` from `events.approval_gate`, `APPROVAL_GATE_RESUME_DELETE_FAILED` from `events.approval_gate`, `APPROVAL_GATE_RESUME_TRIGGERED` from `events.approval_gate`, `APPROVAL_GATE_NO_PARKED_CONTEXT` from `events.approval_gate`, `APPROVAL_GATE_LOOP_WIRING_WARNING` from `events.approval_gate`, `STAGNATION_CHECK_PERFORMED` from `events.stagnation`, `STAGNATION_DETECTED` from `events.stagnation`, `STAGNATION_CORRECTION_INJECTED` from `events.stagnation`, `STAGNATION_TERMINATED` from `events.stagnation`, `PERSISTENCE_AGENT_STATE_SAVED` from `events.persistence`, `PERSISTENCE_AGENT_STATE_FETCHED` from `events.persistence`, `PERSISTENCE_AGENT_STATE_ACTIVE_QUERIED` from `events.persistence`, `PERSISTENCE_AGENT_STATE_DELETED` from `events.persistence`, `SETTINGS_VALUE_SET` from `events.settings`, `SETTINGS_VALUE_DELETED` from `events.settings`, `SETTINGS_VALUE_RESOLVED` from `events.settings`, `SETTINGS_CACHE_INVALIDATED` from `events.settings`, `SETTINGS_ENCRYPTION_ERROR` from `events.settings`, `SETTINGS_VALIDATION_FAILED` from `events.settings`, `SETTINGS_NOTIFICATION_PUBLISHED` from `events.settings`, `SETTINGS_NOTIFICATION_FAILED` from `events.settings`, `SETTINGS_FETCH_FAILED` from `events.settings`, `SETTINGS_SET_FAILED` from `events.settings`, `SETTINGS_DELETE_FAILED` from `events.settings`, `SETTINGS_NOT_FOUND` from `events.settings`, `SETTINGS_REGISTRY_DUPLICATE` from `events.settings`, `SETTINGS_CONFIG_PATH_MISS` from `events.settings`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`
- **Event names**: always use constants from the domain-specific module under `synthorg.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`, `BUDGET_RECORD_ADDED` from `events.budget`, `CFO_ANOMALY_DETECTED` from `events.cfo`, `CONFLICT_DETECTED` from `events.conflict`, `MEETING_STARTED` from `events.meeting`, `MEETING_SCHEDULER_STARTED` from `events.meeting`, `MEETING_SCHEDULER_ERROR` from `events.meeting`, `MEETING_SCHEDULER_STOPPED` from `events.meeting`, `MEETING_PERIODIC_TRIGGERED` from `events.meeting`, `MEETING_EVENT_TRIGGERED` from `events.meeting`, `MEETING_PARTICIPANTS_RESOLVED` from `events.meeting`, `MEETING_NO_PARTICIPANTS` from `events.meeting`, `MEETING_NOT_FOUND` from `events.meeting`, `CLASSIFICATION_START` from `events.classification`, `CONSOLIDATION_START` from `events.consolidation`, `ORG_MEMORY_QUERY_START` from `events.org_memory`, `API_REQUEST_STARTED` from `events.api`, `API_REQUEST_COMPLETED` from `events.api`, `API_REQUEST_ERROR` from `events.api`, `API_ROUTE_NOT_FOUND` from `events.api`, `API_HEALTH_CHECK` from `events.api`, `API_COORDINATION_STARTED` from `events.api`, `API_COORDINATION_COMPLETED` from `events.api`, `API_COORDINATION_FAILED` from `events.api`, `API_COORDINATION_AGENT_RESOLVE_FAILED` from `events.api`, `API_CONTENT_NEGOTIATED` from `events.api`, `API_CORRELATION_FALLBACK` from `events.api`, `API_ACCEPT_PARSE_FAILED` from `events.api`, `API_WS_TICKET_ISSUED` from `events.api`, `API_WS_TICKET_CONSUMED` from `events.api`, `API_WS_TICKET_EXPIRED` from `events.api`, `API_WS_TICKET_INVALID` from `events.api`, `API_WS_TICKET_CLEANUP` from `events.api`, `CODE_RUNNER_EXECUTE_START` from `events.code_runner`, `DOCKER_EXECUTE_START` from `events.docker`, `MCP_INVOKE_START` from `events.mcp`, `SECURITY_EVALUATE_START` from `events.security`, `HR_HIRING_REQUEST_CREATED` from `events.hr`, `PERF_METRIC_RECORDED` from `events.performance`, `PERF_LLM_SAMPLE_STARTED` from `events.performance`, `PERF_LLM_SAMPLE_COMPLETED` from `events.performance`, `PERF_LLM_SAMPLE_FAILED` from `events.performance`, `PERF_OVERRIDE_SET` from `events.performance`, `PERF_OVERRIDE_CLEARED` from `events.performance`, `PERF_OVERRIDE_APPLIED` from `events.performance`, `PERF_OVERRIDE_EXPIRED` from `events.performance`, `TRUST_EVALUATE_START` from `events.trust`, `PROMOTION_EVALUATE_START` from `events.promotion`, `PROMPT_BUILD_START` from `events.prompt`, `MEMORY_RETRIEVAL_START` from `events.memory`, `MEMORY_BACKEND_CONNECTED` from `events.memory`, `MEMORY_ENTRY_STORED` from `events.memory`, `MEMORY_BACKEND_SYSTEM_ERROR` from `events.memory`, `MEMORY_RRF_FUSION_COMPLETE` from `events.memory`, `MEMORY_RRF_VALIDATION_FAILED` from `events.memory`, `AUTONOMY_ACTION_AUTO_APPROVED` from `events.autonomy`, `TIMEOUT_POLICY_EVALUATED` from `events.timeout`, `PERSISTENCE_AUDIT_ENTRY_SAVED` from `events.persistence`, `TASK_ENGINE_STARTED` from `events.task_engine`, `COORDINATION_STARTED` from `events.coordination`, `COORDINATION_FACTORY_BUILT` from `events.coordination`, `COMMUNICATION_DISPATCH_START` from `events.communication`, `COMPANY_STARTED` from `events.company`, `CONFIG_LOADED` from `events.config`, `CORRELATION_ID_CREATED` from `events.correlation`, `DECOMPOSITION_STARTED` from `events.decomposition`, `DELEGATION_STARTED` from `events.delegation`, `EXECUTION_LOOP_START` from `events.execution`, `CHECKPOINT_SAVED` from `events.checkpoint`, `PERSISTENCE_CHECKPOINT_SAVED` from `events.persistence`, `GIT_COMMAND_START` from `events.git`, `GIT_CLONE_URL_REJECTED` from `events.git`, `GIT_CLONE_SSRF_BLOCKED` from `events.git`, `GIT_CLONE_DNS_FAILED` from `events.git`, `GIT_CLONE_SSRF_DISABLED` from `events.git`, `PARALLEL_GROUP_START` from `events.parallel`, `PERSONALITY_LOADED` from `events.personality`, `QUOTA_CHECKED` from `events.quota`, `ROLE_ASSIGNED` from `events.role`, `ROUTING_STARTED` from `events.routing`, `SANDBOX_EXECUTE_START` from `events.sandbox`, `TASK_CREATED` from `events.task`, `TASK_ASSIGNMENT_STARTED` from `events.task_assignment`, `TASK_ROUTING_STARTED` from `events.task_routing`, `TEMPLATE_LOADED` from `events.template`, `TOOL_INVOKE_START` from `events.tool`, `TOOL_OUTPUT_WITHHELD` from `events.tool`, `TOOL_FACTORY_BUILT` from `events.tool`, `WORKSPACE_CREATED` from `events.workspace`, `APPROVAL_GATE_ESCALATION_DETECTED` from `events.approval_gate`, `APPROVAL_GATE_ESCALATION_FAILED` from `events.approval_gate`, `APPROVAL_GATE_INITIALIZED` from `events.approval_gate`, `APPROVAL_GATE_RISK_CLASSIFIED` from `events.approval_gate`, `APPROVAL_GATE_RISK_CLASSIFY_FAILED` from `events.approval_gate`, `APPROVAL_GATE_CONTEXT_PARKED` from `events.approval_gate`, `APPROVAL_GATE_CONTEXT_PARK_FAILED` from `events.approval_gate`, `APPROVAL_GATE_PARK_TASKLESS` from `events.approval_gate`, `APPROVAL_GATE_RESUME_STARTED` from `events.approval_gate`, `APPROVAL_GATE_CONTEXT_RESUMED` from `events.approval_gate`, `APPROVAL_GATE_RESUME_FAILED` from `events.approval_gate`, `APPROVAL_GATE_RESUME_DELETE_FAILED` from `events.approval_gate`, `APPROVAL_GATE_RESUME_TRIGGERED` from `events.approval_gate`, `APPROVAL_GATE_NO_PARKED_CONTEXT` from `events.approval_gate`, `APPROVAL_GATE_LOOP_WIRING_WARNING` from `events.approval_gate`, `STAGNATION_CHECK_PERFORMED` from `events.stagnation`, `STAGNATION_DETECTED` from `events.stagnation`, `STAGNATION_CORRECTION_INJECTED` from `events.stagnation`, `STAGNATION_TERMINATED` from `events.stagnation`, `PERSISTENCE_AGENT_STATE_SAVED` from `events.persistence`, `PERSISTENCE_AGENT_STATE_FETCHED` from `events.persistence`, `PERSISTENCE_AGENT_STATE_ACTIVE_QUERIED` from `events.persistence`, `PERSISTENCE_AGENT_STATE_DELETED` from `events.persistence`, `SETTINGS_VALUE_SET` from `events.settings`, `SETTINGS_VALUE_DELETED` from `events.settings`, `SETTINGS_VALUE_RESOLVED` from `events.settings`, `SETTINGS_CACHE_INVALIDATED` from `events.settings`, `SETTINGS_ENCRYPTION_ERROR` from `events.settings`, `SETTINGS_VALIDATION_FAILED` from `events.settings`, `SETTINGS_NOTIFICATION_PUBLISHED` from `events.settings`, `SETTINGS_NOTIFICATION_FAILED` from `events.settings`, `SETTINGS_FETCH_FAILED` from `events.settings`, `SETTINGS_SET_FAILED` from `events.settings`, `SETTINGS_DELETE_FAILED` from `events.settings`, `SETTINGS_NOT_FOUND` from `events.settings`, `SETTINGS_REGISTRY_DUPLICATE` from `events.settings`, `SETTINGS_CONFIG_PATH_MISS` from `events.settings`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This list of example event constants is becoming very long and is difficult to navigate. To improve readability and make it easier to check if an event is already listed, please consider sorting the constants alphabetically within the e.g., (...) block.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.16%. Comparing base (29f7481) to head (33cbd57).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #519   +/-   ##
=======================================
  Coverage   93.15%   93.16%           
=======================================
  Files         505      506    +1     
  Lines       24480    24490   +10     
  Branches     2333     2333           
=======================================
+ Hits        22805    22815   +10     
  Misses       1328     1328           
  Partials      347      347           

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

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@CLAUDE.md`:
- Line 199: Replace the huge inline mega-list of event constants with a concise
example and a pointer to the events package: show one or two example imports
(e.g., "from synthorg.observability.events.api import API_REQUEST_STARTED") and
then add a short sentence directing readers to the events directory for the full
list (referencing the module path src/synthorg/observability/events/). Keep the
wording in the current CLAUDE.md sentence but remove the long comma-separated
list and ensure the example uses the generic symbol EVENT_CONSTANT or a real
constant like API_REQUEST_STARTED to demonstrate the pattern.

In `@src/synthorg/tools/factory.py`:
- Around line 41-92: build_default_tools is over the 50-line limit; split it
into two small private helper builders to reduce size. Create
_build_filesystem_tools(workspace: Path) -> list[BaseTool] that returns the
fs_tools list (ReadFileTool, WriteFileTool, EditFileTool, ListDirectoryTool,
DeleteFileTool) and _build_git_tools(workspace: Path, sandbox: SandboxBackend |
None, git_clone_policy: GitCloneNetworkPolicy | None) -> list[BaseTool] that
returns the git_tools list (GitStatusTool, GitLogTool, GitDiffTool,
GitBranchTool, GitCommitTool, GitCloneTool), then update build_default_tools to
call these helpers, sort the combined list into result, log with
TOOL_FACTORY_BUILT and return result; keep names (fs_tools, git_tools, result,
TOOL_FACTORY_BUILT) so callers and logging remain unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 02262b24-a764-46a3-bcb8-a96874bde3ad

📥 Commits

Reviewing files that changed from the base of the PR and between 32f553d and e91a62b.

📒 Files selected for processing (6)
  • CLAUDE.md
  • src/synthorg/observability/events/tool.py
  • src/synthorg/tools/__init__.py
  • src/synthorg/tools/factory.py
  • tests/integration/tools/test_factory_integration.py
  • tests/unit/tools/test_factory.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Deploy Preview
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do not use from __future__ import annotations — Python 3.14 has PEP 649 native lazy annotations.
Use except A, B: syntax (no parentheses) — PEP 758 except syntax enforced by ruff on Python 3.14.
Add type hints to all public functions; enforce mypy strict mode compliance.
Use Google-style docstrings on all public classes and functions; enforce via ruff D rules.
Keep functions under 50 lines and files under 800 lines.
Handle errors explicitly and never silently swallow exceptions.
Validate at system boundaries (user input, external APIs, config files).
Set line length to 88 characters (ruff enforces).
Use uv for Python dependency management. Install with uv sync, run tests with -n auto for parallelism, lint with ruff check, format with ruff format, type-check with mypy.
Scripts in scripts/ have relaxed ruff rules: print and deferred imports are allowed.

Files:

  • src/synthorg/observability/events/tool.py
  • tests/unit/tools/test_factory.py
  • src/synthorg/tools/factory.py
  • src/synthorg/tools/__init__.py
  • tests/integration/tools/test_factory_integration.py
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Create new objects instead of mutating existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping. For dict/list fields in frozen Pydantic models, rely on frozen=True and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization).
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (with model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Adopt Pydantic v2 conventions: use @computed_field for derived values instead of storing redundant fields; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Every module with business logic must have: from synthorg.observability import get_logger then logger = get_logger(__name__). Never use import logging, logging.getLogger(), or print() in application code.
Always use logger as the variable name (not _logger, not log). Use event name constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Always use structured kwargs for logging: logger.info(EVENT, key=value) — never use string interpolation like logger.info('msg %s', val).
Log all error paths at WARNING or ERROR with context before raising. Log all state transitions at INFO. Log object creation, internal flow, and entry/exit of key functions at DEBUG.
Do NOT use import logging or logging.getLogger(). Pure data models, ...

Files:

  • src/synthorg/observability/events/tool.py
  • src/synthorg/tools/factory.py
  • src/synthorg/tools/__init__.py
**/*.{md,py,ts,tsx,vue,go,yml,yaml,json,toml}

📄 CodeRabbit inference engine (CLAUDE.md)

Use conventional commits: <type>: <description> where types are feat, fix, refactor, docs, test, chore, perf, ci. Commits must be GPG/SSH signed on main branch.

Files:

  • src/synthorg/observability/events/tool.py
  • tests/unit/tools/test_factory.py
  • src/synthorg/tools/factory.py
  • CLAUDE.md
  • src/synthorg/tools/__init__.py
  • tests/integration/tools/test_factory_integration.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Mark tests with @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, or @pytest.mark.slow. Maintain 80% minimum code coverage.
Use asyncio_mode = 'auto' for async tests — no manual @pytest.mark.asyncio needed. Set test timeout to 30 seconds per test. Always include -n auto for parallelism via pytest-xdist.
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned test code, docstrings, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001, test-provider, test-small-001, etc. Vendor names may only appear in Operations design page, .claude/ files, or third-party import paths.
Use Hypothesis for property-based testing with @given + @settings. Profiles: ci (200 examples, default) and dev (1000 examples) via HYPOTHESIS_PROFILE env var. Never skip, dismiss, or ignore flaky tests — fix them fully. Mock time.monotonic() and asyncio.sleep() for deterministic timing-sensitive tests instead of widening margins.

Files:

  • tests/unit/tools/test_factory.py
  • tests/integration/tools/test_factory_integration.py
src/synthorg/tools/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Tool registry with built-in tools: file_system/, git (SSRF prevention via git_url_validator), sandbox/, code_runner. MCP bridge (mcp/). Role-based access. Approval tool (request_human_approval).

Files:

  • src/synthorg/tools/factory.py
  • src/synthorg/tools/__init__.py
**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Read relevant docs/design/ page before implementing features or planning issues. Design spec is the starting point for architecture, data models, and behavior.

Files:

  • CLAUDE.md
🧠 Learnings (17)
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.

Applied to files:

  • src/synthorg/observability/events/tool.py
  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/tools/**/*.py : Tool registry with built-in tools: file_system/, git (SSRF prevention via git_url_validator), sandbox/, code_runner. MCP bridge (mcp/). Role-based access. Approval tool (request_human_approval).

Applied to files:

  • tests/unit/tools/test_factory.py
  • src/synthorg/tools/factory.py
  • CLAUDE.md
  • src/synthorg/tools/__init__.py
  • tests/integration/tools/test_factory_integration.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Create new objects instead of mutating existing ones. For non-Pydantic internal collections (registries, `BaseTool`), use `copy.deepcopy()` at construction + `MappingProxyType` wrapping. For `dict`/`list` fields in frozen Pydantic models, rely on `frozen=True` and `copy.deepcopy()` at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization).

Applied to files:

  • src/synthorg/tools/factory.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Always use `logger` as the variable name (not `_logger`, not `log`). Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/security/**/*.py : SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies: disabled/weighted/per-category/milestone), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to web/**/*.{ts,tsx,vue} : TypeScript Vue 3 dashboard with PrimeVue UI components, Tailwind CSS styling, Pinia state management, VueFlow for org charts, ECharts for charts, Axios for API calls. Structure: `components/` (feature-organized), `composables/` (reusable logic), `stores/` (Pinia), `router/` (Vue Router), `views/` (pages), `__tests__/` (Vitest), `utils/` (helpers), `api/` (endpoints).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to docs/**/*.md : Documentation in Markdown built with Zensical. Design spec: 7 pages under `docs/design/` (index, agents, organization, communication, engine, memory, operations). Architecture: `docs/architecture/`. Roadmap: `docs/roadmap/`. Security: `docs/security.md`. Licensing: `docs/licensing.md`. Reference: `docs/reference/`. REST API: `docs/rest-api.md` with generated Scalar UI. Library reference: `docs/api/` (auto-generated from docstrings via mkdocstrings + Griffe).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger` (not `_logger`, not `log`).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Structured kwargs in logging: always `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Always use structured kwargs for logging: `logger.info(EVENT, key=value)` — never use string interpolation like `logger.info('msg %s', val)`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging`, `logging.getLogger()`, or `print()` in application code.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Log all error paths at WARNING or ERROR with context before raising. Log all state transitions at INFO. Log object creation, internal flow, and entry/exit of key functions at DEBUG.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : All state transitions must log at INFO.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Do NOT use `import logging` or `logging.getLogger()`. Pure data models, enums, and re-exports do NOT need logging setup.

Applied to files:

  • CLAUDE.md
🧬 Code graph analysis (4)
tests/unit/tools/test_factory.py (2)
src/synthorg/config/schema.py (1)
  • RootConfig (387-651)
src/synthorg/tools/git_url_validator.py (1)
  • GitCloneNetworkPolicy (82-127)
src/synthorg/tools/factory.py (3)
src/synthorg/tools/git_tools.py (1)
  • GitCloneTool (596-720)
src/synthorg/config/schema.py (1)
  • RootConfig (387-651)
src/synthorg/tools/git_url_validator.py (1)
  • GitCloneNetworkPolicy (82-127)
src/synthorg/tools/__init__.py (1)
src/synthorg/tools/factory.py (2)
  • build_default_tools (41-92)
  • build_default_tools_from_config (95-119)
tests/integration/tools/test_factory_integration.py (3)
src/synthorg/config/loader.py (1)
  • load_config_from_string (495-524)
src/synthorg/tools/factory.py (2)
  • build_default_tools (41-92)
  • build_default_tools_from_config (95-119)
src/synthorg/tools/git_tools.py (1)
  • GitCloneTool (596-720)
🔇 Additional comments (7)
src/synthorg/observability/events/tool.py (1)

26-27: Looks good: new factory event constant is consistent with existing event taxonomy.

src/synthorg/tools/factory.py (1)

95-119: Nice wrapper design: config policy passthrough is clear and correct.

src/synthorg/tools/__init__.py (1)

14-14: Public exports are correctly wired for the new factory APIs.

Also applies to: 90-91

CLAUDE.md (1)

135-135: Package-structure docs update is aligned with the new tool factory surface.

tests/unit/tools/test_factory.py (2)

34-160: Strong unit coverage for factory construction, ordering, and policy/sandbox wiring.


163-216: Wrapper-focused unit tests are solid and directly validate RootConfig.git_clone passthrough.

tests/integration/tools/test_factory_integration.py (1)

18-68: Great integration coverage for the YAML→config→factory→GitCloneTool pipeline and registry wrapping path.

…t, and Gemini

- Split build_default_tools into private helpers (_build_file_system_tools,
  _build_git_tools) to satisfy the 50-line function limit
- Add workspace absoluteness guard for fail-fast validation before
  partial tool construction
- Add Raises section to both factory function docstrings
- Log git_clone_block_private_ips and git_clone_allowlist_size in
  TOOL_FACTORY_BUILT event for security audit visibility
- Add DEBUG-level entry log to build_default_tools_from_config
- Add TOOL_FACTORY_ERROR event constant for validation failures
- Parametrize three policy-variant unit tests per CLAUDE.md convention
- Add workspace validation unit test for new guard
- Add integration tests for YAML block_private_ips:false and absent
  git_clone key
- Condense CLAUDE.md event constant mega-list to example + pointer
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@src/synthorg/tools/factory.py`:
- Around line 152-155: The DEBUG entry log currently reuses the
TOOL_FACTORY_BUILT event constant (logger.debug(..., source="config")) which
conflicts with the INFO completion log in build_default_tools; update the entry
logging in factory.py to either remove the event constant and log a plain debug
message via logger.debug("Entering tool factory configuration", source="config")
or introduce and use a new constant TOOL_FACTORY_CONFIG_ENTRY for this entry
point and reference that constant in the logger.debug call, ensuring
build_default_tools still uses TOOL_FACTORY_BUILT for completion logging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6dc684e9-cc9f-40ea-ae79-5bc68d9a33fc

📥 Commits

Reviewing files that changed from the base of the PR and between e91a62b and 1706e1e.

📒 Files selected for processing (5)
  • CLAUDE.md
  • src/synthorg/observability/events/tool.py
  • src/synthorg/tools/factory.py
  • tests/integration/tools/test_factory_integration.py
  • tests/unit/tools/test_factory.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Deploy Preview
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Read relevant docs/design/ page before implementing features or planning issues. Design spec is the starting point for architecture, data models, and behavior.

Files:

  • CLAUDE.md
**/*.{md,py,ts,tsx,vue,go,yml,yaml,json,toml}

📄 CodeRabbit inference engine (CLAUDE.md)

Use conventional commits: <type>: <description> where types are feat, fix, refactor, docs, test, chore, perf, ci. Commits must be GPG/SSH signed on main branch.

Files:

  • CLAUDE.md
  • src/synthorg/tools/factory.py
  • src/synthorg/observability/events/tool.py
  • tests/integration/tools/test_factory_integration.py
  • tests/unit/tools/test_factory.py
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Do not use from __future__ import annotations — Python 3.14 has PEP 649 native lazy annotations.
Use except A, B: syntax (no parentheses) — PEP 758 except syntax enforced by ruff on Python 3.14.
Add type hints to all public functions; enforce mypy strict mode compliance.
Use Google-style docstrings on all public classes and functions; enforce via ruff D rules.
Keep functions under 50 lines and files under 800 lines.
Handle errors explicitly and never silently swallow exceptions.
Validate at system boundaries (user input, external APIs, config files).
Set line length to 88 characters (ruff enforces).
Use uv for Python dependency management. Install with uv sync, run tests with -n auto for parallelism, lint with ruff check, format with ruff format, type-check with mypy.
Scripts in scripts/ have relaxed ruff rules: print and deferred imports are allowed.

Files:

  • src/synthorg/tools/factory.py
  • src/synthorg/observability/events/tool.py
  • tests/integration/tools/test_factory_integration.py
  • tests/unit/tools/test_factory.py
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Create new objects instead of mutating existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping. For dict/list fields in frozen Pydantic models, rely on frozen=True and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization).
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (with model_copy(update=...)) for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Adopt Pydantic v2 conventions: use @computed_field for derived values instead of storing redundant fields; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code (multiple tool invocations, parallel agent calls). Prefer structured concurrency over bare create_task.
Every module with business logic must have: from synthorg.observability import get_logger then logger = get_logger(__name__). Never use import logging, logging.getLogger(), or print() in application code.
Always use logger as the variable name (not _logger, not log). Use event name constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Always use structured kwargs for logging: logger.info(EVENT, key=value) — never use string interpolation like logger.info('msg %s', val).
Log all error paths at WARNING or ERROR with context before raising. Log all state transitions at INFO. Log object creation, internal flow, and entry/exit of key functions at DEBUG.
Do NOT use import logging or logging.getLogger(). Pure data models, ...

Files:

  • src/synthorg/tools/factory.py
  • src/synthorg/observability/events/tool.py
src/synthorg/tools/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Tool registry with built-in tools: file_system/, git (SSRF prevention via git_url_validator), sandbox/, code_runner. MCP bridge (mcp/). Role-based access. Approval tool (request_human_approval).

Files:

  • src/synthorg/tools/factory.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Mark tests with @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, or @pytest.mark.slow. Maintain 80% minimum code coverage.
Use asyncio_mode = 'auto' for async tests — no manual @pytest.mark.asyncio needed. Set test timeout to 30 seconds per test. Always include -n auto for parallelism via pytest-xdist.
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned test code, docstrings, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001, test-provider, test-small-001, etc. Vendor names may only appear in Operations design page, .claude/ files, or third-party import paths.
Use Hypothesis for property-based testing with @given + @settings. Profiles: ci (200 examples, default) and dev (1000 examples) via HYPOTHESIS_PROFILE env var. Never skip, dismiss, or ignore flaky tests — fix them fully. Mock time.monotonic() and asyncio.sleep() for deterministic timing-sensitive tests instead of widening margins.

Files:

  • tests/integration/tools/test_factory_integration.py
  • tests/unit/tools/test_factory.py
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/tools/**/*.py : Tool registry with built-in tools: file_system/, git (SSRF prevention via git_url_validator), sandbox/, code_runner. MCP bridge (mcp/). Role-based access. Approval tool (request_human_approval).
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.

Applied to files:

  • CLAUDE.md
  • src/synthorg/observability/events/tool.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Always use `logger` as the variable name (not `_logger`, not `log`). Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `PROVIDER_CALL_START` from `events.provider`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/tools/**/*.py : Tool registry with built-in tools: file_system/, git (SSRF prevention via git_url_validator), sandbox/, code_runner. MCP bridge (mcp/). Role-based access. Approval tool (request_human_approval).

Applied to files:

  • CLAUDE.md
  • src/synthorg/tools/factory.py
  • tests/integration/tools/test_factory_integration.py
  • tests/unit/tools/test_factory.py
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/security/**/*.py : SecOps agent, rule engine (soft-allow/hard-deny, fail-closed), audit log, output scanner, output scan response policies (redact/withhold/log-only/autonomy-tiered), risk classifier, risk tier classifier, action type registry, ToolInvoker security integration, progressive trust (4 strategies: disabled/weighted/per-category/milestone), autonomy levels (presets, resolver, change strategy), timeout policies (park/resume).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to web/**/*.{ts,tsx,vue} : TypeScript Vue 3 dashboard with PrimeVue UI components, Tailwind CSS styling, Pinia state management, VueFlow for org charts, ECharts for charts, Axios for API calls. Structure: `components/` (feature-organized), `composables/` (reusable logic), `stores/` (Pinia), `router/` (Vue Router), `views/` (pages), `__tests__/` (Vitest), `utils/` (helpers), `api/` (endpoints).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to docs/**/*.md : Documentation in Markdown built with Zensical. Design spec: 7 pages under `docs/design/` (index, agents, organization, communication, engine, memory, operations). Architecture: `docs/architecture/`. Roadmap: `docs/roadmap/`. Security: `docs/security.md`. Licensing: `docs/licensing.md`. Reference: `docs/reference/`. REST API: `docs/rest-api.md` with generated Scalar UI. Library reference: `docs/api/` (auto-generated from docstrings via mkdocstrings + Griffe).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging` / `logging.getLogger()` / `print()` in application code. Variable name: always `logger` (not `_logger`, not `log`).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must have: `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`. Never use `import logging`, `logging.getLogger()`, or `print()` in application code.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Structured kwargs in logging: always `logger.info(EVENT, key=value)` — never `logger.info('msg %s', val)`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Always use structured kwargs for logging: `logger.info(EVENT, key=value)` — never use string interpolation like `logger.info('msg %s', val)`.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : All error paths must log at WARNING or ERROR with context before raising.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Log all error paths at WARNING or ERROR with context before raising. Log all state transitions at INFO. Log object creation, internal flow, and entry/exit of key functions at DEBUG.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : All state transitions must log at INFO.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to src/synthorg/**/*.py : Do NOT use `import logging` or `logging.getLogger()`. Pure data models, enums, and re-exports do NOT need logging setup.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T07:15:40.520Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T07:15:40.520Z
Learning: Applies to **/*.py : Keep functions under 50 lines and files under 800 lines.

Applied to files:

  • src/synthorg/tools/factory.py
🧬 Code graph analysis (2)
src/synthorg/tools/factory.py (2)
src/synthorg/config/schema.py (1)
  • RootConfig (387-651)
src/synthorg/tools/git_url_validator.py (1)
  • GitCloneNetworkPolicy (82-127)
tests/unit/tools/test_factory.py (3)
src/synthorg/config/schema.py (1)
  • RootConfig (387-651)
src/synthorg/tools/git_tools.py (1)
  • GitCloneTool (596-720)
src/synthorg/tools/git_url_validator.py (1)
  • GitCloneNetworkPolicy (82-127)
🪛 LanguageTool
CLAUDE.md

[style] ~199-~199: Since ownership is already implied, this phrasing may be redundant.
Context: ...RTfromevents.git). Each domain has its own module — see src/synthorg/observabilit...

(PRP_OWN)

🔇 Additional comments (13)
src/synthorg/observability/events/tool.py (1)

26-29: LGTM!

The new TOOL_FACTORY_BUILT and TOOL_FACTORY_ERROR event constants follow the established naming convention and are properly organized with a section comment. The Final[str] type annotation is consistent with existing constants in this module.

CLAUDE.md (2)

135-135: LGTM!

The tools package structure documentation is correctly updated to include the new factory functions build_default_tools and build_default_tools_from_config.


199-199: LGTM!

The event names guidance is improved with concrete examples (API_REQUEST_STARTED, TOOL_INVOKE_START, GIT_COMMAND_START) and a reference to the events directory for the full inventory. This addresses the prior feedback to make the documentation more maintainable.

src/synthorg/tools/factory.py (3)

1-42: LGTM!

The module structure is well-organized:

  • Proper observability setup with get_logger(__name__)
  • Event constants imported from the domain-specific module
  • TYPE_CHECKING block correctly used for type-only imports
  • Clear module docstring explaining both public APIs

44-76: LGTM!

The private helper functions are well-designed:

  • _build_file_system_tools and _build_git_tools each return a tuple of tools
  • Clear docstrings describe the purpose
  • git_clone_policy is correctly wired to GitCloneTool.network_policy

79-126: LGTM!

The build_default_tools function is well-implemented:

  • Validates workspace absoluteness with proper error logging before raising
  • Combines and sorts tools by name for deterministic ordering
  • Logs TOOL_FACTORY_BUILT with comprehensive metrics (tool count, names, policy details)
  • Correctly handles None policy by defaulting to restrictive values in the log output
tests/unit/tools/test_factory.py (4)

1-31: LGTM!

The test module setup is clean with proper imports and a well-defined _EXPECTED_TOOL_NAMES constant that documents the expected 11 built-in tools in sorted order. This makes test maintenance easier when tools are added or renamed.


34-92: LGTM!

The TestBuildDefaultTools class has excellent coverage:

  • Verifies tool count and sorted order
  • Uses @pytest.mark.parametrize for policy wiring variants (custom allowlist, default when None, permissive policy)
  • Tests workspace validation with relative path rejection

94-166: LGTM!

Good coverage of workspace and sandbox propagation:

  • File system tools receive correct workspace_root
  • Git tools receive correct workspace
  • Sandbox backend is forwarded to all git tools
  • Return type verification (tuple) and BaseTool isinstance checks

169-222: LGTM!

The TestBuildDefaultToolsFromConfig tests properly verify the config wrapper:

  • Policy extraction from RootConfig.git_clone
  • Default config yields default policy
  • Sandbox forwarding through the config wrapper
tests/integration/tools/test_factory_integration.py (3)

1-16: LGTM!

The integration test module is well-structured with proper imports and the _EXPECTED_TOOL_COUNT constant. Using load_config_from_string enables testing the full YAML → RootConfig → factory pipeline without filesystem dependencies.


18-96: LGTM!

Excellent integration test coverage for the config-driven tool factory pipeline:

  • Tests all key YAML configurations: allowlist, empty section, block_private_ips: false, and absent key
  • Each test verifies policy propagation through to GitCloneTool._network_policy
  • Uses realistic YAML syntax with proper indentation

These tests directly validate the PR's objective of wiring RootConfig.git_clone to GitCloneTool.


98-105: LGTM!

The test_factory_tools_form_valid_registry test is a valuable integration check that verifies factory output can be wrapped in a ToolRegistry without errors, confirming compatibility with the existing tool infrastructure.

…try log

Avoid reusing TOOL_FACTORY_BUILT for both the DEBUG entry log in
build_default_tools_from_config and the INFO completion log in
build_default_tools — distinct event constants prevent confusion in
log aggregation and metrics.
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 17, 2026 11:35 — with GitHub Actions Inactive
@Aureliolo Aureliolo merged commit b7d8172 into main Mar 17, 2026
30 checks passed
@Aureliolo Aureliolo deleted the feat/wire-git-clone-config branch March 17, 2026 11:37
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 17, 2026 11:37 — with GitHub Actions Inactive
Aureliolo added a commit that referenced this pull request Mar 17, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.3.1](v0.3.0...v0.3.1)
(2026-03-17)


### Features

* **api:** RFC 9457 Phase 2 — ProblemDetail and content negotiation
([#496](#496))
([30f7c49](30f7c49))
* **cli:** verify container image signatures and SLSA provenance on pull
([#492](#492))
([bef272d](bef272d)),
closes [#491](#491)
* **engine:** implement context budget management in execution loops
([#520](#520))
([181eb8a](181eb8a)),
closes [#416](#416)
* implement settings persistence layer (DB-backed config)
([#495](#495))
([4bd99f7](4bd99f7)),
closes [#450](#450)
* **memory:** implement dual-mode archival in memory consolidation
([#524](#524))
([4603c9e](4603c9e)),
closes [#418](#418)
* migrate config consumers to read through SettingsService
([#510](#510))
([32f553d](32f553d))
* **settings:** implement settings change subscriptions for service
hot-reload ([#526](#526))
([53f908e](53f908e)),
closes [#503](#503)
* **settings:** register API config in SettingsService with 2-phase init
([#518](#518))
([29f7481](29f7481))
* **tools:** add SSRF prevention for git clone URLs
([#505](#505))
([492dd0d](492dd0d))
* **tools:** wire RootConfig.git_clone to GitCloneTool instantiation
([#519](#519))
([b7d8172](b7d8172))


### Bug Fixes

* **api:** replace JWT query parameter with one-time ticket for
WebSocket auth
([#493](#493))
([22a25f6](22a25f6)),
closes [#343](#343)


### Documentation

* add uv cache lock contention handling to worktree skill
([#500](#500))
([bd85a8d](bd85a8d))
* document RFC 9457 dual response formats in OpenAPI schema
([#506](#506))
([8dd2524](8dd2524))


### Maintenance

* upgrade jsdom from 28 to 29
([#499](#499))
([1ea2249](1ea2249))

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

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: wire RootConfig.git_clone to GitCloneTool instantiation

1 participant