DEV Community

Cover image for Building Terminal GPT: How Plugins Turned a Chatbot into an AI Agent
Josiah Mbao
Josiah Mbao

Posted on

Building Terminal GPT: How Plugins Turned a Chatbot into an AI Agent

From Simple CLI Chat to the Real Insight: Plugins as the Boundary Between Reasoning and Action

When I first started building Terminal GPT, I envisioned a simple CLI chat interface with an LLM backend. But as I iterated through the architecture, something unexpected happened - the plugin system I built to extend functionality became the most fascinating and powerful part of the entire project.

The key insight: plugins aren't just features - they're the essential boundary between AI reasoning and real-world action. This architectural pattern fundamentally changed how I think about building AI systems.

Why Plugin Architecture Matters

What started as a way to add basic file operations and calculations evolved into a formalized plugin architecture that fundamentally changed how my AI assistant interacts with the world. Instead of being limited to text-based responses, my AI can now:

  • Read and write files
  • Perform complex calculations
  • Access live sports data
  • Execute system operations
  • And much more through extensible plugins

The Architecture That Made It Click

The real learning moment came when I realized that plugins aren't just features - they're a fundamental architectural pattern for building AI systems that can actually do things.

Key Design Decisions:

1. Formal Plugin Contracts

class Plugin(ABC):
    name: str
    description: str
    input_model: Type[BaseModel]
    output_model: Type[BaseModel]

    async def run(self, input: BaseModel) -> BaseModel: ...
Enter fullscreen mode Exit fullscreen mode

2. Automatic Registration
Plugins automatically register themselves with the LLM, creating a dynamic tool ecosystem.

3. Structured Input/Output
Pydantic models ensure type safety and clear contracts between the AI and tools.

4. Isolated Execution
Each plugin runs in its own validated environment with error boundaries, ensuring failures are contained and don't crash the entire system.

The Technical Stack

  • Backend: Python with FastAPI for the REST API
  • CLI: Rich terminal interface with beautiful formatting
  • LLM Integration: OpenRouter for flexible model access
  • Plugin System: Pydantic for contracts, async/await for execution
  • Architecture: Clean separation with domain-driven design

What I Learned

The plugin architecture taught me that building AI systems isn't just about the model - it's about creating a framework where the AI can leverage external capabilities. This pattern:

  • Makes the system infinitely extensible
  • Provides clear boundaries between concerns
  • Enables graceful failure handling
  • Creates opportunities for community contributions

Personal Touch: Building My Own AI Agent

What makes this project especially cool for me is that I'm essentially building an AI agent from scratch. As a Houston Rockets and Manchester United fan, I've added sports tools so my AI can answer all my stat-head questions. I've also given the AI some personality - it's got a laid-back, slightly whimsical character that makes our conversations more engaging. It's like having a coding buddy who's also into sports and can actually do things, not just chat!
AI Agent answering sports questions

The Star of the Show

What began as a simple file reader plugin is now a sophisticated system where the AI can reason about which tools to use, chain multiple operations together, and provide structured results back to the conversation.

What's Next?

I'm curious to hear your thoughts on what tools would be valuable in an AI assistant like this. I'm thinking about:

  • Git operations (status, commits, branches)
  • Code analysis and refactoring suggestions
  • System monitoring and diagnostics
  • Package management (pip, npm, cargo)
  • API testing and documentation generation

What would you add to make this more useful in your daily development workflow?


Media Assets

Screenshot 1: Terminal Interface

Terminal interface showing a conversation with tool execution results

Show the CLI interface with a conversation where the AI has just executed a plugin, displaying the structured results.

Screenshot 2: Plugin Architecture Diagram

Plugin architecture diagram

The mental model: AI reasons about what to do, then hands off to specialized plugins that safely perform actions and return structured results.

Code Snippet: Simple Plugin Implementation

Here's a clean example of how easy it is to add new capabilities to the system:

from pydantic import BaseModel
from terminal_gpt.domain.plugins import Plugin

class ReadFileInput(BaseModel):
    path: str

class ReadFileOutput(BaseModel):
    content: str

class ReadFilePlugin(Plugin):
    name = "read_file"
    description = "Reads a text file from disk"
    input_model = ReadFileInput
    output_model = ReadFileOutput

    async def run(self, input: ReadFileInput) -> ReadFileOutput:
        content = Path(input.path).read_text()
        return ReadFileOutput(content=content)
Enter fullscreen mode Exit fullscreen mode

I'd love to hear your thoughts on plugin architectures in AI projects. What patterns have you found useful, and what would you add to make systems like this even more powerful?

Top comments (0)