2026-02-15 10:43:21 -08:00
2026-02-15 10:23:03 -08:00
2026-02-15 10:43:21 -08:00
2026-02-15 10:23:03 -08:00

Flynn

Self-hosted personal AI assistant with Telegram and Terminal interfaces.

Features

  • Multi-Frontend: Telegram bot + Terminal UI (minimal & fullscreen modes) + Web UI dashboard
  • Multi-Model: Anthropic Claude, OpenAI, GitHub Copilot, Gemini, Bedrock, Zhipu AI (GLM), xAI (Grok), Ollama, llama.cpp with intelligent routing
  • Multi-Channel: Telegram, Discord, Slack, WhatsApp with unified adapter interface
  • Web Dashboard: SPA control panel with health monitoring, chat, session browser, usage stats, and settings editor
  • Model Switching: Switch between cloud/local models on demand
  • Session Persistence: SQLite-backed conversation history
  • Fallback Chains: Automatic failover when primary model fails
  • Hook Engine: Confirmation system for sensitive operations
  • Tool Framework: Shell, file, file patch, web-fetch, web-search, browser control, image analysis, media send, audio transcribe, system info
  • Docker Sandboxing: Per-session container isolation for tool execution
  • Multi-Agent Routing: Config-driven agent selection per sender/channel with tool profiles
  • Media Pipeline: Image analysis, outbound attachments, audio transcription and native audio passthrough across all channels
  • Session Transfer: Move conversations between frontends
  • CLI: Full command-line interface (flynn start, send, doctor, completion, etc.)
  • Shell Completion: Auto-generated completions for bash, zsh, and fish with --install flag
  • Cron Scheduling: Automated messages on cron schedules with output routing
  • Inbound Webhooks: HTTP endpoints that trigger agent processing with HMAC auth and template rendering
  • Heartbeat Monitor: Periodic health checks (gateway, model, channels, memory, disk) with failure notifications
  • Gmail Pub/Sub Watcher: Monitor Gmail inbox via Google Cloud Pub/Sub push notifications with polling fallback
  • Vector Memory Search: Hybrid keyword + semantic search with embeddings (OpenAI, Gemini, Ollama, llama.cpp, Voyage AI)
  • Docker Deployment: Multi-stage Dockerfile and docker-compose.yml for production containers
  • Health Diagnostics: flynn doctor validates config, connectivity, and system state
  • MCP Integration: External tool servers via Model Context Protocol
  • Skills System: Extensible capability packages (bundled, managed, workspace tiers)
  • Gateway Lock: Single-client mode — reject additional WebSocket connections when one is active
  • Tailscale Serve: Auto-expose gateway via Tailscale Serve on daemon start with lifecycle management
  • DM Pairing Codes: Allow unknown senders to pair with the bot via time-limited codes across all channels, with SQLite-backed persistence across restarts
  • Lane Queue: Per-session FIFO queue serializes concurrent gateway requests

Quick Start

# Install dependencies
pnpm install

# Copy and configure
cp config/default.yaml ~/.config/flynn/config.yaml
# Edit config with your API keys and Telegram bot token

# Build and run
pnpm build
flynn start

# Or run without building
pnpm start

CLI Commands

Flynn provides a full CLI via the flynn binary (or npx tsx src/cli/index.ts during development):

Command Description
flynn start Start the Flynn daemon (Telegram, WebChat, cron, Gmail watcher)
flynn tui Launch the interactive terminal UI
flynn send <message> Send a one-shot message and print the response
flynn sessions List active sessions
flynn doctor Validate config and check system health
flynn config Show resolved configuration (secrets redacted)
flynn completion <shell> Generate shell completions (bash, zsh, fish)
flynn setup Interactive setup wizard
flynn gmail-auth Authenticate with Gmail via OAuth2
flynn gcal-auth Authenticate with Google Calendar via OAuth2
flynn skills List/install/manage skills

Examples

# Start daemon with custom config
flynn start --config ~/my-config.yaml

# One-shot query
flynn send "What's the weather in London?"

# Check system health
flynn doctor --config ~/.config/flynn/config.yaml

# Show current config (secrets masked)
flynn config

# List sessions
flynn sessions

# Generate shell completions
flynn completion bash              # Print bash completions to stdout
flynn completion zsh --install     # Install zsh completions to ~/.zshrc
flynn completion fish --install    # Install fish completions to config

Configuration

Config location: ~/.config/flynn/config.yaml (or set FLYNN_CONFIG)

telegram:
  bot_token: "your-telegram-bot-token"
  allowed_chat_ids: [123456789]  # Your Telegram user ID

models:
  default:
    provider: anthropic
    model: claude-opus-4-5-20251101
    api_key: sk-ant-api03-...
  local:
    provider: ollama
    model: qwen2.5:14b
  fallback_chain: [local]

hooks:
  confirm: [shell.*, file.write, file.patch]
  log: [web.*, file.read]
  silent: [notify]

Safety Model

Flynn is designed to be safe-by-default when expanded beyond "chat":

  • Tool policy restricts which tools are even available to a given context (profiles + allow/deny + per-agent/per-provider overrides).
  • Skills can declare explicit capabilities (manifest.json.permissions) which are enforced at runtime.
  • Sandboxing can isolate high-risk execution (shell/process) per-session via Docker.
  • Prompt-injection hardening treats fetched content/tool output as untrusted data and blocks obviously unsafe tool calls when untrusted content is present.
  • Audit logs record tool usage and approvals with redaction.

Details: docs/security/SAFE_PERSONAL_AGENT.md

Agent-Oriented Architecture Diagram

If you want a fast mental model of where to start as an AI agent / contributor:

  • docs/architecture/AGENT_DIAGRAM.md
  • docs/architecture/CONTRIBUTOR_MAP.md
  • docs/architecture/TYPESCRIPT_MAP.md
  • docs/architecture/SYMBOL_INDEX.md

Model Providers

Provider Config
Anthropic provider: anthropic, api_key or auth_token
OpenAI provider: openai, api_key, optional endpoint
GitHub Copilot provider: github, auto-login via OAuth device flow
Gemini provider: gemini, api_key
Bedrock provider: bedrock, AWS credentials
Ollama provider: ollama, model, optional endpoint
Zhipu AI (GLM) provider: zhipuai, api_key or ZHIPUAI_API_KEY, optional endpoint
xAI (Grok) provider: xai, api_key or XAI_API_KEY
llama.cpp provider: llamacpp, endpoint

Model Tiers

Configure multiple models for different purposes:

models:
  fast: { provider: anthropic, model: claude-sonnet-4-... }
  default: { provider: anthropic, model: claude-opus-4-5-... }
  complex: { provider: anthropic, model: claude-opus-4-5-... }
  local: { provider: ollama, model: qwen2.5:14b }

Each tier can optionally specify auth_mode (auto | api_key | oauth) to control whether Flynn uses API keys vs OAuth/token auth for that provider. use_oauth: true remains supported as a compatibility alias for auth_mode: oauth.

Native Audio Support

Voice messages from channels can be handled in two ways:

  1. Native passthrough -- Audio sent directly to models that support audio input (Gemini, OpenAI, GitHub). No transcription step needed.
  2. Whisper transcription -- Audio transcribed to text via a Whisper-compatible API, then sent as text to models that don't support audio input (Anthropic, Bedrock, Ollama, llama.cpp).

Flynn automatically routes based on the model's capabilities. You can override this per-tier:

models:
  default:
    provider: gemini
    model: gemini-2.0-flash
    supports_audio: true     # Force native audio (auto-detected for known providers)
  fast:
    provider: anthropic
    model: claude-sonnet-4
    supports_audio: false    # Force transcription (default for Anthropic)

Audio Transcription

Configure a Whisper-compatible endpoint for models that don't support native audio:

audio:
  enabled: true
  provider:
    type: custom                            # openai, groq, ollama, llamacpp, custom
    endpoint: "http://localhost:18801/v1/audio/transcriptions"
    api_key: "${WHISPER_API_KEY}"            # Optional Bearer token
    model: "whisper-1"                       # Model name (default: whisper-1)
Field Required Description
enabled no Enable audio transcription (default: false)
provider.type yes Provider type: openai, groq, ollama, llamacpp, or custom
provider.endpoint yes Whisper-compatible API endpoint
provider.api_key no Bearer token for authentication
provider.model no Model name sent in request (default: whisper-1)

Without an audio config, voice messages from non-audio-capable models will display an error message to the user. For local transcription, you can run a whisper.cpp server:

# Option 1: Manual docker run
docker run -d \
  --name whisper-server \
  -p 18801:8080 \
  ghcr.io/ggml-org/whisper.cpp:main \
  --model /app/models/ggml-base.en.bin \
  --host 0.0.0.0 \
  --port 8080 \
  --convert \
  --language en \
  --inference-path /v1/audio/transcriptions

# Option 2: Using docker-compose (uncomment whisper-server service in docker-compose.yml)
# docker compose up -d

Telegram Commands

Command Description
/start Initialize bot
/reset Clear conversation history
/status Show current model and status
/local Switch to local model
/cloud Switch to cloud model
/model Show model info and options

Web UI Dashboard

Flynn includes a built-in web control dashboard served by the WebSocket gateway. Access it at http://localhost:18800 (or your configured gateway port).

Pages

Page Description
Dashboard System health cards, channel status, usage stats. Auto-refreshes every 10s
Chat Session selector, streaming tool events, markdown rendering with syntax highlighting
Sessions Browse all sessions, view message history, delete sessions
Usage Token usage summary cards, per-session breakdown table, auto-refresh
Settings Edit hook patterns (confirm/log/silent), view tools, channels, and redacted config

The dashboard is a vanilla JS SPA with no build step — hash-based routing, ES modules, and the existing WebSocket JSON-RPC protocol.

Terminal UI

# Minimal mode (readline)
pnpm tui

# Fullscreen mode (React/Ink)
pnpm tui:fs

TUI Commands

Command Description
/help Show help
/model Show all model tiers and which is active
/model <tier> Switch active tier (local, default, fast, complex, or aliases ollama, sonnet, haiku, opus)
/model <tier> <provider/model> Hot-swap a tier's provider and model at runtime
/backend [provider] Show or switch local backend (ollama, llamacpp)
/login [provider] Authenticate with GitHub (OAuth device flow)
/reset Clear history
/status Show session info
/compact Compact conversation context
/usage Show token usage and cost
/verbose Toggle verbose output mode
/pair Generate/list/revoke DM pairing codes
/fullscreen Switch to fullscreen mode
/transfer <dest> Transfer session to another frontend
/quit Exit

Runtime Model Switching

Switch providers and models on the fly without editing config or restarting:

# Show current tiers
/model

# Switch active tier
/model fast
/model complex

# Hot-swap a tier's provider/model
/model default anthropic/claude-sonnet-4
/model default zhipuai/glm-4.7
/model fast github/gpt-4o-mini
/model local ollama/glm-4.7-flash

The provider name must match a supported provider (anthropic, openai, gemini, ollama, llamacpp, openrouter, bedrock, github, zhipuai, xai). Tab completion is available for both tiers and provider names.

For cloud Zhipu models, ensure ZHIPUAI_API_KEY is set or api_key is configured in the relevant tier.

Note: The /model command works in the TUI only. WebChat sessions inherit the active tier from the daemon.

Running as Service

# Create systemd user service
mkdir -p ~/.config/systemd/user

cat > ~/.config/systemd/user/flynn.service << 'EOF'
[Unit]
Description=Flynn Personal AI Assistant
After=network.target ollama.service

[Service]
Type=simple
WorkingDirectory=/path/to/flynn
ExecStart=/usr/bin/pnpm start
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production

[Install]
WantedBy=default.target
EOF

# Enable and start
systemctl --user daemon-reload
systemctl --user enable --now flynn

# View logs
journalctl --user -u flynn -f

Hook Engine

Control sensitive operations with pattern matching:

hooks:
  confirm:    # Requires user approval via Telegram
    - shell.*
    - file.write
    - file.patch
  log:        # Logs but doesn't block
    - web.*
    - file.read
  silent:     # Executes without notification
    - notify

Cron Scheduling

Schedule automated messages on cron schedules. Each job fires an inbound message through the agent pipeline and routes the response to a configured output channel.

automation:
  cron:
    - name: daily-summary
      schedule: "0 9 * * *"            # 9 AM daily
      message: "Give me a summary of today's tasks"
      output:
        channel: telegram               # Route response to Telegram
        peer: "123456789"               # Chat ID to send to
      timezone: Europe/London           # Optional timezone
      enabled: true

    - name: hourly-check
      schedule: "0 * * * *"            # Every hour
      message: "Check system status"
      output:
        channel: telegram
        peer: "123456789"
      enabled: false                    # Disabled, won't fire
      model_tier: fast                  # Use fast tier for quick checks

Cron Config Fields

Field Required Description
name yes Unique job identifier
schedule yes Cron expression (standard 5-field)
message yes Text sent to the agent when the job fires
output.channel yes Channel name to route the response (e.g. telegram)
output.peer yes Peer/chat ID on the output channel
timezone no IANA timezone (defaults to system timezone)
enabled no Whether the job is active (default: true)
model_tier no Model tier for this job: fast, default, complex, or local

Inbound Webhooks

HTTP endpoints that trigger agent processing. Each webhook accepts POST requests, optionally verifies an HMAC signature, renders a message template, and routes the agent's response to an output channel.

automation:
  webhooks:
    - name: github-push
      secret: "whsec_..."                  # HMAC secret for signature verification
      message: "GitHub push to {{json.repository.full_name}}: {{json.head_commit.message}}"
      output:
        channel: telegram
        peer: "123456789"

    - name: alertmanager
      message: "Alert: {{json.alerts.0.annotations.summary}}"
      output:
        channel: discord
        peer: "channel-id"

Webhooks are available at POST /webhooks/:name on the gateway HTTP server. They bypass gateway token auth and use their own per-webhook HMAC verification instead.

Webhook Config Fields

Field Required Description
name yes Unique webhook identifier (used in URL path)
secret no HMAC secret for X-Webhook-Signature header verification (SHA-256)
message no Template for the message sent to the agent (default: {{body}})
output.channel yes Channel name to route the response (e.g. telegram)
output.peer yes Peer/chat ID on the output channel
enabled no Whether the webhook is active (default: true)

Template Variables

Variable Description
{{body}} Raw request body as string
{{json.field}} Extract a field from JSON body (dot notation for nested fields)

Heartbeat Monitor

Periodic health checks that validate system components and notify a configured channel on failure.

automation:
  heartbeat:
    enabled: true
    interval: "5m"                         # Check every 5 minutes
    checks: [gateway, model, channels, memory, disk]
    notify:
      channel: telegram
      peer: "123456789"
    failure_threshold: 2                   # Notify after 2 consecutive failures
    disk_threshold_mb: 100                 # Warn when <100MB free

Heartbeat Checks

Check What it validates
gateway HTTP server is responsive
model Model router has an active tier configured
channels At least one channel adapter is connected
memory Memory directory is readable and writable
disk Free disk space exceeds threshold

The monitor sends a notification when failures reach the configured threshold and a recovery notification when all checks pass again.

Heartbeat Config Fields

Field Required Description
enabled no Enable the heartbeat monitor (default: false)
interval no Check interval: 60s, 5m, 1h (default: 5m)
checks no Which checks to run (default: all five)
notify.channel no Channel to send failure/recovery notifications
notify.peer no Peer/chat ID for notifications
failure_threshold no Consecutive failures before notifying (default: 2)
disk_threshold_mb no Disk space warning threshold in MB (default: 100)

Gmail Pub/Sub Watcher

Monitor a Gmail inbox and forward new messages into the agent pipeline.

Supported delivery modes:

  • Push (Gmail watch → Pub/Sub topic → HTTP push subscription → POST /gmail/push)
  • Pull (Pub/Sub pull subscription → Flynn periodically pulls messages; no inbound webhook)
  • Polling (Gmail History API polling fallback)

Prerequisites

  1. Create a Google Cloud project with the Gmail API enabled
  2. Create OAuth2 credentials (Desktop application type) and download the JSON file
  3. Run flynn gmail-auth to complete the OAuth2 flow and store the refresh token

For Pub/Sub delivery (push/pull), also enable the Pub/Sub API and create:

  • A topic (e.g. projects/your-project/topics/gmail-push)
  • A subscription (push and/or pull)

Configuration

automation:
  gmail:
    enabled: true
    credentials_file: ~/.config/flynn/gmail-credentials.json
    token_file: ~/.config/flynn/gmail-token.json   # Default location

    # Push mode (optional)
    pubsub_topic: projects/your-project/topics/gmail-push
    disable_push: false

    # Pull mode (optional; no inbound webhook required)
    pubsub_subscription_id: projects/your-project/subscriptions/gmail-pull
    pubsub_pull_interval: "60s"
    pubsub_max_messages: 10

    watch_labels: [INBOX]                           # Labels to watch
    poll_interval: "60s"                            # Polling fallback interval
    message: "New email from {{from}}: {{subject}}\n\n{{snippet}}"
    output:
      channel: telegram
      peer: "123456789"

Push notifications arrive at POST /gmail/push on the gateway HTTP server (bypasses gateway auth).

Pull mode uses Application Default Credentials (e.g. GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json) to access Pub/Sub.

Gmail Config Fields

Field Required Description
enabled no Enable the Gmail watcher (default: false)
credentials_file yes Path to Google OAuth2 credentials JSON
token_file no Path to stored OAuth2 refresh token (default: ~/.config/flynn/gmail-token.json)
pubsub_topic no Pub/Sub topic for Gmail watch push notifications (projects/<project>/topics/<topic>)
disable_push no Disable watch registration even if pubsub_topic is set (default: false)
pubsub_subscription_id no Pub/Sub pull subscription (projects/<project>/subscriptions/<sub>)
pubsub_pull_interval no How often to pull subscription messages (default: 60s)
pubsub_max_messages no Max messages per pull cycle (default: 10)
watch_labels no Gmail labels to watch (default: [INBOX])
poll_interval no Polling fallback interval: 60s, 5m (default: 300s)
history_start no ISO date string — only process emails received after this date
message no Template for the agent message (default: New email from {{from}}: {{subject}}\n\n{{snippet}})
output.channel yes Channel name to route the response (e.g. telegram)
output.peer yes Peer/chat ID on the output channel

Template Variables

Variable Description
{{from}} Sender address
{{to}} Recipient address
{{subject}} Email subject line
{{snippet}} Gmail-provided message snippet
{{date}} Email date
{{id}} Gmail message ID
{{labels}} Comma-separated label names

Google Calendar Tools

Query Google Calendar events from within conversations. Provides three tools: calendar.today (today's agenda), calendar.list (date range), and calendar.search (full-text search).

Prerequisites

  1. A Google Cloud project with the Calendar API enabled
  2. OAuth2 credentials (Desktop application type) — the same credentials file used for Gmail works
  3. Run flynn gcal-auth to complete the OAuth2 flow and store the refresh token

Configuration

automation:
  gcal:
    enabled: true
    credentials_file: ~/.config/flynn/gmail-credentials.json
    token_file: ~/.config/flynn/gcal-token.json   # Default location
    calendar_ids: [primary]                        # Calendar IDs to query

Google Calendar Config Fields

Field Required Description
enabled no Enable the calendar tools (default: false)
credentials_file yes Path to Google OAuth2 credentials JSON
token_file no Path to stored OAuth2 refresh token (default: ~/.config/flynn/gcal-token.json)
calendar_ids no Calendar IDs available for queries (default: [primary])

The memory system supports hybrid search combining keyword matching with semantic vector similarity. When embeddings are enabled, memory.search uses both approaches and merges results with configurable weighting.

memory:
  enabled: true
  auto_extract: true
  max_context_tokens: 2000
  embedding:
    enabled: true
    provider: openai                       # openai, gemini, ollama, llamacpp
    model: text-embedding-3-small
    api_key: "${OPENAI_API_KEY}"
    chunk_size: 512                        # Tokens per chunk
    chunk_overlap: 50                      # Overlap between chunks
    top_k: 5                               # Top results from vector search
    hybrid_weight: 0.7                     # 0.0 = keyword only, 1.0 = vector only

Embedding Providers

Provider Config
OpenAI provider: openai, api_key, model (default: text-embedding-3-small)
Gemini provider: gemini, api_key, model
Ollama provider: ollama, endpoint (default: localhost:11434), model
llama.cpp provider: llamacpp, endpoint, optional model
Voyage AI provider: voyageai, api_key or VOYAGE_API_KEY, model (default: voyage-3-large)

Embeddings are indexed in the background — when memory is written, the namespace is marked dirty and re-indexed within 30 seconds. The vector index is stored in vectors.db alongside the session database.

When embeddings are disabled or the provider is unreachable, search falls back gracefully to keyword matching.

Embedding Config Fields

Field Required Description
enabled no Enable vector search (default: false)
provider no Embedding provider (default: openai)
model no Embedding model name (default: text-embedding-3-small)
endpoint no Provider endpoint (required for ollama/llamacpp)
api_key no API key (required for openai/gemini/voyageai)
dimensions no Vector dimensions (auto-detected from model if not set)
chunk_size no Max tokens per chunk (default: 512)
chunk_overlap no Token overlap between chunks (default: 50)
top_k no Number of vector results to return (default: 5)
hybrid_weight no Vector vs keyword weight, 0.0-1.0 (default: 0.7)

Gateway Lock

Single-client mode for the WebSocket gateway. When enabled, only one WebSocket connection is allowed at a time. Additional connections are rejected with close code 4003.

server:
  lock: true

The web UI detects the locked state and disables auto-reconnect when rejected.

Tailscale Serve

Automatically expose the gateway via Tailscale Serve when the daemon starts. Requires Tailscale to be installed and authenticated on the host.

server:
  tailscale:
    serve: true

When enabled, Flynn runs tailscale serve on startup to expose the gateway port over your tailnet, and cleans up on shutdown. The flynn doctor command includes a Tailscale availability check.

DM Pairing Codes

Allow unknown senders to authenticate with the bot via time-limited pairing codes. Works across all channel adapters (Telegram, Discord, Slack, WhatsApp).

pairing:
  enabled: true
  code_ttl: "10m"       # Code expiry time (default: 10 minutes)
  code_length: 6        # Code length (default: 6 digits)

How it works

  1. Generate a code via the TUI (/pair generate), gateway API (pairing.generate), or web dashboard
  2. Share the code with the user
  3. The user sends the code as their first DM to the bot
  4. If valid, the user's sender ID is permanently approved for that channel (persisted in SQLite, survives daemon restarts)
  5. Approved users can be listed (/pair list) and revoked (/pair revoke <channel> <id>)

TUI Commands

Command Description
/pair Generate a new pairing code
/pair generate [label] Generate a code with optional label
/pair list List pending codes and approved senders
/pair revoke <channel> <id> Revoke an approved sender

Gateway API

Method Description
pairing.generate Generate a new pairing code (optional label param)
pairing.list List pending codes and approved senders
pairing.revoke Revoke an approved sender (channel + senderId params)

Shell Completion

Generate shell completions for bash, zsh, or fish:

# Print completions to stdout
flynn completion bash
flynn completion zsh
flynn completion fish

# Install directly to shell config
flynn completion bash --install    # Appends to ~/.bashrc
flynn completion zsh --install     # Appends to ~/.zshrc
flynn completion fish --install    # Writes to ~/.config/fish/completions/flynn.fish

Docker Deployment

Flynn includes a production-ready Dockerfile with multi-stage build.

# Build the image
docker build -t flynn .

# Run with config and data volumes
docker run -d \
  --name flynn \
  -p 18800:18800 \
  -v ./config.yaml:/config/config.yaml:ro \
  -v flynn-data:/data \
  -e ANTHROPIC_API_KEY=sk-ant-... \
  flynn

Or use the included docker-compose.yml:

# Copy your config
cp ~/.config/flynn/config.yaml ./config.yaml

# Start with compose
docker compose up -d

# View logs
docker compose logs -f

Docker Environment Variables

Variable Description
FLYNN_CONFIG Config file path (default: /config/config.yaml)
FLYNN_DATA_DIR Data directory path (default: /data)
ANTHROPIC_API_KEY Anthropic API key
OPENAI_API_KEY OpenAI API key
TELEGRAM_BOT_TOKEN Telegram bot token

Volumes

Mount Point Purpose
/config/config.yaml Configuration file (read-only)
/data Persistent data (sessions DB, memory files, vector index)

Doctor Diagnostics

flynn doctor runs 10 health checks to validate your setup:

$ flynn doctor

Flynn Doctor
============

[PASS] Config file exists (/home/user/.config/flynn/config.yaml)
[PASS] Config parses (valid YAML)
[PASS] Config validates (schema valid)
[PASS] Env vars resolved
[PASS] Data directory writable (/home/user/.local/share/flynn)
[PASS] Session DB accessible (sessions.db)
[PASS] Model connectivity (anthropic: claude-sonnet)
[PASS] Telegram bot configured (1 allowed chat(s))
[SKIP] MCP servers configured (none configured)
[PASS] Skills loaded (3 skill(s))

Results: 8 passed, 0 failed, 0 warnings, 1 skipped

Check Details

Check What it validates
Config file exists Config YAML file is present at the expected path
Config parses File is valid YAML syntax
Config validates YAML content passes Zod schema validation
Env vars resolved Any ${VAR} references in config have values set
Data directory writable Can write to ~/.local/share/flynn/
Session DB accessible SQLite database opens and queries succeed
Model connectivity Default model provider and model name are configured
Telegram bot configured Bot token is present and reasonable length
MCP servers configured Lists configured MCP tool servers
Skills loaded Discovers and loads skill packages

Exit code is 1 if any check fails, 0 otherwise. Checks that depend on a valid config are skipped when config is invalid.

Session Management

  • Sessions persist in ~/.local/share/flynn/sessions.db
  • Session ID format: {frontend}:{userId} (e.g., telegram:123456789)
  • History survives restarts
  • Transfer sessions between frontends with /transfer

Architecture

src/
├── agents/               # Multi-agent routing
├── auth/                 # OAuth flows (GitHub Copilot)
├── backends/native/      # Agent implementation + orchestrator
├── channels/             # Channel adapters (Telegram, Discord, Slack, WhatsApp, WebChat)
│   └── pairing.ts        # DM pairing code manager
├── cli/                  # CLI commands (commander)
│   └── completion.ts     # Shell completion generator (bash/zsh/fish)
├── config/               # YAML config + Zod validation
├── context/              # Token estimation + compaction
├── daemon/               # Lifecycle management + routing
├── frontends/
│   ├── telegram/         # Telegram bot
│   └── tui/              # Terminal UI (minimal + fullscreen)
├── gateway/              # WebSocket gateway + web UI dashboard
│   ├── handlers/         # JSON-RPC method handlers (agent, sessions, system, pairing, tools, config)
│   ├── tailscale.ts      # Tailscale Serve lifecycle management
│   ├── lane-queue.ts     # Per-session FIFO request queue
│   └── ui/               # SPA dashboard (vanilla JS)
│       ├── pages/        # Dashboard, Chat, Sessions, Usage, Settings
│       └── lib/          # WebSocket RPC client
├── hooks/                # Confirmation engine
├── mcp/                  # MCP tool server integration
├── memory/               # Persistent memory store + vector search
├── models/               # Model providers + router + media pipeline + audio capabilities
├── prompt/               # System prompt templating (auto-injects current date/time)
├── sandbox/              # Docker sandboxing
├── session/              # SQLite persistence
├── skills/               # Skill packages
├── tools/                # Builtin tools (shell, file, web, browser, process, media, audio, system.info)
└── automation/           # Cron scheduler, webhooks, heartbeat monitor, Gmail watcher

System Prompt

Flynn assembles its system prompt from layered template files (SOUL.md, AGENTS.md, IDENTITY.md, USER.md, TOOLS.md) searched in configurable directories. The first match per file wins.

A Runtime Context section is automatically appended to every system prompt with the current date and time, so the model always knows when "now" is without needing a tool call.

The system.info tool provides on-demand access to more detailed runtime information: current date/time, hostname, platform, architecture, OS release, uptime, Node.js version, memory usage, and working directory.

Development

# Dev mode with watch
pnpm dev          # Daemon
pnpm tui:dev      # TUI

# Type check
pnpm typecheck

# Lint
pnpm lint

# Test
pnpm test

Environment Variables

Variable Description
FLYNN_CONFIG Override config file path
FLYNN_DATA_DIR Override data directory (default: ~/.local/share/flynn)
ANTHROPIC_API_KEY Anthropic API key (fallback)
OPENAI_API_KEY OpenAI API key (fallback)

License

MIT

S
Description
flynn personal assistant - inspired by OpenClaw but implemented only with Pi
Readme 6.9 MiB
Languages
TypeScript 92.3%
JavaScript 6.4%
HTML 0.4%
Swift 0.3%
Makefile 0.2%
Other 0.1%