Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions DESIGN_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -2186,8 +2186,41 @@ template:

workflow: "agile_kanban"
communication: "hybrid"

workflow_handoffs:
- from_department: "engineering"
to_department: "qa"
trigger: "pr_ready"

escalation_paths:
- from_department: "engineering"
to_department: "security"
condition: "vulnerability_found"
```

**Template Inheritance** — Templates can extend other templates using `extends`:

```yaml
template:
name: "Extended Startup"
extends: "startup" # inherits all agents, departments, config
agents:
- role: "QA Engineer" # appended to parent agents
level: "mid"
- role: "full_stack_developer"
department: "engineering"
_remove: true # removes matching parent agent by (role, department)

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

The example uses role: "full_stack_developer" (snake_case) but the actual templates and role catalog use "Full-Stack Developer" (Title-Case with hyphens). Since the merge key uses role.lower(), this role name wouldn't match the parent's "Full-Stack Developer" ("full-stack developer" vs "full_stack_developer"). The example should use "Full-Stack Developer" to accurately illustrate how _remove works.

Copilot uses AI. Check for mistakes.
```

Inheritance resolves parent→child chains up to 10 levels deep. Merge semantics:
- **Scalars** (`company_name`, `company_type`): child wins if present.
- **`config`** dict: deep-merged (child keys override parent).
- **`agents`** list: merged by `(role, department)` key. Child can override, append, or remove (`_remove: true`) parent agents.
- **`departments`** list: merged by name (case-insensitive). Child dept replaces parent entirely.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- **`workflow_handoffs`**, **`escalation_paths`**: child replaces entirely if present.

Circular inheritance is detected via chain tracking and raises `TemplateInheritanceError`.

### 14.2 Company Builder

Interactive CLI/web wizard for creating custom companies:
Expand Down Expand Up @@ -2473,6 +2506,7 @@ ai-company/
│ ├── schema.py # Template schema models
│ ├── loader.py # Template loader
│ ├── renderer.py # Template renderer
│ ├── merge.py # Template config merging for inheritance
│ ├── presets.py # Personality presets + auto-name generation
│ ├── errors.py # Template errors
│ └── builtins/ # Pre-built company templates
Expand Down Expand Up @@ -2531,6 +2565,8 @@ These conventions were established during the M0–M2+ review cycle. **Adopted**
| **State coordination** | Planned (M4) | Centralized single-writer: `TaskEngine` owns all task/project mutations via `asyncio.Queue`. Agents submit requests, engine applies `model_copy(update=...)` sequentially and publishes snapshots. `version: int` field on state models for future optimistic concurrency if multi-process scaling is needed. | Prevents lost updates by design. Trivial in single-threaded asyncio (no locks). Perfect audit trail. Industry consensus: MetaGPT, CrewAI, AutoGen all use prevention-by-design, not conflict resolution. See §6.8 State Coordination table. |
| **Workspace isolation** | Planned (M4) | Pluggable `WorkspaceIsolationStrategy` protocol. Default: planner + git worktrees. Each agent works in an isolated worktree; sequential merge on completion. Textual conflicts detected by git; semantic conflicts reviewed by agent or human. | Industry standard (Codex, Cursor, Claude Code, VS Code). Maximum parallelism. Leverages mature git infrastructure. See §6.8. |
| **Graceful shutdown** | Adopted (M3) | Pluggable `ShutdownStrategy` protocol. Default: cooperative with 30s timeout. Agents check shutdown event at turn boundaries. Force-cancel after timeout. `INTERRUPTED` status for force-cancelled tasks. M4/M5: upgrade to checkpoint-and-stop. | Cross-platform (Windows `signal.signal()` fallback). Bounded shutdown time. Mirrors cooperative shutdown in §6.7. |
| **Template inheritance** | Adopted (M2.5) | `extends` field on `CompanyTemplate` triggers parent resolution at render time. `merge.py` merges configs by field type: scalars (child wins), config dicts (deep merge), agents (by `(role, department)` key with `_remove` support), departments (by name). `_ParentEntry` dataclass tracks merge state. `DEFAULT_MERGE_DEPARTMENT = "engineering"` shared between merge and renderer. Circular chains detected via `frozenset` tracking; max depth = 10. | Enables template composition without copy-paste. Merge-by-key preserves parent order. `_remove` directive enables clean agent removal without workarounds. |

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

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

The conventions table entry for Template inheritance describes the agent merge key as (role, department) but the actual code and the detailed documentation in §14.1 (line 2221) correctly describe it as (role, department, merge_id). This row in the conventions table should be updated to mention merge_id for consistency with the actual merge key.

Suggested change
| **Template inheritance** | Adopted (M2.5) | `extends` field on `CompanyTemplate` triggers parent resolution at render time. `merge.py` merges configs by field type: scalars (child wins), config dicts (deep merge), agents (by `(role, department)` key with `_remove` support), departments (by name). `_ParentEntry` dataclass tracks merge state. `DEFAULT_MERGE_DEPARTMENT = "engineering"` shared between merge and renderer. Circular chains detected via `frozenset` tracking; max depth = 10. | Enables template composition without copy-paste. Merge-by-key preserves parent order. `_remove` directive enables clean agent removal without workarounds. |
| **Template inheritance** | Adopted (M2.5) | `extends` field on `CompanyTemplate` triggers parent resolution at render time. `merge.py` merges configs by field type: scalars (child wins), config dicts (deep merge), agents (by `(role, department, merge_id)` key with `_remove` support), departments (by name). `_ParentEntry` dataclass tracks merge state. `DEFAULT_MERGE_DEPARTMENT = "engineering"` shared between merge and renderer. Circular chains detected via `frozenset` tracking; max depth = 10. | Enables template composition without copy-paste. Merge-by-key preserves parent order. `_remove` directive enables clean agent removal without workarounds. |

Copilot uses AI. Check for mistakes.
| **Pydantic alias for YAML directives** | Adopted (M2.5) | `Field(alias="_remove")` in `TemplateAgentConfig` — YAML uses `_remove: true`, Python accesses `agent.remove`. Keeps the YAML-facing name (underscore prefix signals internal directive) separate from the Python attribute name. | Underscore-prefixed YAML keys signal merge directives vs regular fields. Pydantic alias bridges the naming convention gap cleanly. |
| **Communication foundation** | Adopted (M4) | `MessageBus` protocol with `InMemoryMessageBus` backend (asyncio queues, pull-model `receive()` with shutdown signaling via `asyncio.Event`). `MessageDispatcher` routes to concurrent handlers via `asyncio.TaskGroup` with pre-allocated error collection. `AgentMessenger` per-agent facade auto-fills sender/timestamp/ID; deterministic direct-channel naming `@{sorted_a}:{sorted_b}`. `DeliveryEnvelope` for delivery tracking. `NotBlankStr` validation on all protocol boundary identifiers. | Pull-model avoids callback complexity and enables agents to consume at their own pace. Protocol + backend split enables future persistent/distributed bus implementations. Deterministic DM channel names prevent duplicates. See §5. |

---
Expand Down
11 changes: 11 additions & 0 deletions src/ai_company/observability/events/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,14 @@
TEMPLATE_RENDER_VALIDATION_ERROR: Final[str] = "template.render.validation_error"
TEMPLATE_PERSONALITY_PRESET_UNKNOWN: Final[str] = "template.personality_preset.unknown"
TEMPLATE_PASS1_FLOAT_FALLBACK: Final[str] = "template.pass1.float_fallback"
TEMPLATE_INHERIT_RESOLVE_START: Final[str] = "template.inherit.resolve_start"
TEMPLATE_INHERIT_RESOLVE_SUCCESS: Final[str] = "template.inherit.resolve_success"
TEMPLATE_INHERIT_CIRCULAR: Final[str] = "template.inherit.circular"
TEMPLATE_INHERIT_DEPTH_EXCEEDED: Final[str] = "template.inherit.depth_exceeded"
TEMPLATE_INHERIT_MERGE: Final[str] = "template.inherit.merge"
TEMPLATE_INHERIT_MERGE_ERROR: Final[str] = "template.inherit.merge_error"
TEMPLATE_RENDER_TYPE_ERROR: Final[str] = "template.render.type_error"
TEMPLATE_LOAD_NOT_FOUND: Final[str] = "template.load.not_found"
TEMPLATE_LOAD_READ_ERROR: Final[str] = "template.load.read_error"
TEMPLATE_LOAD_PARSE_ERROR: Final[str] = "template.load.parse_error"
TEMPLATE_LOAD_STRUCTURE_ERROR: Final[str] = "template.load.structure_error"
3 changes: 3 additions & 0 deletions src/ai_company/templates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
TemplateAgentConfig
TemplateDepartmentConfig
TemplateError
TemplateInheritanceError
TemplateNotFoundError
TemplateRenderError
TemplateValidationError
"""

from ai_company.templates.errors import (
TemplateError,
TemplateInheritanceError,
TemplateNotFoundError,
TemplateRenderError,
TemplateValidationError,
Expand Down Expand Up @@ -51,6 +53,7 @@
"TemplateDepartmentConfig",
"TemplateError",
"TemplateInfo",
"TemplateInheritanceError",
"TemplateMetadata",
"TemplateNotFoundError",
"TemplateRenderError",
Expand Down
64 changes: 59 additions & 5 deletions src/ai_company/templates/builtins/agency.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ template:
name: "Agency"
description: "Client-focused agency with project management and creative roles"
version: "1.0.0"
min_agents: 10
max_agents: 15
tags:
- "agency"
- "client-work"
Expand All @@ -23,30 +25,82 @@ template:

departments:
- name: "operations"
budget_percent: 30
budget_percent: 20
head_role: "Project Manager"
- name: "engineering"
budget_percent: 40
budget_percent: 35
head_role: "Full-Stack Developer"
- name: "design"
budget_percent: 30
head_role: "UI Designer"
budget_percent: 20
head_role: "UX Designer"
- name: "quality_assurance"
budget_percent: 10
head_role: "QA Engineer"
- name: "creative_marketing"
budget_percent: 15
head_role: "Brand Strategist"

agents:
- role: "Project Manager"
level: "senior"
model: "medium"
personality_preset: "visionary_leader"
personality_preset: "process_optimizer"
department: "operations"
- role: "Product Manager"
level: "mid"
model: "medium"
personality_preset: "strategic_planner"
department: "operations"
- role: "Scrum Master"
level: "senior"
model: "medium"
personality_preset: "process_optimizer"
department: "operations"
- role: "UX Designer"
level: "mid"
model: "medium"
personality_preset: "user_advocate"
department: "design"
- role: "UI Designer"
level: "mid"
model: "medium"
personality_preset: "creative_innovator"
department: "design"
- role: "Frontend Developer"
level: "mid"
model: "small"
personality_preset: "creative_innovator"
department: "engineering"
- role: "Backend Developer"
level: "senior"
model: "medium"
personality_preset: "pragmatic_builder"
department: "engineering"
- role: "Full-Stack Developer"
level: "senior"
model: "medium"
personality_preset: "pragmatic_builder"
department: "engineering"
- role: "QA Engineer"
level: "mid"
model: "small"
personality_preset: "quality_guardian"
department: "quality_assurance"
- role: "Content Writer"
level: "mid"
model: "small"
personality_preset: "technical_communicator"
department: "creative_marketing"
- role: "Brand Strategist"
level: "senior"
model: "medium"
personality_preset: "growth_hacker"
department: "creative_marketing"
- role: "Full-Stack Developer"
level: "mid"
model: "small"
personality_preset: "eager_learner"
department: "engineering"
Comment thread
coderabbitai[bot] marked this conversation as resolved.

workflow: "kanban"
communication: "hybrid"
21 changes: 19 additions & 2 deletions src/ai_company/templates/builtins/dev_shop.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ template:
name: "Dev Shop"
description: "Software development focused team with QA and DevOps"
version: "1.0.0"
min_agents: 6
max_agents: 10
tags:
- "development"
- "engineering"
Expand Down Expand Up @@ -36,7 +38,7 @@ template:
- role: "Software Architect"
level: "principal"
model: "large"
personality_preset: "methodical_analyst"
personality_preset: "systems_thinker"
department: "engineering"
- role: "Backend Developer"
level: "senior"
Expand All @@ -48,16 +50,31 @@ template:
model: "small"
personality_preset: "eager_learner"
department: "engineering"
- role: "Frontend Developer"
level: "mid"
model: "small"
personality_preset: "creative_innovator"
department: "engineering"
- role: "QA Lead"
level: "lead"
model: "medium"
personality_preset: "quality_guardian"
department: "quality_assurance"
- role: "QA Engineer"
level: "mid"
model: "small"
personality_preset: "methodical_analyst"
department: "quality_assurance"
- role: "DevOps/SRE Engineer"
level: "mid"
model: "medium"
personality_preset: "pragmatic_builder"
personality_preset: "process_optimizer"
department: "operations"
- role: "Backend Developer"
level: "senior"
model: "medium"
personality_preset: "disciplined_executor"
department: "engineering"

workflow: "agile_kanban"
communication: "hybrid"
Loading