Skip to content

Askimo CLI Architecture Guide

The Askimo CLI is a command-line interface application that provides interactive and non-interactive modes for AI-powered assistance. It supports piped input, recipe execution, and rich terminal interactions with command history and auto-completion.

  • Language: Kotlin
  • Terminal Framework: JLine 3
  • Architecture Pattern: Command Pattern + Session Management
  • Concurrency: Kotlin Coroutines
  • Persistence: Shared with Desktop module (SQLite via Exposed)

The CLI application follows a command-driven architecture with clear separation between interactive and non-interactive modes:

graph TD
    A[Terminal Layer
JLine Terminal & Input Processing] B[Command Layer
Command Handlers & Parsers] C[Session Layer
Session Management & Chat Service] D[Core Layer
Shared Module: Providers, Repository, Recipes] A --> B B --> C C --> D style A fill:#e1f5ff,stroke:#0288d1,stroke-width:2px style B fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style C fill:#fff3e0,stroke:#ef6c00,stroke-width:2px style D fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
  1. Mode Separation: Clear distinction between interactive and non-interactive modes
  2. Command Pattern: Each operation is encapsulated as a command handler
  3. Session-Centric: All operations revolve around a chat session
  4. Stream-Friendly: First-class support for piped input/output
  5. Extensibility: Easy to add new commands and recipes

The CLI module is organized into the following key packages:

cli/
├── ChatCli.kt # Application entry point and main loop
├── commands/ # Command handlers
│ ├── HelpCommandHandler.kt
│ ├── ConfigCommandHandler.kt
│ ├── SessionCommandHandlers.kt
│ └── ...
├── recipes/ # Recipe system
│ ├── RecipeExecutor.kt
│ ├── RecipeRegistry.kt
│ ├── ToolRegistry.kt
│ └── DefaultRecipeInitializer.kt
├── util/ # Utilities
│ ├── CompositeCommandExecutor.kt
│ ├── NonInteractiveCommandParser.kt
│ └── ...
├── autocompleter/ # Terminal auto-completion
│ └── CliCommandCompleter.kt
├── LoadingIndicator.kt # Terminal UI feedback
├── MarkdownJLineRenderer.kt # Markdown rendering in terminal
└── MarkdownStreamingSink.kt # Streaming output handler
PackagePurpose
commands/Command handlers for both interactive and non-interactive modes
recipes/YAML-based automation recipes and execution engine
util/Command parsing, execution, and utility functions
autocompleter/JLine auto-completion for commands
Root packageMain entry point, rendering, and terminal interaction

Handles all terminal I/O, user input, and rendering. Provides rich terminal features like history, auto-completion, and multi-line input.

Key Components:

  • Terminal: Low-level terminal control
  • LineReader: Interactive line reading with history
  • Parser: Multi-line input parsing with continuation support
  • Completer: Command and argument auto-completion

Features:

  • Command history with search (Ctrl+R)
  • Tab completion for commands
  • Multi-line input with backslash continuation
  • Markdown rendering in terminal
  • Loading indicators and progress feedback

Implements the Command Pattern for handling user actions. Each command is a self-contained handler.

Command Types:

Shared Commands (available in both modes):

  • Help, Config, Providers, Models, Parameters, Tools, Version

Interactive-Only Commands:

  • Copy, Clear Memory, Project Management, Session Management

Non-Interactive-Only Commands:

  • Recipe Management (Create, List, Delete)

Command Handler Interface:

Command Handler
├── keyword: String (e.g., ":help", ":config")
├── handle(ParsedLine): Unit
└── getDescription(): String

Manages the chat session lifecycle and coordinates with the Core layer.

Key Components:

  • Session: Maintains conversation state and context
  • ChatService: Coordinates message sending and streaming
  • SessionMode: Differentiates between CLI_INTERACTIVE and CLI_PROMPT modes

Responsibilities:

  • Maintain conversation history
  • Manage provider and model configuration
  • Handle context preparation
  • Coordinate streaming responses

Shared functionality used by both CLI and Desktop applications.

Components:

  • Providers: AI provider integrations (OpenAI, Anthropic, etc.)
  • Repository: Data persistence layer
  • Session: Core session management
  • Recipes: YAML-based automation definitions

The CLI supports three distinct execution modes:

Launched when no arguments are provided. Provides a REPL-style interface.

askimo> [user input]

Features:

  • Command history and search
  • Tab completion
  • Multi-line input with \ continuation
  • Session management
  • Real-time streaming responses

Single prompt execution with optional piped input.

askimo -p "your prompt" < input.txt
askimo -p "direct prompt"
echo "data" | askimo -p "analyze this"

Features:

  • One-shot execution
  • Stdin piping support
  • Automatic context building from piped input

Execute YAML-defined automation recipes.

askimo -r recipe-name --set key=value

Features:

  • Multi-step automation
  • Variable substitution
  • External tool integration
  • Retry logic with exponential backoff

The application follows different flows depending on the execution mode:

graph TD
    A[User Input
JLine LineReader] --> B[Parser
Parse command or chat message] B -->|Command| C[CommandHandler] B -->|Chat Message| D[Session] C --> E[Execute] D --> F[Provider] F --> G[Stream Response] G --> H[Terminal Output] style A fill:#e1f5ff,stroke:#0288d1,stroke-width:2px style B fill:#fff3e0,stroke:#ef6c00,stroke-width:2px style C fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style D fill:#e8f5e9,stroke:#388e3c,stroke-width:2px style E fill:#fce4ec,stroke:#c2185b,stroke-width:2px style F fill:#e8f5e9,stroke:#388e3c,stroke-width:2px style G fill:#fff9c4,stroke:#f57f17,stroke-width:2px style H fill:#e1f5ff,stroke:#0288d1,stroke-width:2px
graph TD
    A[Recipe Name] --> B[Registry]
    B --> C[Executor]
    C --> D[Steps]
    D --> E[Prompt Step]
    D --> F[Tool Step]
    D --> G[Loop Step]
    D --> H[Parallel Step]
    E --> I[Output/Result]
    F --> I
    G --> I
    H --> I

    style A fill:#e1f5ff,stroke:#0288d1,stroke-width:2px
    style B fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
    style C fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
    style D fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
    style E fill:#fce4ec,stroke:#c2185b,stroke-width:2px
    style F fill:#fce4ec,stroke:#c2185b,stroke-width:2px
    style G fill:#fce4ec,stroke:#c2185b,stroke-width:2px
    style H fill:#fce4ec,stroke:#c2185b,stroke-width:2px
    style I fill:#fff9c4,stroke:#f57f17,stroke-width:2px

Each user action is encapsulated as a command handler with a consistent interface:

  • Keyword-based routing
  • Unified handling mechanism
  • Easy to add new commands

The CLI adapts its behavior based on execution mode:

  • Interactive: Full REPL with terminal features
  • Prompt: One-shot execution with piping support
  • Recipe: Multi-step automation with tool integration

AI responses are streamed in real-time:

  • Token-by-token rendering
  • Markdown formatting on-the-fly
  • Loading indicators with elapsed time
  • Non-blocking terminal updates

YAML-based declarative automation:

  • Step-by-step execution
  • Variable substitution and overrides
  • Tool allowlisting for security
  • Retry logic for transient failures

The recipe system provides YAML-based automation for complex multi-step tasks.

name: example
description: Example recipe
steps:
  - type: prompt
    prompt: "Step 1 prompt"
  - type: tool
    tool: read_file
    args:
      path: "file.txt"
  • prompt: Send a prompt to AI
  • tool: Execute a tool (file operations, code execution, etc.)
  • loop: Iterate over items
  • parallel: Execute steps concurrently

Manages available tools and enforces security:

  • Default tools (file operations, search, etc.)
  • Tool allowlisting per recipe
  • Safe execution environment

The CLI runs on multiple platforms with terminal-specific adaptations:

  • macOS: Full terminal support with native features
  • Windows: PowerShell and CMD support
  • Linux: Bash, Zsh, and other shell support

Input Handling:

  • Stdin piping for data processing
  • Multi-line input with continuation
  • Command history persistence
  • Auto-completion

Output Rendering:

  • ANSI color support
  • Markdown rendering with syntax highlighting
  • Loading indicators
  • Streaming output
  1. Create a new command handler implementing CommandHandler
  2. Define keyword (e.g., :mycommand)
  3. Implement handle(ParsedLine) method
  4. Add to appropriate command list (shared/interactive/non-interactive)
  5. Update help text
  1. Define recipe in YAML format
  2. Place in recipes directory or user config
  3. Use variable substitution with ${var} syntax
  4. Test with --set overrides
  5. Document in recipe list
  • Use MarkdownJLineRenderer for formatted output
  • Show loading indicators for long operations
  • Stream responses token-by-token for better UX
  • Handle terminal width and scrolling gracefully

When contributing to the CLI module, please:

  1. Follow the Command Pattern for new features
  2. Support both interactive and non-interactive modes where applicable
  3. Write tests for command handlers
  4. Update help text and documentation
  5. Follow Kotlin coding conventions