Quickstart: Initialize New Agent Project¶
Goal: Get developers from "zero to working agent project" in under 30 seconds
For End Users¶
Installation¶
pip install holodeck
Create Your First Agent Project¶
# Create a conversational chatbot (default template)
holodeck init my-chatbot
# Or choose a different template
holodeck init research-tool --template research
holodeck init support-bot --template customer-support
# Add metadata
holodeck init my-agent --description "My AI assistant" --author "Alice"
What You Get¶
my-chatbot/
├── agent.yaml # Main agent configuration with embedded test cases
├── instructions/
│ └── system-prompt.md # Agent system prompt (edit this!)
├── tools/
│ └── README.md # How to add custom functions
├── data/
│ └── faqs.md # Sample data for vector search
└── .gitignore # Standard Python ignores
Next Steps¶
# Test your agent
cd my-chatbot
holodeck test agent.yaml
# Chat interactively
holodeck chat agent.yaml
# Deploy locally
holodeck deploy agent.yaml --port 8000
For Developers (Implementation Guide)¶
Module Overview¶
CLI Command (src/holodeck/cli/commands/init.py):
- Entry point: @click.command('init')
- Parse arguments (project_name, template, description, author, force)
- Validate inputs
- Call ProjectInitializer.initialize() from project_init.py
- Format and display result
Core Logic (src/holodeck/cli/utils/project_init.py):
- ProjectInitializer class:
- validate_inputs(ProjectInitInput) → ValidationError
- load_template(template_name) → TemplateManifest
- initialize(ProjectInitInput) → ProjectInitResult
- Returns structured result with success/errors
Template Rendering (src/holodeck/lib/template_engine.py):
- TemplateRenderer class:
- render_template(path, variables) → str
- validate_agent_config(yaml_content) → AgentConfig (VALIDATION GATE)
- render_and_validate(path, variables) → str (safe to write after this)
- Strict validation: render → validate → write
Data Models (src/holodeck/models/):
- ProjectInitInput: Pydantic model for CLI args
- ProjectInitResult: Pydantic model for outcome
- TemplateManifest: Pydantic model for template metadata
- AgentConfig: Imported from holodeck.core (reused, not duplicated)
Templates (src/holodeck/templates/):
- conversational/, research/, customer-support/ directories
- Each template:
- manifest.yaml: Template metadata and variables
- agent.yaml.j2: Jinja2 template for agent config (includes test_cases field)
- instructions/system-prompt.md.j2: System prompt template
- tools/README.md.j2: Tools directory guidance
- data/*: Sample data files
- .gitignore: Standard Python ignores
Key Implementation Patterns¶
Pattern 1: Template Manifest Validation¶
# Load and validate template manifest
manifest = TemplateManifest.model_validate(
yaml.safe_load(open(f'templates/{template_name}/manifest.yaml'))
)
# Manifest automatically validates:
# - Required fields present (name, version, variables)
# - Variable types correct
# - No invalid variable names
# - Version is valid semver
Pattern 2: Template Rendering with Strict Validation¶
# Render Jinja2 template
template = env.get_template('agent.yaml.j2')
rendered_yaml = template.render(variables)
# CRITICAL: Validate rendered YAML against schema BEFORE writing
config = AgentConfig.model_validate(
yaml.safe_load(rendered_yaml)
)
# Only now is it safe to write to disk
with open(f'{project_dir}/agent.yaml', 'w') as f:
f.write(rendered_yaml)
Pattern 3: All-or-Nothing Project Creation¶
try:
# Create directory
project_dir.mkdir(parents=True, exist_ok=False)
# Render and validate each file
for file_spec in manifest.files:
content = render_and_validate(file_spec, variables)
(project_dir / file_spec.path).write_text(content)
# Success!
return ProjectInitResult(success=True, ...)
except Exception as e:
# CLEANUP: Remove partially created directory
shutil.rmtree(project_dir)
return ProjectInitResult(success=False, errors=[str(e)])
Pattern 4: Input Validation¶
# Validate project name
if not re.match(r'^[a-zA-Z0-9_-]+$', project_name):
raise ValidationError(f"Invalid project name: {project_name}")
# Validate template exists
if template not in AVAILABLE_TEMPLATES:
raise ValidationError(f"Unknown template: {template}")
# Validate directory doesn't exist (unless force=True)
if project_dir.exists() and not force:
raise ValidationError(f"Directory already exists: {project_dir}")
File Structure for Templates¶
Each template directory must contain manifest.yaml:
name: conversational
display_name: Conversational Agent
description: Multi-turn AI conversation assistant
category: conversational-ai
version: 1.0.0
variables:
project_name:
type: string
required: true
description: "Name of the agent project"
description:
type: string
required: false
default: "TODO: Add agent description"
author:
type: string
required: false
default: ""
model_temperature:
type: number
default: 0.7
defaults:
model.provider: "openai"
model.name: "gpt-4o"
files:
agent.yaml:
path: agent.yaml
template: true
required: true
instructions/system-prompt.md:
path: instructions/system-prompt.md
template: true
required: true
tools/README.md:
path: tools/README.md
template: true
required: true
data/faqs.md:
path: data/faqs.md
template: false
required: false
.gitignore:
path: .gitignore
template: false
required: true
Testing Strategy¶
Unit Tests (tests/unit/):
- test_project_init.py: ProjectInitializer logic (isolation, mocking filesystem)
- test_cli_init_command.py: CLI argument parsing and error handling
- test_template_engine.py: Jinja2 rendering and validation
Integration Tests (tests/integration/):
- test_init_templates.py: Full flow (render → validate → create for each template)
- test_agent_config_compliance.py: Verify generated agent.yaml matches schema
Test Fixtures (tests/fixtures/):
- generated_projects/: Temporary directories for integration tests
- Template manifests and example variables for testing
Coverage Target: 80% minimum (per Constitution)
Error Handling¶
| Scenario | Error Message | Exit Code | Cleanup |
|---|---|---|---|
| Invalid name | "Invalid project name: 'bad!name'" | 1 | None |
| Template not found | "Unknown template: 'badtemplate'" | 1 | None |
| Dir exists (no force) | "Project 'my-agent' already exists" | 1 | None |
| Permission denied | "Cannot write to directory; check permissions" | 1 | Remove partial dir |
| Disk full | "Insufficient disk space" | 1 | Remove partial dir |
| Invalid agent.yaml | "agent.yaml validation error: [details]" | 1 | Remove full dir |
| Ctrl+C | "Initialization cancelled" | 130 | Remove partial dir |
Integration Points¶
Dependency on 001-cli-core-engine¶
- Reuses:
AgentConfigPydantic model (schema source of truth) - Depends on:
holodeckCLI command structure (Click setup) - Provides to: Generated agent.yaml files that feed into Agent Engine
Future Integration (v0.2+)¶
- Custom templates: Template registry/marketplace
- Interactive mode: Prompts for customization
- Git integration: Auto-initialize git repos
- Environment setup: Auto-install dependencies
Success Metrics¶
✓ SC-001: < 30 seconds initialization time
✓ SC-002: Generated agent.yaml is parseable (0 validation errors)
✓ SC-003: All template files present and formatted
✓ SC-004: 80%+ of first-time users succeed without errors
✓ SC-005: Users find customization patterns within 2 minutes
✓ SC-006: Sample test cases validate perfectly against schema
✓ SC-007: Can run holodeck test immediately after init
Troubleshooting¶
"Permission denied: Cannot write to current directory"¶
- Solution: Run
cdto a directory you own or have write permissions for - Check:
ls -ld .to see directory permissions
"Project 'my-agent' already exists"¶
- Solution 1: Use
holodeck init my-agent-v2(different name) - Solution 2: Use
holodeck init my-agent --forceto overwrite
"Unknown template: 'mytemplate'"¶
- Solution: Use one of:
conversational,research,customer-support - List:
holodeck init --helpto see available templates
Generated agent.yaml fails validation¶
- This should not happen if template is valid
- Solution: Reinstall HoloDeck:
pip install --upgrade holodeck - Report bug with template name if issue persists
Architecture Diagram¶
User: holodeck init my-chatbot --template conversational
↓
CLI Command (init.py)
├─ Validate: name, template, permissions
├─ Parse: ProjectInitInput
└─ Call: ProjectInitializer.initialize()
↓
ProjectInitializer (project_init.py)
├─ Load: TemplateManifest from conversational/manifest.yaml
├─ For each file in manifest:
│ └─ Render + Validate via TemplateRenderer
├─ Create: project directory + files
└─ Return: ProjectInitResult
↓
TemplateRenderer (template_engine.py)
├─ Render: agent.yaml.j2 with variables
├─ Validate: rendered YAML against AgentConfig [GATE]
└─ Return: validated content
↓
Result
├─ Success → Display next steps
└─ Error → Show validation errors + cleanup
This architecture ensures: - ✅ Template flexibility (Jinja2) - ✅ Strict validation (AgentConfig model) - ✅ User-friendly errors (clear messages) - ✅ Safety (all-or-nothing semantics)