# build (default action)
nix run .#<host>
# deploy (switch)
nix run .#<host> -- switch
# VM for dev (no reboot needed)
nix run .#vm
# regenerate flake.nix (auto-generated, do not edit by hand)
nix run .#write-flake
# update the den framework input
nix flake update dennh is used under the hood. See AGENTS_PROJECT.md for available hosts and their package names.
nix flake check is the CI gate. Run it locally before opening a PR.
CI runs on both ubuntu-latest and macos-latest. It creates modules/ci-runtime.nix setting _module.args.CI = true — you can condition on it.
├── flake.nix # auto-generated by flake-file — DO NOT EDIT
├── AGENTS.md # this file (generic reference)
├── AGENTS_PROJECT.md # project-specific details (hosts, users, features, TODOs)
├── docs/
│ ├── den/ # Den framework documentation
│ └── superpowers/ # superpowers skill specs
└── modules/ # import-tree root (all .nix files auto-imported)
├── defaults.nix # global defaults (stateVersion, strict schema, hm)
├── dendritic.nix # flake-file config + input declarations
├── hosts/ # per-host & per-user definitions
├── features/ # reusable feature modules (aspects)
└── packages/ # wrapper packages (opencode, fish, starship, git, nh)
flake.nixis auto-generated byflake-file. Entry point:inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules). Editdendritic.nixfor config, then runnix run .#write-flake.import-tree ./modulesrecursively imports every.nixfile undermodules/. Any new.nixfile anywhere undermodules/is automatically picked up.
This flake uses the Den framework (github:denful/den). See docs/den/ for full Chinese documentation or https://den.denful.dev.
Aspects — the fundamental unit of configuration. Each aspect lives at den.aspects.<path>.<name> where path mirrors the filesystem path under modules/features/. An aspect can own NixOS config, home-manager config, or both.
4 aspect types:
| Type | Description |
|---|---|
| Static | Fixed config, no parameters. den.aspects.my-feature = { homeManager = ...; } |
| Parametric | Function returning an aspect. (system.boot "/boot/efi") |
| Forward | Proxies to another aspect via provides.to-*. Enables cross-class config flow. |
| Conditional | Gated on host/user property. Evaluated after full resolution. |
Entities — the topology of hosts and users:
den.hosts.<system>.<hostname>.users.<username> = { };Batteries — built-in convenience aspects for common tasks (hostname, define-user, primary-user, user-shell, unfree, self', system services, etc.).
Classes — the config targets. Default: [ "homeManager" ].
nixos— NixOS system confighomeManager— home-manager user config
Strict mode — when enabled (den.schema.host.strict = true), all aspects must be explicitly included.
Aspects compose via includes (pulling in sub-aspects) and cross-class wire via provides.to-*:
host (nixos class)
├── includes: hostname-battery, hardware-aspects, boot, nix, sound
└── provides.to-users.homeManager → default home packages
user (homeManager class)
├── includes: define-user, primary-user, user-shell, self', features...
└── provides.to-hosts.nixos → NixOS config extensions
Aspect name = file path relative to modules/features/, dot-separated:
| Filesystem Path | Aspect Name |
|---|---|
apps/zen-browser.nix |
den.aspects.apps.zen-browser |
desktop/wm/niri.nix |
den.aspects.desktop.wm.niri |
system/hardware/nvidia.nix |
den.aspects.system.hardware.nvidia |
services/dae.nix |
den.aspects.services.dae |
dendritic.nix ──> flake.nix (auto-generated)
│
flake-parts + import-tree
│
modules/
├── defaults.nix # global defaults
├── hosts/<hostname>/ # host + user definitions
└── features/ # reusable aspects by domain
| input | source | follows | purpose |
|---|---|---|---|
den |
github:denful/den |
— | framework |
nixpkgs |
nixpkgs-unstable | — | package set |
home-manager |
nix-community/home-manager |
nixpkgs | user envs |
flake-parts |
hercules-ci/flake-parts |
nixpkgs-lib → nixpkgs | perSystem |
import-tree |
vic/import-tree |
— | recursive module import |
flake-file |
vic/flake-file |
— | flake.nix generation |
wrappers |
BirdeeHub/nix-wrapper-modules |
nixpkgs | binary wrapping |
niri-nix |
codeberg.org/BANanaD3V/niri-nix |
— | niri home-manager module |
daeuniverse |
daeuniverse/flake.nix |
— | dae/daed proxy |
dms |
AvengeMedia/DankMaterialShell/stable |
nixpkgs | desktop shell |
dms-plugin-registry |
AvengeMedia/dms-plugin-registry |
nixpkgs | DMS plugin registry |
zen-browser |
0xc000022070/zen-browser-flake |
nixpkgs, home-manager | zen browser |
- Create
<domain>/<name>.nixundermodules/features/(e.g.,services/syncthing.nix) - Define
den.aspects.<domain>.<name>with{ nixos = ...; }and/or{ homeManager = ...; } - Add it to the relevant host/user
includesinmodules/hosts/ - Run
nix run .#write-flakeif new inputs are needed - No manual registration needed —
import-treeauto-discovers new.nixfiles
modules/packages/ wraps binaries using inputs.wrappers. Each package exposes a runnable binary via nix run .#<name>.
nix run .#opencode
nix run .#fish
nix run .#starship
nix run .#gitnh helper is available via den.lib.nh.denPackages, which exposes flake apps as packages for each host.
This project uses superpowers (github:obra/superpowers) — a skill system for OpenCode.
| Skill | When to Use |
|---|---|
brainstorming |
Before any creative work — features, changes, new modules. Always start here. |
writing-plans |
After brainstorming completes. Creates implementation plan. |
test-driven-development |
Before writing implementation code for features/bugfixes. |
systematic-debugging |
When encountering bugs, test failures, or unexpected behavior. |
requesting-code-review |
After completing work, before merging. |
receiving-code-review |
When receiving review feedback (before implementing suggestions). |
verification-before-completion |
Before claiming work is complete — run verification. |
dispatching-parallel-agents |
When facing 2+ independent tasks without shared state. |
executing-plans |
When executing an implementation plan in a separate session. |
subagent-driven-development |
When executing implementation plans with independent tasks. |
writing-skills |
When creating or editing superpowers skills. |
customize-opencode |
When editing opencode's own config. |
finishing-a-development-branch |
After implementation, to decide merge/PR/cleanup. |
using-git-worktrees |
Before starting feature work needing isolation. |
using-superpowers |
When unsure how to use superpowers. |
1. brainstorming → explore, clarify, design, approve
2. writing-plans → create implementation plan
3. test-driven-development (or subagent-driven-development → executing-plans)
4. nix flake check → verify CI passes
5. requesting-code-review → verify work meets requirements
6. finishing-a-development-branch → merge/PR/cleanup
1. systematic-debugging → diagnose root cause
2. test-driven-development → write test then fix
3. verification-before-completion → confirm fix
4. nix flake check
- Read AGENTS.md first — understand project structure, conventions, and available tools.
- Invoke relevant skills — if any skill might apply, invoke it before action.
- Brainstorm before doing — use the
brainstormingworkflow before writing code. - Follow existing patterns — look at neighboring files for conventions.
- Verify before asserting — run
nix flake checkbefore claiming completion. - Ask, don't assume — when unclear, ask the user rather than guessing.
- Commit when asked — only commit or create PRs when explicitly requested.
- Document decisions — save design specs to
docs/superpowers/specs/following the brainstorming skill process.