Skip to content

feat: restructure builtin templates into inheritance tree#982

Merged
Aureliolo merged 9 commits intomainfrom
feat/template-inheritance-tree
Apr 1, 2026
Merged

feat: restructure builtin templates into inheritance tree#982
Aureliolo merged 9 commits intomainfrom
feat/template-inheritance-tree

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Restructure builtin templates into an inheritance tree: solo_founder -> startup -> dev_shop, product_team and research_lab -> data_team; agency, full_company, consultancy remain standalone
  • Add department _remove support (mirroring agent _remove) so child templates can remove inherited departments
  • Fix workflow config propagation during inheritance merge (was silently dropped)
  • Add _as_parent rendering mode to preserve merge_id when a template is rendered as a parent
  • Add post-merge agent name deduplication for auto-generated names
  • Extract inheritance functions into _inheritance.py to keep renderer.py under 800 lines

Test plan

  • uv run python -m pytest tests/unit/templates/ -n auto -v -- 459 tests covering all inheritance chains, dept _remove, standalone templates
  • uv run ruff check src/ tests/ -- passes
  • uv run mypy src/ tests/ -- passes
  • Verify each template renders: startup (5 agents), dev_shop (8), product_team (10), data_team (6)

Pre-reviewed by 7 agents, 12 findings addressed

Closes #725

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 1, 2026 19:47
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 1, 2026

Walkthrough

Adds a dedicated inheritance resolver (src/synthorg/templates/_inheritance.py) with resolve_inheritance and collect_parent_variables, enforces max depth/cycle checks, renders parents via a callback, merges configs, and deduplicates agent names. renderer.py delegates to this resolver and adds _as_parent/preserve-merge-id rendering paths. merge.py and schema.py introduce department _remove semantics and make workflow, workflow_handoffs, and escalation_paths replace-if-present. _render_helpers.py validates _remove usage with has_extends. Multiple builtin templates now use extends and added merge_ids; tests and docs updated accordingly.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: restructure builtin templates into inheritance tree' directly and clearly summarizes the main change—restructuring templates into an inheritance hierarchy.
Description check ✅ Passed The PR description is related to the changeset, providing a detailed summary of the restructuring, new features (department _remove, _as_parent mode, deduplication), and listing specific template changes.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #725: restructures templates into the specified tree (solo_founder->startup->(dev_shop, product_team); research_lab->data_team), adds merge_id to base agents, implements _remove for departments, fixes workflow propagation, and includes comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly related to template restructuring objectives: YAML template inheritance setup, merge/render logic updates to support removal and _as_parent rendering, comprehensive tests, and dependency-review.yml updates for license compliance.
Docstring Coverage ✅ Passed Docstring coverage is 69.23% which is sufficient. The required threshold is 40.00%.

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


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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 13 package(s) with unknown licenses.
See the Details below.

Snapshot Warnings

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

License Issues

uv.lock

PackageVersionLicenseIssue Type
hf-xet1.4.3NullUnknown License
importlib-metadata9.0.0NullUnknown License
mkdocstrings-python2.0.3NullUnknown License
openai2.30.0NullUnknown License
protobuf6.33.6NullUnknown License
pydantic-extra-types2.11.1NullUnknown License
pymdown-extensions10.21.2NullUnknown License
python-discovery1.2.1NullUnknown License
regex2026.3.32NullUnknown License
requests2.33.1NullUnknown License
sse-starlette3.3.4NullUnknown License
starlette1.0.0NullUnknown License
uv0.11.2NullUnknown License
Allowed Licenses: MIT, MIT-0, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, MPL-2.0, PSF-2.0, Unlicense, 0BSD, CC0-1.0, CC-BY-3.0, CC-BY-4.0, Python-2.0, Python-2.0.1, LicenseRef-scancode-free-unknown, LicenseRef-scancode-protobuf, LicenseRef-scancode-google-patent-license-golang, ZPL-2.1, LGPL-2.0-only, LGPL-2.0-or-later, LGPL-2.1-only, LGPL-2.1-or-later, LGPL-3.0-only, LGPL-3.0-or-later, BlueOak-1.0.0, OFL-1.1
Excluded from license check: pkg:pypi/mem0ai@1.0.9, pkg:pypi/numpy@2.4.4, pkg:pypi/qdrant-client@1.17.1, pkg:pypi/posthog@7.9.12, pkg:pypi/aiohttp@3.13.5, pkg:pypi/cyclonedx-python-lib@11.7.0, pkg:pypi/fsspec@2026.3.0, pkg:pypi/griffelib@2.0.2, pkg:pypi/grpcio@1.80.0, pkg:pypi/charset-normalizer@3.4.6, pkg:pypi/wrapt@2.1.2, pkg:npm/@img/sharp-wasm32@0.33.5, pkg:npm/@img/sharp-win32-ia32@0.33.5, pkg:npm/@img/sharp-win32-x64@0.33.5, pkg:golang/github.com/golangci/golangci-lint/v2@2.11.3, pkg:golang/github.com/denis-tingaikin/go-header@0.5.0, pkg:golang/github.com/ldez/structtags@0.6.1, pkg:golang/github.com/leonklingele/grouper@1.1.2, pkg:golang/github.com/xen0n/gosmopolitan@1.3.0, pkg:golang/github.com/alfatraining/structtag@1.0.0, pkg:golang/github.com/fatih/structtag@1.2.0, pkg:npm/json-schema-typed@8.0.2, pkg:npm/victory-vendor@37.3.6

OpenSSF Scorecard

Scorecard details
PackageVersionScoreDetails
pip/aiohttp 3.13.5 UnknownUnknown
pip/anyio 4.13.0 UnknownUnknown
pip/attrs 26.1.0 UnknownUnknown
pip/charset-normalizer 3.4.6 UnknownUnknown
pip/coverage 7.13.5 UnknownUnknown
pip/cyclonedx-python-lib 11.7.0 UnknownUnknown
pip/filelock 3.25.2 UnknownUnknown
pip/fsspec 2026.3.0 UnknownUnknown
pip/griffelib 2.0.2 UnknownUnknown
pip/grpcio 1.80.0 UnknownUnknown
pip/hf-xet 1.4.3 UnknownUnknown
pip/huggingface-hub 1.8.0 🟢 5.7
Details
CheckScoreReason
Code-Review🟢 7Found 23/29 approved changesets -- score normalized to 7
Maintained🟢 1030 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Security-Policy⚠️ 0security policy file not detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST🟢 9SAST tool is not run on all commits -- score normalized to 9
pip/identify 2.6.18 🟢 5.9
Details
CheckScoreReason
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 8Found 15/17 approved changesets -- score normalized to 8
Maintained🟢 1030 commit(s) and 7 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Security-Policy🟢 10security policy file detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/importlib-metadata 9.0.0 UnknownUnknown
pip/mkdocstrings-python 2.0.3 UnknownUnknown
pip/numpy 2.4.4 UnknownUnknown
pip/openai 2.30.0 UnknownUnknown
pip/platformdirs 4.9.4 UnknownUnknown
pip/protobuf 6.33.6 UnknownUnknown
pip/pydantic-extra-types 2.11.1 UnknownUnknown
pip/pymdown-extensions 10.21.2 UnknownUnknown
pip/python-discovery 1.2.1 UnknownUnknown
pip/python-dotenv 1.2.2 UnknownUnknown
pip/qdrant-client 1.17.1 UnknownUnknown
pip/regex 2026.3.32 UnknownUnknown
pip/requests 2.33.1 UnknownUnknown
pip/sse-starlette 3.3.4 UnknownUnknown
pip/starlette 1.0.0 UnknownUnknown
pip/tomli 2.4.1 UnknownUnknown
pip/uv 0.11.2 UnknownUnknown
pip/uvicorn 0.42.0 UnknownUnknown
pip/virtualenv 21.2.0 UnknownUnknown
pip/wrapt 2.1.2 UnknownUnknown
pip/yarl 1.23.0 🟢 6.4
Details
CheckScoreReason
Maintained🟢 78 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 7
Code-Review⚠️ 1Found 2/11 approved changesets -- score normalized to 1
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Fuzzing🟢 10project is fuzzed
License🟢 10license file detected
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection🟢 3branch protection is not maximal on development and all release branches
Signed-Releases🟢 85 out of the last 5 releases have a total of 5 signed artifacts.

Scanned Files

  • uv.lock

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 implements a robust template inheritance system, enabling templates to extend others, merge configurations, and explicitly remove inherited departments or agents using a new _remove directive. The changes include refactoring the inheritance logic into a dedicated module, updating the merge engine to handle workflow and department overrides, and updating several builtin templates to utilize these features. Review feedback correctly identified critical issues in the dev_shop.yaml and product_team.yaml templates, where agent removals and overrides would fail because the entries lacked the merge_id values necessary to match the definitions in the parent templates.

Comment on lines +93 to +98
- role: "Full-Stack Developer"
department: "engineering"
_remove: true
- role: "Full-Stack Developer"
department: "engineering"
_remove: true
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.

critical

The removal of Full-Stack Developer agents will fail because the parent template (startup) defines these agents with specific merge_id values (fullstack-senior and fullstack-mid). Since _agent_key includes the merge_id in the comparison, these removal entries must also specify the matching merge_id to successfully target the parent agents.

    - role: "Full-Stack Developer"
      merge_id: "fullstack-senior"
      department: "engineering"
      _remove: true
    - role: "Full-Stack Developer"
      merge_id: "fullstack-mid"
      department: "engineering"
      _remove: true

Comment on lines +103 to +113
# Override first Full-Stack Developer (positional): change personality
- role: "Full-Stack Developer"
name: ""
level: "senior"
model:
tier: "medium"
priority: "speed"
personality_preset: "strategic_planner"
department: "product"
- role: "UX Designer"
name: ""
level: "mid"
model: "medium"
personality_preset: "user_advocate"
department: "design"
- role: "UX Researcher"
name: ""
level: "mid"
model: "medium"
personality_preset: "methodical_analyst"
department: "design"
personality_preset: "communication_bridge"
department: "engineering"
# Remove second Full-Stack Developer (positional)
- role: "Full-Stack Developer"
department: "engineering"
_remove: true
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.

critical

The override and removal of Full-Stack Developer agents will fail to match the parent agents from startup because they are missing the required merge_id values (fullstack-senior and fullstack-mid). Without the merge_id, the merge engine treats these as different keys, resulting in duplicate agents or failed removals.

    # Override first Full-Stack Developer: change personality
    - role: "Full-Stack Developer"
      name: ""
      merge_id: "fullstack-senior"
      level: "senior"
      model: "medium"
      personality_preset: "communication_bridge"
      department: "engineering"
    # Remove second Full-Stack Developer
    - role: "Full-Stack Developer"
      merge_id: "fullstack-mid"
      department: "engineering"
      _remove: true

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR restructures the built-in company templates to actually use the existing template inheritance system (forming a small inheritance tree), while extending the inheritance/merge pipeline to support department removal, improved workflow field handling, and post-merge agent name deduplication.

Changes:

  • Reworked built-in YAML templates to use extends (e.g., solo_founder -> startup -> dev_shop/product_team, research_lab -> data_team) and added needed merge_ids on base agents.
  • Added department-level _remove support (schema + render validation + merge semantics) and extracted inheritance resolution into src/synthorg/templates/_inheritance.py.
  • Added tests covering the builtin inheritance chains and department removal behavior; updated docs to reflect new merge semantics.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/unit/templates/test_schema.py Adds schema tests for department _remove alias/default behavior.
tests/unit/templates/test_inheritance.py Adds unit + integration tests for department removal and updates variable collection import.
tests/unit/templates/test_builtin_inheritance.py New tests asserting builtin templates render correctly across inheritance chains.
tests/unit/templates/conftest.py Updates fixtures with merge_id and adds YAML fixtures for department removal tests.
src/synthorg/templates/schema.py Adds TemplateDepartmentConfig.remove (alias _remove) to support dept removal directives.
src/synthorg/templates/renderer.py Routes inheritance through new _inheritance.py and adds _as_parent mode to preserve merge_id for parent renders.
src/synthorg/templates/_render_helpers.py Adds _remove handling for departments and rejects _remove when no extends.
src/synthorg/templates/_inheritance.py New module extracting inheritance resolution + adds post-merge agent name deduplication and parent-variable collection.
src/synthorg/templates/merge.py Adds dept _remove behavior and includes workflow in replace-if-present inheritance merge fields.
src/synthorg/templates/builtins/solo_founder.yaml Adds merge_id to enable child targeting of the senior full-stack agent.
src/synthorg/templates/builtins/startup.yaml Converts to extends: solo_founder and overrides the inherited full-stack agent via merge_id.
src/synthorg/templates/builtins/dev_shop.yaml Converts to extends: startup and switches to removal/override deltas.
src/synthorg/templates/builtins/product_team.yaml Converts to extends: startup and uses dept/agent removals + additions.
src/synthorg/templates/builtins/data_team.yaml Converts to extends: research_lab and uses removals/overrides to form the data-focused subset.
docs/design/organization.md Documents dept _remove, workflow merge behavior, and post-merge agent name deduplication.
CLAUDE.md Updates templates directory description to mention inheritance tree.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +93 to +101
- role: "Full-Stack Developer"
department: "engineering"
_remove: true
- role: "Full-Stack Developer"
department: "engineering"
_remove: true
- role: "Product Manager"
department: "product"
_remove: true
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

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

The two _remove: true entries for Full-Stack Developer won't match the inherited agents from startup because those inherited agents have merge_ids (fullstack-senior / fullstack-mid). The merge key is (role, department, merge_id), so a child entry without merge_id has key (..., "") and will raise TemplateInheritanceError (no matching parent) or fail to remove anything. Add the appropriate merge_id to each removal entry (or remove merge_id from the parent agents, but then targeted overrides become ambiguous).

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +113
# Override first Full-Stack Developer (positional): change personality
- role: "Full-Stack Developer"
name: ""
level: "senior"
model:
tier: "medium"
priority: "speed"
personality_preset: "strategic_planner"
department: "product"
- role: "UX Designer"
name: ""
level: "mid"
model: "medium"
personality_preset: "user_advocate"
department: "design"
- role: "UX Researcher"
name: ""
level: "mid"
model: "medium"
personality_preset: "methodical_analyst"
department: "design"
personality_preset: "communication_bridge"
department: "engineering"
# Remove second Full-Stack Developer (positional)
- role: "Full-Stack Developer"
department: "engineering"
_remove: true
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

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

The Full-Stack Developer override/removal here is written as “positional”, but the inheritance merge matches agents by (role, department, merge_id). Since the inherited startup full-stack agents have merge_ids (fullstack-senior / fullstack-mid), the override entry (no merge_id) will be appended instead of overriding, and the _remove entry (no merge_id) will raise TemplateInheritanceError (no matching parent). Add the correct merge_id to both entries and update the comment to reflect merge-id based matching.

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 1, 2026

Codecov Report

❌ Patch coverage is 96.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.94%. Comparing base (43564a9) to head (727d8cf).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/synthorg/templates/_inheritance.py 93.22% 3 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #982      +/-   ##
==========================================
+ Coverage   91.91%   91.94%   +0.02%     
==========================================
  Files         637      638       +1     
  Lines       34521    34578      +57     
  Branches     3367     3377      +10     
==========================================
+ Hits        31730    31792      +62     
+ Misses       2196     2193       -3     
+ Partials      595      593       -2     

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

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
src/synthorg/templates/merge.py (1)

93-98: ⚠️ Potential issue | 🟠 Major

Parent workflow still gets overwritten when the child omits it.

This branch only inherits from parent when workflow is absent from child, but src/synthorg/templates/renderer.py always materializes a workflow dict from template defaults. A child template that leaves out workflow/workflow_config still replaces the parent workflow instead of inheriting it, so the propagation bug survives for omission-based inheritance. Please only emit workflow when the YAML actually defines it, or carry an explicit sentinel through merge.

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

In `@src/synthorg/templates/merge.py` around lines 93 - 98, The merge logic
currently treats a materialized-but-omitted workflow in child as an explicit
override; change the conditional in the loop over keys ("workflow",
"workflow_handoffs", "escalation_paths") so you only copy child[key] into result
when the child actually declared the field (e.g., check for an explicit-sentinel
like child.get("_explicit_fields") containing key or child.get("_explicit_" +
key) True) and child[key] is not None; otherwise deepcopy the parent value into
result. Ensure you preserve the deepcopy behavior and update the renderer to set
the chosen sentinel when a field is present in the original YAML so merge.py can
rely on it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/organization.md`:
- Around line 371-377: The docs currently contradict each other: the
`workflow_config` bullet says a child using `extends` must re-declare the full
`workflow_config` because the parent's config is not carried forward, but the
later change in this PR intends for `workflow_config` to propagate during
inheritance; update the `workflow_config` paragraph to match the implemented
behavior (i.e., describe that `workflow_config` is merged/inherited from the
parent unless overridden) and ensure its wording aligns with the existing rules
for `workflow`, `workflow_handoffs`, and `escalation_paths` (which state child
replaces entirely if present; otherwise inherits), referencing `extends`
semantics consistently.

In `@src/synthorg/templates/builtins/data_team.yaml`:
- Around line 93-97: The comment block listing inherited roles is misaligned and
triggers yamlint's comments-indentation; adjust the indentation of that entire
comment block so it lines up with the surrounding agents sequence items (i.e.,
align the "#" comment lines to the same indentation level as the "- Data
Engineer ..." list entries under agents) so yamlint no longer flags
comments-indentation in the agents section.

In `@src/synthorg/templates/renderer.py`:
- Around line 162-163: The current use of _preserve_merge_ids=_as_parent only
preserves merge_id during the immediate template expansion and loses it when
resolve_inheritance() merges parent templates; update resolve_inheritance() and
the merge path to thread a preserve_merge_ids flag through recursive inheritance
merging so merge_id is retained while traversing parents and only stripped on
the final non-parent render; modify callers that pass _preserve_merge_ids (e.g.,
the render/expand functions around _preserve_merge_ids=_as_parent and the code
paths at lines ~170-178) to forward the flag into resolve_inheritance(), ensure
merge logic respects preserve_merge_ids during intermediate merges, and perform
the final merge_id stripping only when preserve_merge_ids is false or at the
final render step.

In `@tests/unit/templates/test_builtin_inheritance.py`:
- Around line 44-282: Add regression tests in
tests/unit/templates/test_builtin_inheritance.py that exercise the two new
fragile inheritance paths: (1) a three-template chain that verifies a grandchild
inherits a parent's workflow when the intermediate parent omits it (cover the
"inheriting a parent's workflow by omission" case), and (2) a three-template
chain where an intermediate parent's agent is overridden/removed via merge_id
and ensure the grandchild reflects that removal (cover the "override/remove by
merge_id" case). Implement these as small pytest cases (similar style to
TestStartupExtendsSoloFounder and TestDevShopExtendsStartup) that render three
templates (e.g., "parent", "intermediate", "child") via _render and assert the
expected workflow presence/absence and agent list/roles (use _roles,
_dept_names, and merge_id-targeted agent lookups) so the tests fail if
inheritance rules regress.

---

Outside diff comments:
In `@src/synthorg/templates/merge.py`:
- Around line 93-98: The merge logic currently treats a materialized-but-omitted
workflow in child as an explicit override; change the conditional in the loop
over keys ("workflow", "workflow_handoffs", "escalation_paths") so you only copy
child[key] into result when the child actually declared the field (e.g., check
for an explicit-sentinel like child.get("_explicit_fields") containing key or
child.get("_explicit_" + key) True) and child[key] is not None; otherwise
deepcopy the parent value into result. Ensure you preserve the deepcopy behavior
and update the renderer to set the chosen sentinel when a field is present in
the original YAML so merge.py can rely on it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 106dc189-d5de-4e8c-b31c-3090bacb9bb4

📥 Commits

Reviewing files that changed from the base of the PR and between a854dcc and 325b318.

📒 Files selected for processing (16)
  • CLAUDE.md
  • docs/design/organization.md
  • src/synthorg/templates/_inheritance.py
  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/builtins/data_team.yaml
  • src/synthorg/templates/builtins/dev_shop.yaml
  • src/synthorg/templates/builtins/product_team.yaml
  • src/synthorg/templates/builtins/solo_founder.yaml
  • src/synthorg/templates/builtins/startup.yaml
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
  • src/synthorg/templates/schema.py
  • tests/unit/templates/conftest.py
  • tests/unit/templates/test_builtin_inheritance.py
  • tests/unit/templates/test_inheritance.py
  • tests/unit/templates/test_schema.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). (7)
  • GitHub Check: Agent
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Analyze (python)
  • GitHub Check: Dependency Review
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Python 3.14+ with PEP 649 native lazy annotations -- do NOT use from __future__ import annotations.
Use PEP 758 except syntax: except A, B: (no parentheses) -- ruff enforces this on Python 3.14.
Maximum line length is 88 characters (ruff enforced).

Files:

  • tests/unit/templates/test_schema.py
  • tests/unit/templates/test_inheritance.py
  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/schema.py
  • src/synthorg/templates/merge.py
  • tests/unit/templates/conftest.py
  • src/synthorg/templates/renderer.py
  • src/synthorg/templates/_inheritance.py
  • tests/unit/templates/test_builtin_inheritance.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use vendor-agnostic test names: test-provider, test-small-001, etc. in all Python tests.
Tests must use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow.
Minimum coverage is 80% (enforced in CI). Use pytest -m <marker> --cov=synthorg --cov-fail-under=80.
Use asyncio_mode = "auto" for async tests -- no manual @pytest.mark.asyncio needed.
Global test timeout is 30 seconds per test (do not add per-file markers; non-default overrides like timeout(60) are allowed).
Prefer @pytest.mark.parametrize for testing similar cases.
Use Hypothesis for property-based testing in Python with @given + @settings. Profiles: ci (50 examples, default) and dev (1000 examples). Run dev profile: HYPOTHESIS_PROFILE=dev uv run python -m pytest tests/ -m unit -n auto -k properties.
Never skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock time.monotonic() and asyncio.sleep(). For tasks that must block indefinitely, use asyncio.Event().wait() instead of asyncio.sleep(large_number).

Files:

  • tests/unit/templates/test_schema.py
  • tests/unit/templates/test_inheritance.py
  • tests/unit/templates/conftest.py
  • tests/unit/templates/test_builtin_inheritance.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.py: All public functions must have type hints; mypy strict mode enforced.
Docstrings must follow Google style and are required on public classes/functions (enforced by ruff D rules).
Use immutability: create new objects, never mutate existing ones. For non-Pydantic internal collections, use copy.deepcopy() at construction and MappingProxyType wrapping for read-only enforcement.
Use frozen Pydantic models for config/identity; separate mutable-via-copy models for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Adopt Pydantic v2 conventions: use allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields; use @computed_field for derived values instead of storing redundant fields; use NotBlankStr for all identifier/name fields.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code. Prefer structured concurrency over bare create_task.
Functions must be less than 50 lines, files must be less than 800 lines.
Handle errors explicitly, never silently swallow exceptions.
Validate at system boundaries (user input, external APIs, config files).
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001. Vendor names only in: (1) docs/design/operations.md, (2) .claude/ files, (3) third-party imports, (4) provider presets.

Files:

  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/schema.py
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
  • src/synthorg/templates/_inheritance.py
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Every module with business logic MUST have from synthorg.observability import get_logger then logger = get_logger(__name__).
Never use import logging, logging.getLogger(), or print() in application code. Exceptions: observability/setup.py, observability/sinks.py, observability/syslog_handler.py, observability/http_handler.py may use stdlib logging and stderr prints.
Always use variable name logger (not _logger, not log).
Use event name constants from synthorg.observability.events domain-specific modules, not hardcoded strings. Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Always use structured logging: logger.info(EVENT, key=value) -- never logger.info("msg %s", val).
All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and entry/exit of key functions.

Files:

  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/schema.py
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
  • src/synthorg/templates/_inheritance.py
🧠 Learnings (24)
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/templates/**/*.py : Templates: pre-built company templates, personality presets, and builder.

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Settings: Runtime-editable settings persistence (DB > env > YAML > code defaults), typed definitions (9 namespaces), Fernet encryption for sensitive values, config bridge, ConfigResolver (typed composed reads for controllers), validation, registry, change notifications via message bus. Per-namespace setting definitions in definitions/ submodule (api, company, providers, memory, budget, security, coordination, observability, backup).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Web dashboard: see `web/CLAUDE.md` for commands, design system, and component inventory

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality

Applied to files:

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

Applied to files:

  • src/synthorg/templates/builtins/data_team.yaml
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from `synthorg.observability.events.<domain>` modules (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly and use in structured logging

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Use event constants from `synthorg.observability.events.<domain>` (e.g., `API_REQUEST_STARTED` from `events.api`); import directly and log with structured kwargs: `logger.info(EVENT, key=value)`, never interpolated strings

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability package (observability/): structured logging, correlation tracking, log sinks; event constants organized by domain under observability/events/ (e.g., events.api, events.tool, events.git, events.context_budget, events.backup)

Applied to files:

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

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from synthorg.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : 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.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability includes structured logging via `get_logger(__name__)`, correlation tracking, and log sinks.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import logger via `from synthorg.observability import get_logger` and initialize with `logger = get_logger(__name__)`

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-04-01T18:29:59.468Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T18:29:59.468Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from the domain-specific module under `synthorg.observability.events` in logging calls

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget tracking includes pre-flight/in-flight checks, auto-downgrade, billing periods, cost tiers, quota/subscription. CFO includes anomaly detection, efficiency analysis, downgrade recommendations.

Applied to files:

  • src/synthorg/templates/builtins/dev_shop.yaml
🪛 YAMLlint (1.38.0)
src/synthorg/templates/builtins/data_team.yaml

[warning] 93-93: comment not indented like content

(comments-indentation)

🔇 Additional comments (7)
CLAUDE.md (1)

104-104: Good package-map update for templates subsystem.

Line 104 now reflects the inheritance-tree and merge-engine responsibilities clearly.

src/synthorg/templates/builtins/solo_founder.yaml (1)

59-59: merge_id addition is the right fix for deterministic inheritance targeting.

Line 59 gives child templates a stable key for override/remove operations.

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

227-238: Nice targeted schema coverage for department remove semantics.

Lines 227-238 correctly lock _remove alias mapping and the default False behavior.

src/synthorg/templates/schema.py (1)

229-233: Department _remove directive is modeled cleanly in schema.

Lines 229-233 align with the agent-side directive pattern and keep defaults safe.

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

138-227: Strong coverage expansion for department _remove behavior.

Lines 138-227 validate merge behavior, case-insensitive matching, and full-pipeline errors (without extends / missing parent) effectively.

src/synthorg/templates/_render_helpers.py (1)

128-151: Good explicit guardrail for invalid department _remove usage.

Line 139+ correctly fails fast when _remove is used without extends, instead of allowing a silent no-op.

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

230-288: Fixture additions are well-scoped for new inheritance/remove paths.

Lines 230-288 provide clear scenario coverage for successful department removal and expected failure modes.

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

♻️ Duplicate comments (2)
src/synthorg/templates/builtins/data_team.yaml (1)

70-97: 🧹 Nitpick | 🔵 Trivial

Align comment block indentation with agents sequence.

The comment block at lines 93-97 documenting inherited agents may trigger yamllint's comments-indentation warning. Align these comments to the same indentation level as the agent list entries above.

📝 Suggested fix
       department: "engineering"
-  # Inherited unchanged from research_lab:
-  # - Data Engineer (data_analytics)
-  # - Data Analyst [analyst-primary] (data_analytics)
-  # - Data Analyst [analyst-secondary] (data_analytics)
-  # - ML Engineer (data_analytics)
+    # Inherited unchanged from research_lab:
+    # - Data Engineer (data_analytics)
+    # - Data Analyst [analyst-primary] (data_analytics)
+    # - Data Analyst [analyst-secondary] (data_analytics)
+    # - ML Engineer (data_analytics)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/synthorg/templates/builtins/data_team.yaml` around lines 70 - 97, The
comment block "Inherited unchanged from research_lab:" is misaligned with the
surrounding agents list and can trigger yamllint comments-indentation; move and
indent that entire comment block so it lines up with the agent list entries
(same leading indentation as the "- role:" lines under the agents sequence),
i.e., add the same number of spaces before each "# -" comment line so the
comment sits at the same column as the agent items and preserves the comment
text exactly.
tests/unit/templates/test_builtin_inheritance.py (1)

44-257: 🧹 Nitpick | 🔵 Trivial

Add a three-template regression for _as_parent and workflow propagation.

These tests validate final counts and roles, but they still never exercise the two fragile paths introduced here: a grandchild inheriting the workflow path when the intermediate template omits it, and a merge_id-targeted override/remove surviving through the intermediate render. A regression in either _as_parent or the workflow propagation fix would still pass this suite.

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

In `@tests/unit/templates/test_builtin_inheritance.py` around lines 44 - 257, Add
a three-template regression that exercises _as_parent and workflow propagation:
create a chain of templates (grandparent -> parent -> child) where the parent
omits the workflow/path and the child relies on inheriting it from the
grandparent, then call _render("child") and assert the child's workflow/path is
present (verifying workflow propagation through an intermediate that omits it).
Also add a case where the parent performs a merge_id-targeted override or
removal on an agent defined in the grandparent and ensure that after
_render("child") the merge_id change persists (verifying merge_id-targeted
overrides survive the intermediate render); use existing helpers _render,
_as_parent, and reference merge_id and workflow symbols in the assertions.
🤖 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/templates/_inheritance.py`:
- Around line 78-80: Replace the runtime assert in _render_to_dict with an
explicit guard: check if loaded.template.extends is None and if so raise
TemplateInheritanceError with a clear message (include identifying information
like loaded.template.name or loaded.name) instead of relying on assert, then
assign parent_name: str = loaded.template.extends; this ensures a deterministic
error path when the caller contract is violated even under python -O.

In `@src/synthorg/templates/builtins/product_team.yaml`:
- Around line 103-113: The two Full-Stack Developer entries lack the merge key
so they won't match parent agents; add merge_id: "fullstack-senior" to the
override entry that sets personality_preset: "communication_bridge" (role:
"Full-Stack Developer", department: "engineering", level: "senior") so it
replaces the senior agent, and add merge_id: "fullstack-mid" to the removal
entry (role: "Full-Stack Developer", department: "engineering", _remove: true)
so it matches and removes the mid-level agent.

---

Duplicate comments:
In `@src/synthorg/templates/builtins/data_team.yaml`:
- Around line 70-97: The comment block "Inherited unchanged from research_lab:"
is misaligned with the surrounding agents list and can trigger yamllint
comments-indentation; move and indent that entire comment block so it lines up
with the agent list entries (same leading indentation as the "- role:" lines
under the agents sequence), i.e., add the same number of spaces before each "#
-" comment line so the comment sits at the same column as the agent items and
preserves the comment text exactly.

In `@tests/unit/templates/test_builtin_inheritance.py`:
- Around line 44-257: Add a three-template regression that exercises _as_parent
and workflow propagation: create a chain of templates (grandparent -> parent ->
child) where the parent omits the workflow/path and the child relies on
inheriting it from the grandparent, then call _render("child") and assert the
child's workflow/path is present (verifying workflow propagation through an
intermediate that omits it). Also add a case where the parent performs a
merge_id-targeted override or removal on an agent defined in the grandparent and
ensure that after _render("child") the merge_id change persists (verifying
merge_id-targeted overrides survive the intermediate render); use existing
helpers _render, _as_parent, and reference merge_id and workflow symbols in the
assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3e01efd1-9fda-4d66-a130-376bd896a2ab

📥 Commits

Reviewing files that changed from the base of the PR and between 325b318 and 052fdd1.

📒 Files selected for processing (12)
  • docs/design/organization.md
  • docs/guides/agents.md
  • docs/guides/company-config.md
  • src/synthorg/templates/_inheritance.py
  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/builtins/data_team.yaml
  • src/synthorg/templates/builtins/product_team.yaml
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
  • tests/unit/templates/test_builtin_inheritance.py
  • tests/unit/templates/test_inheritance.py
  • tests/unit/templates/test_renderer.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: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Python 3.14+ with PEP 649 native lazy annotations -- do NOT use from __future__ import annotations.
Use PEP 758 except syntax: except A, B: (no parentheses) -- ruff enforces this on Python 3.14.
Maximum line length is 88 characters (ruff enforced).

Files:

  • tests/unit/templates/test_renderer.py
  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
  • src/synthorg/templates/_inheritance.py
  • tests/unit/templates/test_inheritance.py
  • tests/unit/templates/test_builtin_inheritance.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use vendor-agnostic test names: test-provider, test-small-001, etc. in all Python tests.
Tests must use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow.
Minimum coverage is 80% (enforced in CI). Use pytest -m <marker> --cov=synthorg --cov-fail-under=80.
Use asyncio_mode = "auto" for async tests -- no manual @pytest.mark.asyncio needed.
Global test timeout is 30 seconds per test (do not add per-file markers; non-default overrides like timeout(60) are allowed).
Prefer @pytest.mark.parametrize for testing similar cases.
Use Hypothesis for property-based testing in Python with @given + @settings. Profiles: ci (50 examples, default) and dev (1000 examples). Run dev profile: HYPOTHESIS_PROFILE=dev uv run python -m pytest tests/ -m unit -n auto -k properties.
Never skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock time.monotonic() and asyncio.sleep(). For tasks that must block indefinitely, use asyncio.Event().wait() instead of asyncio.sleep(large_number).

Files:

  • tests/unit/templates/test_renderer.py
  • tests/unit/templates/test_inheritance.py
  • tests/unit/templates/test_builtin_inheritance.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.py: All public functions must have type hints; mypy strict mode enforced.
Docstrings must follow Google style and are required on public classes/functions (enforced by ruff D rules).
Use immutability: create new objects, never mutate existing ones. For non-Pydantic internal collections, use copy.deepcopy() at construction and MappingProxyType wrapping for read-only enforcement.
Use frozen Pydantic models for config/identity; separate mutable-via-copy models for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Adopt Pydantic v2 conventions: use allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields; use @computed_field for derived values instead of storing redundant fields; use NotBlankStr for all identifier/name fields.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code. Prefer structured concurrency over bare create_task.
Functions must be less than 50 lines, files must be less than 800 lines.
Handle errors explicitly, never silently swallow exceptions.
Validate at system boundaries (user input, external APIs, config files).
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001. Vendor names only in: (1) docs/design/operations.md, (2) .claude/ files, (3) third-party imports, (4) provider presets.

Files:

  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
  • src/synthorg/templates/_inheritance.py
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Every module with business logic MUST have from synthorg.observability import get_logger then logger = get_logger(__name__).
Never use import logging, logging.getLogger(), or print() in application code. Exceptions: observability/setup.py, observability/sinks.py, observability/syslog_handler.py, observability/http_handler.py may use stdlib logging and stderr prints.
Always use variable name logger (not _logger, not log).
Use event name constants from synthorg.observability.events domain-specific modules, not hardcoded strings. Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Always use structured logging: logger.info(EVENT, key=value) -- never logger.info("msg %s", val).
All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and entry/exit of key functions.

Files:

  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
  • src/synthorg/templates/_inheritance.py
🧠 Learnings (20)
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality

Applied to files:

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

Applied to files:

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

Applied to files:

  • src/synthorg/templates/builtins/data_team.yaml
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from `synthorg.observability.events.<domain>` modules (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly and use in structured logging

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Use event constants from `synthorg.observability.events.<domain>` (e.g., `API_REQUEST_STARTED` from `events.api`); import directly and log with structured kwargs: `logger.info(EVENT, key=value)`, never interpolated strings

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability package (observability/): structured logging, correlation tracking, log sinks; event constants organized by domain under observability/events/ (e.g., events.api, events.tool, events.git, events.context_budget, events.backup)

Applied to files:

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

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from synthorg.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : 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.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability includes structured logging via `get_logger(__name__)`, correlation tracking, and log sinks.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import logger via `from synthorg.observability import get_logger` and initialize with `logger = get_logger(__name__)`

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-04-01T18:29:59.468Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T18:29:59.468Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST have `from synthorg.observability import get_logger` then `logger = get_logger(__name__)`.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/**/*.py : Always use event name constants from the domain-specific module under `synthorg.observability.events` in logging calls

Applied to files:

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

Applied to files:

  • tests/unit/templates/test_inheritance.py
🪛 LanguageTool
docs/design/organization.md

[grammar] ~351-~351: Ensure spelling is correct
Context: ...d raises TemplateInheritanceError. Builtin inheritance tree: ``` solo_founder (...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (18)
src/synthorg/templates/_render_helpers.py (2)

128-150: LGTM! Clean validation helper for department removal.

The function correctly validates that _remove is only used with extends, logs appropriately at ERROR level before raising, and returns a minimal marker dict. The structured logging follows project conventions.


153-202: LGTM! Proper integration of _remove handling.

The has_extends parameter is correctly threaded through, and the early continue after handling _remove entries prevents invalid processing of removal markers through the normal budget/head parsing path.

docs/guides/company-config.md (1)

73-79: LGTM! Documentation updated to reflect inheritance-based agent counts.

The agent count ranges now reflect the expanded agent rosters from template inheritance (e.g., dev_shop extends startup and adds specialized roles). These match the values documented in docs/guides/agents.md.

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

645-661: LGTM! Test covers the preserve_merge_id parameter for parent rendering.

This test correctly validates that when preserve_merge_id=True is passed (simulating parent rendering via _as_parent), the merge_id is retained even when has_extends=False. This enables child templates to target parent agents by merge_id.

docs/guides/agents.md (1)

283-289: LGTM! Template table updated consistently with inheritance changes.

Agent counts and behavioral attributes (Autonomy, Communication) now match the actual template configurations after the inheritance restructuring. These values are consistent with docs/guides/company-config.md.

src/synthorg/templates/builtins/data_team.yaml (2)

21-21: LGTM! Clean inheritance declaration.

The extends: "research_lab" establishes the parent relationship correctly. The child template now only declares deltas (removals, overrides, additions) rather than duplicating all parent content.


46-67: LGTM! Department merge directives are well-structured.

The department section correctly:

  • Removes inherited product department using _remove: true
  • Overrides data_analytics with new head and reporting lines
  • Overrides engineering with Backend Developer as head

The budget allocations (65% + 35%) sum to 100%.

docs/design/organization.md (2)

351-363: LGTM! Clear inheritance tree documentation.

The builtin inheritance tree diagram accurately reflects the implemented structure:

  • solo_founderstartup → {dev_shop, product_team}
  • research_labdata_team
  • Standalone: agency, full_company, consultancy

Agent counts match the template definitions.


383-399: LGTM! Merge semantics documentation is accurate and complete.

The documented behaviors match the implementation:

  • Department _remove: true removes parent departments
  • workflow_config is consumed during rendering (not merged)
  • workflow, workflow_handoffs, escalation_paths follow replace-if-present semantics
  • Post-merge agent name deduplication with numeric suffix
src/synthorg/templates/merge.py (4)

27-27: LGTM! Separate strip keys for departments.

Using _DEPT_STRIP_KEYS (only _remove) separately from _STRIP_KEYS (which includes merge_id) is correct since departments don't use merge_id.


94-98: LGTM! Replace-if-present with deep copy prevents reference sharing.

The deep copy ensures that workflow fields from parent/child configs don't share references with the merged result, preventing accidental mutation of source data.


260-274: LGTM! Clean department removal and override logic.

The logic correctly handles three cases:

  1. _remove: true → skip parent dept, mark name as seen
  2. Override → use cleaned child version (strip _remove key)
  3. No match → copy parent dept

Adding to seen_names in the removal case prevents the department from being re-added by _collect_unmatched_child_depts.


283-311: LGTM! Error handling for invalid _remove targets.

The function correctly raises TemplateInheritanceError with structured logging when a child attempts to remove a non-existent parent department. This provides clear feedback for template authors.

src/synthorg/templates/renderer.py (5)

36-45: LGTM! Clean import reorganization.

The inheritance resolution is now delegated to _inheritance.py, keeping the renderer focused on Jinja2 rendering and config building. The import structure follows project conventions.


123-137: LGTM! _as_parent parameter enables merge_id preservation for parent rendering.

The parameter and its docstring clearly explain that this mode preserves merge_id on agents even when the template has no extends, allowing child templates to target parent agents by merge_id.


384-395: LGTM! Correct computation of preserve_merge flag.

The logic preserve_merge = has_extends or preserve_merge_ids correctly ensures that:

  1. Templates with extends always preserve merge_ids for the merge step
  2. Parent templates (rendered via _as_parent=True) preserve merge_ids even without extends

622-627: LGTM! Merge_id preservation logic is correct.

The condition if keep_merge and merge_id ensures that:

  • merge_id is preserved when inheritance is active OR when rendering as parent
  • Empty merge_id values are not added to the output (preventing empty string pollution)

170-178: Verified: _as_parent=True is correctly threaded through the callback for parent rendering.

The _render_to_dict callback accepts the _as_parent parameter (default False), and when invoked for parent templates in _render_and_merge_parent, it is called with _as_parent=True. This parameter is passed to _build_config_dict as preserve_merge_ids=_as_parent, ensuring merge_id values survive through multi-level inheritance chains as intended.

Comment on lines +103 to +113
# Override first Full-Stack Developer (matched by role+department): change personality
- role: "Full-Stack Developer"
name: ""
level: "senior"
model:
tier: "medium"
priority: "speed"
personality_preset: "strategic_planner"
department: "product"
- role: "UX Designer"
name: ""
level: "mid"
model: "medium"
personality_preset: "user_advocate"
department: "design"
- role: "UX Researcher"
name: ""
level: "mid"
model: "medium"
personality_preset: "methodical_analyst"
department: "design"
personality_preset: "communication_bridge"
department: "engineering"
# Remove second Full-Stack Developer (matched by role+department)
- role: "Full-Stack Developer"
department: "engineering"
_remove: 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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -i '^startup\.yaml$' | while read -r file; do
  echo "== $file =="
  rg -n -C2 'Full-Stack Developer|merge_id' "$file"
done

Repository: Aureliolo/synthorg

Length of output: 862


🏁 Script executed:

sed -n '100,120p' src/synthorg/templates/builtins/product_team.yaml | cat -n

Repository: Aureliolo/synthorg

Length of output: 895


🏁 Script executed:

sed -n '104,147p' src/synthorg/templates/merge.py | cat -n

Repository: Aureliolo/synthorg

Length of output: 2048


🏁 Script executed:

rg -n '_agent_key' src/synthorg/templates/merge.py -A 5

Repository: Aureliolo/synthorg

Length of output: 760


🏁 Script executed:

sed -n '314,340p' src/synthorg/templates/merge.py | cat -n

Repository: Aureliolo/synthorg

Length of output: 1017


Add merge_id to match the inherited Full-Stack Developer agents.

These entries have no merge_id, so they cannot match the parent's agents which have merge_id: "fullstack-senior" and merge_id: "fullstack-mid". The merge key is (role, department, merge_id), so missing merge_id defaults to "", creating mismatched keys.

  • The override entry (line 105) will be appended instead of replacing the senior agent.
  • The _remove entry (line 112) will fail with TemplateInheritanceError since no parent agent matches the key.

Add merge_id: "fullstack-senior" to the first entry and merge_id: "fullstack-mid" to the second.

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

In `@src/synthorg/templates/builtins/product_team.yaml` around lines 103 - 113,
The two Full-Stack Developer entries lack the merge key so they won't match
parent agents; add merge_id: "fullstack-senior" to the override entry that sets
personality_preset: "communication_bridge" (role: "Full-Stack Developer",
department: "engineering", level: "senior") so it replaces the senior agent, and
add merge_id: "fullstack-mid" to the removal entry (role: "Full-Stack
Developer", department: "engineering", _remove: true) so it matches and removes
the mid-level agent.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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/templates/_inheritance.py`:
- Around line 78-83: The branch in resolve_inheritance that raises
TemplateInheritanceError when loaded.template.extends is None lacks a logged
WARNING/ERROR; before raising, emit a structured log (e.g., logger.warning or
logger.error) that includes the template identity and context (use
loaded.source_name and indicate resolve_inheritance was called despite no
'extends') so observers can track the invalid caller; then raise
TemplateInheritanceError as before.
- Line 8: The code currently uses dict(child_vars) which only shallow-copies the
mapping and allows nested lists/dicts in child_vars to be shared and mutated by
parent layering; change the shallow copy to a deep copy (use
copy.deepcopy(child_vars)) when preparing the child context in the inheritance
logic (replace dict(child_vars) with copy.deepcopy(child_vars) in the places
where child_vars is cloned, including the occurrences around the inheritance
layering and the block referenced at lines ~226-229), and then wrap the
resulting mapping in MappingProxyType to enforce read-only access for downstream
code; also add the necessary imports (import copy and from types import
MappingProxyType) and ensure any tests that expect immutability still pass.
- Around line 48-114: The resolve_inheritance function is too large and mixes
validation, orchestration, rendering and post-merge normalization; split one
stage into a private helper to reduce its length under 50 lines. Extract either
validation (the call to _validate_inheritance_chain), parent rendering/merge
orchestration (the _render_and_merge_parent call and its args) or post-merge
normalization (the _deduplicate_merged_agent_names call) into a new private
function (e.g., _prepare_parent_merge or _finalize_merged_config) and update
resolve_inheritance to delegate to that helper while keeping calls to logger,
child_id/parent_name setup, and exception behavior unchanged so
resolve_inheritance now only coordinates logging, calls the new helper, and
returns the merged dict.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d7d700f9-c268-48ff-b354-b18513e7fe57

📥 Commits

Reviewing files that changed from the base of the PR and between 052fdd1 and 8ff1ab7.

📒 Files selected for processing (2)
  • src/synthorg/templates/_inheritance.py
  • tests/unit/templates/test_builtin_inheritance.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: Test (Python 3.14)
  • GitHub Check: Build Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Python 3.14+ with PEP 649 native lazy annotations -- do NOT use from __future__ import annotations.
Use PEP 758 except syntax: except A, B: (no parentheses) -- ruff enforces this on Python 3.14.
Maximum line length is 88 characters (ruff enforced).

Files:

  • src/synthorg/templates/_inheritance.py
  • tests/unit/templates/test_builtin_inheritance.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.py: All public functions must have type hints; mypy strict mode enforced.
Docstrings must follow Google style and are required on public classes/functions (enforced by ruff D rules).
Use immutability: create new objects, never mutate existing ones. For non-Pydantic internal collections, use copy.deepcopy() at construction and MappingProxyType wrapping for read-only enforcement.
Use frozen Pydantic models for config/identity; separate mutable-via-copy models for runtime state that evolves. Never mix static config fields with mutable runtime fields in one model.
Adopt Pydantic v2 conventions: use allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields; use @computed_field for derived values instead of storing redundant fields; use NotBlankStr for all identifier/name fields.
Prefer asyncio.TaskGroup for fan-out/fan-in parallel operations in new code. Prefer structured concurrency over bare create_task.
Functions must be less than 50 lines, files must be less than 800 lines.
Handle errors explicitly, never silently swallow exceptions.
Validate at system boundaries (user input, external APIs, config files).
Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names: example-provider, example-large-001, example-medium-001, example-small-001. Vendor names only in: (1) docs/design/operations.md, (2) .claude/ files, (3) third-party imports, (4) provider presets.

Files:

  • src/synthorg/templates/_inheritance.py
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Every module with business logic MUST have from synthorg.observability import get_logger then logger = get_logger(__name__).
Never use import logging, logging.getLogger(), or print() in application code. Exceptions: observability/setup.py, observability/sinks.py, observability/syslog_handler.py, observability/http_handler.py may use stdlib logging and stderr prints.
Always use variable name logger (not _logger, not log).
Use event name constants from synthorg.observability.events domain-specific modules, not hardcoded strings. Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Always use structured logging: logger.info(EVENT, key=value) -- never logger.info("msg %s", val).
All error paths must log at WARNING or ERROR with context before raising. All state transitions must log at INFO. DEBUG for object creation, internal flow, and entry/exit of key functions.

Files:

  • src/synthorg/templates/_inheritance.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use vendor-agnostic test names: test-provider, test-small-001, etc. in all Python tests.
Tests must use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow.
Minimum coverage is 80% (enforced in CI). Use pytest -m <marker> --cov=synthorg --cov-fail-under=80.
Use asyncio_mode = "auto" for async tests -- no manual @pytest.mark.asyncio needed.
Global test timeout is 30 seconds per test (do not add per-file markers; non-default overrides like timeout(60) are allowed).
Prefer @pytest.mark.parametrize for testing similar cases.
Use Hypothesis for property-based testing in Python with @given + @settings. Profiles: ci (50 examples, default) and dev (1000 examples). Run dev profile: HYPOTHESIS_PROFILE=dev uv run python -m pytest tests/ -m unit -n auto -k properties.
Never skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock time.monotonic() and asyncio.sleep(). For tasks that must block indefinitely, use asyncio.Event().wait() instead of asyncio.sleep(large_number).

Files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • src/synthorg/templates/_inheritance.py
🔇 Additional comments (1)
tests/unit/templates/test_builtin_inheritance.py (1)

295-343: Nice regression coverage for the three-level chain.

These cases pin the workflow isolation, grandparent removal, and chained override behavior that this PR is touching, so future inheritance refactors should fail loudly.

Extracted from ``renderer.py`` to keep file sizes under 800 lines.
"""

from typing import TYPE_CHECKING, Any, Protocol
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

Deep-copy child_vars before layering parent defaults.

dict(child_vars) only clones the top-level mapping. Nested lists/dicts stay shared across inheritance levels, so any mutation during parent rendering can leak back into the child pass.

Suggested fix
+import copy
 from typing import TYPE_CHECKING, Any, Protocol
@@
-    result: dict[str, Any] = dict(child_vars)
+    result: dict[str, Any] = copy.deepcopy(child_vars)
As per coding guidelines "Use immutability: create new objects, never mutate existing ones. For non-Pydantic internal collections, use `copy.deepcopy()` at construction and `MappingProxyType` wrapping for read-only enforcement."

Also applies to: 226-229

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

In `@src/synthorg/templates/_inheritance.py` at line 8, The code currently uses
dict(child_vars) which only shallow-copies the mapping and allows nested
lists/dicts in child_vars to be shared and mutated by parent layering; change
the shallow copy to a deep copy (use copy.deepcopy(child_vars)) when preparing
the child context in the inheritance logic (replace dict(child_vars) with
copy.deepcopy(child_vars) in the places where child_vars is cloned, including
the occurrences around the inheritance layering and the block referenced at
lines ~226-229), and then wrap the resulting mapping in MappingProxyType to
enforce read-only access for downstream code; also add the necessary imports
(import copy and from types import MappingProxyType) and ensure any tests that
expect immutability still pass.

Aureliolo and others added 6 commits April 1, 2026 22:58
Restructure builtin templates to use extends, creating an inheritance
tree that reduces duplication and shows the natural scaling path:
- solo_founder -> startup -> dev_shop, product_team
- research_lab -> data_team
- agency, full_company, consultancy remain standalone

Add department _remove support (mirroring agent _remove) so child
templates can remove inherited departments. Fix workflow config
propagation during inheritance merge. Add _as_parent rendering mode
to preserve merge_ids when a template is rendered as a parent, and
post-merge agent name deduplication for auto-generated names.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract inheritance functions into _inheritance.py to bring renderer.py
under 800 lines. Extract dept merge/render helpers to keep functions
under 50 lines. Add _DEPT_STRIP_KEYS constant for consistency with
agent stripping. Simplify preserve_merge_id from bool|None to bool.
Update merge docstring and design spec for workflow field propagation
and post-merge name deduplication. Add missing docstrings.

Pre-reviewed by 7 agents, 12 findings addressed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Source fixes:
- Replace render_to_dict_fn: Any with Protocol type
- Fix empty-name dedup to skip nameless agents
- Fix _handle_dept_remove log level WARNING -> ERROR
- Normalize _preserve_merge_ids underscore prefix
- Add Returns section to _expand_single_agent docstring
- Fix collect_parent_variables docstring wording
- Refactor _append_unmatched_child_depts to return list
- Fix "backwards compatibility" -> "as the default" in docstring

YAML fixes:
- Fix "positional" comments in product_team.yaml
- Fix yamlint comment indentation in data_team.yaml

Docs fixes:
- Clarify workflow_config vs workflow merge semantics
- Add builtin inheritance tree diagram
- Fix Engineering Squad size 5-10 -> 6-10
- Update stale agent counts in guides

Test fixes:
- Add 7 tests for _deduplicate_merged_agent_names
- Add 4 tests for workflow merge during inheritance
- Add test for preserve_merge_id without extends
- Add 3 tests for nameless department merge
- Fix weak >= 1 assertion to specific count
- Rename TestInheritanceIntegration -> TestInheritanceFullPipeline
- Split full_company into own test class with behavioral check

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

- Replace `assert loaded.template.extends is not None` with an explicit
  TemplateInheritanceError guard that survives python -O
- Add TestThreeLevelInheritanceRegression: 3 tests verifying workflow
  config isolation, grandparent agent removal, and override chaining
  across the solo_founder -> startup -> dev_shop/product_team chain

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo force-pushed the feat/template-inheritance-tree branch from 8ff1ab7 to 8aefe19 Compare April 1, 2026 21:01
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 1, 2026 21:02 — with GitHub Actions Inactive
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/synthorg/templates/builtins/product_team.yaml (1)

103-113: ⚠️ Potential issue | 🔴 Critical

Add merge_id to Full-Stack Developer entries to match parent agents.

This is the same issue flagged in the past review comment. The override entry (lines 104-109) and the _remove entry (lines 111-113) lack merge_id. Per src/synthorg/templates/builtins/startup.yaml:68-103, the parent's Full-Stack Developers have merge_id: "fullstack-senior" and merge_id: "fullstack-mid".

Without merge_id:

  • The override entry will be appended instead of replacing the senior agent
  • The _remove entry will fail with TemplateInheritanceError
🐛 Proposed fix
     # Override first Full-Stack Developer (matched by role+department): change personality
     - role: "Full-Stack Developer"
       name: ""
+      merge_id: "fullstack-senior"
       level: "senior"
       model: "medium"
       personality_preset: "communication_bridge"
       department: "engineering"
     # Remove second Full-Stack Developer (matched by role+department)
     - role: "Full-Stack Developer"
+      merge_id: "fullstack-mid"
       department: "engineering"
       _remove: true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/synthorg/templates/builtins/product_team.yaml` around lines 103 - 113,
The two Full-Stack Developer override entries are missing merge_id so they won't
match parent agents; add merge_id: "fullstack-senior" to the override entry that
sets personality_preset: "communication_bridge" (so it replaces the senior agent
instead of appending) and add merge_id: "fullstack-mid" to the entry with
_remove: true (so the removal matches the mid-level parent), keeping the rest of
the fields unchanged.
src/synthorg/templates/_inheritance.py (1)

232-232: ⚠️ Potential issue | 🟠 Major

Shallow copy allows nested mutation leakage.

dict(child_vars) only clones the top-level mapping. If child_vars contains nested dicts or lists (e.g., complex variable defaults), those remain shared references and any mutation during parent rendering can leak back into the child pass.

🛡️ Proposed fix
+import copy
 from typing import TYPE_CHECKING, Any, Protocol
-    result: dict[str, Any] = dict(child_vars)
+    result: dict[str, Any] = copy.deepcopy(child_vars)

Based on learnings: "Use copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization) for dict/list fields."

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

In `@src/synthorg/templates/_inheritance.py` at line 232, Replace the shallow copy
operation that creates result from child_vars with a deep copy to prevent nested
mutation leakage: import the copy module and change the construction of result
(currently using dict(child_vars)) to use copy.deepcopy(child_vars) so nested
dicts/lists are fully cloned; ensure the copy import is added near other imports
and keep the result variable type annotation (result: dict[str, Any]) intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/organization.md`:
- Line 351: The heading text "Builtin inheritance tree:" uses inconsistent
spelling; change it to "Built-in inheritance tree:" to match surrounding docs
and standard terminology, updating the exact string "Builtin inheritance tree:"
in the document to "Built-in inheritance tree:".

In `@src/synthorg/templates/builtins/dev_shop.yaml`:
- Around line 93-98: The two removal entries for role "Full-Stack Developer"
with department "engineering" in dev_shop.yaml are missing merge_id and
therefore won't match parent agents; update those two entries to include
merge_id: "fullstack-senior" and merge_id: "fullstack-mid" respectively so the
(role, department, merge_id) key matches the parent Full-Stack Developer agents
defined in startup.yaml.

---

Duplicate comments:
In `@src/synthorg/templates/_inheritance.py`:
- Line 232: Replace the shallow copy operation that creates result from
child_vars with a deep copy to prevent nested mutation leakage: import the copy
module and change the construction of result (currently using dict(child_vars))
to use copy.deepcopy(child_vars) so nested dicts/lists are fully cloned; ensure
the copy import is added near other imports and keep the result variable type
annotation (result: dict[str, Any]) intact.

In `@src/synthorg/templates/builtins/product_team.yaml`:
- Around line 103-113: The two Full-Stack Developer override entries are missing
merge_id so they won't match parent agents; add merge_id: "fullstack-senior" to
the override entry that sets personality_preset: "communication_bridge" (so it
replaces the senior agent instead of appending) and add merge_id:
"fullstack-mid" to the entry with _remove: true (so the removal matches the
mid-level parent), keeping the rest of the fields 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 88af95b2-dc4c-4720-945c-f4341e9cdc93

📥 Commits

Reviewing files that changed from the base of the PR and between 8ff1ab7 and 8aefe19.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (19)
  • CLAUDE.md
  • docs/design/organization.md
  • docs/guides/agents.md
  • docs/guides/company-config.md
  • src/synthorg/templates/_inheritance.py
  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/builtins/data_team.yaml
  • src/synthorg/templates/builtins/dev_shop.yaml
  • src/synthorg/templates/builtins/product_team.yaml
  • src/synthorg/templates/builtins/solo_founder.yaml
  • src/synthorg/templates/builtins/startup.yaml
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
  • src/synthorg/templates/schema.py
  • tests/unit/templates/conftest.py
  • tests/unit/templates/test_builtin_inheritance.py
  • tests/unit/templates/test_inheritance.py
  • tests/unit/templates/test_renderer.py
  • tests/unit/templates/test_schema.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: Test (Python 3.14)
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Python version requirement: Python 3.14+ with PEP 649 native lazy annotations
No from __future__ import annotations -- Python 3.14 has PEP 649

Files:

  • src/synthorg/templates/schema.py
  • tests/unit/templates/test_schema.py
  • src/synthorg/templates/_render_helpers.py
  • tests/unit/templates/conftest.py
  • src/synthorg/templates/_inheritance.py
  • tests/unit/templates/test_inheritance.py
  • tests/unit/templates/test_renderer.py
  • src/synthorg/templates/merge.py
  • tests/unit/templates/test_builtin_inheritance.py
  • src/synthorg/templates/renderer.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use PEP 758 except syntax: except A, B: (no parentheses) -- ruff enforces this on Python 3.14

Files:

  • src/synthorg/templates/schema.py
  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/_inheritance.py
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
src/synthorg/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/synthorg/**/*.py: Type hints required on all public functions, mypy strict mode
Docstrings in Google style, required on all public classes and functions -- enforced by ruff D rules
Every module with business logic MUST import logger via from synthorg.observability import get_logger and assign logger = get_logger(__name__)
Use constants from domain-specific modules under synthorg.observability.events for all event names (e.g., API_REQUEST_STARTED from events.api, TOOL_INVOKE_START from events.tool) -- import directly
Always use structured logging: logger.info(EVENT, key=value) -- never logger.info("msg %s", val)
All error paths must log at WARNING or ERROR with context before raising
All state transitions must log at INFO
Use Pydantic v2 with BaseModel, model_validator, computed_field, ConfigDict
Use allow_inf_nan=False in all ConfigDict declarations to reject NaN/Inf in numeric fields at validation time
Use @computed_field for derived values instead of storing and validating redundant fields (e.g., TokenUsage.total_tokens)
Use NotBlankStr from core.types for all identifier/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 (e.g., multiple tool invocations, parallel agent calls) over bare create_task
Line length: 88 characters, enforced by ruff
Functions must be less than 50 lines
Files must be less than 800 lines
Handle errors explicitly, never silently swallow errors
Validate at system boundaries: user input, external APIs, config files
Create new objects and never mutate existing ones -- immutability pattern. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.
For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM pro...

Files:

  • src/synthorg/templates/schema.py
  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/_inheritance.py
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
src/synthorg/!(observability)/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Never use import logging / logging.getLogger() / print() in application code -- exceptions: observability/setup.py, observability/sinks.py, observability/syslog_handler.py, and observability/http_handler.py may use stdlib logging and print for handler construction and bootstrap

Files:

  • src/synthorg/templates/schema.py
  • src/synthorg/templates/_render_helpers.py
  • src/synthorg/templates/_inheritance.py
  • src/synthorg/templates/merge.py
  • src/synthorg/templates/renderer.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use test markers @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow for test organization
Prefer @pytest.mark.parametrize for testing similar cases in test files
Never use real vendor names in test code -- use test-provider, test-small-001, etc.
Never skip, dismiss, or ignore flaky tests -- always fix them fully and fundamentally. For timing-sensitive tests, mock time.monotonic() and asyncio.sleep() to make them deterministic. For tasks that must block indefinitely until cancelled, use asyncio.Event().wait() instead of asyncio.sleep(large_number) for cancellation-safety.

Files:

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

Applied to files:

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

Applied to files:

  • CLAUDE.md
  • docs/guides/agents.md
  • src/synthorg/templates/builtins/product_team.yaml
  • src/synthorg/templates/_inheritance.py
  • tests/unit/templates/test_inheritance.py
  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to {docs/design/operations.md,src/synthorg/providers/presets.py,.claude/**/*.{md,yml,yaml}} : Vendor names may appear only in: (1) Operations design page, (2) `.claude/` skill/agent files, (3) third-party import paths, (4) provider presets (`src/synthorg/providers/presets.py`), (5) tests using `test-provider`, `test-small-001`, etc.

Applied to files:

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

Applied to files:

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

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Settings: Runtime-editable settings persistence (DB > env > YAML > code defaults), typed definitions (9 namespaces), Fernet encryption for sensitive values, config bridge, ConfigResolver (typed composed reads for controllers), validation, registry, change notifications via message bus. Per-namespace setting definitions in definitions/ submodule (api, company, providers, memory, budget, security, coordination, observability, backup).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Web dashboard: see `web/CLAUDE.md` for commands, design system, and component inventory

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • src/synthorg/templates/builtins/data_team.yaml
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/budget/**/*.py : Budget tracking includes pre-flight/in-flight checks, auto-downgrade, billing periods, cost tiers, quota/subscription. CFO includes anomaly detection, efficiency analysis, downgrade recommendations.

Applied to files:

  • src/synthorg/templates/builtins/dev_shop.yaml
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality

Applied to files:

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

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-04-01T20:43:15.699Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T20:43:15.699Z
Learning: Applies to src/synthorg/**/*.py : Handle errors explicitly, never silently swallow errors

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to src/synthorg/**/*.py : Use `copy.deepcopy()` at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization) for `dict`/`list` fields

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to **/*.py : Use `copy.deepcopy()` at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization) for dict/list fields in frozen Pydantic models

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to **/*.py : Use `copy.deepcopy()` at construction and `MappingProxyType` wrapping for read-only enforcement in non-Pydantic internal collections (registries, BaseTool)

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to src/synthorg/**/*.py : For non-Pydantic internal collections (registries, `BaseTool`), use `copy.deepcopy()` at construction and wrap with `MappingProxyType` for read-only enforcement

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-04-01T20:43:15.699Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T20:43:15.699Z
Learning: Applies to src/synthorg/**/*.py : For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, persistence serialization)

Applied to files:

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

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-20T21:44:04.528Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T21:44:04.528Z
Learning: Applies to **/*.py : Immutability: create new objects, never mutate existing ones. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-04-01T20:43:15.699Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T20:43:15.699Z
Learning: Applies to src/synthorg/**/*.py : Create new objects and never mutate existing ones -- immutability pattern. For non-Pydantic internal collections (registries, BaseTool), use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement.

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-16T23:05:29.577Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T23:05:29.577Z
Learning: Applies to **/*.py : For dict/list fields in frozen Pydantic models, rely on frozen=True for field reassignment prevention and copy.deepcopy() at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-04-01T20:43:15.699Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T20:43:15.699Z
Learning: Applies to src/synthorg/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (model_copy(update=...)) for runtime state that evolves (e.g., agent execution state, task progress). Never mix static config fields with mutable runtime fields in one model.

Applied to files:

  • src/synthorg/templates/_inheritance.py
  • src/synthorg/templates/renderer.py
📚 Learning: 2026-04-01T20:43:15.699Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T20:43:15.699Z
Learning: Applies to src/synthorg/**/*.py : Functions must be less than 50 lines

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to {**/*.py,web/src/**/*.{ts,tsx}} : Keep functions under 50 lines and files under 800 lines

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-04-01T20:43:15.699Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T20:43:15.699Z
Learning: Applies to src/synthorg/**/*.py : Files must be less than 800 lines

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-16T07:22:28.134Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T07:22:28.134Z
Learning: Applies to **/*.py : Functions must be less than 50 lines; files must be less than 800 lines

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-04-01T20:43:15.699Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T20:43:15.699Z
Learning: Applies to src/synthorg/**/*.py : Line length: 88 characters, enforced by ruff

Applied to files:

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

Applied to files:

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

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-14T16:18:57.267Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T16:18:57.267Z
Learning: Applies to src/ai_company/!(observability)/**/*.py : All error paths must log at WARNING or ERROR with context before raising.

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • src/synthorg/templates/_inheritance.py
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from `synthorg.observability.events.<domain>` modules (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`); import directly and use in structured logging

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Use event constants from `synthorg.observability.events.<domain>` (e.g., `API_REQUEST_STARTED` from `events.api`); import directly and log with structured kwargs: `logger.info(EVENT, key=value)`, never interpolated strings

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability package (observability/): structured logging, correlation tracking, log sinks; event constants organized by domain under observability/events/ (e.g., events.api, events.tool, events.git, events.context_budget, events.backup)

Applied to files:

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

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-04-01T20:43:15.699Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T20:43:15.699Z
Learning: Applies to src/synthorg/**/*.py : Use constants from domain-specific modules under `synthorg.observability.events` for all event names (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`) -- import directly

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-04-01T20:43:15.699Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-01T20:43:15.699Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic MUST import logger via `from synthorg.observability import get_logger` and assign `logger = get_logger(__name__)`

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : Use event name constants from synthorg.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider). Import directly: from synthorg.observability.events.<domain> import EVENT_CONSTANT.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-15T19:14:27.144Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T19:14:27.144Z
Learning: Applies to src/synthorg/**/*.py : 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.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-17T06:30:14.180Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T06:30:14.180Z
Learning: Applies to src/synthorg/observability/**/*.py : Observability includes structured logging via `get_logger(__name__)`, correlation tracking, and log sinks.

Applied to files:

  • src/synthorg/templates/renderer.py
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to src/synthorg/**/*.py : Every module with business logic must import logger via `from synthorg.observability import get_logger` and initialize with `logger = get_logger(__name__)`

Applied to files:

  • src/synthorg/templates/renderer.py
🪛 LanguageTool
docs/design/organization.md

[grammar] ~351-~351: Ensure spelling is correct
Context: ...d raises TemplateInheritanceError. Builtin inheritance tree: ``` solo_founder (...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (26)
src/synthorg/templates/_render_helpers.py (2)

128-150: LGTM!

The _handle_dept_remove function correctly validates that _remove is only used with extends, logs at ERROR level before raising (per guidelines), and returns a minimal marker dict for the merge phase.


153-202: LGTM!

The build_departments function properly:

  • Accepts the new has_extends keyword-only parameter
  • Short-circuits _remove entries to skip budget/head parsing
  • Forwards has_extends to _handle_dept_remove for validation

The implementation aligns with the relevant code snippet from renderer.py:383-395 which shows the caller correctly passing has_extends=has_extends.

src/synthorg/templates/builtins/data_team.yaml (3)

21-21: LGTM on the inheritance structure and workflow configuration.

The template correctly:

  • Extends research_lab as per the PR objectives (solo_founder → startup → {dev_shop, product_team}; research_lab → data_team)
  • Sets workflow and communication at the template level
  • Documents inherited agents in comments for clarity

Also applies to: 42-43, 93-97


46-48: No issues identified.

The product department exists in research_lab.yaml (line 63), so the removal in data_team.yaml is valid and will not cause a TemplateInheritanceError.

			> Likely an incorrect or invalid review comment.

74-76: Remove this comment — the assumption is incorrect.

The research_lab.yaml file does have a product department, and it includes a Technical Writer as the head_role (line 65 in research_lab.yaml). The removal entry in data_team.yaml will succeed in removing the inherited Technical Writer from the product department.

			> Likely an incorrect or invalid review comment.
tests/unit/templates/conftest.py (2)

137-137: LGTM!

Adding merge_id: "fullstack-senior" to both override and remove fixtures ensures the child entries correctly match the parent's Full-Stack Developer agent (which has the same merge_id in solo_founder.yaml). This aligns with the merge logic that uses (role, department, merge_id) as the matching key.

Also applies to: 159-159


230-288: LGTM!

The three new YAML fixtures provide comprehensive test coverage for department _remove behavior:

  • CHILD_REMOVE_DEPARTMENT_YAML: Valid removal via inheritance
  • CHILD_REMOVE_NONEXISTENT_DEPT_YAML: Error case for non-existent parent department
  • DEPT_REMOVE_WITHOUT_EXTENDS_YAML: Error case for _remove without extends

These fixtures align with the validation logic in _handle_dept_remove and _merge_departments.

src/synthorg/templates/builtins/dev_shop.yaml (1)

21-21: LGTM on the overall structure and new agent definitions.

The template correctly:

  • Extends startup per the PR objectives (solo_founder → startup → dev_shop)
  • Defines new departments (quality_assurance, operations) with proper budget allocation
  • Defines a complete engineering squad with appropriate merge_id values for the three Backend Developers
  • Uses structured model requirements where appropriate (tier/priority/min_context)

Also applies to: 44-68, 102-162

src/synthorg/templates/renderer.py (3)

116-178: LGTM on the inheritance resolution refactor.

The _render_to_dict function now correctly:

  • Accepts _as_parent: bool = False parameter (line 123)
  • Passes preserve_merge_ids=_as_parent to _build_config_dict (line 162)
  • Delegates inheritance resolution to resolve_inheritance with render_to_dict_fn=_render_to_dict callback (lines 170-178)

Per the context snippet from _inheritance.py:174-181, parent templates are rendered with _as_parent=True, which correctly preserves merge_id through multi-level inheritance chains.


346-395: LGTM on _build_config_dict changes.

The function correctly:

  • Accepts preserve_merge_ids: bool = False parameter (line 353)
  • Computes preserve_merge = has_extends or preserve_merge_ids (line 384)
  • Forwards the flag to _expand_agents (lines 385-391)
  • Passes has_extends to build_departments (lines 392-395)

The docstring properly documents the new parameter's purpose.


505-629: LGTM on agent expansion changes.

Both _expand_agents and _expand_single_agent correctly:

  • Accept and thread the preserve_merge_ids / preserve_merge_id parameters
  • Compute keep_merge = preserve_merge_ids or has_extends (lines 525, 624)
  • Retain merge_id on agents when keep_merge and merge_id (line 626-627)

This ensures parent agents retain their merge_id values so child templates can target them during inheritance merge.

src/synthorg/templates/merge.py (3)

27-27: LGTM on the new constants and workflow field handling.

  • _DEPT_STRIP_KEYS correctly only includes "_remove" (departments don't have merge_id)
  • Adding "workflow" to the replace-if-present fields (line 94) fixes the workflow config propagation bug mentioned in the PR objectives

Also applies to: 94-94


214-280: LGTM on department merge with _remove support.

The _merge_departments function correctly:

  • Skips parent departments when child has _remove: true (lines 262-264)
  • Strips _remove from non-removal overrides (lines 267-270)
  • Tracks seen_names to detect unmatched child removals
  • Delegates unmatched handling to _collect_unmatched_child_depts

The docstring accurately documents the new raise condition.


283-311: LGTM on _collect_unmatched_child_depts helper.

The function correctly:

  • Iterates unmatched child departments (not in seen_names)
  • Raises TemplateInheritanceError with clear message for _remove on non-existent parents
  • Logs at ERROR level before raising (per guidelines)
  • Strips _remove from appended departments

This mirrors the agent removal error handling in _apply_child_agent.

src/synthorg/templates/builtins/product_team.yaml (1)

22-22: LGTM on the overall structure and agent definitions.

The template correctly:

  • Extends startup per the PR objectives (solo_founder → startup → product_team)
  • Sets communication: "meeting_based" at the template level
  • Defines new departments (design, quality_assurance, data_analytics)
  • Defines new agents with appropriate merge_id values for Backend Developers
  • Uses UX roles moved to the new design department

Also applies to: 44-93, 116-169

tests/unit/templates/test_inheritance.py (6)

13-24: LGTM on updated imports.

The imports correctly align with the refactored code:

  • collect_parent_variables and _deduplicate_merged_agent_names moved to _inheritance module
  • TemplateRenderError added for the new error case tests
  • New YAML fixtures imported for department removal testing

Also applies to: 36-40


141-178: LGTM on department _remove unit tests.

Comprehensive coverage for _merge_departments:

  • test_remove_matching_parent_department: Validates successful removal
  • test_remove_nonexistent_department_raises: Validates error for non-existent target
  • test_remove_stripped_from_output: Validates _remove key is not in output
  • test_remove_case_insensitive: Validates case-insensitive matching

These tests align with the implementation in merge.py.


181-229: LGTM on integration tests for department removal.

The TestDepartmentRemoveIntegration class validates end-to-end behavior through the full render pipeline:

  • test_department_remove_via_extends: Successful removal via inheritance
  • test_department_remove_nonexistent_raises: TemplateInheritanceError for missing parent
  • test_department_remove_without_extends_raises: TemplateRenderError when _remove used without extends

These tests use the YAML fixtures from conftest.py and exercise the complete inheritance resolution path.


319-347: LGTM on workflow merge tests.

Good coverage for the new workflow merge semantics:

  • test_workflow_child_replaces_parent: Child workflow replaces entirely
  • test_workflow_inherited_from_parent: Parent workflow inherited when child omits
  • test_workflow_deep_copy_isolation: Verifies deep-copy prevents mutation leakage

These tests validate the fix for workflow config propagation mentioned in the PR objectives.


350-438: LGTM on deduplication and nameless department tests.

TestDeduplicateMergedAgentNames covers:

  • Empty/missing agents → no-op
  • Unique names unchanged
  • Duplicate names get numeric suffixes
  • Empty string names skipped
  • Missing name key skipped

TestNamelessDepartmentMerge validates edge cases:

  • Parent nameless dept passes through
  • Child nameless dept appended
  • Both preserved

All tests correctly exercise the new helper functions.


804-816: LGTM on renamed class and tightened assertions.

The rename from TestInheritanceIntegration to TestInheritanceFullPipeline better describes the test scope. The exact count assertions (6 agents, 3 departments) replace the previous lower-bound checks, providing stricter validation of inheritance behavior.

src/synthorg/templates/builtins/startup.yaml (1)

22-22: LGTM! Inheritance structure is correctly implemented.

The extends: "solo_founder" declaration and the merge_id: "fullstack-senior" override correctly leverage the (role, department, merge_id) matching key to target the parent's Full-Stack Developer for replacement. The resulting 5-agent composition aligns with the test assertions in test_builtin_inheritance.py.

Also applies to: 69-76

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

1-343: LGTM! Comprehensive test coverage for builtin inheritance chains.

The test file properly uses @pytest.mark.unit markers, leverages @pytest.mark.parametrize for standalone templates, and includes the three-level inheritance regression tests that exercise workflow config and agent merge_id handling across solo_founder -> startup -> dev_shop/product_team.

src/synthorg/templates/_inheritance.py (3)

79-89: LGTM! Guard with logging before raising is correctly implemented.

The explicit if check replaces the previous runtime assert, and the structured logger.error call ensures observability for this contract-violation path even when assertions are disabled via python -O.


28-40: LGTM! Protocol correctly matches the actual implementation.

The _RenderToDictFn protocol signature with = ... defaults aligns with the actual _render_to_dict implementation in renderer.py (context snippet shows matching parameters including _as_parent: bool).


123-153: LGTM! Validation helpers follow structured logging conventions.

Both _validate_inheritance_chain branches (circular detection and depth overflow) correctly log at ERROR level with context before raising TemplateInheritanceError.

Comment on lines +93 to +98
- role: "Full-Stack Developer"
department: "engineering"
_remove: true
- role: "Full-Stack Developer"
department: "engineering"
_remove: 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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify Full-Stack Developer merge_ids in startup.yaml
echo "=== Full-Stack Developer entries in startup.yaml ==="
rg -n -B1 -A6 'Full-Stack Developer' src/synthorg/templates/builtins/startup.yaml

Repository: Aureliolo/synthorg

Length of output: 1015


🏁 Script executed:

cat -n src/synthorg/templates/builtins/dev_shop.yaml | sed -n '85,105p'

Repository: Aureliolo/synthorg

Length of output: 767


Add merge_id to Full-Stack Developer removal entries to match parent agents.

The two Full-Stack Developer removal entries lack merge_id. Per src/synthorg/templates/builtins/startup.yaml, the parent's Full-Stack Developers have merge_id: "fullstack-senior" and merge_id: "fullstack-mid". The merge key is (role, department, merge_id), so missing merge_id defaults to "", which won't match the parent agents.

This will cause TemplateInheritanceError: no matching parent agent found.

🐛 Proposed fix
     - role: "Full-Stack Developer"
+      merge_id: "fullstack-senior"
       department: "engineering"
       _remove: true
     - role: "Full-Stack Developer"
+      merge_id: "fullstack-mid"
       department: "engineering"
       _remove: true
📝 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
- role: "Full-Stack Developer"
department: "engineering"
_remove: true
- role: "Full-Stack Developer"
department: "engineering"
_remove: true
- role: "Full-Stack Developer"
merge_id: "fullstack-senior"
department: "engineering"
_remove: true
- role: "Full-Stack Developer"
merge_id: "fullstack-mid"
department: "engineering"
_remove: true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/synthorg/templates/builtins/dev_shop.yaml` around lines 93 - 98, The two
removal entries for role "Full-Stack Developer" with department "engineering" in
dev_shop.yaml are missing merge_id and therefore won't match parent agents;
update those two entries to include merge_id: "fullstack-senior" and merge_id:
"fullstack-mid" respectively so the (role, department, merge_id) key matches the
parent Full-Stack Developer agents defined in startup.yaml.

- Add LGPL-2.0-or-later to license allow-list
- Add per-package exemptions for compound AND licenses:
  charset-normalizer (MIT actual), wrapt (BSD-2-Clause actual)
- Add null-license exemptions for aiohttp, cyclonedx-python-lib,
  fsspec, griffelib, grpcio (all verified permissive)
- Update stale version pins: numpy 2.4.4, qdrant-client 1.17.1,
  mem0ai 1.0.9
- Fix "Builtin" -> "Built-in" spelling in organization.md
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
.github/workflows/dependency-review.yml (1)

44-53: ⚠️ Potential issue | 🟡 Minor

Add LGPL-2.1-or-later to the allow-licenses list.

The allowlist includes LGPL-2.1-only, LGPL-2.0-or-later, and other LGPL variants, but LGPL-2.1-or-later is missing. This gap can block a future dependency bump that uses this standard SPDX identifier.

Suggested patch
           allow-licenses: >-
             MIT, MIT-0, Apache-2.0, BSD-2-Clause, BSD-3-Clause,
             ISC, MPL-2.0, PSF-2.0, Unlicense, 0BSD,
             CC0-1.0, CC-BY-3.0, CC-BY-4.0,
             Python-2.0, Python-2.0.1,
             LicenseRef-scancode-free-unknown, LicenseRef-scancode-protobuf,
             LicenseRef-scancode-google-patent-license-golang,
             ZPL-2.1,
-            LGPL-2.0-only, LGPL-2.0-or-later, LGPL-2.1-only, LGPL-3.0-only, LGPL-3.0-or-later,
+            LGPL-2.0-only, LGPL-2.0-or-later, LGPL-2.1-only, LGPL-2.1-or-later,
+            LGPL-3.0-only, LGPL-3.0-or-later,
             BlueOak-1.0.0,
             OFL-1.1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dependency-review.yml around lines 44 - 53, The
allow-licenses list in the dependency-review workflow is missing the SPDX
identifier "LGPL-2.1-or-later"; update the allow-licenses entry (the multi-line
value under the allow-licenses key) to include "LGPL-2.1-or-later" alongside the
existing LGPL variants (e.g., next to "LGPL-2.1-only" and "LGPL-2.0-or-later")
so future dependency bumps using that identifier are not blocked.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/organization.md`:
- Around line 353-363: The fenced code block showing the agent hierarchy
(starting with "solo_founder (base: 2 agents)" and the subsequent lines) lacks a
language identifier and triggers MD040; update the opening fence from ``` to
```text (or another appropriate language like ```yaml) so the block becomes
fenced with a language identifier, e.g., ```text, and leave the block contents
unchanged.

---

Outside diff comments:
In @.github/workflows/dependency-review.yml:
- Around line 44-53: The allow-licenses list in the dependency-review workflow
is missing the SPDX identifier "LGPL-2.1-or-later"; update the allow-licenses
entry (the multi-line value under the allow-licenses key) to include
"LGPL-2.1-or-later" alongside the existing LGPL variants (e.g., next to
"LGPL-2.1-only" and "LGPL-2.0-or-later") so future dependency bumps using that
identifier are not blocked.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 526b4221-2315-4c8e-8ba8-a389ed29a25a

📥 Commits

Reviewing files that changed from the base of the PR and between 8aefe19 and 319a10a.

📒 Files selected for processing (2)
  • .github/workflows/dependency-review.yml
  • docs/design/organization.md
📜 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: Test (Python 3.14)
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/templates/**/*.py : Templates: pre-built company templates, personality presets, and builder.
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.

Applied to files:

  • .github/workflows/dependency-review.yml
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Dependency allow-list in CI: permissive + weak-copyleft licenses, per-package GPL exemptions for dev-only tool deps (golangci-lint)

Applied to files:

  • .github/workflows/dependency-review.yml
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to pyproject.toml : Required runtime dependencies: `mem0ai` (default and currently only memory backend), `cryptography` (Fernet encryption), `faker` (multi-locale name generation)

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality

Applied to files:

  • docs/design/organization.md
🪛 markdownlint-cli2 (0.22.0)
docs/design/organization.md

[warning] 353-353: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (1)
docs/design/organization.md (1)

383-399: Docs align with implemented inheritance semantics.

departments._remove, workflow replace/inherit behavior, and post-merge agent-name deduplication now match the current implementation and reduce ambiguity.

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 `@docs/design/organization.md`:
- Around line 386-395: Clarify the inheritance semantics by updating the prose
to state that during Jinja2 rendering each template's workflow_config (not the
parent's raw workflow_config) is used and transformed by the renderer
(mentioning _build_workflow_dict) into a workflow dict per-template, and that at
config-merge time the workflow dict produced by the child always overrides the
parent's (so the "otherwise inherited" case for workflow does not occur in
practice); also explicitly call out that only workflow_handoffs and
escalation_paths use the "replace-if-present-else-inherit" merge rule because
they may be absent from rendered output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b3875311-50df-4b62-a405-1da10085ee0c

📥 Commits

Reviewing files that changed from the base of the PR and between 319a10a and e5b213c.

📒 Files selected for processing (2)
  • .github/workflows/dependency-review.yml
  • docs/design/organization.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Deploy Preview
  • GitHub Check: Test (Python 3.14)
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to src/synthorg/templates/**/*.py : Templates: pre-built company templates, personality presets, and builder.
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use `/review-dep-pr` to review Dependabot PRs before merging.

Applied to files:

  • .github/workflows/dependency-review.yml
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Dependency allow-list in CI: permissive + weak-copyleft licenses, per-package GPL exemptions for dev-only tool deps (golangci-lint)

Applied to files:

  • .github/workflows/dependency-review.yml
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to pyproject.toml : Required runtime dependencies: `mem0ai` (default and currently only memory backend), `cryptography` (Fernet encryption), `faker` (multi-locale name generation)

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality

Applied to files:

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

Applied to files:

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

Applied to files:

  • docs/design/organization.md
🔇 Additional comments (8)
.github/workflows/dependency-review.yml (4)

52-52: Allowlist expansion for LGPL variants looks correct.

Adding the -or-later LGPL SPDX variants is consistent with the existing weak-copyleft policy and avoids unnecessary false failures.

Based on learnings: Dependency allow-list in CI: permissive + weak-copyleft licenses, per-package GPL exemptions for dev-only tool deps (golangci-lint).


57-60: Manual verification notes are clear and appropriately scoped.

The updated comments make the newly exempted Python packages auditable and easier to maintain.


66-75: Good documentation for compound-license edge cases.

The charset-normalizer and wrapt notes clearly explain why package-level exemptions are used.


94-104: Version-pinned package exemptions are well implemented.

Keeping exemptions tied to exact package versions preserves review friction on future upgrades instead of silently allowing drift.

Based on learnings: Applies to .github/workflows/*.yml : Dependabot: daily updates for uv + github-actions + npm + pre-commit + docker + gomod, grouped minor/patch, no auto-merge. Use /review-dep-pr to review Dependabot PRs before merging.

docs/design/organization.md (4)

351-363: LGTM: Inheritance tree documentation is clear and complete.

The built-in inheritance tree structure is well-documented and matches the PR objectives. The previous spelling and markdown linting issues have been resolved (correct "Built-in" spelling and text language identifier on the code block).


383-383: LGTM: Department _remove documentation is clear.

The addition clearly documents the department removal feature and maintains consistency with the agent _remove pattern shown earlier in the document.


397-399: LGTM: Agent name deduplication is clearly documented.

The post-merge deduplication behavior is clearly explained with a concrete example format. This accurately reflects the PR objective to add name deduplication for auto-generated names.


16-16: No changes needed—the Engineering Squad size range is accurate.

The size range of 6-10 correctly matches the actual dev_shop.yaml builtin template, which defines min_agents: 6 and max_agents: 10. The 8 agents in the template definition represent the standard configuration, while the range allows flexibility for customization.

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 `@docs/design/organization.md`:
- Around line 403-405: The documentation example shows deduplication as "Kenji
Matsuda 2" but the actual implementation in
src/synthorg/templates/_inheritance.py appends an underscore before the numeric
suffix (e.g., "Kenji Matsuda_2"); update docs/design/organization.md to reflect
the real format by changing the example to use the underscore-suffixed form and
ensure any explanatory text mentions the underscore convention used by the
deduplication logic in _inheritance.py.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c0eef18c-b9e5-4c57-98f1-3bb6accf4bec

📥 Commits

Reviewing files that changed from the base of the PR and between e5b213c and 727d8cf.

📒 Files selected for processing (1)
  • docs/design/organization.md
📜 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: Test (Python 3.14)
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations

Applied to files:

  • docs/design/organization.md
📚 Learning: 2026-03-31T14:17:24.182Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-31T14:17:24.182Z
Learning: Applies to docs/design/*.md : Update the relevant `docs/design/` page when approved deviations occur to reflect the new reality

Applied to files:

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

Applied to files:

  • docs/design/organization.md
🔇 Additional comments (4)
docs/design/organization.md (4)

16-16: Looks good: updated Engineering Squad sizing is consistent with the inheritance restructure context.


351-364: Built-in inheritance tree section is clear and correctly scoped.
This matches the documented parent→child template relationships and standalone templates.


383-383: Department _remove semantics are documented correctly.
This line is aligned with merge behavior for department removal.


386-401: Workflow inheritance/merge semantics are now well clarified and implementation-aligned.
The distinction between render-time workflow_config handling and merge-time replacement behavior is accurate.

Comment on lines +403 to +405
After merging, agent names are deduplicated: if parent and child auto-generation
produces the same name, later occurrences receive a numeric suffix (e.g.,
``"Kenji Matsuda 2"``).
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

Fix deduplication example format to match actual suffixing behavior.
The example says Kenji Matsuda 2, but implementation suffixes with an underscore (Kenji Matsuda_2) in src/synthorg/templates/_inheritance.py.

Suggested doc fix
-``"Kenji Matsuda 2"``).
+``"Kenji Matsuda_2"``).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/design/organization.md` around lines 403 - 405, The documentation
example shows deduplication as "Kenji Matsuda 2" but the actual implementation
in src/synthorg/templates/_inheritance.py appends an underscore before the
numeric suffix (e.g., "Kenji Matsuda_2"); update docs/design/organization.md to
reflect the real format by changing the example to use the underscore-suffixed
form and ensure any explanatory text mentions the underscore convention used by
the deduplication logic in _inheritance.py.

@Aureliolo Aureliolo merged commit 3794c12 into main Apr 1, 2026
32 checks passed
@Aureliolo Aureliolo deleted the feat/template-inheritance-tree branch April 1, 2026 21:34
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview April 1, 2026 21:34 — with GitHub Actions Inactive
Aureliolo added a commit that referenced this pull request Apr 2, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.5.6](v0.5.5...v0.5.6)
(2026-04-02)


### Features

* calendar + hybrid ceremony scheduling strategies
([#985](#985))
([59a9b84](59a9b84)),
closes [#969](#969)
[#970](#970)
* landing page interactive components
([#984](#984))
([49868cb](49868cb))
* log aggregation and shipping (syslog, HTTP, compression)
([#964](#964))
([84be9f8](84be9f8))
* restructure builtin templates into inheritance tree
([#982](#982))
([3794c12](3794c12))
* sprint ceremony runtime scheduler with pluggable strategies
([#983](#983))
([43564a9](43564a9))


### Maintenance

* add no-bash-file-writes rule to CLAUDE.md
([#968](#968))
([a854dcc](a854dcc))
* bump web dependencies (lodash, eslint-react v4, storybook, playwright,
esbuild, codemirror)
([#987](#987))
([c344dfb](c344dfb))

---
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: restructure builtin templates into inheritance tree

2 participants