This commit is contained in:
kiri committed 2026-09-22 21:44:35 +02:00
1 parent f164d8b76e
commit 5748b3409b
60 files changed
+1346 -590

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
# AI tools
Nix installs the tools, assets, skills and system Codex defaults. Codex owns its
writable user configuration; credentials, session history and other runtime state
remain outside this repository. `instructions/codex.md` owns global agent guidance.
Herdr is optional experimentation. Reload its managed configuration with
Ctrl+Alt+Shift+R (or Ctrl+B then Shift+R); its configuration owns the binding reference.
Home Manager may preserve an earlier regular configuration file with `.bak`.
Ollama supplies `nomic-embed-text` for grounded-docs. The latter runs on localhost
port 6280 with persistent Podman volumes. Removing another tool must not delete
these models or volumes. No mandatory agent persistence or orchestration workflow
is defined here.
@@ -1,6 +1,6 @@
{ pkgs }:
let
sources = import ./_sources.nix { inherit pkgs; };
sources = import ./sources.nix { inherit pkgs; };
context7Headers = pkgs.writeShellScript "context7-http-headers" ''
set -euo pipefail
CONTEXT7_KEY_FILE="''${XDG_CONFIG_HOME:-$HOME/.config}/context7/api-key"
@@ -26,7 +26,6 @@ in
inherit context7Headers codexHooks;
skills = {
context7-mcp = ../skills/context7-mcp;
# nixos-maintainer = ../skills/nixos-maintainer;
herdr = "${sources.herdr}/skills/herdr";
};
servers = {
+189
View File
@@ -0,0 +1,189 @@
{ inputs, config, ... }:
let
hmModules = config.flake.modules.homeManager;
nixosModules = config.flake.modules.nixos;
in
{
flake.modules.nixos.ai =
{ pkgs, ... }:
let
ai = import ./_support/assets.nix { inherit pkgs; };
codexConfig = (pkgs.formats.toml { }).generate "codex-config.toml" {
model = "gpt-5.6-sol";
model_reasoning_effort = "high";
plan_mode_reasoning_effort = "high";
service_tier = "default";
approvals_reviewer = "auto_review";
features.hooks = true;
tui = {
status_line = [
"model-with-reasoning"
"current-dir"
"context-remaining"
"five-hour-limit"
"weekly-limit"
"git-branch"
];
status_line_use_colors = true;
};
features.plugins = true;
hooks = ai.codexHooks;
mcp_servers = ai.servers // {
context7 = ai.servers.context7 // {
http_headers_helper = "${ai.context7Headers}";
};
nixos = ai.servers.nixos // {
startup_timeout_sec = 60.0;
tools.nix.approval_mode = "approve";
};
};
};
in
{
imports = [ nixosModules.podman ];
home-manager.sharedModules = [ hmModules.ai ];
environment.etc."codex/config.toml".source = codexConfig;
nixpkgs.overlays = [ inputs.llm-agents.overlays.shared-nixpkgs ];
nix.settings = {
extra-substituters = [ "https://cache.numtide.com" ];
extra-trusted-public-keys = [
"niks3.numtide.com-1:DTx8wZduET09hRmMtKdQDxNNthLQETkc/yaX7M4qK0g="
];
};
services.ollama = {
enable = true;
package = pkgs.ollama-vulkan;
loadModels = [ "nomic-embed-text" ];
};
};
flake.modules.homeManager.ai =
{ pkgs, lib, ... }:
let
ai = import ./_support/assets.nix { inherit pkgs; };
in
{
services.podman = {
volumes = {
grounded-docs-config = { };
grounded-docs-data = { };
};
containers.grounded-docs = {
image = "ghcr.io/arabold/docs-mcp-server:2.4.0";
network = "host";
volumes = [
"grounded-docs-config.volume:/config"
"grounded-docs-data.volume:/data"
];
environment = {
DOCS_MCP_APP_TELEMETRY_ENABLED = "false";
DOCS_MCP_EMBEDDING_MODEL = "openai:nomic-embed-text";
DOCS_MCP_EMBEDDINGS_VECTOR_DIMENSION = "768";
OPENAI_API_BASE = "http://127.0.0.1:11434/v1";
OPENAI_API_KEY = "ollama";
};
exec = "--protocol http --host 127.0.0.1 --port 6280";
};
};
home.packages = [
# Node-based Codex plugin hooks and skill scripts need node/npm outside project dev shells.
pkgs.nodejs
pkgs.python3
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex
pkgs.llm-agents.pi
pkgs.llm-agents.claude-code
pkgs.llm-agents.herdr
pkgs.ctx7
];
xdg.configFile."herdr/config.toml".text = ''
onboarding = false
[ui]
agent_panel_sort = "spaces"
prompt_new_tab_name = false
[ui.toast]
delivery = "off"
[keys]
# Super belongs to Niri; Ctrl navigation belongs to Neovim.
focus_pane_left = ["prefix+h", "ctrl+alt+h"]
focus_pane_down = ["prefix+j", "ctrl+alt+j"]
focus_pane_up = ["prefix+k", "ctrl+alt+k"]
focus_pane_right = ["prefix+l", "ctrl+alt+l"]
next_workspace = "ctrl+alt+u"
previous_workspace = "ctrl+alt+i"
navigate_workspace_down = "u"
navigate_workspace_up = "i"
workspace_picker = ["prefix+w", "ctrl+alt+o"]
goto = ["prefix+g", "ctrl+alt+g"]
previous_agent = "ctrl+alt+p"
next_agent = "ctrl+alt+n"
previous_tab = ["prefix+p", "ctrl+alt+["]
next_tab = ["prefix+n", "ctrl+alt+]"]
new_tab = ["prefix+c", "ctrl+alt+enter"]
split_vertical = ["prefix+v", "ctrl+alt+v"]
split_horizontal = ["prefix+minus", "ctrl+alt+minus"]
zoom = ["prefix+z", "ctrl+alt+f"]
detach = ["prefix+q", "ctrl+alt+q"]
swap_pane_left = ["prefix+shift+h", "ctrl+alt+shift+h"]
swap_pane_down = ["prefix+shift+j", "ctrl+alt+shift+j"]
swap_pane_up = ["prefix+shift+k", "ctrl+alt+shift+k"]
swap_pane_right = ["prefix+shift+l", "ctrl+alt+shift+l"]
resize_pane_left = "ctrl+alt+shift+left"
resize_pane_down = "ctrl+alt+shift+down"
resize_pane_up = "ctrl+alt+shift+up"
resize_pane_right = "ctrl+alt+shift+right"
resize_mode = ["prefix+r", "ctrl+alt+r"]
cycle_pane_next = ["prefix+tab", "ctrl+alt+tab"]
cycle_pane_previous = ["prefix+shift+tab", "ctrl+alt+shift+tab"]
last_pane = "ctrl+alt+backspace"
close_pane = ["prefix+x", "ctrl+alt+x"]
rename_pane = ["prefix+shift+p", "ctrl+alt+shift+p"]
copy_mode = ["prefix+[", "ctrl+alt+y"]
edit_scrollback = ["prefix+e", "ctrl+alt+e"]
close_tab = ["prefix+shift+x", "ctrl+alt+shift+x"]
rename_tab = ["prefix+shift+t", "ctrl+alt+shift+a"]
move_tab_previous = "ctrl+alt+shift+["
move_tab_next = "ctrl+alt+shift+]"
new_workspace = ["prefix+shift+n", "ctrl+alt+shift+enter"]
rename_workspace = ["prefix+shift+w", "ctrl+alt+shift+w"]
close_workspace = ["prefix+shift+d", "ctrl+alt+shift+d"]
open_worktree = "ctrl+alt+w"
new_worktree = ["prefix+shift+g", "ctrl+alt+shift+b"]
toggle_sidebar = ["prefix+b", "ctrl+alt+b"]
help = ["prefix+?", "ctrl+alt+slash"]
settings = ["prefix+s", "ctrl+alt+s"]
reload_config = ["prefix+shift+r", "ctrl+alt+shift+r"]
[[keys.command]]
key = "ctrl+alt+shift+g"
type = "popup"
command = "lazygit"
description = "Lazygit"
width = "90%"
height = "90%"
'';
# Codex owns its writable user config; Nix owns assets and system defaults.
home.file =
lib.mapAttrs' (
name: source: lib.nameValuePair ".agents/skills/${name}" { inherit source; }
) ai.skills
// {
".codex/AGENTS.md".text = builtins.readFile ./instructions/codex.md;
};
};
}
@@ -0,0 +1,56 @@
---
name: context7-mcp
description: This skill should be used when the user asks about libraries, frameworks, API references, or needs code examples. Activates for setup questions, code generation involving libraries, or mentions of specific frameworks like React, Vue, Next.js, Prisma, Supabase, etc.
---
When the user asks about libraries, frameworks, or needs code examples, use Context7 to fetch current documentation instead of relying on training data.
## When to Use This Skill
Activate this skill when the user:
- Asks setup or configuration questions ("How do I configure Next.js middleware?")
- Requests code involving libraries ("Write a Prisma query for...")
- Needs API references ("What are the Supabase auth methods?")
- Mentions specific frameworks (React, Vue, Svelte, Express, Tailwind, etc.)
## How to Fetch Documentation
### Step 1: Resolve the Library ID
Call `resolve-library-id` with:
- `libraryName`: The library name extracted from the user's question
- `query`: The user's full question (improves relevance ranking)
### Step 2: Select the Best Match
From the resolution results, choose based on:
- Exact or closest name match to what the user asked for
- Higher benchmark scores indicate better documentation quality
- If the user mentioned a version (e.g., "React 19"), prefer version-specific IDs
### Step 3: Fetch the Documentation
Call `query-docs` with:
- `libraryId`: The selected Context7 library ID (e.g., `/vercel/next.js`)
- `query`: The user's specific question, scoped to a single concept
If the user's question spans multiple distinct concepts (e.g. routing and auth and caching), make a separate `query-docs` call per concept with the same library ID, unless the question is about how the concepts interact — combined queries dilute ranking and return shallow results for each topic.
### Step 4: Use the Documentation
Incorporate the fetched documentation into your response:
- Answer the user's question using current, accurate information
- Include relevant code examples from the docs
- Cite the library version when relevant
## Guidelines
- **Be specific**: Pass the user's full question as the query for better results, but keep each query to a single concept
- **One topic per query**: Split multi-topic questions into separate `query-docs` calls — resolve the library ID once, then query per concept, unless the question is about how the concepts interact
- **Version awareness**: When users mention versions ("Next.js 15", "React 19"), use version-specific library IDs if available from the resolution step
- **Prefer official sources**: When multiple matches exist, prefer official/primary packages over community forks