Author SHA1 Message Date
Renovate Bot 4ee28842cf chore(deps): update renovatebot/github-action action to v46.1.21 2026-07-27 19:24:08 +00:00
moons-14andgithub-actions[bot] 6cb15f3a54 chore(nix): update nixpkgs-unstable to d4221905 (#44)
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-27 04:43:36 +09:00
moons-14andgithub-actions[bot] 99132ef43f chore(nix): update nixpkgs to c76cb9d6 (#46)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-27 04:43:35 +09:00
moons-14andgithub-actions[bot] d40b5b4b00 chore(nix): update nixpkgs to 8db7e9c9 (#45)
NixOS CI / Validate flake (push) Has been cancelled
NixOS CI / Build ${{ matrix.host }} (push) Has been cancelled
NixOS CI / Report main status (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-26 04:42:32 +09:00
543 changed files with 6754 additions and 11058 deletions
-27
View File
@@ -1,27 +0,0 @@
# Reference: https://github.com/ryoppippi/dotfiles/blob/main/.github/workflows/nix-build.yaml
name: Check NixOS configurations
description: Build every NixOS configuration and the Registry tests
runs:
using: composite
steps:
- name: Build every NixOS configuration
shell: bash
run: |
set -euo pipefail
mapfile -t hosts < <(
nix eval --raw .#nixosConfigurations \
--apply 'configs: builtins.concatStringsSep "\n" (builtins.attrNames configs)'
)
installables=(.#checks.x86_64-linux.registry)
for host in "${hosts[@]}"; do
installables+=(".#nixosConfigurations.${host}.config.system.build.toplevel")
done
nix build \
--keep-going \
--no-link \
--print-build-logs \
--show-trace \
"${installables[@]}"
-22
View File
@@ -1,22 +0,0 @@
# Reference: https://github.com/ryoppippi/dotfiles/blob/main/.github/actions/setup-nix/action.yaml
name: Setup Nix
description: Install Nix and cache the Nix store
runs:
using: composite
steps:
- name: Allow unprivileged user namespaces
if: runner.os == 'Linux'
shell: bash
run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 2>/dev/null || true
- name: Install Nix
uses: nixbuild/nix-quick-install-action@9f63be77f412a248c9d9a65a4c82cf066cdf8f0c # v35
with:
nix_conf: |
accept-flake-config = true
max-jobs = auto
- name: Cache Nix store
uses: nix-community/cache-nix-action@7df957e333c1e5da7721f60227dbba6d06080569 # v7.0.2
with:
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('flake.lock') }}
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}-
gc-max-store-size-linux: 4G
@@ -0,0 +1,260 @@
name: Update Flake Input
description: Update one GitHub-backed Nix flake input and create a pull request
inputs:
input-name:
description: Name of the flake input to update
required: true
github-token:
description: Token used to query GitHub, push the update branch, and manage the pull request
required: true
base-branch:
description: Branch targeted by the pull request
required: false
default: main
minimum-release-age-days:
description: Minimum age of the target commit in days
required: false
default: "3"
skip-delay:
description: Update to the latest revision without applying the minimum age
required: false
default: "false"
auto-merge:
description: Enable squash auto-merge on the pull request
required: false
default: "true"
pr-labels:
description: Comma-separated labels to add when they already exist in the repository
required: false
default: dependencies,automated
outputs:
updated:
description: Whether flake.lock changed
value: ${{ steps.update.outputs.updated }}
current-version:
description: Previous locked revision
value: ${{ steps.update.outputs.current_version }}
new-version:
description: New locked revision
value: ${{ steps.update.outputs.new_version }}
pr-url:
description: URL of the created or updated pull request
value: ${{ steps.pull-request.outputs.pr_url }}
runs:
using: composite
steps:
- name: Update flake input
id: update
shell: bash
env:
GH_TOKEN: ${{ inputs.github-token }}
INPUT_NAME: ${{ inputs.input-name }}
MINIMUM_RELEASE_AGE_DAYS: ${{ inputs.minimum-release-age-days }}
SKIP_DELAY: ${{ inputs.skip-delay }}
run: |
set -euo pipefail
if [[ ! "$MINIMUM_RELEASE_AGE_DAYS" =~ ^[0-9]+$ ]]; then
echo "::error::minimum-release-age-days must be a non-negative integer"
exit 1
fi
node_key="$(
jq -er --arg input "$INPUT_NAME" '
.nodes.root.inputs[$input]
| if type == "array" then .[0] else . end
' flake.lock
)"
input_type="$(jq -r --arg node "$node_key" '.nodes[$node].locked.type // ""' flake.lock)"
input_owner="$(jq -r --arg node "$node_key" '.nodes[$node].locked.owner // ""' flake.lock)"
input_repo="$(jq -r --arg node "$node_key" '.nodes[$node].locked.repo // ""' flake.lock)"
input_ref="$(jq -r --arg node "$node_key" '.nodes[$node].original.ref // ""' flake.lock)"
current_rev="$(jq -er --arg node "$node_key" '.nodes[$node].locked.rev' flake.lock)"
if [ "$input_type" != "github" ] || [ -z "$input_owner" ] || [ -z "$input_repo" ]; then
echo "::error::${INPUT_NAME} is not a GitHub-backed flake input"
exit 1
fi
echo "Input: $INPUT_NAME"
echo "Repository: ${input_owner}/${input_repo}"
echo "Current revision: $current_rev"
if [ "$SKIP_DELAY" = "true" ]; then
nix flake update "$INPUT_NAME"
else
cutoff="$(date --utc --date="${MINIMUM_RELEASE_AGE_DAYS} days ago" +%Y-%m-%dT%H:%M:%SZ)"
api_args=(
--method GET
"repos/${input_owner}/${input_repo}/commits"
-f "until=$cutoff"
-f per_page=1
)
if [ -n "$input_ref" ]; then
api_args+=(-f "sha=$input_ref")
fi
echo "Selecting the newest commit no later than $cutoff"
target_data="$(gh api "${api_args[@]}" --jq '.[0] | {sha: .sha, date: .commit.committer.date}')"
target_rev="$(jq -er '.sha' <<< "$target_data")"
target_date="$(jq -er '.date' <<< "$target_data")"
if [ "$target_rev" = "$current_rev" ]; then
echo "The input is already at the newest eligible revision"
{
echo "updated=false"
echo "current_version=$current_rev"
echo "new_version=$current_rev"
} >> "$GITHUB_OUTPUT"
exit 0
fi
current_date="$(
gh api "repos/${input_owner}/${input_repo}/commits/${current_rev}" \
--jq '.commit.committer.date'
)"
current_timestamp="$(date --date="$current_date" +%s)"
target_timestamp="$(date --date="$target_date" +%s)"
if [ "$target_timestamp" -lt "$current_timestamp" ]; then
echo "The newest eligible revision is older than the current revision; skipping"
{
echo "updated=false"
echo "current_version=$current_rev"
echo "new_version=$current_rev"
} >> "$GITHUB_OUTPUT"
exit 0
fi
nix flake update "$INPUT_NAME" \
--override-input "$INPUT_NAME" "github:${input_owner}/${input_repo}/${target_rev}"
fi
if git diff --quiet -- flake.lock; then
echo "No lock file changes were produced"
{
echo "updated=false"
echo "current_version=$current_rev"
echo "new_version=$current_rev"
} >> "$GITHUB_OUTPUT"
exit 0
fi
new_node_key="$(
jq -er --arg input "$INPUT_NAME" '
.nodes.root.inputs[$input]
| if type == "array" then .[0] else . end
' flake.lock
)"
new_rev="$(jq -er --arg node "$new_node_key" '.nodes[$node].locked.rev' flake.lock)"
echo "New revision: $new_rev"
{
echo "updated=true"
echo "current_version=$current_rev"
echo "new_version=$new_rev"
echo "input_owner=$input_owner"
echo "input_repo=$input_repo"
} >> "$GITHUB_OUTPUT"
- name: Create or update pull request
id: pull-request
if: steps.update.outputs.updated == 'true'
shell: bash
env:
GH_TOKEN: ${{ inputs.github-token }}
INPUT_NAME: ${{ inputs.input-name }}
BASE_BRANCH: ${{ inputs.base-branch }}
CURRENT_REV: ${{ steps.update.outputs.current_version }}
NEW_REV: ${{ steps.update.outputs.new_version }}
INPUT_OWNER: ${{ steps.update.outputs.input_owner }}
INPUT_REPO: ${{ steps.update.outputs.input_repo }}
MINIMUM_RELEASE_AGE_DAYS: ${{ inputs.minimum-release-age-days }}
SKIP_DELAY: ${{ inputs.skip-delay }}
AUTO_MERGE: ${{ inputs.auto-merge }}
PR_LABELS: ${{ inputs.pr-labels }}
run: |
set -euo pipefail
branch_suffix="$(tr -c 'A-Za-z0-9._-' '-' <<< "$INPUT_NAME" | sed 's/-$//')"
branch="update-flake-${branch_suffix}"
current_short="${CURRENT_REV:0:8}"
new_short="${NEW_REV:0:8}"
title="chore(nix): update ${INPUT_NAME} to ${new_short}"
if [ "$SKIP_DELAY" = "true" ]; then
age_note="The minimum release age check was skipped for this manually requested update."
else
age_note="The target commit is at least ${MINIMUM_RELEASE_AGE_DAYS} days old."
fi
body="$(
printf '%s\n' \
"Automated update of the \`${INPUT_NAME}\` flake input." \
"" \
"- Previous revision: [\`${current_short}\`](https://github.com/${INPUT_OWNER}/${INPUT_REPO}/commit/${CURRENT_REV})" \
"- New revision: [\`${new_short}\`](https://github.com/${INPUT_OWNER}/${INPUT_REPO}/commit/${NEW_REV})" \
"- Changes: [compare](https://github.com/${INPUT_OWNER}/${INPUT_REPO}/compare/${CURRENT_REV}...${NEW_REV})" \
"" \
"$age_note"
)"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add flake.lock
git switch -C "$branch"
git commit -m "$title"
git fetch origin "refs/heads/${branch}:refs/remotes/origin/${branch}" || true
git push --force-with-lease origin "HEAD:refs/heads/${branch}"
label_args=()
available_labels="$(gh label list --limit 100 --json name --jq '.[].name')"
IFS=',' read -ra requested_labels <<< "$PR_LABELS"
for label in "${requested_labels[@]}"; do
label="$(xargs <<< "$label")"
if [ -n "$label" ] && grep -Fxq "$label" <<< "$available_labels"; then
label_args+=(--add-label "$label")
elif [ -n "$label" ]; then
echo "::warning::Skipping missing pull request label: $label"
fi
done
pr_number="$(
gh pr list \
--state open \
--head "$branch" \
--json number \
--jq '.[0].number // empty'
)"
if [ -n "$pr_number" ]; then
gh pr edit "$pr_number" \
--title "$title" \
--body "$body" \
"${label_args[@]}"
else
gh pr create \
--base "$BASE_BRANCH" \
--head "$branch" \
--title "$title" \
--body "$body"
pr_number="$(
gh pr list \
--state open \
--head "$branch" \
--json number \
--jq '.[0].number'
)"
if [ "${#label_args[@]}" -gt 0 ]; then
gh pr edit "$pr_number" "${label_args[@]}"
fi
fi
if [ "$AUTO_MERGE" = "true" ]; then
gh pr merge "$pr_number" --auto --squash ||
echo "::warning::Auto-merge could not be enabled; check the repository merge settings"
fi
pr_url="$(gh pr view "$pr_number" --json url --jq '.url')"
echo "pr_url=$pr_url" >> "$GITHUB_OUTPUT"
echo "Pull request: $pr_url"
+150
View File
@@ -0,0 +1,150 @@
name: NixOS CI
on:
pull_request:
branches:
- main
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
concurrency:
group: nixos-ci-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
validate:
name: Validate flake
runs-on: ubuntu-latest
timeout-minutes: 30
outputs:
hosts: ${{ steps.hosts.outputs.hosts }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Nix
uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31.11.0
with:
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
access-tokens = github.com=${{ github.token }}
- name: Check flake and evaluate all outputs
run: nix flake check --all-systems --no-build --show-trace
- name: Discover NixOS hosts
id: hosts
run: |
hosts=$(nix eval --json '.#nixosConfigurations' --apply 'configs: builtins.attrNames configs')
echo "hosts=$hosts" >> "$GITHUB_OUTPUT"
echo "Discovered hosts: $hosts"
build:
name: Build ${{ matrix.host }}
needs: validate
if: ${{ needs.validate.outputs.hosts != '[]' }}
runs-on: ubuntu-latest
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
host: ${{ fromJSON(needs.validate.outputs.hosts) }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Nix
uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31.11.0
with:
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
access-tokens = github.com=${{ github.token }}
- name: Build NixOS system
run: |
nix build ".#nixosConfigurations.${{ matrix.host }}.config.system.build.toplevel" \
--no-link \
--print-build-logs \
--show-trace
report-main-status:
name: Report main status
needs:
- validate
- build
if: ${{ always() && !cancelled() && github.event_name == 'push' && github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
issues: write
env:
CI_FAILED: ${{ needs.validate.result == 'failure' || needs.build.result == 'failure' }}
JOB_RESULTS: ${{ toJSON(needs) }}
steps:
- name: Create or resolve failure issue
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const title = "NixOS CI is failing on main";
const marker = "<!-- nixos-ci-main-failure -->";
const failed = process.env.CI_FAILED === "true";
const jobs = JSON.parse(process.env.JOB_RESULTS);
const failedJobs = Object.entries(jobs)
.filter(([, job]) => job.result === "failure")
.map(([name]) => `\`${name}\``)
.join(", ");
const runUrl = `${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`;
const commitUrl = `${context.serverUrl}/${owner}/${repo}/commit/${context.sha}`;
const issues = await github.paginate(github.rest.issues.listForRepo, {
owner,
repo,
state: "open",
per_page: 100,
});
const existing = issues.find(
(issue) => !issue.pull_request && issue.title === title && issue.body?.includes(marker),
);
if (failed) {
const body = [
marker,
"The NixOS CI workflow failed after a push to `main`.",
"",
`- Failed jobs: ${failedJobs || "unknown"}`,
`- Commit: [\`${context.sha.slice(0, 7)}\`](${commitUrl})`,
`- Workflow run: [${context.runId}](${runUrl})`,
"",
"This issue is updated on subsequent failures and closed automatically after CI recovers.",
].join("\n");
if (existing) {
await github.rest.issues.update({
owner,
repo,
issue_number: existing.number,
body,
});
} else {
await github.rest.issues.create({ owner, repo, title, body });
}
return;
}
if (existing) {
await github.rest.issues.createComment({
owner,
repo,
issue_number: existing.number,
body: `CI recovered in [workflow run ${context.runId}](${runUrl}).`,
});
await github.rest.issues.update({
owner,
repo,
issue_number: existing.number,
state: "closed",
state_reason: "completed",
});
}
-51
View File
@@ -1,51 +0,0 @@
# Reference: https://github.com/ryoppippi/dotfiles/blob/main/.github/workflows/nix-build.yaml
name: "CI: NixOS"
on:
push:
branches:
- main
paths:
- flake.nix
- flake.lock
- "flake/**"
- "hosts/**"
- "libs/**"
- "modules/**"
- "overlays/**"
- "shells/**"
- "tests/**"
- ".github/actions/check-nixos/**"
- ".github/actions/setup-nix/**"
- ".github/workflows/nixos.yaml"
pull_request:
paths:
- flake.nix
- flake.lock
- "flake/**"
- "hosts/**"
- "libs/**"
- "modules/**"
- "overlays/**"
- "shells/**"
- "tests/**"
- ".github/actions/check-nixos/**"
- ".github/actions/setup-nix/**"
- ".github/workflows/nixos.yaml"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
check:
name: Check all NixOS configurations
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Nix
uses: ./.github/actions/setup-nix
- name: Check NixOS configurations
uses: ./.github/actions/check-nixos
+31
View File
@@ -0,0 +1,31 @@
name: Renovate
on:
schedule:
# Every day at 03:00 JST (18:00 UTC on the previous day).
- cron: "0 18 * * *"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: renovate
cancel-in-progress: false
jobs:
renovate:
name: Update GitHub Actions dependencies
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# Use a PAT or GitHub App token so Renovate PRs trigger the other workflows.
- name: Run Renovate
uses: renovatebot/github-action@1a96852b0384df1837619d04c60b2d10d1f9ff08 # v46.1.21
with:
renovate-version: 43.262.1
token: ${{ secrets.RENOVATE_TOKEN }}
env:
LOG_LEVEL: info
RENOVATE_PLATFORM: github
RENOVATE_REPOSITORIES: ${{ github.repository }}
+106
View File
@@ -0,0 +1,106 @@
name: Update Flake Inputs
on:
schedule:
# Every day at 03:30 JST (18:30 UTC on the previous day).
- cron: "30 18 * * *"
workflow_dispatch:
inputs:
input:
description: Update only this flake input (empty updates all inputs)
required: false
type: string
skip-delay:
description: Update to the latest revision without the three-day delay
required: false
default: false
type: boolean
auto-merge:
description: Enable auto-merge after required checks pass
required: false
default: true
type: boolean
permissions:
contents: write
pull-requests: write
concurrency:
group: update-flake-inputs
cancel-in-progress: false
jobs:
discover:
name: Discover flake inputs
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
matrix: ${{ steps.inputs.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Build update matrix
id: inputs
env:
REQUESTED_INPUT: ${{ inputs.input }}
run: |
set -euo pipefail
github_inputs="$(
jq -c '
. as $lock
| [
$lock.nodes.root.inputs
| to_entries[]
| .key as $name
| (
.value
| if type == "array" then .[0] else . end
) as $node
| select($lock.nodes[$node].locked.type == "github")
| $name
]
| sort
' flake.lock
)"
if [ -n "$REQUESTED_INPUT" ]; then
if ! jq -e --arg input "$REQUESTED_INPUT" 'index($input) != null' <<< "$github_inputs" >/dev/null; then
echo "::error::Unknown or unsupported flake input: $REQUESTED_INPUT"
exit 1
fi
matrix="$(jq -cn --arg input "$REQUESTED_INPUT" '{input: [$input]}')"
else
matrix="$(jq -cn --argjson inputs "$github_inputs" '{input: $inputs}')"
fi
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
echo "Update matrix: $matrix"
update:
name: Update ${{ matrix.input }}
needs: discover
if: ${{ needs.discover.outputs.matrix != '{"input":[]}' }}
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
max-parallel: 4
matrix: ${{ fromJSON(needs.discover.outputs.matrix) }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
token: ${{ secrets.RENOVATE_TOKEN }}
- name: Install Nix
uses: cachix/install-nix-action@630ae543ea3a38a9a4166f03376c02c50f408342 # v31.11.0
with:
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
access-tokens = github.com=${{ secrets.RENOVATE_TOKEN }}
- name: Update input
uses: ./.github/actions/update-flake-input
with:
input-name: ${{ matrix.input }}
github-token: ${{ secrets.RENOVATE_TOKEN }}
skip-delay: ${{ github.event_name == 'workflow_dispatch' && inputs.skip-delay }}
auto-merge: ${{ github.event_name != 'workflow_dispatch' || inputs.auto-merge }}
-48
View File
@@ -1,48 +0,0 @@
# Reference: https://github.com/ryoppippi/dotfiles/blob/main/.github/workflows/update-flake.yaml
name: "Bot: Update flake inputs"
on:
schedule:
- cron: "0 6 * * *"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: write
pull-requests: write
jobs:
update:
name: Update and validate flake inputs
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Nix
uses: ./.github/actions/setup-nix
- name: Update flake inputs
id: update
run: |
nix flake update
if git diff --quiet -- flake.lock; then
echo 'changed=false' >> "$GITHUB_OUTPUT"
else
echo 'changed=true' >> "$GITHUB_OUTPUT"
fi
- name: Check updated NixOS configurations
if: steps.update.outputs.changed == 'true'
uses: ./.github/actions/check-nixos
- name: Create update pull request
if: steps.update.outputs.changed == 'true'
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
add-paths: flake.lock
branch: automation/update-flake-lock
delete-branch: true
commit-message: "flake: update inputs"
title: "flake: update inputs"
body: |
Automated update of `flake.lock`.
The updated inputs passed the Registry tests and a build of every NixOS configuration.
+10 -15
View File
@@ -4,7 +4,6 @@
!README.md
!LICENSE
!AGENTS.md
!/docs/
!.github/
!.gitea/
@@ -15,19 +14,15 @@
!/flake.nix
!/flake.lock
!/renovate.json
!shells/
!hosts/
!overlays/
!profiles/
!modules/
!docs/
!images/
!secrets/
!/shells/
!/flake/
!/overlays/
!/images/
!/secrets/
!/windows/
!/hosts/
!/libs/
!/modules/
!/tests/
!/skills/
-2
View File
@@ -3,7 +3,6 @@ keys:
- &host_x1g13 age12g85cuvg4kjfr79lqf5fx2k0d82tchrgv88xgkt7ukk2cfcsw98s2rjyat
- &host_ops age18rtm2dq2r62zvnhwdq0gkm24hu85r7zyleyk3jqv22zpdtw064eq7ay7dl
- &host_internal-app-01 age1mcp5gma7y0k59equhzqfsnn0ed335ljjtn0k08ua77htlxf0x54qsravch
- &host_galleria age1wh7r9wnvyrgt5efjvg2324khsf4w6e9atpmz2udr4uw7frhnvvwquzcu72
creation_rules:
- path_regex: ^secrets/common/[^/]+\.ya?ml$
key_groups:
@@ -12,7 +11,6 @@ creation_rules:
- *host_x1g13
- *host_ops
- *host_internal-app-01
- *host_galleria
- path_regex: ^secrets/hosts/x1g13/[^/]+\.ya?ml$
key_groups:
- age:
+340 -814
View File
File diff suppressed because it is too large Load Diff
+190 -2
View File
@@ -1,3 +1,191 @@
# moons14 dotfiles
# dotfiles
My NixOS + Home Manager configurations build with flake.
My NixOS + Home Manager configurations built with flake-parts.
## Overview
- **OS**: NixOS 26.05 (stable) + nixpkgs-unstable
- **Window Manager**: Niri (Wayland)
- **Shell**: Zsh
- **Terminal**: Ghostty
- **Editor**: Neovim (nixvim), VSCode
- **Launcher**: Vicinae
- **Theme**: Stylix (Dracula)
- **Secrets**: sops-nix + age + YubiKey
## Hosts
| Host | Description | Profiles |
| ------------- | --------------- | -------------------------------------------- |
| `x1g13` | ThinkPad laptop | gui, thinkpad, dev, personal, secure-storage |
| `nix-example` | VM | cli-interactive, vm, dev, remote |
| `installer` | NixOS installer | (standalone) |
## Directory Structure
```
.
├── flake.nix # Flake inputs and outputs
├── flake/
│ ├── formatter.nix # treefmt configuration (nixfmt, deadnix, statix, etc.)
│ └── git-hooks.nix # pre-commit hooks
├── hosts/
│ ├── default.nix # mkSystem helper and host definitions
│ ├── x1g13/ # ThinkPad host config
│ ├── nix-example/ # VM host config
│ └── installer/ # Installer ISO config
├── modules/
│ ├── applications/ # Application configs (NixOS + Home Manager)
│ │ ├── niri/ # Wayland compositor
│ │ ├── ghostty/ # Terminal emulator
│ │ ├── vim/ # Neovim (nixvim)
│ │ ├── vscode/ # VSCode
│ │ ├── zsh/ # Shell
│ │ ├── zellij/ # Terminal multiplexer
│ │ ├── git/ # Git config
│ │ ├── docker.nix # Container runtime
│ │ ├── tailscale.nix # VPN
│ │ ├── claude/ # Claude Code
│ │ ├── opencode.nix # OpenCode
│ │ └── ... # chrome, discord, zoom, slack, etc.
│ ├── system/ # NixOS system configs
│ │ ├── audio.nix # PipeWire
│ │ ├── boot/ # Bootloader (systemd-boot, lanzaboote)
│ │ ├── disko.nix # Disk partitioning
│ │ ├── fonts.nix # Fonts
│ │ ├── network/ # Networking
│ │ ├── sops.nix # Secrets management
│ │ ├── user/ # User accounts
│ │ └── ...
│ ├── features/ # Feature bundles (abstraction layer)
│ │ ├── application/ # browser, communication
│ │ ├── boot/ # UEFI
│ │ ├── cli/ # base, interactive, shell
│ │ ├── connect/ # WiFi, Bluetooth
│ │ ├── dev/ # agent, nix, python, bun, java, arduino
│ │ ├── gui/ # desktop, terminal, audio, editor, capture
│ │ ├── identity/ # SSH key, fingerprint
│ │ ├── network/ # Tailscale
│ │ ├── services/ # container, KDE
│ │ └── storage/ # disko
│ ├── drivers/ # Hardware drivers (Intel)
│ └── integrations/ # Home Manager integration
├── profiles/
│ ├── interfaces/ # cli-minimal, cli-interactive, gui
│ ├── platforms/ # desktop, laptop, thinkpad, vm
│ └── workloads/ # dev, personal, srv, remote, secure-storage
├── overlays/ # nixpkgs overlays
├── shells/ # devShells (pre-commit hooks, sops, age)
├── secrets/ # Encrypted secrets (sops)
└── docs/ # Documentation
```
## Architecture
```
profile (enable features)
→ features (bundle applications/system + add packages)
→ applications (system.nix + home.nix)
→ system (NixOS config)
```
### Module Patterns
**Simple Module** — Single file for NixOS-only or Home Manager-only configs:
```nix
{ lib, config, ... }:
let cfg = config.my.system.audio;
in {
options.my.system.audio.enable = lib.mkEnableOption "Audio";
config = lib.mkIf cfg.enable { ... };
}
```
**Complex Module** — Directory with `default.nix`, `system.nix`, `home.nix`:
```
modules/applications/<app>/
├── default.nix # Master enable + imports
├── system.nix # NixOS config
└── home.nix # Home Manager config (sharedModules)
```
**Feature Module** — Bundles multiple applications/system modules:
```nix
{ lib, config, ... }:
let cfg = config.my.features.gui.desktop;
in {
options.my.features.gui.desktop.enable = lib.mkEnableOption "Desktop";
config = lib.mkIf cfg.enable {
my.applications = { niri.enable = true; gtk.enable = true; ... };
};
}
```
**Profile** — Thin layer that only enables features:
```nix
{
my.features = {
gui.desktop.enable = true;
dev.agent.enable = true;
};
}
```
## Packages
### CLI
- **Shell**: Zsh with zoxide, direnv
- **Terminal multiplexer**: Zellij
- **Editor**: Neovim (nixvim)
- **Tools**: ripgrep, curl, wget, htop, btop, fastfetch, unzip, unrar
### GUI
- **Compositor**: Niri
- **Terminal**: Ghostty, Alacritty
- **Editor**: VSCode
- **Browser**: Chrome
- **Launcher**: Vicinae
- **File manager**: Nautilus
- **Communication**: Discord, Zoom, Slack
### Development
- **AI agents**: Claude Code, Codex, OpenCode, Grok
- **Languages**: Python, Bun (JavaScript/TypeScript), Java, Arduino
- **Container**: Docker
- **Nix**: nh, nixfmt, deadnix, statix
### System
- **VPN**: Tailscale
- **Secrets**: sops-nix, age
- **Boot**: systemd-boot, lanzaboote (Secure Boot)
- **Disk**: disko
- **Theme**: Stylix
## Commands
```sh
nix flake update # Update flake inputs
nix fmt # Format code
nix develop .#dotnix # Enter dev shell
sudo nixos-rebuild switch --flake .#<host> # Apply config
sudo nixos-rebuild build --flake .#<host> # Build without applying
```
## Inspired
- [Zaney/zaneyos](https://gitlab.com/Zaney/zaneyos)
- [fa0311/.zshrc](https://gist.github.com/fa0311/d37d53ff39c73c54c883379e8e3732df)
- [AsianLovesLinux/Niri](https://github.com/AsianLovesLinux/Niri)
- [natsukium/dotfiles](https://github.com/natsukium/dotfiles)
- [dracula](https://github.com/dracula)
- [akazdayo/nix-configs](https://github.com/akazdayo/nix-configs)
- [yutakobayashidev/dotnix](https://github.com/yutakobayashidev/dotnix)
- [kawaemon/dotfiles](https://github.com/kawaemon/dotfiles)
-153
View File
@@ -1,153 +0,0 @@
# NixOSインストール手順(SOPSなし・ディスク暗号化なし)
この手順は、SOPSによるシークレット管理とLUKSによるディスク暗号化を
使用しないホスト向けの、独立したインストール手順である。
SOPSとディスク暗号化を使用する場合は、[暗号化ありの手順](install.md)を参照。
## 事前準備
1. [ISOビルド](iso-build.md)を参照してISOを作成
2. USBに書き込んで対象マシンでブート
## ネットワーク接続
### 有線LAN
DHCPで自動設定される。
### Wi-Fi(有線が使えない場合)
```bash
nmcli device wifi connect <SSID> --ask
```
## SSH接続
コンソールに表示されたIPアドレスに接続:
```bash
ssh root@<ip-address>
```
## インストール手順
### 1. dotfilesのクローン
```bash
git clone [email protected]:moons-14/dotfiles.git ~/dotfiles
cd ~/dotfiles
```
### 2. ホスト設定の作成
`hosts/<hostname>/nixos.nix`を作成し、`hosts/default.nix`にホストと使用する
プロファイルを登録する。ホスト固有の設定だけをホストディレクトリに置き、
再利用可能な設定は適切なunitまたはprofileに置く。
### 3. インストール先ディスクの確認
```bash
lsblk -o NAME,PATH,SIZE,MODEL,SERIAL,TYPE,FSTYPE,MOUNTPOINTS
ls -l /dev/disk/by-id/
```
以降の操作では指定したディスクの既存データが消去される。対象を必ず確認し、
可能であれば`/dev/sda`や`/dev/nvme0n1`ではなく、安定した
`/dev/disk/by-id/...`パスを使用する。
### 4. Disko設定の作成
`hosts/<hostname>/disko.nix`を作成する:
```nix
_:
{
disko.enableConfig = true;
disko.devices.disk.main = {
type = "disk";
device = "/dev/disk/by-id/<target-disk>";
content = {
type = "gpt";
partitions = {
ESP = {
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
}
```
`<target-disk>`を手順3で確認した実際のディスクIDに置き換える。指定した
ディスクの既存データは消去される。
### 5. パーティション作成とマウント
```bash
disko --mode destroy,format,mount hosts/<hostname>/disko.nix
```
Diskoの実行結果を確認する:
```bash
findmnt /mnt
findmnt /mnt/boot
```
### 6. ハードウェア設定の生成
```bash
nixos-generate-config --no-filesystems --root /mnt --show-hardware-config \
> ~/dotfiles/hosts/<hostname>/hardware-configuration.nix
```
### 7. ホストモジュールから設定を読み込む
`hosts/<hostname>/nixos.nix`で、生成したハードウェア設定とDisko設定を読み込む:
```nix
{
imports = [
./hardware-configuration.nix
./disko.nix
];
}
```
### 8. NixOSインストール
```bash
nixos-install --flake ~/dotfiles#<hostname>
```
SOPSを使用しないため、age鍵の登録、シークレットの再暗号化、SSHホストキーの
事前生成とコピーは不要である。OpenSSHを有効にしたホストでは、SSHホストキーは
通常の初回起動時に生成される。
### 9. 再起動
```bash
reboot
```
## インストール後の確認
- 正しいディスクから起動できるか
- `/`と`/boot`が意図したファイルシステムからマウントされているか
- ネットワークと、設定している場合はSSH接続が利用できるか
+44 -32
View File
@@ -1,10 +1,4 @@
# NixOSインストール手順(SOPS・ディスク暗号化あり)
この手順は、SOPSによるシークレット管理とLUKSによるディスク暗号化を
使用するホスト向けである。
どちらも使用しない場合は、
[SOPSなし・ディスク暗号化なしの手順](install-simple.md)を参照。
# NixOSインストール手順
## 事前準備
@@ -89,36 +83,54 @@ sops updatekeys secrets/hosts/<hostname>/*.yaml
新しいホスト用の`hosts/<hostname>/disko.nix`を作成。
LUKS暗号化とbtrfsの構成は`hosts/x1g13/disko.nix`を参照。
#### シンプル構成(暗号化なし)
```nix
_:
{
disko.enableConfig = true;
disko.devices.disk.main = {
type = "disk";
device = "/dev/sda";
content = {
type = "gpt";
partitions = {
ESP = {
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
}
```
#### LUKS暗号化 + btrfs
`hosts/x1g13/disko.nix`を参照。
### 7. ディスクのパーティション
```bash
cd ~/dotfiles
disko --mode destroy,format,mount hosts/<hostname>/disko.nix
nix run github:nix-community/disko -- --mode disko hosts/<hostname>/disko.nix
```
### 8. ハードウェア設定の生成
対象マシンのハードウェア設定を生成し、新しいホストのディレクトリへ直接保存:
```bash
nixos-generate-config --no-filesystems --root /mnt --show-hardware-config \
> ~/dotfiles/hosts/<hostname>/hardware-configuration.nix
```
`hosts/<hostname>/nixos.nix`から生成した設定とDisko設定を読み込む:
```nix
{
imports = [
./hardware-configuration.nix
./disko.nix
];
}
```
### 9. ホストキーのコピー
### 8. ホストキーのコピー
```bash
mkdir -p /mnt/etc/ssh
@@ -126,13 +138,13 @@ cp /tmp/ssh_host_ed25519_key* /mnt/etc/ssh/
chmod 600 /mnt/etc/ssh/ssh_host_ed25519_key
```
### 10. NixOSインストール
### 9. NixOSインストール
```bash
nixos-install --flake ~/dotfiles#<hostname>
```
### 11. 再起動
### 10. 再起動
```bash
reboot
-119
View File
@@ -1,119 +0,0 @@
# iOS Simulator 初期セットアップ
この手順は `m2` の macOS 環境で、stable Xcode と最新の stable iOS Simulator Runtime を使える状態にするためのもの。
## 前提
- `m2` が `workload.development` profile を有効にしていること
- Mac App Store に Apple Account でサインイン済みであること
- dotfiles を最新化していること
Xcode 本体は `applications.xcode` が Mac App Store 版を管理する。Simulator Runtime は Apple が管理する mutable state のため、Nix store には入れず専用 dev shell から導入する。
## 1. macOS 設定を反映する
リポジトリ直下で nix-darwin の設定を反映する。
```bash
sudo darwin-rebuild switch --flake .#m2
```
これにより `/Applications/Xcode.app` に stable Xcode がインストールされる。
Xcode のインストールで Mac App Store の認証エラーになる場合は、App Store を一度開いてサインイン状態を確認してから再実行する。
## 2. iOS Simulator Runtime を導入する
初回セットアップは次の1コマンドで行う。
```bash
nix develop .#ios -c ios-simulator-install
```
`ios-simulator-install` は次を順に実行する。
1. `/Applications/Xcode.app` が存在することを確認
2. `xcode-select` の Developer Directory を stable Xcode に切り替え
3. Xcode の first-launch components を導入
4. 利用可能な新しい hardware support components を確認
5. 選択中の Xcode に対応する最新の iOS Simulator Runtime をダウンロードしてインストール
6. Xcode のバージョンとインストール済み Simulator Runtime を表示
途中で `sudo` の認証を求められる場合がある。
## 3. インストールを確認する
```bash
xcodebuild -version
xcode-select -p
xcrun simctl list runtimes
xcrun simctl list devices available
```
`xcode-select -p` は次を指していること。
```text
/Applications/Xcode.app/Contents/Developer
```
`xcrun simctl list runtimes` に iOS runtime が表示されればセットアップ完了。
## 4. Simulator を起動する
```bash
open -a Simulator
```
Simulator の Device メニューから、インストール済み runtime で利用可能な iPhone を選択する。
## Runtime の更新
Xcode を stable の新しいバージョンへ更新した後は、同じコマンドを再実行する。
```bash
nix develop .#ios -c ios-simulator-install
```
Xcode の選択、first-launch components、hardware support、iOS Simulator Runtime の状態をまとめて更新できる。
## トラブルシューティング
### Xcode が見つからない
次のエラーが出る場合、先に nix-darwin の設定を反映する。
```text
Xcode is not installed at /Applications/Xcode.app.
```
```bash
sudo darwin-rebuild switch --flake .#m2
```
### Simulator Runtime が見えない
まず runtime 一覧を確認する。
```bash
xcrun simctl list runtimes
```
iOS runtime がない場合は再度インストーラーを実行する。
```bash
nix develop .#ios -c ios-simulator-install
```
### Command Line Tools 側を参照している
```bash
xcode-select -p
```
が `/Library/Developer/CommandLineTools` を指している場合でも、`ios-simulator-install` が `/Applications/Xcode.app/Contents/Developer` へ切り替える。
手動で直す場合は次を実行する。
```bash
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
```
+12 -72
View File
@@ -1,86 +1,26 @@
# カスタムインストーラー ISO
`hosts/installer` から、NixOS 26.05 ベースの `x86_64-linux` 用インストーラー
ISO を作成する。installer ホストは Home Manager を使用せず、`base` プロファイルと
ホスト固有のインストール支援設定だけを含む。
# カスタムISOビルド
## ビルド
flake 対応の Nix が利用できる環境で、リポジトリのルートから実行する。
`x86_64-linux` 以外のマシンで実行する場合は、対応する Linux リモートビルダーが
必要になる。
```bash
nix build .#nixosConfigurations.installer.config.system.build.isoImage
```
生成された ISO は次の場所にある。
```text
result/iso/nixos-minimal-*-x86_64-linux.iso
```
ファイル名に含まれる NixOS のバージョンとリビジョンは、`flake.lock` の更新に応じて
変わる。生成物を確認するには次を実行する。
## ISO書き込み
```bash
ls -lh result/iso/*.iso
sha256sum result/iso/*.iso
```
# USBデバイスの確認
lsblk
## USB メモリへの書き込み
書き込み先はパーティション(例: `/dev/sdX1`)ではなく、USB デバイス全体
(例: `/dev/sdX`)を指定する。この操作は指定したデバイスの内容を上書きするため、
サイズ、モデル、マウント先を確認する。
```bash
lsblk -p -o NAME,SIZE,TYPE,MODEL,MOUNTPOINTS
```
USB のマウント済みパーティションをアンマウントしてから、`/dev/sdX` と
`/dev/sdX1` を確認した実際のデバイス名に置き換えて書き込む。パーティションが
複数ある場合は、それぞれをアンマウントする。
```bash
sudo umount /dev/sdX1
sudo dd if=result/iso/nixos-minimal-*-x86_64-linux.iso \
of=/dev/sdX bs=4M conv=fsync status=progress
# 書き込み(/dev/sdXは実際のデバイスに置き換える)
sudo dd if=./result/nixos-minimal-*.iso of=/dev/sdX bs=4M status=progress
sync
```
書き込み完了後、USB を安全に取り外して対象マシンから起動する。
## ISOの特徴
## 起動後の接続
有線 LAN は DHCP で自動設定される。Wi-Fi を使用する場合は、インストーラーの
コンソールで NetworkManager を使って接続する。
```bash
nmcli device wifi list
nmcli device wifi connect <SSID> --ask
```
起動時にコンソールへ IPv4 アドレスと簡易ヘルプが表示される。表示されたアドレスへ
登録済みの SSH 鍵で接続する。
```bash
ssh root@<ip-address>
```
root のパスワードログインとキーボード対話認証は無効で、
`hosts/installer/nixos.nix` に登録された公開鍵だけが利用できる。
以降の作業は、構成に応じて次の手順を参照する:
- [SOPSなし・ディスク暗号化なし](install-simple.md)
- [SOPS・ディスク暗号化あり](install.md)
## ISO に含まれる主な設定とツール
- Nix flakes と `nix-command`
- NetworkManager、OpenSSH、起動時の IP アドレス表示
- `disko`、`parted`、`cryptsetup`、`btrfs-progs`、`efibootmgr`
- `sops`、`age`、`ssh-to-age`
- `age-plugin-yubikey`、`yubikey-manager`、`pcsc-tools` と `pcscd`
- `sbctl`、`tpm2-tools`
- `git`、`rsync`、`vim`、`wget`、`curl`、`jq`、`pciutils`、`util-linux`
- SSH鍵認証でrootログイン可能
- 有線LANはDHCPで自動設定
- WiFiは`nmcli`で手動設定可能
- disko/sops/ageなどのツールを内蔵
- ブート時にIPアドレスとヘルプを表示
Generated
+282 -865
View File
File diff suppressed because it is too large Load Diff
+12 -27
View File
@@ -11,11 +11,6 @@
inputs.nixpkgs.follows = "nixpkgs";
};
nix-darwin = {
url = "github:nix-darwin/nix-darwin/nix-darwin-26.05";
inputs.nixpkgs.follows = "nixpkgs";
};
# Hardware / Platform
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
nixos-wsl.url = "github:nix-community/NixOS-WSL";
@@ -23,11 +18,6 @@
# Desktop
niri-flake.url = "github:sodiboo/niri-flake";
nix-hazkey = {
url = "github:aster-void/nix-hazkey";
inputs.nixpkgs.follows = "nixpkgs";
};
stylix = {
url = "github:nix-community/stylix";
inputs.nixpkgs.follows = "nixpkgs";
@@ -35,7 +25,7 @@
# Terminal
ghostty = {
url = "github:ghostty-org/ghostty";
url = "github:moons-14/ghostty";
};
# Shell / Launcher
@@ -46,7 +36,10 @@
inputs.nixpkgs.follows = "nixpkgs";
};
noctalia.url = "github:noctalia-dev/noctalia/cachix";
noctalia = {
url = "github:noctalia-dev/noctalia";
inputs.nixpkgs.follows = "nixpkgs";
};
# Editor
nixvim = {
@@ -91,13 +84,6 @@
url = "github:ilysenko/codex-desktop-linux";
};
codex-session-usage.url = "github:moons-14/codex-session-usage";
skills = {
url = "github:mattpocock/skills";
flake = false;
};
# Index / Search
nix-index-database = {
url = "github:nix-community/nix-index-database";
@@ -105,16 +91,13 @@
};
# Systems
systems.url = "github:nix-systems/default";
systems.url = "github:nix-systems/default-linux";
browser-previews = {
url = "github:nix-community/browser-previews";
# Japanese Input Method
nix-hazkey = {
url = "github:aster-void/nix-hazkey";
inputs.nixpkgs.follows = "nixpkgs";
};
nani-translate-linux.url = "git+https://github.com/zunoser/nani-translate-linux.git";
containerlab.url = "github:srl-labs/containerlab";
};
outputs =
@@ -128,8 +111,10 @@
imports = [
./overlays
./hosts
./shells
./flake
./flake/formatter.nix
./flake/git-hooks.nix
];
};
}
-7
View File
@@ -1,7 +0,0 @@
{
imports = [
./formatter.nix
./git-hooks.nix
./registry.nix
];
}
-54
View File
@@ -1,54 +0,0 @@
{
inputs,
lib,
...
}:
let
dotfilesLib = import ../libs {
inherit inputs lib;
root = ../.;
};
hostSpecsPath = ../hosts/default.nix;
hostSpecs =
if builtins.pathExists hostSpecsPath then
let
value = import hostSpecsPath;
in
if builtins.isFunction value then
value (
builtins.intersectAttrs (builtins.functionArgs value) {
inherit inputs lib;
}
)
else
value
else
{ };
configurations = dotfilesLib.hosts.mkConfigurations hostSpecs;
in
{
flake = {
inherit (configurations) darwinConfigurations nixosConfigurations;
lib = dotfilesLib;
};
perSystem =
{ pkgs, system, ... }:
let
nixosChecks =
lib.mapAttrs' (name: nixos: lib.nameValuePair "nixos-${name}" nixos.config.system.build.toplevel)
(
lib.filterAttrs (
_: nixos: nixos.pkgs.stdenv.hostPlatform.system == system
) configurations.nixosConfigurations
);
in
{
checks = {
registry = import ../tests/registry.nix {
inherit inputs lib pkgs;
};
}
// nixosChecks;
};
}
+107 -138
View File
@@ -1,144 +1,113 @@
{
nix-builder = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./nix-builder;
inputs,
config,
lib,
...
}:
let
inherit (inputs.nixpkgs.lib) nixosSystem;
profiles = [
"base"
"interface.minimal"
"platform.vm"
"workload.remote-access"
];
username = "moons";
mkSystem =
{
host,
system,
profiles ? [ ],
extraModules ? [ ],
}:
let
unstable = import inputs.nixpkgs-unstable {
inherit system;
config = {
allowUnfree = true;
};
};
in
assert lib.assertMsg (lib.elem system config.systems)
"mkSystem: system '${system}' not in valid systems: ${lib.generators.toPretty { } config.systems}";
nixosSystem {
inherit system;
modules = [
{
nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = builtins.attrValues inputs.self.overlays;
}
../modules
./${host}/default.nix
]
++ map (p: ../profiles/${p}.nix) profiles
++ extraModules;
specialArgs = {
inherit
inputs
username
unstable
host
;
};
};
nixosConfigurations = {
nix-example = mkSystem {
host = "nix-example";
system = "x86_64-linux";
profiles = [
"interfaces/cli-interactive"
"platforms/vm"
"workloads/dev"
"workloads/remote"
];
};
ops = mkSystem {
host = "ops";
system = "x86_64-linux";
profiles = [
"interfaces/cli-interactive"
"platforms/vm"
"workloads/remote"
];
};
internal-app-01 = mkSystem {
host = "internal-app-01";
system = "x86_64-linux";
profiles = [
"interfaces/cli-interactive"
"platforms/vm"
"workloads/srv"
];
};
x1g13 = mkSystem {
host = "x1g13";
system = "x86_64-linux";
profiles = [
"interfaces/gui"
"platforms/thinkpad"
"workloads/dev"
"workloads/personal"
"workloads/secure-storage"
"workloads/tailscale/client"
];
};
installer = nixosSystem {
system = "x86_64-linux";
modules = [
./installer/default.nix
];
specialArgs = {
inherit inputs;
};
};
};
in
{
flake = {
inherit nixosConfigurations;
ops = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./ops;
profiles = [
"base"
"interface.minimal"
"platform.vm"
"workload.remote-access"
"workload.deploy-rs-target"
];
};
netsrv-01 = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./netsrv-01;
profiles = [
"base"
"interface.minimal"
"platform.vm"
"workload.remote-access"
"workload.deploy-rs-target"
"workload.server"
];
};
installer = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./installer;
homeManager = false;
profiles = [ "base" ];
};
x1g9 = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./x1g9;
profiles = [
"base"
"interface.cli"
"interface.labwc"
"interface.niri"
"platform.thinkpad-x1"
"security.fingerprint"
# "security.secrets"
"workload.personal"
];
};
x1g13 = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./x1g13;
profiles = [
"base"
"interface.cli"
"interface.labwc"
"interface.niri"
"networking.tailscale-client"
"platform.thinkpad-x1"
"security.fingerprint"
"security.secrets"
"security.secure-boot"
"security.tpm-storage"
"workload.development"
"workload.game"
"workload.network-lab"
"workload.personal"
];
};
galleria = {
system = "x86_64-linux";
stateVersion = "26.05";
user = "moons";
path = ./galleria;
profiles = [
"base"
"interface.cli"
"interface.labwc"
"interface.niri"
"networking.tailscale-client"
"platform.intel-nvidia-desktop"
"security.secrets"
"security.secure-boot"
"security.tpm-storage"
"security.fingerprint"
"workload.development"
"workload.game"
"workload.machine-learning"
"workload.network-lab"
"workload.personal"
"workload.photography"
"workload.camera"
];
};
m2 = {
system = "aarch64-darwin";
stateVersion = "26.05";
user = "moons";
path = ./m2;
profiles = [
"base"
"interface.cli"
"interface.macos"
"security.fingerprint"
# "security.secrets"
"workload.development"
"workload.game"
"workload.personal"
];
checks.x86_64-linux = lib.mapAttrs' (
name: nixos: lib.nameValuePair "nixos-${name}" nixos.config.system.build.toplevel
) nixosConfigurations;
};
}
-91
View File
@@ -1,91 +0,0 @@
_:
let
espPart = "/dev/disk/by-partuuid/008b04ef-9c06-4049-bffb-3906f5c3a9c1";
nixosPart = "/dev/disk/by-partuuid/04295552-cbb8-4511-ac1e-1171ec20f8d1";
btrfsMountOptions = [
"compress=zstd"
"noatime"
"ssd"
"space_cache=v2"
];
in
{
disko.enableConfig = true;
# These are deliberately partition paths, not the whole Windows disk. Disko
# must never own or destroy the disk's GPT or any Windows partition.
disko.devices.disk = {
esp = {
type = "disk";
device = espPart;
destroy = false;
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
nixos = {
type = "disk";
device = nixosPart;
destroy = false;
content = {
type = "luks";
name = "cryptroot";
askPassword = true;
settings.allowDiscards = true;
extraFormatArgs = [
"--type"
"luks2"
"--pbkdf"
"argon2id"
"--label"
"NixOS-LUKS"
];
content = {
type = "btrfs";
extraArgs = [
"-f"
"-L"
"NixOS"
];
subvolumes = {
"@root" = {
mountpoint = "/";
mountOptions = btrfsMountOptions;
};
"@home" = {
mountpoint = "/home";
mountOptions = btrfsMountOptions;
};
"@nix" = {
mountpoint = "/nix";
mountOptions = btrfsMountOptions;
};
"@log" = {
mountpoint = "/var/log";
mountOptions = btrfsMountOptions;
};
"@swap" = {
mountpoint = "/.swapvol";
mountOptions = [ "noatime" ];
swap.swapfile.size = "32G";
};
};
};
};
};
};
}
-30
View File
@@ -1,30 +0,0 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{
config,
lib,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [
"xhci_pci"
"ahci"
"nvme"
"usbhid"
"usb_storage"
"sd_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
-51
View File
@@ -1,51 +0,0 @@
{
lib,
config,
...
}:
{
# This desktop is permanently connected to AC power.
systemd.user.services.swayidle.Service.Environment = [
"SWAYIDLE_ASSUME_AC=1"
];
services.kanshi = {
enable = true;
settings = [
{
profile = {
name = "galleria";
outputs = [
{
criteria = "HDMI-A-1";
status = "enable";
position = "0,0";
scale = 1.5;
}
{
criteria = "DP-1";
status = "enable";
position = "2560,0";
}
{
criteria = "DP-2";
status = "enable";
position = "5120,0";
scale = 1.5;
}
];
};
}
];
};
home.file.".wallpapers" = {
source = lib.mkForce (
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/Pictures/wallpapers"
);
recursive = lib.mkForce false;
};
}
-21
View File
@@ -1,21 +0,0 @@
{ inputs, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
./disko.nix
];
boot.initrd.luks.devices.cryptroot.device =
"/dev/disk/by-partuuid/04295552-cbb8-4511-ac1e-1171ec20f8d1";
# Keep Windows data and recovery partitions out of UDisks-based file
# managers. The shared EFI System Partition stays available as /boot.
services.udev.extraRules = ''
ENV{ID_PART_ENTRY_UUID}=="0480f887-d1f9-489d-b8fe-78549ced1938", ENV{UDISKS_IGNORE}="1"
ENV{ID_PART_ENTRY_UUID}=="6c70041b-3f65-4eb1-8b08-18ed20001877", ENV{UDISKS_IGNORE}="1"
'';
environment.systemPackages = with inputs.browser-previews.packages.${pkgs.system}; [
google-chrome-beta
];
}
@@ -5,7 +5,9 @@
...
}:
{
imports = [ "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" ];
imports = [
"${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix"
];
boot.zfs.forceImportRoot = false;
@@ -31,32 +33,26 @@
users.users.root.openssh.authorizedKeys.keys = [
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIKhxDkucmeCor6CKoXAua7DgDSzuXrZOtpdkyzQxz5+aAAAABHNzaDo= moons@moons14.com"
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIN6hZJyng/5LgFKPjR6uZAd/00UkO0vN0uQOoIvfSELdAAAABHNzaDo= moons@moons14.com"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPLwReAiwhXoO34S2+MrvqUhi8IWp4IzUq4OSp3niJdq"
];
environment.systemPackages = with pkgs; [
git
disko
sops
age
ssh-to-age
age-plugin-yubikey
yubikey-manager
pcsc-tools
mkpasswd
rsync
vim
wget
curl
jq
parted
cryptsetup
btrfs-progs
efibootmgr
pciutils
sbctl
tpm2-tools
util-linux
git # Clone dotfiles repository
disko # Disk partitioning
sops # Secrets management
age # Age encryption
ssh-to-age # Convert SSH keys to age
age-plugin-yubikey # YubiKey support
yubikey-manager # YubiKey management
pcsc-tools # Smart card tools
mkpasswd # Password hash generation
rsync # File synchronization
vim # Text editor
wget # Download files
curl # HTTP client
jq # JSON processor
parted # Partition tools
cryptsetup # LUKS encryption
btrfs-progs # Btrfs filesystem tools
];
services.pcscd.enable = true;
@@ -76,12 +72,6 @@
║ ║
║ Installation Workflow: ║
║ ║
║ Choose a guide after cloning: ║
║ Simple: docs/install-simple.md ║
║ SOPS + LUKS: docs/install.md ║
║ ║
║ The workflow below is for SOPS + LUKS: ║
║ ║
║ 1. Clone dotfiles: ║
║ git clone git@github.com:moons-14/dotfiles.git ~/dotfiles║
║ ║
@@ -109,25 +99,37 @@
║ # See hosts/x1g13/disko.nix for reference ║
║ ║
║ 7. Partition disk with disko: ║
║ disko --mode destroy,format,mount \ ║
║ hosts/<host>/disko.nix ║
║ nix run github:nix-community/disko -- \ ║
║ --mode disko hosts/<host>/disko.nix ║
║ ║
║ 8. Generate hardware configuration: ║
║ nixos-generate-config --no-filesystems --root /mnt \ ║
║ --show-hardware-config > \ ║
║ ~/dotfiles/hosts/<host>/hardware-configuration.nix ║
║ # Import hardware-configuration.nix and disko.nix ║
║ # from hosts/<host>/nixos.nix ║
║ ║
║ 9. Copy host key to installed system: ║
║ 8. Copy host key to installed system: ║
║ mkdir -p /mnt/etc/ssh ║
║ cp /tmp/ssh_host_ed25519_key* /mnt/etc/ssh/ ║
║ chmod 600 /mnt/etc/ssh/ssh_host_ed25519_key ║
║ ║
║ 10. Install NixOS: ║
║ 9. Install NixOS: ║
║ nixos-install --flake ~/dotfiles#<host> ║
║ ║
║ LUKS + btrfs (see hosts/x1g13/disko.nix): ║
║ Disko Configuration Examples: ║
║ ║
║ Simple (no encryption): ║
║ disko.devices.disk.main = { ║
║ type = "disk"; ║
║ device = "/dev/sda"; ║
║ content = { ║
║ type = "gpt"; ║
║ partitions = { ║
║ ESP = { size = "512M"; type = "EF00"; ║
║ content = { type = "filesystem"; ║
║ format = "vfat"; mountpoint = "/boot"; }; }; ║
║ root = { size = "100%"; ║
║ content = { type = "filesystem"; ║
║ format = "ext4"; mountpoint = "/"; }; }; ║
║ }; ║
║ }; ║
║ }; ║
║ ║
║ LUKS + btrfs (see hosts/x1g13/disko.nix): ║
║ - Use partuuid for device path ║
║ - Set askPassword = true for LUKS ║
║ - Configure btrfs subvolumes ║
@@ -186,4 +188,6 @@
};
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
system.stateVersion = "26.05";
}
@@ -1,3 +1,4 @@
{ ... }:
{
imports = [
./hardware-configuration.nix
@@ -20,6 +20,20 @@
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/1b12ab98-2537-4207-a3f4-bb8ba7b53b00";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/8365-C778";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
swapDevices = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
-10
View File
@@ -1,10 +0,0 @@
{ hostName, ... }:
{
# networking.hostName and networking.localHostName are derived from the
# registry name; computerName controls the user-visible macOS name.
networking.computerName = hostName;
# Keep this value stable after the first activation. It is independent of
# the Home Manager stateVersion in hosts/default.nix.
system.stateVersion = 7;
}
-30
View File
@@ -1,30 +0,0 @@
_: {
disko.enableConfig = true;
disko.devices.disk.main = {
type = "disk";
device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0";
content = {
type = "gpt";
partitions = {
ESP = {
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
}
@@ -1,27 +0,0 @@
# QEMU hardware baseline. Replace this with the output of
# `nixos-generate-config` after provisioning the VM if its hardware differs.
{
lib,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [
"ata_piix"
"uhci_hcd"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}
-40
View File
@@ -1,40 +0,0 @@
{
networking = {
interfaces = {
ens18 = {
useDHCP = false;
ipv4.addresses = [
{
address = "10.50.65.11";
prefixLength = 24;
}
];
};
ens19 = {
useDHCP = false;
ipv4.addresses = [
{
address = "10.50.66.10";
prefixLength = 24;
}
];
};
ens20 = {
useDHCP = false;
ipv4.addresses = [
{
address = "10.50.77.21";
prefixLength = 24;
}
];
};
};
defaultGateway = {
address = "10.50.66.1";
interface = "ens19";
};
};
}
-66
View File
@@ -1,66 +0,0 @@
_:
let
osDisk = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0";
in
{
disko.enableConfig = true;
# The VM disks already contain live filesystems. Model each existing
# filesystem without giving Disko ownership of their partitioning or data.
disko.devices.disk = {
boot = {
type = "disk";
device = "${osDisk}-part1";
destroy = false;
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
root = {
type = "disk";
device = "${osDisk}-part2";
destroy = false;
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
nix-build = {
type = "disk";
device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi1";
destroy = false;
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/var/lib/nix-build";
mountOptions = [ "noatime" ];
};
};
nix-store = {
type = "disk";
device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi2";
destroy = false;
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/nix/store";
mountOptions = [ "noatime" ];
};
};
};
fileSystems."/nix/store".neededForBoot = true;
nix.settings.build-dir = "/var/lib/nix-build";
services.fstrim.enable = true;
}
-83
View File
@@ -1,83 +0,0 @@
{
config,
pkgs,
primaryUser,
...
}:
let
homeDirectory = "/home/${primaryUser}";
fleetDirectory = "${homeDirectory}/srv/nix-fleet";
stateDirectory = "/var/lib/nix-fleet";
sourceDirectory = "${stateDirectory}/source";
git = "${pkgs.git}/bin/git";
nix = "${config.nix.package}/bin/nix";
rsync = "${pkgs.rsync}/bin/rsync";
cleanCheckoutConditions = [
"${git} -C ${fleetDirectory} diff --quiet"
"${git} -C ${fleetDirectory} diff --cached --quiet"
];
in
{
systemd.services.nix-fleet-converge = {
description = "Update inputs, build the fleet, and deploy changed hosts";
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
environment = {
HOME = homeDirectory;
NIX_CONFIG = ''
accept-flake-config = true
max-jobs = 4
cores = 3
'';
};
serviceConfig = {
Type = "oneshot";
User = primaryUser;
Restart = "on-failure";
RestartSec = "5min";
StateDirectory = "nix-fleet";
StateDirectoryMode = "0750";
WorkingDirectory = stateDirectory;
UMask = "0077";
ExecCondition = cleanCheckoutConditions;
EnvironmentFile = "${fleetDirectory}/.env";
# Work in a disposable copy so updating the dotfiles lock never dirties
# the operator's nix-fleet checkout.
ExecStart = [
"${git} -C ${fleetDirectory} pull --ff-only"
"${rsync} --archive --delete --exclude=.git/ --exclude=.direnv/ --exclude=.env --exclude=result --exclude=result-* ${fleetDirectory}/ ${sourceDirectory}/"
"${nix} flake update --flake ${sourceDirectory} dotfiles"
"${nix} run ${sourceDirectory}#converge -- ${sourceDirectory} ${stateDirectory}"
];
};
};
systemd.timers.nix-fleet-converge = {
description = "Periodically converge the NixOS fleet";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "2min";
OnUnitInactiveSec = "5min";
RandomizedDelaySec = "30s";
Persistent = true;
Unit = "nix-fleet-converge.service";
};
};
# Only an actual successful deployment touches gc-request. This starts the
# builder's root nh-clean unit; remote host stores are never cleaned here.
systemd.paths.nix-fleet-gc = {
description = "Garbage-collect superseded fleet builds on nix-builder";
wantedBy = [ "multi-user.target" ];
pathConfig = {
PathChanged = "${stateDirectory}/gc-request";
Unit = "nh-clean.service";
};
};
}
-37
View File
@@ -1,37 +0,0 @@
{
lib,
...
}:
{
nix.settings = {
build-dir = "/var/lib/nix-build";
secret-key-files = [
"/var/lib/secrets/nix-cache-signing-key"
];
auto-optimise-store = lib.mkForce false;
keep-outputs = false;
keep-derivations = true;
};
services.harmonia.cache = {
enable = true;
signKeyPaths = [
"/var/lib/secrets/nix-cache-signing-key"
];
settings = {
bind = "[::]:5000";
priority = 30;
workers = 4;
};
};
networking.firewall.allowedTCPPorts = [
5000
];
}
-40
View File
@@ -1,40 +0,0 @@
{
networking = {
interfaces = {
ens18 = {
useDHCP = false;
ipv4.addresses = [
{
address = "10.50.65.10";
prefixLength = 24;
}
];
};
ens19 = {
useDHCP = false;
ipv4.addresses = [
{
address = "10.50.77.10";
prefixLength = 24;
}
];
};
ens20 = {
useDHCP = false;
ipv4.addresses = [
{
address = "10.50.68.10";
prefixLength = 24;
}
];
};
};
defaultGateway = {
address = "10.50.68.1";
interface = "ens20";
};
};
}
-9
View File
@@ -1,9 +0,0 @@
{
imports = [
./fleet-automation.nix
./disko.nix
./hardware-configuration.nix
./harmonia.nix
./networking.nix
];
}
@@ -1,7 +1,6 @@
{ ... }:
{
imports = [
./hardware-configuration.nix
./disko.nix
./networking.nix
];
}
@@ -0,0 +1,43 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{
lib,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [
"ata_piix"
"uhci_hcd"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/8f0eaec6-5dc9-4821-aa8d-fb6809b5a5bf";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/201C-961B";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
swapDevices = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}
@@ -1,11 +1,18 @@
{ ... }:
{
imports = [
./hardware-configuration.nix
];
networking = {
useDHCP = false;
interfaces = {
ens18 = {
useDHCP = false;
ipv4.addresses = [
{
address = "10.50.65.100";
address = "10.50.128.20";
prefixLength = 24;
}
];
@@ -15,7 +22,7 @@
useDHCP = false;
ipv4.addresses = [
{
address = "10.50.80.10";
address = "10.50.7.101";
prefixLength = 24;
}
];
@@ -23,18 +30,27 @@
ens20 = {
useDHCP = false;
ipv4.routes = [
{
address = "10.50.64.0";
prefixLength = 24;
via = "10.50.82.1";
}
];
ipv4.addresses = [
{
address = "10.50.77.20";
address = "10.50.82.10";
prefixLength = 24;
}
];
};
};
defaultGateway = {
address = "10.50.80.1";
interface = "ens19";
address = "10.50.128.1";
interface = "ens18";
};
};
}
-30
View File
@@ -1,30 +0,0 @@
_: {
disko.enableConfig = true;
disko.devices.disk.main = {
type = "disk";
device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0";
content = {
type = "gpt";
partitions = {
ESP = {
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
}
+16
View File
@@ -24,5 +24,21 @@
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/69fa2193-1e4f-438a-8898-5de8a3f36e5b";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/D09B-4277";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
swapDevices = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}
-7
View File
@@ -1,7 +0,0 @@
{
imports = [
./hardware-configuration.nix
./networking.nix
./disko.nix
];
}
@@ -1,3 +1,4 @@
{ ... }:
{
imports = [
./hardware-configuration.nix
+13 -3
View File
@@ -1,6 +1,7 @@
_:
let
espPart = "/dev/disk/by-partuuid/a53e3b19-67de-40de-9ded-3eac3117689a";
nixosPart = "/dev/disk/by-partuuid/311d0f9c-f35f-42e6-b6fc-a4d67dd21b2e";
btrfsMountOptions = [
@@ -23,7 +24,9 @@ in
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
mountOptions = [
"umask=0077"
];
};
};
@@ -35,8 +38,12 @@ in
content = {
type = "luks";
name = "cryptroot";
askPassword = true;
settings.allowDiscards = true;
settings = {
allowDiscards = true;
};
extraFormatArgs = [
"--type"
@@ -78,7 +85,10 @@ in
"@swap" = {
mountpoint = "/.swapvol";
mountOptions = [ "noatime" ];
mountOptions = [
"noatime"
];
swap.swapfile.size = "32G";
};
};
+3 -2
View File
@@ -1,5 +1,6 @@
# Do not modify this file! It was generated by `nixos-generate-config`
# and may be overwritten by future invocations. Make changes in nixos.nix.
# Do not modify this file! It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{
config,
lib,
-22
View File
@@ -1,22 +0,0 @@
{
services.kanshi = {
enable = true;
settings = [
{
profile = {
name = "x1g13";
outputs = [
{
criteria = "eDP-1";
status = "enable";
position = "0,0";
scale = 1.5;
}
];
};
}
];
};
}
-52
View File
@@ -1,52 +0,0 @@
# Do not modify this file! It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{
config,
lib,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [
"xhci_pci"
"thunderbolt"
"nvme"
"usb_storage"
"sd_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/16b29578-6836-414b-a5e1-863bc21c5fc3";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/209A-C8C9";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp0s20f3.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
-17
View File
@@ -1,17 +0,0 @@
{
inputs,
lib ? inputs.nixpkgs.lib,
root,
}:
let
registry = import ./registry.nix {
inherit inputs lib;
modulesRoot = root + "/modules";
};
hosts = import ./hosts.nix {
inherit inputs lib registry;
};
in
{
inherit hosts registry;
}
-191
View File
@@ -1,191 +0,0 @@
{
inputs,
lib,
registry,
}:
let
ensure =
condition: message: value:
if condition then value else throw "host registry: ${message}";
isLinux = system: lib.hasSuffix "-linux" system;
isDarwin = system: lib.hasSuffix "-darwin" system;
hostFile =
spec: name:
let
path = spec.path + "/${name}";
in
if builtins.pathExists path then path else null;
selectedUnits =
spec:
[ "users.${spec.user}" ]
++ map (name: "profiles.${name}") (spec.profiles or [ ])
++ map (name: "applications.${name}") (spec.applications or [ ])
++ (spec.units or [ ]);
validateSpec =
name: spec:
ensure (builtins.isAttrs spec) "${name}: host specification must be an attribute set" (
ensure (spec ? system && builtins.isString spec.system) "${name}: system is required" (
ensure (isLinux spec.system || isDarwin spec.system)
"${name}: unsupported system '${spec.system}'; expected a Linux NixOS or Darwin system"
(
ensure (spec ? user && builtins.isString spec.user && spec.user != "") "${name}: user is required" (
ensure (spec ? path && builtins.pathExists spec.path)
"${name}: path must name an existing host directory"
(
ensure
(
spec ? stateVersion
&& builtins.isString spec.stateVersion
&& builtins.match "[0-9][0-9]\\.[0-9][0-9]" spec.stateVersion != null
)
"${name}: stateVersion is required and must have the form YY.MM"
(
ensure
(lib.all
(field: builtins.isList (spec.${field} or [ ]) && lib.all builtins.isString (spec.${field} or [ ]))
[
"profiles"
"applications"
"units"
]
)
"${name}: profiles, applications, and units must be lists of strings"
(ensure (builtins.isBool (spec.homeManager or true)) "${name}: homeManager must be a boolean" spec)
)
)
)
)
)
);
mkSpecialArgs = name: spec: {
inherit inputs registry;
inherit (spec) system;
hostName = name;
primaryUser = spec.user;
};
mkHomeManagerModule =
name: spec: selected:
let
homePath = hostFile spec "home.nix";
homeModules = [
(registry.mkModule {
class = "home";
systemClass = "nixos";
})
(registry.mkSelectionModule selected)
{ home.stateVersion = spec.stateVersion; }
]
++ lib.optional (homePath != null) homePath;
in
{
imports = [ inputs.home-manager.nixosModules.home-manager ];
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = mkSpecialArgs name spec;
users.${spec.user}.imports = homeModules;
};
};
mkDarwinHomeManagerModule =
name: spec: selected:
let
homePath = hostFile spec "home.nix";
homeModules = [
(registry.mkModule {
class = "home";
systemClass = "darwin";
})
(registry.mkSelectionModule selected)
{ home.stateVersion = spec.stateVersion; }
]
++ lib.optional (homePath != null) homePath;
in
{
imports = [ inputs.home-manager.darwinModules.home-manager ];
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = mkSpecialArgs name spec;
users.${spec.user}.imports = homeModules;
};
};
mkNixos =
name: rawSpec:
let
spec = validateSpec name rawSpec;
selected = registry.validateUnitIds (selectedUnits spec);
nixosPath = hostFile spec "nixos.nix";
modules = [
(registry.mkModule { class = "nixos"; })
(registry.mkSelectionModule selected)
{
networking.hostName = lib.mkDefault name;
system.stateVersion = spec.stateVersion;
}
]
++ lib.optional (spec.homeManager or true) (mkHomeManagerModule name spec selected)
++ lib.optional (nixosPath != null) nixosPath;
in
inputs.nixpkgs.lib.nixosSystem {
inherit (spec) system;
specialArgs = mkSpecialArgs name spec;
inherit modules;
};
mkDarwin =
name: rawSpec:
let
spec = validateSpec name rawSpec;
selected = registry.validateUnitIds (selectedUnits spec);
darwinPath = hostFile spec "darwin.nix";
modules = [
(registry.mkModule { class = "darwin"; })
(registry.mkSelectionModule selected)
{
networking.hostName = lib.mkDefault name;
system.primaryUser = lib.mkDefault spec.user;
}
]
++ lib.optional (spec.homeManager or true) (mkDarwinHomeManagerModule name spec selected)
++ lib.optional (darwinPath != null) darwinPath;
in
ensure (inputs ? nix-darwin) "${name}: the nix-darwin input is required" (
inputs.nix-darwin.lib.darwinSystem {
inherit (spec) system;
specialArgs = mkSpecialArgs name spec;
inherit modules;
}
);
mkConfigurations =
hostSpecs:
let
validated = lib.mapAttrs validateSpec hostSpecs;
in
{
nixosConfigurations = lib.mapAttrs mkNixos (
lib.filterAttrs (_: spec: isLinux spec.system) validated
);
darwinConfigurations = lib.mapAttrs mkDarwin (
lib.filterAttrs (_: spec: isDarwin spec.system) validated
);
};
in
{
inherit
mkConfigurations
mkDarwin
mkNixos
selectedUnits
;
}
-386
View File
@@ -1,386 +0,0 @@
{
inputs,
lib,
modulesRoot,
}:
let
rootFragmentFiles = {
common = "common.nix";
nixos = "nixos.nix";
darwin = "darwin.nix";
home = "home.nix";
meta = "meta.nix";
};
homeFragmentFiles = {
homeCommon = "common.nix";
homeNixos = "nixos.nix";
homeDarwin = "darwin.nix";
};
fragmentFileNames = rootFragmentFiles // lib.mapAttrs (_: name: "home/${name}") homeFragmentFiles;
isFile = kind: kind == "regular" || kind == "symlink";
ensure =
condition: message: value:
if condition then value else throw "unit registry: ${message}";
callWithAvailableArgs =
value: availableArgs:
if builtins.isFunction value then
value (builtins.intersectAttrs (builtins.functionArgs value) availableArgs)
else
value;
pathFor =
relativePath:
if relativePath == [ ] then
modulesRoot
else
modulesRoot + "/${lib.concatStringsSep "/" relativePath}";
entryIsFile = entries: name: builtins.hasAttr name entries && isFile entries.${name};
normalizeMeta =
unit:
let
metaPath = unit.fragments.meta;
importedValue =
if metaPath == null then
{ }
else
callWithAvailableArgs (import metaPath) {
inherit inputs lib unit;
};
imported =
ensure (builtins.isAttrs importedValue) "${unit.id}: meta.nix must return an attribute set"
importedValue;
allowedKeys = [
"description"
"includes"
"imports"
];
unknownKeys = lib.filter (name: !(builtins.elem name allowedKeys)) (builtins.attrNames imported);
description = imported.description or null;
includes = imported.includes or [ ];
imports = imported.imports or { };
allowedImportKeys = [
"nixos"
"darwin"
"home"
];
unknownImportKeys =
if builtins.isAttrs imports then
lib.filter (name: !(builtins.elem name allowedImportKeys)) (builtins.attrNames imports)
else
[ ];
normalized = {
inherit description includes;
imports = {
nixos = imports.nixos or [ ];
darwin = imports.darwin or [ ];
home = imports.home or [ ];
};
};
in
ensure (unknownKeys == [ ])
"${unit.id}: meta.nix has unsupported keys: ${lib.concatStringsSep ", " unknownKeys}"
(
ensure (description == null || builtins.isString description)
"${unit.id}: meta.description must be a string"
(
ensure (builtins.isList includes && lib.all builtins.isString includes)
"${unit.id}: meta.includes must be a list of fully qualified unit IDs"
(
ensure (lib.unique includes == includes) "${unit.id}: meta.includes contains duplicate unit IDs" (
ensure (builtins.isAttrs imports) "${unit.id}: meta.imports must be an attribute set" (
ensure (unknownImportKeys == [ ])
"${unit.id}: meta.imports has unsupported classes: ${lib.concatStringsSep ", " unknownImportKeys}"
(
ensure (lib.all builtins.isList [
normalized.imports.nixos
normalized.imports.darwin
normalized.imports.home
]) "${unit.id}: every meta.imports.<class> value must be a list" normalized
)
)
)
)
)
);
makeUnit =
relativePath: entries: homeEntries:
let
directory = pathFor relativePath;
id = lib.concatStringsSep "." relativePath;
rootFragments = lib.mapAttrs (
_class: fileName: if entryIsFile entries fileName then directory + "/${fileName}" else null
) rootFragmentFiles;
homeFragments = lib.mapAttrs (
_class: fileName: if entryIsFile homeEntries fileName then directory + "/home/${fileName}" else null
) homeFragmentFiles;
fragments = rootFragments // homeFragments;
baseUnit = {
inherit
id
directory
fragments
relativePath
;
optionPath = [ "my" ] ++ relativePath ++ [ "enable" ];
kind = builtins.head relativePath;
name = lib.last relativePath;
}
//
lib.optionalAttrs (builtins.length relativePath > 2 && builtins.head relativePath == "profiles")
{
group = builtins.elemAt relativePath 1;
};
in
ensure (relativePath != [ ]) "the modules root cannot itself be a unit" (
ensure (lib.all (component: component != "" && !(lib.hasInfix "." component)) relativePath)
"${id}: path components must be non-empty and must not contain dots"
(baseUnit // { meta = normalizeMeta baseUnit; })
);
walk =
relativePath:
let
directory = pathFor relativePath;
entries = builtins.readDir directory;
homeEntries =
if relativePath != [ ] && (entries.home or null) == "directory" then
builtins.readDir (directory + "/home")
else
{ };
hasRootFragment = lib.any (fileName: entryIsFile entries fileName) (
builtins.attrValues rootFragmentFiles
);
hasHomeFragment = lib.any (fileName: entryIsFile homeEntries fileName) (
builtins.attrValues homeFragmentFiles
);
hasFragment = hasRootFragment || hasHomeFragment;
childDirectories = lib.filter (
name: entries.${name} == "directory" && !(name == "home" && hasHomeFragment)
) (builtins.attrNames entries);
current = lib.optional hasFragment (makeUnit relativePath entries homeEntries);
children = lib.concatMap (name: walk (relativePath ++ [ name ])) childDirectories;
in
current ++ children;
discoveredUnits =
ensure (builtins.pathExists modulesRoot) "modules root does not exist: ${toString modulesRoot}"
(walk [ ]);
unitsById = builtins.listToAttrs (map (unit: lib.nameValuePair unit.id unit) discoveredUnits);
dependencyValidation = lib.foldl' (
valid: unit:
lib.foldl' (
inner: includedId:
if builtins.hasAttr includedId unitsById then
inner
else
throw "unit registry: ${unit.id} includes missing unit '${includedId}'"
) valid unit.meta.includes
) true discoveredUnits;
units = builtins.seq dependencyValidation unitsById;
unitIds = builtins.attrNames units;
getUnit =
id: if builtins.hasAttr id units then units.${id} else throw "unit registry: unknown unit '${id}'";
validateUnitIds =
ids:
ensure (
builtins.isList ids && lib.all builtins.isString ids
) "selected units must be a list of strings" (map (id: builtins.seq (getUnit id) id) ids);
optionDefinitions = lib.foldl' lib.recursiveUpdate { } (
map (
unit:
lib.setAttrByPath unit.optionPath (
lib.mkOption {
type = lib.types.bool;
default = false;
description =
if unit.meta.description == null then
"Whether to enable the ${unit.id} unit."
else
"Whether to enable ${unit.meta.description}.";
}
)
) discoveredUnits
);
enabled = config: unit: lib.getAttrFromPath unit.optionPath config;
enableUnit = id: lib.setAttrByPath (getUnit id).optionPath true;
includeConfig =
config: unit: lib.mkIf (enabled config unit) (lib.mkMerge (map enableUnit unit.meta.includes));
fragmentClasses = {
nixos = [
"common"
"nixos"
];
darwin = [
"common"
"darwin"
];
home = {
nixos = [
"home"
"homeCommon"
"homeNixos"
];
darwin = [
"home"
"homeCommon"
"homeDarwin"
];
};
};
fragmentClassesFor =
{
class,
systemClass,
}:
ensure (builtins.hasAttr class fragmentClasses) "unsupported module class '${class}'" (
if class == "home" then
ensure
(builtins.elem systemClass [
"nixos"
"darwin"
])
"the home module class requires systemClass to be 'nixos' or 'darwin'"
fragmentClasses.home.${systemClass}
else
ensure (
systemClass == null
) "systemClass is only supported for the home module class" fragmentClasses.${class}
);
applyFragment =
{
config,
fragmentName,
fragmentPath,
options,
specialArgs,
unit,
}:
let
fragment = import fragmentPath;
directArgs = specialArgs // {
inherit
config
lib
options
specialArgs
unit
;
};
fragmentArgSpec = builtins.functionArgs fragment;
fragmentArgs = builtins.listToAttrs (
lib.concatMap (
name:
if builtins.hasAttr name directArgs then
[ (lib.nameValuePair name directArgs.${name}) ]
else if fragmentArgSpec.${name} then
[ ]
else
[ (lib.nameValuePair name config._module.args.${name}) ]
) (builtins.attrNames fragmentArgSpec)
);
resultValue = if builtins.isFunction fragment then fragment fragmentArgs else fragment;
result =
ensure (builtins.isAttrs resultValue) "${unit.id}: ${fragmentName} must return an attribute set"
resultValue;
forbiddenKeys = lib.filter (name: builtins.hasAttr name result) [
"imports"
"options"
"config"
];
in
ensure (forbiddenKeys == [ ])
"${unit.id}: ${fragmentName} is a configuration fragment and cannot define top-level ${lib.concatStringsSep ", " forbiddenKeys}"
result;
externalImports = class: lib.concatMap (unit: unit.meta.imports.${class}) discoveredUnits;
mkModule =
{
class,
systemClass ? null,
}:
let
selectedFragmentClasses = fragmentClassesFor { inherit class systemClass; };
in
builtins.seq selectedFragmentClasses (
builtins.seq dependencyValidation (
{
config,
lib,
options,
specialArgs,
...
}:
let
fragmentConfigs = lib.concatMap (
unit:
lib.filter (value: value != null) (
map (
fragmentClass:
let
fragmentName = fragmentFileNames.${fragmentClass};
fragmentPath = unit.fragments.${fragmentClass};
in
if fragmentPath == null then
null
else
lib.mkIf (enabled config unit) (applyFragment {
inherit
config
fragmentName
fragmentPath
options
specialArgs
unit
;
})
) selectedFragmentClasses
)
) discoveredUnits;
in
{
imports = externalImports class;
options = optionDefinitions;
config = lib.mkMerge ((map (includeConfig config) discoveredUnits) ++ fragmentConfigs);
}
)
);
mkSelectionModule =
selectedIds:
let
checkedIds = validateUnitIds (lib.unique selectedIds);
in
{
config = lib.mkMerge (map enableUnit checkedIds);
};
in
{
inherit
getUnit
mkModule
mkSelectionModule
unitIds
units
validateUnitIds
;
}
+26
View File
@@ -0,0 +1,26 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications."1password";
in
{
options.my.applications."1password" = {
enable = lib.mkEnableOption "1Password password manager";
};
config = lib.mkIf cfg.enable {
programs._1password.enable = true;
programs._1password-gui = {
enable = true;
polkitPolicyOwners = [ "moons" ];
};
programs.ssh.startAgent = lib.mkForce false;
programs.gnupg.agent.enableSSHSupport = lib.mkForce false;
services.gnome.gcr-ssh-agent.enable = lib.mkForce false;
};
}
@@ -1,4 +0,0 @@
_: {
programs._1password-gui.enable = true;
programs._1password.enable = true;
}
-9
View File
@@ -1,9 +0,0 @@
{ primaryUser, lib, ... }:
{
programs._1password-gui.polkitPolicyOwners = [ primaryUser ];
# 1Password SSH Agentと競合するagentを無効化
programs.ssh.startAgent = lib.mkForce false;
programs.gnupg.agent.enableSSHSupport = lib.mkForce false;
services.gnome.gcr-ssh-agent.enable = lib.mkForce false;
}
@@ -1,8 +0,0 @@
{
homebrew.casks = [ "activitywatch" ];
launchd.agents.activitywatch = {
command = "/usr/bin/open -gja ActivityWatch";
serviceConfig.RunAtLoad = true;
};
}
@@ -1,11 +0,0 @@
{ pkgs, ... }:
{
services.activitywatch = {
enable = true;
watchers.aw-awatcher = {
package = pkgs.awatcher;
executable = "awatcher";
};
};
}
@@ -1,3 +0,0 @@
{
description = "ActivityWatch automated time tracker";
}
+29
View File
@@ -0,0 +1,29 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.arduino;
arduinoIdeX11 = pkgs.arduino-ide.overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.makeWrapper ];
postFixup = (old.postFixup or "") + ''
wrapProgram $out/bin/arduino-ide \
--add-flags "--ozone-platform=x11"
'';
});
in
{
options.my.applications.arduino = {
enable = lib.mkEnableOption "Arduino development tools";
};
config = lib.mkIf cfg.enable {
environment.systemPackages = with pkgs; [
arduino-cli # Arduino command-line interface
arduinoIdeX11 # Arduino IDE with X11 support
];
};
}
-4
View File
@@ -1,4 +0,0 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.arduino-cli ];
}
-14
View File
@@ -1,14 +0,0 @@
{ pkgs, ... }:
let
arduinoIdeX11 = pkgs.arduino-ide.overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.makeWrapper ];
postFixup = (old.postFixup or "") + ''
wrapProgram $out/bin/arduino-ide \
--add-flags "--ozone-platform=x11"
'';
});
in
{
environment.systemPackages = [ arduinoIdeX11 ];
}
-9
View File
@@ -1,9 +0,0 @@
{
programs.atuin = {
enable = true;
enableZshIntegration = true;
enableBashIntegration = true;
enableFishIntegration = true;
};
}
-4
View File
@@ -1,4 +0,0 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.baobab ];
}
+23
View File
@@ -0,0 +1,23 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.btop;
in
{
imports = [
./home.nix
./system.nix
];
options.my.applications.btop = {
enable = lib.mkEnableOption "btop system monitor";
};
config = lib.mkIf cfg.enable {
my.applications.btop.system.enable = lib.mkDefault true;
my.applications.btop.homeManager.enable = lib.mkDefault true;
};
}
+3 -3
View File
@@ -1,5 +1,5 @@
# Bashtop theme with Nord palette (https://www.nordtheme.com)
# by Justin Zobel <[email protected]>
#Bashtop theme with nord palette (https://www.nordtheme.com)
#by Justin Zobel <[email protected]>
# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: "#RRGGBB", "#BW" or "0-255 0-255 0-255"
# example for white: "#ffffff", "#ff" or "255 255 255".
@@ -18,7 +18,7 @@ theme[main_fg]="#BD93F9"
# Title color for boxes
theme[title]="#f8f8f2"
# Highlight color for keyboard shortcuts
# Higlight color for keyboard shortcuts
theme[hi_fg]="#ff79c6"
# Background color of selected item in processes box
+22 -5
View File
@@ -1,8 +1,25 @@
{
programs.btop = {
enable = true;
settings.color_theme = "dracula";
themes.dracula = builtins.readFile ./dracula.theme;
lib,
config,
...
}:
let
cfg = config.my.applications.btop.homeManager;
in
{
options.my.applications.btop.homeManager = {
enable = lib.mkEnableOption "btop home-manager configuration";
};
config.home-manager.sharedModules = [
{
config = lib.mkIf cfg.enable {
programs.btop = {
enable = true;
settings.color_theme = "dracula";
themes.dracula = builtins.readFile ./dracula.theme;
};
};
}
];
}
+20
View File
@@ -0,0 +1,20 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.btop.system;
in
{
options.my.applications.btop.system = {
enable = lib.mkEnableOption "btop system configuration";
};
config = lib.mkIf cfg.enable {
environment.systemPackages = with pkgs; [
btop # Resource monitor that shows usage and stats
];
};
}
@@ -1,31 +0,0 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.celluloid ];
xdg.mimeApps = {
enable = true;
defaultApplicationPackages = [ pkgs.celluloid ];
defaultApplications = builtins.listToAttrs (
map
(mime: {
name = mime;
value = [ "io.github.celluloid_player.Celluloid.desktop" ];
})
[
"video/3gpp"
"video/3gpp2"
"video/mp2t"
"video/mp4"
"video/mpeg"
"video/ogg"
"video/quicktime"
"video/webm"
"video/x-flv"
"video/x-m4v"
"video/x-matroska"
"video/x-msvideo"
"video/x-ms-wmv"
]
);
};
}
+44
View File
@@ -0,0 +1,44 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.chrome;
in
{
options.my.applications.chrome = {
enable = lib.mkEnableOption "Google Chrome browser";
};
config = lib.mkIf cfg.enable {
home-manager.sharedModules = [
{
home.packages = with pkgs; [
google-chrome # Popular web browser from Google
];
xdg.desktopEntries."google-chrome" = {
name = "Google Chrome";
genericName = "Web Browser";
exec = "${pkgs.google-chrome}/bin/google-chrome-stable --enable-features=TouchpadOverscrollHistoryNavigation %U";
terminal = false;
icon = "google-chrome";
categories = [
"Network"
"WebBrowser"
];
startupNotify = true;
type = "Application";
};
xdg.mimeApps.defaultApplications = {
"text/html" = "google-chrome.desktop";
"x-scheme-handler/http" = "google-chrome.desktop";
"x-scheme-handler/https" = "google-chrome.desktop";
};
}
];
};
}
-6
View File
@@ -1,6 +0,0 @@
{
homebrew = {
enable = true;
casks = [ "google-chrome" ];
};
}
@@ -1,47 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
chrome = pkgs.google-chrome.overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.makeWrapper ];
postFixup = (old.postFixup or "") + ''
wrapProgram $out/bin/google-chrome-stable \
--set LIBVA_DRIVER_NAME nvidia \
--set NVD_BACKEND direct
'';
});
features = [
"MiddleClickAutoscroll"
"AcceleratedVideoDecoder"
"AcceleratedVideoDecodeLinuxGL"
"PlatformHEVCDecoderSupport"
]
++ lib.optional config.my.hardwares.nvidia.enable "VaapiOnNvidiaGPUs";
in
{
programs.google-chrome = {
enable = true;
package = if config.my.hardwares.nvidia.enable then chrome else pkgs.google-chrome;
commandLineArgs = [
"--enable-features=${lib.concatStringsSep "," features}"
"--use-gl=angle"
"--use-angle=gl"
];
};
xdg.mimeApps = {
enable = true;
defaultApplications = {
"text/html" = "google-chrome.desktop";
"x-scheme-handler/http" = "google-chrome.desktop";
"x-scheme-handler/https" = "google-chrome.desktop";
};
};
}
+23
View File
@@ -0,0 +1,23 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.claude;
in
{
imports = [
./home.nix
./system.nix
];
options.my.applications.claude = {
enable = lib.mkEnableOption "Claude Code AI assistant";
};
config = lib.mkIf cfg.enable {
my.applications.claude.system.enable = lib.mkDefault true;
my.applications.claude.homeManager.enable = lib.mkDefault true;
};
}
+21 -12
View File
@@ -1,18 +1,27 @@
{
inputs,
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.claude.homeManager;
in
{
home.packages = [
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.claude-code
];
home.file.".claude/settings.json".text = builtins.toJSON {
statusLine = {
type = "command";
command = "bun x ccusage statusline --no-offline";
padding = 0;
};
options.my.applications.claude.homeManager = {
enable = lib.mkEnableOption "Claude Code home-manager configuration";
};
config.home-manager.sharedModules = [
{
config = lib.mkIf cfg.enable {
home.file.".claude/settings.json".text = builtins.toJSON {
statusLine = {
type = "command";
command = "bun x ccusage statusline --no-offline";
padding = 0;
};
};
};
}
];
}
+20
View File
@@ -0,0 +1,20 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.claude.system;
in
{
options.my.applications.claude.system = {
enable = lib.mkEnableOption "Claude Code system configuration";
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [
pkgs.llm-agents.claude-code # AI coding assistant
];
};
}
+65
View File
@@ -0,0 +1,65 @@
{
inputs,
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.codexDesktop;
codexCliPackage = pkgs.llm-agents.codex;
codexDesktopPackage =
inputs.codex-desktop-linux.packages.${pkgs.stdenv.hostPlatform.system}.codex-desktop-computer-use-ui;
codexDesktopLauncher = pkgs.makeDesktopItem {
name = "codex";
desktopName = "Codex";
genericName = "ChatGPT Desktop";
comment = "Run Codex Desktop on Linux";
exec = "env CODEX_CLI_PATH=${lib.getExe' codexCliPackage "codex"} BAMF_DESKTOP_FILE_HINT=codex.desktop CHROME_DESKTOP=codex.desktop ${lib.getExe' codexDesktopPackage "codex-desktop"} %u";
icon = "codex-desktop";
terminal = false;
categories = [ "Development" ];
keywords = [
"codex"
"chatgpt"
"openai"
"ai"
"assistant"
];
startupNotify = true;
startupWMClass = "codex-desktop";
actions = {
new-window = {
name = "New Window";
exec = "env CODEX_CLI_PATH=${lib.getExe' codexCliPackage "codex"} BAMF_DESKTOP_FILE_HINT=codex.desktop CHROME_DESKTOP=codex.desktop CODEX_MULTI_LAUNCH=1 ${lib.getExe' codexDesktopPackage "codex-desktop"} --new-instance";
};
};
extraConfig = {
X-GNOME-WMClass = "codex-desktop";
};
};
in
{
imports = [
inputs.codex-desktop-linux.nixosModules.default
];
options.my.applications.codexDesktop = {
enable = lib.mkEnableOption "ChatGPT Desktop for Linux";
};
config = lib.mkIf cfg.enable {
my.applications.codex.enable = true;
programs.codexDesktopLinux = {
enable = true;
package = codexDesktopPackage;
cliPackage = codexCliPackage;
computerUseUi.enable = true;
};
environment.systemPackages = [
codexDesktopLauncher # Vicinae-searchable Codex Desktop launcher alias
];
};
}
@@ -1,8 +0,0 @@
{
# The former Codex app cask is deprecated in favor of ChatGPT, whose desktop
# application includes the current Codex experience on macOS.
homebrew = {
enable = true;
casks = [ "chatgpt" ];
};
}
@@ -1,5 +0,0 @@
_: {
description = "Codex Desktop for Linux";
includes = [ "applications.codex" ];
}
@@ -1,10 +0,0 @@
{
inputs,
pkgs,
...
}:
{
environment.systemPackages = [
inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.chatgpt
];
}
@@ -1,52 +0,0 @@
{
lib,
pkgs,
inputs,
...
}:
let
codexSessionUsage = inputs.codex-session-usage.packages.${pkgs.stdenv.hostPlatform.system}.default;
in
{
home.packages = [ codexSessionUsage ];
xdg.dataFile = {
"vicinae/scripts/codex-session-usage/start" = {
executable = true;
text = ''
#!${lib.getExe pkgs.bash}
# @vicinae.schemaVersion 1
# @vicinae.title Start Codex Session Usage
# @vicinae.description Start the local Codex session usage dashboard
# @vicinae.mode compact
# @vicinae.icon 📊
# @vicinae.argument1 { "type": "text", "placeholder": "Port (optional)", "optional": true }
if [[ -z "$1" ]]; then
exec ${lib.getExe codexSessionUsage} start
fi
if [[ "$1" =~ ^[0-9]+$ ]] && (( 10#$1 >= 1 && 10#$1 <= 65535 )); then
exec ${lib.getExe codexSessionUsage} start --port "$1"
fi
printf '%s\n' 'Port must be an integer between 1 and 65535.' >&2
exit 2
'';
};
"vicinae/scripts/codex-session-usage/stop" = {
executable = true;
text = ''
#!${lib.getExe pkgs.bash}
# @vicinae.schemaVersion 1
# @vicinae.title Stop Codex Session Usage
# @vicinae.description Stop the local Codex session usage dashboard
# @vicinae.mode compact
# @vicinae.icon 📊
exec ${lib.getExe codexSessionUsage} stop
'';
};
};
}
+20
View File
@@ -0,0 +1,20 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.codex;
in
{
options.my.applications.codex = {
enable = lib.mkEnableOption "Codex AI coding assistant";
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [
pkgs.llm-agents.codex # OpenAI Codex CLI
];
};
}
-13
View File
@@ -1,13 +0,0 @@
model = "gpt-5.6-sol"
model_reasoning_effort = "medium"
approval_policy = "on-request"
approvals_reviewer = "auto_review"
sandbox_mode = "workspace-write"
web_search = "cached"
[sandbox_workspace_write]
network_access = false
[projects."/home/moons/dotfiles"]
trust_level = "trusted"
-36
View File
@@ -1,36 +0,0 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
configDirectory =
if config.home.preferXdgDirectories then
"${config.xdg.configHome}/codex"
else
"${config.home.homeDirectory}/.codex";
configFile = "${configDirectory}/config.toml";
in
{
programs.codex = {
enable = true;
package = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.codex;
skills = {
grilling = inputs.skills + "/skills/productivity/grilling";
};
};
# Keep the repository copy as an initial value. Codex may mutate the live
# file between activations; each Home Manager switch resets it from here.
home.activation.resetCodexConfig = {
after = [ "writeBoundary" ];
before = [ ];
data = ''
${pkgs.coreutils}/bin/mkdir -p ${lib.escapeShellArg configDirectory}
${pkgs.coreutils}/bin/install -m 0600 ${./config.toml} ${lib.escapeShellArg configFile}
'';
};
}
@@ -1,8 +0,0 @@
{ inputs, ... }:
{
description = "Container-based networking labs";
includes = [ "services.docker" ];
imports.nixos = [ inputs.containerlab.nixosModules.default ];
}
@@ -1,17 +0,0 @@
{
inputs,
pkgs,
primaryUser,
}:
{
programs.containerlab.enable = true;
users.users.${primaryUser}.extraGroups = [ "clab_admins" ];
programs.containerlab.package =
inputs.containerlab.packages.${pkgs.stdenv.hostPlatform.system}.default.overrideAttrs
(_old: {
vendorHash = "sha256-Na2s9GdyYo2e/8dLAs5NPT0auEWq4MKQcnngjaO3r9M=";
});
}
@@ -1,22 +0,0 @@
{
inputs,
osConfig,
pkgs,
...
}:
let
unstable = import inputs.nixpkgs-unstable {
inherit (pkgs.stdenv.hostPlatform) system;
# Keep default CUDA targets so dependencies match the CUDA binary cache.
config = pkgs.config // {
cudaSupport = osConfig.my.hardwares.nvidia.enable;
};
};
in
{
home.packages = [
(unstable.darktable.override {
withAi = true;
})
];
}
+47
View File
@@ -0,0 +1,47 @@
{
imports = [
./1password.nix
./arduino.nix
./btop
./chrome.nix
./claude
./codex-desktop.nix
./codex.nix
./direnv.nix
./discord.nix
./docker.nix
./fcitx5
./ghostty
./git
./gnupg
./grok.nix
./gnome.nix
./greetd.nix
./ly
./gtk
./java
./kde.nix
./nautilus.nix
./nh.nix
./niri
./nix-index
./noctalia
./opencode.nix
./openssh.nix
./slack.nix
./ssh
./swayidle.nix
./swaylock
./tailscale.nix
./vicinae.nix
./vim
./vscode
./wayland.nix
./yazi.nix
./zed
./zellij
./zoom.nix
./zoxide.nix
./zsh
];
}
+16
View File
@@ -0,0 +1,16 @@
{ lib, config, ... }:
let
cfg = config.my.applications.direnv;
in
{
options.my.applications.direnv = {
enable = lib.mkEnableOption "direnv environment variable manager";
};
config = lib.mkIf cfg.enable {
programs.direnv = {
enable = true;
nix-direnv.enable = true;
};
};
}
-10
View File
@@ -1,10 +0,0 @@
{
programs.direnv = {
enable = true;
nix-direnv.enable = true;
config.global = {
warn_timeout = "10s";
};
};
}
+23
View File
@@ -0,0 +1,23 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.discord;
in
{
options.my.applications.discord = {
enable = lib.mkEnableOption "Discord (Vesktop)";
};
config = lib.mkIf cfg.enable {
home-manager.sharedModules = [
{
programs.vesktop = {
enable = true;
};
}
];
};
}
-108
View File
@@ -1,108 +0,0 @@
{
inputs,
pkgs,
...
}:
let
unstable = inputs.nixpkgs-unstable.legacyPackages.${pkgs.stdenv.hostPlatform.system};
in
{
programs.vesktop = {
enable = true;
package = unstable.vesktop;
settings = {
discordBranch = "stable";
hardwareAcceleration = true;
hardwareVideoAcceleration = true;
tray = true;
minimizeToTray = true;
# Discord Rich Presence
arRPC = true;
openLinksWithElectron = false;
# Keep WebRTC on the public interface selected by the default route.
# Secondary private interfaces can otherwise stall voice at DTLS.
webRTCIPHandlingPolicy = "default_public_interface_only";
spellCheckLanguages = [
"ja-JP"
"en-US"
];
};
vencord = {
useSystem = false;
settings = {
autoUpdate = true;
autoUpdateNotification = false;
useQuickCss = false;
cloud.settingsSync = false;
notifications = {
position = "bottom-right";
useNative = "not-focused";
timeout = 5000;
logLimit = 50;
};
plugins = {
# プライバシー・安全性
NoTrack.enabled = true;
ClearURLs.enabled = true;
# 設定・セッション
BetterSettings.enabled = true;
BetterSessions.enabled = true;
# 画像・添付ファイル
FixImagesQuality.enabled = true;
ImageZoom.enabled = true;
ViewIcons.enabled = true;
CopyFileContents.enabled = true;
# メッセージ操作
QuickReply.enabled = true;
SendTimestamps.enabled = true;
FullSearchContext.enabled = true;
MessageLinkEmbeds.enabled = true;
Unindent.enabled = true;
ValidReply.enabled = true;
# 通知・誤操作対策
ReadAllNotificationsButton.enabled = true;
NoReplyMention.enabled = true;
NotificationVolume.enabled = true;
# UI・パフォーマンス
NoTypingAnimation.enabled = true;
FavoriteEmojiFirst.enabled = true;
KeepCurrentChannel.enabled = true;
# サーバー・権限確認
PermissionsViewer.enabled = true;
MemberCount.enabled = true;
# ボイス・アクティビティ
CallTimer.enabled = true;
GameActivityToggle.enabled = true;
# Vesktop向け
WebKeybinds.enabled = true;
WebScreenShareFixes.enabled = true;
# Message history
MessageLogger.enabled = true;
ShowHiddenChannels.enabled = true;
};
};
};
};
}
+34
View File
@@ -0,0 +1,34 @@
{
pkgs,
lib,
config,
...
}:
let
cfg = config.my.applications.docker;
in
{
options.my.applications.docker = {
enable = lib.mkEnableOption "Docker container runtime";
};
config = lib.mkIf cfg.enable {
virtualisation.docker = {
enable = true;
autoPrune = {
enable = true;
dates = "weekly";
};
daemon.settings = {
ipv6 = true;
"fixed-cidr-v6" = "fd00:30::/64";
ip6tables = true;
};
};
environment.systemPackages = with pkgs; [
docker # Container runtime
oxker # Docker TUI Tool
];
};
}
-6
View File
@@ -1,6 +0,0 @@
{
homebrew = {
enable = true;
casks = [ "orbstack" ];
};
}
@@ -1,6 +0,0 @@
{ pkgs, ... }:
{
home.packages = [
pkgs.docker-client
];
}
@@ -1,6 +0,0 @@
{ pkgs, ... }:
{
home.packages = [
pkgs.oxker
];
}
-5
View File
@@ -1,5 +0,0 @@
{
description = "Docker command-line client and NixOS daemon";
includes = [ "services.docker" ];
}
-4
View File
@@ -1,4 +0,0 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.drawio ];
}
@@ -1,4 +0,0 @@
{ pkgs, ... }:
{
home.packages = [ pkgs.easyeffects ];
}
+69
View File
@@ -0,0 +1,69 @@
[Hotkey]
# トリガーキーを押すたびに切り替える
EnumerateWithTriggerKeys=False
# 一時的に第1入力メソッドに切り替える
AltTriggerKeys=
# 切り替え時は第1入力メソッドをスキップする
EnumerateSkipFirst=False
# Time limit in milliseconds for triggering modifier key shortcuts
ModifierOnlyKeyTimeout=250
[Hotkey/TriggerKeys]
1=Zenkaku_Hankaku
[Hotkey/ActivateKeys]
0=Henkan
[Hotkey/DeactivateKeys]
0=Muhenkan
[Hotkey/PrevPage]
0=Up
[Hotkey/NextPage]
0=Down
[Hotkey/PrevCandidate]
0=Shift+Tab
[Hotkey/NextCandidate]
0=Tab
[Hotkey/TogglePreedit]
0=Control+Alt+P
[Behavior]
# デフォルトで有効にする
ActiveByDefault=False
# フォーカス時に状態をリセット
resetStateWhenFocusIn=No
# 入力状態を共有する
ShareInputState=No
# アプリケーションにプリエディットを表示する
PreeditEnabledByDefault=True
# 入力メソッドを切り替える際に入力メソッドの情報を表示する
ShowInputMethodInformation=True
# フォーカスを変更する際に入力メソッドの情報を表示する
showInputMethodInformationWhenFocusIn=False
# 入力メソッドの情報をコンパクトに表示する
CompactInputMethodInformation=True
# 第1入力メソッドの情報を表示する
ShowFirstInputMethodInformation=True
# デフォルトのページサイズ
DefaultPageSize=5
# XKB オプションより優先する
OverrideXkbOption=False
# カスタム XKB オプション
CustomXkbOption=
# Force Enabled Addons
EnabledAddons=
# Force Disabled Addons
DisabledAddons=
# Preload input method to be used by default
PreloadInputMethod=True
# パスワード欄に入力メソッドを許可する
AllowInputMethodForPassword=False
# パスワード入力時にプリエディットテキストを表示する
ShowPreeditForPassword=False
# ユーザーデータを保存する間隔(分)
AutoSavePeriod=30
+23
View File
@@ -0,0 +1,23 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.fcitx5;
in
{
imports = [
./home.nix
./system.nix
];
options.my.applications.fcitx5 = {
enable = lib.mkEnableOption "fcitx5 input method";
};
config = lib.mkIf cfg.enable {
my.applications.fcitx5.system.enable = lib.mkDefault true;
my.applications.fcitx5.homeManager.enable = lib.mkDefault true;
};
}
+24
View File
@@ -0,0 +1,24 @@
{
lib,
config,
...
}:
let
cfg = config.my.applications.fcitx5.homeManager;
in
{
options.my.applications.fcitx5.homeManager = {
enable = lib.mkEnableOption "fcitx5 home-manager configuration";
};
config.home-manager.sharedModules = [
{
config = lib.mkIf cfg.enable {
home.file.".config/fcitx5/config" = {
recursive = true;
source = ./config;
};
};
}
];
}
@@ -1,82 +0,0 @@
{ inputs, pkgs, ... }:
{
services.hazkey = {
enable = true;
server.package =
inputs.nix-hazkey.packages.${pkgs.stdenv.hostPlatform.system}.hazkey-server.override
{ enableVulkan = true; };
};
i18n.inputMethod = {
enable = true;
type = "fcitx5";
fcitx5 = {
waylandFrontend = true;
addons = with pkgs; [
fcitx5-gtk
kdePackages.fcitx5-qt
qt6Packages.fcitx5-configtool
];
settings = {
inputMethod = {
GroupOrder."0" = "Default";
"Groups/0" = {
Name = "Default";
"Default Layout" = "jp";
DefaultIM = "hazkey";
};
"Groups/0/Items/0" = {
Name = "keyboard-jp";
};
"Groups/0/Items/1" = {
Name = "hazkey";
};
};
globalOptions = {
Hotkey = {
EnumerateWithTriggerKeys = false;
EnumerateSkipFirst = false;
ModifierOnlyKeyTimeout = 250;
};
"Hotkey/TriggerKeys"."1" = "Zenkaku_Hankaku";
"Hotkey/ActivateKeys"."0" = "Henkan";
"Hotkey/DeactivateKeys"."0" = "Muhenkan";
"Hotkey/PrevPage"."0" = "Up";
"Hotkey/NextPage"."0" = "Down";
"Hotkey/PrevCandidate"."0" = "Shift+Tab";
"Hotkey/NextCandidate"."0" = "Tab";
"Hotkey/TogglePreedit"."0" = "Control+Alt+P";
Behavior = {
ActiveByDefault = false;
resetStateWhenFocusIn = "No";
ShareInputState = "No";
PreeditEnabledByDefault = true;
ShowInputMethodInformation = true;
showInputMethodInformationWhenFocusIn = false;
CompactInputMethodInformation = true;
ShowFirstInputMethodInformation = true;
DefaultPageSize = 5;
OverrideXkbOption = false;
CustomXkbOption = "";
EnabledAddons = "";
DisabledAddons = "";
PreloadInputMethod = true;
AllowInputMethodForPassword = false;
ShowPreeditForPassword = false;
AutoSavePeriod = 30;
};
};
};
};
};
}

Some files were not shown because too many files have changed in this diff Show More