Files
azos/AGENTS.md
T
2026-06-07 01:27:09 +03:00

8.5 KiB

AGENTS.md - Guidelines for Agentic Coding in Azos

This is a NixOS/Nix flake-based configuration repository using home-manager for dotfiles and system configuration.

Build Commands

Evaluating

nix eval .#nixosConfigurations.lauretta.config.system.build.toplevel
nix flake show

Building

# VM (with submodules for azos-core)
nix build '.?submodules=1#nixosConfigurations.vm.config.system.build.vm'

# Formatter
nix build .#formatter.x86_64-linux

Deploying

# Rebuild the azos environment for lauretta (this machine) — use this when asked to "rebuild"
azos-lauretta-update
nix flake update --flake '.?submodules=1'                    # Update all inputs
nix flake lock --flake '.?submodules=1' --update-input X    # Update specific input

Note

: When the user asks to "rebuild", they mean rebuilding the lauretta environment with the command above — NOT building the VM.

Dev Shell & REPL

nix develop .#shells.x86_64-linux.default
nix repl
:lf .

Ad-hoc Commands

If an executable doesn't exist on the system, run it ad-hoc with:

nix shell nixpkgs#<package> --command <cmd> <args>

Linting/Formatting

Uses alejandra:

nix fmt   # Format all Nix files
alejandra .

Testing

Manual VM testing:

nix build '.?submodules=1#nixosConfigurations.vm.config.system.build.vm'
./result/bin/run-nixos-vm

Emacs Debugging

When adding or debugging Emacs functionality, you can interact with the running Emacs session via emacsclient (with user permission):

# Create and switch to a buffer
emacsclient -c -e '(switch-to-buffer (get-buffer-create "test"))'

# Evaluate arbitrary Elisp
emacsclient -e '(message "hello")'

Repository Structure

azos/
├── flake.nix                  # Main flake
├── home-manager/home.nix      # Home-manager entry point; manually imports all modules
├── _machines/                 # Per-machine NixOS configs (pass suiteModules as specialArgs)
├── nixos/                     # NixOS system configs (configuration.nix, configuration-vm.nix, etc.)
├── features/                  # Machine-specific home-manager features (auto-discovered)
├── overlays/                  # Package overlays
├── shells/                    # Dev shells
└── azos-core/                 # Shared feature library (git submodule)
    ├── flake.nix
    ├── features/              # Shared/reusable features (auto-discovered)
    ├── overlays/              # Core overlays
    └── _lib/                  # Module schema helpers

Features are auto-discovered by import-tree — no central imports file. Each feature's default.nix registers itself via config.flake.modules.homeManager.<name>. Modules are then explicitly imported in home-manager/home.nix via suiteModules.homeManager.<name>.

Where to put a new feature:

  • Shared / reusable across machines → azos-core/features/<name>/default.nix
  • Machine-specific → azos/features/<name>/default.nix

Code Style Guidelines

Nix Module Template

All features follow this flake-parts registration pattern:

{...}: {
  config.flake.modules.homeManager.<name> = {
    lib,
    config,
    pkgs,
    ...
  }: {
    options.azos.<name>.enable = lib.mkOption {
      default = false;
      example = true;
      type = lib.types.bool;
    };

    config = lib.mkIf config.azos.<name>.enable {
      home.packages = with pkgs; [pkg1 pkg2];
    };
  };
}

Naming Conventions

  • Option paths: azos.<module-name>.<option>
  • Module names: kebab-case (git-config, claude-memory)
  • Feature directories: kebab-case, one default.nix per feature
  • Variables: kebab-case

Formatting

  • Indentation: 2 spaces
  • Packages: with pkgs; [pkg1 pkg2] (no trailing semicolon inside list)

Imports

  • Always include {...} for the outer module args
  • Inner module args: lib, config, pkgs, ...

Option Patterns

  • Boolean enable: lib.mkOption { default = false; example = true; type = lib.types.bool; }
  • Conditional config: lib.mkIf config.azos.<name>.enable { ... }
  • Auto-enable a dependency: azos.<dep>.enable = lib.mkDefault true;
  • Force value: lib.mkForce (sparingly)

Extensible Options

For options that multiple modules should be able to contribute to, use attrset options:

options.azos.<name>.things = lib.mkOption {
  default = {};
  type = lib.types.attrsOf lib.types.path;  # or lines, str, etc.
};

Any module can then add entries without modifying the owning feature. Examples in use:

  • azos.claude.globalSkills — attrset of skill name → markdown file path
  • azos.claude.globalMdSections — attrset of key → markdown string (merged into ~/.claude/CLAUDE.md)

Home-Manager vs NixOS

  • Home-manager: home.packages, home.file, programs.<program>
  • NixOS: config.services, environment.systemPackages

Deploying Files

  • Static file: home.file."dest".source = ./file;
  • Generated text: home.file."dest".text = "...";
  • Runtime script (e.g. merging JSON at activation): home.activation.<name> = lib.hm.dag.entryAfter ["writeBoundary"] ''...'';

Suites System

Top-level suites group related features (defined in azos-core/):

  • azos.suites.base — base packages and config
  • azos.suites.editor — editor tools
  • azos.suites.dev — development tools
  • azos.suites.station — desktop applications
  • azos.suites.exwm — EXWM window manager

The machine suite (azos.suites.lauretta) enables the relevant suites for this machine.

Specializations

NixOS supports specializations for alternative configurations:

specialisation = {
  hyprland = {
    configuration = {
      home-manager.users.aner = {pkgs, ...}: {
        azos.suites.exwm.enable = lib.mkForce false;
        azos.suites.hyprland.enable = true;
      };
    };
  };
};

Adding New Modules

  1. Create features/<name>/default.nix (machine-specific) or azos-core/features/<name>/default.nix (shared)
  2. Use the module template above
  3. Add suiteModules.homeManager.<name> to the imports list in home-manager/home.nix
  4. Run nix fmt

Submodule gotcha: New files in azos-core/ must be git add-ed inside the submodule before nix build will see them — Nix flakes only evaluate git-tracked files.

cd azos-core && git add features/<name>/

Claude Integration

Claude Code is integrated with this environment via several azos-core features:

Feature Option What it does
azos-core/features/claude-memory azos.claude-memory.enable Registers org-roam-mcp as a global MCP server in ~/.claude.json
azos-core/features/claude-skills azos.claude-skills.enable Deploys skills to ~/.claude/commands/ and content to ~/.claude/CLAUDE.md
azos/features/claude azos.claude.enable Installs claude-code, auto-enables the above two

Adding Claude skills or standing instructions

From any module — no need to touch azos-core:

azos.claude.globalSkills.my-skill = ./skills/my-skill.md;
azos.claude.globalMdSections.my-rule = ''
  # My Rule
  Always do X when Y.
'';

See azos-core/features/claude-skills/README.md for full documentation.

Key Files

File Purpose
flake.nix Main flake, defines systems and overlays
home-manager/home.nix Home-manager entry point, imports all modules
_machines/lauretta.nix Lauretta machine config, passes suiteModules as specialArgs
nixos/configuration.nix Lauretta NixOS system config
nixos/configuration-vm.nix Test VM config
overlays/ Package overlays
azos-core/ Shared feature library (git submodule)
azos-core/features/ Shared features (auto-discovered by import-tree)
features/ Machine-specific features (auto-discovered by import-tree)
azos-core/features/editor/emacs/config.org Literate Emacs config
azos-core/features/claude-skills/README.md Claude skills extensibility docs

Common Tasks

Add system package: Edit a NixOS feature, add to environment.systemPackages = with pkgs; [ pkg ]

Add home-manager package: Edit a feature's config block, add to home.packages = with pkgs; [ pkg ]

Add system service: Edit a NixOS feature, add under services.<service>

Add custom package: Add to azos-core/overlays/ via config.flake.overlayPkgs.<name>, then use as pkgs.<name>

Access unstable packages: Use pkgs.unstable.<package> (via unstable-packages overlay)