Imported from arecarn/dotfiles (
AGENTS.md). Install upstream withnpx skills add arecarn/dotfiles. Copyright stays with the author.
Agent Context File
Project Overview
This repository manages personal configuration files (dotfiles) across Linux and Windows. It provides an automated way to provision system packages and symlink configurations to the user's home directory.
- Main Technologies: Python,
uv(package management),invoke(task running),dploy(symlink management), andAnsible(Linux provisioning). - Core Architecture:
- Tool Configurations: Located in root-level directories (e.g.,
git/,nvim/,tmux/,zsh/). - Provisioning: Ansible task files in
ansible/tasks/for Linux systems, imported byansible/site.yml. - Task Automation:
tasks.pydefines the CLI interface for management.
- Tool Configurations: Located in root-level directories (e.g.,
Agent knowledge
Read agents-knowledge/index.md before searching the repo. It is an index
plus topic documents covering pi configuration, MCP servers, provisioning, and
this repo's own knowledge integration. Open only the entries whose descriptions
match your task -- one of them usually names the file you were about to go
looking for. These are facts and procedures; the rules in this file take
precedence.
Building and Running
The project uses uv for environment management. Tasks are executed via invoke.
| Task | Command | Description |
|---|---|---|
| Setup Environment | uv sync |
Install Python dependencies. |
| Stow Configurations | uv run inv stow |
Symlink dotfiles into the home directory using dploy. |
| Unstow | uv run inv unstow |
Remove symlinks created by stow. |
| Provision System | uv run inv provision |
Install system packages (Ansible on Linux, Chocolatey on Windows). |
| Linting | uv run inv lint |
Run all linters (ShellCheck, yamllint, Pylint, Ruff, stylua, luacheck, Biome, tsc). |
| Clean Repo | uv run inv clean |
Interactively clean untracked files using git clean. |
Development Conventions
- Cross-Platform Compatibility: Logic in
tasks.pydetects the environment (Windows, Linux) to ensure tasks likeprovisionandstowuse the correct platform-specific tools. - Symlink Strategy:
dployis used to map stow package directories to the home directory. New stow packages must be added to theStowPlanclass inmanage/stow.py. - This repo is public: config that is private goes in a
dotfiles_localrepo instead — employer-internal hostnames, registries, proxies, project or team names, work email addresses, VPN or corporate tooling, and equally any personal config the user would not publish. Adotfiles_localexists per work or personal setup, and can span several machines. Keep what lands here public-safe and portable. uv runrewritesuv.lockto the machine's configured package index, so an unrelateduv run inv lintleaves ~250 changed lines pointing at an internal host. Revert it (git checkout -- uv.lock) before every commit and nevergit add -Ahere — see docs/gotchas/uv-run-rewrites-uv-lock-to-an-internal-registry.md.- Windows symlink privilege: stowing on Windows needs an elevated shell or Developer Mode — see docs/gotchas/windows-symlink-creation-needs-elevation.md.
- Linting Standards:
- Python:
ruffandpylint. - Shell:
shellcheck. - YAML:
yamllint. - Lua:
styluaandluacheck. - TypeScript:
biome(lint and format) andtsc --noEmit(types), both from the project's ownpnpminstall rather than a global one.
- Python:
- The TypeScript toolchain installs itself:
lint_typescripthas apnpm_installpre-task that runspnpm install --frozen-lockfilewhennode_modules/is absent, so a fresh clone can lint and push with no manual setup. CI relies on this too and has no install step of its own — but pnpm only reaches PATH via provisioning, so linting before provisioning finds none. - Branch, don't PR. The user is the sole author and user of this repo, so
changes go straight to
mainonce CI is green. After the work is approved, carry the whole cycle without re-asking per step: branch, commit, push, watch CI by SHA, and on green merge--no-ffintomain, push, and delete the branch. A red run is different — investigate and report, never merge or push a speculative fix. Don't open a pull request or hand back a "create a PR" link as the deliverable. - Watch CI after every push, using the
watch-ciskill. A green local run is not evidence — see docs/gotchas/lint-passing-locally-proves-nothing-about-ci.md for why. The skill is the procedure: it selects the run by commit SHA and workflow, tells a cancelled run from a failed one, and survives a dropped connection. Do not improvise a poll loop or follow a recipe written here or anywhere else in this repo instead — a repo-local variant is how those distinctions get lost. CI here takes ~7 min. - Private instructions are read, not imported: the generated instruction files
point every agent at
~/.config/ai-instructions/local.md, which adotfiles_localrepo places there and which never enters this repo. Claude's@imports are no longer used, so their resolution rules no longer apply here. - Instruction files are generated: global and project instruction files are
assembled from fragments in
agents/.config/ai-instructions/byuv run inv gen-instructions, permanifest.yaml. Edit the fragments, never the generated files;inv lintfails on drift. Fragments carry no harness-specific syntax (no@imports, no glob arrays) because pi expands none, so every harness gets the same flat content. - Agent knowledge is reference material, not instructions. Bundles are
discovered, never declared: a directory under
~/.config/ai-knowledge/is a bundle, and a project opts in by committingagents-knowledge/index.mdat its worktree root. Reference detail belongs in a bundle; a rule that always applies belongs in these fragments. Runagent-knowledge statusto see what applies where.
Agent skills
Issue tracker
Issues live as GitHub issues on arecarn/dotfiles, managed with the gh CLI. See docs/agents/issue-tracker.md.
Triage labels
The five canonical triage roles used verbatim as label strings, plus a local blocked state and two closure reasons. Single-participant tracker, so parts of the skills' reporter model do not apply. See docs/agents/triage-labels.md.
Domain docs
Single-context: one CONTEXT.md plus docs/adr/ at the repo root, both created lazily. See docs/agents/domain.md.
Gotchas
docs/gotchas/ holds non-obvious traps confirmed the hard way, so the same debugging is not paid for twice. Search with grep -ri "<term>" docs/gotchas/. The record-gotcha and review-gotchas skills drive writing and re-verifying entries.
This directory is not the whole set. A trap that cannot be described without private detail (internal hostnames, employer tooling, credential variable names, project or team names) is recorded in the dotfiles_local checkout instead, so searching here alone can come up empty on a trap already known. Search both:
grep -ri "<term>" docs/gotchas/ ~/dotfiles_local/ 2>/dev/null
When recording a new one, put it wherever it can be stated fully: public-safe traps here, everything else there. Split an entry across both when only part of it is sensitive — the public half describes the mechanism and the private half supplies the specifics. A missing dotfiles_local is normal; the grep just finds nothing.
- One trap per file, named for the trap, leading with the symptom you would grep for mid-debug. Deliberately unnumbered, unlike ADRs: entries are deleted when they stop reproducing, which would leave numbering gappy.
- A gotcha is not an ADR. Something decided — alternatives weighed, a call made — goes in
docs/adr/. Something the system simply does, that nobody chose, goes here. - Every entry ends with a
**Confirmed:**line — the date it last reproduced and what against. Without it a live trap is indistinguishable from one fixed two years ago. Never backfill a date you cannot stand behind; writeunknown, predates this convention. - Review on a trigger, not a calendar: when a tool an entry names is upgraded, when its symptom recurs, or when you open it mid-debug and it does not help. Then update the
**Confirmed:**line, or delete the entry if it no longer reproduces or a check now prevents it. Deletion is the goal, not the failure case — a trap engineered out of existence beats the best entry describing it.