The Evolution of Todo – Mastering Spec-Driven Development & Cloud Native AIPhase I: Todo In-Memory Python Console App.

Phase I: Todo In-Memory Python Console App.

Building a Command-Line Todo App with Python, Claude Code & Spec-Kit Plus | Step-by-Step Guide

Learn how to create a complete command-line todo application using Python 3.13+, Claude Code AI assistance, and Spec-Kit Plus specification-driven development. Perfect for beginners

Basic Level Functionality
Objective: Build a command-line todo application that stores tasks in memory using Claude
Code and Spec-Kit Plus.
Requirements

  • Implement all 5 Basic Level features (Add, Delete, Update, View, Mark Complete)
  • Use spec-driven development with Claude Code and Spec-Kit Plus
  • Follow clean code principles and proper Python project structure
    Technology Stack
  • UV
  • Python 3.13+
  • Claude Code
  • GitHub Spec-Kit

Windows Users: WSL 2 Setup
Windows users must use WSL 2 (Windows Subsystem for Linux) for development:

# Install WSL 2
wsl --install
# Set WSL 2 as default
wsl --set-default-version 2
# Install Ubuntu
wsl --install -d Ubuntu-22.04
Python
Expand

Step 1: Navigate to Desktop

cd %USERPROFILE%\Desktop
Python

Step 2: Create Main Project Folder

mkdir MyTodoApp
Python

Step 3: Navigate into Project Folder

cd MyTodoApp
Python

Step 4: Create All Required Folders in One Command

mkdir src src\models src\managers src\ui specs_history
Python

Step 5: Verify Your Structure

dir
Python

Step 6: Create the Task Model File

Create src\models\task.py with this content:

from datetime import datetime
from typing import Optional

class Task:
    def __init__(self, task_id: int, title: str, description: str = ""):
        self.id = task_id
        self.title = title
        self.description = description
        self.completed = False
        self.created_at = datetime.now()
        self.updated_at = datetime.now()
    
    def mark_complete(self) -> None:
        self.completed = True
        self.updated_at = datetime.now()
    
    def mark_incomplete(self) -> None:
        self.completed = False
        self.updated_at = datetime.now()
    
    def update(self, title: Optional[str] = None, description: Optional[str] = None) -> None:
        if title is not None:
            self.title = title
        if description is not None:
            self.description = description
        self.updated_at = datetime.now()
    
    def __str__(self) -> str:
        status = "✓" if self.completed else "○"
        return f"[{status}] {self.id}: {self.title}"
Python

Step 7: Create the Todo Manager File

Create src\managers\todo_manager.py with this content:

from typing import List, Optional
from models.task import Task

class TodoManager:
    def __init__(self):
        self.tasks: List[Task] = []
        self.next_id = 1
    
    def add_task(self, title: str, description: str = "") -> Task:
        task = Task(self.next_id, title, description)
        self.tasks.append(task)
        self.next_id += 1
        return task
    
    def get_task(self, task_id: int) -> Optional[Task]:
        for task in self.tasks:
            if task.id == task_id:
                return task
        return None
    
    def update_task(self, task_id: int, title: Optional[str] = None, 
                   description: Optional[str] = None) -> bool:
        task = self.get_task(task_id)
        if task:
            task.update(title, description)
            return True
        return False
    
    def delete_task(self, task_id: int) -> bool:
        task = self.get_task(task_id)
        if task:
            self.tasks.remove(task)
            return True
        return False
    
    def mark_complete(self, task_id: int) -> bool:
        task = self.get_task(task_id)
        if task:
            task.mark_complete()
            return True
        return False
    
    def mark_incomplete(self, task_id: int) -> bool:
        task = self.get_task(task_id)
        if task:
            task.mark_incomplete()
            return True
        return False
    
    def list_tasks(self) -> List[Task]:
        return self.tasks[:]
    
    def get_completed_tasks(self) -> List[Task]:
        return [task for task in self.tasks if task.completed]
    
    def get_pending_tasks(self) -> List[Task]:
        return [task for task in self.tasks if not task.completed]
Python


Step 8: Create the Console UI File

import sys
from typing import Optional
from managers.todo_manager import TodoManager
from models.task import Task

class ConsoleUI:
    def __init__(self, todo_manager: TodoManager):
        self.todo_manager = todo_manager
    
    def display_menu(self) -> None:
        print("\n===== MY TODO APP =====")
        print("1. Add New Task")
        print("2. Show All Tasks")
        print("3. Edit Task")
        print("4. Delete Task")
        print("5. Mark Task Done")
        print("6. Mark Task Not Done")
        print("7. Exit Program")
        print("========================")
    
    def get_user_choice(self) -> str:
        return input("Enter your choice (1-7): ").strip()
    
    def get_task_details(self) -> tuple[str, str]:
        title = input("What do you need to do? : ").strip()
        description = input("Any extra details? (optional): ").strip()
        return title, description
    
    def get_task_id(self) -> Optional[int]:
        try:
            return int(input("Enter task number: ").strip())
        except ValueError:
            print("That's not a valid number!")
            return None
    
    def add_task(self) -> None:
        print("\n--- Adding New Task ---")
        title, description = self.get_task_details()
        
        if not title:
            print("You must enter what you need to do!")
            return
        
        task = self.todo_manager.add_task(title, description)
        print(f"Added! Task #{task.id}: {task.title}")
    
    def list_tasks(self) -> None:
        print("\n--- Your Tasks ---")
        tasks = self.todo_manager.list_tasks()
        
        if not tasks:
            print("No tasks yet! Add one to get started.")
            return
        
        pending_tasks = self.todo_manager.get_pending_tasks()
        if pending_tasks:
            print("\n📋 Things to do:")
            for task in pending_tasks:
                print(f"  {task}")
        
        completed_tasks = self.todo_manager.get_completed_tasks()
        if completed_tasks:
            print("\n✅ Completed tasks:")
            for task in completed_tasks:
                print(f"  {task}")
    
    def update_task(self) -> None:
        print("\n--- Editing Task ---")
        task_id = self.get_task_id()
        
        if task_id is None:
            return
        
        task = self.todo_manager.get_task(task_id)
        if not task:
            print(f"No task found with number {task_id}")
            return
        
        print(f"Current task: {task.title}")
        print(f"Current details: {task.description}")
        
        new_title = input("New task name (press Enter to keep current): ").strip()
        new_description = input("New details (press Enter to keep current): ").strip()
        
        if not new_title:
            new_title = None
        if not new_description:
            new_description = None
        
        if self.todo_manager.update_task(task_id, new_title, new_description):
            print("Task updated successfully!")
        else:
            print("Could not update task.")
    
    def delete_task(self) -> None:
        print("\n--- Deleting Task ---")
        task_id = self.get_task_id()
        
        if task_id is None:
            return
        
        task = self.todo_manager.get_task(task_id)
        if not task:
            print(f"No task found with number {task_id}")
            return
        
        confirm = input(f"Really delete '{task.title}'? (y/N): ").strip().lower()
        if confirm == 'y' or confirm == 'yes':
            if self.todo_manager.delete_task(task_id):
                print("Task deleted!")
            else:
                print("Could not delete task.")
        else:
            print("Deletion cancelled.")
    
    def mark_complete(self) -> None:
        print("\n--- Marking Task Done ---")
        task_id = self.get_task_id()
        
        if task_id is None:
            return
        
        if self.todo_manager.mark_complete(task_id):
            print("Task marked as done! ✅")
        else:
            print(f"No task found with number {task_id}")
    
    def mark_incomplete(self) -> None:
        print("\n--- Marking Task Not Done ---")
        task_id = self.get_task_id()
        
        if task_id is None:
            return
        
        if self.todo_manager.mark_incomplete(task_id):
            print("Task marked as not done! 📋")
        else:
            print(f"No task found with number {task_id}")
    
    def run(self) -> None:
        print("Welcome to My Todo App!")
        print("Let's get organized! 🚀")
        
        while True:
            self.display_menu()
            choice = self.get_user_choice()
            
            if choice == '1':
                self.add_task()
            elif choice == '2':
                self.list_tasks()
            elif choice == '3':
                self.update_task()
            elif choice == '4':
                self.delete_task()
            elif choice == '5':
                self.mark_complete()
            elif choice == '6':
                self.mark_incomplete()
            elif choice == '7':
                print("Thanks for using My Todo App! See you next time! 👋")
                sys.exit(0)
            else:
                print("Please pick a number between 1 and 7!")
Python

Step 9: Create the Main Application File

Create src\main.py with this content:

from managers.todo_manager import TodoManager
from ui.console_ui import ConsoleUI

def main():
    todo_manager = TodoManager()
    console_ui = ConsoleUI(todo_manager)
    console_ui.run()

if __name__ == "__main__":
    main()
Python

Step 10:Run Your Application

python src\main.py
Python

Leave a Reply

error: Content is protected !!