Skip to content

Feat/declarative ssh agent - #417

Merged
shunkakinoki merged 31 commits into
mainfrom
feat/declarative-ssh-agent
Dec 13, 2025
Merged

Feat/declarative ssh agent#417
shunkakinoki merged 31 commits into
mainfrom
feat/declarative-ssh-agent

Conversation

@shunkakinoki

Copy link
Copy Markdown
Owner

No description provided.

shunkakinoki and others added 10 commits December 13, 2025 07:25
## Summary
Implement fully declarative SSH key management for kyber using keychain
and improve agenix secret deployment with automatic activation scripts.

## Changes

### SSH Agent Management
- Add keychain package for Linux systems
- Create `home-manager/services/ssh-agent.nix` module
- Configure keychain to automatically load SSH keys on login
- Use modern keychain flags (--confirm) to handle passphrase-protected keys

### Agenix Deployment
- Add activation scripts to ensure SSH directory exists
- Implement automatic decryption and deployment of GitHub SSH key
- Deploy secrets during home-manager activation if they don't exist

### Fish Shell Enhancements
- Add `_ssh_add_github` function for manual key loading
- Add `sag` abbreviation for quick GitHub key addition
- Initialize keychain in fish loginShellInit for automatic agent setup

### Documentation
- Expand kyber README with comprehensive SSH key management docs
- Add troubleshooting section for common issues
- Document passphrase-protected key handling

## Architecture

**Keychain Integration:**
- Automatically starts ssh-agent on first login
- Persists ssh-agent across shell sessions
- Gracefully handles passphrase-protected keys with --confirm flag

**Agenix Deployment:**
- Secrets are decrypted from galactica's encrypted store
- Deployed to ~/.ssh/id_ed25519_github with 0600 permissions
- Activation runs before home-manager linkGeneration phase

**GitOps Workflow:**
- All configuration is declarative in Nix
- SSH keys sync automatically from galactica via agenix
- `make switch` deploys everything without manual intervention

## Testing

Verified on kyber:
- keychain package installed
- SSH key decryption working
- Manual key addition via `sag` command
- Documentation complete

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Use ssh-add directly instead of eval'ing keychain output, since keychain
outputs bash syntax that fish can't parse. The function now:

1. Checks if ssh-agent is running
2. Starts ssh-agent if needed (using fish syntax)
3. Uses ssh-add directly to add the GitHub key
4. Prompts for passphrase if needed
5. Verifies and tests GitHub connection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Update grep pattern to check for both key filename and email address.
Also add fallback to test GitHub connection even if verification fails.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Update agenix configuration to sync ~/.ssh/id_github from galactica
instead of ~/.ssh/id_ed25519. The id_github key is the GitHub
CLI-authorized key with fingerprint SHA256:WA5wUwzlgMgujLm0U9gZBGTkGXiid5PfgDjMKJhHUis.

## Changes

- Update galactica/secrets.nix to encrypt id_github.age
- Update kyber/secrets.nix to reference id_github.age
- Update kyber/default.nix to decrypt id_github.age
- Keep deployment path as ~/.ssh/id_ed25519_github on kyber

## Next Steps on Galactica

1. Encrypt the correct key:
   cd ~/dotfiles
   make encrypt-key-galactica KEY_FILE=~/.ssh/id_github

2. Commit and push:
   git add named-hosts/galactica/keys/id_github.age
   git commit -m 'chore(agenix): encrypt GitHub SSH key (id_github)'
   git push

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Configure agenix to share GPG key between galactica and kyber,
enabling signed commits on kyber using the same GPG key.

## Changes

- Update galactica/secrets.nix: Share GPG key with allMachines
- Update kyber/secrets.nix: Add GPG key secret reference
- Add GPG import activation script on kyber
- Configure GPG and Git signing on kyber (matching galactica)
- Enable gpg-agent with same settings as galactica

## Features

- Automatic GPG key import on activation
- Git configured to sign commits by default
- GPG agent with 30min/2hr cache TTLs
- Idempotent: skips import if key already exists

## Next Steps on Galactica

Run: make rekey-galactica

This will re-encrypt gpg.age to include kyber's public key.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add programs.git.enable = true to ensure Git configuration
is applied by home-manager.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fix Git GPG signing configuration to use nested attribute sets
in extraConfig, matching home-manager expectations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Move GPG signing settings from kyber-specific config to the base
git configuration in home-manager/programs/git/default.nix.
This ensures the settings are properly applied.

Remove duplicate git.enable from kyber config since it's already
enabled in the base configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings December 13, 2025 08:02
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Dec 13, 2025

Copy link
Copy Markdown

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Added automatic SSH key management with keychain integration for Linux systems
    • Enabled automatic GitHub SSH key loading at shell startup
    • Added Git commit signing by default
    • Enabled GPG key management with automatic import and signing support
    • Enabled remote management access in configuration
  • Documentation

    • Updated SSH key management guide with enhanced setup instructions and troubleshooting steps
  • Improvements

    • Enhanced build system with automatic host detection for Linux deployments

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

This PR adds GitHub SSH key management with keychain integration, GPG signing support for Git commits, and refactors home-manager activation hook references across multiple modules. It also updates SSH key deployment in the Kyber host configuration and enables remote management for cliproxyapi.

Changes

Cohort / File(s) Summary
SSH Key Management & Keychain Integration
home-manager/packages/default.nix, home-manager/services/default.nix, home-manager/services/ssh-agent.nix
Adds keychain package for Linux; imports new sshAgent service; introduces SSH agent initialization module that sets up keychain for Linux with Fish shell login integration to load GitHub and default SSH keys.
Fish Shell SSH Functions
home-manager/programs/fish/default.nix, home-manager/programs/fish/functions/_ssh_add_github.fish
Adds sag shell abbreviation and _ssh_add_github function; new function handles GitHub SSH key addition via keychain with fallback mechanisms for ssh-agent, verification checks, and GitHub connectivity testing.
Kyber Host SSH & GPG Deployment
named-hosts/kyber/default.nix
Converts module to function-wrapped structure; adds activation hooks for SSH directory creation, agenix secret deployment (GitHub key), and GPG key import; configures GPG and gpg-agent with signing support; updates Fish interactiveShellInit for GPG_TTY.
Kyber & Galactica Secrets
named-hosts/galactica/secrets.nix, named-hosts/kyber/secrets.nix
Renames SSH key entry from id_ed25519 to id_github in both hosts; Galactica also expands GPG key sharing to allMachines; Kyber removes tailscale-auth entry and adds gpg.age with shared access.
Git Signing Configuration
home-manager/programs/git/default.nix
Removes unused pkgs argument; adds signing block with signByDefault = true and key = "shunkakinoki@gmail.com".
DAG Reference Refactoring
config/k3s/default.nix, home-manager/modules/npm-globals/default.nix, home-manager/modules/tailscale/default.nix, home-manager/modules/yek/default.nix, home-manager/programs/neovim/default.nix
Replaces lib.hm.dag.entryAfter references with config.lib.dag.entryAfter across 5 modules for consistent activation hook ordering.
Build & Configuration
Makefile, config/cliproxyapi/config.yaml
Makefile adds automatic Linux host detection and conditional flake check logic; cliproxyapi enables remote management access.
Kyber Documentation
named-hosts/kyber/README.md
Expands SSH key management workflow with automated setup details, multi-step procedures for Galactica and Kyber, manual key addition instructions, and improved troubleshooting guidance.

Sequence Diagram

sequenceDiagram
    participant User
    participant Fish as Fish Shell
    participant Agenix as Agenix
    participant FS as File System
    participant Keychain as Keychain
    participant SSHAgent as SSH-Agent
    participant GitHub as GitHub

    User->>Fish: nix flake switch / home-manager switch
    
    Note over FS: Activation Phase
    Agenix->>FS: Decrypt secrets (id_github.age)
    FS->>FS: Deploy ~/.ssh/id_ed25519_github (mode 0600)
    FS->>FS: Import GPG key from agenix

    Note over Fish: Login Shell Initialization
    Fish->>Keychain: Check keychain availability
    Keychain->>SSHAgent: Initialize/verify ssh-agent
    Fish->>Keychain: Load id_ed25519 if exists
    Fish->>Keychain: Load id_ed25519_github if exists
    Keychain->>SSHAgent: Store decrypted keys

    User->>Fish: sag (shell abbreviation)
    Fish->>Fish: Invoke _ssh_add_github function
    Fish->>FS: Verify ~/.ssh/id_ed25519_github exists
    Fish->>Keychain: Verify keychain available
    Fish->>Keychain: Initialize keychain for key
    Fish->>SSHAgent: Add key via ssh-add
    SSHAgent->>SSHAgent: Store GitHub key
    Fish->>SSHAgent: Verify key loaded (ssh-add -l)
    Fish->>GitHub: Test connection (ssh -T git@github.com)
    GitHub-->>Fish: Authentication success
    Fish-->>User: Key successfully loaded
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • kyber/default.nix requires careful review of the new function wrapper structure, multiple activation hooks, agenix secret deployment logic, and GPG/gpg-agent configuration interplay
  • _ssh_add_github.fish has multi-path error handling and fallback logic for ssh-agent initialization that needs verification
  • services/ssh-agent.nix introduces new Fish login shell initialization with keychain commands that must work correctly on Linux
  • DAG reference refactoring across 5 modules is repetitive but should be verified for consistency and correct API usage
  • Secrets migration (id_ed25519 → id_github) and GPG key sharing scope changes need validation

Possibly related PRs

  • feat(agenix): configure SSH key sync from galactica to kyber #412: Directly related; both modify SSH GitHub key deployment, home-manager configuration for secrets, kyber deployment paths, and Fish shell SSH helper and keychain integration
  • chore: update system #348: Related; both modify home-manager/packages/default.nix's Linux-specific package lists (adding Linux-only optional packages like keychain)
  • fix switch #404: Related; both modify Makefile's nix-switch logic to handle host detection and switching to homeConfigurations targets

Poem

🐰 A keychain unlocked, GitHub keys in hand,
SSH agents dance at our rabbit's command,
Fish shell abbreviations speed up the quest,
With GPG signatures signing our best,
SSH and keychain in harmony stand!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive No pull request description was provided by the author. Add a description explaining the purpose and scope of the SSH agent declarative configuration changes, including the key functionality being added.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feat/declarative ssh agent' accurately reflects the main objective of the changeset, which introduces declarative SSH agent configuration across multiple configuration files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/declarative-ssh-agent

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a7f9718 and 5ca4f57.

📒 Files selected for processing (8)
  • Makefile (3 hunks)
  • config/k3s/default.nix (1 hunks)
  • home-manager/modules/npm-globals/default.nix (1 hunks)
  • home-manager/modules/tailscale/default.nix (2 hunks)
  • home-manager/modules/yek/default.nix (1 hunks)
  • home-manager/programs/neovim/default.nix (1 hunks)
  • named-hosts/kyber/default.nix (1 hunks)
  • named-hosts/kyber/secrets.nix (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.nix

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.nix: Use nixfmt for formatting all Nix files
Document complex configurations with comments in Nix files

**/*.nix: Use 2 spaces for indentation in Nix files
Keep line length under 100 characters in Nix files
Sort attribute sets alphabetically in Nix files
Use consistent spacing around operators in Nix files
Format lists and sets consistently in Nix files

Use treefmt.toml for formatting Nix files

**/*.nix: Use mkOption for configurable options in Nix modules
Implement proper typing for all options in Nix modules
Follow the Nix expression language style guide

Files:

  • named-hosts/kyber/secrets.nix
  • home-manager/programs/neovim/default.nix
  • home-manager/modules/yek/default.nix
  • config/k3s/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
  • named-hosts/kyber/default.nix
**/default.nix

📄 CodeRabbit inference engine (CLAUDE.md)

Use default.nix files for module exports

Files:

  • home-manager/programs/neovim/default.nix
  • home-manager/modules/yek/default.nix
  • config/k3s/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
  • named-hosts/kyber/default.nix
home-manager/programs/*/default.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Program configurations should be located in home-manager/programs/<name>/ and use home-manager's built-in modules when available

Files:

  • home-manager/programs/neovim/default.nix
home-manager/programs/**/default.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Program configurations must include all necessary dependencies in their configuration

Files:

  • home-manager/programs/neovim/default.nix
home-manager/**/*.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

home-manager/**/*.nix: Use typed options whenever possible in Nix configurations
Document all configuration options in Nix modules and programs
Follow home-manager's module structure and keep configurations modular
Use proper indentation and formatting in Nix configuration files

Files:

  • home-manager/programs/neovim/default.nix
  • home-manager/modules/yek/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
home-manager/programs/**/*.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Follow program-specific best practices in program configuration files

Program configurations in home-manager/programs/ should be organized by program name, include all necessary dependencies, use home.packages for package installations, and use programs.<name> when available in home-manager

Files:

  • home-manager/programs/neovim/default.nix
home-manager/modules/*/default.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Custom modules must be located in home-manager/modules/<name>/ and must include a default.nix file

Files:

  • home-manager/modules/yek/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
home-manager/modules/**/default.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Custom modules should include proper option types and document all options

Each module in home-manager/modules/ should have a clear default.nix with proper option declarations following the home-manager module structure

Files:

  • home-manager/modules/yek/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
home-manager/modules/**/*.nix

📄 CodeRabbit inference engine (.cursor/rules/nix.mdc)

Document all custom modules and options

Files:

  • home-manager/modules/yek/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
🧠 Learnings (23)
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Document all major changes in Nix configurations

Applied to files:

  • Makefile
  • named-hosts/kyber/secrets.nix
  • home-manager/programs/neovim/default.nix
  • home-manager/modules/yek/default.nix
  • config/k3s/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Applies to flake.nix : Maintain flake.nix as the main Nix configuration with proper structure

Applied to files:

  • Makefile
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Test configurations before committing using `nix flake check` and `home-manager build --show-trace`

Applied to files:

  • Makefile
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Keep configurations modular across home-manager, hosts, and nix-darwin directories

Applied to files:

  • Makefile
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:47.854Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/github-workflows.mdc:0-0
Timestamp: 2025-11-25T09:34:47.854Z
Learning: Applies to .github/workflows/*.yml : CI Pipeline must run on all pull requests and main branch pushes, validating Nix flake checks, home-manager builds, nix-darwin builds, and system configurations

Applied to files:

  • Makefile
📚 Learning: 2025-11-25T09:34:23.224Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:34:23.224Z
Learning: Applies to nix-darwin/**/*.nix : Use Homebrew only for macOS-specific applications

Applied to files:

  • Makefile
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to flake.nix : Always pin package versions in `flake.lock`

Applied to files:

  • Makefile
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Test Nix and home-manager configurations locally before pushing using `make test`

Applied to files:

  • Makefile
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/**/*.nix : Follow program-specific best practices in program configuration files

Applied to files:

  • Makefile
  • home-manager/programs/neovim/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Follow home-manager's module structure and keep configurations modular

Applied to files:

  • Makefile
  • home-manager/programs/neovim/default.nix
  • home-manager/modules/yek/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/programs/**/*.nix : Program configurations in `home-manager/programs/` should be organized by program name, include all necessary dependencies, use `home.packages` for package installations, and use `programs.<name>` when available in home-manager

Applied to files:

  • Makefile
  • home-manager/programs/neovim/default.nix
  • home-manager/modules/npm-globals/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Use proper indentation and formatting in Nix configuration files

Applied to files:

  • home-manager/programs/neovim/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/**/default.nix : Program configurations must include all necessary dependencies in their configuration

Applied to files:

  • home-manager/programs/neovim/default.nix
  • home-manager/modules/npm-globals/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Document all configuration options in Nix modules and programs

Applied to files:

  • home-manager/programs/neovim/default.nix
  • home-manager/modules/tailscale/default.nix
  • home-manager/modules/npm-globals/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/*/default.nix : Program configurations should be located in `home-manager/programs/<name>/` and use home-manager's built-in modules when available

Applied to files:

  • home-manager/programs/neovim/default.nix
  • home-manager/modules/npm-globals/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:23.224Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:34:23.224Z
Learning: Applies to **/default.nix : Use `default.nix` files for module exports

Applied to files:

  • config/k3s/default.nix
  • home-manager/modules/npm-globals/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/services/**/default.nix : Service configurations must include proper service definitions, handle dependencies correctly, and document service parameters

Applied to files:

  • home-manager/modules/tailscale/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/services/*/default.nix : Service configurations should be located in `home-manager/services/<name>/` with proper service definitions and correct dependency handling

Applied to files:

  • home-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/services/**/*.nix : Service configurations in `home-manager/services/` should follow systemd service conventions, include proper service dependencies, and have clear documentation for service parameters

Applied to files:

  • home-manager/modules/tailscale/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/modules/**/*.nix : Document all custom modules and options

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/modules/**/default.nix : Each module in `home-manager/modules/` should have a clear `default.nix` with proper option declarations following the home-manager module structure

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/modules/**/default.nix : Custom modules should include proper option types and document all options

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/modules/*/default.nix : Custom modules must be located in `home-manager/modules/<name>/` and must include a `default.nix` file

Applied to files:

  • named-hosts/kyber/default.nix
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: docker-build-push (linux/arm64, arm64, ubuntu-24.04-arm)
  • GitHub Check: docker-build-push (linux/amd64, amd64, ubuntu-latest)
  • GitHub Check: e2e-run (NixOS, ubuntu-latest)
  • GitHub Check: e2e-run (Ubuntu, ubuntu-latest)
  • GitHub Check: e2e-run (MacOS, macos-latest)
  • GitHub Check: nix-nixos
  • GitHub Check: nix-linux
  • GitHub Check: nix-darwin
  • GitHub Check: auto-approve-check
  • GitHub Check: shellcheck
  • GitHub Check: lua-hammerspoon
  • GitHub Check: lua-neovim
  • GitHub Check: lua-neovim-test
  • GitHub Check: shellspec
🔇 Additional comments (15)
config/k3s/default.nix (1)

15-15: LGTM! Activation hook namespace updated correctly.

The change from lib.hm.dag.entryAfter to config.lib.dag.entryAfter aligns with the PR-wide standardization of activation hook references.

home-manager/modules/yek/default.nix (1)

91-91: LGTM! Activation hook reference updated.

Consistent with the PR-wide standardization to config.lib.dag.entryAfter.

home-manager/programs/neovim/default.nix (1)

25-25: LGTM! Activation hook reference updated.

Aligns with the PR-wide refactor to config.lib.dag.entryAfter.

home-manager/modules/npm-globals/default.nix (1)

9-9: LGTM! Activation hook reference updated.

Consistent with the PR-wide standardization effort.

home-manager/modules/tailscale/default.nix (1)

202-202: LGTM! Activation hook references updated.

Both activation blocks now use config.lib.dag.entryAfter, consistent with the PR-wide refactor.

Also applies to: 218-218

Makefile (3)

83-89: LGTM! Linux host auto-detection added.

The hostname-based detection for "kyber" mirrors the Darwin logic and enables automatic host configuration switching for Linux systems.


267-271: LGTM! OS-specific flake check logic added.

The conditional logic optimizes flake checks by using --all-systems on Darwin and --system $(NIX_SYSTEM) elsewhere, improving efficiency.


337-339: LGTM! Auto-detected host switching enabled for home configurations.

The DETECTED_HOST branch enables automatic home configuration activation for Linux systems, consistent with Darwin behavior.

named-hosts/kyber/secrets.nix (1)

24-28: LGTM! GPG key for commit signing added.

The new keys/gpg.age secret is properly configured with allMachines access, supporting the PR's goal of enabling GPG commit signing across hosts.

named-hosts/kyber/default.nix (6)

27-46: LGTM! Module wrapper and bash backup logic added.

The function wrapper correctly provides config and lib in scope, resolving previous evaluation errors. The bash file backup prevents home-manager conflicts during initial activation.


48-65: LGTM! Agenix configuration properly structured.

The identity paths and secrets mapping are correctly configured, with appropriate special handling for the GitHub SSH key deployment.


67-77: LGTM! Directory pre-creation ensures proper secret deployment.

The activation hooks correctly create necessary directories with proper permissions before agenix deployment, using the standardized config.lib.dag.entryBefore.


79-94: Manual secret deployment depends on filename resolution.

The activation script references ../galactica/keys/id_github.age, which must exist for successful deployment. Ensure the file mismatch noted in secrets.nix is resolved.

Verify that the secret file path aligns with the actual filename after resolving the id_github.age vs id_ed25519.age naming in named-hosts/kyber/secrets.nix and named-hosts/galactica/keys/.


122-145: LGTM! GPG configuration properly set up for commit signing.

The GPG and gpg-agent configurations are appropriate, and GPG_TTY is correctly set dynamically in the Fish shell initialization, addressing previous concerns.


147-162: LGTM! XDG and Tailscale configuration appropriate.

The XDG directories are enabled, and Tailscale is correctly configured for system-level service deployment on non-NixOS Linux.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @shunkakinoki, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a comprehensive declarative approach to managing SSH and GPG keys within the Nix Home Manager configuration. It streamlines the setup of ssh-agent for Linux using keychain, automates the deployment and loading of GitHub SSH keys, and integrates GPG for commit signing, ensuring a consistent and secure development environment across different machines.

Highlights

  • Declarative SSH Agent Setup: Introduces a new Home Manager service to declaratively configure ssh-agent using keychain for Linux systems, automating SSH key loading upon login.
  • GitHub SSH Key Management: Standardizes the deployment and loading of the GitHub SSH key (id_ed25519_github) across machines, including a new Fish function _ssh_add_github and alias sag for manual addition of passphrase-protected keys.
  • GPG Key Integration: Adds declarative configuration for GPG, enabling GPG commit signing in Git, and ensures the GPG key is synced and imported across machines.
  • Improved Secret Deployment: Enhances the agenix secret deployment process on Kyber by ensuring the .ssh directory exists and manually deploying SSH and GPG secrets during Home Manager activation, improving reliability.
  • Documentation Updates: The README.md for Kyber has been significantly updated to reflect the new SSH key management and GPG setup, including automated setup details, manual steps for passphrase-protected keys, and troubleshooting guidance.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@mesa-dot-dev

mesa-dot-dev Bot commented Dec 13, 2025

Copy link
Copy Markdown

You do not have enough credits to review this pull request. Please purchase more credits to continue.

@mesa-dot-dev

mesa-dot-dev Bot commented Dec 13, 2025

Copy link
Copy Markdown

Mesa Description

TL;DR

Implemented a declarative SSH and GPG key management system using keychain and agenix across hosts, automating key decryption and deployment, enabling default Git commit signing, and enhancing fish shell functions for key management. Remote management for cliproxyapi was also enabled.

What changed?

  • Makefile: Added host detection for "kyber" on Linux to apply Nix home configuration.
  • config/cliproxyapi/config.yaml: Enabled remote management by setting allow-remote to true.
  • home-manager/default.nix: Introduced a new Home Manager activation script to import a GPG secret key using rage and an SSH key.
  • home-manager/packages/default.nix: Added the keychain package.
  • home-manager/programs/fish/default.nix: Updated fish shell configuration to include _ssh_add_github function and sag alias.
  • home-manager/programs/fish/functions/_ssh_add_github.fish: Added a new fish function to automate adding the GitHub SSH key to ssh-agent.
  • home-manager/programs/git/default.nix: Removed pkgs argument, enabled default Git signing, and set the signing key.
  • home-manager/services/default.nix: Integrated a new sshAgent service by importing ssh-agent.nix.
  • home-manager/services/ssh-agent.nix: Added a new Home Manager service to configure keychain for ssh-agent on Linux, loading specific SSH keys.
  • named-hosts/galactica/secrets.nix: Renamed GitHub SSH key to id_github.age and broadened GPG key scope to allMachines.
  • named-hosts/kyber/README.md: Updated SSH key management documentation with details on agenix, keychain, and troubleshooting.
  • named-hosts/kyber/default.nix: Refactored home-manager module for kyber, updated age.secrets, added activation hooks for ~/.ssh and ~/.config/agenix, deployed GitHub SSH key, and added GPG support.
  • named-hosts/kyber/secrets.nix: Removed Tailscale auth key, clarified GitHub SSH key comment, and added a new GPG key secret.

Description generated by Mesa. Update settings

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a declarative SSH agent setup using keychain for Linux environments. It adds a new fish function _ssh_add_github to manually add a GitHub SSH key, and updates the Nix configuration to deploy SSH and GPG keys via agenix. The changes are mostly well-structured, but I've found a critical issue in the new fish function and some inconsistencies in the documentation. My review includes suggestions to fix the function's logic and update the documentation to match the code changes.

Comment on lines +14 to +26
# Initialize keychain and add the GitHub key
echo "🔑 Adding GitHub SSH key to keychain..."
# Use bash to evaluate keychain output, then use ssh-add
bash -c 'eval $(keychain --eval --quiet --confirm ~/.ssh/id_ed25519_github 2>/dev/null); ssh-add -l' >/dev/null 2>&1

# Alternative: directly use ssh-add if keychain already initialized ssh-agent
if not ssh-add -l >/dev/null 2>&1
# Start ssh-agent if not running
eval (ssh-agent -c)
end

# Add the key directly
ssh-add ~/.ssh/id_ed25519_github

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The logic for adding the SSH key is overly complex and contains a critical error. The command on line 17, bash -c 'eval $(keychain ...)', is incorrect for a fish shell. The environment variables set by eval will be scoped to the bash subshell and won't be available in the parent fish shell, making the command ineffective.

The subsequent logic (lines 20-26) correctly checks for and starts ssh-agent if needed, and then adds the key with ssh-add. This is a robust approach.

I suggest simplifying the script to remove the confusing and non-functional keychain call. The remaining logic is sufficient to add the key, prompting for a passphrase if necessary. While this makes the keychain availability check on line 9 redundant for this specific function, keychain is still used for agent initialization at login, so ssh-add should work correctly here.

    # Ensure ssh-agent is running. keychain should have started it on login,
    # but we can start it here as a fallback if needed.
    if not ssh-add -l >/dev/null 2>&1
        echo "ssh-agent not running. Starting it..."
        eval (ssh-agent -c)
    end

    # Add the key directly. This will prompt for a passphrase if there is one.
    echo "🔑 Adding GitHub SSH key to ssh-agent..."
    ssh-add ~/.ssh/id_ed25519_github


The GitHub SSH key will be automatically:

1. Decrypted from `named-hosts/galactica/keys/id_ed25519.age`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The secret file for the GitHub SSH key was renamed from id_ed25519.age to id_github.age in the Nix configurations, but this documentation still refers to the old name. Please update it to maintain consistency and avoid confusion.

Suggested change
1. Decrypted from `named-hosts/galactica/keys/id_ed25519.age`
1. Decrypted from `named-hosts/galactica/keys/id_github.age`


# Manually deploy if needed
age -d -i ~/.ssh/id_ed25519 -o ~/.ssh/id_ed25519_github \
named-hosts/galactica/keys/id_ed25519.age

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The secret file for the GitHub SSH key was renamed from id_ed25519.age to id_github.age in the Nix configurations, but this documentation still refers to the old name. Please update it to maintain consistency and avoid confusion.

Suggested change
named-hosts/galactica/keys/id_ed25519.age
named-hosts/galactica/keys/id_github.age

Comment thread named-hosts/kyber/default.nix Outdated
if [[ -f "$GPG_SECRET_FILE" ]]; then
echo "Importing GPG key from agenix..."
# Check if key is already imported
if ! ${pkgs.gnupg}/bin/gpg --list-secret-keys | grep -q "C2E97FCFF482925D"; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The GPG key ID C2E97FCFF482925D is hardcoded here. To improve readability and maintainability, consider defining it as a variable in the let block at the top of the file and referencing it here. This would make it easier to update if the key ever changes.

Use pinentry-curses instead of the default pinentry for kyber.
This allows GPG to prompt for passphrases in terminal environments.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (4)
named-hosts/kyber/default.nix (1)

105-136: GPG and Git signing configuration looks good.

The GPG agent, signing configuration, and Git integration are properly set up. Consider extracting the hardcoded key ID (C2E97FCFF482925D on line 92 and email on lines 109, 118) into a variable for maintainability, but this is optional for personal dotfiles.

home-manager/services/default.nix (1)

9-9: Inconsistent import pattern compared to other services.

The sshAgent import doesn't pass parameters, while all other service imports in this file use { inherit pkgs; }. Even though ssh-agent.nix is a home-manager module that receives { config, lib, pkgs, ... } from the module system, maintaining consistency with the established pattern in this file would improve code clarity.

Consider applying this diff for consistency:

- sshAgent = import ./ssh-agent.nix;
+ sshAgent = import ./ssh-agent.nix { inherit pkgs; };

Then update ssh-agent.nix to accept and ignore the parameter if needed, or restructure it as a service package similar to the others.

home-manager/services/ssh-agent.nix (1)

21-23: Clarify passphrase assumption for default key.

The comment states "no passphrase" for the default key, but there's no enforcement or verification of this assumption. If a user adds a passphrase to id_ed25519, the --confirm flag will skip it in non-interactive contexts, which may not be obvious.

Consider updating the comment to be more explicit:

-      # Always try to load the default key (no passphrase)
+      # Always try to load the default key (expected to have no passphrase)
+      # If this key requires a passphrase, it will be skipped by --confirm in non-interactive contexts
       if test -f ~/.ssh/id_ed25519
         set -a keys ~/.ssh/id_ed25519
       end
home-manager/programs/fish/functions/_ssh_add_github.fish (1)

3-6: Use $HOME instead of hardcoded ~/.ssh path for consistency.

While ~ typically expands in Fish, using $HOME is more explicit and consistent with Nix conventions.

-    if not test -f ~/.ssh/id_ed25519_github
-        echo "❌ GitHub SSH key not found at ~/.ssh/id_ed25519_github"
+    if not test -f $HOME/.ssh/id_ed25519_github
+        echo "❌ GitHub SSH key not found at $HOME/.ssh/id_ed25519_github"
         return 1
     end
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 05a2998 and 5f87a2f.

📒 Files selected for processing (9)
  • home-manager/packages/default.nix (1 hunks)
  • home-manager/programs/fish/default.nix (2 hunks)
  • home-manager/programs/fish/functions/_ssh_add_github.fish (1 hunks)
  • home-manager/services/default.nix (2 hunks)
  • home-manager/services/ssh-agent.nix (1 hunks)
  • named-hosts/galactica/secrets.nix (1 hunks)
  • named-hosts/kyber/README.md (2 hunks)
  • named-hosts/kyber/default.nix (2 hunks)
  • named-hosts/kyber/secrets.nix (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.nix

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.nix: Use nixfmt for formatting all Nix files
Document complex configurations with comments in Nix files

**/*.nix: Use 2 spaces for indentation in Nix files
Keep line length under 100 characters in Nix files
Sort attribute sets alphabetically in Nix files
Use consistent spacing around operators in Nix files
Format lists and sets consistently in Nix files

Use treefmt.toml for formatting Nix files

**/*.nix: Use mkOption for configurable options in Nix modules
Implement proper typing for all options in Nix modules
Follow the Nix expression language style guide

Files:

  • home-manager/services/ssh-agent.nix
  • named-hosts/galactica/secrets.nix
  • named-hosts/kyber/secrets.nix
  • home-manager/services/default.nix
  • home-manager/programs/fish/default.nix
  • named-hosts/kyber/default.nix
  • home-manager/packages/default.nix
home-manager/**/*.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

home-manager/**/*.nix: Use typed options whenever possible in Nix configurations
Document all configuration options in Nix modules and programs
Follow home-manager's module structure and keep configurations modular
Use proper indentation and formatting in Nix configuration files

Files:

  • home-manager/services/ssh-agent.nix
  • home-manager/services/default.nix
  • home-manager/programs/fish/default.nix
  • home-manager/packages/default.nix
home-manager/services/**/*.nix

📄 CodeRabbit inference engine (.cursor/rules/nix.mdc)

Service configurations in home-manager/services/ should follow systemd service conventions, include proper service dependencies, and have clear documentation for service parameters

Files:

  • home-manager/services/ssh-agent.nix
  • home-manager/services/default.nix
**/default.nix

📄 CodeRabbit inference engine (CLAUDE.md)

Use default.nix files for module exports

Files:

  • home-manager/services/default.nix
  • home-manager/programs/fish/default.nix
  • named-hosts/kyber/default.nix
  • home-manager/packages/default.nix
home-manager/services/**/default.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Service configurations must include proper service definitions, handle dependencies correctly, and document service parameters

Files:

  • home-manager/services/default.nix
home-manager/programs/*/default.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Program configurations should be located in home-manager/programs/<name>/ and use home-manager's built-in modules when available

Files:

  • home-manager/programs/fish/default.nix
home-manager/programs/**/default.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Program configurations must include all necessary dependencies in their configuration

Files:

  • home-manager/programs/fish/default.nix
home-manager/programs/**/*.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Follow program-specific best practices in program configuration files

Program configurations in home-manager/programs/ should be organized by program name, include all necessary dependencies, use home.packages for package installations, and use programs.<name> when available in home-manager

Files:

  • home-manager/programs/fish/default.nix
**/*.{js,jsx,ts,tsx,json,jsonc,md}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Use Biome for code formatting as configured in biome.json

Files:

  • named-hosts/kyber/README.md
🧠 Learnings (14)
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/**/*.nix : Follow program-specific best practices in program configuration files

Applied to files:

  • home-manager/services/ssh-agent.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Document all major changes in Nix configurations

Applied to files:

  • named-hosts/galactica/secrets.nix
  • named-hosts/kyber/default.nix
  • home-manager/packages/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/services/**/default.nix : Service configurations must include proper service definitions, handle dependencies correctly, and document service parameters

Applied to files:

  • home-manager/services/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/services/*/default.nix : Service configurations should be located in `home-manager/services/<name>/` with proper service definitions and correct dependency handling

Applied to files:

  • home-manager/services/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/services/**/*.nix : Service configurations in `home-manager/services/` should follow systemd service conventions, include proper service dependencies, and have clear documentation for service parameters

Applied to files:

  • home-manager/services/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:23.224Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:34:23.224Z
Learning: Applies to nix-darwin/**/*.nix : Use Homebrew only for macOS-specific applications

Applied to files:

  • home-manager/services/default.nix
📚 Learning: 2025-11-25T09:34:23.224Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:34:23.224Z
Learning: Prefer Nix packages over external package managers

Applied to files:

  • home-manager/services/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Follow home-manager's module structure and keep configurations modular

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Keep configurations modular across home-manager, hosts, and nix-darwin directories

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/programs/**/*.nix : Program configurations in `home-manager/programs/` should be organized by program name, include all necessary dependencies, use `home.packages` for package installations, and use `programs.<name>` when available in home-manager

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Document all configuration options in Nix modules and programs

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Test configurations before committing using `nix flake check` and `home-manager build --show-trace`

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/*/default.nix : Program configurations should be located in `home-manager/programs/<name>/` and use home-manager's built-in modules when available

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/**/default.nix : Program configurations must include all necessary dependencies in their configuration

Applied to files:

  • named-hosts/kyber/default.nix
  • home-manager/packages/default.nix
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Agent
  • GitHub Check: e2e-run (NixOS, ubuntu-latest)
  • GitHub Check: e2e-run (MacOS, macos-latest)
  • GitHub Check: e2e-run (Ubuntu, ubuntu-latest)
  • GitHub Check: docker-build-push (linux/arm64, arm64, ubuntu-24.04-arm)
  • GitHub Check: nix-linux
  • GitHub Check: docker-build-push (linux/amd64, amd64, ubuntu-latest)
  • GitHub Check: nix-nixos
  • GitHub Check: nix-darwin
  • GitHub Check: lua-neovim-test
  • GitHub Check: lua-neovim
  • GitHub Check: lua-hammerspoon
  • GitHub Check: shellspec
  • GitHub Check: shellcheck
🔇 Additional comments (7)
named-hosts/galactica/secrets.nix (1)

13-23: LGTM! Key management updates are well-documented.

The rename from id_ed25519.age to id_github.age improves clarity about the key's purpose, and broadening GPG key access to allMachines enables consistent commit signing across hosts. Comments accurately describe the changes. Based on learnings, documenting major changes in Nix configurations is followed here.

named-hosts/kyber/secrets.nix (1)

23-34: LGTM! Cross-host secret sharing is properly configured.

Referencing secrets from ../galactica/keys/ centralizes key management while allowing decryption on both machines via allMachines. The comments clearly explain the sync relationship.

home-manager/packages/default.nix (1)

89-89: LGTM! Keychain package added for Linux SSH management.

The addition of the keychain package to the Linux-specific package list aligns with the PR's objectives to introduce declarative SSH agent management using keychain on Linux systems.

home-manager/services/default.nix (1)

18-18: LGTM! Service integration added correctly.

The sshAgent service is properly included in the returned services list, enabling the SSH agent configuration for the system.

home-manager/programs/fish/default.nix (2)

52-52: LGTM! GitHub SSH key abbreviation added.

The sag abbreviation for _ssh_add_github follows the existing pattern and provides a convenient shorthand for adding the GitHub SSH key to the agent.


139-139: LGTM! Function registration added correctly.

The _ssh_add_github function is properly registered in the Fish functions list, enabling the function to be loaded and used in Fish shells.

home-manager/services/ssh-agent.nix (1)

13-39: Use config.home.homeDirectory instead of hardcoded ~/.ssh paths.

The hardcoded ~/.ssh paths may not expand properly in all contexts within Nix expressions. Using config.home.homeDirectory ensures consistent path resolution across different environments.

Apply this diff to use proper home directory interpolation:

       # Always try to load the default key (no passphrase)
-      if test -f ~/.ssh/id_ed25519
-        set -a keys ~/.ssh/id_ed25519
+      if test -f ${config.home.homeDirectory}/.ssh/id_ed25519
+        set -a keys ${config.home.homeDirectory}/.ssh/id_ed25519
       end

       # Load GitHub key if it exists (may have passphrase)
-      if test -f ~/.ssh/id_ed25519_github
-        set -a keys ~/.ssh/id_ed25519_github
+      if test -f ${config.home.homeDirectory}/.ssh/id_ed25519_github
+        set -a keys ${config.home.homeDirectory}/.ssh/id_ed25519_github
       end
⛔ Skipped due to learnings
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/**/*.nix : Follow program-specific best practices in program configuration files
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Keep configurations modular across home-manager, hosts, and nix-darwin directories
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Use proper indentation and formatting in Nix configuration files
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Follow home-manager's module structure and keep configurations modular
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/*/default.nix : Program configurations should be located in `home-manager/programs/<name>/` and use home-manager's built-in modules when available
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Use typed options whenever possible in Nix configurations
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/services/*/default.nix : Service configurations should be located in `home-manager/services/<name>/` with proper service definitions and correct dependency handling
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/programs/**/*.nix : Program configurations in `home-manager/programs/` should be organized by program name, include all necessary dependencies, use `home.packages` for package installations, and use `programs.<name>` when available in home-manager

Comment on lines +17 to +26
bash -c 'eval $(keychain --eval --quiet --confirm ~/.ssh/id_ed25519_github 2>/dev/null); ssh-add -l' >/dev/null 2>&1

# Alternative: directly use ssh-add if keychain already initialized ssh-agent
if not ssh-add -l >/dev/null 2>&1
# Start ssh-agent if not running
eval (ssh-agent -c)
end

# Add the key directly
ssh-add ~/.ssh/id_ed25519_github

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Simplify redundant SSH agent initialization flow.

The function has confusing redundant logic:

  1. Line 17 uses bash to evaluate keychain (then ignores the result)
  2. Lines 20-23 check and potentially start ssh-agent
  3. Line 26 directly adds the key

This creates unnecessary complexity. Since keychain is already initialized in loginShellInit (from ssh-agent.nix), the function should verify the agent is running and add the key only if not already present.

Apply this diff to simplify:

-    # Initialize keychain and add the GitHub key
-    echo "🔑 Adding GitHub SSH key to keychain..."
-    # Use bash to evaluate keychain output, then use ssh-add
-    bash -c 'eval $(keychain --eval --quiet --confirm ~/.ssh/id_ed25519_github 2>/dev/null); ssh-add -l' >/dev/null 2>&1
-
-    # Alternative: directly use ssh-add if keychain already initialized ssh-agent
+    # Check if ssh-agent is running (keychain should have started it)
     if not ssh-add -l >/dev/null 2>&1
-        # Start ssh-agent if not running
-        eval (ssh-agent -c)
+        echo "❌ ssh-agent not running. Run 'eval (keychain --eval)' first."
+        return 1
     end
 
+    # Check if key is already added
+    if ssh-add -l | grep -qE "(id_ed25519_github|shunkakinoki@gmail.com)"
+        echo "✅ GitHub SSH key already loaded"
+        return 0
+    end
+
+    # Add the key
+    echo "🔑 Adding GitHub SSH key..."
     ssh-add ~/.ssh/id_ed25519_github

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In home-manager/programs/fish/functions/_ssh_add_github.fish around lines 17 to
26, remove the redundant bash keychain eval and the manual ssh-agent startup;
instead simply check whether the github key is already loaded and, if not, call
ssh-add to add it. Implement this by running ssh-add -l and testing for the
presence of ~/.ssh/id_ed25519_github (or its key fingerprint/name) and only call
ssh-add ~/.ssh/id_ed25519_github when that check fails; do not attempt to start
ssh-agent or invoke keychain here since agent initialization is handled in
loginShellInit.

ssh-add ~/.ssh/id_ed25519_github

# Verify the key was added (check for either the filename or email)
if ssh-add -l | grep -qE "(id_ed25519_github|shunkakinoki@gmail.com)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n home-manager/programs/fish/functions/_ssh_add_github.fish | head -40

Repository: shunkakinoki/dotfiles

Length of output: 1797


🌐 Web query:

ssh-add -l output format what fields does it show

💡 Result:

ssh-add -l prints one line per identity with these fields:

  • bits — key size (e.g. 4096)
  • fingerprint — fingerprint of the public key (default SHA256:... unless changed with -E)
  • comment — free‑form comment (usually user@host or whatever was set in the pubkey); ssh-agent does not record the source filename.
  • algorithm — key type in parentheses (e.g. (RSA), (ED25519))

Example:
4096 SHA256:abc... user@host (RSA). (mankier.com)

Citations:


The grep pattern is ineffective; verification relies entirely on the hardcoded email.

The ssh-add -l command does not output the filename id_ed25519_github; it only shows the comment field (usually user@host format). This means the first pattern in the regex will never match. The verification succeeds only if the public key's comment is exactly shunkakinoki@gmail.com. If the key was generated with a different comment (e.g., shun@laptop or user@hostname), verification will fail despite the key being correctly added.

Either document that the key must be generated with this specific comment, or use a more robust check (e.g., verify by fingerprint or check ssh-add -L for the full key).

🤖 Prompt for AI Agents
In home-manager/programs/fish/functions/_ssh_add_github.fish around line 29, the
current grep against ssh-add -l relies on a filename that never appears and on a
hardcoded email comment; replace this with a robust check using ssh-add -L
(which prints the public keys) and match either the public key blob or the key
fingerprint (or both) instead of the comment alone, e.g., call ssh-keygen -lf on
each public key line from ssh-add -L to compare the expected fingerprint, or
grep the full public key string/comment from ssh-add -L; alternatively, if you
prefer keeping the simple approach, update the function comment to require
generating the key with the specific email and document that constraint.

Comment on lines +34 to +39
else
echo "⚠️ Could not verify key was added, but ssh-add may have succeeded"
echo "🧪 Testing GitHub connection anyway..."
ssh -T git@github.com
return $status
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fallback error handling could be more robust.

The fallback path (lines 34-39) returns the status of ssh -T git@github.com, but this command always exits with status 1 for successful authentication (GitHub's design). This makes the return value misleading.

Apply this diff to handle GitHub's authentication response correctly:

     else
         echo "⚠️  Could not verify key was added, but ssh-add may have succeeded"
         echo "🧪 Testing GitHub connection anyway..."
-        ssh -T git@github.com
-        return $status
+        # GitHub returns exit code 1 for successful auth with message
+        # "Hi username! You've successfully authenticated..."
+        if ssh -T git@github.com 2>&1 | grep -q "successfully authenticated"
+            return 0
+        else
+            return 1
+        end
     end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
else
echo "⚠️ Could not verify key was added, but ssh-add may have succeeded"
echo "🧪 Testing GitHub connection anyway..."
ssh -T git@github.com
return $status
end
else
echo "⚠️ Could not verify key was added, but ssh-add may have succeeded"
echo "🧪 Testing GitHub connection anyway..."
# GitHub returns exit code 1 for successful auth with message
# "Hi username! You've successfully authenticated..."
if ssh -T git@github.com 2>&1 | grep -q "successfully authenticated"
return 0
else
return 1
end
end

Comment on lines +34 to +35
# --confirm will skip keys that need a passphrase in non-interactive contexts
eval (keychain --eval --quiet --confirm $keys ^/dev/null; or true)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

keychain --confirm flag behavior non-interactive ssh passphrase

💡 Result:

Short answer: --confirm tells keychain to add keys with SSH confirmation enabled (ssh-add -c). That makes every use require an interactive confirmation via SSH_ASKPASS; in non‑interactive contexts (cron, CI, headless shells without SSH_ASKPASS) the key will either block waiting for confirmation or fail, so it is unsuitable for non‑interactive use. [1][2]

What to do

  • Remove --confirm when you need non‑interactive access (let keychain load keys normally). [1][2]
  • Or provide a working SSH_ASKPASS program and DISPLAY/X11 or an alternative GUI prompt so confirmations can succeed in your environment. [1][2]
  • Alternative: preload the key into an agent without -c (ssh-add without -c) or use OS keychain integration (macOS UseKeychain / ssh-add options) depending on platform. [2][3]

Sources

  1. keychain man page (--confirm description). [1]
  2. ssh-add man / docs describing -c (confirmation via SSH_ASKPASS) and effects on non‑interactive runs (quoted/summary). [2]
  3. Platform notes (macOS UseKeychain / ssh-add behavior) for alternatives. [3]

Remove --confirm flag or provide SSH_ASKPASS in non-interactive login contexts.

The --confirm flag makes ssh-add require interactive confirmation for every key usage via SSH_ASKPASS. In non-interactive contexts (headless servers, systemd services without a display), this will block or fail. The fallback or true won't prevent the blocking during evaluation. Either remove --confirm to allow normal key loading, or ensure SSH_ASKPASS and a display mechanism (DISPLAY/X11 or alternative GUI prompt) are available in this service environment.

🤖 Prompt for AI Agents
In home-manager/services/ssh-agent.nix around lines 34-35, remove the
problematic --confirm flag from the keychain invocation or ensure an
SSH_ASKPASS-based prompt is available in the service environment; specifically,
either drop --confirm so keys are loaded non-interactively (preventing blocking
in headless/systemd contexts), or set up and export SSH_ASKPASS and any required
DISPLAY/X11 or alternative GUI prompt before invoking keychain so confirmations
can be handled without a tty.

if test (count $keys) -gt 0
# Use --quiet to suppress most output, --eval to set environment variables
# --confirm will skip keys that need a passphrase in non-interactive contexts
eval (keychain --eval --quiet --confirm $keys ^/dev/null; or true)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Error suppression may hide legitimate keychain failures.

The ^/dev/null; or true pattern suppresses all errors from keychain, which could hide configuration problems or missing dependencies. While this prevents login shell interruption, it makes debugging difficult.

Consider logging suppressed errors to a file for debugging:

-        eval (keychain --eval --quiet --confirm $keys ^/dev/null; or true)
+        eval (keychain --eval --quiet --confirm $keys 2>>~/.keychain-errors.log; or true)

Or at minimum, document why errors are suppressed:

         # Use --quiet to suppress most output, --eval to set environment variables
-        # --confirm will skip keys that need a passphrase in non-interactive contexts
+        # --confirm will skip keys that need a passphrase in non-interactive contexts
+        # Errors are suppressed to prevent login shell failures if keychain has issues
         eval (keychain --eval --quiet --confirm $keys ^/dev/null; or true)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
eval (keychain --eval --quiet --confirm $keys ^/dev/null; or true)
# Use --quiet to suppress most output, --eval to set environment variables
# --confirm will skip keys that need a passphrase in non-interactive contexts
# Errors are suppressed to prevent login shell failures if keychain has issues
eval (keychain --eval --quiet --confirm $keys ^/dev/null; or true)
🤖 Prompt for AI Agents
In home-manager/services/ssh-agent.nix around line 35, the use of `^/dev/null;
or true` blindly suppresses keychain errors; replace this with a non-destructive
suppression that preserves diagnostics by redirecting keychain stderr to a log
file (e.g. append stderr to a designated log under /var/log or a user-specific
log) while allowing the shell to continue (use a safe `|| true` if necessary),
ensure the log directory/file exists and has appropriate permissions, and add a
brief comment explaining why errors are not fatal and where to find the logs for
debugging.

Comment thread named-hosts/kyber/default.nix Outdated
Comment thread named-hosts/kyber/default.nix Outdated
Comment on lines +71 to +101
# Manually deploy agenix secrets during activation
# This ensures secrets are deployed even if the agenix activation hook doesn't run properly
home.activation.deployAgenixSecrets = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
# Decrypt and deploy GitHub SSH key if it doesn't exist
if [[ ! -f "${config.home.homeDirectory}/.ssh/id_ed25519_github" ]]; then
echo "Deploying GitHub SSH key from agenix..."
SECRET_FILE="${builtins.toString ../galactica/keys/id_github.age}"
if [[ -f "$SECRET_FILE" ]]; then
$DRY_RUN_CMD ${pkgs.rage}/bin/rage -d -i ${config.home.homeDirectory}/.ssh/id_ed25519 "$SECRET_FILE" -o ${config.home.homeDirectory}/.ssh/id_ed25519_github
$DRY_RUN_CMD chmod $VERBOSE_ARG 0600 ${config.home.homeDirectory}/.ssh/id_ed25519_github
echo "✅ GitHub SSH key deployed successfully"
else
echo "⚠️ Warning: Secret file not found at $SECRET_FILE"
fi
fi

# Decrypt and import GPG key for commit signing
GPG_SECRET_FILE="${builtins.toString ../galactica/keys/gpg.age}"
if [[ -f "$GPG_SECRET_FILE" ]]; then
echo "Importing GPG key from agenix..."
# Check if key is already imported
if ! ${pkgs.gnupg}/bin/gpg --list-secret-keys | grep -q "C2E97FCFF482925D"; then
$DRY_RUN_CMD ${pkgs.rage}/bin/rage -d -i ${config.home.homeDirectory}/.ssh/id_ed25519 "$GPG_SECRET_FILE" | ${pkgs.gnupg}/bin/gpg --batch --import
echo "✅ GPG key imported successfully"
else
echo "ℹ️ GPG key already imported"
fi
else
echo "⚠️ Warning: GPG secret file not found at $GPG_SECRET_FILE"
fi
'';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Same config scope issue in deployment script.

This activation script also references config.home.homeDirectory which is undefined. Apply the same fix—either add config to module arguments or use /home/${username}.

       home.activation.deployAgenixSecrets = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
         # Decrypt and deploy GitHub SSH key if it doesn't exist
-        if [[ ! -f "${config.home.homeDirectory}/.ssh/id_ed25519_github" ]]; then
+        if [[ ! -f "/home/${username}/.ssh/id_ed25519_github" ]]; then
           echo "Deploying GitHub SSH key from agenix..."
           SECRET_FILE="${builtins.toString ../galactica/keys/id_github.age}"
           if [[ -f "$SECRET_FILE" ]]; then
-            $DRY_RUN_CMD ${pkgs.rage}/bin/rage -d -i ${config.home.homeDirectory}/.ssh/id_ed25519 "$SECRET_FILE" -o ${config.home.homeDirectory}/.ssh/id_ed25519_github
-            $DRY_RUN_CMD chmod $VERBOSE_ARG 0600 ${config.home.homeDirectory}/.ssh/id_ed25519_github
+            $DRY_RUN_CMD ${pkgs.rage}/bin/rage -d -i /home/${username}/.ssh/id_ed25519 "$SECRET_FILE" -o /home/${username}/.ssh/id_ed25519_github
+            $DRY_RUN_CMD chmod $VERBOSE_ARG 0600 /home/${username}/.ssh/id_ed25519_github

Apply similar changes for the GPG section (lines 87-100).

Committable suggestion skipped: line range outside the PR's diff.

Comment thread named-hosts/kyber/default.nix Outdated
Comment on lines +83 to +88
The GitHub SSH key will be automatically:

1. Decrypted from `named-hosts/galactica/keys/id_ed25519.age`
2. Deployed to `~/.ssh/id_ed25519_github`
3. Loaded into ssh-agent via keychain (if no passphrase)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Documentation references outdated filename.

Line 85 references id_ed25519.age but the secrets configuration uses id_github.age. Update to match the actual filename.

 The GitHub SSH key will be automatically:

-1. Decrypted from `named-hosts/galactica/keys/id_ed25519.age`
+1. Decrypted from `named-hosts/galactica/keys/id_github.age`
 2. Deployed to `~/.ssh/id_ed25519_github`
 3. Loaded into ssh-agent via keychain (if no passphrase)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
The GitHub SSH key will be automatically:
1. Decrypted from `named-hosts/galactica/keys/id_ed25519.age`
2. Deployed to `~/.ssh/id_ed25519_github`
3. Loaded into ssh-agent via keychain (if no passphrase)
The GitHub SSH key will be automatically:
1. Decrypted from `named-hosts/galactica/keys/id_github.age`
2. Deployed to `~/.ssh/id_ed25519_github`
3. Loaded into ssh-agent via keychain (if no passphrase)
🤖 Prompt for AI Agents
In named-hosts/kyber/README.md around lines 83 to 88, the documentation
references the outdated filename id_ed25519.age; update that line to the actual
secret filename id_github.age so the steps reflect the secrets configuration
(i.e., decrypt from named-hosts/galactica/keys/id_github.age, then deploy/load
as described).

Comment on lines +115 to +118
# Manually deploy if needed
age -d -i ~/.ssh/id_ed25519 -o ~/.ssh/id_ed25519_github \
named-hosts/galactica/keys/id_ed25519.age
chmod 0600 ~/.ssh/id_ed25519_github

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Troubleshooting command uses wrong filename.

The manual decrypt command references id_ed25519.age instead of id_github.age.

 # Manually deploy if needed
 age -d -i ~/.ssh/id_ed25519 -o ~/.ssh/id_ed25519_github \
-  named-hosts/galactica/keys/id_ed25519.age
+  named-hosts/galactica/keys/id_github.age
 chmod 0600 ~/.ssh/id_ed25519_github
🤖 Prompt for AI Agents
In named-hosts/kyber/README.md around lines 115 to 118, the manual decrypt
command references the wrong filename (id_ed25519.age) — it should reference
id_github.age; update the age command to use the correct encrypted file path
(named-hosts/galactica/keys/id_github.age) so the correct key is decrypted, and
keep the subsequent chmod step unchanged.

shunkakinoki and others added 3 commits December 13, 2025 08:07
Disable signByDefault to avoid GPG agent issues in server environments.
The GPG key is still synced and configured - users can enable signing
with: git config --global commit.gpgsign true

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements declarative SSH agent management using keychain and agenix for automated SSH key deployment. The changes enable automatic deployment and loading of SSH keys (specifically GitHub authentication keys) across machines, along with GPG key setup for commit signing. The implementation renames the SSH key from id_ed25519.age to id_github.age to better reflect its purpose and adds comprehensive documentation for key management workflows.

Key changes:

  • Automated SSH key deployment via agenix during home-manager activation
  • Linux SSH agent management using keychain with automatic key loading
  • GPG key deployment and configuration for commit signing
  • Helper Fish function for manual GitHub SSH key addition

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
named-hosts/kyber/secrets.nix Renames SSH key reference from id_ed25519.age to id_github.age and adds GPG key secret configuration
named-hosts/kyber/default.nix Adds activation hooks for SSH directory creation and secret deployment, configures GPG and Git signing, adds GPG agent service
named-hosts/kyber/README.md Expands documentation with automated setup details, troubleshooting steps, and key management workflows
named-hosts/galactica/secrets.nix Updates secret references from id_ed25519.age to id_github.age and shares GPG key across all machines
named-hosts/galactica/keys/gpg.age Adds encrypted GPG key file for commit signing
home-manager/services/ssh-agent.nix Implements keychain-based SSH agent management for Linux with automatic key loading
home-manager/services/default.nix Registers new ssh-agent service module
home-manager/programs/fish/functions/_ssh_add_github.fish Adds Fish function for manually adding GitHub SSH key to ssh-agent
home-manager/programs/fish/default.nix Registers sag abbreviation for GitHub SSH key function
home-manager/packages/default.nix Adds keychain package dependency
Comments suppressed due to low confidence (1)

named-hosts/kyber/default.nix:140

  • The GPG_TTY environment variable is set to a literal string "$(tty)" instead of being evaluated. This should use a shell initialization hook or be set in a way that evaluates the command at runtime, not at build time. Consider moving this to a shell init script where it can be properly evaluated.
          "--accept-dns=false"
        ];

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread named-hosts/kyber/secrets.nix Outdated
file = ../galactica/keys/id_ed25519.age;
# This is the id_github key from galactica, which is the GitHub-authorized key
"keys/id_github.age" = {
file = ../galactica/keys/id_github.age;

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code references id_github.age but the actual file in the repository is id_ed25519.age. This mismatch will cause the secret deployment to fail at runtime. Either rename the actual file to id_github.age or update the code to reference the correct filename id_ed25519.age.

Suggested change
file = ../galactica/keys/id_github.age;
file = ../galactica/keys/id_ed25519.age;

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +16
"keys/id_github.age" = {
file = ./keys/id_github.age;

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code references id_github.age but the actual file in the repository is id_ed25519.age. This mismatch will cause the secret deployment to fail. Either rename the actual file to id_github.age or update the code to reference the correct filename id_ed25519.age.

Suggested change
"keys/id_github.age" = {
file = ./keys/id_github.age;
"keys/id_ed25519.age" = {
file = ./keys/id_ed25519.age;

Copilot uses AI. Check for mistakes.

The GitHub SSH key will be automatically:

1. Decrypted from `named-hosts/galactica/keys/id_ed25519.age`

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation references id_ed25519.age but the code has been updated to use id_github.age. This inconsistency will confuse users trying to follow the manual deployment instructions. Update this line to reference id_github.age to match the code changes.

Suggested change
1. Decrypted from `named-hosts/galactica/keys/id_ed25519.age`
1. Decrypted from `named-hosts/galactica/keys/id_github.age`

Copilot uses AI. Check for mistakes.
Comment thread named-hosts/kyber/default.nix Outdated
echo "Importing GPG key from agenix..."
# Check if key is already imported
if ! ${pkgs.gnupg}/bin/gpg --list-secret-keys | grep -q "C2E97FCFF482925D"; then
$DRY_RUN_CMD ${pkgs.rage}/bin/rage -d -i ${config.home.homeDirectory}/.ssh/id_ed25519 "$GPG_SECRET_FILE" | ${pkgs.gnupg}/bin/gpg --batch --import

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GPG key import command doesn't respect the DRY_RUN_CMD variable, which means it will always execute even during dry-run mode. This could cause unintended side effects when users run with --dry-run. The command should be prefixed with $DRY_RUN_CMD to maintain consistency with the rest of the script.

Suggested change
$DRY_RUN_CMD ${pkgs.rage}/bin/rage -d -i ${config.home.homeDirectory}/.ssh/id_ed25519 "$GPG_SECRET_FILE" | ${pkgs.gnupg}/bin/gpg --batch --import
$DRY_RUN_CMD sh -c '${pkgs.rage}/bin/rage -d -i ${config.home.homeDirectory}/.ssh/id_ed25519 "$GPG_SECRET_FILE" | ${pkgs.gnupg}/bin/gpg --batch --import'

Copilot uses AI. Check for mistakes.
# Alternative: directly use ssh-add if keychain already initialized ssh-agent
if not ssh-add -l >/dev/null 2>&1
# Start ssh-agent if not running
eval (ssh-agent -c)

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function starts ssh-agent with the -c flag for csh-style output, but Fish shell requires fish-style output using the -c flag is incorrect. Fish can handle the default output format, but using ssh-agent -c | source would be more appropriate for Fish shell.

Suggested change
eval (ssh-agent -c)
eval (ssh-agent | psub)

Copilot uses AI. Check for mistakes.
Comment thread named-hosts/kyber/default.nix Outdated
Comment on lines +109 to +118
default-key = "shunkakinoki@gmail.com";
};
};

# GPG agent configuration
services.gpg-agent = {
enable = true;
enableSshSupport = false;
pinentryPackage = pkgs.pinentry-curses;
defaultCacheTtl = 1800;

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The email address "shunkakinoki@gmail.com" is hardcoded in multiple places. If this configuration needs to be reused for different users or machines, consider extracting this to a variable or configuration parameter to improve maintainability and reusability.

Copilot uses AI. Check for mistakes.

# Manually deploy if needed
age -d -i ~/.ssh/id_ed25519 -o ~/.ssh/id_ed25519_github \
named-hosts/galactica/keys/id_ed25519.age

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation references id_ed25519.age but the code has been updated to use id_github.age. This inconsistency will confuse users trying to follow the troubleshooting instructions. Update this line to reference id_github.age to match the code changes.

Suggested change
named-hosts/galactica/keys/id_ed25519.age
named-hosts/galactica/keys/id_github.age

Copilot uses AI. Check for mistakes.
Comment thread named-hosts/kyber/default.nix Outdated
if [[ -f "$GPG_SECRET_FILE" ]]; then
echo "Importing GPG key from agenix..."
# Check if key is already imported
if ! ${pkgs.gnupg}/bin/gpg --list-secret-keys | grep -q "C2E97FCFF482925D"; then

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GPG key fingerprint "C2E97FCFF482925D" is hardcoded in the deployment script. If this key needs to be changed or if this configuration is shared across different users/machines, this hardcoded value will cause issues. Consider making this configurable or documenting that this is specific to a particular user.

Copilot uses AI. Check for mistakes.
Comment thread named-hosts/kyber/default.nix Outdated
Comment on lines +120 to +126
};

# GPG_TTY is set in fish shell init instead of sessionVariables
# because it needs to be evaluated dynamically per shell session
programs.fish.loginShellInit = lib.mkAfter ''
set -gx GPG_TTY (tty)
'';

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gpgSign = true settings are redundant. The signByDefault = true at line 117 already enables signing for all commits and tags. The explicit commit.gpgSign and tag.gpgSign settings in extraConfig are unnecessary and should be removed to avoid duplication.

Copilot uses AI. Check for mistakes.
if test (count $keys) -gt 0
# Use --quiet to suppress most output, --eval to set environment variables
# --confirm will skip keys that need a passphrase in non-interactive contexts
eval (keychain --eval --quiet --confirm $keys ^/dev/null; or true)

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handling with ^/dev/null; or true combined with the semicolon inside the eval may cause issues. In Fish, the or operator should typically be outside the eval command substitution. Consider restructuring to eval (keychain --eval --quiet --confirm $keys 2>/dev/null) and handling errors separately, or ensuring the error handling logic is correct for the intended behavior.

Suggested change
eval (keychain --eval --quiet --confirm $keys ^/dev/null; or true)
eval (keychain --eval --quiet --confirm $keys ^/dev/null); or true

Copilot uses AI. Check for mistakes.
shunkakinoki and others added 6 commits December 13, 2025 08:10
Re-enable signByDefault with proper pinentry-curses configuration
for terminal-based passphrase prompts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enable automatic GPG signing only on macOS (galactica) where the
GPG agent works properly. Disable on Linux servers (kyber) due to
GPG agent version conflicts.

Users can still manually sign on Linux with: git commit --gpg-sign

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Enable GPG signing on both macOS and Linux
- Switch to pinentry-tty for better SSH compatibility
- Configure GPG agent with proper cache timeouts
- Set GPG_TTY in fish loginShellInit for proper terminal access

This ensures all commits are automatically signed with GPG across
both galactica (macOS) and kyber (Linux) systems.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This ensures GPG_TTY is set for all interactive fish sessions,
not just login shells. Fixes the issue where commits would fail
without manually setting GPG_TTY.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
named-hosts/kyber/default.nix (3)

105-111: Hardcoded email address in GPG configuration.

The email "shunkakinoki@gmail.com" is hardcoded at line 109. For a personal dotfiles repository this is acceptable, but if you plan to reuse this configuration across different users or machines, consider extracting this to a variable.

+let
+  userEmail = "shunkakinoki@gmail.com";
+in
 {
   # ...
   programs.gpg = {
     enable = true;
     settings = {
-      default-key = "shunkakinoki@gmail.com";
+      default-key = userEmail;
     };
   };

65-69: config is not in scope — activation will fail.

The inline module at line 27 does not destructure config from its arguments, so config.home.homeDirectory is undefined and will cause an evaluation error at lines 67-68.

Add config to the module arguments:

-    {
+    { config, ... }: {
       home = {

Or use the already-defined username variable:

-        $DRY_RUN_CMD mkdir -p $VERBOSE_ARG ${config.home.homeDirectory}/.ssh
-        $DRY_RUN_CMD chmod $VERBOSE_ARG 700 ${config.home.homeDirectory}/.ssh
+        $DRY_RUN_CMD mkdir -p $VERBOSE_ARG /home/${username}/.ssh
+        $DRY_RUN_CMD chmod $VERBOSE_ARG 700 /home/${username}/.ssh

71-101: Multiple unresolved critical issues in secret deployment.

This activation script has several problems flagged in previous reviews:

  1. Lines 75, 79, 80, 93: config.home.homeDirectory is undefined (same scope issue as above)
  2. Line 92: Hardcoded GPG key fingerprint C2E97FCFF482925D
  3. Line 93: Missing $DRY_RUN_CMD prefix for GPG import command

Apply the same config scope fix as above, then:

For the GPG key fingerprint (line 92):

-          if ! ${pkgs.gnupg}/bin/gpg --list-secret-keys | grep -q "C2E97FCFF482925D"; then
+          GPG_KEY="C2E97FCFF482925D"
+          if ! ${pkgs.gnupg}/bin/gpg --list-secret-keys | grep -q "$GPG_KEY"; then

For the DRY_RUN_CMD (line 93):

-            $DRY_RUN_CMD ${pkgs.rage}/bin/rage -d -i ${config.home.homeDirectory}/.ssh/id_ed25519 "$GPG_SECRET_FILE" | ${pkgs.gnupg}/bin/gpg --batch --import
+            if [[ -z "$DRY_RUN_CMD" ]]; then
+              ${pkgs.rage}/bin/rage -d -i /home/${username}/.ssh/id_ed25519 "$GPG_SECRET_FILE" | ${pkgs.gnupg}/bin/gpg --batch --import
+            fi
🧹 Nitpick comments (1)
home-manager/programs/git/default.nix (1)

2-6: Consider inlining the variable or implementing conditional logic.

The enableGpgSigning variable is defined but only used once. If GPG signing is truly meant to be enabled on all systems, this variable adds no value and can be inlined. Alternatively, if you plan to make this conditional per system (as the comment on line 86 suggests), implement that logic here.

If keeping it simple and always enabled:

-let
-  # Determine if we're on a system where GPG signing should be enabled
-  # Enable on all systems
-  enableGpgSigning = true;
-in
 {
   programs = {
     git = {

And inline on line 88:

-        signByDefault = enableGpgSigning;
+        signByDefault = true;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5f87a2f and 9d97d9b.

📒 Files selected for processing (2)
  • home-manager/programs/git/default.nix (2 hunks)
  • named-hosts/kyber/default.nix (2 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.nix

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.nix: Use nixfmt for formatting all Nix files
Document complex configurations with comments in Nix files

**/*.nix: Use 2 spaces for indentation in Nix files
Keep line length under 100 characters in Nix files
Sort attribute sets alphabetically in Nix files
Use consistent spacing around operators in Nix files
Format lists and sets consistently in Nix files

Use treefmt.toml for formatting Nix files

**/*.nix: Use mkOption for configurable options in Nix modules
Implement proper typing for all options in Nix modules
Follow the Nix expression language style guide

Files:

  • named-hosts/kyber/default.nix
  • home-manager/programs/git/default.nix
**/default.nix

📄 CodeRabbit inference engine (CLAUDE.md)

Use default.nix files for module exports

Files:

  • named-hosts/kyber/default.nix
  • home-manager/programs/git/default.nix
home-manager/programs/*/default.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Program configurations should be located in home-manager/programs/<name>/ and use home-manager's built-in modules when available

Files:

  • home-manager/programs/git/default.nix
home-manager/programs/**/default.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Program configurations must include all necessary dependencies in their configuration

Files:

  • home-manager/programs/git/default.nix
home-manager/**/*.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

home-manager/**/*.nix: Use typed options whenever possible in Nix configurations
Document all configuration options in Nix modules and programs
Follow home-manager's module structure and keep configurations modular
Use proper indentation and formatting in Nix configuration files

Files:

  • home-manager/programs/git/default.nix
home-manager/programs/**/*.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

Follow program-specific best practices in program configuration files

Program configurations in home-manager/programs/ should be organized by program name, include all necessary dependencies, use home.packages for package installations, and use programs.<name> when available in home-manager

Files:

  • home-manager/programs/git/default.nix
🧠 Learnings (14)
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Document all major changes in Nix configurations

Applied to files:

  • named-hosts/kyber/default.nix
  • home-manager/programs/git/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/**/*.nix : Follow program-specific best practices in program configuration files

Applied to files:

  • named-hosts/kyber/default.nix
  • home-manager/programs/git/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Follow home-manager's module structure and keep configurations modular

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Keep configurations modular across home-manager, hosts, and nix-darwin directories

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/*/default.nix : Program configurations should be located in `home-manager/programs/<name>/` and use home-manager's built-in modules when available

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/modules/**/default.nix : Custom modules should include proper option types and document all options

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Document all configuration options in Nix modules and programs

Applied to files:

  • named-hosts/kyber/default.nix
  • home-manager/programs/git/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Use proper indentation and formatting in Nix configuration files

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/services/**/default.nix : Service configurations must include proper service definitions, handle dependencies correctly, and document service parameters

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/programs/**/*.nix : Program configurations in `home-manager/programs/` should be organized by program name, include all necessary dependencies, use `home.packages` for package installations, and use `programs.<name>` when available in home-manager

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/modules/**/default.nix : Each module in `home-manager/modules/` should have a clear `default.nix` with proper option declarations following the home-manager module structure

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Test configurations before committing using `nix flake check` and `home-manager build --show-trace`

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/services/**/*.nix : Service configurations in `home-manager/services/` should follow systemd service conventions, include proper service dependencies, and have clear documentation for service parameters

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Test Nix and home-manager configurations locally before pushing using `make test`

Applied to files:

  • named-hosts/kyber/default.nix
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: docker-build-push (linux/arm64, arm64, ubuntu-24.04-arm)
  • GitHub Check: docker-build-push (linux/amd64, amd64, ubuntu-latest)
  • GitHub Check: e2e-run (Ubuntu, ubuntu-latest)
  • GitHub Check: e2e-run (NixOS, ubuntu-latest)
  • GitHub Check: e2e-run (MacOS, macos-latest)
  • GitHub Check: nix-darwin
  • GitHub Check: nix-flake
  • GitHub Check: nix-nixos
  • GitHub Check: nix-linux
  • GitHub Check: shellspec
  • GitHub Check: shellcheck
  • GitHub Check: lua-hammerspoon
  • GitHub Check: lua-neovim-test
  • GitHub Check: lua-neovim
🔇 Additional comments (4)
home-manager/programs/git/default.nix (1)

87-90: LGTM: GPG signing configured correctly.

The signing configuration properly references the user email from line 21 and follows home-manager conventions.

named-hosts/kyber/default.nix (3)

54-62: Age secrets mapping updated correctly.

The conditional logic properly targets the GitHub SSH key and sets appropriate permissions (0600) and deployment path.


113-120: GPG agent configuration looks good.

The agent is properly configured for a server environment with TTY pinentry and reasonable cache TTLs. Disabling SSH support is appropriate since SSH key management is handled separately.


122-126: LGTM: GPG_TTY set correctly in shell init.

Using programs.fish.interactiveShellInit with lib.mkAfter properly evaluates tty dynamically per shell session, which is the correct approach. The comment clearly explains why sessionVariables cannot be used here.

Comment thread home-manager/programs/git/default.nix Outdated
shunkakinoki and others added 5 commits December 14, 2025 06:03
- Add GPG key import activation script to home-manager/default.nix
- Automatically decrypt and import galactica GPG key on Linux systems
- Check if key (C2E97FCFF482925D) is already imported before importing
- Use pinentry-tty for better SSH compatibility
- GPG signing now works automatically with galactica key on kyber

This ensures the GPG key from galactica is automatically synced and
imported on all Linux systems during home-manager activation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
named-hosts/kyber/default.nix (3)

27-27: CRITICAL: config parameter must be added to module arguments.

The inline module starting at line 27 does not destructure config from the module arguments, but multiple activation hooks (lines 67, 68, 73, 74, 81, 85, 86, 98, 107, 108, 110) reference config.home.homeDirectory. This will cause an "undefined variable" error during evaluation.

Add config to the module parameters:

     agenix.homeManagerModules.default
     ../../home-manager/default.nix
-    {
+    { config, ... }: {
       home = {

As per coding guidelines, test configurations before committing using nix flake check and home-manager build --show-trace.


104-104: Hardcoded GPG key ID reduces maintainability.

The GPG key fingerprint C2E97FCFF482925D is hardcoded. Consider defining it as a variable in the let block for easier maintenance if the key needs to be changed.

 let
+  gpgKeyId = "C2E97FCFF482925D";
   # ...
 in
 # ...
-          if ! ${pkgs.gnupg}/bin/gpg --list-secret-keys | grep -q "C2E97FCFF482925D"; then
+          if ! ${pkgs.gnupg}/bin/gpg --list-secret-keys | grep -q "${gpgKeyId}"; then

122-128: Hardcoded email address is acceptable for personal dotfiles.

The email address is hardcoded, which past reviews flagged for reusability. However, since this is a host-specific configuration in a personal dotfiles repository, this is acceptable. If you plan to share this configuration or use it across multiple identities, consider parameterizing it.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 67f5d26 and ba04595.

📒 Files selected for processing (2)
  • home-manager/default.nix (1 hunks)
  • named-hosts/kyber/default.nix (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.nix

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.nix: Use nixfmt for formatting all Nix files
Document complex configurations with comments in Nix files

**/*.nix: Use 2 spaces for indentation in Nix files
Keep line length under 100 characters in Nix files
Sort attribute sets alphabetically in Nix files
Use consistent spacing around operators in Nix files
Format lists and sets consistently in Nix files

Use treefmt.toml for formatting Nix files

**/*.nix: Use mkOption for configurable options in Nix modules
Implement proper typing for all options in Nix modules
Follow the Nix expression language style guide

Files:

  • home-manager/default.nix
  • named-hosts/kyber/default.nix
**/default.nix

📄 CodeRabbit inference engine (CLAUDE.md)

Use default.nix files for module exports

Files:

  • home-manager/default.nix
  • named-hosts/kyber/default.nix
home-manager/**/*.nix

📄 CodeRabbit inference engine (.cursor/rules/home-manager.mdc)

home-manager/**/*.nix: Use typed options whenever possible in Nix configurations
Document all configuration options in Nix modules and programs
Follow home-manager's module structure and keep configurations modular
Use proper indentation and formatting in Nix configuration files

Files:

  • home-manager/default.nix
🧠 Learnings (14)
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Document all major changes in Nix configurations

Applied to files:

  • home-manager/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Follow home-manager's module structure and keep configurations modular

Applied to files:

  • home-manager/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/**/*.nix : Follow program-specific best practices in program configuration files

Applied to files:

  • home-manager/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Document all configuration options in Nix modules and programs

Applied to files:

  • home-manager/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/programs/**/*.nix : Program configurations in `home-manager/programs/` should be organized by program name, include all necessary dependencies, use `home.packages` for package installations, and use `programs.<name>` when available in home-manager

Applied to files:

  • home-manager/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Keep configurations modular across home-manager, hosts, and nix-darwin directories

Applied to files:

  • home-manager/default.nix
  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/programs/*/default.nix : Program configurations should be located in `home-manager/programs/<name>/` and use home-manager's built-in modules when available

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/modules/**/default.nix : Custom modules should include proper option types and document all options

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/**/*.nix : Use proper indentation and formatting in Nix configuration files

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:55.014Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/home-manager.mdc:0-0
Timestamp: 2025-11-25T09:34:55.014Z
Learning: Applies to home-manager/services/**/default.nix : Service configurations must include proper service definitions, handle dependencies correctly, and document service parameters

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/modules/**/default.nix : Each module in `home-manager/modules/` should have a clear `default.nix` with proper option declarations following the home-manager module structure

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Test configurations before committing using `nix flake check` and `home-manager build --show-trace`

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:35:01.066Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/nix.mdc:0-0
Timestamp: 2025-11-25T09:35:01.066Z
Learning: Applies to home-manager/services/**/*.nix : Service configurations in `home-manager/services/` should follow systemd service conventions, include proper service dependencies, and have clear documentation for service parameters

Applied to files:

  • named-hosts/kyber/default.nix
📚 Learning: 2025-11-25T09:34:40.062Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T09:34:40.062Z
Learning: Test Nix and home-manager configurations locally before pushing using `make test`

Applied to files:

  • named-hosts/kyber/default.nix
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: docker-build-push (linux/amd64, amd64, ubuntu-latest)
  • GitHub Check: docker-build-push (linux/arm64, arm64, ubuntu-24.04-arm)
  • GitHub Check: e2e-run (NixOS, ubuntu-latest)
  • GitHub Check: e2e-run (Ubuntu, ubuntu-latest)
  • GitHub Check: e2e-run (MacOS, macos-latest)
  • GitHub Check: nix-linux
  • GitHub Check: nix-darwin
  • GitHub Check: nix-nixos
  • GitHub Check: shellspec
  • GitHub Check: shellcheck
  • GitHub Check: lua-neovim-test
  • GitHub Check: lua-neovim
  • GitHub Check: lua-hammerspoon
🔇 Additional comments (3)
named-hosts/kyber/default.nix (3)

54-63: LGTM: GitHub SSH key mapping is correctly configured.

The secret mapping has been appropriately updated to use a dedicated GitHub SSH key with correct deployment path and permissions.


130-137: LGTM: GPG agent configuration is appropriate for server environment.

The configuration correctly uses pinentry-tty for terminal-only access and sets reasonable cache timeouts. Disabling SSH support is appropriate if managing SSH keys separately via ssh-agent/keychain.


139-143: LGTM: GPG_TTY is correctly configured for dynamic evaluation.

This properly sets GPG_TTY in the Fish shell initialization where it will be evaluated dynamically per session. The comment clearly explains the rationale, and using lib.mkAfter ensures correct ordering.

Comment thread home-manager/default.nix Outdated
shunkakinoki and others added 5 commits December 13, 2025 22:08
- Remove Linux-only condition so it runs on macOS too
- Add silent failure handling with 2>/dev/null
- Only import if decryption succeeds (authorized SSH key required)
- Keeps GPG key management consistent across all systems

This ensures galactica can also auto-import the GPG key if needed
(e.g., after fresh install or keyring corruption), while failing
gracefully on unauthorized systems.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@shunkakinoki
shunkakinoki enabled auto-merge (squash) December 13, 2025 22:42
@shunkakinoki
shunkakinoki merged commit 341e6cd into main Dec 13, 2025
27 checks passed
@shunkakinoki
shunkakinoki deleted the feat/declarative-ssh-agent branch December 13, 2025 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants