refactor: reorganize, add package (opencode, osgrep, beads), add ai agent shell

This commit is contained in:
Rasyidan Akbar F. 2025-12-09 15:09:05 +07:00
commit a0f0f39399
58 changed files with 7867 additions and 42 deletions

212
shells/README.md Normal file
View file

@ -0,0 +1,212 @@
# Development Shells
This directory contains modular Nix devShell configurations for various programming languages and use cases.
## Available Shells
> **Note:** When in the dotfiles directory, use `.#shell-name`. From other directories, use the full path `~/Development/dotfiles#shell-name`.
### `default`
Basic shell with git and nixfmt for dotfiles development.
```bash
nix develop # or: nix develop .#default
```
**Includes:**
- Git
- nixfmt-classic
- uv (for `uvx` commands)
**MCP helper:**
- `mcp-nixos` alias pins UV caches to `.cache/` so `uvx mcp-nixos` works without extra setup; useful before launching Codex.
### `python-uv`
Python development with UV package manager.
```bash
nix develop .#python-uv
```
**Includes:**
- Python 3.12
- UV (fast Python package manager)
- Ruff (linter/formatter)
- Pyright (type checker)
### `ai-notebook`
Notebook-focused ML/AI environment with HuggingFace tooling and JupyterLab.
```bash
nix develop .#ai-notebook
```
**Includes:**
- Python 3.12 with JupyterLab, NumPy/Pandas/SciPy stack
- HuggingFace `transformers`, `datasets`, `accelerate`, `tokenizers`
- Vision tooling: OpenCV, scikit-image, Pillow, albumentations, Altair/Plotly
- Optional CPU PyTorch (Linux hosts) plus torchvision/torchaudio
- UV, Ruff, Pyright, Git LFS
**HuggingFace caches:**
- Models: `~/.cache/huggingface/hub`
- Transformers: `~/.cache/huggingface/transformers`
**Example usage:**
```bash
# Launch JupyterLab with AI helpers
jupyter lab
# Download a model or dataset
huggingface-cli download meta-llama/Llama-3.2-1B
python -c "from datasets import load_dataset; load_dataset('ag_news')"
# Fine-tune with Accelerate
python -m accelerate.commands.launch train.py
```
### `go`
Go development environment.
```bash
nix develop .#go
```
**Includes:**
- Go compiler
- gopls (language server)
- golangci-lint
- delve (debugger)
### `web-bun`
Modern web development with Bun runtime.
```bash
nix develop .#web-bun
```
**Includes:**
- Bun
- Node.js 20
- Yarn
- esbuild
- vscode-langservers-extracted
### `rust`
Rust development environment.
```bash
nix develop .#rust
```
**Includes:**
- Cargo & rustc
- rust-analyzer
- rustfmt
- clippy
## Usage from Any Directory
### Option 1: Direct Path Reference
Use the full path to your dotfiles:
```bash
cd ~/my-project
nix develop ~/Development/dotfiles#ai-notebook
```
### Option 2: Flake Registry Alias (Recommended)
**One-time setup:**
```bash
nix registry add dotfiles ~/Development/dotfiles
# Verify it worked
nix registry list | grep dotfiles
```
**Then from anywhere:**
```bash
cd ~/any-project
nix develop dotfiles#ai-notebook
```
Benefits: Shorter commands, cleaner paths, easy to remember!
### Option 3: Auto-loading with direnv (Best for per-project)
**Recommended: Combine registry + direnv for cleanest setup:**
```bash
# One-time: Set up registry (if not done already)
nix registry add dotfiles ~/Development/dotfiles
# In each project:
cd ~/my-ml-project
echo "use flake dotfiles#ai-notebook" > .envrc
direnv allow
```
**Alternative: Without registry (using full path):**
```bash
cd ~/my-ml-project
echo "use flake ~/Development/dotfiles#ai-notebook" > .envrc
direnv allow
```
Now the shell automatically activates when you `cd` into that directory!
### Option 4: Project-specific flake.nix
Create a `flake.nix` in your project that imports the shell:
```nix
{
inputs = {
dotfiles.url = "path:/Users/rasyidanakbar/Development/dotfiles";
};
outputs = { self, dotfiles }:
let
system = "aarch64-darwin";
in {
devShells.${system}.default = dotfiles.devShells.${system}.ai-notebook;
};
}
```
Then simply:
```bash
cd ~/my-project
nix develop
```
### Quick Reference
| Method | Command | Pros |
|--------|---------|------|
| Direct path | `nix develop ~/Development/dotfiles#ai-notebook` | Simple, no setup |
| Registry | `nix develop dotfiles#ai-notebook` | Clean, short commands |
| direnv + registry | `echo "use flake dotfiles#ai-notebook" > .envrc` | Auto-loads, clean |
| Project flake | `nix develop` | Shareable, version-controlled |
## Adding New Shells
1. Create a new file in `devshells/` (e.g., `devshells/java.nix`)
2. Follow the pattern:
```nix
{ pkgs, ... }:
pkgs.mkShell {
name = "java";
packages = with pkgs; [ jdk maven ];
shellHook = ''
echo "Java development shell ready"
'';
}
```
3. Add it to `flake.nix` imports:
```nix
java = importShell "java";
```
4. Test: `nix flake check`

98
shells/ai-agent.nix Normal file
View file

@ -0,0 +1,98 @@
{ pkgs, lib, customPkgs, ... }:
let
# Get Beads package from custom packages
beadsPkg = customPkgs.beads;
# Helper script to show Beads project status
beadsStatus = pkgs.writeShellScriptBin "beads-status" ''
if [ ! -d ".beads" ]; then
echo "Not a Beads project (no .beads directory found)"
exit 1
fi
echo "=== Beads Project Status ==="
echo ""
echo "Ready tasks:"
${beadsPkg}/bin/bd ready --json | ${pkgs.jq}/bin/jq -r '.[] | " - [\(.id)] \(.title) (\(.type))"'
echo ""
echo "In Progress:"
${beadsPkg}/bin/bd list --status in-progress --json | ${pkgs.jq}/bin/jq -r '.[] | " - [\(.id)] \(.title)"'
echo ""
echo "For full details, run: bd list --json | jq"
'';
# Helper script to generate full project context for AI agents
beadsContext = pkgs.writeShellScriptBin "beads-context" ''
if [ ! -d ".beads" ]; then
echo "Not a Beads project (no .beads directory found)"
exit 1
fi
echo "=== Beads Project Context ==="
echo ""
echo "All issues:"
${beadsPkg}/bin/bd list --json | ${pkgs.jq}/bin/jq '.'
echo ""
echo "Dependency tree (first ready task):"
ready_id=$(${beadsPkg}/bin/bd ready --json | ${pkgs.jq}/bin/jq -r '.[0].id // empty')
if [ -n "$ready_id" ]; then
${beadsPkg}/bin/bd dep tree "$ready_id"
else
echo "No ready tasks"
fi
'';
in pkgs.mkShell {
name = "ai-agent";
packages = with pkgs; [
# Custom packages
customPkgs.beads
customPkgs.osgrep
# Version control
git
jujutsu
# Code search and navigation
ripgrep
ast-grep
fzf
# JSON processing
jq
# Helper scripts
beadsStatus
beadsContext
];
shellHook = ''
# Add home-manager binaries to PATH (claude-code, codex, etc.)
if [ -d "$HOME/.nix-profile/bin" ]; then
export PATH="$HOME/.nix-profile/bin:$PATH"
fi
echo "AI Agent development shell loaded"
echo ""
echo "Available tools:"
echo " bd - Beads CLI (issue tracker)"
echo " beads-status - Show project status summary"
echo " beads-context - Generate full context for AI"
echo " osgrep - Semantic code search"
echo " jj/git - Version control"
echo " rg/ast-grep - Code search"
echo ""
echo "Quick start:"
echo " bd init - Initialize Beads in current project"
echo " bd create - Create new issue"
echo " bd ready - Show ready tasks"
echo " bd --help - Full command reference"
echo ""
echo "Nushell helpers (if in nushell):"
echo " bd-init - Safe init with git checks"
echo " bd-ready - View ready tasks (structured)"
echo " bd-sync - Sync database with git"
'';
}

54
shells/ai-notebook.nix Normal file
View file

@ -0,0 +1,54 @@
{ pkgs, lib, python ? pkgs.python312, ... }:
let
pythonWithAI = python.withPackages (ps:
let
basePackages = with ps; [
accelerate
albumentations
altair
datasets
evaluate
huggingface-hub
ipykernel
jupyterlab
matplotlib
numpy
opencv4
pandas
pillow
plotly
scipy
scikit-image
scikit-learn
seaborn
sentencepiece
tokenizers
transformers
];
linuxOnlyPackages = lib.optionals pkgs.stdenv.isLinux
(with ps; [ torch torchaudio torchvision ]);
in basePackages ++ linuxOnlyPackages);
in pkgs.mkShell {
name = "ai-notebook";
packages = with pkgs; [ pythonWithAI uv git-lfs ruff pyright ];
shellHook = ''
export UV_PYTHON="${pythonWithAI}/bin/python3"
export UV_LINK_MODE=copy
export PYTHONNOUSERSITE=1
export HF_HOME="''${XDG_CACHE_HOME:-$HOME/.cache}/huggingface"
export HF_HUB_CACHE="$HF_HOME/hub"
export TRANSFORMERS_CACHE="$HF_HOME/transformers"
export JUPYTER_CONFIG_DIR="''${XDG_CONFIG_HOME:-$HOME/.config}/jupyter"
mkdir -p "$HF_HOME" "$JUPYTER_CONFIG_DIR"
echo "AI notebook shell ready"
echo "Python: ${python.version}"
echo "HuggingFace cache: $HF_HOME"
echo "Launch JupyterLab: jupyter lab"
echo "Launch classic notebook: jupyter notebook"
'';
}

120
shells/default.nix Normal file
View file

@ -0,0 +1,120 @@
{ pkgs, ... }:
let
# MCP wrapper script that ensures Python is available for GUI apps
mcpNixosWrapper = pkgs.writeShellScriptBin "mcp-nixos-wrapper" ''
export PATH="${pkgs.python3}/bin:${pkgs.uv}/bin:$PATH"
exec ${pkgs.uv}/bin/uvx mcp-nixos "$@"
'';
# Generate MCP configs for GUI applications
mcpConfigForGUI = pkgs.writeText "mcp_settings.json" (builtins.toJSON {
mcpServers = {
nixos = {
type = "stdio";
command = "${mcpNixosWrapper}/bin/mcp-nixos-wrapper";
args = [ ];
};
};
});
# Script to install MCP configs for Claude Code and Codex
installMcpConfigs = pkgs.writeShellScriptBin "install-mcp-configs" ''
set -e
echo "Installing MCP configurations..."
mkdir -p "$HOME/.config/claude-code"
mkdir -p "$HOME/.config/codex"
cp ${mcpConfigForGUI} "$HOME/.config/claude-code/mcp_settings.json"
cp ${mcpConfigForGUI} "$HOME/.config/codex/mcp_settings.json"
echo " Installed MCP config to ~/.config/claude-code/mcp_settings.json"
echo " Installed MCP config to ~/.config/codex/mcp_settings.json"
echo ""
echo "Restart Claude Code and Codex to apply changes."
'';
# Helper that builds the wrapped Neovim from the flake and runs it with repo-scoped XDG dirs
previewNvim = pkgs.writeShellScriptBin "preview-nvim" ''
set -euo pipefail
root="''${DOTFILES_ROOT:-$PWD}"
cache_base="$root/.cache"
nvim_cache="$cache_base/nvim-preview"
xdg_state="$cache_base/xdg-state"
xdg_data="$cache_base/xdg-data"
xdg_config="$root/modules/home/rsydn/programs"
mkdir -p "$nvim_cache" "$xdg_state" "$xdg_data"
attr="''${NVIM_ATTR:-}"
if [ "$#" -gt 0 ]; then
attr="$1"
shift
fi
if [ -z "$attr" ]; then
case "$(uname -s)" in
Darwin)
attr=".#darwinConfigurations.macbook-pro.config.home-manager.users.rasyidanakbar.programs.neovim.finalPackage"
;;
Linux)
attr=".#nixosConfigurations.dev-vm.config.home-manager.users.rasyidanakbar.programs.neovim.finalPackage"
;;
*)
echo "error: unsupported system; pass flake attribute as first argument or set NVIM_ATTR" >&2
exit 1
;;
esac
fi
out_link="$nvim_cache/result"
echo "Building Neovim package: $attr"
XDG_CACHE_HOME="$nvim_cache" nix build "$attr" --out-link "$out_link"
echo "Launching Neovim..."
XDG_CACHE_HOME="$nvim_cache" \
XDG_STATE_HOME="$xdg_state" \
XDG_DATA_HOME="$xdg_data" \
XDG_CONFIG_HOME="$xdg_config" \
NVIM_APPNAME="nvim" \
"$out_link/bin/nvim" "$@"
'';
in pkgs.mkShell {
name = "default";
packages = with pkgs; [
git
nix
nixfmt-classic
uv
python3
mcpNixosWrapper
installMcpConfigs
previewNvim
];
shellHook = ''
export DOTFILES_ROOT="$PWD"
export XDG_CACHE_HOME="$DOTFILES_ROOT/.cache"
export UV_CACHE_DIR="$XDG_CACHE_HOME/uv"
export UV_TOOL_HOME="$XDG_CACHE_HOME/uv-tools"
export XDG_DATA_HOME="$DOTFILES_ROOT/.cache/xdg-data"
export UV_PYTHON_DOWNLOADS=never
export MCP_CONFIG_PATH="$DOTFILES_ROOT/.mcp.json"
mkdir -p "$XDG_CACHE_HOME" "$UV_CACHE_DIR" "$UV_TOOL_HOME" "$XDG_DATA_HOME"
alias mcp-nixos='XDG_CACHE_HOME="$XDG_CACHE_HOME" XDG_DATA_HOME="$XDG_DATA_HOME" UV_CACHE_DIR="$UV_CACHE_DIR" UV_TOOL_HOME="$UV_TOOL_HOME" UV_PYTHON_DOWNLOADS="$UV_PYTHON_DOWNLOADS" uvx mcp-nixos'
echo "Loaded default shell for dotfiles development"
echo "MCP helper alias ready: mcp-nixos"
echo ""
echo "To install MCP configs for Claude Code and Codex, run:"
echo " install-mcp-configs"
echo ""
echo "To preview the Neovim config without switching, run:"
echo " preview-nvim [flakeAttr] [-- extra args]"
'';
}

13
shells/go.nix Normal file
View file

@ -0,0 +1,13 @@
{ pkgs, ... }:
pkgs.mkShell {
name = "go";
packages = with pkgs; [ go gopls golangci-lint delve git ];
shellHook = ''
mkdir -p "$PWD/.cache/go" "$PWD/.cache/gomod"
export GOPATH="$PWD/.cache/go"
export GOMODCACHE="$PWD/.cache/gomod"
echo "Go toolchain shell ready"
echo "Go: ${pkgs.go.version}"
'';
}

View file

@ -0,0 +1,31 @@
{ pkgs, python ? pkgs.python312, ... }:
let
# Python environment with notebook tooling and core data-science libs
pythonWithNotebook = python.withPackages (ps:
with ps; [
altair
ipykernel
jupyterlab
matplotlib
numpy
pandas
polars
plotly
scipy
scikit-learn
seaborn
]);
in pkgs.mkShell {
name = "jupyter-notebook";
packages = [ pythonWithNotebook pkgs.ruff pkgs.pyright pkgs.git ];
shellHook = ''
export PYTHONNOUSERSITE=1
export JUPYTER_CONFIG_DIR="''${XDG_CONFIG_HOME:-$HOME/.config}/jupyter"
mkdir -p "$JUPYTER_CONFIG_DIR"
echo "Jupyter notebook shell ready"
echo "Python: ${python.version}"
echo "Launch notebook: jupyter lab"
echo "Launch classic: jupyter notebook"
'';
}

12
shells/python-uv.nix Normal file
View file

@ -0,0 +1,12 @@
{ pkgs, python ? pkgs.python312, ... }:
pkgs.mkShell {
name = "python-uv";
packages = [ python pkgs.uv pkgs.ruff pkgs.pyright ];
shellHook = ''
export UV_PYTHON="${python}/bin/python3"
export UV_LINK_MODE=copy
echo "Python (uv) shell ready"
echo "Python: ${python.version}"
'';
}

12
shells/rust.nix Normal file
View file

@ -0,0 +1,12 @@
{ pkgs, ... }:
pkgs.mkShell {
name = "rust";
packages = with pkgs; [ cargo rustc rust-analyzer rustfmt clippy ];
shellHook = ''
mkdir -p "$PWD/.cache/cargo"
export CARGO_HOME="$PWD/.cache/cargo"
echo "Rust toolchain shell ready"
echo "Rust: ${pkgs.rustc.version}"
'';
}

21
shells/web-bun.nix Normal file
View file

@ -0,0 +1,21 @@
{ pkgs, ... }:
pkgs.mkShell {
name = "web-bun";
packages = with pkgs; [
bun
nodejs_20
yarn
esbuild
vscode-langservers-extracted
];
shellHook = ''
mkdir -p "$PWD/.cache/bun"
export BUN_INSTALL_CACHE="$PWD/.cache/bun"
ccusage() { bunx ccusage "$@"; }
export -f ccusage
echo "Bun/Node web shell ready"
echo "Bun: ${pkgs.bun.version}"
echo "Node: ${pkgs.nodejs_20.version}"
'';
}