SLOPSHOPPER

language-guard

Send back a final answer whose prose is English instead of Japanese

new
A shopper browsing a rack in a slop shop
README

kokatsu's dotfiles

CI NixOS Home Manager Checked with Biome

Dotfiles repository for managing shell and tool configurations across macOS and Linux systems using Nix + Home Manager with Flakes.

Features

  • ๐Ÿ”„ Declarative & Reproducible - All configurations managed through Nix Flakes
  • ๐Ÿ–ฅ๏ธ Multi-platform - Supports Linux (x86_64, aarch64) and macOS ARM (Apple Silicon)
  • ๐Ÿ“ฆ Unified Package Management - All CLI tools installed via Home Manager
  • ๐Ÿ”— Automated Symlinks - Dotfiles automatically linked to ~/.config/

Setup

Prerequisites

  • macOS (arm64) or Linux (x86_64 / aarch64)
  • curl (for Nix installer)

Installation

# Install Nix (using Determinate Systems installer)
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install

# Clone the repository
git clone https://github.com/kokatsu/dotfiles.git ~/dotfiles
cd ~/dotfiles

# Build and activate Home Manager configuration
DOTFILES_DIR="$PWD" nix run home-manager -- switch --flake . --impure

Usage

Apply Configuration Changes

# User environment (packages / dotfiles) on both Linux and macOS.
# Set this to the actual repository path on each PC.
DOTFILES_DIR="$HOME/dotfiles" home-manager switch --flake "$HOME/dotfiles" --impure

# macOS system settings + Homebrew (quit Chrome first: casks get upgraded in place)
sudo HOSTNAME=$(hostname -s) DOTFILES_DIR="$HOME/dotfiles" darwin-rebuild switch --flake "$HOME/dotfiles" --impure

Update Packages

nix flake update
DOTFILES_DIR="$HOME/dotfiles" home-manager switch --flake "$HOME/dotfiles" --impure

Development

nix develop        # Enter development shell with every linter / formatter
just check         # Format check, lint, typos, script tests, and flake evaluation
just fmt           # Format everything (Nix, Lua, shell, TOML, YAML, JSON, TypeScript)
just               # List all recipes

Lefthook runs a subset of these on commit and push (formatters, linters, gitleaks, commitlint); the script tests and flake evaluation only run through just check and CI.

Directory Structure

.
โ”œโ”€โ”€ flake.nix          # Flake outputs and Home Manager/nix-darwin builders
โ”œโ”€โ”€ flake.lock         # Locked dependencies for reproducibility
โ”œโ”€โ”€ justfile           # Task runner: checks, formatters, tests
โ”œโ”€โ”€ nix/
โ”‚   โ”œโ”€โ”€ home/          # Home Manager modules (packages, files, programs, services)
โ”‚   โ”œโ”€โ”€ darwin/        # macOS system and Homebrew configuration
โ”‚   โ””โ”€โ”€ overlays/      # Custom packages and upstream workarounds
โ”œโ”€โ”€ bin/               # User scripts, linked to ~/.local/bin/scripts and on PATH
โ”œโ”€โ”€ scripts/           # Test and helper scripts used by just and CI
โ”œโ”€โ”€ karabiner-config/  # Karabiner-Elements rules written with karabiner.ts
โ””โ”€โ”€ .config/           # Dotfile sources linked by Home Manager
    โ”œโ”€โ”€ zsh/           # Zsh shell configuration
    โ”œโ”€โ”€ nvim/          # Neovim configuration
    โ”œโ”€โ”€ wezterm/       # WezTerm terminal configuration
    โ”œโ”€โ”€ claude/        # Claude Code settings, hooks, and skills
    โ””โ”€โ”€ ...            # Other tool configurations

Static application settings live in nix/home/programs/. Home Manager generates Git, Ghostty, ripgrep, Starship, Yazi, Biome, markdown-oxide, ov, Taplo, psql, Vim, Claude Code keybindings, and the Codex base configuration from Nix. Edit these modules, then run home-manager switch --flake . --impure to apply them.

Yazi plugins come from nixpkgs yaziPlugins where available; the remaining plugins and flavors are vendored under .config/yazi/. All are installed through programs.yazi; update them via nix flake update or in Git instead of using ya pkg. Yazi's init.lua and git-changes.sh also need home-manager switch --flake . --impure after editing to apply the changes. Lua, shell scripts, and repository tooling configurations remain under .config/. Claude Code's settings.json keeps its writable repository link. Codex receives a writable copy of its generated configuration and preserves the existing local state sections during activation.

License

MIT. Third-party notices are listed in THIRD_PARTY_LICENSES.md.

Source 1 files
hooks/register.ts 38 lines
1import type { Register, SessionMessage } from "claude-code";
2
3const MIN_LATIN = 40;
4
5const ENGLISH_REQUEST =
6  /่‹ฑ่ชž(?:ใ ใ‘|ใฎใฟ)?ใง|่‹ฑ่จณ|่‹ฑๆ–‡|in English|English only/i;
7
8const REASON =
9  "ๆœฌๆ–‡ใŒ่‹ฑ่ชžใงใ™ใ€‚ๅŒใ˜ๅ†…ๅฎนใ‚’ๆ—ฅๆœฌ่ชžใงๆ›ธใ็›ดใ—ใฆใใ ใ•ใ„ (ใ‚ณใƒผใƒ‰ใƒป่ญ˜ๅˆฅๅญใƒปใ‚ณใƒŸใƒƒใƒˆใƒกใƒƒใ‚ปใƒผใ‚ธใฏๅŽŸๆ–‡ใฎใพใพ)ใ€‚";
10
11export function isUntranslated(text: string): boolean {
12  const prose = text
13    .replace(/(```|~~~)[\s\S]*?\1/g, "")
14    .replace(/`[^`\n]*`/g, "")
15    .replace(/https?:\/\/\S+/g, "");
16  if (/[\p{Script=Hiragana}\p{Script=Katakana}]/u.test(prose)) return false;
17  return (prose.match(/[A-Za-z]/g)?.length ?? 0) >= MIN_LATIN;
18}
19
20export function requestsEnglish(messages: readonly SessionMessage[]): boolean {
21  const prompt = messages.findLast((m) =>
22    m.role === "user" && !m.toolResults?.length && m.text !== ""
23  );
24  return ENGLISH_REQUEST.test(prompt?.text ?? "");
25}
26
27export const register: Register = (on) => {
28  on("classic.Stop", async ($, e, next) => {
29    if (
30      isUntranslated(e.last_assistant_message ?? "") &&
31      !requestsEnglish(await $.session.messages())
32    ) {
33      return { block: REASON };
34    }
35    return next(e);
36  }).catch((_$, e, next) => next(e));
37};
38