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.
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.
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 --versionin the model-free bootstrap and one real offlineasksmoke 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.
- The architecture and cross-repository artifact contracts are documented.
- NixOS
26.05.7006.445d861c6d31is pinned directly innix/artifacts.nix, and classicnix-buildattributes 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-aisystem 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 Codegeist0.5.0metadata 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 askresponse. 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
geistresponse. The loopback API is accessible to all local processes. - Calamares creates a private
<username>group shared by the human and locked<username>-geistsystem accounts. The Geist account has no password, login shell, own group, orwheelmembership. ANOPASSWD:NOSETENVsudo rule permits only the immutable internal Geist command; arbitrary commands as the Geist account remain denied. The human home is0750, login umask is007, and the internal command also uses umask0007so both accounts can update group-shared project and session files. geist one twoexecutescodegeist ask "one two"as<username>-geistwhile preserving the current directory. The immutable wrapper directs Codegeist'sLOG_FILEto/var/lib/geist/<username>/logs/codegeist.logandCODEGEIST_SESSION_DIRECTORYto/var/lib/geist/<username>/.codegeist, and disables Spring shell history so application state is not created in the human workspace. The rawcodegeistcommand 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.0is sufficient for the bootstrap metadata smoke but its Linux archive requires anx86-64-v3CPU, omits the documented license file, and carries an optionallibinstrument.sodependency on an absentlibjli.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.
After Calamares creates the human account, geist accepts the complete prompt as
ordinary shell arguments:
geist Explain this projectThe 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.
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-demotask 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 -- -snapshotFor graphical testing, start the same UEFI VM with a localhost-only VNC server:
task start-vncConnect 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:1The 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-installerThe 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-driverThe 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-vmThe bootstrap VM deliberately has no login credential. Mutable VM disks, EFI
variables, generated images, and build links stay under ignored target/ and
outside Git.
docs/architecture.mddefines the selected Version 1 system architecture and identity boundaries.docs/base-system-selection.mdrecords the NixOS decision and the stable Nix, no-Flakes policy.docs/artifact-contract.mddefines image inputs, the shared LLM and speech catalog, hardware profiles, external test bundles, fixtures, and per-system Codegeist releases.docs/build-workflow.mddefines the independent model, CLI, bootstrap VM, payload-free ISO, installed inference, external-bundle, and hardware-profile verification flow.docs/feature-demos.mddefines how successful feature workflows become local full recordings and curated repository-owned GIFs.docs/speech-model-evaluation.mdrecords the local TTS/STT hardware smoke, candidate models, diarization research, licenses, and first accelerator-profile direction.docs/security.mddefines least-privilege, isolation, artifact, audit, disablement, and recovery requirements.
.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 .opencoderefs/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-llmUpdating 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.
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.
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.
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.
