No description
  • Rust 74.5%
  • Vue 10.8%
  • Nix 7.7%
  • TypeScript 6.7%
  • PLpgSQL 0.2%
Find a file
2026-07-23 15:58:23 +02:00
docs make it compile 2026-07-21 07:29:01 +02:00
examples api key file option 2026-07-23 00:14:35 +02:00
nixosConfigurations/modules test vm working 2026-07-19 19:02:38 +02:00
nixosModules microvm template editor 2026-07-23 15:02:08 +02:00
packages admin webui with skills and vm template management 2026-07-23 15:58:23 +02:00
.gitignore local login first steps 2026-07-22 22:29:06 +02:00
flake.lock build with crane to cache rust deps 2026-07-21 13:20:51 +02:00
flake.nix local login first steps 2026-07-22 22:29:06 +02:00
IMPLEMENTATION.md flake demo 2026-07-19 16:11:48 +02:00
README.md fix readme mermaid charts 2026-07-22 09:44:27 +02:00
review.md local login first steps 2026-07-22 22:29:06 +02:00

Agent Platform

A Nix-based platform for running AI agents as MicroVMs.

Architecture

High-Level Architecture

graph TB
    subgraph Browser["🌐 Web Browser"]
        FE["Web Frontend<br/>(Vue.js + Element Plus)"]
    end

    subgraph Host["🖥️ Host Machine (NixOS)"]
        subgraph Nginx["nginx (reverse proxy)"]
            NGINX[":80 / :443"]
        end

        subgraph AgentWeb["agent-web (Axum/Rust)"]
            AW[":3000<br/>OIDC Auth + LLM Proxy<br/>Agent CRUD + SSE Streams<br/>Secret Management"]
        end

        subgraph MicrovmMgr["microvm-manager (Axum/Rust)"]
            MM[":9090<br/>VM Lifecycle API"]
        end

        POSTGRES["PostgreSQL<br/>agents, secrets,<br/>skill_packs, api_keys"]

        subgraph MicrovmHost["MicroVM Host Infrastructure"]
            BRIDGE["br-microvm<br/>bridge interface"]
            NAT["NAT / Firewall<br/>iptables + ip6tables"]
            CH["cloud-hypervisor<br/>hypervisor binary"]
        end

        subgraph MicroVMs["📦 Agent MicroVMs"]
            MV1["microvm-1<br/>pi-agent (Rust)"]
            MV2["microvm-N<br/>pi-agent (Rust)"]
        end

        LLM["External LLM API<br/>(OpenAI / Ollama / etc.)"]
        AUTH["OIDC Provider<br/>(Authentik)"]
    end

    FE -->|proxy /api| NGINX
    NGINX -->|proxy /| AW
    NGINX -->|proxy /| FE

    AW -->|HTTP REST| MM
    AW -->|SQL queries| POSTGRES
    AW -->|OpenAI-compatible API| LLM
    AW -->|OIDC introspect| AUTH
    AW -->|WebSocket| MV1
    AW -->|WebSocket| MV2

    MM -->|spawn| CH
    CH -->|virtio| MV1
    CH -->|virtio| MV2

    MV1 -.->|eth0 over veth| BRIDGE
    MV2 -.->|eth0 over veth| BRIDGE
    BRIDGE -->|NAT masquerade| NAT

    style Browser fill:#e8f4fd,stroke:#2196F3
    style Host fill:#f5f5f5,stroke:#9e9e9e
    style MicroVMs fill:#fff3e0,stroke:#FF9800

Agent Web Internal

classDiagram
    class AppState {
        +PgPool db
        +AuthClient auth_client
        +LlmProxy llm_proxy
        +AdminService admin_service
        +AgentService agent_service
        +WsManager ws_manager
        +MicrovmManager microvm_manager
        +ModelCache model_cache
        +String auth_mode
        +Option admin_api_key
    }

    class AuthClient {
        +provider_url
        +client_id
        +client_secret
        +http_client
        +jwks_cache
        +introspect_token()
        +validate_id_token()
        +exchange_code()
        +get_jwks()
        +verify_jws_signature()
    }

    class LlmProxy {
        +http_client
        +api_url
        +api_key
        +default_model
        +chat()
        +list_models()
        +forward_for_agent()
        +get_usage()
    }

    class AgentService {
        +pool
        +microvm_manager
        +create()
        +list()
        +get()
        +delete()
        +update()
        +assign_skill_pack()
        +update_status()
        +generate_api_key()
        +store_api_key()
        +validate_api_key()
        +start_agent_vm()
    }

    class AdminService {
        +pool
        +create_skill_pack()
        +list_skill_packs()
        +get_skill_pack()
        +update_skill_pack()
        +delete_skill_pack()
        +create_secret()
        +list_secrets()
        +get_secret()
        +update_secret()
        +delete_secret()
        +configure_agent()
        +encrypt_value_with_versioning()
        +decrypt_value_with_versioning()
    }

    class WsManager {
        +agent_senders
        +agent_receivers
        +key_registry
        +connected
        +agent_service
        +register()
        +unregister()
        +send()
        +receive()
        +is_connected()
        +notify_response()
    }

    class ModelCache {
        +cache
        +ttl_seconds
        +get()
        +list()
    }

    class AuthExtractor
    class require_auth
    class require_admin

    class OidcProvider {
        +issuer_url
        +jwks_url
        +authorize_url
        +token_url
        +userinfo_url
    }

    class LlmApi {
        +base_url
        +api_key
        +models()
        +chat_completion()
    }

    class PostgreSQL {
        +connection_pool
        +query()
        +execute()
        +transaction()
    }

    class BroadcastChannels {
        +channels
        +send()
        +receive()
    }

    AppState --> AuthClient
    AppState --> LlmProxy
    AppState --> AgentService
    AppState --> AdminService
    AppState --> WsManager
    AppState --> ModelCache
    AppState --> MicrovmManager

    AuthClient --> OidcProvider
    LlmProxy --> LlmApi
    AgentService --> MicrovmManager
    AgentService --> PostgreSQL
    AdminService --> PostgreSQL
    WsManager --> BroadcastChannels

    note for AppState "Central application state, shared via Arc"
    note for AuthClient "Handles OIDC flow: PKCE, introspect, JWKS, JWS verify"
    note for AdminService "AES-256-GCM encryption for secrets at rest"

MicroVM Manager Internal

classDiagram
    class VmManager {
        +vms
        +child_processes
        +config_loader
        +network_manager
        +start()
        +stop()
        +destroy()
        +list()
        +get_logs()
        +configure()
    }

    class NetworkManager {
        +assigned_ips
        +vms_dir
        +setup_network()
        +teardown_network()
        +create_bridge()
        +assign_nic_to_bridge()
        +setup_ipv6()
        +setup_iptables_nat()
    }

    class ConfigLoader {
        +vms_dir
        +api_key
        +allowed_origin
        +default_image
        +generate_vm_config()
        +save_vm_config()
        +load_vm_config()
    }

    class AppState {
        +vm_manager
        +config_loader
        +api_key
        +allowed_origin
    }

    class VmState {
        <<enumeration>>
        Stopped
        Starting
        Running
        Stopping
    }

    class VmInfo {
        +name
        +state
        +ip_address
        +pid
        +config_path
        +created_at
    }

    class VmConfig {
        +name
        +image
        +memory_mb
        +cpu_count
        +network
        +agent_config
        +api_key
        +config_hash
    }

    class HashMapVmEntry {
        +VmEntry
        +HashMap<VmName, VmEntry>
    }

    VmManager --> NetworkManager
    VmManager --> ConfigLoader
    VmManager --> HashMapVmEntry
    AppState --> VmManager
    VmManager --> VmState
    VmManager --> VmInfo
    VmManager --> VmConfig
    ConfigLoader --> VmConfig
    NetworkManager --> VmConfig

    note for VmManager "Manages cloud-hypervisor processes"
    note for NetworkManager "Creates bridges, veth pairs, IPv6, NAT"
    note for ConfigLoader "Generates VM config JSON + API keys"

Frontend Architecture

graph TB
    subgraph Frontend["🖥️ Web Frontend (Vue 3 + TypeScript)"]
        subgraph AppLayer["App Layer"]
            APP["App.vue"]
            ROUTER["router/index.ts<br/>Vue Router + guards"]
        end

        subgraph ViewLayer["View Layer"]
            LOGIN["LoginView.vue"]
            CALLBACK["AuthCallbackView.vue"]
            AGENTS_LIST["AgentsView.vue"]
            AGENT_CREATE["AgentCreateView.vue"]
            AGENT_CHAT["AgentChatView.vue"]
            ADMIN["AdminView.vue"]
        end

        subgraph ComponentLayer["Component Layer"]
            SECRET_MGR["SecretManager.vue"]
            SKILL_MGR["SkillPackManager.vue"]
        end

        subgraph StoreLayer["State Layer (Pinia)"]
            AUTH_STORE["auth store<br/>user, roles, token"]
            AGENT_STORE["agent store<br/>agents, currentAgent, models"]
            ADMIN_STORE["admin store<br/>secrets, skillPacks"]
        end

        subgraph ApiLayer["API Layer"]
            CLIENT["api/client.ts<br/>axios instance + interceptors"]
            AGENTS_API["api/agents.ts<br/>agent CRUD + ws + SSE"]
            MODELS_API["api/models.ts<br/>LLM model list"]
            ADMIN_API["api/admin.ts<br/>secrets + skill packs"]
        end

        subgraph TypeLayer["Types"]
            TYPES["types/index.ts<br/>Agent, Secret, SkillPack"]
        end
    end

    ROUTER --> LOGIN
    ROUTER --> CALLBACK
    ROUTER --> AGENTS_LIST
    ROUTER --> AGENT_CREATE
    ROUTER --> AGENT_CHAT
    ROUTER --> ADMIN

    AGENTS_LIST --> AGENT_STORE
    AGENTS_LIST --> SECRET_MGR
    AGENTS_LIST --> SKILL_MGR
    AGENT_CHAT --> AGENT_STORE
    AGENT_CHAT --> AGENTS_API
    ADMIN --> ADMIN_STORE
    ADMIN --> SECRET_MGR
    ADMIN --> SKILL_MGR

    AGENT_STORE --> AGENTS_API
    ADMIN_STORE --> ADMIN_API
    AUTH_STORE --> CLIENT

    CLIENT --> TYPES

    style Frontend fill:#e3f2fd,stroke:#1976D2
    style ViewLayer fill:#fff,stroke:#ccc

Multihost Architecture

graph TB
    subgraph WebServiceHost["🖥️ Web-Service Host"]
        subgraph Nginx["nginx"]
            NGINX[":80 / :443<br/>TLS termination"]
        end

        subgraph AgentWebService["agent-web (Axum)"]
            AW[":3000<br/>Web API + OIDC + LLM Proxy"]
        end

        subgraph MicrovmMgrSvc["microvm-manager (Axum)"]
            MM1[":9090<br/>VM lifecycle API"]
        end

        POSTGRES["PostgreSQL"]
        LLM["External LLM API"]
        AUTH["OIDC Provider<br/>(Authentik)"]
    end

    subgraph MicrovmHost["📦 Dedicated MicroVM Host"]
        subgraph MicrovmMgrHost["microvm-manager (Axum)"]
            MM2[":9090<br/>VM lifecycle API"]
        end

        subgraph HostInfra["Host Infrastructure"]
            CH["cloud-hypervisor"]
            BRIDGE["br-microvm<br/>bridge"]
            NAT["NAT / Firewall"]
        end

        subgraph GuestVMs["Agent MicroVMs"]
            MV1["microvm-1<br/>pi-agent"]
            MV2["microvm-2<br/>pi-agent"]
            MVN["microvm-N<br/>pi-agent"]
        end
    end

    NGINX -->|proxy /api/| AW
    NGINX -->|proxy /| FE["Web Frontend"]

    AW -->|HTTP REST| MM1
    AW -->|SQL| POSTGRES
    AW -->|API calls| LLM
    AW -->|OIDC| AUTH

    MM1 -->|HTTP| MM2
    MM2 -->|spawn| CH
    CH -->|virtio| MV1
    CH -->|virtio| MV2
    CH -->|virtio| MVN

    MV1 -.->|eth0/veth| BRIDGE
    MV2 -.->|eth0/veth| BRIDGE
    MVN -.->|eth0/veth| BRIDGE
    BRIDGE --> NAT

    style WebServiceHost fill:#e3f2fd,stroke:#1976D2
    style MicrovmHost fill:#fff3e0,stroke:#FF9800
    style GuestVMs fill:#f3e5f5,stroke:#9C27B0
Component Description
flake.packages.x86_64-linux.agent-web Axum web service with OIDC auth, PostgreSQL, agent/chat management.
flake.packages.x86_64-linux.microvm-manager Axum API for starting/stopping/configuring MicroVMs.
flake.packages.x86_64-linux.agent-microvm-image NixOS closure for MicroVMs (cloud-hypervisor + microvm.nix).
flake.packages.x86_64-linux.web-frontend Vue.js web application.
nixosModules.web-service NixOS module that deploys the agent-web systemd service.
nixosModules.microvm-host NixOS module that configures the host running MicroVMs.
nixosModules.microvm-image NixOS module that configures the MicroVM guest image.
nixosConfigurations.example-single-host Example NixOS configuration for single-host deployment.

Getting started

Show available packages

nix flake show .#flake.packages.x86_64-linux

Build everything

nix build .#flake.packages.x86_64-linux.agent-web .#flake.packages.x86_64-linux.microvm-manager .#flake.packages.x86_64-linux.agent-microvm-image

Enter the development shell

nix develop

Use the example single-host configuration

# Evaluate the configuration
nix eval .#nixosConfigurations.example-single-host.config.system.build.toplevel

# Test the configuration
nixos-rebuild test --flake .#example-single-host

# Switch to the configuration
nixos-rebuild switch --flake .#example-single-host

See examples/single-host/README.md for details.

Module options

services.agent-web

Option Type Default Description
enable bool false Enable the agent-web systemd service.
host str "0.0.0.0" Bind address.
port port 8080 Bind port.
authentik.clientId str OAuth2 client ID.
authentik.clientSecret str OAuth2 client secret.
authentik.issuerUrl str OpenID Connect issuer URL.
llmApiUrl str Base URL of the LLM API endpoint.
maxAgentsPerUser int 3 Maximum number of agents per user.
microvmManagerUrl str Base URL of the microvm-manager service.

services.microvm-manager

Option Type Default Description
enable bool false Enable the microvm-manager systemd service.
host str "0.0.0.0" Bind address.
port port 9090 Bind port.

networking.bridge (custom)

Option Type Default Description
enable bool false Create a bridge for MicroVMs.
name str "br-microvm" Bridge interface name.
ipv6Addresses list of str [] IPv6 addresses for the bridge.
natIpv4 bool true Enable NAT masquerade for IPv4.

microvm-host

Option Type Default Description
hypervisor str "cloud-hypervisor" Hypervisor binary.
defaultVcpu int 2 Default vCPU count per MicroVM.
defaultMem int 1024 Default memory (MiB) per MicroVM.
sharesHostStore bool false Share /nix/store via virtiofs.
image path "" Path to the MicroVM disk image.
autostart bool false Autostart managed MicroVMs on boot.

microvm-image

Option Type Default Description
sharesHostStore bool false Share host /nix/store via virtiofs.

Directory layout

.
├── flake.nix                              # Flake entry point
├── examples/
│   └── single-host/                       # Example single-host deployment
│       ├── configuration.nix
│       └── README.md
├── packages/
│   ├── agent-web/                         # Web service source (Rust/Axum)
│   ├── microvm-manager/                   # Manager API source (Rust/Axum)
│   └── web-frontend/                      # Vue.js web application
├── nixosModules/
│   ├── web-service.nix                    # Module: deploy agent-web
│   ├── microvm-host.nix                   # Module: configure MicroVM host
│   └── microvm-image.nix                  # Module: configure MicroVM guest
└── IMPLEMENTATION.md                      # Detailed implementation summary

Security

  • Root login uses key-only authentication (prohibit-password).
  • users.mutableUsers = false prevents runtime user creation.
  • Both services run as dedicated system users with sandboxed systemd units.
  • ACME + nginx terminates TLS before reaching the services.

State version

Both NixOS configurations use system.stateVersion = "24.05". Update this when rolling to a newer NixOS release.