Skip to content

Repository files navigation

Codegeist OS

Codegeist OS graphical installation and offline inference

Codegeist OS is the workspace for a NixOS-based personal desktop that integrates a catalog-selected local language model, the Codegeist CLI, and accelerator- backed local speech while keeping AI execution separate from the normal human user.

Purpose

The project defines an operating system in which AI-assisted actions are constrained by operating-system identity, policy, approval, and auditable system boundaries. Access to human data, credentials, devices, processes, networks, and privileged operations must be granted deliberately and remain revocable.

codegeist-llm owns logical language-model selection, training, provenance, evaluation, runtime-variant production, and release artifacts. codegeist owns the CLI and its native releases. This repository owns the current direct integration pins and operating-system isolation. It will also own the planned generic catalog that connects LLM and speech variants to hardware profiles and their lifecycle, updates, rollback, and recovery.

Version 1 Target

The first integration milestone is intentionally narrow:

  • NixOS with classic stable Nix interfaces, not experimental Nix Flakes.
  • Separate x86_64 and aarch64 UEFI desktop images using GNOME.
  • A model-free bootstrap VM and a production live-ISO closure with no GGUF or speech-model bytes. The installed x86_64 system receives one model through a mandatory Calamares download.
  • A broad hardware-profile contract for CPU and independently verified Intel, AMD, NVIDIA, and Qualcomm accelerators. The RTX A2000 12GB remains the first planned CUDA reference profile, not a measured or universal requirement.
  • One approved logical language-model release with multiple cataloged variants for formats, quantizations, system architectures, backends, and resource envelopes.
  • SafeTensors as the canonical training output and quantized GGUF as the OS runtime-variant format where appropriate.
  • A native llama.cpp server exposing one OpenAI-compatible loopback API.
  • A shared future catalog for German STT, anonymous diarization, and fixed-voice TTS variants, with model payloads also excluded from the base ISO.
  • Anonymous speaker diarization that assigns transcript segments to file-local labels such as SPEAKER_00, without identifying people.
  • Matching preinstalled Codegeist Linux native releases for each supported system architecture.
  • Architecture-specific QEMU VMs and bootable GNOME installer ISOs built from reviewed NixOS profiles.
  • codegeist --version in the model-free bootstrap and one real offline ask smoke under the locked paired Geist identity in the installed system.

The current x86_64 ISO is a reproducible GNOME live image and Codegeist OS-branded Calamares disk installer whose closure contains no GGUF bytes. It retains the upstream NixOS installer layout, replaces the installation slideshow with a Codegeist progress page, installs the pinned NixOS channel, and lets the human configure the installation account and hostname. Installation requires network access: after building the target, Calamares downloads the 1.1 GB codegeist-llm Q4_K_M GGUF directly to /var/lib/codegeist/model.gguf. A native llama.cpp server loads that file with context 4096 and exposes its OpenAI-compatible API at 127.0.0.1:11434. /etc/codegeist/codegeist.yml directs Codegeist to that endpoint using the gpt-5-mini alias required by Codegeist 0.5.0. The installer does not checksum the download.

The human account receives only geist; the wrapper runs codegeist ask as a locked, non-login <username>-geist system user. The two accounts share the private primary group <username> with group-writable newly created files. The installer installs this one pinned model but does not rank hardware or offer model selection. Generic catalog selection, alternate-model acquisition, offline package import, persistent model lifecycle and recovery, live microphone capture, speaker identification, voice cloning, desktop control, privileged actions, and a general human approval interface remain later milestones.

Current State

  • The architecture and cross-repository artifact contracts are documented.
  • NixOS 26.05.7006.445d861c6d31 is pinned directly in nix/artifacts.nix, and classic nix-build attributes build the Codegeist package, x86_64 UEFI headless and VNC bootstrap runners, the Geist wrapper, native llama.cpp runtime, the payload-free GNOME Calamares ISO closure, and the wrapper, bootstrap, and graphical installer tests.
  • The bootstrap creates a locked non-login codegeist-ai system user, keeps its home and empty workspace private, disables SSH and sudo, and does not add a human-facing Codegeist command to the system PATH.
  • The UEFI test boots through OVMF and systemd-boot, reaches multi-user.target, and verifies Codegeist 0.5.0 metadata commands under the AI UID in a private-network systemd unit.
  • The production ISO boots GNOME and installs to a blank UEFI disk through a minimally branded Calamares UI with Codegeist OS product strings, a color Directed Bus sidebar and application icon, the full welcome wordmark, a Codegeist installation-progress page, the Codegeist palette, and a dedicated Local AI model page that discloses the mandatory artifact, size, and source before partitioning. During installation, the progress status changes for target-runtime transfer and model download. Its QEMU test verifies the branded welcome and model pages, partitioning, model download, installation, ISO ejection, reboot, GDM, login with the configured human test account, the hostname in GNOME Console, and a visible real offline geist ask response. The visible host-side smoke uses the production model URL without a test cache, mirror, firmware override, or install wrapper.
  • The Calamares-generated target starts one native llama.cpp service on loopback. The graphical installation smoke proves the complete local request path through a visible geist response. The loopback API is accessible to all local processes.
  • Calamares creates a private <username> group shared by the human and locked <username>-geist system accounts. The Geist account has no password, login shell, own group, or wheel membership. A NOPASSWD:NOSETENV sudo rule permits only the immutable internal Geist command; arbitrary commands as the Geist account remain denied. The human home is 0750, login umask is 007, and the internal command also uses umask 0007 so both accounts can update group-shared project and session files.
  • geist one two executes codegeist ask "one two" as <username>-geist while preserving the current directory. The immutable wrapper directs Codegeist's LOG_FILE to /var/lib/geist/<username>/logs/codegeist.log and CODEGEIST_SESSION_DIRECTORY to /var/lib/geist/<username>/.codegeist, and disables Spring shell history so application state is not created in the human workspace. The raw codegeist command is not added to the human PATH. On the installed system, the real wrapper reaches the local llama.cpp API and returns a non-empty offline model response. The separate bootstrap VM remains model-free and exercises the provider-unavailable path.
  • Aarch64, the generic variant catalog, hardware ranking and model selection, model-manager lifecycle and recovery, external package import, speech, accelerator profiles, hardened human desktop policy, rollback, and recovery outputs remain target decisions rather than implemented guarantees.
  • The native llama.cpp path is CPU-only in the current QEMU gate. No CUDA-capable development container, accelerated speech package, anonymous diarization implementation, or physical hardware smoke is implemented yet.
  • Human approval, audit, rollback, and recovery remain design requirements, not implemented security controls.
  • Codegeist v0.5.0 is sufficient for the bootstrap metadata smoke but its Linux archive requires an x86-64-v3 CPU, omits the documented license file, and carries an optional libinstrument.so dependency on an absent libjli.so. The Nix package pins the later repository 0BSD license separately and permits only that unused instrumentation dependency; a corrected upstream archive is required before an OS release.
  • This repository is public through its GitHub mirror. Do not commit private planning material, credentials, personal data, model weights, or restricted artifacts.

Geist Command

After Calamares creates the human account, geist accepts the complete prompt as ordinary shell arguments:

geist Explain this project

The wrapper joins those arguments with spaces and executes the equivalent of codegeist ask "Explain this project" as <username>-geist. It does not use eval, preserve caller-selected environment variables through sudo, or permit a different command. The paired account cannot log in. Because both accounts share the private <username> group, the process can access every path whose group mode allows it, not only the current directory. It preserves that caller directory but keeps logs and Codegeist sessions under /var/lib/geist/<username> and disables Spring shell history. Codegeist reads /etc/codegeist/codegeist.yml and reaches the local llama.cpp OpenAI-compatible endpoint.

Build And Test

Use the Taskfile shortcuts from the repository root:

task build
task test
task check
task start
task start-vnc
task test-installer
task record-installer-demo

task build builds the GNOME installer ISO whose closure excludes the GGUF; installing from it still requires the mandatory network model download. task build-bootstrap builds the Codegeist and Geist packages plus both model-free VM runners. task test runs the wrapper, unattended bootstrap, and graphical installation tests, including installed-system llama.cpp startup and real offline inference, while task check also verifies the pins and all build outputs. The installer smoke runs outside the Nix sandbox because Calamares must reach the immutable production model URL. It first discards its old VM, probe, OCR-output, and driver state. task start builds the model-free bootstrap VM when needed and starts QEMU on the serial console. Additional QEMU arguments can be forwarded after --, for example:

task start -- -snapshot

For graphical testing, start the same UEFI VM with a localhost-only VNC server:

task start-vnc

Connect a VNC client to vnc://127.0.0.1:5900. To use another local display and port, pass a Task variable; display :1 maps to TCP port 5901:

task start-vnc VNC_DISPLAY=127.0.0.1:1

The VNC endpoint has no password because it is a local development interface. Keep it bound to 127.0.0.1; do not expose it on 0.0.0.0 or a remote network. The dedicated VNC runner uses tty0 as the primary kernel console, so firmware, systemd-boot, kernel messages, and the final login prompt remain visible in the VNC client instead of switching to the serial-only headless console.

To run the complete production installation and installed-system login smoke:

task test-installer

The task builds the host-side test driver, boots the exact production ISO on a fresh 32 GiB QEMU disk, and automatically opens a view-only TigerVNC window on 127.0.0.1:5900. OCR and emulated keyboard input drive Calamares; no mouse or USB tablet is added. Calamares downloads the GGUF from its production URL directly into the installed target. After reboot the test logs in through GDM, skips the GNOME tour, opens GNOME Console, runs a real offline geist ask, and verifies the visible response. QEMU and OCR use a fixed 1280x800 framebuffer. OCR reads only bounded page-specific regions, limits each ImageMagick and Tesseract subprocess to ten seconds, and uses one Tesseract thread. The VNC endpoint has no password, remains fixed to localhost, and closes when the test finishes; viewer input is disabled. Screenshots and structured timing records remain under target/installer-vnc-output/; installer-events.jsonl records every OCR attempt, installation duration, and total test duration.

task record-installer-demo runs that same authoritative E2E through a view-only localhost VNC client. It keeps the complete H.264 recording at target/installer-demo/codegeist-os-installer-full.mp4 and, only after a successful test, rebuilds the curated 37-second README GIF from the screenshots captured during that run. The full MP4 and recording logs remain ignored local artifacts; only docs/assets/installer/codegeist-os-installer.gif belongs in Git. See docs/feature-demos.md for the reusable workflow, visual and size defaults, security checks, validation commands, and conventions for future feature GIFs.

The VM itself has no login credential. Use task reset-vm-state to delete its mutable disk and EFI variables, task clean to remove only build result links, or task clean-all for both. Run task --list for the complete command list. Run task reset-vm-state after changing a VM profile: an existing QCOW2 overlay keeps the immutable backing image from the moment that overlay was created.

All generated workspace artifacts stay under target/:

target/
  codegeist
  geist
  iso
  installer-driver
  installer-demo/
  installer-vnc-output/
  vm
  vm-vnc
  test
  test-geist-wrapper
  vm-state/
    headless/
    installer-vnc/
    vnc/

The tasks delegate to these classic build attributes:

nix-build -A packages.x86_64.codegeist -o target/codegeist
nix-build -A packages.x86_64.geist -o target/geist
nix-build -A images.x86_64.iso -o target/iso
nix-build -A images.x86_64.vm -o target/vm
nix-build -A images.x86_64.vmVnc -o target/vm-vnc
nix-build -A tests.x86_64.bootstrap -o target/test
nix-build -A tests.x86_64.geistWrapper -o target/test-geist-wrapper
nix-build -A tests.x86_64.installerDriver -o target/installer-driver

The VM runner can also be started directly with:

NIX_DISK_IMAGE=./target/vm-state/headless/codegeist-os.qcow2 \
NIX_EFI_VARS=./target/vm-state/headless/codegeist-os-efi-vars.fd \
./target/vm/bin/run-codegeist-os-vm

The bootstrap VM deliberately has no login credential. Mutable VM disks, EFI variables, generated images, and build links stay under ignored target/ and outside Git.

Documentation

  • docs/architecture.md defines the selected Version 1 system architecture and identity boundaries.
  • docs/base-system-selection.md records the NixOS decision and the stable Nix, no-Flakes policy.
  • docs/artifact-contract.md defines image inputs, the shared LLM and speech catalog, hardware profiles, external test bundles, fixtures, and per-system Codegeist releases.
  • docs/build-workflow.md defines the independent model, CLI, bootstrap VM, payload-free ISO, installed inference, external-bundle, and hardware-profile verification flow.
  • docs/feature-demos.md defines how successful feature workflows become local full recordings and curated repository-owned GIFs.
  • docs/speech-model-evaluation.md records the local TTS/STT hardware smoke, candidate models, diarization research, licenses, and first accelerator-profile direction.
  • docs/security.md defines least-privilege, isolation, artifact, audit, disablement, and recovery requirements.

Workspace Kits

.devcontainer/ and .opencode/ are Git submodules that track the release branches of the shared Codegeist development and agent kits. Initialize them from this repository with:

git submodule update --init .devcontainer .opencode

Source References

refs/codegeist/ and refs/codegeist-llm/ are read-only source-reference submodules that track main on the public GitHub repositories. They support cross-repository review and contract work without making either mutable source tree an OS build input. Normal VM and ISO builds must continue to consume only reviewed native releases, manifests, catalogs, and hashes from docs/artifact-contract.md.

Initialize all workspace submodules with:

git submodule update --init \
  .devcontainer .opencode refs/codegeist refs/codegeist-llm

Updating a reference submodule changes a real parent-repository gitlink and must be reviewed explicitly. Both reference repositories track main, but the parent repository always records a concrete commit.

Hosting

Gitea at git.codegeist.ai is the primary write target. GitHub at github.com/codegeist-ai/codegeist-os is a public push mirror of Git refs. Issues, pull requests, secrets, permissions, and other platform state are not automatically synchronized.

TLS Trust

Development environments should trust the certificate authority used by the Gitea deployment and keep Git TLS verification enabled. Installing that CA in the environment trust store is the required long-term fix.

This repository currently carries an explicit temporary exception in .codegeist/Dockerfile: GIT_SSL_NO_VERIFY=true disables certificate verification for every Git HTTPS request made inside the rebuilt devcontainer, including non-Gitea hosts. It does not provide Gitea authentication and does not affect host-side submodule initialization before the container starts. Never put a Gitea token in a remote URL, Dockerfile, environment committed to Git, or other tracked file. Remove the exception as soon as the Gitea CA is trusted.

License Status

Codegeist OS-owned repository material is available under the Zero Clause BSD License (0BSD) in LICENSE. Third-party packages, firmware, drivers, models, voices, fixtures, and other artifacts retain their own terms. Their complete distribution rights still require review before an OS release is published.

About

AI-focused Linux distribution research with a least-privilege AI user

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages