Skip to content

feat: add pluggable MemoryBackend protocol with models, config, and events#180

Merged
Aureliolo merged 4 commits intomainfrom
feat/agent-memory-interface
Mar 9, 2026
Merged

feat: add pluggable MemoryBackend protocol with models, config, and events#180
Aureliolo merged 4 commits intomainfrom
feat/agent-memory-interface

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Add pluggable MemoryBackend protocol with lifecycle management (connect/disconnect/health_check) and CRUD operations (store/retrieve/get/delete/count)
  • Add MemoryCapabilities protocol for runtime capability discovery and SharedKnowledgeStore protocol for cross-agent shared knowledge
  • Add frozen Pydantic models: MemoryEntry, MemoryMetadata, MemoryStoreRequest, MemoryQuery with full validation (bounds, NaN rejection, tag dedup, timestamp ordering, time range)
  • Add CompanyMemoryConfig, MemoryStorageConfig, MemoryOptionsConfig with path traversal prevention and backend validation
  • Add MemoryCategory, MemoryLevel, ConsolidationInterval enums to core/enums.py
  • Add memory error hierarchy: MemoryError base with 6 specific subclasses
  • Add create_memory_backend() factory (placeholder for Mem0 adapter Implement memory retrieval, ranking, and context injection #41)
  • Add 21 MEMORY_* structured logging event constants
  • Add MemoryConfig to AgentIdentity and CompanyMemoryConfig to RootConfig
  • Update DESIGN_SPEC.md §7.5 with full protocol documentation, fix §15.3 file listing, fix §7.3 level mismatch
  • Add logger + validation logging to agent.py, models.py, schema.py validators

Closes #32

Test plan

  • 57 new tests added (4295 total, 96.34% coverage)
  • Protocol compliance tests (positive + negative isinstance checks)
  • Model validation boundary tests (bounds, NaN, timestamps, tag dedup)
  • Path traversal edge cases (Windows, nested, substring)
  • Memory event constant value assertions
  • __all__ re-export importability test
  • Enum member count + string value tests
  • JSON roundtrip tests with full field assertions
  • All pre-commit hooks pass (ruff, mypy, gitleaks, commitizen)

Review coverage

Pre-reviewed by 10 agents (code-reviewer, python-reviewer, pr-test-analyzer, silent-failure-hunter, comment-analyzer, type-design-analyzer, logging-audit, resilience-audit, security-reviewer, docs-consistency). 34 findings identified and addressed.

🤖 Generated with Claude Code

…vents (#32)

Implement the abstract memory system interface per DESIGN_SPEC §7.1-7.3:

- Rename MemoryType → MemoryLevel (fixes naming collision with memory
  categories); add MemoryCategory (5 types) and ConsolidationInterval enums
- Add MemoryBackend protocol (connect/disconnect/store/retrieve/get/delete/count)
- Add MemoryCapabilities protocol for runtime capability discovery
- Add SharedKnowledgeStore protocol for cross-agent shared knowledge
- Add frozen Pydantic models: MemoryMetadata, MemoryStoreRequest, MemoryEntry,
  MemoryQuery (with since/until validation)
- Add CompanyMemoryConfig (backend selection + storage + options), integrated
  into RootConfig
- Add MemoryError hierarchy (7 error classes)
- Add memory event constants (20 events) for structured logging
- Add placeholder factory (raises MemoryConfigError for mem0 — concrete impl
  in #41)
- Add 114 unit tests with fake backend verifying protocol compliance,
  per-agent isolation, and model validation

Closes #32
Pre-reviewed by 10 agents, 34 findings addressed:

- Fix misleading MEMORY_BACKEND_CREATED log in factory (use warning)
- Add logger + validation logging to agent.py, models.py, schema.py
- Add Raises sections to protocol.py and shared.py docstrings
- Clarify health_check() semantics in protocol
- Add MEMORY_ENTRY_FETCHED/FETCH_FAILED event constants
- Fix events module docstring to cover all log levels
- Add allow_inf_nan=False to MemoryStoreRequest
- Add tag deduplication validator to MemoryMetadata
- Add updated_at >= created_at validator to MemoryEntry
- Document MemoryLevel spec deviation (persistent vs full)
- Document dead else branch in factory as defensive guard
- Improve data_dir field description (Docker mount default)
- Add logging to RetryConfig._validate_delay_ordering
- Add enum member count/value tests for MemoryCategory, ConsolidationInterval
- Add MemoryQuery roundtrip test assertions for all fields
- Add NaN rejection tests for relevance_score, min_relevance
- Add timestamp ordering tests for MemoryEntry
- Add negative protocol compliance tests (capabilities, protocol, shared)
- Add __all__ re-export importability test
- Add path traversal edge case tests
- Add memory event value assertion tests
- Update DESIGN_SPEC §7.5 with MemoryBackend protocol docs
- Update DESIGN_SPEC §15.3 with actual memory/ file listing
- Fix DESIGN_SPEC §7.3 level: "full" -> "persistent"
- Update implementation snapshot
Copilot AI review requested due to automatic review settings March 9, 2026 08:06
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 9, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 85bbcabd-4e78-4242-8923-4110b62fba0d

📥 Commits

Reviewing files that changed from the base of the PR and between 884b7b5 and 377d4d2.

📒 Files selected for processing (5)
  • docs/decisions/ADR-001-memory-layer.md
  • src/ai_company/memory/models.py
  • src/ai_company/observability/events/memory.py
  • tests/unit/memory/test_models.py
  • tests/unit/observability/test_events.py

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Pluggable memory backend system with capability discovery and cross-agent shared knowledge support
    • New memory enums for levels and categories, plus consolidation interval options
  • Configuration

    • Company-level memory config: storage, retention, consolidation interval, per-agent limits, and backend selection
  • Observability

    • Structured memory logging events for backend lifecycle and operations
  • Documentation

    • Updated docs and README to reflect memory-backend architecture
  • Tests

    • Extensive unit tests covering memory models, protocols, factory, and errors

Walkthrough

Introduces a pluggable Memory subsystem: public protocols (MemoryBackend, MemoryCapabilities, SharedKnowledgeStore), data models/config/factory, a MemoryError hierarchy, observability events, core enum changes (MemoryLevel, MemoryCategory, ConsolidationInterval), and extensive unit tests and config integration.

Changes

Cohort / File(s) Summary
Design & ADR
DESIGN_SPEC.md, docs/decisions/ADR-001-memory-layer.md
Reorganized memory & persistence sections; formalized MemoryBackend protocol and MemoryCapabilities, updated ADR to reflect new protocol signatures and semantics.
Core enums & exports
src/ai_company/core/enums.py, src/ai_company/core/__init__.py
Renamed MemoryType→MemoryLevel; added MemoryCategory and ConsolidationInterval; updated package exports and docstrings.
Root config & defaults
src/ai_company/config/defaults.py, src/ai_company/config/schema.py, tests/unit/config/conftest.py
Added memory: CompanyMemoryConfig to root config schema and default config; small retry-config validation warning added; tests updated to include CompanyMemoryConfig.
Agent config & validation
src/ai_company/core/agent.py, tests/unit/core/*, tests/unit/core/conftest.py, tests/unit/core/test_agent.py
Switched MemoryConfig.type to MemoryLevel; added CONFIG_VALIDATION_FAILED logging on retention and tool-permission validation paths; tests adjusted to MemoryLevel.
Memory package public API
src/ai_company/memory/__init__.py
New package entrypoint re-exporting protocols, models, config, factory, and errors for ai_company.memory.
Protocols
src/ai_company/memory/protocol.py, src/ai_company/memory/capabilities.py, src/ai_company/memory/shared.py
Added runtime-checkable protocols: MemoryBackend (lifecycle + store/retrieve/get/delete/count), MemoryCapabilities (capability flags, limits), SharedKnowledgeStore (publish/search_shared/retract).
Models & config models
src/ai_company/memory/models.py, src/ai_company/memory/config.py
Added frozen Pydantic models: MemoryEntry, MemoryMetadata, MemoryQuery, MemoryStoreRequest, MemoryStorageConfig, MemoryOptionsConfig, CompanyMemoryConfig with validators (path traversal, backend whitelist, temporal checks).
Error types & events
src/ai_company/memory/errors.py, src/ai_company/observability/events/memory.py
Introduced MemoryError hierarchy and many MEMORY_* event constants for structured logging.
Factory & placeholder backend
src/ai_company/memory/factory.py
Added create_memory_backend(config) with placeholder handling (raises MemoryConfigError for unimplemented/unknown backends).
Unit tests — memory
tests/unit/memory/*
Extensive tests added for models, protocols (fake backends/stores), factory, errors, capabilities, and package re-exports.
Unit tests — core & observability
tests/unit/core/*, tests/unit/observability/test_events.py
Updated tests to new enums, integration of memory in test fixtures, and added checks for memory observability events.
Docs & README
README.md
Updated naming from Memory Layer→Memory Interface/Backends and adjusted implemented/planned items and backlog references.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Agent as Agent
participant Backend as MemoryBackend
participant DB as Storage (Database)
participant Shared as SharedKnowledgeStore

Agent->>Backend: connect()
Backend->>DB: initialize/open storage
DB-->>Backend: ready
Backend-->>Agent: connected

Agent->>Backend: store(agent_id, MemoryStoreRequest)
Backend->>DB: persist entry (vector/history)
DB-->>Backend: entry_id
Backend-->>Agent: return entry_id

Agent->>Backend: retrieve(agent_id, MemoryQuery)
Backend->>DB: query (filters, vectors, time)
DB-->>Backend: entries[]
Backend-->>Agent: entries[]

Agent->>Shared: publish(agent_id, MemoryStoreRequest)
Shared->>DB: persist shared entry
DB-->>Shared: shared_entry_id
Shared-->>Agent: shared_entry_id

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.40% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately describes the main change: adding a pluggable MemoryBackend protocol with supporting models, config, and events. It is specific, concise, and highlights the primary contribution.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering protocols, models, enums, errors, factory, events, documentation, and testing. It demonstrates clear intent aligned with the implementation.
Linked Issues check ✅ Passed The PR successfully implements all requirements from issue #32: memory types (MemoryCategory enum covering working, episodic, semantic, procedural, social), interface design (MemoryBackend protocol with store/retrieve/get/delete/count), capability discovery (MemoryCapabilities), shared knowledge support (SharedKnowledgeStore), per-agent isolation, configuration (CompanyMemoryConfig with retention/limits/consolidation), metadata models, and comprehensive unit tests (57 new tests).
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #32 (individual agent memory interface) and do not include unrelated work. The factory placeholder for Mem0 adapter (referenced as #41) and documentation updates are supporting changes aligned with the issue scope.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/agent-memory-interface
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/agent-memory-interface

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

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

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

This pull request significantly enhances the agent memory system by introducing a pluggable architecture. It defines clear protocols for memory backends, capability discovery, and shared knowledge, alongside robust Pydantic models for memory data and configuration. This foundational work ensures that the memory layer is extensible, well-validated, and properly integrated into the overall system, paving the way for future backend implementations like Mem0.

Highlights

  • Pluggable Memory Backend Protocol: Introduced a MemoryBackend protocol with lifecycle management (connect/disconnect/health_check) and comprehensive CRUD operations (store/retrieve/get/delete/count) for agent memory storage, enabling swappable backend implementations.
  • Memory Capability Discovery and Shared Knowledge: Added a MemoryCapabilities protocol for runtime feature discovery (e.g., graph support, vector search) and a SharedKnowledgeStore protocol for managing cross-agent shared knowledge, including publish, search, and retract operations.
  • Robust Pydantic Models for Memory: Implemented frozen Pydantic models (MemoryEntry, MemoryMetadata, MemoryStoreRequest, MemoryQuery) with extensive validation, covering bounds, NaN rejection, tag deduplication, and timestamp ordering/range checks.
  • Comprehensive Memory Configuration: Defined CompanyMemoryConfig, MemoryStorageConfig, and MemoryOptionsConfig Pydantic models, incorporating validation for path traversal prevention and backend selection, and integrated memory configuration into the RootConfig.
  • New Enums and Error Hierarchy: Added MemoryCategory, MemoryLevel, and ConsolidationInterval enums to core/enums.py and established a structured memory error hierarchy with a base MemoryError and six specific subclasses for better error handling.
  • Structured Logging and Documentation Updates: Introduced 21 new MEMORY_* structured logging event constants and updated DESIGN_SPEC.md with full protocol documentation, fixing several inconsistencies.
Changelog
  • DESIGN_SPEC.md
    • Updated table of contents to include 'Memory Backend Protocol' and renumbered 'Operational Data Persistence'.
    • Revised implementation snapshot date and progress description for M5, detailing the completion of the memory interface protocol.
    • Changed memory level configuration example from 'full' to 'persistent'.
    • Added extensive documentation for the 'Memory Backend Protocol' section, including enums, MemoryBackend, MemoryCapabilities, SharedKnowledgeStore protocols, error hierarchy, and configuration examples.
    • Updated references to the persistence protocol section from §7.5 to §7.6.
    • Adjusted file listing for the memory/ and persistence/ directories to reflect new structure and files.
  • docs/decisions/ADR-001-memory-layer.md
    • Updated MemoryCapabilities protocol definition to use MemoryCategory instead of MemoryType for supported_types.
  • src/ai_company/config/defaults.py
    • Added an empty dictionary for 'memory' to the default configuration.
  • src/ai_company/config/schema.py
    • Imported CompanyMemoryConfig.
    • Added logging for validation failures in _validate_delay_ordering method of RetryConfig.
    • Added memory field with CompanyMemoryConfig to RootConfig.
  • src/ai_company/core/init.py
    • Imported ConsolidationInterval, MemoryCategory, and MemoryLevel enums.
    • Removed MemoryType import.
    • Added ConsolidationInterval, MemoryCategory, and MemoryLevel to __all__ for re-export.
    • Removed MemoryType from __all__.
  • src/ai_company/core/agent.py
    • Imported MemoryLevel and removed MemoryType.
    • Added get_logger and CONFIG_VALIDATION_FAILED imports and initialized a logger.
    • Updated MemoryConfig.type to use MemoryLevel instead of MemoryType.
    • Updated validation logic in _validate_retention_consistency to use MemoryLevel.NONE and added logging for validation failures.
    • Added logging for validation failures in _validate_no_overlap method of ToolPermissions.
  • src/ai_company/core/enums.py
    • Renamed MemoryType enum to MemoryLevel and updated its docstring.
    • Added MemoryCategory enum with WORKING, EPISODIC, SEMANTIC, PROCEDURAL, SOCIAL values.
    • Added ConsolidationInterval enum with HOURLY, DAILY, WEEKLY, NEVER values.
  • src/ai_company/memory/init.py
    • Added __init__.py to define the memory package.
    • Imported and re-exported MemoryCapabilities, CompanyMemoryConfig, MemoryOptionsConfig, MemoryStorageConfig, memory error classes, create_memory_backend, MemoryEntry, MemoryMetadata, MemoryQuery, MemoryStoreRequest, MemoryBackend, and SharedKnowledgeStore.
  • src/ai_company/memory/capabilities.py
    • Added capabilities.py defining the MemoryCapabilities protocol for runtime feature discovery.
  • src/ai_company/memory/config.py
    • Added config.py defining MemoryStorageConfig, MemoryOptionsConfig, and CompanyMemoryConfig Pydantic models with validation, including path traversal prevention.
  • src/ai_company/memory/errors.py
    • Added errors.py defining a hierarchy of memory-related exceptions, all inheriting from MemoryError.
  • src/ai_company/memory/factory.py
    • Added factory.py containing the create_memory_backend factory function, which currently acts as a placeholder and raises MemoryConfigError.
  • src/ai_company/memory/models.py
    • Added models.py defining MemoryMetadata, MemoryStoreRequest, MemoryEntry, and MemoryQuery Pydantic models with extensive validation rules.
  • src/ai_company/memory/protocol.py
    • Added protocol.py defining the MemoryBackend protocol, outlining lifecycle and CRUD operations for memory storage.
  • src/ai_company/memory/shared.py
    • Added shared.py defining the SharedKnowledgeStore protocol for cross-agent shared knowledge operations.
  • src/ai_company/observability/events/memory.py
    • Added memory.py containing 21 new MEMORY_* structured logging event constants for backend lifecycle, entry operations, shared knowledge, and capability checks.
  • tests/unit/config/conftest.py
    • Imported CompanyMemoryConfig.
    • Added memory field to RootConfigFactory with a default CompanyMemoryConfig instance.
  • tests/unit/core/conftest.py
    • Imported MemoryLevel and removed MemoryType.
    • Updated MemoryConfigFactory.type to use MemoryLevel.SESSION.
  • tests/unit/core/test_agent.py
    • Imported MemoryLevel and removed MemoryType.
    • Updated assertions and instantiations in TestMemoryConfig to use MemoryLevel instead of MemoryType.
    • Updated test_json_roundtrip_with_full_nested_data to use MemoryLevel.PERSISTENT.
  • tests/unit/core/test_enums.py
    • Imported ConsolidationInterval, MemoryCategory, and MemoryLevel.
    • Updated test_memory_type_has_4_members to test MemoryLevel.
    • Added tests for MemoryCategory and ConsolidationInterval enum member counts and values.
  • tests/unit/memory/test_capabilities.py
    • Added new test file test_capabilities.py to verify MemoryCapabilities protocol compliance, including positive and negative isinstance checks and property type assertions.
  • tests/unit/memory/test_config.py
    • Added new test file test_config.py to thoroughly test MemoryStorageConfig, MemoryOptionsConfig, and CompanyMemoryConfig models, covering defaults, custom values, immutability, validation rules (e.g., path traversal, bounds), and JSON roundtrips.
  • tests/unit/memory/test_errors.py
    • Added new test file test_errors.py to verify the memory error hierarchy, ensuring all custom errors inherit correctly from MemoryError and preserve messages.
  • tests/unit/memory/test_factory.py
    • Added new test file test_factory.py to test the create_memory_backend factory, confirming it raises MemoryConfigError for unimplemented backends and that config validation prevents unknown backends.
  • tests/unit/memory/test_init.py
    • Added new test file test_init.py to ensure all intended exports from the ai_company.memory package are importable and accounted for in __all__.
  • tests/unit/memory/test_models.py
    • Added new test file test_models.py to comprehensively test MemoryMetadata, MemoryStoreRequest, MemoryEntry, and MemoryQuery models, including defaults, custom values, immutability, validation (e.g., confidence bounds, tag deduplication, timestamp ordering, query limits), and JSON roundtrips.
  • tests/unit/memory/test_protocol.py
    • Added new test file test_protocol.py to verify MemoryBackend protocol compliance using a fake in-memory backend, testing connection lifecycle, CRUD operations, and per-agent isolation.
  • tests/unit/memory/test_shared.py
    • Added new test file test_shared.py to verify SharedKnowledgeStore protocol compliance using a fake in-memory store, testing publish, search (with exclusion), and retract operations.
  • tests/unit/observability/test_events.py
    • Added 'memory' to the list of discovered domain modules.
    • Added parameterized tests to confirm the existence and correct values of all new MEMORY_* event constants.
Activity
  • 57 new tests were added, bringing the total to 4295 tests with 96.34% coverage.
  • Protocol compliance tests were implemented, including positive and negative isinstance checks.
  • Model validation boundary tests were added for bounds, NaN values, timestamps, and tag deduplication.
  • Path traversal edge cases were tested for memory storage configuration.
  • Assertions were added for memory event constant values.
  • An __all__ re-export importability test was included for the new memory package.
  • Enum member count and string value tests were added for new enums.
  • JSON roundtrip tests with full field assertions were implemented for memory models and configurations.
  • All pre-commit hooks (ruff, mypy, gitleaks, commitizen) passed.
  • The pull request underwent pre-review by 10 automated agents, leading to 34 identified findings that were subsequently addressed.
Using Gemini Code Assist

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

Invoking Gemini

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

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

Customization

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

Limitations & Feedback

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

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

Footnotes

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

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 is an excellent and comprehensive pull request that introduces a pluggable memory backend system. The design is robust, featuring clear protocols, well-defined data models, thorough configuration options, and a logical error hierarchy. The code quality is high, with strong validation, consistent logging, and extensive test coverage. I've identified a few minor areas for improvement to enhance documentation consistency and code clarity, but overall, this is a very strong contribution to the framework.


@property
def supported_types(self) -> frozenset[MemoryType]: ...
def supported_types(self) -> frozenset[MemoryCategory]: ...
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

There's an inconsistency in the property name for the MemoryCapabilities protocol. Here it's supported_types, but in the implementation (src/ai_company/memory/capabilities.py) and DESIGN_SPEC.md, it's supported_categories. Using supported_categories is more descriptive and consistent with the MemoryCategory enum.

Additionally, the protocol definition in this ADR is incomplete compared to the final implementation. It's missing the supports_shared_access and max_memories_per_agent properties. Please update this ADR to align with the implementation for consistency.

MemoryCapabilityError,
MemoryConfigError,
MemoryConnectionError,
MemoryError, # noqa: A004
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The noqa comment here is incorrect. A004 is for a "star import used" warning, but the issue here is shadowing the built-in MemoryError, which corresponds to code A001. Using the correct suppression code improves maintainability and ensures the right check is being silenced.

Suggested change
MemoryError, # noqa: A004
MemoryError, # noqa: A001

Comment on lines +47 to +58
@model_validator(mode="after")
def _deduplicate_tags(self) -> Self:
"""Remove duplicate tags while preserving order."""
seen: set[str] = set()
deduped: list[str] = []
for tag in self.tags:
if tag not in seen:
seen.add(tag)
deduped.append(tag)
if len(deduped) != len(self.tags):
object.__setattr__(self, "tags", tuple(deduped))
return self
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The implementation of _deduplicate_tags is correct but can be made more concise and Pythonic. Using dict.fromkeys() is a more idiomatic way to get unique items from a list while preserving order (since Python 3.7). This would improve readability and maintainability.

Suggested change
@model_validator(mode="after")
def _deduplicate_tags(self) -> Self:
"""Remove duplicate tags while preserving order."""
seen: set[str] = set()
deduped: list[str] = []
for tag in self.tags:
if tag not in seen:
seen.add(tag)
deduped.append(tag)
if len(deduped) != len(self.tags):
object.__setattr__(self, "tags", tuple(deduped))
return self
@model_validator(mode="after")
def _deduplicate_tags(self) -> Self:
"""Remove duplicate tags while preserving order."""
if not self.tags:
return self
# dict.fromkeys preserves insertion order since Python 3.7.
unique_tags = tuple(dict.fromkeys(self.tags))
if len(unique_tags) != len(self.tags):
object.__setattr__(self, "tags", unique_tags)
return self

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 9, 2026

Greptile Summary

This PR introduces the pluggable MemoryBackend protocol layer for M5 of the AI Company framework — protocols (MemoryBackend, MemoryCapabilities, SharedKnowledgeStore), frozen Pydantic domain models (MemoryEntry, MemoryMetadata, MemoryStoreRequest, MemoryQuery), configuration models (CompanyMemoryConfig, MemoryStorageConfig, MemoryOptionsConfig), an error hierarchy, a factory stub, and 21 structured-log event constants. It also migrates MemoryTypeMemoryLevel and wires CompanyMemoryConfig into RootConfig. The overall design is sound and well-tested with 57 new tests at 96% coverage. Previous review findings (CONFIG_VALIDATION_FAILED misuse, naive/aware datetime mixing, expires_at gap in MemoryEntry, ADR property name mismatch) have all been addressed.

Key remaining items to address:

  • MemoryNotFoundError semantic contradiction: The error's docstring says it is raised when a memory ID is not found, but the protocol contracts for get() and delete() explicitly return None/False instead of raising it. Backend authors reading errors.py in isolation will produce non-conformant implementations. The docstring should clarify when (if ever) this error is appropriate to raise.
  • Vendor name "mem0" in source and test code: The literal "mem0" is hardcoded across config.py, factory.py, and multiple test files. Per the project's code conventions (CLAUDE.md), vendor names should only appear in DESIGN_SPEC.md, .claude/ files, or third-party import paths — not in production source or tests. Centralising the string into a named constant would satisfy the rule and make future renaming trivial.
  • MemoryBackend.backend_name typed as str: Inconsistent with the codebase-wide convention of using NotBlankStr for all identifier fields — a blank backend_name is semantically invalid.
  • vector_store / history_store accept any string: No enum or Literal constraint means typos pass config validation silently and only fail at backend startup.

Confidence Score: 4/5

  • Safe to merge — this is a protocol/model/config layer with no runtime execution path; all concrete backend work is deferred to Implement memory retrieval, ranking, and context injection #41.
  • The PR is a well-structured interface layer with no runnable backend code (the factory always raises). The models are thoroughly validated and previous reviewer findings are all resolved. The four remaining issues are style/documentation concerns rather than correctness bugs: the MemoryNotFoundError docstring contradiction could mislead future implementors but won't break anything today; the vendor name rule violation is a convention issue; backend_name: str vs NotBlankStr is a minor type gap; and the unvalidated vector_store/history_store fields are latent config-time blind spots. None of these block the PR from merging safely.
  • src/ai_company/memory/errors.py (MemoryNotFoundError docstring), src/ai_company/memory/config.py (vendor name + unvalidated store fields), src/ai_company/memory/protocol.py (backend_name type).

Important Files Changed

Filename Overview
src/ai_company/memory/protocol.py Clean @runtime_checkable Protocol with full lifecycle + CRUD surface; minor type inconsistency (backend_name: str vs codebase-standard NotBlankStr).
src/ai_company/memory/models.py Well-validated frozen Pydantic models using AwareDatetime throughout; previous concerns (CONFIG_VALIDATION_FAILED misuse, expires_at gap, naive/aware mixing) are fully resolved in this version.
src/ai_company/memory/config.py Solid frozen config models with path-traversal protection; two concerns: "mem0" vendor name hardcoded throughout (CLAUDE.md rule), and vector_store/history_store accept any string with no enum/literal guard.
src/ai_company/memory/errors.py Clean error hierarchy, but MemoryNotFoundError docstring contradicts the protocol's documented get() / delete() return-value contracts, which will confuse backend implementors.
src/ai_company/memory/factory.py Correct stub using distinct MEMORY_BACKEND_NOT_IMPLEMENTED vs MEMORY_BACKEND_UNKNOWN events; hardcodes "mem0" string literal (same vendor-name concern as config.py).
src/ai_company/memory/capabilities.py Clean @runtime_checkable Protocol for capability discovery; property names now match the implementation after ADR fix.
src/ai_company/memory/shared.py Well-defined SharedKnowledgeStore Protocol with clear publish/search/retract surface and correct return types.
src/ai_company/observability/events/memory.py 21 well-named Final[str] constants following the memory.<entity>.<action> convention; MEMORY_MODEL_INVALID correctly added for data-model validation events.

Class Diagram

%%{init: {'theme': 'neutral'}}%%
classDiagram
    class MemoryBackend {
        <<Protocol>>
        +is_connected: bool
        +backend_name: str
        +connect() None
        +disconnect() None
        +health_check() bool
        +store(agent_id, request) NotBlankStr
        +retrieve(agent_id, query) tuple[MemoryEntry, ...]
        +get(agent_id, memory_id) MemoryEntry | None
        +delete(agent_id, memory_id) bool
        +count(agent_id, category) int
    }

    class MemoryCapabilities {
        <<Protocol>>
        +supported_categories: frozenset[MemoryCategory]
        +supports_graph: bool
        +supports_temporal: bool
        +supports_vector_search: bool
        +supports_shared_access: bool
        +max_memories_per_agent: int | None
    }

    class SharedKnowledgeStore {
        <<Protocol>>
        +publish(agent_id, request) NotBlankStr
        +search_shared(query, exclude_agent) tuple[MemoryEntry, ...]
        +retract(agent_id, memory_id) bool
    }

    class MemoryEntry {
        +id: NotBlankStr
        +agent_id: NotBlankStr
        +category: MemoryCategory
        +content: NotBlankStr
        +metadata: MemoryMetadata
        +created_at: AwareDatetime
        +updated_at: AwareDatetime | None
        +expires_at: AwareDatetime | None
        +relevance_score: float | None
    }

    class MemoryStoreRequest {
        +category: MemoryCategory
        +content: NotBlankStr
        +metadata: MemoryMetadata
        +expires_at: AwareDatetime | None
    }

    class MemoryQuery {
        +text: NotBlankStr | None
        +categories: frozenset[MemoryCategory] | None
        +tags: tuple[NotBlankStr, ...]
        +min_relevance: float
        +limit: int
        +since: AwareDatetime | None
        +until: AwareDatetime | None
    }

    class CompanyMemoryConfig {
        +backend: NotBlankStr
        +level: MemoryLevel
        +storage: MemoryStorageConfig
        +options: MemoryOptionsConfig
    }

    class MemoryError {
        <<Exception>>
    }
    class MemoryConnectionError
    class MemoryStoreError
    class MemoryRetrievalError
    class MemoryNotFoundError
    class MemoryConfigError
    class MemoryCapabilityError

    MemoryBackend ..> MemoryStoreRequest : store() accepts
    MemoryBackend ..> MemoryQuery : retrieve() accepts
    MemoryBackend ..> MemoryEntry : retrieve()/get() returns
    SharedKnowledgeStore ..> MemoryStoreRequest : publish() accepts
    SharedKnowledgeStore ..> MemoryEntry : search_shared() returns
    CompanyMemoryConfig --> MemoryBackend : factory creates

    MemoryConnectionError --|> MemoryError
    MemoryStoreError --|> MemoryError
    MemoryRetrievalError --|> MemoryError
    MemoryNotFoundError --|> MemoryError
    MemoryConfigError --|> MemoryError
    MemoryCapabilityError --|> MemoryError
Loading

Last reviewed commit: 377d4d2

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Introduces the foundational, pluggable agent memory interface layer (protocols + frozen models + config + events) and wires it into core configuration, enabling future concrete backends (e.g., Mem0 adapter in #41) without coupling application code to an implementation.

Changes:

  • Added MemoryBackend, MemoryCapabilities, and SharedKnowledgeStore runtime-checkable protocols plus a placeholder create_memory_backend() factory.
  • Added frozen Pydantic memory models and company-level memory config with validation + new structured logging event constants.
  • Updated core enums/config/docs/tests to reflect the new memory system (MemoryLevel, MemoryCategory, etc.) and to validate/cover the new API surface.

Reviewed changes

Copilot reviewed 29 out of 30 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/unit/observability/test_events.py Extends event-module discovery expectations and asserts MEMORY_* constants.
tests/unit/memory/test_shared.py Adds protocol compliance + basic behavior tests for SharedKnowledgeStore.
tests/unit/memory/test_protocol.py Adds protocol compliance + basic behavior tests for MemoryBackend.
tests/unit/memory/test_models.py Adds validation and JSON roundtrip tests for memory domain models.
tests/unit/memory/test_init.py Verifies ai_company.memory re-exports via __all__.
tests/unit/memory/test_factory.py Tests create_memory_backend() placeholder error behavior + config validation.
tests/unit/memory/test_errors.py Tests the memory error hierarchy invariants.
tests/unit/memory/test_config.py Tests memory config defaults, immutability, validation (incl. traversal checks), and JSON roundtrip.
tests/unit/memory/test_capabilities.py Adds protocol compliance tests for MemoryCapabilities.
tests/unit/memory/init.py Introduces memory unit test package marker.
tests/unit/core/test_enums.py Updates enum coverage for new memory enums and renames usage from MemoryType to MemoryLevel.
tests/unit/core/test_agent.py Updates agent memory config tests to use MemoryLevel.
tests/unit/core/conftest.py Updates factories to use MemoryLevel.
tests/unit/config/conftest.py Extends RootConfigFactory to include company memory config.
src/ai_company/observability/events/memory.py Adds structured logging event constants for memory lifecycle and operations.
src/ai_company/memory/shared.py Adds SharedKnowledgeStore protocol definition.
src/ai_company/memory/protocol.py Adds MemoryBackend protocol definition (lifecycle + CRUD).
src/ai_company/memory/models.py Adds frozen Pydantic models for entries/requests/queries with validation + logging on validation failures.
src/ai_company/memory/factory.py Adds placeholder backend factory (currently raises).
src/ai_company/memory/errors.py Adds memory error hierarchy.
src/ai_company/memory/config.py Adds frozen company memory config models + traversal/back-end validation.
src/ai_company/memory/capabilities.py Adds MemoryCapabilities protocol definition.
src/ai_company/memory/init.py Adds memory package re-exports for public API ergonomics.
src/ai_company/core/enums.py Introduces MemoryLevel, MemoryCategory, ConsolidationInterval enums and removes MemoryType.
src/ai_company/core/agent.py Updates agent MemoryConfig to use MemoryLevel and adds validation logging.
src/ai_company/core/init.py Re-exports new memory-related enums from the core package.
src/ai_company/config/schema.py Adds memory: CompanyMemoryConfig into RootConfig and adds validation logging in retry config.
src/ai_company/config/defaults.py Adds default memory section to generated default config dict.
docs/decisions/ADR-001-memory-layer.md Updates ADR protocol snippet type to MemoryCategory.
DESIGN_SPEC.md Documents the new memory protocol section and updates section numbering/index references.

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


@property
def supported_types(self) -> frozenset[MemoryType]: ...
def supported_types(self) -> frozenset[MemoryCategory]: ...
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

In the ADR protocol snippet, the property is shown as supported_types, but the implemented MemoryCapabilities protocol in src/ai_company/memory/capabilities.py exposes supported_categories. This mismatch will mislead readers/implementers; update the ADR snippet to use the correct property name (or rename the protocol property if the ADR is intended as the source of truth).

Suggested change
def supported_types(self) -> frozenset[MemoryCategory]: ...
def supported_categories(self) -> frozenset[MemoryCategory]: ...

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +41
if config.backend == "mem0":
msg = "mem0 backend not yet implemented"
logger.warning(
MEMORY_BACKEND_UNKNOWN,
backend="mem0",
reason=msg,
)
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

create_memory_backend() logs MEMORY_BACKEND_UNKNOWN for the mem0 backend even though it is a known backend that is merely not implemented yet. This will make observability/alerting ambiguous. Consider logging a more accurate event (e.g., introduce a MEMORY_BACKEND_NOT_IMPLEMENTED constant) and reserve MEMORY_BACKEND_UNKNOWN for truly unknown backend names.

Copilot uses AI. Check for mistakes.
@@ -47,7 +49,7 @@ def test_creativity_level_has_3_members(self) -> None:
assert len(CreativityLevel) == 3

def test_memory_type_has_4_members(self) -> None:
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

Test name test_memory_type_has_4_members no longer matches what it's asserting (MemoryLevel). Renaming the test to reflect MemoryLevel will keep the suite self-describing and avoid confusion when MemoryType no longer exists.

Suggested change
def test_memory_type_has_4_members(self) -> None:
def test_memory_level_has_4_members(self) -> None:

Copilot uses AI. Check for mistakes.
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: 5

🤖 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/decisions/ADR-001-memory-layer.md`:
- Around line 411-413: The ADR declares a property named supported_types but the
implementation exposes supported_categories; update the ADR to use the same
property name supported_categories (and keep the declared return type
frozenset[MemoryCategory]) so the design document matches the code (also scan
for any references in ADR-001-memory-layer.md to supported_types and rename them
to supported_categories).

In `@src/ai_company/config/schema.py`:
- Around line 540-543: The RootConfig currently instantiates a
CompanyMemoryConfig by default (the memory Field with
default_factory=CompanyMemoryConfig) but create_memory_backend() rejects the
only accepted backend ("mem0"), leaving the top-level config unbuildable; change
the default to make memory opt-in by either returning a disabled
CompanyMemoryConfig (e.g., default_factory that returns
CompanyMemoryConfig(enabled=False)) or by making the memory field Optional
(default None) so backend creation is deferred, and ensure
create_memory_backend() is only called when CompanyMemoryConfig indicates
enabled; reference CompanyMemoryConfig, the memory Field on RootConfig, and
create_memory_backend() when implementing the change.

In `@src/ai_company/memory/models.py`:
- Around line 173-176: MemoryQuery currently doesn't deduplicate tags while
MemoryMetadata does via _deduplicate_tags; add a validator on MemoryQuery.tags
that mirrors MemoryMetadata._deduplicate_tags to remove duplicate tags (preserve
order or enforce a deterministic order), and register it so it runs before the
existing _validate_time_range validator (or combine deduplication into the same
validator) to ensure consistent, deduplicated tag filters across models.

In `@tests/unit/core/test_enums.py`:
- Around line 51-52: Rename the test function to match the enum's current name:
change the test function name test_memory_type_has_4_members to
test_memory_level_has_4_members so it clearly references MemoryLevel; update any
test references/imports if present and ensure the test still asserts
len(MemoryLevel) == 4 in the test_enums module.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5094ff48-5819-4419-b719-739c947ee946

📥 Commits

Reviewing files that changed from the base of the PR and between f753779 and 077dddd.

📒 Files selected for processing (30)
  • DESIGN_SPEC.md
  • docs/decisions/ADR-001-memory-layer.md
  • src/ai_company/config/defaults.py
  • src/ai_company/config/schema.py
  • src/ai_company/core/__init__.py
  • src/ai_company/core/agent.py
  • src/ai_company/core/enums.py
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/capabilities.py
  • src/ai_company/memory/config.py
  • src/ai_company/memory/errors.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/models.py
  • src/ai_company/memory/protocol.py
  • src/ai_company/memory/shared.py
  • src/ai_company/observability/events/memory.py
  • tests/unit/config/conftest.py
  • tests/unit/core/conftest.py
  • tests/unit/core/test_agent.py
  • tests/unit/core/test_enums.py
  • tests/unit/memory/__init__.py
  • tests/unit/memory/test_capabilities.py
  • tests/unit/memory/test_config.py
  • tests/unit/memory/test_errors.py
  • tests/unit/memory/test_factory.py
  • tests/unit/memory/test_init.py
  • tests/unit/memory/test_models.py
  • tests/unit/memory/test_protocol.py
  • tests/unit/memory/test_shared.py
  • tests/unit/observability/test_events.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). (2)
  • GitHub Check: Agent
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Use Python 3.14+ with PEP 649 native lazy annotations
Do NOT use from __future__ import annotations — Python 3.14 has PEP 649
Use PEP 758 except syntax: use except A, B: (no parentheses) — ruff enforces this on Python 3.14

Files:

  • tests/unit/memory/test_factory.py
  • tests/unit/config/conftest.py
  • src/ai_company/core/enums.py
  • src/ai_company/memory/factory.py
  • tests/unit/memory/test_capabilities.py
  • src/ai_company/memory/capabilities.py
  • src/ai_company/memory/protocol.py
  • tests/unit/memory/test_shared.py
  • src/ai_company/memory/models.py
  • tests/unit/memory/test_init.py
  • tests/unit/core/test_agent.py
  • src/ai_company/config/defaults.py
  • tests/unit/memory/test_protocol.py
  • src/ai_company/config/schema.py
  • tests/unit/memory/test_config.py
  • src/ai_company/core/agent.py
  • tests/unit/memory/test_models.py
  • src/ai_company/memory/errors.py
  • src/ai_company/observability/events/memory.py
  • src/ai_company/core/__init__.py
  • tests/unit/observability/test_events.py
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/config.py
  • src/ai_company/memory/shared.py
  • tests/unit/memory/test_errors.py
  • tests/unit/core/conftest.py
  • tests/unit/core/test_enums.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow to categorize tests
Configure asyncio_mode = 'auto' for pytest — no manual @pytest.mark.asyncio needed
Set test timeout to 30 seconds per test
Prefer @pytest.mark.parametrize for testing similar cases
Use generic test provider names (test-provider, test-small-001, etc.) in tests

Files:

  • tests/unit/memory/test_factory.py
  • tests/unit/config/conftest.py
  • tests/unit/memory/test_capabilities.py
  • tests/unit/memory/test_shared.py
  • tests/unit/memory/test_init.py
  • tests/unit/core/test_agent.py
  • tests/unit/memory/test_protocol.py
  • tests/unit/memory/test_config.py
  • tests/unit/memory/test_models.py
  • tests/unit/observability/test_events.py
  • tests/unit/memory/test_errors.py
  • tests/unit/core/conftest.py
  • tests/unit/core/test_enums.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.py: Add type hints to all public functions and classes; mypy strict mode is enforced
Use Google-style docstrings required on public classes and functions (enforced by ruff D rules)
Create new objects instead of mutating existing ones (immutability); for non-Pydantic internal collections use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves — never mix static config fields with mutable runtime fields in one model
Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict); use @computed_field for derived values; 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) — prefer structured concurrency over bare create_task
Enforce 88 character line length (ruff)
Keep functions to less than 50 lines and files to less than 800 lines
Handle errors explicitly, never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)

Files:

  • src/ai_company/core/enums.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/capabilities.py
  • src/ai_company/memory/protocol.py
  • src/ai_company/memory/models.py
  • src/ai_company/config/defaults.py
  • src/ai_company/config/schema.py
  • src/ai_company/core/agent.py
  • src/ai_company/memory/errors.py
  • src/ai_company/observability/events/memory.py
  • src/ai_company/core/__init__.py
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/config.py
  • src/ai_company/memory/shared.py
src/ai_company/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/ai_company/**/*.py: Every module with business logic MUST have: from ai_company.observability import get_logger then logger = get_logger(name)
Never use import logging, logging.getLogger(), or print() in application code — use the structured logger from ai_company.observability
Always use variable name logger (not _logger, not log) for the logger instance
Always use event name constants from ai_company.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider); import directly: from ai_company.observability.events. import EVENT_CONSTANT
Always use structured kwargs in 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, entry/exit of key functions
Pure data models, enums, and re-exports do NOT need logging
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, or large/medium/small aliases

Files:

  • src/ai_company/core/enums.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/capabilities.py
  • src/ai_company/memory/protocol.py
  • src/ai_company/memory/models.py
  • src/ai_company/config/defaults.py
  • src/ai_company/config/schema.py
  • src/ai_company/core/agent.py
  • src/ai_company/memory/errors.py
  • src/ai_company/observability/events/memory.py
  • src/ai_company/core/__init__.py
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/config.py
  • src/ai_company/memory/shared.py
🧠 Learnings (9)
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/ai_company/**/*.py : Every module with business logic MUST have: from ai_company.observability import get_logger then logger = get_logger(__name__)

Applied to files:

  • src/ai_company/config/schema.py
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/ai_company/**/*.py : Never use `import logging`, `logging.getLogger()`, or `print()` in application code — use the structured logger from ai_company.observability

Applied to files:

  • src/ai_company/config/schema.py
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/ai_company/**/*.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/ai_company/config/schema.py
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/ai_company/**/*.py : Always use event name constants from ai_company.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider); import directly: from ai_company.observability.events.<domain> import EVENT_CONSTANT

Applied to files:

  • src/ai_company/config/schema.py
  • src/ai_company/observability/events/memory.py
  • tests/unit/observability/test_events.py
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/ai_company/**/*.py : Pure data models, enums, and re-exports do NOT need logging

Applied to files:

  • src/ai_company/config/schema.py
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/ai_company/**/*.py : Always use variable name `logger` (not `_logger`, not `log`) for the logger instance

Applied to files:

  • src/ai_company/config/schema.py
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves — never mix static config fields with mutable runtime fields in one model

Applied to files:

  • src/ai_company/memory/config.py
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Always read DESIGN_SPEC.md before implementing any feature or planning any issue — the design spec is the starting point for architecture, data models, and behavior

Applied to files:

  • DESIGN_SPEC.md
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/**/*.py : Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict); use computed_field for derived values; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators

Applied to files:

  • DESIGN_SPEC.md
🧬 Code graph analysis (20)
tests/unit/memory/test_factory.py (3)
src/ai_company/memory/config.py (1)
  • CompanyMemoryConfig (101-147)
src/ai_company/memory/errors.py (1)
  • MemoryConfigError (33-34)
src/ai_company/memory/factory.py (1)
  • create_memory_backend (16-49)
tests/unit/config/conftest.py (1)
src/ai_company/memory/config.py (1)
  • CompanyMemoryConfig (101-147)
src/ai_company/memory/factory.py (4)
src/ai_company/memory/config.py (1)
  • CompanyMemoryConfig (101-147)
src/ai_company/memory/errors.py (1)
  • MemoryConfigError (33-34)
src/ai_company/memory/protocol.py (1)
  • MemoryBackend (20-171)
src/ai_company/observability/_logger.py (1)
  • get_logger (8-28)
tests/unit/memory/test_capabilities.py (2)
src/ai_company/core/enums.py (1)
  • MemoryCategory (104-111)
src/ai_company/memory/capabilities.py (7)
  • MemoryCapabilities (13-56)
  • supported_categories (29-31)
  • supports_graph (34-36)
  • supports_temporal (39-41)
  • supports_vector_search (44-46)
  • supports_shared_access (49-51)
  • max_memories_per_agent (54-56)
src/ai_company/memory/protocol.py (3)
src/ai_company/core/enums.py (1)
  • MemoryCategory (104-111)
src/ai_company/memory/models.py (3)
  • MemoryEntry (88-144)
  • MemoryQuery (147-216)
  • MemoryStoreRequest (61-85)
tests/unit/memory/test_protocol.py (12)
  • connect (27-28)
  • connect (93-93)
  • disconnect (30-31)
  • health_check (33-34)
  • is_connected (37-38)
  • is_connected (96-97)
  • backend_name (41-42)
  • store (44-57)
  • retrieve (59-66)
  • get (68-69)
  • delete (71-76)
  • count (78-87)
tests/unit/memory/test_shared.py (3)
src/ai_company/core/enums.py (1)
  • MemoryCategory (104-111)
src/ai_company/memory/models.py (3)
  • MemoryEntry (88-144)
  • MemoryQuery (147-216)
  • MemoryStoreRequest (61-85)
src/ai_company/memory/shared.py (4)
  • SharedKnowledgeStore (18-82)
  • publish (26-43)
  • search_shared (45-63)
  • retract (65-82)
src/ai_company/memory/models.py (2)
src/ai_company/core/enums.py (1)
  • MemoryCategory (104-111)
src/ai_company/observability/_logger.py (1)
  • get_logger (8-28)
tests/unit/memory/test_init.py (1)
tests/unit/core/test_enums.py (1)
  • test_all_exports_importable (384-388)
tests/unit/core/test_agent.py (2)
src/ai_company/core/enums.py (1)
  • MemoryLevel (91-101)
src/ai_company/core/agent.py (1)
  • MemoryConfig (181-215)
tests/unit/memory/test_protocol.py (3)
src/ai_company/core/enums.py (1)
  • MemoryCategory (104-111)
src/ai_company/memory/models.py (4)
  • MemoryEntry (88-144)
  • MemoryMetadata (21-58)
  • MemoryQuery (147-216)
  • MemoryStoreRequest (61-85)
src/ai_company/memory/protocol.py (11)
  • MemoryBackend (20-171)
  • connect (31-38)
  • disconnect (40-45)
  • health_check (47-59)
  • is_connected (62-64)
  • backend_name (67-69)
  • store (71-88)
  • retrieve (90-110)
  • get (112-132)
  • delete (134-151)
  • count (153-171)
src/ai_company/config/schema.py (1)
src/ai_company/memory/config.py (1)
  • CompanyMemoryConfig (101-147)
tests/unit/memory/test_config.py (2)
src/ai_company/core/enums.py (2)
  • ConsolidationInterval (114-120)
  • MemoryLevel (91-101)
src/ai_company/memory/config.py (3)
  • CompanyMemoryConfig (101-147)
  • MemoryOptionsConfig (69-98)
  • MemoryStorageConfig (23-66)
src/ai_company/core/agent.py (3)
src/ai_company/core/enums.py (4)
  • MemoryLevel (91-101)
  • RiskTolerance (75-80)
  • SeniorityLevel (6-21)
  • ToolAccessLevel (264-281)
src/ai_company/core/role.py (1)
  • Authority (33-61)
src/ai_company/observability/_logger.py (1)
  • get_logger (8-28)
tests/unit/memory/test_models.py (2)
src/ai_company/core/enums.py (1)
  • MemoryCategory (104-111)
src/ai_company/memory/models.py (4)
  • MemoryEntry (88-144)
  • MemoryMetadata (21-58)
  • MemoryQuery (147-216)
  • MemoryStoreRequest (61-85)
src/ai_company/core/__init__.py (1)
src/ai_company/core/enums.py (3)
  • ConsolidationInterval (114-120)
  • MemoryCategory (104-111)
  • MemoryLevel (91-101)
src/ai_company/memory/__init__.py (7)
src/ai_company/memory/capabilities.py (1)
  • MemoryCapabilities (13-56)
src/ai_company/memory/config.py (3)
  • CompanyMemoryConfig (101-147)
  • MemoryOptionsConfig (69-98)
  • MemoryStorageConfig (23-66)
src/ai_company/memory/errors.py (7)
  • MemoryCapabilityError (37-38)
  • MemoryConfigError (33-34)
  • MemoryConnectionError (17-18)
  • MemoryError (13-14)
  • MemoryNotFoundError (29-30)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
src/ai_company/memory/factory.py (1)
  • create_memory_backend (16-49)
src/ai_company/memory/models.py (4)
  • MemoryEntry (88-144)
  • MemoryMetadata (21-58)
  • MemoryQuery (147-216)
  • MemoryStoreRequest (61-85)
src/ai_company/memory/protocol.py (1)
  • MemoryBackend (20-171)
src/ai_company/memory/shared.py (1)
  • SharedKnowledgeStore (18-82)
src/ai_company/memory/shared.py (3)
src/ai_company/memory/models.py (3)
  • MemoryEntry (88-144)
  • MemoryQuery (147-216)
  • MemoryStoreRequest (61-85)
tests/unit/memory/test_shared.py (4)
  • publish (25-35)
  • publish (59-60)
  • search_shared (37-46)
  • retract (48-53)
src/ai_company/engine/parallel_models.py (1)
  • agent_id (79-81)
tests/unit/memory/test_errors.py (1)
src/ai_company/memory/errors.py (7)
  • MemoryCapabilityError (37-38)
  • MemoryConfigError (33-34)
  • MemoryConnectionError (17-18)
  • MemoryError (13-14)
  • MemoryNotFoundError (29-30)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
tests/unit/core/conftest.py (1)
src/ai_company/core/enums.py (1)
  • MemoryLevel (91-101)
tests/unit/core/test_enums.py (1)
src/ai_company/core/enums.py (3)
  • ConsolidationInterval (114-120)
  • MemoryCategory (104-111)
  • MemoryLevel (91-101)
🔇 Additional comments (24)
src/ai_company/core/__init__.py (1)

34-41: LGTM!

The new memory-related enum exports (ConsolidationInterval, MemoryCategory, MemoryLevel) are correctly added to both the imports and __all__, maintaining alphabetical ordering. The removal of MemoryType and replacement with MemoryLevel aligns with the design spec changes.

Also applies to: 91-105

src/ai_company/core/enums.py (1)

91-121: LGTM!

The new memory-related enums are well-defined:

  • MemoryLevel correctly replaces MemoryType with clear documentation of the "full" → "PERSISTENT" deviation
  • MemoryCategory covers the §7.2 memory type categories
  • ConsolidationInterval provides consolidation options per §7.3

All enums follow the StrEnum pattern consistent with the rest of the file and include appropriate docstrings.

src/ai_company/memory/errors.py (1)

1-38: LGTM!

Well-structured error hierarchy with:

  • Clear documentation about shadowing the built-in MemoryError
  • Appropriate noqa: A001 suppression with explanation
  • Granular subclasses enabling both specific and broad exception handling
  • Concise docstrings for each exception type
src/ai_company/observability/events/memory.py (1)

1-47: LGTM!

Comprehensive memory event constants following the established memory.<entity>.<action> naming convention. The constants are well-organized by category (backend lifecycle, entry operations, shared knowledge, capability checks) and properly typed with Final[str].

tests/unit/observability/test_events.py (1)

179-179: LGTM!

Comprehensive test coverage for memory events:

  • Domain discovery test correctly updated to include "memory"
  • Parametrized test covers all 27 memory event constants
  • Dynamic import approach is consistent with the persistence events test pattern

Also applies to: 371-405

src/ai_company/core/agent.py (3)

16-26: LGTM!

Proper integration of observability:

  • Logger initialized with get_logger(__name__) following coding guidelines
  • CONFIG_VALIDATION_FAILED event constant imported from the correct domain module

191-215: LGTM!

Clean migration from MemoryType to MemoryLevel with proper validation logging:

  • Structured kwargs provide full context (model, field, memory_type, retention_days, reason)
  • Warning logged before raising ValueError per coding guidelines

243-262: LGTM!

ToolPermissions validation updated with structured logging that provides useful context (model, field, overlap, reason) before raising the validation error.

src/ai_company/config/defaults.py (1)

33-33: LGTM!

The "memory": {} default placeholder is correctly positioned and follows the pattern of other optional configuration sections.

tests/unit/memory/test_init.py (2)

10-14: LGTM!

The test_all_exports_importable test follows the established pattern from tests/unit/core/test_enums.py and ensures all names in __all__ are actually importable from the package.


16-17: The export count assertion is correct—the memory module __all__ contains exactly 18 items.

tests/unit/memory/test_factory.py (1)

1-23: LGTM!

Test structure follows guidelines: @pytest.mark.unit marker, 30-second timeout, and proper imports. The test correctly expects ValidationError since Pydantic wraps ValueError raised from model_validator into a ValidationError.

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

23-23: LGTM!

The CompanyMemoryConfig import and factory field addition follow the established patterns for other config components in RootConfigFactory.

Also applies to: 78-78

src/ai_company/memory/capabilities.py (1)

1-56: LGTM!

Clean protocol definition with proper @runtime_checkable decorator, type hints on all properties, and Google-style docstrings. The # noqa: TC001 is correct since MemoryCategory is used at runtime in the frozenset generic.

tests/unit/core/test_enums.py (1)

99-103: LGTM!

New tests for MemoryCategory and ConsolidationInterval enums follow the established patterns: member count verification and parametrized value assertions. Good coverage of the new enum types.

Also applies to: 232-257

tests/unit/core/test_agent.py (1)

24-24: LGTM!

All MemoryType references correctly updated to MemoryLevel. The test assertions align with the new enum members (SESSION, PERSISTENT, NONE) and maintain proper coverage of MemoryConfig validation logic.

Also applies to: 372-372, 377-378, 394-394, 398-398, 405-405, 655-655

tests/unit/memory/test_capabilities.py (1)

1-116: LGTM!

Excellent test coverage for protocol compliance:

  • Positive tests verify compliant implementations pass isinstance checks
  • Negative tests confirm incomplete implementations and plain objects fail
  • Variant tests cover edge cases like None for unlimited memories

The test doubles (_FakeMemoryCapabilities, _FakeUnlimitedCapabilities, _IncompleteCapabilities) are minimal and purpose-built.

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

35-35: LGTM!

Factory configuration correctly updated to use MemoryLevel.SESSION, consistent with the MemoryConfig model's default value defined in src/ai_company/core/agent.py.

Also applies to: 85-85

src/ai_company/memory/protocol.py (1)

1-171: LGTM!

The MemoryBackend protocol is well-designed with comprehensive docstrings, proper type hints using NotBlankStr for identifiers, and clear error semantics documented for each method. The use of @runtime_checkable enables structural subtyping checks at runtime.

src/ai_company/memory/models.py (1)

1-216: LGTM overall!

The memory models are well-structured with:

  • Proper frozen configuration with allow_inf_nan=False for numeric safety
  • Consistent use of NotBlankStr for identifiers
  • Good validation patterns with structured logging before raising errors
  • Appropriate bounds on numeric fields (confidence, relevance_score, min_relevance, limit)
src/ai_company/memory/config.py (1)

1-147: LGTM!

The configuration models are well-designed:

  • Path traversal prevention in MemoryStorageConfig handles both Windows and POSIX path formats
  • MemoryOptionsConfig properly uses allow_inf_nan=False for its numeric fields
  • Backend validation in CompanyMemoryConfig uses a ClassVar frozenset for the valid backends list, enabling easy extension
  • All validators log structured warnings with context before raising ValueError

The use of frozen Pydantic models for config aligns with the project's immutability conventions. Based on learnings: "Use frozen Pydantic models for config/identity."

src/ai_company/memory/__init__.py (1)

1-52: LGTM!

Clean package re-export with:

  • All public symbols properly imported and listed in __all__
  • Alphabetically sorted __all__ for maintainability
  • Appropriate noqa: A004 comment for the MemoryError shadow (intentional domain-specific naming)
DESIGN_SPEC.md (2)

1335-1439: LGTM!

The new §7.5 Memory Backend Protocol section is comprehensive and accurately documents:

  • The three protocols (MemoryBackend, MemoryCapabilities, SharedKnowledgeStore)
  • The enum definitions matching the code
  • The error hierarchy with clear "When Raised" descriptions
  • Configuration structure that aligns with the Pydantic models

The documentation properly references the related design sections (§7.2-7.4) and the ADR-001 decision record.


82-85: Implementation snapshot is accurate.

The snapshot correctly reflects M5 progress with the memory interface protocol complete and Mem0 adapter pending.

Comment on lines 411 to 413
@property
def supported_types(self) -> frozenset[MemoryType]: ...
def supported_types(self) -> frozenset[MemoryCategory]: ...
@property
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

Property name mismatch between ADR and implementation.

The ADR shows supported_types but src/ai_company/memory/capabilities.py (line 29) defines supported_categories. Update the ADR to match the actual implementation.

📝 Suggested fix
     `@property`
-    def supported_types(self) -> frozenset[MemoryCategory]: ...
+    def supported_categories(self) -> frozenset[MemoryCategory]: ...
📝 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
@property
def supported_types(self) -> frozenset[MemoryType]: ...
def supported_types(self) -> frozenset[MemoryCategory]: ...
@property
`@property`
def supported_categories(self) -> frozenset[MemoryCategory]: ...
`@property`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/decisions/ADR-001-memory-layer.md` around lines 411 - 413, The ADR
declares a property named supported_types but the implementation exposes
supported_categories; update the ADR to use the same property name
supported_categories (and keep the declared return type
frozenset[MemoryCategory]) so the design document matches the code (also scan
for any references in ADR-001-memory-layer.md to supported_types and rename them
to supported_categories).

Comment on lines +540 to +543
memory: CompanyMemoryConfig = Field(
default_factory=CompanyMemoryConfig,
description="Memory backend configuration",
)
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

Don't default every root config to an unbuildable backend.

RootConfig now eagerly creates CompanyMemoryConfig(), but the only accepted backend is "mem0" and create_memory_backend() currently raises for that value. That leaves the top-level default config in an "enabled" state that cannot actually be instantiated. Please make memory opt-in/disabled by default, or defer backend creation until the adapter lands.

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

In `@src/ai_company/config/schema.py` around lines 540 - 543, The RootConfig
currently instantiates a CompanyMemoryConfig by default (the memory Field with
default_factory=CompanyMemoryConfig) but create_memory_backend() rejects the
only accepted backend ("mem0"), leaving the top-level config unbuildable; change
the default to make memory opt-in by either returning a disabled
CompanyMemoryConfig (e.g., default_factory that returns
CompanyMemoryConfig(enabled=False)) or by making the memory field Optional
(default None) so backend creation is deferred, and ensure
create_memory_backend() is only called when CompanyMemoryConfig indicates
enabled; reference CompanyMemoryConfig, the memory Field on RootConfig, and
create_memory_backend() when implementing the change.

… agents

- Add MEMORY_BACKEND_NOT_IMPLEMENTED event constant, use it for mem0 stub
- Add expires_at >= created_at validation to MemoryEntry
- Add tag deduplication to MemoryQuery for consistency with MemoryMetadata
- Use dict.fromkeys() for more idiomatic tag dedup in MemoryMetadata
- Fix docstring: "before" → "strictly before" in MemoryQuery time range
- Update health_check() docstring to mandate logging before returning False
- Add MemoryConnectionError to all CRUD method Raises sections
- Add class-level connection requirement note to MemoryBackend
- Fix ADR-001 supported_types → supported_categories, add missing properties
- Update README to reflect completed memory protocol interface
- Add default annotations to DESIGN_SPEC yaml examples
- Remove outdated "full" deviation comment from MemoryLevel
- Fix __init__.py module docstring to include domain models
- Rename test_memory_type → test_memory_level in test_enums.py
- Add 7 new tests (expires_at validation + query tag dedup)
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@docs/decisions/ADR-001-memory-layer.md`:
- Around line 412-422: Update the ADR snippet for the MemoryBackend example to
match the actual synchronous protocol in src/ai_company/memory/protocol.py:
replace the old async store/retrieve/delete/list_memories docs with the real
synchronous API and include the methods and properties present on the protocol
(connect, disconnect, health_check, get, count, backend_name, is_connected) and
keep the updated capability properties (supported_categories, supports_graph,
supports_temporal, supports_vector_search, supports_shared_access,
max_memories_per_agent) so the ADR documents the exact contract exposed by the
MemoryBackend.

In `@src/ai_company/core/enums.py`:
- Around line 91-97: MemoryLevel now renames the serialized value
"full"→"persistent", which breaks existing configs; add a backward-compatible
alias and parsing acceptance: add a deprecated enum member (e.g.,
MemoryLevel.FULL = "full") and/or a compatibility constant alias MemoryType =
MemoryLevel, and update the config parsing logic that reads memory levels to map
the legacy string "full" to MemoryLevel.PERSISTENT (or accept both values) so
existing YAMLs and imports continue to work while emitting a deprecation notice.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4beb38e8-56ff-4ec8-bfcd-0966f68ac5e9

📥 Commits

Reviewing files that changed from the base of the PR and between 077dddd and 884b7b5.

📒 Files selected for processing (12)
  • DESIGN_SPEC.md
  • README.md
  • docs/decisions/ADR-001-memory-layer.md
  • src/ai_company/core/enums.py
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/models.py
  • src/ai_company/memory/protocol.py
  • src/ai_company/observability/events/memory.py
  • tests/unit/core/test_enums.py
  • tests/unit/memory/test_models.py
  • tests/unit/observability/test_events.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). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Use Python 3.14+ with PEP 649 native lazy annotations
Do NOT use from __future__ import annotations — Python 3.14 has PEP 649
Use PEP 758 except syntax: use except A, B: (no parentheses) — ruff enforces this on Python 3.14

Files:

  • src/ai_company/memory/models.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/protocol.py
  • tests/unit/core/test_enums.py
  • src/ai_company/observability/events/memory.py
  • tests/unit/observability/test_events.py
  • tests/unit/memory/test_models.py
  • src/ai_company/core/enums.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.py: Add type hints to all public functions and classes; mypy strict mode is enforced
Use Google-style docstrings required on public classes and functions (enforced by ruff D rules)
Create new objects instead of mutating existing ones (immutability); for non-Pydantic internal collections use copy.deepcopy() at construction + MappingProxyType wrapping for read-only enforcement
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves — never mix static config fields with mutable runtime fields in one model
Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict); use @computed_field for derived values; 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) — prefer structured concurrency over bare create_task
Enforce 88 character line length (ruff)
Keep functions to less than 50 lines and files to less than 800 lines
Handle errors explicitly, never silently swallow exceptions
Validate at system boundaries (user input, external APIs, config files)

Files:

  • src/ai_company/memory/models.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/protocol.py
  • src/ai_company/observability/events/memory.py
  • src/ai_company/core/enums.py
src/ai_company/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/ai_company/**/*.py: Every module with business logic MUST have: from ai_company.observability import get_logger then logger = get_logger(name)
Never use import logging, logging.getLogger(), or print() in application code — use the structured logger from ai_company.observability
Always use variable name logger (not _logger, not log) for the logger instance
Always use event name constants from ai_company.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider); import directly: from ai_company.observability.events. import EVENT_CONSTANT
Always use structured kwargs in 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, entry/exit of key functions
Pure data models, enums, and re-exports do NOT need logging
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, or large/medium/small aliases

Files:

  • src/ai_company/memory/models.py
  • src/ai_company/memory/factory.py
  • src/ai_company/memory/__init__.py
  • src/ai_company/memory/protocol.py
  • src/ai_company/observability/events/memory.py
  • src/ai_company/core/enums.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.e2e, @pytest.mark.slow to categorize tests
Configure asyncio_mode = 'auto' for pytest — no manual @pytest.mark.asyncio needed
Set test timeout to 30 seconds per test
Prefer @pytest.mark.parametrize for testing similar cases
Use generic test provider names (test-provider, test-small-001, etc.) in tests

Files:

  • tests/unit/core/test_enums.py
  • tests/unit/observability/test_events.py
  • tests/unit/memory/test_models.py
🧠 Learnings (4)
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/**/*.py : Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (using model_copy(update=...)) for runtime state that evolves — never mix static config fields with mutable runtime fields in one model

Applied to files:

  • src/ai_company/memory/models.py
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/ai_company/**/*.py : Always use event name constants from ai_company.observability.events domain-specific modules (e.g., PROVIDER_CALL_START from events.provider); import directly: from ai_company.observability.events.<domain> import EVENT_CONSTANT

Applied to files:

  • src/ai_company/observability/events/memory.py
  • tests/unit/observability/test_events.py
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Always read DESIGN_SPEC.md before implementing any feature or planning any issue — the design spec is the starting point for architecture, data models, and behavior

Applied to files:

  • DESIGN_SPEC.md
📚 Learning: 2026-03-09T06:51:01.916Z
Learnt from: CR
Repo: Aureliolo/ai-company PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-09T06:51:01.916Z
Learning: Applies to src/**/*.py : Use Pydantic v2 (BaseModel, model_validator, computed_field, ConfigDict); use computed_field for derived values; use NotBlankStr from core.types for all identifier/name fields (including optional and tuple variants) instead of manual whitespace validators

Applied to files:

  • DESIGN_SPEC.md
🧬 Code graph analysis (5)
src/ai_company/memory/models.py (2)
src/ai_company/core/enums.py (1)
  • MemoryCategory (100-107)
src/ai_company/observability/_logger.py (1)
  • get_logger (8-28)
src/ai_company/memory/factory.py (4)
src/ai_company/memory/config.py (1)
  • CompanyMemoryConfig (101-147)
src/ai_company/memory/errors.py (1)
  • MemoryConfigError (33-34)
src/ai_company/memory/protocol.py (1)
  • MemoryBackend (20-182)
src/ai_company/observability/_logger.py (1)
  • get_logger (8-28)
src/ai_company/memory/__init__.py (7)
src/ai_company/memory/capabilities.py (1)
  • MemoryCapabilities (13-56)
src/ai_company/memory/config.py (3)
  • CompanyMemoryConfig (101-147)
  • MemoryOptionsConfig (69-98)
  • MemoryStorageConfig (23-66)
src/ai_company/memory/errors.py (7)
  • MemoryCapabilityError (37-38)
  • MemoryConfigError (33-34)
  • MemoryConnectionError (17-18)
  • MemoryError (13-14)
  • MemoryNotFoundError (29-30)
  • MemoryRetrievalError (25-26)
  • MemoryStoreError (21-22)
src/ai_company/memory/factory.py (1)
  • create_memory_backend (19-52)
src/ai_company/memory/models.py (4)
  • MemoryEntry (83-151)
  • MemoryMetadata (21-53)
  • MemoryQuery (154-231)
  • MemoryStoreRequest (56-80)
src/ai_company/memory/protocol.py (1)
  • MemoryBackend (20-182)
src/ai_company/memory/shared.py (1)
  • SharedKnowledgeStore (18-82)
src/ai_company/memory/protocol.py (2)
src/ai_company/core/enums.py (1)
  • MemoryCategory (100-107)
src/ai_company/memory/models.py (3)
  • MemoryEntry (83-151)
  • MemoryQuery (154-231)
  • MemoryStoreRequest (56-80)
tests/unit/core/test_enums.py (1)
src/ai_company/core/enums.py (3)
  • ConsolidationInterval (110-116)
  • MemoryCategory (100-107)
  • MemoryLevel (91-97)
🪛 LanguageTool
README.md

[typographical] ~24-~24: To join two clauses or introduce examples, consider using an em dash.
Context: ...a migrations - Memory Interface (M5) - Pluggable MemoryBackend protocol with ...

(DASH_RULE)


[typographical] ~28-~28: To join two clauses or introduce examples, consider using an em dash.
Context: ... milestones) - Memory Backends (M5) - Mem0 adapter ([ADR-001](docs/decisions/A...

(DASH_RULE)

🔇 Additional comments (5)
src/ai_company/memory/protocol.py (1)

1-182: LGTM!

The MemoryBackend protocol is well-designed with clear separation between lifecycle management (connect, disconnect, health_check) and CRUD operations (store, retrieve, get, delete, count). The docstrings thoroughly document error semantics and the health_check note appropriately specifies logging requirements for implementations. Type hints using NotBlankStr for identifiers align with project conventions.

src/ai_company/memory/models.py (1)

1-231: LGTM!

The memory domain models are well-implemented with frozen Pydantic models, appropriate validation (timestamp ordering, tag deduplication, NaN rejection), and structured logging on validation failures. The _deduplicate_tags validator on MemoryQuery (lines 205-211) addresses the previous review feedback for consistency with MemoryMetadata.

src/ai_company/memory/__init__.py (1)

1-53: LGTM!

Clean re-export surface with all 18 public symbols properly imported and listed in __all__. The noqa: A004 comment on line 19 appropriately acknowledges the intentional shadowing of the built-in MemoryError.

DESIGN_SPEC.md (2)

1335-1439: LGTM!

The new §7.5 Memory Backend Protocol section comprehensively documents the memory subsystem architecture: enums, MemoryBackend protocol with lifecycle and CRUD methods, MemoryCapabilities protocol for runtime discovery, SharedKnowledgeStore protocol for cross-agent operations, error hierarchy, and configuration models. The protocol signatures and error semantics align with the implementation in src/ai_company/memory/.


2732-2741: LGTM!

The project structure listing correctly reflects all new memory subsystem files: __init__.py, capabilities.py, config.py, errors.py, factory.py, models.py, protocol.py, and shared.py.

Comment on lines +91 to 97
class MemoryLevel(StrEnum):
"""Memory persistence level for an agent (§7.3)."""

PERSISTENT = "persistent"
PROJECT = "project"
SESSION = "session"
NONE = "none"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add a compatibility path for the renamed memory level.

MemoryLevel is config-facing, so changing the serialized value from "full" to "persistent" and dropping MemoryType will break existing YAML and imports. This PR still has level: "full" examples in docs/decisions/ADR-001-memory-layer.md, so please either accept the legacy spelling during parsing and keep a deprecated alias, or treat this as an explicit breaking change with migration notes.

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

In `@src/ai_company/core/enums.py` around lines 91 - 97, MemoryLevel now renames
the serialized value "full"→"persistent", which breaks existing configs; add a
backward-compatible alias and parsing acceptance: add a deprecated enum member
(e.g., MemoryLevel.FULL = "full") and/or a compatibility constant alias
MemoryType = MemoryLevel, and update the config parsing logic that reads memory
levels to map the legacy string "full" to MemoryLevel.PERSISTENT (or accept both
values) so existing YAMLs and imports continue to work while emitting a
deprecation notice.

…1 protocol

- Replace datetime with AwareDatetime on all memory model timestamp fields
  to prevent TypeError from naive/aware mixing (Pydantic rejects naive at
  field validation before model validators run)
- Add MEMORY_MODEL_INVALID event constant for runtime domain model validation
  failures — replaces CONFIG_VALIDATION_FAILED which is scoped to config models
- Update ADR-001 MemoryBackend snippet to match the shipped protocol
  (lifecycle methods, properties, correct parameter types)
- Add 4 new tests (naive datetime rejection + query naive since)
Copilot AI review requested due to automatic review settings March 9, 2026 08:33
@Aureliolo Aureliolo merged commit 46cfdd4 into main Mar 9, 2026
9 of 11 checks passed
@Aureliolo Aureliolo deleted the feat/agent-memory-interface branch March 9, 2026 08:34
Comment on lines +29 to +30
class MemoryNotFoundError(MemoryError):
"""Raised when a specific memory ID is not found."""
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MemoryNotFoundError is never raised by the protocol

MemoryNotFoundError is documented as "Raised when a specific memory ID is not found," yet the MemoryBackend protocol explicitly documents the opposite contract:

  • get(): "Returns None when the entry does not exist — MemoryNotFoundError is never raised by this method" (protocol.py line 127–128)
  • delete(): "Returns True if the entry was deleted, False if not found" (not raised)

This creates a direct contradiction for backend implementors: the error's docstring says to raise it, but the protocol says not to. Backend authors reading errors.py in isolation will raise MemoryNotFoundError from get(), breaking callers that expect None.

Either:

  • Update the error's docstring to clarify the specific scenarios where backends should raise it (if any exist outside the base protocol, e.g. in a hypothetical strict-mode variant), or
  • If MemoryNotFoundError is reserved for future use or non-protocol extension points, add a note explaining its intended scope.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ai_company/memory/errors.py
Line: 29-30

Comment:
**`MemoryNotFoundError` is never raised by the protocol**

`MemoryNotFoundError` is documented as "Raised when a specific memory ID is not found," yet the `MemoryBackend` protocol explicitly documents the opposite contract:
- `get()`: "Returns `None` when the entry does not exist — `MemoryNotFoundError` is **never** raised by this method" (`protocol.py` line 127–128)
- `delete()`: "Returns `True` if the entry was deleted, `False` if not found" (not raised)

This creates a direct contradiction for backend implementors: the error's docstring says to raise it, but the protocol says not to. Backend authors reading `errors.py` in isolation will raise `MemoryNotFoundError` from `get()`, breaking callers that expect `None`.

Either:
- Update the error's docstring to clarify the specific scenarios where backends *should* raise it (if any exist outside the base protocol, e.g. in a hypothetical strict-mode variant), or
- If `MemoryNotFoundError` is reserved for future use or non-protocol extension points, add a note explaining its intended scope.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +73 to +75
def backend_name(self) -> str:
"""Human-readable backend identifier (e.g. ``"mem0"``)."""
...
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

backend_name typed as str instead of NotBlankStr

The codebase convention (CLAUDE.md) says "use NotBlankStr (from core.types) for all identifier/name fields — including optional (NotBlankStr | None) and tuple variants — instead of manual whitespace validators." backend_name is a human-readable backend identifier, so a blank or whitespace-only value would be semantically invalid, yet the current type allows it.

Suggested change
def backend_name(self) -> str:
"""Human-readable backend identifier (e.g. ``"mem0"``)."""
...
@property
def backend_name(self) -> "NotBlankStr":
"""Human-readable backend identifier (e.g. ``"mem0"``)."""
...

You'll also need to add NotBlankStr to the imports at the top of the file (it's already used elsewhere in the file, just not for this property).

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ai_company/memory/protocol.py
Line: 73-75

Comment:
**`backend_name` typed as `str` instead of `NotBlankStr`**

The codebase convention (CLAUDE.md) says "use `NotBlankStr` (from `core.types`) for all identifier/name fields — including optional (`NotBlankStr | None`) and tuple variants — instead of manual whitespace validators." `backend_name` is a human-readable backend identifier, so a blank or whitespace-only value would be semantically invalid, yet the current type allows it.

```suggestion
    @property
    def backend_name(self) -> "NotBlankStr":
        """Human-readable backend identifier (e.g. ``"mem0"``)."""
        ...
```

You'll also need to add `NotBlankStr` to the imports at the top of the file (it's already used elsewhere in the file, just not for this property).

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +113 to +118
_VALID_BACKENDS: ClassVar[frozenset[str]] = frozenset({"mem0"})

backend: NotBlankStr = Field(
default="mem0",
description="Memory backend name",
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Vendor name "mem0" used directly in production source code

Per the project's code conventions (CLAUDE.md), vendor names should only appear in DESIGN_SPEC.md provider lists, .claude/ skill files, or third-party import paths — not in project-owned source code, default field values, or tests. The literal string "mem0" appears as a hardcoded value across several changed files:

  • src/ai_company/memory/config.py:113_VALID_BACKENDS = frozenset({"mem0"})
  • src/ai_company/memory/config.py:116default="mem0" field default
  • src/ai_company/memory/factory.py:38if config.backend == "mem0":
  • src/ai_company/memory/factory.py:43backend="mem0" log kwarg
  • tests/unit/memory/test_factory.py:16CompanyMemoryConfig(backend="mem0")
  • tests/unit/memory/test_config.py:138, 144, 165, 175backend="mem0" usage

Consider using a symbolic constant (e.g., MEM0_BACKEND_NAME: Final[str] = "mem0" defined once in the memory package) so the raw vendor string is isolated to a single declaration point, and all other references use the constant.

Rule Used: CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ai_company/memory/config.py
Line: 113-118

Comment:
**Vendor name `"mem0"` used directly in production source code**

Per the project's code conventions (CLAUDE.md), vendor names should only appear in DESIGN_SPEC.md provider lists, `.claude/` skill files, or third-party import paths — not in project-owned source code, default field values, or tests. The literal string `"mem0"` appears as a hardcoded value across several changed files:

- `src/ai_company/memory/config.py:113``_VALID_BACKENDS = frozenset({"mem0"})`
- `src/ai_company/memory/config.py:116``default="mem0"` field default
- `src/ai_company/memory/factory.py:38``if config.backend == "mem0":`
- `src/ai_company/memory/factory.py:43``backend="mem0"` log kwarg
- `tests/unit/memory/test_factory.py:16``CompanyMemoryConfig(backend="mem0")`
- `tests/unit/memory/test_config.py:138`, `144`, `165`, `175``backend="mem0"` usage

Consider using a symbolic constant (e.g., `MEM0_BACKEND_NAME: Final[str] = "mem0"` defined once in the memory package) so the raw vendor string is isolated to a single declaration point, and all other references use the constant.

**Rule Used:** CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=6816cd03-d0e1-4fd0-9d04-2417487a584c))

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +42 to +49
vector_store: NotBlankStr = Field(
default="qdrant",
description="Vector store backend name",
)
history_store: NotBlankStr = Field(
default="sqlite",
description="History store backend name",
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

vector_store and history_store accept any non-blank string with no validation

Both fields accept arbitrary strings (NotBlankStr), which means values like "invalid-store", "postgres", or typos like "sqlit" will pass config validation and only fail at runtime when the backend attempts to initialize. Since the set of valid store backends is small and known at this stage ("qdrant" for vector, "sqlite" for history per the design spec), using a Literal type or an enum would give config-time errors with clear messages, consistent with how backend and level are constrained.

If open extensibility is intentional (to allow future store backends without code changes), a comment explaining this design choice would prevent future reviewers from treating it as an oversight.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/ai_company/memory/config.py
Line: 42-49

Comment:
**`vector_store` and `history_store` accept any non-blank string with no validation**

Both fields accept arbitrary strings (`NotBlankStr`), which means values like `"invalid-store"`, `"postgres"`, or typos like `"sqlit"` will pass config validation and only fail at runtime when the backend attempts to initialize. Since the set of valid store backends is small and known at this stage (`"qdrant"` for vector, `"sqlite"` for history per the design spec), using a `Literal` type or an enum would give config-time errors with clear messages, consistent with how `backend` and `level` are constrained.

If open extensibility is intentional (to allow future store backends without code changes), a comment explaining this design choice would prevent future reviewers from treating it as an oversight.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 30 out of 31 changed files in this pull request and generated 3 comments.


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

"/data/sub/../../../etc",
"/data/..",
"..",
"data/../secret",
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

Path traversal validation in MemoryStorageConfig is intended to handle Windows paths too (PureWindowsPath is used in the validator), but the parametrized bad_path cases only cover POSIX-style separators. Add a couple of Windows-style traversal examples (e.g. drive-letter and backslash variants) to ensure the validator behaves correctly on Windows inputs.

Suggested change
"data/../secret",
"data/../secret",
r"C:\data\..\secret",
r"..\secret",

Copilot uses AI. Check for mistakes.
5. [Communication Architecture](#5-communication-architecture) — 5.6 Conflict Resolution, 5.7 Meeting Protocol
6. [Task & Workflow Engine](#6-task--workflow-engine) — 6.5 Execution Loop, 6.6 Crash Recovery, **6.7 Graceful Shutdown**, **6.8 Workspace Isolation**, **6.9 Task Decomposability & Coordination Topology**
7. [Memory & Persistence](#7-memory--persistence) — 7.4 Shared Org Memory (Research Directions), **7.5 Operational Data Persistence**
7. [Memory & Persistence](#7-memory--persistence) — **7.5 Memory Backend Protocol**, 7.4 Shared Org Memory (Research Directions), **7.6 Operational Data Persistence**
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

The Table of Contents entry for section 7 lists 7.5 before 7.4; this is out of numeric order and doesn’t match the section numbering below. Please reorder the referenced subsections (7.4, 7.5, 7.6) so the TOC reflects the actual structure.

Suggested change
7. [Memory & Persistence](#7-memory--persistence)**7.5 Memory Backend Protocol**, 7.4 Shared Org Memory (Research Directions), **7.6 Operational Data Persistence**
7. [Memory & Persistence](#7-memory--persistence)7.4 Shared Org Memory (Research Directions), **7.5 Memory Backend Protocol**, **7.6 Operational Data Persistence**

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +15
# ── Backend lifecycle ──────────────────────────────────────────────

MEMORY_BACKEND_CONNECTING: Final[str] = "memory.backend.connecting"
MEMORY_BACKEND_CONNECTED: Final[str] = "memory.backend.connected"
MEMORY_BACKEND_CONNECTION_FAILED: Final[str] = "memory.backend.connection_failed"
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

PR description says 21 MEMORY_* event constants were added, but this module currently defines 28. Please either update the PR description/test plan to match the implemented set, or trim/merge constants so the count aligns with what’s documented.

Copilot uses AI. Check for mistakes.
Aureliolo added a commit that referenced this pull request Mar 10, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.1](ai-company-v0.1.0...ai-company-v0.1.1)
(2026-03-10)


### Features

* add autonomy levels and approval timeout policies
([#42](#42),
[#126](#126))
([#197](#197))
([eecc25a](eecc25a))
* add CFO cost optimization service with anomaly detection, reports, and
approval decisions
([#186](#186))
([a7fa00b](a7fa00b))
* add code quality toolchain (ruff, mypy, pre-commit, dependabot)
([#63](#63))
([36681a8](36681a8))
* add configurable cost tiers and subscription/quota-aware tracking
([#67](#67))
([#185](#185))
([9baedfa](9baedfa))
* add container packaging, Docker Compose, and CI pipeline
([#269](#269))
([435bdfe](435bdfe)),
closes [#267](#267)
* add coordination error taxonomy classification pipeline
([#146](#146))
([#181](#181))
([70c7480](70c7480))
* add cost-optimized, hierarchical, and auction assignment strategies
([#175](#175))
([ce924fa](ce924fa)),
closes [#173](#173)
* add design specification, license, and project setup
([8669a09](8669a09))
* add env var substitution and config file auto-discovery
([#77](#77))
([7f53832](7f53832))
* add FastestStrategy routing + vendor-agnostic cleanup
([#140](#140))
([09619cb](09619cb)),
closes [#139](#139)
* add HR engine and performance tracking
([#45](#45),
[#47](#47))
([#193](#193))
([2d091ea](2d091ea))
* add issue auto-search and resolution verification to PR review skill
([#119](#119))
([deecc39](deecc39))
* add memory retrieval, ranking, and context injection pipeline
([#41](#41))
([873b0aa](873b0aa))
* add pluggable MemoryBackend protocol with models, config, and events
([#180](#180))
([46cfdd4](46cfdd4))
* add pluggable MemoryBackend protocol with models, config, and events
([#32](#32))
([46cfdd4](46cfdd4))
* add pluggable PersistenceBackend protocol with SQLite implementation
([#36](#36))
([f753779](f753779))
* add progressive trust and promotion/demotion subsystems
([#43](#43),
[#49](#49))
([3a87c08](3a87c08))
* add retry handler, rate limiter, and provider resilience
([#100](#100))
([b890545](b890545))
* add SecOps security agent with rule engine, audit log, and ToolInvoker
integration ([#40](#40))
([83b7b6c](83b7b6c))
* add shared org memory and memory consolidation/archival
([#125](#125),
[#48](#48))
([4a0832b](4a0832b))
* design unified provider interface
([#86](#86))
([3e23d64](3e23d64))
* expand template presets, rosters, and add inheritance
([#80](#80),
[#81](#81),
[#84](#84))
([15a9134](15a9134))
* implement agent runtime state vs immutable config split
([#115](#115))
([4cb1ca5](4cb1ca5))
* implement AgentEngine core orchestrator
([#11](#11))
([#143](#143))
([f2eb73a](f2eb73a))
* implement basic tool system (registry, invocation, results)
([#15](#15))
([c51068b](c51068b))
* implement built-in file system tools
([#18](#18))
([325ef98](325ef98))
* implement communication foundation — message bus, dispatcher, and
messenger ([#157](#157))
([8e71bfd](8e71bfd))
* implement company template system with 7 built-in presets
([#85](#85))
([cbf1496](cbf1496))
* implement conflict resolution protocol
([#122](#122))
([#166](#166))
([e03f9f2](e03f9f2))
* implement core entity and role system models
([#69](#69))
([acf9801](acf9801))
* implement crash recovery with fail-and-reassign strategy
([#149](#149))
([e6e91ed](e6e91ed))
* implement engine extensions — Plan-and-Execute loop and call
categorization
([#134](#134),
[#135](#135))
([#159](#159))
([9b2699f](9b2699f))
* implement enterprise logging system with structlog
([#73](#73))
([2f787e5](2f787e5))
* implement graceful shutdown with cooperative timeout strategy
([#130](#130))
([6592515](6592515))
* implement hierarchical delegation and loop prevention
([#12](#12),
[#17](#17))
([6be60b6](6be60b6))
* implement LiteLLM driver and provider registry
([#88](#88))
([ae3f18b](ae3f18b)),
closes [#4](#4)
* implement LLM decomposition strategy and workspace isolation
([#174](#174))
([aa0eefe](aa0eefe))
* implement meeting protocol system
([#123](#123))
([ee7caca](ee7caca))
* implement message and communication domain models
([#74](#74))
([560a5d2](560a5d2))
* implement model routing engine
([#99](#99))
([d3c250b](d3c250b))
* implement parallel agent execution
([#22](#22))
([#161](#161))
([65940b3](65940b3))
* implement per-call cost tracking service
([#7](#7))
([#102](#102))
([c4f1f1c](c4f1f1c))
* implement personality injection and system prompt construction
([#105](#105))
([934dd85](934dd85))
* implement single-task execution lifecycle
([#21](#21))
([#144](#144))
([c7e64e4](c7e64e4))
* implement subprocess sandbox for tool execution isolation
([#131](#131))
([#153](#153))
([3c8394e](3c8394e))
* implement task assignment subsystem with pluggable strategies
([#172](#172))
([c7f1b26](c7f1b26)),
closes [#26](#26)
[#30](#30)
* implement task decomposition and routing engine
([#14](#14))
([9c7fb52](9c7fb52))
* implement Task, Project, Artifact, Budget, and Cost domain models
([#71](#71))
([81eabf1](81eabf1))
* implement tool permission checking
([#16](#16))
([833c190](833c190))
* implement YAML config loader with Pydantic validation
([#59](#59))
([ff3a2ba](ff3a2ba))
* implement YAML config loader with Pydantic validation
([#75](#75))
([ff3a2ba](ff3a2ba))
* initialize project with uv, hatchling, and src layout
([39005f9](39005f9))
* initialize project with uv, hatchling, and src layout
([#62](#62))
([39005f9](39005f9))
* Litestar REST API, WebSocket feed, and approval queue (M6)
([#189](#189))
([29fcd08](29fcd08))
* make TokenUsage.total_tokens a computed field
([#118](#118))
([c0bab18](c0bab18)),
closes [#109](#109)
* parallel tool execution in ToolInvoker.invoke_all
([#137](#137))
([58517ee](58517ee))
* testing framework, CI pipeline, and M0 gap fixes
([#64](#64))
([f581749](f581749))
* wire all modules into observability system
([#97](#97))
([f7a0617](f7a0617))


### Bug Fixes

* address Greptile post-merge review findings from PRs
[#170](https://github.com/Aureliolo/ai-company/issues/170)-[#175](https://github.com/Aureliolo/ai-company/issues/175)
([#176](#176))
([c5ca929](c5ca929))
* address post-merge review feedback from PRs
[#164](https://github.com/Aureliolo/ai-company/issues/164)-[#167](https://github.com/Aureliolo/ai-company/issues/167)
([#170](#170))
([3bf897a](3bf897a)),
closes [#169](#169)
* enforce strict mypy on test files
([#89](#89))
([aeeff8c](aeeff8c))
* harden Docker sandbox, MCP bridge, and code runner
([#50](#50),
[#53](#53))
([d5e1b6e](d5e1b6e))
* harden git tools security + code quality improvements
([#150](#150))
([000a325](000a325))
* harden subprocess cleanup, env filtering, and shutdown resilience
([#155](#155))
([d1fe1fb](d1fe1fb))
* incorporate post-merge feedback + pre-PR review fixes
([#164](#164))
([c02832a](c02832a))
* pre-PR review fixes for post-merge findings
([#183](#183))
([26b3108](26b3108))
* strengthen immutability for BaseTool schema and ToolInvoker boundaries
([#117](#117))
([7e5e861](7e5e861))


### Performance

* harden non-inferable principle implementation
([#195](#195))
([02b5f4e](02b5f4e)),
closes [#188](#188)


### Refactoring

* adopt NotBlankStr across all models
([#108](#108))
([#120](#120))
([ef89b90](ef89b90))
* extract _SpendingTotals base class from spending summary models
([#111](#111))
([2f39c1b](2f39c1b))
* harden BudgetEnforcer with error handling, validation extraction, and
review fixes
([#182](#182))
([c107bf9](c107bf9))
* harden personality profiles, department validation, and template
rendering ([#158](#158))
([10b2299](10b2299))
* pre-PR review improvements for ExecutionLoop + ReAct loop
([#124](#124))
([8dfb3c0](8dfb3c0))
* split events.py into per-domain event modules
([#136](#136))
([e9cba89](e9cba89))


### Documentation

* add ADR-001 memory layer evaluation and selection
([#178](#178))
([db3026f](db3026f)),
closes [#39](#39)
* add agent scaling research findings to DESIGN_SPEC
([#145](#145))
([57e487b](57e487b))
* add CLAUDE.md, contributing guide, and dev documentation
([#65](#65))
([55c1025](55c1025)),
closes [#54](#54)
* add crash recovery, sandboxing, analytics, and testing decisions
([#127](#127))
([5c11595](5c11595))
* address external review feedback with MVP scope and new protocols
([#128](#128))
([3b30b9a](3b30b9a))
* expand design spec with pluggable strategy protocols
([#121](#121))
([6832db6](6832db6))
* finalize 23 design decisions (ADR-002)
([#190](#190))
([8c39742](8c39742))
* update project docs for M2.5 conventions and add docs-consistency
review agent
([#114](#114))
([99766ee](99766ee))


### Tests

* add e2e single agent integration tests
([#24](#24))
([#156](#156))
([f566fb4](f566fb4))
* add provider adapter integration tests
([#90](#90))
([40a61f4](40a61f4))


### CI/CD

* add Release Please for automated versioning and GitHub Releases
([#278](#278))
([a488758](a488758))
* bump actions/checkout from 4 to 6
([#95](#95))
([1897247](1897247))
* bump actions/upload-artifact from 4 to 7
([#94](#94))
([27b1517](27b1517))
* harden CI/CD pipeline
([#92](#92))
([ce4693c](ce4693c))
* split vulnerability scans into critical-fail and high-warn tiers
([#277](#277))
([aba48af](aba48af))


### Maintenance

* add /worktree skill for parallel worktree management
([#171](#171))
([951e337](951e337))
* add design spec context loading to research-link skill
([8ef9685](8ef9685))
* add post-merge-cleanup skill
([#70](#70))
([f913705](f913705))
* add pre-pr-review skill and update CLAUDE.md
([#103](#103))
([92e9023](92e9023))
* add research-link skill and rename skill files to SKILL.md
([#101](#101))
([651c577](651c577))
* bump aiosqlite from 0.21.0 to 0.22.1
([#191](#191))
([3274a86](3274a86))
* bump pyyaml from 6.0.2 to 6.0.3 in the minor-and-patch group
([#96](#96))
([0338d0c](0338d0c))
* bump ruff from 0.15.4 to 0.15.5
([a49ee46](a49ee46))
* fix M0 audit items
([#66](#66))
([c7724b5](c7724b5))
* pin setup-uv action to full SHA
([#281](#281))
([4448002](4448002))
* post-audit cleanup — PEP 758, loggers, bug fixes, refactoring, tests,
hookify rules
([#148](#148))
([c57a6a9](c57a6a9))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
Aureliolo added a commit that referenced this pull request Mar 11, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.0](v0.0.0...v0.1.0)
(2026-03-11)


### Features

* add autonomy levels and approval timeout policies
([#42](#42),
[#126](#126))
([#197](#197))
([eecc25a](eecc25a))
* add CFO cost optimization service with anomaly detection, reports, and
approval decisions
([#186](#186))
([a7fa00b](a7fa00b))
* add code quality toolchain (ruff, mypy, pre-commit, dependabot)
([#63](#63))
([36681a8](36681a8))
* add configurable cost tiers and subscription/quota-aware tracking
([#67](#67))
([#185](#185))
([9baedfa](9baedfa))
* add container packaging, Docker Compose, and CI pipeline
([#269](#269))
([435bdfe](435bdfe)),
closes [#267](#267)
* add coordination error taxonomy classification pipeline
([#146](#146))
([#181](#181))
([70c7480](70c7480))
* add cost-optimized, hierarchical, and auction assignment strategies
([#175](#175))
([ce924fa](ce924fa)),
closes [#173](#173)
* add design specification, license, and project setup
([8669a09](8669a09))
* add env var substitution and config file auto-discovery
([#77](#77))
([7f53832](7f53832))
* add FastestStrategy routing + vendor-agnostic cleanup
([#140](#140))
([09619cb](09619cb)),
closes [#139](#139)
* add HR engine and performance tracking
([#45](#45),
[#47](#47))
([#193](#193))
([2d091ea](2d091ea))
* add issue auto-search and resolution verification to PR review skill
([#119](#119))
([deecc39](deecc39))
* add mandatory JWT + API key authentication
([#256](#256))
([c279cfe](c279cfe))
* add memory retrieval, ranking, and context injection pipeline
([#41](#41))
([873b0aa](873b0aa))
* add pluggable MemoryBackend protocol with models, config, and events
([#180](#180))
([46cfdd4](46cfdd4))
* add pluggable MemoryBackend protocol with models, config, and events
([#32](#32))
([46cfdd4](46cfdd4))
* add pluggable output scan response policies
([#263](#263))
([b9907e8](b9907e8))
* add pluggable PersistenceBackend protocol with SQLite implementation
([#36](#36))
([f753779](f753779))
* add progressive trust and promotion/demotion subsystems
([#43](#43),
[#49](#49))
([3a87c08](3a87c08))
* add retry handler, rate limiter, and provider resilience
([#100](#100))
([b890545](b890545))
* add SecOps security agent with rule engine, audit log, and ToolInvoker
integration ([#40](#40))
([83b7b6c](83b7b6c))
* add shared org memory and memory consolidation/archival
([#125](#125),
[#48](#48))
([4a0832b](4a0832b))
* design unified provider interface
([#86](#86))
([3e23d64](3e23d64))
* expand template presets, rosters, and add inheritance
([#80](#80),
[#81](#81),
[#84](#84))
([15a9134](15a9134))
* implement agent runtime state vs immutable config split
([#115](#115))
([4cb1ca5](4cb1ca5))
* implement AgentEngine core orchestrator
([#11](#11))
([#143](#143))
([f2eb73a](f2eb73a))
* implement AuditRepository for security audit log persistence
([#279](#279))
([94bc29f](94bc29f))
* implement basic tool system (registry, invocation, results)
([#15](#15))
([c51068b](c51068b))
* implement built-in file system tools
([#18](#18))
([325ef98](325ef98))
* implement communication foundation — message bus, dispatcher, and
messenger ([#157](#157))
([8e71bfd](8e71bfd))
* implement company template system with 7 built-in presets
([#85](#85))
([cbf1496](cbf1496))
* implement conflict resolution protocol
([#122](#122))
([#166](#166))
([e03f9f2](e03f9f2))
* implement core entity and role system models
([#69](#69))
([acf9801](acf9801))
* implement crash recovery with fail-and-reassign strategy
([#149](#149))
([e6e91ed](e6e91ed))
* implement engine extensions — Plan-and-Execute loop and call
categorization
([#134](#134),
[#135](#135))
([#159](#159))
([9b2699f](9b2699f))
* implement enterprise logging system with structlog
([#73](#73))
([2f787e5](2f787e5))
* implement graceful shutdown with cooperative timeout strategy
([#130](#130))
([6592515](6592515))
* implement hierarchical delegation and loop prevention
([#12](#12),
[#17](#17))
([6be60b6](6be60b6))
* implement LiteLLM driver and provider registry
([#88](#88))
([ae3f18b](ae3f18b)),
closes [#4](#4)
* implement LLM decomposition strategy and workspace isolation
([#174](#174))
([aa0eefe](aa0eefe))
* implement meeting protocol system
([#123](#123))
([ee7caca](ee7caca))
* implement message and communication domain models
([#74](#74))
([560a5d2](560a5d2))
* implement model routing engine
([#99](#99))
([d3c250b](d3c250b))
* implement parallel agent execution
([#22](#22))
([#161](#161))
([65940b3](65940b3))
* implement per-call cost tracking service
([#7](#7))
([#102](#102))
([c4f1f1c](c4f1f1c))
* implement personality injection and system prompt construction
([#105](#105))
([934dd85](934dd85))
* implement single-task execution lifecycle
([#21](#21))
([#144](#144))
([c7e64e4](c7e64e4))
* implement subprocess sandbox for tool execution isolation
([#131](#131))
([#153](#153))
([3c8394e](3c8394e))
* implement task assignment subsystem with pluggable strategies
([#172](#172))
([c7f1b26](c7f1b26)),
closes [#26](#26)
[#30](#30)
* implement task decomposition and routing engine
([#14](#14))
([9c7fb52](9c7fb52))
* implement Task, Project, Artifact, Budget, and Cost domain models
([#71](#71))
([81eabf1](81eabf1))
* implement tool permission checking
([#16](#16))
([833c190](833c190))
* implement YAML config loader with Pydantic validation
([#59](#59))
([ff3a2ba](ff3a2ba))
* implement YAML config loader with Pydantic validation
([#75](#75))
([ff3a2ba](ff3a2ba))
* initialize project with uv, hatchling, and src layout
([39005f9](39005f9))
* initialize project with uv, hatchling, and src layout
([#62](#62))
([39005f9](39005f9))
* Litestar REST API, WebSocket feed, and approval queue (M6)
([#189](#189))
([29fcd08](29fcd08))
* make TokenUsage.total_tokens a computed field
([#118](#118))
([c0bab18](c0bab18)),
closes [#109](#109)
* parallel tool execution in ToolInvoker.invoke_all
([#137](#137))
([58517ee](58517ee))
* testing framework, CI pipeline, and M0 gap fixes
([#64](#64))
([f581749](f581749))
* wire all modules into observability system
([#97](#97))
([f7a0617](f7a0617))


### Bug Fixes

* address Greptile post-merge review findings from PRs
[#170](https://github.com/Aureliolo/ai-company/issues/170)-[#175](https://github.com/Aureliolo/ai-company/issues/175)
([#176](#176))
([c5ca929](c5ca929))
* address post-merge review feedback from PRs
[#164](https://github.com/Aureliolo/ai-company/issues/164)-[#167](https://github.com/Aureliolo/ai-company/issues/167)
([#170](#170))
([3bf897a](3bf897a)),
closes [#169](#169)
* enforce strict mypy on test files
([#89](#89))
([aeeff8c](aeeff8c))
* harden Docker sandbox, MCP bridge, and code runner
([#50](#50),
[#53](#53))
([d5e1b6e](d5e1b6e))
* harden git tools security + code quality improvements
([#150](#150))
([000a325](000a325))
* harden subprocess cleanup, env filtering, and shutdown resilience
([#155](#155))
([d1fe1fb](d1fe1fb))
* incorporate post-merge feedback + pre-PR review fixes
([#164](#164))
([c02832a](c02832a))
* pre-PR review fixes for post-merge findings
([#183](#183))
([26b3108](26b3108))
* resolve circular imports, bump litellm, fix release tag format
([#286](#286))
([a6659b5](a6659b5))
* strengthen immutability for BaseTool schema and ToolInvoker boundaries
([#117](#117))
([7e5e861](7e5e861))


### Performance

* harden non-inferable principle implementation
([#195](#195))
([02b5f4e](02b5f4e)),
closes [#188](#188)


### Refactoring

* adopt NotBlankStr across all models
([#108](#108))
([#120](#120))
([ef89b90](ef89b90))
* extract _SpendingTotals base class from spending summary models
([#111](#111))
([2f39c1b](2f39c1b))
* harden BudgetEnforcer with error handling, validation extraction, and
review fixes
([#182](#182))
([c107bf9](c107bf9))
* harden personality profiles, department validation, and template
rendering ([#158](#158))
([10b2299](10b2299))
* pre-PR review improvements for ExecutionLoop + ReAct loop
([#124](#124))
([8dfb3c0](8dfb3c0))
* split events.py into per-domain event modules
([#136](#136))
([e9cba89](e9cba89))


### Documentation

* add ADR-001 memory layer evaluation and selection
([#178](#178))
([db3026f](db3026f)),
closes [#39](#39)
* add agent scaling research findings to DESIGN_SPEC
([#145](#145))
([57e487b](57e487b))
* add CLAUDE.md, contributing guide, and dev documentation
([#65](#65))
([55c1025](55c1025)),
closes [#54](#54)
* add crash recovery, sandboxing, analytics, and testing decisions
([#127](#127))
([5c11595](5c11595))
* address external review feedback with MVP scope and new protocols
([#128](#128))
([3b30b9a](3b30b9a))
* expand design spec with pluggable strategy protocols
([#121](#121))
([6832db6](6832db6))
* finalize 23 design decisions (ADR-002)
([#190](#190))
([8c39742](8c39742))
* update project docs for M2.5 conventions and add docs-consistency
review agent
([#114](#114))
([99766ee](99766ee))


### Tests

* add e2e single agent integration tests
([#24](#24))
([#156](#156))
([f566fb4](f566fb4))
* add provider adapter integration tests
([#90](#90))
([40a61f4](40a61f4))


### CI/CD

* add Release Please for automated versioning and GitHub Releases
([#278](#278))
([a488758](a488758))
* bump actions/checkout from 4 to 6
([#95](#95))
([1897247](1897247))
* bump actions/upload-artifact from 4 to 7
([#94](#94))
([27b1517](27b1517))
* bump anchore/scan-action from 6.5.1 to 7.3.2
([#271](#271))
([80a1c15](80a1c15))
* bump docker/build-push-action from 6.19.2 to 7.0.0
([#273](#273))
([dd0219e](dd0219e))
* bump docker/login-action from 3.7.0 to 4.0.0
([#272](#272))
([33d6238](33d6238))
* bump docker/metadata-action from 5.10.0 to 6.0.0
([#270](#270))
([baee04e](baee04e))
* bump docker/setup-buildx-action from 3.12.0 to 4.0.0
([#274](#274))
([5fc06f7](5fc06f7))
* bump sigstore/cosign-installer from 3.9.1 to 4.1.0
([#275](#275))
([29dd16c](29dd16c))
* harden CI/CD pipeline
([#92](#92))
([ce4693c](ce4693c))
* split vulnerability scans into critical-fail and high-warn tiers
([#277](#277))
([aba48af](aba48af))


### Maintenance

* add /worktree skill for parallel worktree management
([#171](#171))
([951e337](951e337))
* add design spec context loading to research-link skill
([8ef9685](8ef9685))
* add post-merge-cleanup skill
([#70](#70))
([f913705](f913705))
* add pre-pr-review skill and update CLAUDE.md
([#103](#103))
([92e9023](92e9023))
* add research-link skill and rename skill files to SKILL.md
([#101](#101))
([651c577](651c577))
* bump aiosqlite from 0.21.0 to 0.22.1
([#191](#191))
([3274a86](3274a86))
* bump pyyaml from 6.0.2 to 6.0.3 in the minor-and-patch group
([#96](#96))
([0338d0c](0338d0c))
* bump ruff from 0.15.4 to 0.15.5
([a49ee46](a49ee46))
* fix M0 audit items
([#66](#66))
([c7724b5](c7724b5))
* **main:** release ai-company 0.1.1
([#282](#282))
([2f4703d](2f4703d))
* pin setup-uv action to full SHA
([#281](#281))
([4448002](4448002))
* post-audit cleanup — PEP 758, loggers, bug fixes, refactoring, tests,
hookify rules
([#148](#148))
([c57a6a9](c57a6a9))

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

---------

Signed-off-by: Aurelio <19254254+Aureliolo@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.

Design individual agent memory interface: working, episodic, semantic, procedural (DESIGN_SPEC §7.1-7.3)

2 participants