GSoC Week 1 & 2: Building Lima's Plugin Architecture - From Concept to Code


After diving deep into the world of virtualisation and plugin systems, these first two weeks of Google Summer of Code 2025 have been nothing short of transformative. I'm excited to update you on the significant progress made in developing Lima's driver plugin system.
Mentor Guidance
One of the highlights of these initial weeks was the insightful meeting with my mentors. The session went incredibly smoothly, and I'm truly grateful for the valuable guidance provided by my mentors, Akihiro Suda and Anders Björklund. Jan Dubois, though not officially my GSoC mentor, attended the meeting as a core maintainer of the project and shared detailed insights that proved invaluable for the project direction. Many thanks to him and my mentors for coming despite their busy schedules!
Project Overview: Lima Driver Plugin System
For those new to Lima, it's a powerful virtual machine manager that launches Linux VMs with automatic file sharing and port forwarding, similar to WSL2. Lima supports various VM types, including QEMU, VZ (on macOS), and WSL2 (on Windows), making it an essential tool for containerised development workflows.
My GSoC project focuses on creating a comprehensive plugin system that allows Lima drivers to work both as:
Internal drivers: Embedded directly into the main binary
External drivers: Separate binaries communicating via gRPC
Technical Deep Dive: Major Achievements
1. Driver Architecture Refactoring
The first major milestone was completely refactoring Lima's driver architecture. Previously, Lima used a BaseDriver
pattern that all drivers extended:
I completely removed the struct and made changes accordingly to the drivers and driver.Driver interface for getting the essential details, like I also defined a new method to set the *store.Instance
and SSHLocalPort
to the driver object.
I also refactored the driver.Driver
interface which has been divided into smaller interfaces, each handling a specific aspect of virtual machine management: lifecycle operations, GUI management, snapshot handling, registration interfaces, and guest agent operations, in order to comply with the best practices of defining Go interfaces. This modular approach provides better separation of concerns and makes the codebase more maintainable.
2. Internal Driver Implementation via Blank Imports
I implemented Lima's internal driver implementation that leverages Go's powerful package initialisation mechanism through the use of blank imports and init()
functions. In Go, the blank import syntax (using the underscore character _
) allows importing a package solely for its side effects without directly referencing any of its exported identifiers.
The initialisation flow follows this sequence: when the Lima application starts, the Go runtime processes all imported packages, executing their init()
functions in dependency order. Each driver package (QEMU, VZ, WSL2) contains an init()
function that self-registers with the central driver registry.
This mechanism ensures that adding a new internal driver is as simple as creating a package that implements the driver interface and adding a blank import in the main package. The driver's init()
function handles the registration, making the system cleanly extensible without modifying core code.
3. Driver Registry Implementation
I implemented a comprehensive driver registry system that handles both internal and external drivers. Internal drivers register themselves through blank imports, and external drivers are discovered through LIMA_DRIVERS_PATH
and <PREFIX>/libexec/lima/drivers/
. The discovery through the path works well, but I need to work on the drivers directory part(see #Blockers). Users have to manually build and place the executables in the respective places for the discovery system to work:
Then the drivers can be listed through limactl create --list-drivers
command:
When Lima starts, the external driver manager scans predefined paths for executable drivers, launches them with appropriate arguments, and establishes gRPC connections. Each external driver process runs as a separate executable.
4. gRPC Protocol for External Drivers
For external drivers, Lima uses gRPC as the communication protocol, providing strong typing, versioning, and bidirectional streaming capabilities. The protocol definition is implemented in Protocol Buffers, defining service methods that mirror the Go driver interface.
The gRPC service definition includes both unary RPCs for simple operations (Validate, Initialise, etc.) and streaming RPCs for more complex interactions (Start, GuestAgentConn). This design enables external drivers to implement the same capabilities as internal drivers while running in separate processes. One key optimisation was consolidating several informational methods (Name, GetVSockPort, GetVirtioPort) into a single GetInfo RPC call to reduce round-trips.
Blockers
GuestAgentConn Implementation: Converting between net.Conn and gRPC streams in
GuestAgentConn()
function required a deep understanding of both Go networking and gRPC patterns, which is already implemented inbuildkit
. I'm currently debugging an error: "connection error: desc = 'error reading server preface: rpc error: code = Internal desc = SendMsg called after CloseSend'"gRPC Client Connection: Had to use deprecated
grpc.Dial()
instead ofgrpc.NewClient()
due to addressing issues with named pipes. I need to figure out a way to stop using the deprecated function.External drivers discovery in
<PREFIX>/libexec/lima/drivers/
doesn’t work currently."First, try to make everything work, then optimise."This wisdom helped me overcome one of my major blockers - overthinking the best approach for every implementation detail, which was slowing down my progress significantly.
Current Status and Testing
As of the end of week 2, I have successfully:
✅ Refactored the entire driver architecture
✅ Implemented internal driver registry and registration
✅ Created gRPC protocol definition and generated code
✅ Built external driver manager with discovery functionality
✅ Implemented bidirectional streaming (with ongoing debugging)
✅ Successfully created VM instances using the new system(both embedded and external)
Current external driver testing shows that VM creation works, but port forwarding has issues due to the GuestAgentConn()
implementation is still being debugged.
Reading "Mastering KVM Virtualisation" alongside the practical implementation has provided valuable context about virtualisation technologies that will help with future external driver implementations.
What's Next: Week 3-4 Goals
Moving forward, my priorities are:
Debug and fix the GuestAgentConn bidirectional streaming.
Resolve external driver process management issues and implement proper external driver lifecycle management.
Work on integrating the VZ driver as an external driver for testing.
Start implementing the
libkrun
driver(see #2277) as part of the new external driver.
Track my progress: All work is documented in the draft PR #3573 with detailed commit history showing the evolution of the implementation.
This post is part of my GSoC 2025 journey with Lima. Stay tuned for more updates as we build towards a comprehensive driver plugin system that will enable Lima to support cloud drivers and other external virtualisation technologies.
Subscribe to my newsletter
Read articles from Anshuman Sahoo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
