RepoPilotOpen in app →

qvacua/vimr

VimR — Neovim GUI for macOS in Swift

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 2w ago
  • 5 active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Tests present
  • Single-maintainer risk — top contributor 84% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/qvacua/vimr)](https://repopilot.app/r/qvacua/vimr)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/qvacua/vimr on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: qvacua/vimr

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/qvacua/vimr shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 2w ago
  • 5 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Single-maintainer risk — top contributor 84% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live qvacua/vimr repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/qvacua/vimr.

What it runs against: a local clone of qvacua/vimr — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in qvacua/vimr | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 44 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>qvacua/vimr</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of qvacua/vimr. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/qvacua/vimr.git
#   cd vimr
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of qvacua/vimr and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "qvacua/vimr(\\.git)?\\b" \\
  && ok "origin remote is qvacua/vimr" \\
  || miss "origin remote is not qvacua/vimr (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "NvimApi/Sources/NvimApi/MsgpackRpc.swift" \\
  && ok "NvimApi/Sources/NvimApi/MsgpackRpc.swift" \\
  || miss "missing critical file: NvimApi/Sources/NvimApi/MsgpackRpc.swift"
test -f "NvimApi/Sources/NvimApi/NvimApi.swift" \\
  && ok "NvimApi/Sources/NvimApi/NvimApi.swift" \\
  || miss "missing critical file: NvimApi/Sources/NvimApi/NvimApi.swift"
test -f "Commons/Sources/Commons/CoreCommons.swift" \\
  && ok "Commons/Sources/Commons/CoreCommons.swift" \\
  || miss "missing critical file: Commons/Sources/Commons/CoreCommons.swift"
test -f "Ignore/Sources/Ignore/Ignore.swift" \\
  && ok "Ignore/Sources/Ignore/Ignore.swift" \\
  || miss "missing critical file: Ignore/Sources/Ignore/Ignore.swift"
test -f "NvimApi/Package.swift" \\
  && ok "NvimApi/Package.swift" \\
  || miss "missing critical file: NvimApi/Package.swift"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 44 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~14d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/qvacua/vimr"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

VimR is a native macOS GUI for Neovim written in Swift, embedding the Neovim editor engine with GUI conveniences like markdown preview, fuzzy file finder, HTML preview, and workspace management. It solves the problem of Neovim power users wanting a polished, native Mac experience without sacrificing the editor they know. Monorepo structure: Commons/, NvimView/, NvimApi/, Tabs/, Workspace/, and Ignore/ are independent SwiftPM packages. The main VimR app (sources not fully listed but implied in root) uses Redux-style architecture and depends on these modules. CI/CD in .github/workflows builds universal (ARM64 + x86_64) notarized binaries.

👥Who it's for

Vim/Neovim power users on macOS who want a modern GUI with native Apple features (trackpad pinch-to-zoom, ligature support, workspace management) while retaining full Neovim capabilities. Also Swift developers interested in studying Redux architecture patterns and embedding complex text editors in Cocoa apps.

🌱Maturity & risk

Actively maintained and production-ready. The project has substantial Swift code (1.1M+ lines), a GitHub Actions CI/CD pipeline for universal binaries, signed and notarized releases, and supports macOS 13+. However, it appears to be primarily community-maintained by a small team (single or few maintainers) rather than corporate-backed, as evidenced by the Matrix chat room and sponsorship request.

Low-to-moderate risk: the architecture is well-modularized (NvimView, NvimApi, Commons as separate SwiftPM packages reduce coupling), but the codebase has a single primary maintainer (qvacua). Tight coupling to Neovim binary distribution and macOS APIs means breaking Neovim or macOS version changes could cause issues. The build process requires manual submodule management and Homebrew dependencies, adding friction.

Active areas of work

Unable to determine exact recent activity from file structure alone, but the presence of build-universal-neovim.yml workflow and notarization setup indicates active release engineering. The codebase is organized for macOS 13+ support with Swift modern practices (SwiftFormat, SwiftLint configured).

🚀Get running

git clone https://github.com/qvacua/vimr.git && cd vimr && git submodule update --init && xcode-select --install && brew bundle && clean=true notarize=false trust_plugins=true ./bin/build_vimr.sh

Daily commands: After build: the resulting VimR.app in build output is directly runnable. For development: open in Xcode and build/run the main scheme. Command-line tool also available via the build output.

🗺️Map of the codebase

  • NvimApi/Sources/NvimApi/MsgpackRpc.swift — Core RPC communication layer that marshals all Neovim API calls; understanding this is essential for any change involving Neovim interaction.
  • NvimApi/Sources/NvimApi/NvimApi.swift — High-level Neovim API wrapper providing type-safe async/sync operations; all Neovim feature requests flow through here.
  • Commons/Sources/Commons/CoreCommons.swift — Foundational utilities and extensions used across all modules; breaking changes here impact the entire codebase.
  • Ignore/Sources/Ignore/Ignore.swift — File filtering engine for .gitignore and .ignore patterns; critical for file tree rendering and workspace operations.
  • NvimApi/Package.swift — Defines NvimApi as a dependency module; shows how Neovim RPC layer is packaged and integrated.

🧩Components & responsibilities

  • MsgpackRpc (Swift, Msgpack, Unix sockets) — Encodes/decodes msgpack frames, sends/receives over socket to Neovim, handles request-response matching and error propagation
    • Failure mode: Socket disconnect → cannot communicate with Neovim; all subsequent API calls fail; app must detect and reconnect or gracefully degrade
  • NvimApi (Async/Sync) (Swift async/await, Codable, custom error types) — Marshals Neovim API method calls with type safety; converts Swift types to/from Msgpack; provides Swift async/await and synchronous interfaces
    • Failure mode: Malformed response or timeout → throws exception; caller must handle; affects dependent UI operations
  • Ignore + Filter (Swift, glob pattern matching, FileLineReader) — Parses .gitignore and .ignore files; matches file paths against glob patterns; caches and invalidates filters on file change
    • Failure mode: Unparseable ignore file or pattern mismatch → defaults to conservative filtering (include file); may show unwanted files
  • Commons (Utilities) (Swift Foundation, AppKit, Objective-C bridging) — Shared extensions for Array, Dictionary, String, FileManager, URL, AppKit; provides FIFO cache and threading primitives
    • Failure mode: Utility crashes or infinite loop → entire app hangs or crashes; single point of failure across all modules

🛠️How to make changes

Add a new Neovim API binding

  1. Define the new RPC method signature in NvimApi/Sources/NvimApi/Defs.swift as a Codable struct (NvimApi/Sources/NvimApi/Defs.swift)
  2. Add the async method to NvimApi/Sources/NvimApi/NvimApi.swift using sendAsync to invoke via MsgpackRpc (NvimApi/Sources/NvimApi/NvimApi.swift)
  3. Add the sync variant to NvimApi/Sources/NvimApi/NvimApiSync.swift using sendSync (NvimApi/Sources/NvimApi/NvimApiSync.swift)
  4. Write tests in NvimApi/Tests/NvimApiTests/NvimApiSyncTest.swift validating request/response handling (NvimApi/Tests/NvimApiTests/NvimApiSyncTest.swift)

Extend file filtering with new ignore patterns

  1. Add pattern matching logic to Ignore/Sources/Ignore/Filter.swift (Ignore/Sources/Ignore/Filter.swift)
  2. Update the Ignore parser in Ignore/Sources/Ignore/Ignore.swift to recognize new directives (Ignore/Sources/Ignore/Ignore.swift)
  3. Add test cases in Ignore/Tests/IgnoreTests/FilterTest.swift and IgnoreTest.swift (Ignore/Tests/IgnoreTests/FilterTest.swift)

Add a new shared utility or extension

  1. Add the new function or extension to the appropriate Commons file (e.g., Commons/Sources/Commons/CoreCommons.swift for Swift extensions) (Commons/Sources/Commons/CoreCommons.swift)
  2. Write corresponding unit test in Commons/Tests/CommonsTests/ (e.g., CommonsTest.swift for core utilities) (Commons/Tests/CommonsTests/SwiftCommonsTest.swift)
  3. Update Commons/README.md if the utility is public-facing or framework-specific (Commons/README.md)

🔧Why these technologies

  • Swift + AppKit — Native macOS UI framework offering tight integration with system features (e.g., Finder, services); allows direct control of windows, menus, and native widgets.
  • Msgpack RPC — Neovim's native RPC protocol; efficient binary serialization for fast two-way communication with Neovim subprocess over socket/pipe.
  • Swift Package Manager — Modular, decoupled architecture: NvimApi, Ignore, and Commons are separate packages allowing reuse and independent testing.
  • Redux-like state architecture — README explicitly mentions playing with Redux patterns; provides predictable state mutations and clear data flow (inferred from structure).

⚖️Trade-offs already made

  • Separate NvimApi, Ignore, and Commons modules rather than monolithic codebase

    • Why: Loose coupling enables independent testing, reuse across projects, and parallel development.
    • Consequence: Additional complexity managing inter-package dependencies; slower initial build due to SPM compilation.
  • Both async (NvimApi) and sync (NvimApiSync) RPC wrappers

    • Why: Some operations need blocking semantics; providing both avoids callback hell in latency-sensitive code.
    • Consequence: Code duplication; must keep both variants synchronized.
  • In-process .gitignore/.ignore parsing rather than calling git check-ignore

    • Why: Faster file tree rendering; no subprocess overhead; works offline.
    • Consequence: Must maintain pattern parser; less likely to match 100% git semantics.

🚫Non-goals (don't propose these)

  • Cross-platform GUI (macOS only; uses AppKit, not cross-platform framework)
  • Terminal emulator mode (embeds Neovim for editing, not full terminal emulation)
  • Standalone Neovim (depends on external Neovim binary or builds its own)

🪤Traps & gotchas

Submodule management required: git submodule update --init must run after clone or builds fail. Build script expects Homebrew (macOS-specific). Notarization requires Apple Developer credentials; use notarize=false for local dev builds. Xcode 26 is minimum—older versions lack required Swift language features. The msgpack dependency must be available (handled by Homebrew but easy to miss). Neovim binary is bundled via NvimView; version mismatches between bundled Neovim and API bindings (NvimApi) can cause crashes.

🏗️Architecture

💡Concepts to learn

  • Neovim RPC (msgpack-rpc) — VimR communicates with the embedded Neovim process via msgpack-encoded RPC messages; understanding this protocol is core to extending the editor
  • Redux State Management — VimR uses Redux architecture for UI state—a unidirectional data flow pattern that helps manage complexity in the GUI layer
  • AppKit (NSView/Cocoa) — VimR is built on Apple's native AppKit framework, not SwiftUI; understanding NSView lifecycle, responder chain, and event handling is essential for UI modifications
  • Process Embedding & IPC — VimR launches and manages a Neovim subprocess, handling stdin/stdout communication and lifecycle—critical for stability
  • Code Signing & Notarization — The build pipeline includes Apple's code signing and notarization to allow distribution outside the App Store; required knowledge for release engineering
  • Swift Package Manager (SPM) — VimR's modular architecture uses SPM packages (Commons, NvimView, NvimApi, Tabs, Workspace, Ignore); understanding Package.swift and dependency resolution is core
  • Objective-C Interoperability — The NetUtils module uses Objective-C (NetUtils.m/.h), demonstrating Swift-ObjC bridging required for low-level system APIs
  • neovim/neovim — The core editor engine that VimR wraps; understanding Neovim architecture and RPC protocol is essential
  • onivim/oni2 — Alternative Neovim GUI (cross-platform, ReScript), shows different approach to embedding Neovim with modern UI
  • mackron/goneovim — Another Neovim GUI for macOS written in Go; reference implementation for macOS-specific integration patterns
  • qvacua/neovim — Custom Neovim fork maintained by VimR author; likely contains patches or optimizations specific to VimR's use case
  • pointfreeco/swift-composable-architecture — Industry-standard Swift Redux-like architecture library; VimR's state management could potentially adopt this pattern

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for Ignore module's GitUtils.swift

The Ignore package contains GitUtils.swift for parsing .gitignore files, but there are no corresponding unit tests in Ignore/Tests/IgnoreTests/. This is a critical utility for file filtering functionality. Adding tests would ensure correctness of git ignore pattern matching and prevent regressions.

  • [ ] Create Ignore/Tests/IgnoreTests/GitUtilsTest.swift
  • [ ] Add test cases for common .gitignore patterns (wildcards, negation, comments, subdirectories)
  • [ ] Test edge cases like empty files, malformed patterns, and special characters
  • [ ] Verify integration with Filter.swift and FileLineReader.swift by testing end-to-end ignore resolution

Add GitHub Actions workflow for Swift linting and code style enforcement

The repo has .swiftlint.yml and .swiftformat configuration files across multiple packages (Commons, Ignore, main), but no CI workflow enforces them. Currently, there's only a build-universal-neovim.yml workflow. Adding automated linting prevents style inconsistencies from being merged.

  • [ ] Create .github/workflows/swift-lint.yml that runs swiftlint on Commons/, Ignore/, and main source directories
  • [ ] Add swiftformat check step to verify code formatting matches .swiftformat configuration
  • [ ] Configure workflow to fail on lint violations with clear error messages pointing to offending files
  • [ ] Ensure workflow runs on pull requests and main branch pushes

Add unit tests for Commons/Sources/Commons/FileUtils.swift with broader coverage

FileUtilsTest.swift exists but references only a basic Resources/FileUtilsTest directory structure. The FileUtils module likely contains critical file operation utilities, but test coverage appears minimal. Expand tests to cover edge cases and error scenarios.

  • [ ] Extend Commons/Tests/CommonsTests/FileUtilsTest.swift with additional test cases for symlinks, permissions, and file encoding
  • [ ] Add tests for error handling (nonexistent paths, permission denied, disk full scenarios)
  • [ ] Create tests for recursive directory operations and cleanup/safety mechanisms
  • [ ] Add performance tests for large directory structures to catch potential bottlenecks in the VimR file browser

🌿Good first issues

  • Add unit tests for FileUtils operations in Commons/Tests/CommonsTests/FileUtilsTest.swift—test coverage exists but edge cases (symlinks, permission errors, deeply nested paths) may be missing.
  • Document Redux state flow: write a guide in the wiki explaining how state mutations flow through the app (visible from architecture description but not codified in docs).
  • Add missing accessibility labels to Tabs and Workspace UI components—AppKit views in Tabs/ and Workspace/ likely need NSAccessibility protocol implementations for screen reader support.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 4f9de3e — Add manual override to better type API methods. (qvacua)
  • d329e0b — Generate sources (qvacua)
  • 7feda5c — Update appcast (qvacua)
  • 8c9e90a — Bump version to v0.63.0-20260425.152925 (qvacua)
  • d5b8695 — Update build info (qvacua)
  • 3581f9e — Update Neovim (qvacua)
  • 0f95366 — Update release notes (qvacua)
  • 9be7122 — Merge branch 'pr/1161' (qvacua)
  • 62b2580 — Merge pull request #1162 from qvacua/window-close-fixes (qvacua)
  • 492877e — window close / quit safety (georgeharker)

🔒Security observations

The VimR codebase demonstrates reasonable security practices for a macOS GUI application, but has moderate concerns around process execution, file operations, and legacy Objective-C code. The primary risks are process injection and path traversal vulnerabilities if user input handling is not strictly validated. The absence of a security policy and limited visibility into critical utility implementations prevents a higher security score. The application's use of Swift provides good memory safety, but mixed Swift/Objective-C code and external process execution require careful auditing. No hardcoded credentials or obvious injection points were detected in the visible file structure.

  • Medium · Objective-C Legacy Code - Network Utilities — Commons/Sources/CommonsObjC/NetUtils.m, Commons/Sources/CommonsObjC/include/NetUtils.h. The codebase includes Objective-C network utilities (NetUtils.m/h) which are legacy code patterns. While not inherently vulnerable, mixing Objective-C and Swift can introduce memory management issues and reduce code review coverage, especially in security-sensitive network operations. Fix: Consider migrating NetUtils to pure Swift or ensure comprehensive security auditing of Objective-C code. Review for potential memory leaks, buffer overflows, and unsafe pointer operations.
  • Medium · Process Execution Utilities — Commons/Sources/Commons/ProcessUtils.swift. The codebase contains ProcessUtils.swift which handles process execution. Improper handling of process execution can lead to command injection vulnerabilities if user input is not properly sanitized before being passed to system processes. Fix: Audit ProcessUtils.swift to ensure: 1) User input is never directly interpolated into command strings, 2) Arguments are properly escaped or passed as separate arguments array, 3) Environment variables are safely managed, 4) Input validation is enforced.
  • Medium · File Operations Without Validation — Commons/Sources/Commons/FileUtils.swift. FileUtils.swift handles file operations which could be vulnerable to path traversal attacks if file paths from user input are not properly validated. The test resources show various file structures that may indicate path manipulation testing. Fix: Implement strict path validation: 1) Canonicalize paths and ensure they resolve within expected directories, 2) Validate against path traversal sequences (../, ..), 3) Use URL APIs with secure defaults, 4) Implement allowlist-based path access controls.
  • Low · No Security Documentation — Repository root. The repository lacks security.md, vulnerability disclosure policy, or security guidelines. This makes it difficult for security researchers to report issues responsibly. Fix: Create a SECURITY.md file with: 1) Security reporting procedure, 2) Response timeframe expectations, 3) Security contact information, 4) Scope of vulnerability reports.
  • Low · Potential Logging of Sensitive Data — Commons/Sources/Commons/LoggerCommons.swift. LoggerCommons.swift is present but actual implementation is not visible. Logging utilities in GUI applications often inadvertently log sensitive data (passwords, tokens, file contents). Fix: Review logging implementation to ensure: 1) Sensitive data is never logged, 2) Log levels are appropriately configured in production builds, 3) Log files are not stored in world-readable locations, 4) Implement log redaction for credentials.
  • Low · Cache Implementation Security — Commons/Sources/Commons/FifoCache.swift. FifoCache.swift implements a cache mechanism. If this cache stores sensitive data (such as file contents or user preferences), there could be information disclosure risks if cache is not properly cleared. Fix: Ensure cache implementation: 1) Does not store sensitive data, or encrypts cached sensitive data, 2) Implements secure eviction policies, 3) Provides explicit cache clearing mechanisms, 4) Has memory limits to prevent unbounded growth.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.