DEV Community

Cover image for Building a Local AI Task Planner with ClientAI and Ollama
Igor Benav
Igor Benav

Posted on

Building a Local AI Task Planner with ClientAI and Ollama

In this tutorial, we'll build an AI-powered task planner using ClientAI and Ollama. Our planner will break down goals into actionable tasks, create realistic timelines, and manage resources — all of this running in your own machine.

Our task planner will be capable of:

  • Breaking down goals into specific, actionable tasks
  • Creating realistic timelines with error handling
  • Managing and allocating resources effectively
  • Providing structured, formatted plans

For ClientAI's docs see here and for Github Repo, here.

Setting Up Our Environment

First, create a new directory for your project:

mkdir local_task_planner
cd local_task_planner
Enter fullscreen mode Exit fullscreen mode

Install ClientAI with Ollama support:

pip install clientai[ollama]
Enter fullscreen mode Exit fullscreen mode

Make sure you have Ollama installed on your system. You can get it from Ollama's website.

Create our main Python file:

touch task_planner.py
Enter fullscreen mode Exit fullscreen mode

Let's start with our core imports:

from datetime import datetime, timedelta
from typing import Dict, List
import logging

from clientai import ClientAI
from clientai.agent import create_agent, tool
from clientai.ollama import OllamaManager

logger = logging.getLogger(__name__)
Enter fullscreen mode Exit fullscreen mode

Each component plays a crucial role:

  • datetime: Helps us manage task timelines and scheduling
  • ClientAI: Provides our AI framework
  • OllamaManager: Manages our local AI model
  • Various utility modules for type hints and logging

Building the Task Planner Core

First, let's create our TaskPlanner class that will manage the AI interaction:

class TaskPlanner:
    """A local task planning system using Ollama."""

    def __init__(self):
        """Initialize the task planner with Ollama."""
        self.manager = OllamaManager()
        self.client = None
        self.planner = None

    def start(self):
        """Start the Ollama server and initialize the client."""
        self.manager.start()
        self.client = ClientAI("ollama", host="http://localhost:11434")

        self.planner = create_agent(
            client=self.client,
            role="task planner",
            system_prompt="""You are a practical task planner. Break down goals into
            specific, actionable tasks with realistic time estimates and resource needs.
            Use the tools provided to validate timelines and format plans properly.""",
            model="llama3",
            step="think",
            tools=[validate_timeline, format_plan],
            tool_confidence=0.8,
            stream=True,
        )
Enter fullscreen mode Exit fullscreen mode

This class serves as our foundation. It manages the Ollama server lifecycle, creates and configures our AI client and sets up our planning agent with specific capabilities.

Creating Our Planning Tools

Now let's build the tools our AI will use. First, the timeline validator:

@tool(name="validate_timeline")
def validate_timeline(tasks: Dict[str, int]) -> Dict[str, dict]:
    """
    Validate time estimates and create a realistic timeline.

    Args:
        tasks: Dictionary of task names and estimated hours

    Returns:
        Dictionary with start dates and deadlines
    """
    try:
        current_date = datetime.now()
        timeline = {}
        accumulated_hours = 0

        for task, hours in tasks.items():
            try:
                hours_int = int(float(str(hours)))

                if hours_int <= 0:
                    logger.warning(f"Skipping task {task}: Invalid hours value {hours}")
                    continue

                days_needed = hours_int / 6
                start_date = current_date + timedelta(hours=accumulated_hours)
                end_date = start_date + timedelta(days=days_needed)

                timeline[task] = {
                    "start": start_date.strftime("%Y-%m-%d"),
                    "end": end_date.strftime("%Y-%m-%d"),
                    "hours": hours_int,
                }

                accumulated_hours += hours_int

            except (ValueError, TypeError) as e:
                logger.warning(f"Skipping task {task}: Invalid hours value {hours} - {e}")
                continue

        return timeline
    except Exception as e:
        logger.error(f"Error validating timeline: {str(e)}")
        return {}
Enter fullscreen mode Exit fullscreen mode

This validator converts time estimates to working days, handles invalid inputs gracefully, creates realistic sequential scheduling and provides detailed logging for debugging.

Next, let's create our plan formatter:

@tool(name="format_plan")
def format_plan(
    tasks: List[str],
    timeline: Dict[str, dict],
    resources: List[str]
) -> str:
    """
    Format the plan in a clear, structured way.

    Args:
        tasks: List of tasks
        timeline: Timeline from validate_timeline
        resources: List of required resources

    Returns:
        Formatted plan as a string
    """
    try:
        plan = "== Project Plan ==\n\n"

        plan += "Tasks and Timeline:\n"
        for i, task in enumerate(tasks, 1):
            if task in timeline:
                t = timeline[task]
                plan += f"\n{i}. {task}\n"
                plan += f"   Start: {t['start']}\n"
                plan += f"   End: {t['end']}\n"
                plan += f"   Estimated Hours: {t['hours']}\n"

        plan += "\nRequired Resources:\n"
        for resource in resources:
            plan += f"- {resource}\n"

        return plan
    except Exception as e:
        logger.error(f"Error formatting plan: {str(e)}")
        return "Error: Unable to format plan"
Enter fullscreen mode Exit fullscreen mode

Here we want to create a consistent, readable output with proper task numbering and organized timeline.

Building the Interface

Let's create a user-friendly interface for our planner:

def get_plan(self, goal: str) -> str:
    """
    Generate a plan for the given goal.

    Args:
        goal: The goal to plan for

    Returns:
        A formatted plan string
    """
    if not self.planner:
        raise RuntimeError("Planner not initialized. Call start() first.")

    return self.planner.run(goal)

def main():
    planner = TaskPlanner()

    try:
        print("Task Planner (Local AI)")
        print("Enter your goal, and I'll create a practical, timeline-based plan.")
        print("Type 'quit' to exit.")

        planner.start()

        while True:
            print("\n" + "=" * 50 + "\n")
            goal = input("Enter your goal: ")

            if goal.lower() == "quit":
                break

            try:
                plan = planner.get_plan(goal)
                print("\nYour Plan:\n")
                for chunk in plan:
                    print(chunk, end="", flush=True)
            except Exception as e:
                print(f"Error: {str(e)}")

    finally:
        planner.stop()

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

Our interface provides:

  • Clear user instructions
  • Real-time plan generation with streaming
  • Proper error handling
  • Clean shutdown management

Example Usage

Here's what you'll see when you run the planner:

Task Planner (Local AI)
Enter your goal, and I'll create a practical, timeline-based plan.
Type 'quit' to exit.

==================================================

Enter your goal: Create a personal portfolio website

Your Plan:

== Project Plan ==

Tasks and Timeline:
1. Requirements Analysis and Planning
   Start: 2024-12-08
   End: 2024-12-09
   Estimated Hours: 6

2. Design and Wireframing
   Start: 2024-12-09
   End: 2024-12-11
   Estimated Hours: 12

3. Content Creation
   Start: 2024-12-11
   End: 2024-12-12
   Estimated Hours: 8

4. Development
   Start: 2024-12-12
   End: 2024-12-15
   Estimated Hours: 20

Required Resources:
- Design software (e.g., Figma)
- Text editor or IDE
- Web hosting service
- Version control system
Enter fullscreen mode Exit fullscreen mode

Future Improvements

Consider these enhancements for your own task planner:

  • Add dependency tracking between tasks
  • Include cost calculations for resources
  • Save plans to files or project management tools
  • Track progress against the original plan
  • Add validation for resource availability
  • Implement parallel task scheduling
  • Add support for recurring tasks
  • Include priority levels for tasks

To see more about ClientAI, go to the docs.

Connect With Me

If you have any questions about this tutorial or want to share your improvements to the task planner, feel free to reach out:

Top comments (0)