diff --git a/AI/skills/haskell/RELUDE.md b/AI/skills/haskell/RELUDE.md deleted file mode 100644 index 7874890..0000000 --- a/AI/skills/haskell/RELUDE.md +++ /dev/null @@ -1,68 +0,0 @@ -# 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 diff --git a/AI/skills/haskell/SKILL.md b/AI/skills/haskell/SKILL.md deleted file mode 100644 index 9e32ceb..0000000 --- a/AI/skills/haskell/SKILL.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -name: haskell -description: Haskell coding with relude, ghcid-based workflow, hlint compliance, and strict error handling. Use when working with .hs files, Cabal projects, or ghcid. ---- - -# 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. - -**CRITICAL - Compile Status**: -- The code MUST compile without errors. -- You MUST check `ghcid.txt` after every change and fix any errors reported there. -- Do NOT proceed to verification or linting until `ghcid.txt` is clean. - -**CRITICAL - HLint Compliance**: -- You MUST check for `.hlint.yaml` in the project root. -- If it exists, you MUST run `hlint` on any file you modify. -- You MUST fix ALL hlint warnings before considering the task complete. -- Do NOT ignore hlint warnings unless explicitly instructed by the user. - -**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 -- Records: - - Use RecordDotSyntax & OverloadedRecordDot (add pragma to modules that use the syntax) - - Use DisambiguateRecordFields and DuplicateRecordFields for simple field names (add pragma to modules that use the syntax) -- Use lenses for record manipulation when appropriate -- Use `Applicative` and `Monad` appropriately -- Avoid trivial `let` bindings when inlining keeps code simple and readable - -**Working with Aeson**: -- NEVER construct aeson objects by hand -- Instead create a type and use `encode` and `decode` on it -- These types should generally use generic deriving of aeson (no hand deriving) - - -## Relude Best Practices - -When using `relude`, refer to [RELUDE.md](RELUDE.md) for best practices and idioms. - -## 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**: MANDATORY. After `ghcid.txt` shows success, if `.hlint.yaml` exists, run `hlint` on the modified files. You are NOT done until `hlint` reports no issues. diff --git a/AI/skills/optimize-nix/SKILL.md b/AI/skills/optimize-nix/SKILL.md deleted file mode 100644 index 8720da3..0000000 --- a/AI/skills/optimize-nix/SKILL.md +++ /dev/null @@ -1,220 +0,0 @@ ---- -name: optimize-nix -description: Optimize Nix flake evaluation and `nix develop` startup time. Use when the user wants to speed up nix develop, nix-shell, or flake evaluation. ---- - -# Nix Flake Evaluation Optimization - -Systematic approach to reducing `nix develop` startup time. - -## Workflow - -Iterative optimization loop. For each change: - -1. **Measure** baseline (5 samples, isolated `$HOME` to avoid cache interference) -2. **Change** one thing -3. **Measure** again -4. **Commit** with before/after measurements in the commit message -5. **Push** to the PR branch -6. **CI** after each significant change -7. Repeat - -### Setup - -Create a branch and open a **draft PR** before starting. Each optimization gets its own commit. - -### Measurement - -Use isolated `$HOME` so measurements don't destroy the developer's caches: - -```bash -for i in 1 2 3 4 5; do - rm -rf /tmp/nix-bench/home && mkdir -p /tmp/nix-bench/home - { time HOME=/tmp/nix-bench/home nix develop -c echo "s$i" 2>/dev/null; } 2>&1 | grep real -done -``` - -Also measure warm (daemon-cached) performance — just run without resetting `$HOME`: - -```bash -# warm up first -HOME=/tmp/nix-bench/home nix develop -c echo warmup 2>/dev/null -for i in 1 2 3; do - { time HOME=/tmp/nix-bench/home nix develop -c echo "s$i" 2>/dev/null; } 2>&1 | grep real -done -``` - -### Commit Format - -Use conventional commits. Include measurements in every commit body. - -## Where Time Goes - -`nix develop` time breaks down into: - -1. **Flake fetcher-cache verification** (~1.5s per input) — nix re-verifies each input on every cold invocation. This is the #1 bottleneck. -2. **Nixpkgs evaluation** (~0.2-0.5s) — importing the nixpkgs tree. -3. **Package resolution** (~0.5-1.5s) — resolving specific packages. -4. **Shell env realization** (~0.3-0.7s) — daemon overhead for building the shell derivation. - -### Key Insight - -With **zero flake inputs**, `nix develop` is fast: ~2.6s cold, ~0.3s warm (daemon eval cache). Each flake input adds ~1.5s. A typical flake with 4+ inputs (nixpkgs, flake-parts, git-hooks, systems) costs 7-18s. - -## The Fix: Zero-Input Flake - -**Import nixpkgs via `fetchTarball` instead of as a flake input.** This eliminates all fetcher-cache overhead while keeping `nix develop` as the interface. - -### Architecture - -``` -nix/nixpkgs.nix ← single nixpkgs pin (fetchTarball) -default.nix ← all packages + shared koluEnv -shell.nix ← devShell (imports default.nix, accepts { pkgs } arg) -flake.nix ← zero inputs, imports the above, exports packages + devShells -``` - -### Source management with npins - -Use [npins](https://github.com/andir/npins) to manage all fetched sources (nixpkgs, GitHub repos, etc.). This replaces hardcoded `fetchTarball`/`fetchFromGitHub` calls with a single `npins/sources.json`. - -```bash -npins init --bare -npins add github nixos nixpkgs --branch nixpkgs-unstable --at -npins add github owner repo --branch main --at -npins update # bump all sources -npins update nixpkgs # bump just nixpkgs -``` - -### `nix/nixpkgs.nix` — Single source of truth - -```nix -# Managed by npins. To update: npins update nixpkgs -let sources = import ../npins; -in import sources.nixpkgs -``` - -Other nix files can also use `sources`: - -```nix -# nix/some-dep/default.nix -{ pkgs }: -let sources = import ../../npins; -in pkgs.runCommand "foo" {} '' - cp -r ${sources.some-repo}/bar $out -'' -``` - -Note: npins handles GitHub repos and tarballs. Plain `fetchurl` (e.g. font files from CDNs) stays hardcoded. - -### `flake.nix` — Zero inputs - -```nix -# IMPORTANT: This flake intentionally has ZERO inputs. -# -# nixpkgs is imported via fetchTarball in nix/nixpkgs.nix, bypassing the -# flake input system. Each flake input adds ~1.5s of fetcher-cache -# verification. With zero inputs, `nix develop` cold is ~2.6s, warm ~0.3s. -# -# DO NOT add flake inputs (nixpkgs, flake-parts, git-hooks, etc.). -# Instead, use fetchTarball or callPackage in nix/ files. -{ - outputs = { self, ... }: - let - systems = [ "x86_64-linux" "aarch64-darwin" ]; - eachSystem = f: builtins.listToAttrs (map - (system: { - name = system; - value = f (import ./nix/nixpkgs.nix { inherit system; }); - }) - systems); - commitHash = self.shortRev or self.dirtyShortRev or "dev"; - in - { - packages = eachSystem (pkgs: - let all = import ./default.nix { inherit pkgs commitHash; }; - in removeAttrs all [ "koluEnv" ]); # koluEnv is not a derivation - devShells = eachSystem (pkgs: - { default = import ./shell.nix { inherit pkgs; }; }); - }; -} -``` - -### `shell.nix` — Shared devShell - -```nix -{ pkgs ? import ./nix/nixpkgs.nix { } }: -let packages = import ./default.nix { inherit pkgs; }; -in pkgs.mkShell { - name = "my-shell"; - # Use mkShell's env attr — no duplicate export lines - env = packages.koluEnv // { ... }; - shellHook = ''...''; - packages = with pkgs; [ ... ]; -} -``` - -### DRY shared env vars - -Define env vars once in `default.nix` as an attrset, use in both the build derivation's `env` and `mkShell`'s `env`: - -```nix -# In default.nix -koluEnv = { - KOLU_THEMES_JSON = "${ghosttyThemes}/themes.json"; - KOLU_FONTS_DIR = "${fonts}"; -}; - -kolu = pkgs.stdenv.mkDerivation { - env = { npm_config_nodedir = nodejs; } // koluEnv; - ... -}; -``` - -**Important:** `koluEnv` is not a derivation — filter it out of flake `packages` output with `removeAttrs` or devour-flake will fail trying to build it. - -### Replacements for common flake inputs - -- **flake-parts** → `eachSystem` helper (3 lines) -- **systems** → inline `[ "x86_64-linux" "aarch64-darwin" ]` -- **git-hooks.nix** → static `.pre-commit-config.yaml` + tools in devShell -- **process-compose-flake** → just's `[parallel]` attribute - -### `.envrc` - -``` -use flake -``` - -### justfile - -```just -nix_shell := if env('IN_NIX_SHELL', '') != '' { '' } else { 'nix develop path:' + justfile_directory() + ' -c' } -``` - -## Why Not nix-shell or env caching? - -We benchmarked all approaches with a zero-input flake: - -| Approach | Cold | Warm | -|---|---|---| -| `nix develop` (zero inputs) | **2.6s** | **0.3s** | -| `nix-shell` (fetchTarball) | 2.4s | 2.4s (no daemon cache) | -| env caching script | 5s miss | 0.014s hit | - -`nix develop` wins: 0.3s warm with zero maintenance. `nix-shell` has no daemon eval cache so it's always 2.4s. Env caching (nix-shell-fast) achieves 0.014s but introduces staleness bugs, manual cache key maintenance, and shellHook side-effects not re-running — complexity not worth the gain. - -## Pitfalls - -- **`nix flake lock` silently bumps inputs** — when removing inputs, nix may update remaining ones to latest. Always verify the nixpkgs rev matches master's. Run CI after any lock change. -- **`fetchTarball` sha256** — use SRI format (`sha256-...`). With npins, hashes are managed automatically. -- **npins `default.nix` is auto-generated** — don't edit it manually; `npins` overwrites it. Mark it in `.gitattributes` as `linguist-generated`. -- **Non-derivation in packages** — if `default.nix` exports non-derivations (like a `koluEnv` attrset), filter them out in `flake.nix` or devour-flake/`nix flake check` will fail. -- **direnv cache staleness** — after changing `nix/nixpkgs.nix`, delete `.direnv/` to force direnv re-evaluation. Otherwise `use flake` serves stale env vars. - -## Expected Results - -| | Cold eval cache | Warm (daemon cached) | -|---|---|---| -| Before (4+ inputs) | 7-18s | 3-7s | -| After (0 inputs) | ~2.6s | ~0.3s | diff --git a/AI/skills/technical-writer/SKILL.md b/AI/skills/technical-writer/SKILL.md deleted file mode 100644 index f10bd03..0000000 --- a/AI/skills/technical-writer/SKILL.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -name: technical-writer -description: Direct, no-nonsense technical writing. Use for blog posts, documentation, and READMEs. Eliminates AI-speak, hedging, and filler. ---- - -# Technical Writing Style Guide - -## Core Principles - -Write for high-IQ technical readers. Assume expertise. Remove hand-holding. - -## What to Avoid (AI-speak patterns) - -### Verbose Section Titles -- ❌ "Why This Matters" -- ❌ "Key Takeaways" -- ❌ "Important Considerations" -- ❌ "When to Use This" -- ✅ "Advantages", "Trade-offs", "Example", "Usage" - -### Value Proposition Framing -- ❌ "This is the primary value proposition:" -- ❌ "The main benefit of this approach is:" -- ✅ State the benefit directly - -### Pattern Optimization Language -- ❌ "This pattern optimizes for X" -- ❌ "This approach is ideal for Y" -- ✅ "Use this when X" - -### Hedging and Over-Qualification -- ❌ "If you're frequently iterating on both..." -- ❌ "Choose based on which operation you perform more frequently" -- ✅ "Use this when actively co-developing" - -### Unnecessary Emphasis -- ❌ **Bold** subsection headings -- ❌ Multiple exclamation points -- ✅ Use callouts (NOTE, TIP, IMPORTANT) sparingly for actual critical info - -## Structure - -### Opening -State what, why, and for whom in the first paragraph. No preamble. - -### Pattern/Implementation -Show code first. Minimal explanation. Assume readers can read code. - -### Technical Details -Link to official documentation. Use callouts for non-obvious gotchas. -- `[!NOTE]` for clarifications -- `[!TIP]` for advanced understanding -- `[!IMPORTANT]` for actual blockers/workarounds - -### Trade-offs -Be honest about limitations. Link to upstream issues. Don't sugarcoat. - -### Usage Guidance -Direct imperatives. "Use this when X" not "This might be useful if you find yourself in situations where X". - -## Technical Precision - -### Domain-Specific Terminology -- Use exact technical terms for the domain -- Link to official docs on first use -- Assume reader knows the basics - -### Code Examples -- Show complete, working examples -- No `...` placeholders or "existing code" comments -- Include all relevant flags/options - -### References Section -- Link to upstream documentation -- Link to relevant issues/discussions -- Link to working examples -- Keep descriptions minimal (one clause) - -## Iteration Notes - -When revising: -1. Remove all "This is because..." explanations unless non-obvious -2. Cut phrases like "as mentioned above", "as we saw earlier" -3. Remove transition sentences between sections -4. State facts directly - no "it's worth noting that" -5. Replace "you can" with imperative: "Run X" not "You can run X" - -## Example Transformations - -### Before (AI-speak) -> This pattern optimizes for active co-development. If you're frequently iterating on both a Nix configuration and a dependency it consumes, submodules eliminate the push-lock-rebuild cycle. Choose based on which operation you perform more frequently. - -### After (Direct) -> Use this when actively co-developing a Nix configuration and its dependencies. Submodules eliminate the push-lock-rebuild cycle. - ---- - -### Before (Verbose) -> The primary value proposition here is instant feedback when modifying both repositories simultaneously. - -### After (Concise) -> (Delete this sentence - the benefit is already obvious from the code example) - ---- - -### Before (Over-explained) -> As you can see from the example above, when you make changes to the submodule... - -### After (Direct) -> Changes to `vendor/AI/` are picked up immediately on rebuild.