Skip to content

AI spaces

An AI space is a DNF host with the ai-space profile, generally a microVM guest. It hosts an assistant OpenClaw 🡕 reserved for its members, with its own secrets and its own data.

  1. Declare the host and its members

    The host’s users are its members: DNF creates the Kanidm group space-<hôte> for them.

    etc/config.yaml
    - hostname: "ia-pro"
    zone: "lan:1.40"
    profile: "ai-space"
    features: ["microvm-guest:hyperviseur", "monitoring-node"]
    users: ["alice", "bob"]
    services:
    openclaw: {}

    monitoring-node places the space under the zone’s supervision: without it, neither a space failure nor an assistant shutdown triggers an alert.

    The owner is the member whose subscription runs the assistant: they receive validation requests and unsolicited messages (reminders, scheduled tasks). If the sole member, it is implicit. With multiple members, it is declared in usr/machines/ia-pro/configuration.nix (the order of users is not preserved):

    { darkone.service.openclaw.owner = "alice"; }
  2. Initialize the space

    just space-init ia-pro: host key, secrets (see Isolated hosts) and, if the network has Matrix, the bot @ia-pro:<domaine>. Then commit usr/secrets/ and var/generated/spaces/.

  3. Deploy

    The hypervisor, the zone gateway (vhost, DNS) and the HCS (Kanidm group): just apply hyperviseur,gw,hcs.

  4. Connect the AI provider

    Once per space, from the host (just enter ia-pro), depending on the space’s model (darkone.service.openclaw.model):

    ModelSubscriptionConnection
    anthropic/* (default: anthropic/claude-sonnet-5-5)Claude Pro/Max, via the claude CLIsudo -u openclaw -H claude auth login
    openai/*ChatGPT Plus/Pro, via the codex pluginopenclaw models auth login --provider openai

    The host’s openclaw command automatically switches to the service user. openclaw models status checks the connection, which stays in /var/lib/openclaw, persistent.

Members write to the bot @<hôte>:<domaine> in direct message, end-to-end encrypted. The channel only exists if the network declares the matrix service: without it, the space runs on its web interface alone.

ElementRule
Who is listened toThe space’s members (@<login>:<domaine>), DM only; other accounts are ignored
RoomsIgnored: non-members would read the replies there
SessionsOne per member when there are several, otherwise a single one for all channels
Command validationNone by default (see Security); any request goes to the owner, via DM
Unsolicited messagesSent to the owner, via DM
Encryption keysIn /var/lib/openclaw, persistent

MCP servers, skills and tools are declared once per space, in usr/machines/<hôte>/configuration.nix. The assistant and each member (Claude Code, Codex) receive the same ones.

{ pkgs, ... }:
{
darkone.host.ai-space = {
mcp.fetch = {
command = "uvx";
args = [ "mcp-server-fetch" ];
};
mcp.github = {
command = "github-mcp-server";
args = [ "stdio" ];
secretEnv = [ "GITHUB_PERSONAL_ACCESS_TOKEN" ];
};
mcp.docs.url = "https://mcp.example.com/mcp";
skills.rapport = ./skills/rapport; # dossier avec SKILL.md
packages = [ pkgs.uv pkgs.pandoc pkgs.github-mcp-server ];
};
darkone.service.openclaw = {
workspace."AGENTS.md" = ./AGENTS.md;
projects.notes = "https://forge.example.com/alice/notes.git";
};
}
OptionRole
darkone.host.ai-space.mcpMCP servers, local (command, args, env, secretEnv) or remote (url, headers)
darkone.host.ai-space.skillsSkills by name: content of SKILL.md, file or directory
darkone.host.ai-space.packagesTools in the assistant’s PATH and for members
darkone.host.ai-space.enableClaude, enableCodexClaude Code and Codex, enabled by default
darkone.service.openclaw.execCommand policy (see Security)
darkone.service.openclaw.identityAssistant name, emoji and avatar (name, emoji, avatar): the configuration being read-only, the assistant cannot change them itself
darkone.service.openclaw.workspaceAssistant workspace files (AGENTS.md, SOUL.md…)
darkone.service.openclaw.projectsGit repositories cloned once into workspace/projects/<nom>
darkone.service.openclaw.transcriptionLocal transcription of voice notes (whisper.cpp)

Voice notes, Matrix or web, are transcribed on the space with whisper.cpp’s small model (466 MB, on CPU), with no external service. The language is detected per note; transcription.language = "fr" sets it.

Each member has a Linux account on the space, trimmed down:

ElementOn the space
Home Manager profilespace-member (zsh, git, vim, tmux), instead of their own
Space toolsClaude Code and Codex, with the space’s MCP and skills (darkone.home.aiSpace)
Customizationsusr/users/<login>/space.nix (all their spaces), then usr/users/<login>/spaces/<hôte>.nix (this space), if they exist
usr/users/<login>/default.nixIgnored: reserved for their workstations
RightsNo group (no sudo), regardless of their profile

Administration of the space goes through the nix account (just enter <hôte>).

Each member connects their own subscriptions, once: claude (then /login) and codex login --device-auth.

ElementRule
Addresshttps://openclaw.<zone>.<domaine>
LoginKanidm SSO, reserved to the space-<hôte> group
DevicePaired on first visit, with no administration or validation rights (owner only)
Administrationopenclaw … on the host, from the nix account
Assistant portReachable from the zone gateway only

By default, the assistant runs its commands without validation, like OpenClaw: the barrier is the space itself (microVM cut off from the LAN, secrets specific to the space). Its service is additionally confined: it only writes to /var/lib/openclaw and sees neither members’ directories nor processes.

darkone.service.openclaw.exec chooses the policy:

ValueCommands
full (default)All, without validation
askAllowlist ones pass, the rest are submitted to the owner
autoA model examines those outside the allowlist and submits doubtful cases to the owner
allowlistAllowlist ones only
denyNone

The allowlist is filled on the host: openclaw approvals allowlist add --agent main <chemin>.