Skip to content

Jpatching/odysseus.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🌊 odysseus.nvim

A local-first AI co-pilot for Neovim — powered by your own models.

Stream completions, self-heal LSP errors, chat with memory, and manage email — all without leaving your editor or sending data to the cloud.

Neovim Lua License: MIT PRs Welcome


odysseus.nvim is the Neovim frontend for the Odysseus AI Workspace — a self-hosted, privacy-first AI stack. Every token is processed by your hardware, on your machine. Zero telemetry. Zero API keys. Full control.


✨ Features

Feature Command Description
💬 AI Chat :OdysseusChat Persistent split buffer — have a full conversation with your local model
❓ Ask Anything :OdysseusAsk <prompt> Fire off a one-shot query, streamed token-by-token into the chat sidebar
🔍 Code Explain :OdysseusExplain Visually select code → get a streamed explanation with optimisation hints
🩹 LSP Self-Heal :OdysseusHeal Grab active LSP diagnostics, stream an AI fix into a diff split, and apply with <CR>
📧 Email Client :OdysseusEmail Manage your Odysseus-integrated inbox — list, read, and compose — without leaving Neovim

🎬 Demo

LSP Self-Healing in Action

┌─────────────────────────────────────┬────────────────────────────────────────────────────┐
│ my_module.py                        │  Odysseus LSP Heal  │  <CR> Apply  │  q Cancel     │
│ ─────────────────────────────────── │ ────────────────────────────────────────────────── │
│  1  def greet(name):                │  1  def greet(name: str) -> str:                   │
│  2    return "Hello " + name + 1    │  2    return "Hello " + name                       │
│     ~~~~~~~~~~~~~~~~~~~~~ ^^^       │                                                    │
│     TypeError: unsupported operand  │  ▓▓▓ streaming fix... ▓                            │
│                                     │                                                    │
└─────────────────────────────────────┴────────────────────────────────────────────────────┘
  [ original file — diff highlighted ]     [ AI-proposed fix — press <CR> to apply ]
  1. Cursor on a red-underlined line
  2. Run :OdysseusHeal (or <leader>oh)
  3. Watch the fix stream in live, character by character
  4. Diff view activates automatically when the model finishes
  5. Press <CR> to apply the patch — or q to discard

Chat Sidebar Workflow

:OdysseusAsk explain this code in plain English
                    ↓
┌────────────────────────────────────────────────┐
│  Odysseus Chat                                  │
│ ──────────────────────────────────────────────  │
│ > explain this code in plain English            │
│                                                 │
│   This function takes a list of integers and   │
│   returns the running sum. On each iteration   │
│   it appends the cumulative total… ▌            │
│                                                 │
└────────────────────────────────────────────────┘
  Tokens stream live — no waiting for full response

🏗️ Architecture

odysseus.nvim/
├── lua/
│   └── odysseus/
│       ├── init.lua                  # Plugin entry point & user config
│       ├── client.lua                # Async SSE streaming client (vim.system)
│       ├── api.lua                   # REST API wrappers for Odysseus backend
│       ├── integrations/
│       │   ├── lsp.lua               # LSP diagnostic → AI heal → diffthis
│       │   └── email.lua             # Email API client (list/send/read)
│       └── ui/
│           ├── chat.lua              # Persistent chat split buffer
│           └── email.lua             # Email inbox, reader & compose splits
└── plugin/
    └── odysseus.lua                  # :Odysseus* commands & default keymaps

The plugin communicates with an Odysseus FastAPI backend via:

  • REST for structured data (email, sessions, memory)
  • Server-Sent Events (SSE) for real-time token streaming

The streaming client uses vim.system (non-blocking, no jobstart hacks) so Neovim's UI thread is never blocked during inference.


📦 Installation

Prerequisites

  • Neovim >= 0.10
  • Odysseus backend running on localhost:7000 (see odysseus)
  • A local model served via vLLM or Ollama (e.g. Qwen3-30B-A3B)

lazy.nvim (recommended)

{
  "jp/odysseus.nvim",
  event = "VeryLazy",
  config = function()
    require("odysseus").setup({
      api_url       = "http://localhost:7000",
      api_token     = vim.env.ODYSSEUS_API_TOKEN or "",
      session_id    = vim.env.ODYSSEUS_SESSION_ID or "",
      default_model = "Qwen3-30B-A3B-NVFP4",
      timeout       = 10000, -- ms; increase for larger models
    })
  end,
}

Packer

use {
  "jp/odysseus.nvim",
  config = function()
    require("odysseus").setup({ api_url = "http://localhost:7000" })
  end
}

⌨️ Default Keymaps

Add these to your lazy.nvim spec keys = { ... } table or your own init.lua:

{ "<leader>oc", "<cmd>OdysseusChat<cr>",    desc = "Odysseus: Open Chat" },
{ "<leader>oa", ":OdysseusAsk ",            desc = "Odysseus: Ask (prompt)" },
{ "<leader>oe", "<cmd>OdysseusExplain<cr>", desc = "Odysseus: Explain selection", mode = "v" },
{ "<leader>oh", "<cmd>OdysseusHeal<cr>",    desc = "Odysseus: Heal LSP Error" },
{ "<leader>om", "<cmd>OdysseusEmail<cr>",   desc = "Odysseus: Email Inbox" },

🔧 Configuration Reference

require("odysseus").setup({
  -- URL of your running Odysseus FastAPI backend
  api_url       = "http://localhost:7000",

  -- Auth token (set via env var for security, or hardcode for dev)
  api_token     = os.getenv("ODYSSEUS_API_TOKEN") or "",

  -- Session ID used to scope memory and context
  session_id    = os.getenv("ODYSSEUS_SESSION_ID") or "",

  -- Name of the model to use (must be loaded in your vLLM/Ollama server)
  default_model = "Qwen3-30B-A3B-NVFP4",

  -- Request timeout in milliseconds
  timeout       = 10000,
})

🩹 LSP Self-Healing Deep Dive

:OdysseusHeal is the flagship integration. Here's exactly what happens:

  1. Diagnostics collectedvim.diagnostic.get() retrieves all LSP errors/warnings on the current line (falls back to nearest in buffer)
  2. Context window built — 15 lines above and below the error are extracted; the culprit line is annotated with <-- LSP Error: <message>
  3. Prompt constructed — a strict instruction prompt is sent telling the model to return only the corrected code (no markdown, no explanation)
  4. Streaming response — tokens arrive via SSE; a </think> watcher strips reasoning blocks before they hit the buffer (critical for models like Qwen3 that emit <think>...</think> preambles)
  5. Diff view — once streaming completes, diffthis is activated on both splits so you see exactly what changed (green = additions, red = deletions)
  6. One-keystroke apply<CR> writes the healed lines back into the original buffer; q discards everything

🔌 Integrations Roadmap

  • Chat / Ask — streamed Q&A sidebar
  • Code Explain — visual selection explainer
  • LSP Self-Heal — diagnostic-driven auto-fix with diffthis
  • Email — list, read, compose via Odysseus mail API
  • Git — AI commit messages, PR descriptions, conflict resolution
  • Shell — explain & fix terminal errors piped from your shell
  • Telescope — fuzzy-search your Odysseus memory / notes
  • Memory Browser — browse, search, and pin Odysseus long-term memories

🤝 Contributing

Pull requests are very welcome! To get started:

git clone https://github.com/jp/odysseus.nvim ~/projects/odysseus.nvim
# point lazy.nvim at ~/projects/odysseus.nvim via `dir = ...`
# make changes, reload with :Lazy reload odysseus.nvim

Please open an issue first for significant changes so we can align on direction.


📄 License

MIT — see LICENSE.


Built for those who believe their AI should work for them — on their terms.

About

Local-first AI co-pilot for Neovim — LSP heal, chat, email, all via your own models

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors