mps 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,935 @@
1
+ # MPS Rust Rollout Specification
2
+
3
+ ## 1. Current Ruby Implementation Analysis
4
+
5
+ ### 1.1 Design Patterns Currently Used
6
+
7
+ | Pattern | Implementation | Assessment |
8
+ |---------|---------------|------------|
9
+ | **Module Namespace** | `module MPS { ... }` | Basic organization, no isolation |
10
+ | **Mixins/Traits** | `include Element` | No real interface enforcement |
11
+ | **Strategy** | Element classes (Task, Note, etc.) | Implicit, no trait bounds |
12
+ | **Factory** | `Engines::MPS.parse_mps_file_to_elments_hash` | Tightly coupled to StringScanner |
13
+ | **Registry** | `MPS::Elements.constants` | Runtime reflection (eval), fragile |
14
+ | **Configuration Object** | `Config` class | Simple but rigid |
15
+
16
+ ### 1.2 Current Limitations
17
+
18
+ 1. **No Type Safety**: Ruby dynamic typing - no compile-time guarantees
19
+ 2. **No Plugin Architecture**: Hardcoded element types, cannot add AI agents at runtime
20
+ 3. **No Event System**: Reminders are passive data only, no active notification mechanism
21
+ 4. **No Async Support**: Synchronous file I/O blocks everything
22
+ 5. **No Persistence Abstention**: Hardcoded YAML, cannot swap to SQLite/PostgreSQL
23
+ 6. **Tight Coupling**: Parser (`Engine::MPS`) directly creates elements with `eval`
24
+ 7. **No Query System**: Cannot filter/search elements efficiently
25
+ 8. **No Error Hierarchy**: Catches generic `Exception`, no typed errors
26
+ 9. **No Testing Infrastructure**: Minimal test coverage
27
+ 10. **No Serialization Framework**: Cannot export to JSON/CSV/etc.
28
+
29
+ ---
30
+
31
+ ## 2. Rust Architecture Specification
32
+
33
+ ### 2.1 Core Design Patterns
34
+
35
+ ```
36
+ ┌─────────────────────────────────────────────────────────────────┐
37
+ │ APPLICATION LAYER │
38
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
39
+ │ │ CLI (Clap) │ │ REPL REPL │ │ TUI (Ratratat) │ │
40
+ │ └──────┬──────┘ └──────┬──────┘ └───────────┬─────────────┘ │
41
+ └─────────┼────────────────┼──────────────────────┼───────────────┘
42
+ │ │ │
43
+ ▼ ▼ ▼
44
+ ┌─────────────────────────────────────────────────────────────────┐
45
+ │ DOMAIN LAYER (Core) │
46
+ │ ┌──────────────────────────────────────────────────────────┐ │
47
+ │ │ DOMAIN MODEL │ │
48
+ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │ │
49
+ │ │ │ Task │ │ Note │ │ Reminder │ │ Log │ │ │
50
+ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬──────┘ │ │
51
+ │ │ └────────────┴────────────┴──────────────┘ │ │
52
+ │ │ ▼ │ │
53
+ │ │ ┌──────────────────┐ │ │
54
+ │ │ │ Element (Trait) │ ◄─── Super Trait │ │
55
+ │ │ │ - id: Uuid │ │ │
56
+ │ │ │ - created_at │ │ │
57
+ │ │ │ - updated_at │ │ │
58
+ │ │ │ - metadata │ │ │
59
+ │ │ └──────────────────┘ │ │
60
+ │ └──────────────────────────────────────────────────────────┘ │
61
+ │ │
62
+ │ ┌──────────────────────────────────────────────────────────┐ │
63
+ │ │ AGGREGATE ROOT │ │
64
+ │ │ ┌─────────────────────────────────────────────────────┐ │ │
65
+ │ │ │ MpsFile (Aggregate) │ │ │
66
+ │ │ │ - id: DateStamp │ │ │
67
+ │ │ │ - elements: Vec<Box<dyn Element>> │ │ │
68
+ │ │ │ - add_element(), remove_element(), query() │ │ │
69
+ │ │ └─────────────────────────────────────────────────────┘ │ │
70
+ │ └──────────────────────────────────────────────────────────┘ │
71
+ └─────────────────────────────────────────────────────────────────┘
72
+
73
+
74
+ ┌─────────────────────────────────────────────────────────────────┐
75
+ │ APPLICATION SERVICES │
76
+ │ ┌────────────────┐ ┌────────────────┐ ┌──────────────────┐ │
77
+ │ │ Parser Service │ │ Query Service │ │ Export Service │ │
78
+ │ └───────┬────────┘ └───────┬────────┘ └────────┬─────────┘ │
79
+ └──────────┼───────────────────┼─────────────────────┼───────────┘
80
+ │ │ │
81
+ ▼ ▼ ▼
82
+ ┌─────────────────────────────────────────────────────────────────┐
83
+ │ INFRASTRUCTURE LAYER │
84
+ │ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
85
+ │ │ File Storage │ │ SQLite │ │ AI Agent Plugin │ │
86
+ │ │ (YAML/JSON) │ │ Repository │ │ System (Plugin) │ │
87
+ │ └──────────────┘ └──────────────┘ └───────────────────────┘ │
88
+ │ │
89
+ │ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
90
+ │ │ Notification │ │ Scheduler │ │ Pluggable AI │ │
91
+ │ │ Service │ │ (Async) │ │ Bridge │ │
92
+ │ └──────────────┘ └──────────────┘ └───────────────────────┘ │
93
+ └─────────────────────────────────────────────────────────────────┘
94
+ ```
95
+
96
+ ### 2.2 Architectural Patterns Used
97
+
98
+ | Pattern | Where Applied | Rationale |
99
+ |---------|--------------|-----------|
100
+ | **Domain-Driven Design** | Domain layer | Clear bounded contexts |
101
+ | **Aggregate Root** | `MpsFile` | Ensures consistency |
102
+ | **Trait Objects** | `Element` trait | Polymorphism for elements |
103
+ | **Repository Pattern** | `MpsRepository` trait | Storage abstraction |
104
+ | **Service Layer** | Parser, Query, Export | Business logic isolation |
105
+ | **Plugin Architecture** | AI Agent system | Extensibility |
106
+ | **Event Sourcing** | Notification system | Audit trail |
107
+ | **CQRS** | Query vs Command | Separation of concerns |
108
+ | **Builder Pattern** | Element creation | Fluent API |
109
+ | **Result/Either** | Error handling | Explicit error types |
110
+
111
+ ---
112
+
113
+ ## 3. Core Domain Model (Rust)
114
+
115
+ ### 3.1 Element Trait (Super Trait)
116
+
117
+ ```rust
118
+ /// Core trait all MPS elements must implement
119
+ pub trait Element: Send + Sync {
120
+ fn id(&self) -> Uuid;
121
+ fn element_type(&self) -> ElementType;
122
+ fn body(&self) -> &str;
123
+ fn tags(&self) -> &[String];
124
+ fn metadata(&self) -> &ElementMetadata;
125
+ fn created_at(&self) -> DateTime<Utc>;
126
+ fn updated_at(&self) -> DateTime<Utc>;
127
+
128
+ fn with_body(mut self: Box<Self>, body: String) -> Box<dyn Element>;
129
+ fn with_tags(mut self: Box<Self>, tags: Vec<String>) -> Box<dyn Element>;
130
+ fn with_metadata(mut self: Box<Self>, metadata: ElementMetadata) -> Box<dyn Element>;
131
+ }
132
+
133
+ #[derive(Clone, Debug, PartialEq, Eq, Hash)]
134
+ pub enum ElementType {
135
+ Task,
136
+ Note,
137
+ Reminder,
138
+ Log,
139
+ Mps, // Nested MPS block
140
+ Custom(String), // For plugin elements
141
+ }
142
+
143
+ #[derive(Clone, Debug, Default)]
144
+ pub struct ElementMetadata {
145
+ pub priority: Option<Priority>,
146
+ pub due_date: Option<DateTime<Utc>>,
147
+ pub completed_at: Option<DateTime<Utc>>,
148
+ pub custom: HashMap<String, String>,
149
+ }
150
+ ```
151
+
152
+ ### 3.2 Concrete Element Types
153
+
154
+ ```rust
155
+ // ╔═══════════════════════════════════════════════════════════════╗
156
+ // ║ CONCRETE ELEMENTS ║
157
+ // ╚═══════════════════════════════════════════════════════════════╝
158
+
159
+ /// Task element - represents actionable items
160
+ pub struct Task {
161
+ id: Uuid,
162
+ body: String,
163
+ tags: Vec<String>,
164
+ metadata: ElementMetadata,
165
+ created_at: DateTime<Utc>,
166
+ updated_at: DateTime<Utc>,
167
+ }
168
+
169
+ impl Task {
170
+ pub fn new(body: impl Into<String>) -> Self { ... }
171
+ pub fn with_priority(mut self, priority: Priority) -> Self { ... }
172
+ pub fn is_completed(&self) -> bool { ... }
173
+ pub fn mark_completed(&mut self) { ... }
174
+ }
175
+
176
+ /// Note element - free-form information
177
+ pub struct Note {
178
+ id: Uuid,
179
+ body: String,
180
+ tags: Vec<String>,
181
+ metadata: ElementMetadata,
182
+ created_at: DateTime<Utc>,
183
+ updated_at: DateTime<Utc>,
184
+ }
185
+
186
+ /// Reminder element - time-based notification trigger
187
+ pub struct Reminder {
188
+ id: Uuid,
189
+ body: String,
190
+ tags: Vec<String>,
191
+ metadata: ElementMetadata,
192
+ trigger_at: DateTime<Utc>, // When to trigger
193
+ repeat: Option<RepeatPattern>, // Recurrence rule
194
+ notification_channel: Channel, // How to notify
195
+ created_at: DateTime<Utc>,
196
+ updated_at: DateTime<Utc>,
197
+ }
198
+
199
+ #[derive(Clone, Debug)]
200
+ pub enum RepeatPattern {
201
+ Daily,
202
+ Weekly(DayOfWeek),
203
+ Monthly(DayOfMonth),
204
+ Custom(CronExpression),
205
+ }
206
+
207
+ /// Log element - time tracking
208
+ pub struct Log {
209
+ id: Uuid,
210
+ body: String,
211
+ tags: Vec<String>,
212
+ metadata: ElementMetadata,
213
+ start_time: DateTime<Utc>,
214
+ end_time: Option<DateTime<Utc>>,
215
+ created_at: DateTime<Utc>,
216
+ updated_at: DateTime<Utc>,
217
+ }
218
+
219
+ impl Log {
220
+ pub fn start(body: impl Into<String>) -> Self { ... }
221
+ pub fn stop(&mut self) { ... }
222
+ pub fn duration(&self) -> Duration { ... }
223
+ }
224
+ ```
225
+
226
+ ### 3.3 Aggregate Root - MpsFile
227
+
228
+ ```rust
229
+ /// MpsFile - Aggregate Root for daily MPS entries
230
+ pub struct MpsFile {
231
+ id: MpsFileId,
232
+ date: NaiveDate,
233
+ elements: Vec<Box<dyn Element>>,
234
+ version: u64,
235
+ created_at: DateTime<Utc>,
236
+ updated_at: DateTime<Utc>,
237
+ }
238
+
239
+ impl MpsFile {
240
+ pub fn new(date: NaiveDate) -> Self { ... }
241
+
242
+ // Command methods (mutating)
243
+ pub fn add_element(&mut self, element: Box<dyn Element>) -> Result<(), MpsError> { ... }
244
+ pub fn remove_element(&mut self, id: Uuid) -> Result<Box<dyn Element>, MpsError> { ... }
245
+ pub fn update_element(&mut self, element: Box<dyn Element>) -> Result<(), MpsError> { ... }
246
+
247
+ // Query methods (immutable)
248
+ pub fn get_element(&self, id: Uuid) -> Option<&dyn Element> { ... }
249
+ pub fn query(&self, filter: &ElementFilter) -> Vec<&dyn Element> { ... }
250
+ pub fn tasks(&self) -> Vec<&Task> { ... }
251
+ pub fn reminders(&self) -> Vec<&Reminder> { ... }
252
+ pub fn logs(&self) -> Vec<&Log> { ... }
253
+
254
+ // Serialization
255
+ pub fn to_json(&self) -> String { ... }
256
+ pub fn to_yaml(&self) -> String { ... }
257
+ pub fn to_markdown(&self) -> String { ... }
258
+ pub fn to_plain_text(&self) -> String { ... }
259
+ }
260
+
261
+ #[derive(Clone, Debug)]
262
+ pub struct MpsFileId(pub String); // Format: "YYYYMMDD.timestamp.mps"
263
+ ```
264
+
265
+ ---
266
+
267
+ ## 4. Plugin Architecture for AI Agents
268
+
269
+ ### 4.1 Plugin System Overview
270
+
271
+ ```
272
+ ┌─────────────────────────────────────────────────────────────────┐
273
+ │ PLUGIN SYSTEM ARCHITECTURE │
274
+ ├─────────────────────────────────────────────────────────────────┤
275
+ │ │
276
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
277
+ │ │ AI Agent │ │ Notification│ │ Custom │ │
278
+ │ │ Plugin A │ │ Plugin B │ │ Plugin C │ │
279
+ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
280
+ │ │ │ │ │
281
+ │ └────────────────────┼────────────────────┘ │
282
+ │ ▼ │
283
+ │ ┌──────────────────┐ │
284
+ │ │ Plugin Manager │ │
285
+ │ │ (PluginRegistry)│ │
286
+ │ └────────┬─────────┘ │
287
+ │ │ │
288
+ │ ▼ │
289
+ │ ┌─────────────────────────────────────────────────────────┐ │
290
+ │ │ PLUGIN TRAIT │ │
291
+ │ │ trait Plugin: Send + Sync { │ │
292
+ │ │ fn name(&self) -> &str; │ │
293
+ │ │ fn version(&self) -> &str; │ │
294
+ │ │ fn initialize(&self, ctx: &PluginContext) │ │
295
+ │ │ fn on_event(&self, event: &PluginEvent) │ │
296
+ │ │ fn capabilities(&self) -> PluginCapabilities; │ │
297
+ │ │ } │ │
298
+ │ └─────────────────────────────────────────────────────────┘ │
299
+ │ │
300
+ └─────────────────────────────────────────────────────────────────┘
301
+ ```
302
+
303
+ ### 4.2 Plugin Trait Definition
304
+
305
+ ```rust
306
+ /// Core plugin trait - all AI agents implement this
307
+ pub trait Plugin: Send + Sync {
308
+ /// Unique plugin identifier
309
+ fn name(&self) -> &str;
310
+
311
+ /// Semantic version
312
+ fn version(&self) -> &str;
313
+
314
+ /// Human-readable description
315
+ fn description(&self) -> &str;
316
+
317
+ /// Initialize plugin with configuration
318
+ fn initialize(&self, ctx: &PluginContext) -> Result<(), PluginError>;
319
+
320
+ /// Handle events from MPS system
321
+ fn on_event(&self, event: &PluginEvent) -> PluginResponse;
322
+
323
+ /// Capabilities this plugin provides
324
+ fn capabilities(&self) -> PluginCapabilities;
325
+
326
+ /// Shutdown hook
327
+ fn shutdown(&self) -> Result<(), PluginError>;
328
+ }
329
+
330
+ #[derive(Clone, Debug, Default)]
331
+ pub struct PluginCapabilities {
332
+ pub ai_enabled: bool,
333
+ pub notifications: bool,
334
+ pub scheduled_tasks: bool,
335
+ pub custom_elements: bool,
336
+ pub export_formats: Vec<String>,
337
+ }
338
+
339
+ pub enum PluginEvent {
340
+ ElementCreated { element: Box<dyn Element>, file: &MpsFile },
341
+ ElementUpdated { element: Box<dyn Element>, file: &MpsFile },
342
+ ElementDeleted { element_id: Uuid, file: &MpsFile },
343
+ ReminderTriggered { reminder: &Reminder },
344
+ TaskCompleted { task: &Task },
345
+ LogStarted { log: &Log },
346
+ LogEnded { log: &Log, duration: Duration },
347
+ }
348
+
349
+ pub enum PluginResponse {
350
+ None,
351
+ Action(PluginAction),
352
+ Notification(PluginNotification),
353
+ ModifiedElement(Box<dyn Element>),
354
+ Error(String),
355
+ }
356
+ ```
357
+
358
+ ### 4.3 AI Agent Plugin Example
359
+
360
+ ```rust
361
+ /// Example: AI Smart Reminder Agent
362
+ pub struct SmartReminderAgent {
363
+ config: SmartReminderConfig,
364
+ model: Option<Box<dyn LlmModel>>,
365
+ }
366
+
367
+ impl SmartReminderAgent {
368
+ pub fn new(config: SmartReminderConfig) -> Self { ... }
369
+
370
+ /// Analyze reminder and suggest optimal timing
371
+ pub fn suggest_timing(&self, reminder: &Reminder) -> DateTime<Utc> { ... }
372
+
373
+ /// Generate smart follow-up tasks
374
+ pub fn suggest_followups(&self, completed_task: &Task) -> Vec<Task> { ... }
375
+
376
+ /// Context-aware notification messages
377
+ pub fn generate_message(&self, reminder: &Reminder, context: &MpsFile) -> String { ... }
378
+ }
379
+
380
+ /// AI LLM trait for model abstraction
381
+ pub trait LlmModel: Send + Sync {
382
+ fn complete(&self, prompt: &str) -> Result<String, LlmError>;
383
+ fn chat(&self, messages: &[ChatMessage]) -> Result<ChatMessage, LlmError>;
384
+ fn embed(&self, text: &str) -> Result<Vec<f32>, EmbeddingError>;
385
+ }
386
+ ```
387
+
388
+ ---
389
+
390
+ ## 5. Event & Notification System
391
+
392
+ ### 5.1 Event Bus
393
+
394
+ ```rust
395
+ /// Async event bus for inter-component communication
396
+ pub struct EventBus {
397
+ subscribers: Arc<RwLock<HashMap<EventType, Vec<Subscription>>>>,
398
+ runtime: Runtime,
399
+ }
400
+
401
+ impl EventBus {
402
+ pub fn new() -> Self { ... }
403
+
404
+ pub fn subscribe<F>(&mut self, event_type: EventType, handler: F)
405
+ where
406
+ F: Fn(Box<dyn Event>) -> Pin<Box<dyn Future<Output=()> + Send>> + Send + Sync + 'static
407
+ { ... }
408
+
409
+ pub async fn publish(&self, event: Box<dyn Event>) { ... }
410
+ }
411
+
412
+ pub trait Event: Send + Debug {
413
+ fn event_type(&self) -> EventType;
414
+ fn timestamp(&self) -> DateTime<Utc>;
415
+ fn source(&self) -> EventSource;
416
+ }
417
+
418
+ pub enum EventType {
419
+ ElementCreated,
420
+ ElementUpdated,
421
+ ElementDeleted,
422
+ ReminderFired,
423
+ TaskCompleted,
424
+ LogStarted,
425
+ LogEnded,
426
+ ScheduleTriggered,
427
+ PluginEvent(String),
428
+ }
429
+ ```
430
+
431
+ ### 5.2 Notification Channels
432
+
433
+ ```rust
434
+ /// Pluggable notification backends
435
+ pub trait NotificationChannel: Send + Sync {
436
+ fn send(&self, notification: &Notification) -> Result<(), NotificationError>;
437
+ fn capabilities(&self) -> ChannelCapabilities;
438
+ }
439
+
440
+ pub struct Notification {
441
+ pub id: Uuid,
442
+ pub title: String,
443
+ pub body: String,
444
+ pub urgency: Urgency,
445
+ pub channel: ChannelType,
446
+ pub actions: Vec<Action>,
447
+ pub scheduled_for: Option<DateTime<Utc>>,
448
+ }
449
+
450
+ pub enum ChannelType {
451
+ Desktop, // libnotify/dunst
452
+ Email, // SMTP
453
+ Slack, // Slack API
454
+ Telegram, // Bot API
455
+ Webhook, // HTTP POST
456
+ Console, // stdout
457
+ }
458
+
459
+ pub enum Urgency {
460
+ Low,
461
+ Normal,
462
+ Critical,
463
+ }
464
+ ```
465
+
466
+ ---
467
+
468
+ ## 6. Repository & Storage Abstraction
469
+
470
+ ### 6.1 Repository Trait
471
+
472
+ ```rust
473
+ pub trait MpsRepository: Send + Sync {
474
+ async fn save(&self, file: &MpsFile) -> Result<(), RepositoryError>;
475
+ async fn load(&self, id: &MpsFileId) -> Result<MpsFile, RepositoryError>;
476
+ async fn delete(&self, id: &MpsFileId) -> Result<(), RepositoryError>;
477
+ async fn list(&self, range: DateRange) -> Result<Vec<MpsFileId>, RepositoryError>;
478
+ async fn search(&self, query: &SearchQuery) -> Result<Vec<SearchResult>, RepositoryError>;
479
+ }
480
+
481
+ pub trait SearchIndex: Send + Sync {
482
+ fn index(&self, file: &MpsFile) -> Result<(), IndexError>;
483
+ fn search(&self, query: &SearchQuery) -> Result<Vec<SearchResult>, IndexError>;
484
+ fn reindex(&self) -> Result<(), IndexError>;
485
+ }
486
+ ```
487
+
488
+ ### 6.2 Storage Implementations
489
+
490
+ ```rust
491
+ // File-based storage (YAML/JSON)
492
+ pub struct FileSystemRepository {
493
+ base_path: PathBuf,
494
+ format: StorageFormat,
495
+ }
496
+
497
+ // SQLite with full-text search
498
+ pub struct SqliteRepository {
499
+ connection: SqliteConnection,
500
+ }
501
+
502
+ // PostgreSQL for multi-device sync
503
+ pub struct PostgresRepository {
504
+ pool: PgPool,
505
+ }
506
+ ```
507
+
508
+ ---
509
+
510
+ ## 7. Query & Filter System
511
+
512
+ ### 7.1 Query DSL
513
+
514
+ ```rust
515
+ /// Fluent query builder
516
+ pub struct MpsQuery {
517
+ filters: Vec<Box<dyn QueryFilter>>,
518
+ sort: SortOption,
519
+ limit: Option<usize>,
520
+ offset: usize,
521
+ }
522
+
523
+ impl MpsQuery {
524
+ pub fn new() -> Self { ... }
525
+
526
+ pub fn for_date(mut self, date: NaiveDate) -> Self { ... }
527
+ pub fn for_date_range(mut self, start: NaiveDate, end: NaiveDate) -> Self { ... }
528
+
529
+ pub fn with_type(mut self, element_type: ElementType) -> Self { ... }
530
+ pub fn with_tag(mut self, tag: impl Into<String>) -> Self { ... }
531
+ pub fn with_tags(mut self, tags: Vec<String>) -> Self { ... }
532
+
533
+ pub fn with_priority(mut self, priority: Priority) -> Self { ... }
534
+ pub fn is_completed(mut self) -> Self { ... }
535
+ pub fn is_pending(mut self) -> Self { ... }
536
+
537
+ pub fn has_due_date(mut self) -> Self { ... }
538
+ pub fn due_before(mut self, date: DateTime<Utc>) -> Self { ... }
539
+ pub fn due_after(mut self, date: DateTime<Utc>) -> Self { ... }
540
+
541
+ pub fn sort_by(mut self, sort: SortOption) -> Self { ... }
542
+ pub fn limit(mut self, n: usize) -> Self { ... }
543
+ pub fn offset(mut self, n: usize) -> Self { ... }
544
+
545
+ pub fn execute(&self, repo: &dyn MpsRepository) -> Result<Vec<Box<dyn Element>>, QueryError> { ... }
546
+ }
547
+ ```
548
+
549
+ ---
550
+
551
+ ## 8. CLI & Interface Layer
552
+
553
+ ### 8.1 Command Structure (using Clap)
554
+
555
+ ```rust
556
+ use clap::{Parser, Subcommand};
557
+
558
+ #[derive(Parser)]
559
+ #[command(name = "mps")]
560
+ #[command(about = "MPS - Personal Productivity Manager", long_about = None)]
561
+ pub struct Cli {
562
+ #[command(subcommand)]
563
+ pub command: Commands,
564
+
565
+ #[arg(short, long, global = true)]
566
+ pub config: Option<PathBuf>,
567
+
568
+ #[arg(short, long, global = true, action = clap::ArgAction::Count)]
569
+ pub verbose: u8,
570
+ }
571
+
572
+ #[derive(Subcommand)]
573
+ pub enum Commands {
574
+ /// Open MPS file in editor
575
+ Open {
576
+ /// Date expression (today, yesterday, YYYYMMDD, "2 days ago")
577
+ #[arg(default_value = "today")]
578
+ date: String,
579
+
580
+ /// Open in specified editor
581
+ #[arg(short, long)]
582
+ editor: Option<String>,
583
+ },
584
+
585
+ /// Create new element
586
+ New {
587
+ /// Element type (task, note, reminder, log)
588
+ #[arg(value_enum)]
589
+ element_type: ElementTypeCli,
590
+
591
+ /// Element body/content
592
+ body: String,
593
+
594
+ /// Tags (comma-separated)
595
+ #[arg(short, long, value_delimiter = ',')]
596
+ tags: Vec<String>,
597
+
598
+ /// Date to add element to
599
+ #[arg(short, long)]
600
+ date: Option<String>,
601
+ },
602
+
603
+ /// List/search elements
604
+ List {
605
+ /// Filter by type
606
+ #[arg(short, long)]
607
+ r#type: Option<ElementTypeCli>,
608
+
609
+ /// Filter by tag
610
+ #[arg(short, long)]
611
+ tag: Option<String>,
612
+
613
+ /// Show completed tasks
614
+ #[arg(long)]
615
+ all: bool,
616
+
617
+ /// Date range
618
+ #[arg(short, long)]
619
+ range: Option<String>,
620
+ },
621
+
622
+ /// Git operations
623
+ Git {
624
+ #[arg(last = true)]
625
+ args: Vec<String>,
626
+ },
627
+
628
+ /// AI Agent commands
629
+ Agent {
630
+ #[command(subcommand)]
631
+ subcommand: AgentCommands,
632
+ },
633
+
634
+ /// Export data
635
+ Export {
636
+ /// Output format (json, yaml, markdown, csv)
637
+ #[arg(short, long)]
638
+ format: ExportFormat,
639
+
640
+ /// Output file
641
+ #[arg(short, long)]
642
+ output: Option<PathBuf>,
643
+
644
+ /// Date range
645
+ #[arg(short, long)]
646
+ range: Option<String>,
647
+ },
648
+
649
+ /// Server mode (for remote access/API)
650
+ Serve {
651
+ #[arg(short, long, default_value = "127.0.0.1:3030")]
652
+ address: String,
653
+ },
654
+ }
655
+ ```
656
+
657
+ ---
658
+
659
+ ## 9. Error Handling
660
+
661
+ ### 9.1 Error Types
662
+
663
+ ```rust
664
+ #[derive(Error, Debug)]
665
+ pub enum MpsError {
666
+ #[error("Element not found: {0}")]
667
+ ElementNotFound(Uuid),
668
+
669
+ #[error("File not found: {0}")]
670
+ FileNotFound(MpsFileId),
671
+
672
+ #[error("Parse error: {0}")]
673
+ ParseError(String),
674
+
675
+ #[error("Storage error: {0}")]
676
+ StorageError(String),
677
+
678
+ #[error("Configuration error: {0}")]
679
+ ConfigError(String),
680
+
681
+ #[error("Plugin error: {0}")]
682
+ PluginError(String),
683
+
684
+ #[error("Validation error: {0}")]
685
+ ValidationError(String),
686
+ }
687
+ ```
688
+
689
+ ---
690
+
691
+ ## 10. Project Structure
692
+
693
+ ```
694
+ mps/
695
+ ├── Cargo.toml
696
+ ├── rust-toolchain.toml
697
+ ├── .env.example
698
+ ├── README.md
699
+ ├── CHANGELOG.md
700
+
701
+ ├── src/
702
+ │ ├── main.rs # Entry point
703
+ │ ├── lib.rs # Library root
704
+ │ │
705
+ │ ├── domain/ # Domain Layer (innermost)
706
+ │ │ ├── mod.rs
707
+ │ │ ├── element.rs # Element trait
708
+ │ │ ├── task.rs
709
+ │ │ ├── note.rs
710
+ │ │ ├── reminder.rs
711
+ │ │ ├── log.rs
712
+ │ │ ├── mps_file.rs # Aggregate root
713
+ │ │ ├── errors.rs # Domain errors
714
+ │ │ └── value_objects/ # Value objects
715
+ │ │ ├── mod.rs
716
+ │ │ ├── mps_file_id.rs
717
+ │ │ ├── priority.rs
718
+ │ │ └── date_stamp.rs
719
+ │ │
720
+ │ ├── application/ # Application Services
721
+ │ │ ├── mod.rs
722
+ │ │ ├── parser.rs # Text file parser
723
+ │ │ ├── query_service.rs # Query execution
724
+ │ │ ├── command_service.rs # Commands (CQRS write)
725
+ │ │ ├── export_service.rs # Export to various formats
726
+ │ │ └── scheduler.rs # Reminder scheduler
727
+ │ │
728
+ │ ├── infrastructure/ # Infrastructure Layer
729
+ │ │ ├── mod.rs
730
+ │ │ ├── repository/
731
+ │ │ │ ├── mod.rs
732
+ │ │ │ ├── repository.rs # Repository trait
733
+ │ │ │ ├── file_system.rs
734
+ │ │ │ ├── sqlite.rs
735
+ │ │ │ └── search_index.rs
736
+ │ │ ├── storage/
737
+ │ │ │ ├── mod.rs
738
+ │ │ │ └── yaml.rs
739
+ │ │ ├── notification/
740
+ │ │ │ ├── mod.rs
741
+ │ │ │ ├── notifier.rs
742
+ │ │ │ └── channels/
743
+ │ │ │ ├── mod.rs
744
+ │ │ │ ├── desktop.rs
745
+ │ │ │ ├── email.rs
746
+ │ │ │ └── slack.rs
747
+ │ │ └── plugins/
748
+ │ │ ├── mod.rs
749
+ │ │ ├── plugin.rs # Plugin trait
750
+ │ │ ├── manager.rs # Plugin registry
751
+ │ │ └── ai/
752
+ │ │ ├── mod.rs
753
+ │ │ ├── llm.rs # LLM trait
754
+ │ │ └── smart_reminder.rs
755
+ │ │
756
+ │ ├── interface/ # Interface Adapters
757
+ │ │ ├── mod.rs
758
+ │ │ ├── cli/
759
+ │ │ │ ├── mod.rs
760
+ │ │ │ ├── commands.rs
761
+ │ │ │ └── parser.rs # CLI arg parsing
762
+ │ │ ├── tui/
763
+ │ │ │ └── mod.rs # Terminal UI
764
+ │ │ └── api/
765
+ │ │ ├── mod.rs
766
+ │ │ └── server.rs # HTTP API server
767
+ │ │
768
+ │ └── common/ # Shared utilities
769
+ │ ├── mod.rs
770
+ │ ├── config.rs
771
+ │ ├── logging.rs
772
+ │ ├── date_utils.rs
773
+ │ └── extensions.rs
774
+
775
+ ├── tests/
776
+ │ ├── integration/
777
+ │ │ └── mod.rs
778
+ │ ├── domain/
779
+ │ │ ├── mod.rs
780
+ │ │ └── element_tests.rs
781
+ │ └── fixtures/
782
+ │ └── mod.rs
783
+
784
+ ├── examples/
785
+ │ ├── basic_usage.rs
786
+ │ ├── plugin_example.rs
787
+ │ └── export_example.rs
788
+
789
+ └── docs/
790
+ ├── architecture.md
791
+ ├── plugin_development.md
792
+ └── api_reference.md
793
+ ```
794
+
795
+ ---
796
+
797
+ ## 11. Dependencies (Cargo.toml)
798
+
799
+ ```toml
800
+ [package]
801
+ name = "mps"
802
+ version = "0.1.0"
803
+ edition = "2024"
804
+
805
+ [dependencies]
806
+ # Async runtime
807
+ tokio = { version = "1", features = ["full"] }
808
+
809
+ # CLI
810
+ clap = { version = "4", features = ["derive", "env"] }
811
+ clap_complete = "4"
812
+
813
+ # Serialization
814
+ serde = { version = "1", features = ["derive"] }
815
+ serde_json = "1"
816
+ serde_yaml = "0.9"
817
+ toml = "0.8"
818
+
819
+ # Database
820
+ rusqlite = { version = "0.31", features = ["bundled"] }
821
+ sqlx = { version = "0.7", features = ["runtime-tokio", "sqlite", "postgres"] }
822
+
823
+ # Date/Time
824
+ chrono = { version = "0.4", features = ["serde"] }
825
+ chrono-tz = "0.8"
826
+
827
+ # UUID
828
+ uuid = { version = "1", features = ["v4", "serde", "fast-rng"] }
829
+
830
+ # Logging
831
+ tracing = "0.1"
832
+ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
833
+ tracing-appender = "0.2"
834
+
835
+ # Error handling
836
+ thiserror = "1"
837
+ anyhow = "1"
838
+
839
+ # Async notifications
840
+ tokio-sync = "0.3"
841
+
842
+ # Editor integration
843
+ tui-editor = "0.2"
844
+
845
+ # HTTP server (for API)
846
+ axum = "0.6"
847
+ tower = "0.4"
848
+
849
+ # Regex
850
+ regex = "1"
851
+ fancy-regex = "0.11"
852
+
853
+ # Fuzzy search
854
+ fuzzy-matcher = "0.3"
855
+
856
+ # Async trait support
857
+ async-trait = "0.1"
858
+
859
+ # Conditional compilation
860
+ cfg-if = "1"
861
+
862
+ [dev-dependencies]
863
+ tokio-test = "0.4"
864
+ mockall = "0.11"
865
+ proptest = "1"
866
+ criterion = "0.5"
867
+
868
+ [features]
869
+ default = ["sqlite"]
870
+ sqlite = ["rusqlite"]
871
+ postgres = ["sqlx/postgres"]
872
+ ```
873
+
874
+ ---
875
+
876
+ ## 12. Implementation Phases
877
+
878
+ ### Phase 1: Core Domain (Weeks 1-2)
879
+ - [ ] Define Element trait and value objects
880
+ - [ ] Implement Task, Note, Reminder, Log types
881
+ - [ ] Implement MpsFile aggregate
882
+ - [ ] Implement basic error types
883
+ - [ ] Unit tests for domain
884
+
885
+ ### Phase 2: Storage & Parser (Weeks 3-4)
886
+ - [ ] FileSystem repository implementation
887
+ - [ ] Text parser for .mps files
888
+ - [ ] YAML/JSON serialization
889
+ - [ ] Search index implementation
890
+
891
+ ### Phase 3: Query System (Week 5)
892
+ - [ ] MpsQuery builder
893
+ - [ ] Filter implementations
894
+ - [ ] SQLite repository
895
+
896
+ ### Phase 4: Event System (Week 6)
897
+ - [ ] EventBus implementation
898
+ - [ ] Scheduler for reminders
899
+ - [ ] Notification channels
900
+
901
+ ### Phase 5: Plugin Architecture (Weeks 7-8)
902
+ - [ ] Plugin trait and manager
903
+ - [ ] Plugin registry
904
+ - [ ] AI agent plugin skeleton
905
+
906
+ ### Phase 6: Interface Layer (Weeks 9-10)
907
+ - [ ] CLI commands implementation
908
+ - [ ] TUI (optional)
909
+ - [ ] HTTP API server
910
+
911
+ ### Phase 7: Polish (Week 11-12)
912
+ - [ ] Integration tests
913
+ - [ ] Performance optimization
914
+ - [ ] Documentation
915
+ - [ ] Release
916
+
917
+ ---
918
+
919
+ ## 13. Summary
920
+
921
+ This specification provides a production-grade Rust implementation with:
922
+
923
+ | Feature | Ruby Implementation | Rust Implementation |
924
+ |---------|--------------------|--------------------|
925
+ | Type Safety | None (dynamic) | Full (static) |
926
+ | Concurrency | GIL-limited | True parallelism |
927
+ | Error Handling | Exceptions | Result/Either types |
928
+ | Extensibility | eval() reflection | Plugin trait system |
929
+ | AI Integration | None | Pluggable LLM interface |
930
+ | Notifications | None | Async event bus |
931
+ | Storage | YAML only | Pluggable backends |
932
+ | Query | None | Full query DSL |
933
+ | Testing | Minimal | Property-based |
934
+
935
+ The architecture enables future AI agent integration through a well-defined plugin system, event bus, and async capabilities.