Files
loyal_companion/docs/implementation/phase-4-complete.md
latte d957120eb3
All checks were successful
Enterprise AI Code Review / ai-review (pull_request) Successful in 38s
i forgot too commit
2026-02-01 15:57:45 +01:00

21 KiB

Phase 4 Complete: CLI Client

Overview

Phase 4 successfully implemented the CLI (Command Line Interface) client for Loyal Companion, providing a quiet, terminal-based interface for private conversations.


What Was Accomplished

1. Complete CLI Application

Created directory structure:

cli/
├── __init__.py           # Module exports
├── main.py               # Typer CLI application (382 lines)
├── client.py             # HTTP client for Web API (179 lines)
├── config.py             # Configuration management (99 lines)
├── session.py            # Local session persistence (154 lines)
└── formatters.py         # Terminal response formatting (251 lines)

Entry point:

lc                        # Executable CLI script (11 lines)

Lines of code:

  • main.py: 382 lines
  • client.py: 179 lines
  • config.py: 99 lines
  • session.py: 154 lines
  • formatters.py: 251 lines
  • lc: 11 lines
  • Total: ~1,076 lines

2. CLI Commands

The CLI provides a complete set of commands for interacting with Loyal Companion:

Talk Command

lc talk - Start or resume a conversation

Options:

  • --session <name> / -s <name> - Use named session
  • --new / -n - Start fresh session
  • --mood / --no-mood - Toggle mood display (default: on)
  • --relationship / --no-relationship - Toggle relationship display (default: off)

Examples:

lc talk                    # Resume default session
lc talk --new              # Start fresh default session
lc talk -s work            # Resume 'work' session
lc talk -s personal --new  # Start fresh 'personal' session

Features:

  • Interactive conversation loop
  • Real-time responses from AI
  • Ctrl+D or Ctrl+C to exit
  • Auto-save on exit
  • Session continuity across invocations

History Command

lc history - Show conversation history

Options:

  • --session <name> / -s <name> - Show specific session
  • --limit <n> / -n <n> - Limit number of messages (default: 50)

Examples:

lc history               # Show default session history
lc history -s work       # Show 'work' session history
lc history -n 10         # Show last 10 messages

Sessions Command

lc sessions - List or delete sessions

Options:

  • --delete <name> / -d <name> - Delete a session

Examples:

lc sessions              # List all sessions
lc sessions -d work      # Delete 'work' session

Config Command

lc config-cmd - Manage configuration

Options:

  • --show - Show current configuration
  • --api-url <url> - Set API URL
  • --email <email> - Set email address
  • --reset - Reset configuration to defaults

Examples:

lc config-cmd --show                           # Show config
lc config-cmd --api-url http://localhost:8080  # Set API URL
lc config-cmd --email user@example.com         # Set email
lc config-cmd --reset                          # Reset config

Auth Command

lc auth - Manage authentication

Options:

  • --logout - Clear stored token

Examples:

lc auth           # Show auth status
lc auth --logout  # Clear token

Health Command

lc health - Check API health

Examples:

lc health    # Check if API is reachable

3. HTTP Client

File: cli/client.py

Features:

  • Full integration with Web API
  • Token-based authentication
  • Clean error handling
  • Context manager support

Methods:

  • request_token(email) - Request auth token
  • send_message(session_id, message) - Send chat message
  • get_history(session_id, limit) - Get conversation history
  • list_sessions() - List all sessions
  • delete_session(session_id) - Delete a session
  • health_check() - Check API health

Usage:

from cli.client import LoyalCompanionClient

client = LoyalCompanionClient("http://localhost:8080", "auth_token")
response = client.send_message("session_123", "Hello!")
client.close()

# Or with context manager
with LoyalCompanionClient(url, token) as client:
    response = client.send_message(session_id, message)

4. Configuration Management

File: cli/config.py

Configuration stored in: ~/.lc/config.json

Settings:

{
  "api_url": "http://127.0.0.1:8080",
  "auth_token": "web:user@example.com",
  "email": "user@example.com",
  "allow_emoji": false,
  "default_session": "default",
  "auto_save": true,
  "show_mood": true,
  "show_relationship": false,
  "show_facts": false,
  "show_timestamps": false
}

Environment variables:

  • LOYAL_COMPANION_API_URL - Override API URL
  • LOYAL_COMPANION_TOKEN - Override auth token

Automatic creation:

  • Config directory created on first run
  • Config file saved automatically
  • Persistent across CLI invocations

5. Session Management

File: cli/session.py

Sessions stored in: ~/.lc/sessions.json

Session data:

{
  "default": {
    "session_id": "cli_default_7ab5231d12eb3e88",
    "name": "default",
    "created_at": "2026-02-01T14:30:00.000000",
    "last_active": "2026-02-01T15:45:23.123456",
    "message_count": 42
  },
  "work": {
    "session_id": "cli_work_9cd1234a56ef7b90",
    "name": "work",
    "created_at": "2026-02-01T09:00:00.000000",
    "last_active": "2026-02-01T14:20:15.654321",
    "message_count": 18
  }
}

Features:

  • Multiple named sessions
  • Auto-generated unique session IDs
  • Timestamp tracking
  • Message count tracking
  • Persistence across restarts

6. Response Formatting

File: cli/formatters.py

Two modes:

Plain Text Mode (fallback)

You: I'm feeling overwhelmed today.

Bartender: That sounds heavy. Want to sit with it for a bit?
  Mood: calm

Rich Mode (if rich library available)

  • Color-coded output
  • Bold text for roles
  • Formatted metadata panels
  • Syntax highlighting
  • Better readability

Features:

  • Configurable display options
  • Mood information
  • Relationship information
  • Facts learned count
  • Timestamps (optional)
  • Error/info/success messages

7. Authentication Flow

Phase 4 approach: Same simple token as Web platform

Flow:

  1. First time:

    $ lc talk
    Email address: alice@example.com
    Authenticated as alice@example.com
    Bartender is here.
    ...
    
  2. Subsequent runs:

    $ lc talk
    Bartender is here.
    Resuming session 'default' (15 messages)
    ...
    
  3. Token stored in: ~/.lc/config.json

  4. Logout:

    $ lc auth --logout
    Authentication cleared
    

Security note:

  • Token is stored in plain text in config file
  • For Phase 4, token is simple: web:{email}
  • In production, should use proper JWT with expiration

Architecture

┌──────────────────────────────────────────────────────────┐
│                    Terminal (User)                        │
└──────────────────────────────────────────────────────────┘
                          │
                          ▼
┌──────────────────────────────────────────────────────────┐
│              Loyal Companion CLI (lc)                     │
│  ┌────────────────────────────────────────────────────┐  │
│  │  Typer Application (main.py)                       │  │
│  │  - talk command                                    │  │
│  │  - history command                                 │  │
│  │  - sessions command                                │  │
│  │  - config command                                  │  │
│  │  - auth command                                    │  │
│  └────────────────────────────────────────────────────┘  │
│                          │                                │
│  ┌────────────────────────────────────────────────────┐  │
│  │  HTTP Client (client.py)                           │  │
│  │  - LoyalCompanionClient                            │  │
│  │  - REST API calls                                  │  │
│  └────────────────────────────────────────────────────┘  │
│                          │                                │
│  ┌──────────────┬──────────────────┬──────────────────┐  │
│  │ Config       │ Session Manager  │ Formatters       │  │
│  │ (~/.lc/)     │ (sessions.json)  │ (rich/plain)     │  │
│  └──────────────┴──────────────────┴──────────────────┘  │
└──────────────────────────────────────────────────────────┘
                          │
                     HTTP/REST
                          │
                          ▼
┌──────────────────────────────────────────────────────────┐
│              FastAPI Web Application                      │
│              (Phase 3: Web Platform)                      │
└──────────────────────────────────────────────────────────┘
                          │
                          ▼
┌──────────────────────────────────────────────────────────┐
│              ConversationGateway                          │
│  (Platform: WEB, Intimacy: HIGH)                          │
└──────────────────────────────────────────────────────────┘
                          │
                          ▼
┌──────────────────────────────────────────────────────────┐
│                   Living AI Core                          │
└──────────────────────────────────────────────────────────┘

Installation & Usage

Installation

  1. Install dependencies:

    pip install typer httpx rich
    
  2. Make CLI executable:

    chmod +x lc
    
  3. Optional: Add to PATH:

    # Add to ~/.bashrc or ~/.zshrc
    export PATH="/path/to/loyal_companion:$PATH"
    
    # Or create symlink
    ln -s /path/to/loyal_companion/lc /usr/local/bin/lc
    

First Run

# Start web server (in one terminal)
python3 run_web.py

# Use CLI (in another terminal)
./lc talk

First time setup:

$ ./lc talk
Email address: alice@example.com
Authenticated as alice@example.com
Bartender is here.
Type your message and press Enter. Press Ctrl+D to end.

You: I miss someone tonight.

Bartender: That kind of missing doesn't ask to be solved.
           Do you want to talk about what it feels like in your body,
           or just let it be here for a moment?

You: Just let it be.

Bartender: Alright. I'm here.

You: ^D

Session saved.

Subsequent Usage

# Resume default session
./lc talk

# Start new session
./lc talk --new

# Use named session
./lc talk -s work

# View history
./lc history

# List sessions
./lc sessions

# Check configuration
./lc config-cmd --show

Testing

Component Tests

Created: test_cli.py

Tests:

  • Configuration management
  • Session management
  • Response formatting
  • HTTP client instantiation

Run tests:

python3 test_cli.py

Output:

============================================================
Loyal Companion CLI - Component Tests
============================================================

Testing configuration...
✓ Configuration works

Testing session management...
✓ Session management works

Testing response formatter...
✓ Response formatter works

Testing HTTP client...
✓ HTTP client works

============================================================
All tests passed! ✓
============================================================

Manual Testing Checklist

  • lc --help shows help
  • lc talk --help shows talk command help
  • lc health checks API (when server running)
  • lc talk authenticates first time
  • lc talk resumes session
  • lc talk --new starts fresh
  • lc talk -s work uses named session
  • lc history shows conversation
  • lc sessions lists sessions
  • lc sessions -d test deletes session
  • lc config-cmd --show shows config
  • lc auth shows auth status
  • lc auth --logout clears token

Comparison: CLI vs Web vs Discord

Feature Discord Web CLI
Platform Discord app Browser Terminal
Intimacy LOW/MEDIUM HIGH HIGH
Interface Rich (buttons, embeds) Rich (HTML/CSS/JS) Minimal (text)
Auth Discord OAuth Simple token Simple token
Sessions Channels/DMs Web sessions Named sessions
Local storage None localStorage ~/.lc/
Real-time Yes (gateway) No (polling) No (request/response)
Formatting Rich (markdown, emoji) Rich (HTML) Plain/Rich text
Offline mode No No No (HTTP client)
Noise level High (social) Medium (UI elements) Low (quiet)
Use case Social bar Quiet back room Empty table at closing

Design Philosophy

Quietness

The CLI embodies the "empty table at closing time" philosophy:

Quiet:

  • No spinners or progress bars
  • No ASCII art or banners
  • No excessive logging
  • Minimal output

Intentional:

  • Explicit commands
  • Named sessions for context switching
  • No automatic behaviors
  • User controls everything

Focused:

  • Text-first interface
  • No distractions
  • No engagement metrics
  • Pure conversation

Text-First Design

No emojis by default:

cli_allow_emoji: bool = False  # Can be enabled in config

No typing indicators:

  • No "Bartender is typing..."
  • Immediate response display
  • No artificial delays

No seen/read receipts:

  • No engagement metrics
  • No pressure to respond
  • Just presence

Known Limitations

Current (Phase 4)

  1. No real-time updates:

    • Request/response only
    • No WebSocket support
    • No push notifications
  2. No offline mode:

    • Requires web server running
    • Requires network connection
    • No local-only conversations
  3. Simple authentication:

    • Token stored in plain text
    • No JWT expiration
    • No refresh tokens
  4. No rich formatting:

    • Plain text only (unless rich library)
    • No markdown rendering in messages
    • No syntax highlighting for code blocks
  5. No image support:

    • Text-only conversations
    • No image upload
    • No image viewing
  6. Single user per config:

    • One email/token per machine
    • No multi-user support
    • No profile switching

To Be Addressed

Phase 5 (Enhancements):

  • Add proper JWT authentication
  • Add markdown rendering in terminal
  • Add image viewing (ASCII art or external viewer)
  • Add multi-user profiles
  • Add WebSocket for real-time (optional)

Dependencies

Required:

  • typer>=0.9.0 - CLI framework
  • httpx>=0.26.0 - HTTP client

Optional:

  • rich>=13.7.0 - Rich terminal formatting (recommended)

Added to requirements.txt:

# CLI Platform
typer>=0.9.0
httpx>=0.26.0
rich>=13.7.0

File Structure Summary

loyal_companion/
├── cli/                         # CLI client (new)
│   ├── __init__.py
│   ├── main.py                  # Typer application
│   ├── client.py                # HTTP client
│   ├── config.py                # Configuration
│   ├── session.py               # Session manager
│   └── formatters.py            # Response formatting
├── lc                           # CLI entry point (new)
├── test_cli.py                  # CLI tests (new)
├── requirements.txt             # Updated with CLI deps
└── docs/
    └── implementation/
        └── phase-4-complete.md  # This file

Success Metrics

Code Quality

  • 1,076 lines of clean, tested code
  • Modular design (5 separate modules)
  • All components tested
  • Type hints throughout
  • Docstrings for all public functions

Functionality

  • Full CLI application with 6 commands
  • HTTP client with complete Web API coverage
  • Local session management
  • Configuration persistence
  • Authentication flow
  • Response formatting (plain + rich)

User Experience

  • Intuitive command structure
  • Helpful error messages
  • Automatic authentication
  • Session continuity
  • Quiet, minimal design
  • No unnecessary output

Architecture

  • Clean separation of concerns
  • HTTP client communicates with Web API
  • Web API uses ConversationGateway
  • Gateway uses Living AI Core
  • CLI is thin client (not duplicate logic)

Example Session

$ lc talk
Email address: alice@example.com
Authenticated as alice@example.com
Bartender is here.
Type your message and press Enter. Press Ctrl+D to end.

You: I had a rough day at work.

Bartender: Sounds like it took a lot out of you. Want to talk about what made it rough, or just let it sit?

You: My manager criticized my code review in front of the whole team.

Bartender: That's embarrassing and it sucks to be called out like that. The public part probably stung more than the criticism itself.

You: Yeah, exactly. I don't mind the feedback but why in front of everyone?

Bartender: Sounds like a power move more than a teaching moment. Did you get a chance to talk to them privately after?

You: No, I just left.

Bartender: Sometimes walking away is the right call. You don't have to process it all at once.

You: Thanks. I needed to hear that.

Bartender: Anytime. I'm here.

You: ^D

Session saved.

$ lc sessions
Found 1 session(s):

  default
    Created: 2026-02-01T15:30:00.000000
    Last active: 2026-02-01T15:35:23.123456
    Messages: 8

$ lc history -n 3
History for session 'default' (3 messages):

You: Thanks. I needed to hear that.
  [15:35:15]

Bartender: Anytime. I'm here.
  [15:35:23]

Next Steps

Phase 5: Cross-Platform Enhancements

With all three platforms complete (Discord, Web, CLI), Phase 5 focuses on:

  1. Platform Identity Linking

    • PlatformIdentity model
    • Account linking UI
    • Cross-platform user lookup
    • Shared memory across platforms
  2. Enhanced Authentication

    • Proper JWT tokens
    • Magic link email
    • Token expiration
    • Refresh tokens
    • OAuth integration
  3. Real-Time Features

    • WebSocket support (Web)
    • Server-sent events (optional)
    • Push notifications (optional)
  4. Rich Content

    • Markdown rendering (CLI + Web)
    • Image upload/viewing
    • Code syntax highlighting
    • File attachments
  5. Safety & Testing

    • Regression tests for safety constraints
    • Intimacy boundary tests
    • Cross-platform behavior tests
    • Load testing

Conclusion

Phase 4 successfully delivered a complete CLI client:

Full-featured CLI with 6 commands
HTTP client for Web API integration
Local session management
Configuration persistence
Authentication flow
Response formatting (plain + rich)
1,076 lines of tested code
Quiet, minimal, intentional design

The CLI is now the empty table at closing time—quiet, focused, intentional.

Same bartender. Different stools. No one is trapped. 🍺


Completed: 2026-02-01
Status: Phase 4 Complete
Next: Phase 5 - Cross-Platform Enhancements