Implementation Plan: CLI & Core Agent Engine (v0.1)¶
Branch: 001-cli-core-engine | Date: 2025-10-19 | Spec: /docs/product-specs/001-cli-core-engine/spec.md
Input: Feature specification from /docs/product-specs/001-cli-core-engine/spec.md
Focus: User Story 1 - Define Agent Configuration (Priority: P1)
Note: This plan focuses on US1 only. US2 and later user stories will be planned separately.
Summary¶
US1 Goal: Enable developers to define AI agents through pure YAML configuration. The agent.yaml schema must support model providers (OpenAI, Azure, Anthropic), instructions (file or inline), tool definitions (vectorstore, function, MCP, prompt), and evaluations with flexible model configuration. Configuration MUST be validated with clear error messages. This is foundational—agents cannot execute without a valid configuration.
Technical Approach:
- Design agent.yaml schema (Pydantic models) with comprehensive validation
- Implement ConfigLoader to parse YAML and validate against schema
- Create type-safe data structures (Agent, Tool, Evaluation, TestCase entities)
- Implement graceful error handling with actionable messages
- Support configuration composition (file references, inline values)
Technical Context¶
Language/Version: Python 3.10+ (per CLAUDE.md) Primary Dependencies:
- Pydantic v2 (schema validation, data models)
- PyYAML (configuration parsing)
- python-dotenv (environment variable support for API keys)
- Semantic Kernel (agent framework base)
Storage: File-based (agent.yaml, instructions files, data sources); no database required for v0.1 Testing: pytest (unit + integration tests for config loading and validation) Target Platform: Linux/macOS/Windows (Python CLI, platform-agnostic) Project Type: Single Python package (CLI-first) Performance Goals: Configuration parsing <100ms per agent.yaml file (measured in tests) Constraints:
- Zero external API calls during config validation (validation must be synchronous, fast)
- All validation errors must be human-readable (surface Pydantic errors with custom messages)
- Support for environment variable interpolation in config (e.g.,
${OPENAI_API_KEY})
Scale/Scope:
- Single agent configuration per agent.yaml (no multi-agent mixing in one file)
- Support up to 50 tools per agent
- Support up to 100 test cases per agent.yaml
Constitution Check¶
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principle | Requirement | US1 Status | Justification |
|---|---|---|---|
| I. No-Code-First | Agent config via YAML only, no Python code required | ✅ PASS | Schema driven by Pydantic models; configuration entirely declarative |
| II. MCP for APIs | API integrations use MCP servers, not custom tools | ✅ PASS | US1 defines tool type definitions; MCP tool type already in schema |
| III. Test-First Multimodal | Test cases support multimodal inputs + expected_tools | ✅ PASS | Test case schema includes file support, expected_tools field |
| IV. OpenTelemetry Native | Tracing/metrics instrumentation from day one | ⚠️ DEFERRED | US1 focuses on config schema; observability integration in Phase 3+ (US3) |
| V. Evaluation Flexibility | Model config at 3 levels (global/run/metric) | ✅ PASS | EvaluationMetric schema supports per-metric model override |
Gate Result: ✅ PASS - No blocking violations. Observability deferred to agent execution phase (post-US1).
Complexity Tracking: None - all constraints can be met with straightforward Pydantic schema.
Project Structure¶
Documentation (this feature)¶
docs/product-specs/[###-feature]/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
├── contracts/ # Phase 1 output
└── tasks.md # Phase 2 output
Source Code (repository root)¶
src/holodeck/
├── config/ # US1: Configuration loading & validation
│ ├── __init__.py
│ ├── schema.py # Pydantic models (Agent, Tool, Evaluation, TestCase)
│ ├── loader.py # ConfigLoader (YAML parsing)
│ ├── validator.py # Validation logic & error handling
│ └── defaults.py # Default configurations & templates
├── models/ # Data entities
│ ├── __init__.py
│ ├── agent.py # Agent entity
│ ├── tool.py # Tool entity
│ ├── evaluation.py # EvaluationMetric entity
│ └── test_case.py # TestCase entity
├── cli/ # CLI entry point (separate from US1)
│ ├── __init__.py
│ └── main.py
└── lib/ # Shared utilities
├── __init__.py
└── errors.py # Custom exception types
tests/
├── unit/
│ ├── test_config_schema.py # Pydantic model validation tests
│ ├── test_config_loader.py # YAML parsing tests
│ ├── test_config_validation.py # Error message tests
│ └── conftest.py
├── integration/
│ ├── test_config_end_to_end.py # Full config loading workflows
│ └── conftest.py
└── fixtures/
├── agents/
│ ├── valid_agent.yaml
│ ├── minimal_agent.yaml
│ └── invalid_agent.yaml
└── tools/
Structure Decision: Single Python package (Option 1). US1 requires:
src/holodeck/config/: Core configuration loading (ConfigLoader, schema validation)src/holodeck/models/: Type-safe data models (Pydantic)tests/: Unit + integration tests for config loading and validation
Complexity Tracking¶
No violations - all constraints can be met.
Implementation Strategy¶
Phase 0: Research & Decisions (Completed)¶
From clarifications session 2025-10-19:
- SearchResult Type → Structured {matched_content, metadata_dict, source_reference, relevance_score}
- Tool Error Handling → Graceful degradation (log + empty string), extensible via middleware
- Chat Memory → Configurable (v0.1 CLI: in-memory last N messages)
- Session Isolation → Via session_id, serialized per session
- Evaluation Failures → Soft failure (ERROR status, log details, test continues)
All unknowns resolved. No NEEDS CLARIFICATION remaining.
Phase 1: Design (This Document - COMPLETE)¶
✅ data-model.md → Complete entity definitions ✅ contracts/config_loader_interface.md → Interface contract ✅ quickstart.md → Test scenarios & acceptance criteria ✅ project structure → Directories defined ✅ Constitution Check → PASS (no violations)
Phase 2: Implementation¶
Tasks for ConfigLoader implementation:
- Define Pydantic models (schema.py)
- Implement ConfigLoader class (loader.py)
- Error handling & validation (validator.py)
- Unit tests (test_config_schema.py, test_config_loader.py)
- Integration tests (test_config_end_to_end.py)
- Fixtures (agent YAML files for testing)
Next Steps¶
- Write tasks.md with implementation tasks for User Story 1
- Execute tasks in order (Phase 1 setup, Phase 2 foundational, Phase 3 US1)
- After US1 completes: Plan User Story 2
Design Decisions¶
| Decision | Choice | Rationale |
|---|---|---|
| Config Schema | Pydantic v2 | Type-safe, built-in validation, excellent error messages |
| YAML Parser | PyYAML | Industry standard, simple API, adequate performance |
| Error Handling | Custom exceptions + human messages | Constitution requires clear, actionable errors |
| Tool Validation | Type-discriminated union (Tool type field) | Clean separation of concerns, extensible for new tool types |
| File Resolution | Relative to agent.yaml directory | Portable, matches industry convention (Docker, k8s, etc.) |
| Env Var Pattern | ${VAR_NAME} |
YAML-safe, matches HashiCorp/Terraform convention |
Risks & Mitigations¶
| Risk | Mitigation |
|---|---|
| Pydantic error messages too technical | Custom validator wraps Pydantic errors in human language |
| Circular file references | Validate file exists before loading to prevent infinite loops |
| Large YAML files slow to parse | Performance budget (< 100ms) covered in tests |
| Complex nested tool validation | Type-discriminated union keeps validation per-tool-type simple |
Appendix: File Structure Decision¶
docs/product-specs/001-cli-core-engine/
├── spec.md # Original feature spec (read-only)
├── plan.md # This file (Phase 1 planning)
├── data-model.md # Phase 1 design output (entity definitions)
├── quickstart.md # Phase 1 design output (test scenarios)
├── contracts/
│ └── config_loader_interface.md # Phase 1 design output (interface contract)
└── tasks.md # Phase 2 output
This structure ensures:
- Clear separation of planning (Phase 1) from implementation (Phase 2+)
- Frozen spec.md vs. living plan.md
- Design artifacts (data-model, contracts, quickstart) before tasks
- Tasks are generated from complete design