Metadata-Version: 2.4
Name: lina-assistant
Version: 0.1.0
Summary: Voice-controlled multi-agent coding assistant with plugin architecture
Home-page: https://github.com/AlessandroLiAppDev/lina-assistant
Author: Alessandro Li
Author-email: Alessandro Li <alessandro.li@fullstack-qa.de>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/AlessandroLiAppDev/lina-assistant
Project-URL: Issues, https://github.com/AlessandroLiAppDev/lina-assistant/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: faster-whisper
Requires-Dist: edge-tts
Requires-Dist: pynput
Requires-Dist: pyyaml
Requires-Dist: watchdog
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# Lina Assistant

A voice-controlled multi-agent coding assistant that coordinates AI agents working in parallel. Speak commands, get responses read aloud, and manage multiple Claude Code sessions hands-free.

## The Agent Team

| Agent | Role | Description |
|-------|------|-------------|
| **Lina** | Coordinator | Voice assistant that listens for commands, routes tasks to agents, monitors their status, and reads responses aloud |
| **Athena** | Feature implementation | Direct, efficient — picks up tickets and ships features |
| **Isis** | Feature implementation | Methodical, thorough — confirms understanding before diving in |
| **Cassandra** | Code quality auditor | Reviews code for quality, security, and best practices before PRs |
| **Selene** | Ticket reviewer | Checks implementations against Jira ticket specs, flags gaps |

## Prerequisites

- **macOS** (currently the only supported platform)
- **Python 3.9+**
- **sox** — audio recording (`brew install sox`)
- **Claude Code CLI** — [install guide](https://docs.anthropic.com/en/docs/claude-code/overview)
- **VS Code** — for the lina-bridge terminal extension
- **Microphone access** — grant in System Settings > Privacy & Security > Microphone
- **Accessibility permissions** — required for `pynput` keyboard input (System Settings > Privacy & Security > Accessibility)

## Installation

**One-liner** — copy-paste into your terminal:

```bash
curl -fsSL https://raw.githubusercontent.com/AlessandroLiAppDev/lina-assistant/main/install.sh | bash
```

Or with pip directly:

```bash
pip install lina-assistant && lina setup
```

The setup wizard walks you through everything else (sox, shell aliases, VS Code extension, macOS permissions).

<details>
<summary>Alternative: clone for development</summary>

```bash
git clone https://github.com/AlessandroLiAppDev/lina-assistant.git
cd lina-assistant
pip install -e .
lina setup
```

</details>

## VS Code Extension Setup

Lina communicates with agent terminals through a lightweight VS Code extension called **lina-bridge**. It polls `~/.lina/commands/agents/` for command files and types their contents into the matching named terminal.

To install:

1. Copy the extension folder to `~/.vscode/extensions/alessandro.lina-bridge-0.0.1/`
2. Reload VS Code (`Cmd+Shift+P` → "Reload Window")
3. Create named terminals for your agents (the terminal name must match the agent name in `lina.yaml`)

When Lina sends a command to an agent, it writes to `~/.lina/commands/agents/{name}.txt`. The extension picks it up and delivers it to the terminal named `{name}`.

## Configuration

Lina loads config from the first file found in this order:

1. Explicit path via `--config` / `-c` flag
2. `./lina.yaml` (project-level)
3. `~/.lina/lina.yaml` (global)
4. Built-in defaults

### Full `lina.yaml` reference

```yaml
# Wake word — what you say to activate Lina
wake_word: "alexa"          # Use "alexa" with openwakeword, or train a custom model for "lina"
language: "en"
model: ""                   # Model for Lina's own Claude session (e.g., "claude-sonnet-4-6")

# Plugin selection — each slot can be swapped for a different implementation
plugins:
  stt: faster_whisper       # Speech-to-text: "whisper" or "faster_whisper" (3x faster)
  tts: edge_tts             # Text-to-speech: "edge_tts" (free Microsoft Edge TTS)
  llm: claude_code          # LLM CLI integration: "claude_code"
  ide: vscode               # IDE terminal bridge: "vscode"
  wake_word: openwakeword   # Wake word engine: "openwakeword" (ML-based) or "whisper" (fallback)

# TTS voice settings
tts:
  voice: "en-US-JennyNeural"   # Edge TTS voice name
  rate: "+40%"                  # Speech rate adjustment
  pitch: "+23Hz"                # Pitch adjustment

# STT model sizes (Whisper)
stt:
  wake_model: "base"           # Fast model for wake word detection (when using whisper wake plugin)
  command_model: "medium"      # Accurate model for command transcription

# Audio recording settings
audio:
  silence_threshold: "3%"          # Volume below this = silence (sox format)
  max_command_duration: 20         # Max seconds to record a single command
  conversation_timeout: 15         # Seconds to wait for follow-up in conversation mode
  mic_restore_volume: 75           # Mic volume to restore after TTS playback (0-100)

# Agent definitions
agents:
  - name: athena
    role: "Feature implementation agent"
    model: ""                      # Model override (e.g., "claude-opus-4-6")
    compact_on_new_ticket: true    # Run /compact before sending a new ticket
  - name: isis
    role: "Ticket handling agent"
    model: ""
    compact_on_new_ticket: true
  - name: cassandra
    role: "Code quality auditor"
    model: ""
  - name: selene
    role: "Ticket review agent"
    model: ""
```

## Quick Start

```bash
# Start the voice listener
lina start

# Lina prints: "Lina is listening. Say 'alexa' to activate."

# 1. Say the wake word → you hear a "tink" sound
# 2. Speak your command → you hear a "pop" when it's sent
# 3. Lina transcribes your speech and delivers it to Claude Code
# 4. After the response, Lina says "mhm?" and listens for follow-ups
# 5. Stay silent to return to wake word mode
```

## Multi-Agent Setup

### Defining agents

Add agents to `lina.yaml` under the `agents` key (see configuration reference above). Each agent needs a `name` that matches the terminal name in VS Code.

### Shell aliases

`lina setup` can add these automatically (Step 5). Or add them manually to `~/.zshrc`:

```bash
# Universal launcher — handles both CLI commands and agent sessions
lina() {
  local name="$1"
  shift 2>/dev/null
  if [ -z "$name" ]; then name="lina"; fi

  # lina stop/status/setup/jira → Python CLI commands
  if [ "$name" = "lina" ] && [ -n "$1" ]; then
    command lina "$@"
    return
  fi

  local model="claude-opus-4-6"
  export AGENT_NAME="$name"

  # Load persona from ~/.lina/personas/{name}.md if it exists
  local persona_file="$HOME/.lina/personas/${name}.md"
  local persona=""
  if [ -f "$persona_file" ]; then persona=$(cat "$persona_file"); fi

  tty > "/tmp/.claude-mute-${name}"
  script -q "/tmp/${name}.log" env AGENT_NAME="$name" claude --model "$model" --append-system-prompt "$persona"
  rm -f "/tmp/.claude-mute-${name}"
}

# Agent shortcuts
athena() { lina athena "$@"; }
isis() { lina isis "$@"; }
cassandra() { lina cassandra "$@"; }
selene() { lina selene "$@"; }
```

What each part does:

- `tty > /tmp/.claude-mute-{name}` — creates a mute file so Lina doesn't read this agent's TTS output aloud
- `script -q /tmp/{name}.log claude ...` — starts Claude Code with output logged so Lina can monitor for permission prompts
- `--append-system-prompt "$persona"` — loads the agent's persona from `~/.lina/personas/{name}.md`
- `rm -f /tmp/.claude-mute-{name}` — cleans up the mute file when the session ends

### Agent personas

Place markdown files in `~/.lina/personas/` to give each agent a personality:

```
~/.lina/personas/
├── athena.md    # "You are Athena. Direct, efficient..."
├── isis.md      # "You are Isis. Methodical, thorough..."
├── cassandra.md # "You are Cassandra. Sharp, critical..."
└── selene.md    # "You are Selene. Strict, detail-obsessed..."
```

The persona content is passed to Claude Code via `--append-system-prompt` when launching the agent.

### How agent communication works

1. **Command dispatch**: Lina writes commands to `~/.lina/commands/agents/{name}.txt`
2. **VS Code extension**: Polls the command files and types contents into the matching named terminal
3. **Log monitoring**: Lina watches `/tmp/{name}.log` for permission prompts and reads them aloud
4. **Status files**: Agents write their status to `~/.lina/status/{name}.json` so Lina can track progress

### Boot sequence

1. Open VS Code with named terminals for each agent
2. In each terminal, type the agent alias (e.g., `athena`) — the agent session starts with logging
3. Run `lina start` — Lina begins listening and monitoring all agent logs
4. Speak commands — Lina routes them to the appropriate agent

## Agent Workflow

The full pipeline for ticket work:

```
Lina receives voice command
  → Analyzes Jira ticket
  → Assigns to Athena or Isis (implementation)
  → Agent implements the feature
  → Selene reviews implementation against ticket spec
  → Cassandra audits code quality and security
  → PR is created
```

Agents update their status in `~/.lina/status/{name}.json`:

```json
{
  "agent": "athena",
  "status": "working",
  "task": "implementing login flow",
  "timestamp": "2026-04-24T12:00:00Z"
}
```

Status values: `working` | `done` | `error` | `idle`

## Plugin Architecture

Lina uses a plugin system with 5 slots. Each slot has an abstract base class in `plugins/base.py`.

### Built-in plugins

| Slot | Plugin | Module |
|------|--------|--------|
| STT | `whisper` | `plugins.stt.whisper_stt` |
| STT | `faster_whisper` | `plugins.stt.faster_whisper_stt` |
| TTS | `edge_tts` | `plugins.tts.edge_tts_plugin` |
| LLM | `claude_code` | `plugins.llm.claude_code` |
| IDE | `vscode` | `plugins.ide.vscode` |
| Wake Word | `openwakeword` | `plugins.wake_word.openwakeword_plugin` |
| Wake Word | `whisper` | `plugins.wake_word.whisper_wake` |

### Swapping plugins

Set the plugin name in `lina.yaml` under `plugins`:

```yaml
plugins:
  stt: faster_whisper    # swap to: whisper
  wake_word: openwakeword  # swap to: whisper
```

### Writing custom plugins

1. Subclass the appropriate base class from `plugins/base.py`:
   - `STTPlugin` — speech-to-text (implement `transcribe`, `is_available`)
   - `TTSPlugin` — text-to-speech (implement `speak`, `is_available`)
   - `LLMPlugin` — LLM CLI integration (implement `get_agent_launch_command`, `get_response_hook_config`, `parse_response`, `get_permission_patterns`, `get_mute_config`, `is_available`)
   - `IDEPlugin` — IDE terminal bridge (implement `send_command`, `setup`, `is_available`)
   - `WakeWordPlugin` — wake word detection (implement `start_listening`, `stop`, `pause`, `resume`, `is_available`)

2. Place your plugin at `~/.lina/plugins/<type>/<name>.py` (e.g., `~/.lina/plugins/tts/elevenlabs.py`)

3. Set the plugin name in `lina.yaml`:
   ```yaml
   plugins:
     tts: elevenlabs
   ```

Lina auto-discovers the plugin class by scanning the module for a subclass of the expected base class.

## Jira Integration

Lina includes a Jira Cloud client for reading and managing tickets.

```bash
# First-time setup — enter your Jira URL, email, and API token
lina jira setup

# Fetch a specific ticket
lina jira KAN-41

# List your assigned tickets
lina jira mine

# Search tickets by text
lina jira search "login bug"
```

Credentials are stored in `~/.lina/jira.yaml` (owner-only permissions, gitignored). Get an API token from [Atlassian API tokens](https://id.atlassian.com/manage-profile/security/api-tokens).

## CLI Reference

| Command | Description |
|---------|-------------|
| `lina start` | Start the voice listener (blocks until interrupted) |
| `lina stop` | Stop the voice listener |
| `lina status` | Show Lina status and all agent states |
| `lina setup` | Interactive setup wizard — checks deps, installs missing ones, configures shell |
| `lina agent list` | List configured agents |
| `lina agent start <name>` | Show the command to start an agent session |
| `lina agent stop <name>` | Clear an agent's log file |
| `lina jira <ticket-key>` | Fetch and display a Jira ticket |
| `lina jira mine` | List your assigned tickets |
| `lina jira search <query>` | Search tickets by text |
| `lina jira setup` | Configure Jira credentials |

Global flag: `--config` / `-c` — path to a specific `lina.yaml` file.

## File Structure

```
~/.lina/
├── lina.yaml                          # Main configuration
├── jira.yaml                          # Jira credentials (gitignored, 0600 permissions)
├── lina.pid                           # PID file (created when running)
├── commands/
│   ├── main.txt                       # Lina's own command file
│   └── agents/
│       ├── athena.txt                 # Command dispatch to Athena
│       ├── isis.txt                   # Command dispatch to Isis
│       └── ...
├── personas/
│   ├── athena.md                      # Agent persona (loaded via --append-system-prompt)
│   ├── isis.md
│   └── ...
├── status/
│   ├── athena.json                    # Agent status file
│   ├── isis.json
│   └── ...
└── plugins/                           # User-installed plugins
    ├── stt/
    ├── tts/
    ├── llm/
    └── ide/

/tmp/
├── {name}.log                         # Agent session logs (created by script command)
└── .claude-mute-{name}               # TTS mute files (created by agent aliases)
```

## Dependencies

- [sox](https://sox.sourceforge.net/) — audio recording
- [faster-whisper](https://github.com/SYSTRAN/faster-whisper) — speech recognition (CTranslate2-based, 3x faster than openai-whisper)
- [edge-tts](https://github.com/rany2k22/edge-tts) — text-to-speech
- [pynput](https://github.com/moses-palmer/pynput) — keyboard input
- [watchdog](https://github.com/gorakhargosh/watchdog) — file system monitoring
- [pyyaml](https://pyyaml.org/) — configuration parsing

## License

Apache 2.0 — see [LICENSE](LICENSE)

## Support

- Star the repo
- [Report issues](https://github.com/AlessandroLiAppDev/lina-assistant/issues)
- Contribute plugins
