aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimen A. W. Olsen <hello@simenandre.no>2026-10-27 10:42:44 +0100
committerSimen A. W. Olsen <hello@simenandre.no>2026-10-27 10:42:44 +0100
commitc541a5fe232ebc7fe8b96ee47499fccd36ea7856 (patch)
tree476c47f3744a5bcb71ae89a238309df4071d3014
parent4b93cc8c2e1f3a00927055bccfc7fbd024693c5c (diff)
downloaddotfiles-c541a5fe232ebc7fe8b96ee47499fccd36ea7856.tar.gz
dotfiles-c541a5fe232ebc7fe8b96ee47499fccd36ea7856.zip
feat(claude): manage agent skills with the skills CLI
-rw-r--r--flake.lock23
-rw-r--r--flake.nix7
-rw-r--r--modules/home/claude.nix103
-rw-r--r--modules/home/default.nix1
-rw-r--r--skills.json28
-rw-r--r--skills.lock47
6 files changed, 116 insertions, 93 deletions
diff --git a/flake.lock b/flake.lock
index f8bffff..25c0b59 100644
--- a/flake.lock
+++ b/flake.lock
@@ -118,7 +118,28 @@
"dina": "dina",
"home-manager": "home-manager",
"nix-darwin": "nix-darwin",
- "nixpkgs": "nixpkgs"
+ "nixpkgs": "nixpkgs",
+ "skills": "skills"
+ }
+ },
+ "skills": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1792928488,
+ "narHash": "sha256-xjenS3UGyQq8WhLxLSHaCaJEP3+2wxF0aBij/y1xJQY=",
+ "ref": "refs/heads/main",
+ "rev": "c596038adc7cdbd64988e61fee856d533b58c25d",
+ "revCount": 1,
+ "type": "git",
+ "url": "https://git.simenandre.no/skills"
+ },
+ "original": {
+ "type": "git",
+ "url": "https://git.simenandre.no/skills"
}
},
"systems": {
diff --git a/flake.nix b/flake.nix
index f09a764..b23079e 100644
--- a/flake.nix
+++ b/flake.nix
@@ -25,6 +25,11 @@
url = "github:dinacomputer/cli/0277ff9e82107ee9a582ae6e0da1258a44a60e1a";
inputs.nixpkgs.follows = "nixpkgs";
};
+
+ skills = {
+ url = "git+https://git.simenandre.no/skills";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
};
outputs =
@@ -35,6 +40,7 @@
home-manager,
config-nvim,
dina,
+ skills,
}:
let
# flakeAttr must match the darwinConfigurations attribute this machine is
@@ -42,6 +48,7 @@
# each machine targets its own configuration.
mkHomeModules = { username, flakeAttr ? "default" }: [
./modules/home
+ skills.homeManagerModules.default
{
home.username = username;
home.file.".config/nvim".source = config-nvim;
diff --git a/modules/home/claude.nix b/modules/home/claude.nix
index 7edca3d..d141130 100644
--- a/modules/home/claude.nix
+++ b/modules/home/claude.nix
@@ -1,7 +1,9 @@
-{ ... }:
+{ config, ... }:
{
- home.file.".claude/CLAUDE.md".text = ''
+ programs.claude-code.enable = true;
+
+ programs.claude-code.context = ''
# Code Style
- ONLY use comments to explain weird code or non-obvious behaviour, never to explain simple code.
@@ -30,93 +32,12 @@
- When ending a conversation or the user says goodbye, use `/session end` to clean up.
'';
- home.file.".claude/skills/session/SKILL.md".text = ''
- ---
- name: session
- description: Start or end a work session — annotates via Loggie and sets the tmux window title.
- allowed-tools: mcp__loggie__annotate, Bash(tmux rename-window *)
- ---
-
- # /session — Work Session Management
-
- You are executing the /session skill. This skill manages Loggie annotations and tmux window titles.
-
- ## Arguments
-
- - `/session <description>` — Start or update the current session with a description of what you're working on.
- - `/session end` — End the current session.
-
- ## Starting / Updating a Session
-
- 1. Use the Loggie `annotate` MCP tool with the provided description. Keep it short and descriptive (e.g. "Fixing auth bug in login flow", "Adding CSV export endpoint").
- 2. Set the tmux window title using `tmux rename-window "<title>"`. The title should be very short and recognizable — it does not need to match the annotation exactly.
-
- ## Ending a Session
-
- 1. Call the Loggie `annotate` MCP tool with an empty string to stop the current annotation.
- 2. Reset the tmux window title using `tmux rename-window "zsh"`.
- '';
-
- home.file.".claude/skills/push/SKILL.md".text = ''
- ---
- name: push
- description: Create a commit and push changes. Optionally creates a branch and opens a PR with an intelligently chosen reviewer.
- disable-model-invocation: true
- ---
-
- # /push — Commit & Push Workflow
-
- You are executing the /push skill. Follow these steps precisely.
-
- ## Step 1: Analyze Changes
-
- Run `git status` and `git diff` (staged + unstaged) to understand all current changes.
- If there are no changes to commit, inform the user and stop.
-
- ## Step 2: Stage Files
-
- Stage the relevant files. Prefer `git add <specific files>` over `git add -A`.
- Never stage files that look like secrets (.env, credentials, tokens).
-
- ## Step 3: Ask — Branch or Main?
-
- Use the **AskUserQuestion** tool to ask the user how to push. Example:
-
- - question: "How should this be pushed?"
- - header: "Push target"
- - options:
- - label: "Current branch", description: "Push directly to the current branch"
- - label: "New branch + PR", description: "Create a new branch and open a pull request"
-
- ### If "Current branch":
-
- - Run `git push` (with `-u` if needed).
- - Done.
-
- ### If "New branch + PR":
-
- 1. Create a descriptive branch name based on the changes (e.g., `feat/add-logging`, `fix/null-check-user`).
- 2. Check out the new branch and push with `-u`.
- 3. **Choose a reviewer:**
- - Run `git log --format='%an' -50 | sort | uniq -c | sort -rn | head -10` to find active contributors.
- - Cross-reference with files changed: run `git log --format='%an' -- <changed-files> | sort | uniq -c | sort -rn | head -5` to find who has context on the modified code.
- - Pick the most relevant reviewer (not the current user — check with `git config user.name`).
- - Build a list of up to 4 candidate reviewers and use **AskUserQuestion** to let the user pick. Example:
- - question: "Who should review this PR?"
- - header: "Reviewer"
- - options: one per candidate, with description showing their commit count / relevance to changed files.
- 4. Create the PR using `gh pr create`:
- - Short title (under 70 chars).
- - Body with a `## Summary` section (2-3 bullet points) and a `## Test plan` section.
- - Add the confirmed reviewer with `--reviewer`.
- 5. Return the PR URL to the user.
-
- ## Step 4: Create Commit
-
- - Analyze the staged diff.
- - Write a concise commit message using **conventional commit format** (e.g., `feat:`, `fix:`, `refactor:`, `chore:`, `docs:`, `test:`, `ci:`). Include a scope when it adds clarity (e.g., `feat(auth):`, `fix(api):`).
- - Output ONLY the raw commit message — no markdown, no code blocks, no backticks, no explanations.
- - **Do NOT add a Co-Authored-By line. Never include any co-author trailer.**
- - Create the commit using a HEREDOC for the message.
- '';
+ # Skills come from skills.json/skills.lock at the repo root; manage them
+ # with the `skills` CLI. los, ups and dina-cli install their own skills,
+ # generated from binaries that live in ~/go/bin rather than Nix.
+ programs.skills = {
+ enable = true;
+ lockFile = ../../skills.lock;
+ manifest = "${config.home.homeDirectory}/ghq/simenandre.no/dotfiles/skills.json";
+ };
}
diff --git a/modules/home/default.nix b/modules/home/default.nix
index 229f8ce..2bd21df 100644
--- a/modules/home/default.nix
+++ b/modules/home/default.nix
@@ -31,7 +31,6 @@
home.packages = with pkgs; [
aerc
- claude-code
dina.packages.${pkgs.stdenv.hostPlatform.system}.default
delta
forgejo-cli
diff --git a/skills.json b/skills.json
new file mode 100644
index 0000000..06323ac
--- /dev/null
+++ b/skills.json
@@ -0,0 +1,28 @@
+{
+ "sources": {
+ "adaa": {
+ "source": "getadaa/plugins",
+ "skills": [
+ "adaa"
+ ]
+ },
+ "mine": {
+ "source": "git@simenandre.no:agent-skills"
+ },
+ "security-audit": {
+ "source": "cloudflare/security-audit-skill"
+ },
+ "simenandre": {
+ "source": "git@simenandre.no:server",
+ "skills": [
+ "simenandre"
+ ]
+ },
+ "skills": {
+ "source": "https://git.simenandre.no/skills",
+ "skills": [
+ "skills"
+ ]
+ }
+ }
+}
diff --git a/skills.lock b/skills.lock
new file mode 100644
index 0000000..b3bf515
--- /dev/null
+++ b/skills.lock
@@ -0,0 +1,47 @@
+{
+ "version": 1,
+ "sources": {
+ "adaa": {
+ "url": "https://github.com/getadaa/plugins",
+ "rev": "d8cefe444d8756309a109031267368dfb517d822",
+ "narHash": "sha256-5UHhqIt7AgzDEgdpsCfzuYef63ht4khcjHiDjWGTIXg=",
+ "skills": {
+ "adaa": "plugins/adaa/skills/adaa"
+ }
+ },
+ "mine": {
+ "url": "ssh://git@simenandre.no/agent-skills",
+ "rev": "d533ba9e3d6ac7dbe5eb796caec1dfb03fd0d7dc",
+ "narHash": "sha256-uzcAELfJM5WdlTkfK4mUgp5GhNGJKxc/4CJzMqcYlS4=",
+ "skills": {
+ "deslop": "deslop",
+ "push": "push",
+ "session": "session"
+ }
+ },
+ "security-audit": {
+ "url": "https://github.com/cloudflare/security-audit-skill",
+ "rev": "c1c8a8c1471069fb0e188eeaff69b8e8db6564a8",
+ "narHash": "sha256-oVVACjotkHvllQGxEP8yWaEt4c3GxT0d909TUM5P3NM=",
+ "skills": {
+ "security-audit": "skills/security-audit"
+ }
+ },
+ "simenandre": {
+ "url": "ssh://git@simenandre.no/server",
+ "rev": "6e864983b50d1e8661040e731231bc0016810948",
+ "narHash": "sha256-C60RJqM5AWc+n3tc5/FwNbtTPkBY/NM/dstLJCzLbYI=",
+ "skills": {
+ "simenandre": "skill/simenandre"
+ }
+ },
+ "skills": {
+ "url": "https://git.simenandre.no/skills",
+ "rev": "c596038adc7cdbd64988e61fee856d533b58c25d",
+ "narHash": "sha256-xjenS3UGyQq8WhLxLSHaCaJEP3+2wxF0aBij/y1xJQY=",
+ "skills": {
+ "skills": "skill/skills"
+ }
+ }
+ }
+}