diff --git a/claude-code/README.md b/claude-code/README.md deleted file mode 100644 index 87ca28d..0000000 --- a/claude-code/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Srid's Claude Code Configuration - -## Nix module - -- `nix/home-manager-module.nix` - Home-manager module for auto-wiring this directory layout. - -### Usage - -Import the home-manager module and set `autoWire.dir`: - -```nix -{ - imports = [ ./claude-code/nix/home-manager-module.nix ]; - - programs.claude-code = { - enable = true; - autoWire.dir = ./claude-code; - }; -} -``` - diff --git a/claude-code/commands/hack.md b/claude-code/commands/hack.md deleted file mode 100644 index ada83fd..0000000 --- a/claude-code/commands/hack.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -name: hack -description: Implement a GitHub issue end-to-end until CI passes -args: - - name: issue_url - description: GitHub issue URL (e.g., https://github.com/user/repo/issues/123) - required: true - - name: plan_mode - description: Whether to run in plan mode (true/false, default false) - required: false ---- - -This command implements a GitHub issue from start to finish, ensuring all CI checks pass. - -**Usage**: `/hack [plan_mode]` - -**What it does**: -1. Fetches the GitHub issue details using `gh` CLI -2. Analyzes the issue requirements and creates an implementation plan -3. If plan_mode=true, presents plan for approval before implementing -4. Implements the requested feature or fix -5. Creates a commit with proper issue reference -6. Runs `om ci` to validate the implementation -7. Iterates and fixes any CI failures until all checks pass - -**Workflow**: -1. Parse the GitHub issue URL to extract repository and issue number -2. Use `gh api` to fetch issue title, description, and labels -3. Create a detailed implementation plan based on issue requirements -4. Implement the solution step by step -5. Commit changes with concise description -6. Run `om ci` and analyze any failures -7. Fix CI issues and re-run until all checks pass -8. Provide final status report - -**Prerequisites**: -- GitHub CLI (`gh`) must be authenticated -- Must be in a git repository with a non-mainline branch -- omnix (`om`) must be available for CI checks -- Repository must have CI configured via omnix - -**Error handling**: -- Validates GitHub URL format -- Handles GitHub API errors gracefully -- Provides detailed feedback on CI failures -- Supports iterative fixing until CI passes - -**Examples**: -``` -/hack https://github.com/myorg/myproject/issues/42 -/hack https://github.com/myorg/myproject/issues/42 true -``` - -First example directly implements issue #42. Second example creates a plan first and waits for approval before implementing. \ No newline at end of file diff --git a/claude-code/commands/pr.md b/claude-code/commands/pr.md deleted file mode 100644 index 0017672..0000000 --- a/claude-code/commands/pr.md +++ /dev/null @@ -1,65 +0,0 @@ -# PR Command - -Create and open a draft pull request on GitHub for the current branch. - -## Workflow - -1. **Gather Information** - - Get the current branch name using `git branch --show-current` - - Get the default branch (usually `main` or `master`) using `git remote show origin | grep 'HEAD branch'` - - Analyze the diff from the default branch to understand all changes (ignore individual commits) - - Review changed files to understand the scope of changes - -2. **Generate PR Content** - - Create a descriptive title that summarizes the changes - - Generate a comprehensive description with: - - A brief summary paragraph at the top - - **User-Facing Changes**: What end-users will notice or experience - - **Developer Notes**: Technical details, implementation notes, or items of interest to other developers - - Keep the description concise but informative - -3. **Get User Confirmation** - - Present the proposed PR title and description to the user - - Ask for confirmation or request modifications - - Allow the user to edit the title or description before proceeding - -4. **Create Draft PR** - - Once confirmed, use the `gh` CLI to create a draft PR: - ```bash - gh pr create --draft --title "TITLE" --body "DESCRIPTION" - ``` - - Report the PR URL to the user - -## Requirements - -- The `gh` CLI must be installed and authenticated (if not installed, use `nix run nixpkgs#gh` to run it) -- The repository must have a remote configured on GitHub -- The current branch must have commits that aren't in the default branch - -## Example Output Format - -```markdown -PR Title: Add new authentication system - -PR Description: -This PR introduces a modern OAuth-based authentication system alongside improved password management, enhancing both security and user experience. - -## User-Facing Changes - -- Users can now log in using OAuth providers (Google, GitHub) -- Improved password reset flow with better email notifications -- Session timeout increased from 1 hour to 24 hours - -## Developer Notes - -- Implemented OAuth2 client using the `oauth2-client` library -- Added new `AuthService` class to handle authentication logic -- Updated database schema with new `oauth_tokens` table -- Added comprehensive unit tests for authentication flows -``` - -## Notes - -- Always create as a **draft** PR initially so the user can make further changes if needed -- If the branch name follows a convention (e.g., `feature/`, `fix/`), incorporate that context into the title -- If there are uncommitted changes, warn the user before proceeding diff --git a/claude-code/mcp/chrome-devtools.nix b/claude-code/mcp/chrome-devtools.nix deleted file mode 100644 index 5e6ee8f..0000000 --- a/claude-code/mcp/chrome-devtools.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ - command = "npx"; - args = [ "chrome-devtools-mcp@latest" ]; -} diff --git a/claude-code/mcp/nixos-mcp.nix b/claude-code/mcp/nixos-mcp.nix deleted file mode 100644 index a8c2457..0000000 --- a/claude-code/mcp/nixos-mcp.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ - command = "uvx"; - args = [ "mcp-nixos" ]; -} diff --git a/claude-code/memory.md b/claude-code/memory.md deleted file mode 100644 index 7474f83..0000000 --- a/claude-code/memory.md +++ /dev/null @@ -1,12 +0,0 @@ -# System Instructions - -- Talk like a naive kid as much as possible -- Sacrifice grammar for brevity. -- Don't say "First, " say "Indeed, " -- Don't say "Good" or "Perfect" say "Great" - -# Tools - -- **gh**: If `gh` is unavailable, get it from nixpkgs, viz.: `nix run nixpkgs#gh`. -- **article-extractor**: To extract clean article content from URLs (blog posts, articles, tutorials), use the article-extractor skill. It removes ads, navigation, and clutter and saves readable text. - diff --git a/claude-code/nix/home-manager-module.nix b/claude-code/nix/home-manager-module.nix deleted file mode 100644 index ee4ee13..0000000 --- a/claude-code/nix/home-manager-module.nix +++ /dev/null @@ -1,124 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - cfg = config.programs.claude-code; - - # Auto-wire subagents from subagents/ directory - subagentsDir = cfg.autoWire.dir + "/subagents"; - autoAgents = lib.optionalAttrs (builtins.pathExists subagentsDir) - (lib.mapAttrs' - (fileName: _: - lib.nameValuePair - (lib.removeSuffix ".md" fileName) - (builtins.readFile (subagentsDir + "/${fileName}")) - ) - (builtins.readDir subagentsDir)); - - # Auto-wire commands from commands/ directory - commandsDir = cfg.autoWire.dir + "/commands"; - autoCommands = lib.optionalAttrs (builtins.pathExists commandsDir) - (lib.mapAttrs' - (fileName: _: - lib.nameValuePair - (lib.removeSuffix ".md" fileName) - (builtins.readFile (commandsDir + "/${fileName}")) - ) - (builtins.readDir commandsDir)); - - # Auto-wire skills from skills/ directory - skillsDir = cfg.autoWire.dir + "/skills"; - skillDirs = lib.optionalAttrs (builtins.pathExists skillsDir) - (lib.filterAttrs (_: type: type == "directory") (builtins.readDir skillsDir)); - - # Process skill: if it has default.nix, build and substitute; otherwise use as-is - processSkill = skillName: - let - skillPath = skillsDir + "/${skillName}"; - hasDefaultNix = builtins.pathExists (skillPath + "/default.nix"); - in - if hasDefaultNix then - let - skillPkg = pkgs.callPackage skillPath { }; - in - pkgs.runCommand "${skillName}-skill" { } '' - mkdir -p $out - substitute ${skillPath}/SKILL.md $out/SKILL.md \ - --replace-fail '@${skillName}@' '${skillPkg}/bin/${skillName}' - '' - else - skillPath; - - # Auto-wire MCP servers from mcp/ directory - mcpDir = cfg.autoWire.dir + "/mcp"; - autoMcpServers = lib.optionalAttrs (builtins.pathExists mcpDir) - (lib.mapAttrs' - (fileName: _: - lib.nameValuePair - (lib.removeSuffix ".nix" fileName) - (import (mcpDir + "/${fileName}")) - ) - (builtins.readDir mcpDir)); - - # Auto-load settings from settings.nix - settingsFile = cfg.autoWire.dir + "/settings.nix"; - autoSettings = lib.optionalAttrs (builtins.pathExists settingsFile) - (import settingsFile); - - # Auto-load memory from memory.md - memoryFile = cfg.autoWire.dir + "/memory.md"; - autoMemory = lib.optionalAttrs (builtins.pathExists memoryFile) - { text = builtins.readFile memoryFile; }; - -in -{ - options.programs.claude-code = { - autoWire = { - enable = lib.mkOption { - type = lib.types.bool; - default = true; - description = '' - Whether to automatically wire up subagents, commands, skills, and MCP servers from autoWire.dir. - Set to false if you want to manually configure these. - ''; - }; - - dir = lib.mkOption { - type = lib.types.nullOr lib.types.path; - default = null; - description = '' - Path to the claude-code directory containing subagents/, commands/, skills/, mcp/, settings.nix, and memory.md. - When set, these will be automatically discovered and configured. - ''; - }; - }; - }; - - config = lib.mkIf (cfg.enable && cfg.autoWire.dir != null && cfg.autoWire.enable) { - # Link skill directories to ~/.claude/skills/ - home.file = lib.mapAttrs' - (skillName: _: - lib.nameValuePair ".claude/skills/${skillName}" { - source = processSkill skillName; - recursive = true; - } - ) - skillDirs; - - programs.claude-code = { - # Auto-wire settings if settings.nix exists - settings = lib.mkDefault autoSettings; - - # Auto-wire memory if memory.md exists - memory = lib.mkDefault autoMemory; - - # Auto-wire commands from commands/ directory - commands = lib.mkDefault autoCommands; - - # Auto-wire agents from subagents/ directory - agents = lib.mkDefault autoAgents; - - # Auto-wire MCP servers from mcp/ directory - mcpServers = lib.mkDefault autoMcpServers; - }; - }; -} diff --git a/claude-code/settings.nix b/claude-code/settings.nix deleted file mode 100644 index 507e1ed..0000000 --- a/claude-code/settings.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ - # theme = "dark"; - permissions = { - defaultMode = "bypassPermissions"; - }; - # Disable Claude from adding itself as co-author to commits - includeCoAuthoredBy = false; -} diff --git a/claude-code/skills/article-extractor/SKILL.md b/claude-code/skills/article-extractor/SKILL.md deleted file mode 100644 index 7ad1f28..0000000 --- a/claude-code/skills/article-extractor/SKILL.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: article-extractor -description: Extract clean article content from URLs using reader. Use when user wants to download/extract/save an article from a URL. -allowed-tools: - - Bash - - Write ---- - -# Article Extractor - -Extracts clean article content from URLs using `reader` (Mozilla Readability). - -## When to Use - -User wants to: -- Extract article from URL -- Download blog post content -- Save article as text - -## Workflow - -Extract article content and save it: - -```bash -CONTENT=$(@article-extractor@ "$URL") -``` - -Then use the Write tool to save `$CONTENT` to the desired location with an appropriate filename. - -The script outputs clean markdown content to stdout. You decide where and how to save it based on the user's request. - diff --git a/claude-code/skills/article-extractor/default.nix b/claude-code/skills/article-extractor/default.nix deleted file mode 100644 index d9cf476..0000000 --- a/claude-code/skills/article-extractor/default.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ writeShellApplication, curl, reader }: - -writeShellApplication { - name = "article-extractor"; - - runtimeInputs = [ curl reader ]; - - text = '' - URL="$1" - - # Create unique temp file - TEMP_HTML=$(mktemp) - - # Download HTML - curl -s -L "$URL" > "$TEMP_HTML" - - # Extract and output article to stdout - reader "$TEMP_HTML" - - # Clean up - rm "$TEMP_HTML" - ''; -} diff --git a/claude-code/skills/haskell/SKILL.md b/claude-code/skills/haskell/SKILL.md deleted file mode 100644 index a1130ce..0000000 --- a/claude-code/skills/haskell/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -name: haskell -description: Expert Haskell development assistance. Use when working with Haskell code, .hs files, Cabal, ghcid, or when user mentions Haskell, functional programming, or type-level programming. ---- - -# Haskell Development - -Expert assistance for Haskell programming. - -## Guidelines - -**CRITICAL - Error Handling in Code**: NEVER write code that silently ignores errors: -- Do NOT use `undefined` or `error` as placeholders -- Do NOT skip handling error cases in pattern matches -- Do NOT ignore `Maybe`/`Either` failure cases -- Handle all possible cases explicitly -- Use types to make impossible states unrepresentable - -Every error case in generated code must be handled properly. - -**Code Quality**: -- Write type signatures for all top-level definitions -- Write total functions (avoid `head`, `tail`) -- Prefer pure functions over IO when possible -- Use explicit exports in modules -- Leverage type system for safety -- Favor composition over complex functions -- Write Haddock documentation for public APIs - -**Idiomatic Patterns**: -- Prefer `Text` over `String` -- Use `newtype` wrappers for domain types -- Apply smart constructors for validation -- Use RecordDotSyntax (`value.field`) instead of manually unpacking data types -- Use lenses for record manipulation when appropriate -- Use `Applicative` and `Monad` appropriately -- Avoid trivial `let` bindings when inlining keeps code simple and readable - -## HLint - -**IMPORTANT**: Always check if the project has a `.hlint.yaml` file. If it does: -1. Read the `.hlint.yaml` file to understand project-specific style rules -2. Follow all recommendations in that file when writing code -3. After making code changes, run `hlint` to ensure no warnings - -## Relude Best Practices - -When using relude prelude, follow these HLint recommendations (from https://github.com/kowainik/relude/blob/main/.hlint.yaml): - -**Basic Idioms**: -- Use `pass` instead of `pure ()` or `return ()` -- Use `one` instead of `(: [])`, `(:| [])`, or singleton functions -- Use `<<$>>` for double fmap: `f <<$>> x` instead of `fmap (fmap f) x` -- Use `??` (flap) operator: `ff ?? x` instead of `fmap ($ x) ff` - -**File I/O**: -- `readFileText`, `writeFileText`, `appendFileText` for Text files -- `readFileLText`, `writeFileLText`, `appendFileLText` for lazy Text -- `readFileBS`, `writeFileBS`, `appendFileBS` for ByteString -- `readFileLBS`, `writeFileLBS`, `appendFileLBS` for lazy ByteString - -**Console Output**: -- `putText`, `putTextLn` for Text -- `putLText`, `putLTextLn` for lazy Text -- `putBS`, `putBSLn` for ByteString -- `putLBS`, `putLBSLn` for lazy ByteString - -**Maybe/Either Helpers**: -- `whenJust m f` instead of `maybe pass f m` -- `whenJustM m f` for monadic versions -- `whenNothing_ m x` / `whenNothingM_ m x` for Nothing cases -- `whenLeft_ m f`, `whenRight_ m f` for Either -- `whenLeftM_ m f`, `whenRightM_ m f` for monadic Either -- `leftToMaybe`, `rightToMaybe` for conversions -- `maybeToRight l`, `maybeToLeft r` for conversions -- `isLeft`, `isRight` instead of `either (const True/False) (const False/True)` - -**List Operations**: -- Use `ordNub` instead of `nub` (O(n log n) vs O(n²)) -- Use `sortNub` instead of `Data.Set.toList . Data.Set.fromList` -- Use `sortWith f` instead of `sortBy (comparing f)` for simple cases -- Use `viaNonEmpty f x` instead of `fmap f (nonEmpty x)` -- Use `asumMap f xs` instead of `asum (map f xs)` -- Use `toList` instead of `foldr (:) []` - -**Monadic Operations**: -- `andM s` instead of `and <$> sequence s` -- `orM s` instead of `or <$> sequence s` -- `allM f s` instead of `and <$> mapM f s` -- `anyM f s` instead of `or <$> mapM f s` -- `guardM f` instead of `f >>= guard` -- `infinitely` instead of `forever` (better typed) -- `unlessM (not <$> x)` → use `whenM x` instead -- `whenM (not <$> x)` → use `unlessM x` instead - -**State/Reader Operations**: -- `usingReaderT` instead of `flip runReaderT` -- `usingStateT` instead of `flip runStateT` -- `evaluatingStateT s st` instead of `fst <$> usingStateT s st` -- `executingStateT s st` instead of `snd <$> usingStateT s st` - -**Transformer Lifting**: -- `hoistMaybe m` instead of `MaybeT (pure m)` -- `hoistEither m` instead of `ExceptT (pure m)` - -**List Pattern Matching**: -- `whenNotNull m f` for `case m of [] -> pass; (x:xs) -> f (x :| xs)` -- `whenNotNullM m f` for monadic version - -**Text/ByteString Conversions**: -- Use relude's `toText`, `toString`, `toLText` instead of pack/unpack -- Use relude's `encodeUtf8`, `decodeUtf8` for UTF-8 encoding -- `fromStrict`, `toStrict` for lazy/strict conversions - -## Testing - -- Use QuickCheck for property-based testing -- Use HUnit or Hspec for unit tests -- Provide good examples in documentation - -## Build instructions - -As you make code changes, start a subagent in parallel to resolve any compile errors in `ghcid.txt`. - -**IMPORTANT**: Do not run build commands yourself. The human runs ghcid in the terminal, which then updates `ghcid.txt` with any compile error or warning (if this file does not exist, or if ghcid has stopped, remind the human to address it). You should read `ghcid.txt` (in _entirety_) after making code changes; this file updates near-instantly. - -**Adding/Deleting modules**: When a new `.hs` file is added or deleted, the `.cabal` file must be updated accordingly. However, if `package.yaml` exists in the project, run `hpack` instead to regenerate the `.cabal` file with the updated module list. This will trigger `ghcid` to restart automatically. - -**HLint warnings**: Once all code changes are made and `ghcid.txt` shows success, check if the project has a `.hlint.yaml` file. If it does, run hlint to ensure there are no warnings and address any that appear. diff --git a/claude-code/skills/nix/SKILL.md b/claude-code/skills/nix/SKILL.md deleted file mode 100644 index ff02770..0000000 --- a/claude-code/skills/nix/SKILL.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: nix -description: Expert Nix development assistance. Use when working with Nix code, .nix files, flakes, NixOS configuration, or when user mentions Nix, flake-parts, nixpkgs. ---- - -# Nix Development - -## Guidelines - -- Use **flake-parts** when creating new flakes -- Format with **nixpkgs-fmt** after changes diff --git a/claude-code/subagents/pre-commit.md b/claude-code/subagents/pre-commit.md deleted file mode 100644 index b955600..0000000 --- a/claude-code/subagents/pre-commit.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: pre-commit -description: Invoke after changing sources locally, and only if git-hooks.nix is used by Nix. -tools: Bash ---- -# Pre-commit Quality Check Agent - -## Purpose -This agent runs `pre-commit run -a` to automatically check code quality and formatting when other agents modify files in the repository. - -## When to Use -- After any agent makes file modifications -- Before committing changes -- When code quality checks are needed - -## Tools Available -- Bash (for running pre-commit) -- Read (for checking file contents if needed) - -## Typical Workflow -1. Run `pre-commit run -a` to check all files -2. Report any issues found -3. Suggest fixes if pre-commit hooks fail -4. Re-run after fixes are applied - -## Example Usage -```bash -pre-commit run -a -``` - -This agent ensures code quality standards are maintained across the repository by leveraging the configured pre-commit hooks. \ No newline at end of file diff --git a/flake.lock b/flake.lock index 3f00797..a8f26e6 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,21 @@ { "nodes": { + "AI": { + "flake": false, + "locked": { + "lastModified": 1762823677, + "narHash": "sha256-tAFietBkeOYSUh+5KqZcfDA55L+A9IsPQZSuupNY+vM=", + "owner": "srid", + "repo": "AI", + "rev": "ba61df36131e5a9a7165c141e7e9ba18a56da324", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "AI", + "type": "github" + } + }, "agenix": { "inputs": { "darwin": "darwin", @@ -895,6 +911,7 @@ }, "root": { "inputs": { + "AI": "AI", "agenix": "agenix", "disko": "disko", "flake-parts": "flake-parts", diff --git a/flake.nix b/flake.nix index 0d1a5b7..20c2b0e 100644 --- a/flake.nix +++ b/flake.nix @@ -31,6 +31,8 @@ nix-ai-tools.url = "github:numtide/nix-ai-tools"; nix-ai-tools.inputs.nixpkgs.follows = "nixpkgs"; landrun-nix.url = "github:srid/landrun-nix"; + AI.url = "github:srid/AI"; + AI.flake = false; # Neovim nixvim.url = "github:nix-community/nixvim"; diff --git a/modules/flake-parts/nixos-flake.nix b/modules/flake-parts/nixos-flake.nix index 3967663..427b68c 100644 --- a/modules/flake-parts/nixos-flake.nix +++ b/modules/flake-parts/nixos-flake.nix @@ -17,6 +17,7 @@ "nix-index-database" "nixvim" "nix-ai-tools" + "AI" ]; }; }; diff --git a/modules/home/claude-code/default.nix b/modules/home/claude-code/default.nix index ae9c768..3df591d 100644 --- a/modules/home/claude-code/default.nix +++ b/modules/home/claude-code/default.nix @@ -1,8 +1,11 @@ { flake, pkgs, ... }: +let + inherit (flake.inputs) AI; +in { # Import the general home-manager module imports = [ - ../../../claude-code/nix/home-manager-module.nix + "${AI}/nix/home-manager-module.nix" ]; # Packages often used by Claude Code CLI @@ -20,6 +23,6 @@ else pkgs.claude-code; # Set the claude-code directory for auto-wiring - autoWire.dir = ../../../claude-code; + autoWire.dir = AI; }; }