ADR-009: CODI Command Interface (v4) - Part 2: Technical Implementation
Document Specification Block
Document: ADR-009-v4-codi-command-interface-part2-technical
Version: 1.0.0
Purpose: Provide complete technical implementation blueprint for CODI command interface
Audience: Engineering teams, AI agents implementing the system, architects
Date Created: 2025-08-27
Date Modified: 2025-08-31
Status: DRAFT
Table of Contents
- 8. Implementation Blueprint
- 9. Testing Strategy
- 10. Security Considerations
- 11. Performance Characteristics
- 12. Operational Considerations
- 13. Migration Strategy
- 14. Appendix
- 15. Review & Approval
- 16. QA Review Block
8. Implementation Blueprint 🔴 REQUIRED
8.1 Architecture Diagram
8.2 Dependencies
# cargo.toml for CODI
[package]
name = "codi"
version = "1.0.0"
edition = "2021"
[dependencies]
clap = { version = "4.4", features = ["derive"] }
tokio = { version = "1.35", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9"
anyhow = "1.0"
dirs = "5.0"
rusqlite = { version = "0.30", features = ["bundled"] }
reqwest = { version = "0.11", features = ["json"] }
tracing = "0.1"
tracing-subscriber = "0.3"
uuid = { version = "1.6", features = ["v4"] }
chrono = { version = "0.4", features = ["serde"] }
# MCP support
mcp-sdk = "0.1" # Hypothetical - real crate TBD
8.3 Core Implementation
// src/main.rs - CODI entry point
use clap::{Parser, Subcommand};
use anyhow::Result;
#[derive(Parser)]
#[command(name = "codi")]
#[command(about = "CODI - Your friendly CODITECT assistant")]
struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(long, global = true)]
verbose: bool,
}
#[derive(Subcommand)]
enum Commands {
/// Show help and available commands
Help {
#[arg(value_name = "COMMAND")]
command: Option<String>,
},
/// Log an entry using codi-log system
Log {
action: String,
message: String,
#[arg(long)]
impact: Option<String>,
#[arg(long)]
files: Option<String>,
},
/// Manage your CODITECT session
Session {
#[command(subcommand)]
action: SessionCommands,
},
/// Work with ADRs
Adr {
#[command(subcommand)]
action: AdrCommands,
},
/// Deploy your application
Deploy {
target: String,
#[arg(long)]
env: Option<String>,
},
/// AI agent operations
Agent {
#[command(subcommand)]
action: AgentCommands,
},
}
// src/lib.rs - Core CODI library
pub mod commands;
pub mod mcp;
pub mod state;
pub mod api;
use std::path::PathBuf;
pub struct Codi {
config: Config,
state_manager: state::StateManager,
api_client: api::ApiClient,
mcp_server: mcp::Server,
}
impl Codi {
pub fn new() -> Result<Self> {
let config_path = Self::find_codi_root()?.join("config.toml");
let config = Config::load(&config_path)?;
let state_manager = state::StateManager::new(&config.state_path)?;
let api_client = api::ApiClient::new(&config.api_endpoint)?;
let mcp_server = mcp::Server::new(&config.mcp)?;
Ok(Self {
config,
state_manager,
api_client,
mcp_server,
})
}
fn find_codi_root() -> Result<PathBuf> {
// Walk up directory tree looking for .codi/
let mut path = std::env::current_dir()?;
loop {
let codi_path = path.join(".codi");
if codi_path.exists() {
return Ok(codi_path);
}
if !path.pop() {
anyhow::bail!("Not in a CODITECT project (no .codi directory found)");
}
}
}
}
8.4 API Specification 🔴 REQUIRED for API changes
// src/api/mod.rs - CODI API client
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct CommandRequest {
pub session_id: String,
pub command: String,
pub args: Vec<String>,
pub context: CommandContext,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CommandResponse {
pub success: bool,
pub output: String,
pub artifacts: Vec<Artifact>,
pub next_suggestions: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CommandContext {
pub user_id: String,
pub project_id: String,
pub workspace: String,
pub timestamp: chrono::DateTime<chrono::Utc>,
}
pub trait CodiApi {
async fn execute_command(&self, req: CommandRequest) -> Result<CommandResponse>;
async fn get_suggestions(&self, partial: &str) -> Result<Vec<String>>;
async fn sync_state(&self, state: LocalState) -> Result<()>;
}
8.5 Data Models 🔴 REQUIRED for data changes
// src/models.rs - Core data structures
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use chrono::{DateTime, Utc};
#[derive(Debug, Serialize, Deserialize)]
pub struct Session {
pub id: Uuid,
pub started_at: DateTime<Utc>,
pub last_command: Option<DateTime<Utc>>,
pub commands_executed: u32,
pub current_context: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LogEntry {
pub timestamp: DateTime<Utc>,
pub session_id: Uuid,
pub action: String,
pub message: String,
pub impact: Option<String>,
pub files: Option<Vec<String>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CodiConfig {
pub version: String,
pub api_endpoint: String,
pub session: SessionConfig,
pub mcp: McpConfig,
pub features: FeatureFlags,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct McpConfig {
pub enabled: bool,
pub server_port: u16,
pub allowed_tools: Vec<String>,
}
8.6 Configuration
# .codi/config.toml - Default configuration
[codi]
version = "1.0.0"
api_endpoint = "https://api.coditect.com/v1/codi"
[session]
auto_start = true
export_on_end = true
retention_days = 30
[mcp]
enabled = true
server_port = 3333
allowed_tools = ["*"] # or specific list
[features]
ai_suggestions = true
team_sync = true
auto_backup = true
[logging]
level = "info"
file = ".codi/logs/codi.log"
8.7 Logging Implementation Pattern 🔴 REQUIRED per v4.2
// src/logging.rs - CODI logging implementation
use tracing::{info, warn, error, debug, trace};
use serde::{Serialize, Deserialize};
use chrono::{DateTime, Utc};
#[derive(Debug, Serialize, Deserialize)]
pub struct LogEntry {
pub timestamp: DateTime<Utc>,
pub level: LogLevel,
pub component: String,
pub action: String,
pub message: String,
pub context: LogContext,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LogContext {
pub session_id: String,
pub user_id: Option<String>,
pub command: Option<String>,
pub duration_ms: Option<u64>,
pub error: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum LogLevel {
Trace,
Debug,
Info,
Warn,
Error,
Fatal,
}
// Usage in CODI commands
impl Codi {
pub async fn execute_command(&self, cmd: &str) -> Result<CommandResponse> {
let start = std::time::Instant::now();
info!(
component = "codi.command",
action = "execute_start",
command = cmd,
session_id = %self.session_id,
"Starting command execution"
);
match self.router.route(cmd).await {
Ok(response) => {
info!(
component = "codi.command",
action = "execute_success",
command = cmd,
duration_ms = start.elapsed().as_millis() as u64,
"Command completed successfully"
);
Ok(response)
}
Err(e) => {
error!(
component = "codi.command",
action = "execute_error",
command = cmd,
error = %e,
duration_ms = start.elapsed().as_millis() as u64,
"Command execution failed"
);
Err(e)
}
}
}
}
// Structured logging for CODI-specific events
pub fn log_codi_event(action: &str, message: &str, impact: Option<&str>, files: Option<Vec<String>>) {
let entry = json!({
"timestamp": Utc::now().to_rfc3339(),
"severity": "INFO",
"sessionId": std::env::var("CLAUDE_SESSION_ID").unwrap_or_default(),
"actor": {
"type": "codi",
"id": "codi-cli",
"role": "command-interface"
},
"action": action,
"message": message,
"metadata": {
"impact": impact,
"files": files,
"environment": "development",
"version": "v4"
}
});
println!("{}", serde_json::to_string(&entry).unwrap());
}
8.8 Error Handling Pattern 🔴 REQUIRED per v4.2
// src/errors.rs - CODI error handling
use thiserror::Error;
use std::fmt;
#[derive(Error, Debug)]
pub enum CodiError {
#[error("Command not found: {0}")]
CommandNotFound(String),
#[error("Invalid arguments for command '{command}': {message}")]
InvalidArguments { command: String, message: String },
#[error("Authentication required. Please run 'codi auth login'")]
Unauthorized,
#[error("Network error: {0}")]
NetworkError(#[from] reqwest::Error),
#[error("Configuration error: {0}")]
ConfigError(String),
#[error("MCP tool error: {tool} - {message}")]
McpToolError { tool: String, message: String },
#[error("State management error: {0}")]
StateError(#[from] rusqlite::Error),
#[error("API error ({status}): {message}")]
ApiError { status: u16, message: String },
}
impl CodiError {
/// Get user-friendly error message with helpful suggestions
pub fn user_message(&self) -> String {
match self {
Self::CommandNotFound(cmd) => {
format!(
"Command '{}' not found. Try 'codi help' to see available commands.",
cmd
)
}
Self::InvalidArguments { command, .. } => {
format!(
"Invalid arguments for '{}'. Use 'codi help {}' for usage.",
command, command
)
}
Self::Unauthorized => {
"You need to log in first. Run 'codi auth login' to authenticate.".to_string()
}
Self::NetworkError(_) => {
"Network connection failed. Please check your internet connection and try again.".to_string()
}
Self::ConfigError(_) => {
"Configuration issue detected. Run 'codi doctor' to diagnose.".to_string()
}
Self::McpToolError { tool, .. } => {
format!(
"The '{}' tool encountered an error. Check 'codi tools status'.",
tool
)
}
Self::StateError(_) => {
"Local state corrupted. Run 'codi repair' to fix.".to_string()
}
Self::ApiError { status: 429, .. } => {
"Rate limit exceeded. Please wait a moment before trying again.".to_string()
}
Self::ApiError { .. } => {
"Server error occurred. If this persists, check 'codi status'.".to_string()
}
}
}
/// Get recovery suggestions for the error
pub fn recovery_hints(&self) -> Vec<String> {
match self {
Self::CommandNotFound(_) => vec![
"Run 'codi help' to see all commands".to_string(),
"Check spelling and try again".to_string(),
],
Self::Unauthorized => vec![
"Run 'codi auth login'".to_string(),
"Check your credentials with 'codi auth status'".to_string(),
],
Self::NetworkError(_) => vec![
"Check internet connection".to_string(),
"Try 'codi doctor network'".to_string(),
"Check proxy settings if behind firewall".to_string(),
],
_ => vec!["Run 'codi doctor' for diagnostics".to_string()],
}
}
}
// Error display for users
impl fmt::Display for CodiError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "\n❌ {}\n", self.user_message())?;
let hints = self.recovery_hints();
if !hints.is_empty() {
write!(f, "\n💡 Suggestions:\n")?;
for hint in hints {
write!(f, " • {}\n", hint)?;
}
}
Ok(())
}
}
// Usage in main CLI
fn main() {
if let Err(e) = run_codi().await {
eprintln!("{}", e);
std::process::exit(1);
}
}
9. Testing Strategy 🔴 REQUIRED
9.1 Unit Tests
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_command_parsing() {
let args = vec!["codi", "log", "WORKING_ON", "test"];
let cli = Cli::parse_from(args);
match cli.command {
Commands::Log { action, message, .. } => {
assert_eq!(action, "WORKING_ON");
assert_eq!(message, "test");
}
_ => panic!("Wrong command parsed"),
}
}
#[tokio::test]
async fn test_session_management() {
let codi = Codi::new().unwrap();
let session = codi.start_session("test session").await.unwrap();
assert!(session.id != Uuid::nil());
assert_eq!(session.commands_executed, 0);
}
#[test]
fn test_mcp_server_initialization() {
let config = McpConfig {
enabled: true,
server_port: 3333,
allowed_tools: vec!["git".to_string()],
};
let server = mcp::Server::new(&config).unwrap();
assert!(server.is_running());
}
}
9.2 Integration Tests
#[tokio::test]
async fn test_full_command_flow() {
// Start CODI
let codi = Codi::new().unwrap();
// Execute command
let result = codi.execute("deploy frontend --env=staging").await.unwrap();
assert!(result.success);
// Verify log entry created
let logs = codi.get_recent_logs(1).await.unwrap();
assert_eq!(logs[0].action, "DEPLOY");
}
#[tokio::test]
async fn test_mcp_tool_integration() {
let codi = Codi::new().unwrap();
// Register as MCP server
codi.mcp_server.start().await.unwrap();
// External tool connects
let client = mcp::Client::connect("localhost:3333").await.unwrap();
let tools = client.list_tools().await.unwrap();
assert!(tools.contains(&"codi-deploy".to_string()));
}
9.3 Test Coverage Requirements 🔴 REQUIRED
- Unit Tests: ≥ 90% coverage for all CODI modules
- Integration Tests: ≥ 80% coverage for API and MCP interactions
- Critical Paths: 100% coverage for:
- Authentication and authorization
- Command routing and execution
- Error handling and recovery
- State management operations
- Performance Tests: All commands must meet latency targets
- Security Tests: Penetration testing for MCP connections
9.4 Test Data 🟡 OPTIONAL
{
"test_sessions": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"started_at": "2025-08-27T20:00:00Z",
"commands": [
"codi session start",
"codi log SESSION_START \"Testing CODI\"",
"codi deploy frontend"
]
}
]
}
10. Security Considerations 🔴 REQUIRED
10.1 Authentication & Authorization
- JWT Integration: Uses CODITECT platform JWT tokens
- MCP Auth: Tool connections require signed certificates
- Local Security: State files encrypted with user key
10.2 Data Protection
- Encryption at rest: SQLite DB encrypted with SQLCipher
- Encryption in transit: TLS 1.3 for all API calls
- PII handling: No PII stored in logs or state
10.3 Threat Model 🟡 OPTIONAL (required for security-critical features)
| # | Threat | Likelihood | Impact | Mitigation |
|---|---|---|---|---|
| 1 | Malicious MCP tool | 🟡 Medium | 🔴 High | Tool allowlist + signatures |
| 2 | State tampering | 🟢 Low | 🟡 Medium | File integrity checks |
| 3 | API key exposure | 🟡 Medium | 🔴 High | Secure keyring storage |
11. Performance Characteristics 🔴 REQUIRED
11.1 Expected Metrics
| Metric | Target | Measurement |
|---|---|---|
| Command Latency | <100ms local, <500ms remote | Timer per command |
| Memory Usage | <50MB resident | Process monitoring |
| Startup Time | <200ms | Time to first prompt |
| MCP Throughput | 1000 msg/sec | Load testing |
11.2 Benchmarks 🟡 OPTIONAL
#[bench]
fn bench_command_routing(b: &mut Bencher) {
let router = CommandRouter::new();
b.iter(|| {
router.route("deploy frontend --env=prod")
});
}
12. Operational Considerations 🔴 REQUIRED
12.1 Deployment
# Installation script
curl -sSf https://coditect.com/install-codi.sh | sh
# Or via package managers
brew install coditect/tap/codi
cargo install codi
npm install -g @coditect/codi
12.2 Monitoring
| What to Monitor | Metric | Alert Threshold |
|---|---|---|
| Command failures | Error rate | >5% |
| API latency | p95 response time | >1s |
| MCP connections | Active connections | >100 |
12.3 Rollback Plan
- Detect issue: Error rate spike in telemetry
- Verify impact: Check user reports
- Execute rollback:
codi self-update --version=previous - Validate: Run smoke tests
13. Migration Strategy 🔴 REQUIRED if changes existing system
13.1 Migration Steps
- Step 1: Create
.codi/in existing projects (ETA: 1 day) - Step 2: Move
.session/→.codi/session/(ETA: 1 day) - Step 3: Update all script references (ETA: 2 days)
- Step 4: Deploy CODI binary (ETA: 1 day)
- Step 5: Deprecation warnings for old commands (ETA: 1 day)
13.2 Compatibility Matrix
| Component | Backward Compatible | Breaking Changes | Migration Required |
|---|---|---|---|
| Commands | ✅ Yes (aliases) | New syntax | No (optional) |
| State files | ⚠️ Partial | New format | Yes (automated) |
| API | ✅ Yes | None | No |
14. Appendix 🟡 OPTIONAL
14.1 Glossary
| Term | Definition |
|---|---|
| CODI | CODITECT's friendly command interface and assistant persona |
| MCP | Model Context Protocol - standard for AI tool integration |
| State Manager | Component managing persistent local state |
14.2 Command Reference
# Session Management
codi session start [name]
codi session end
codi session list
# Logging
codi log <ACTION> "message" [IMPACT: "..."] [FILES: "..."]
# Development
codi adr create "Title"
codi adr qa <adr-number>
codi deploy <target> [--env=<env>]
# AI Operations
codi agent start
codi agent task "description"
codi agent status
15. Review & Approval 🔴 REQUIRED
Approval Signatures
| Role | Name | Date | Signature |
|---|---|---|---|
| Technical Lead | [Name] | YYYY-MM-DD | ___________ |
| Product Owner | [Name] | YYYY-MM-DD | ___________ |
| Security Review | [Name] | YYYY-MM-DD | ___________ |
| Architecture Board | [Name] | YYYY-MM-DD | ___________ |
Review History
| Version | Date | Reviewer | Status | Comments |
|---|---|---|---|---|
| 0.1 | 2025-08-27 | AI System | DRAFT | Initial draft |
16. QA REVIEW BLOCK 🔴 REQUIRED
Reviewed By: [Reviewer Name]
Review Date: YYYY-MM-DD
ADR Document: ADR-009-v4-codi-command-interface
Version Reviewed: 1.0
Review Status: DRAFT
Overall Score: [XX/40] ([XX]%)
Scoring Breakdown
| # | Section | Score | Max | Notes |
|---|---|---|---|---|
| 1 | Structure & Organization | X | 5 | [Notes] |
| 2 | Dual-Audience Content | X | 5 | [Notes] |
| 3 | Visual Requirements | X | 5 | [Notes] |
| 4 | Implementation Blueprint | X | 5 | [Notes] |
| 5 | Testing & Validation | X | 5 | [Notes] |
| 6 | CODITECT Requirements | X | 5 | [Notes] |
| 7 | Documentation Quality | X | 5 | [Notes] |
| 8 | Review Process | X | 5 | [Notes] |
✅ Strengths
- [Key strength 1]
- [Key strength 2]
🔧 Areas for Improvement
- [Improvement 1]
- [Improvement 2]
📝 Recommendation
Decision: DRAFT - Awaiting review
QA Reviewer Signature: ___________________ Date: _______________