Imported from wsdjeg/altf.nvim (
AGENTS.md). Install upstream withnpx skills add wsdjeg/altf.nvim. Copyright stays with the author.
altf.nvim - Neovim Plugin Assistant
altf.nvim is a lightweight project alternate files manager for Neovim. This document defines coding standards, testing conventions, and workflow rules for AI coding assistants.
File Operations
One rule: always use action="overwrite"
replace / insert / delete are forbidden - line numbers drift after each operation, causing duplicates and syntax errors.
Workflow for any file change
1. @read_file filepath="target" # Read complete file
2. Edit in reply # Modify what's needed
3. @write_file action="overwrite" # Write complete content
4. @read_file filepath="target" # Verify: check syntax, duplicates, correctness
5. @make test # Run tests - MUST pass before committing
6. @git_add -> @git_commit -> @git_push # One at a time, wait for each result
Git tools: one at a time
Never batch git calls. Send @git_add, wait for result, then @git_commit, wait, then @git_push.
Development Workflow
After any code change, auto-execute without asking:
Modify -> Verify -> make test -> git_add -> git_commit -> git_push -> Done
Never: skip verification, skip tests, read only partial file, modify without commit, commit without push.
Documentation Principles
- Verify before writing: Only reference commands that actually exist in the codebase. Check
lua/altf/init.luafor functions likealt(),set_config_name(),getConfigPath(),complete(), andget_alt(). - No invented commands: The plugin provides
:Acommand (with optional type argument and bang). Seeplugin/alrf.luaanddoc/altf.txtfor the full reference.
Release
Release-please creates a PR on branch release-please--branches--master. To re-trigger or fix the release PR version, use git tools one at a time:
@git_fetch remote="origin"- fetch latest from origin@git_checkout branch="release-please--branches--master"- switch to release PR branch@git_reset commit="origin/release-please--branches--master" mode="hard"- reset to remote release branch state@git_rebase branch="master"- rebase release PR branch onto latest master@git_push branch="release-please--branches--master" force=true- force push to update PR@git_checkout branch="master"- switch back to master@git_merge branch="release-please--branches--master"- merge release PR into master
禁止手动创建或推送 tags
Release-please 在 release PR 合并后会自动创建 git tags 和 GitHub Releases。在此过程中:
- 不要使用
@git_tag创建任何 tag - 不要使用
@git_push tags=true推送 tags
手动 tag 会与 release-please 的自动化冲突,导致版本混乱或重复 release。
Forbidden Files
Never modify: CHANGELOG.md, CHANGELOG.*.md - auto-generated by release-please. Redirect to source code or docs instead.
Commit Style
Follow Conventional Commits. Format: type(scope): subject
| Type | For | Release |
|---|---|---|
feat |
New feature | Minor |
fix |
Bug fix | Patch |
refactor |
Code restructure | None* |
docs |
Documentation | None |
test |
Tests | None |
ci |
CI/CD | None |
chore |
Maintenance | None |
perf |
Performance | Patch |
style |
Formatting | None |
build |
Build system | None |
security |
Security fix | Patch |
* Unless BREAKING CHANGE footer or Release-As is set.
Rules: imperative mood, lowercase, no period, under 72 chars. Use ! for breaking: refactor!: change API.
Testing
Framework: luaunit. Files: test/*_spec.lua.
Running tests
Run all tests:
@make target="test"
Run specific test file(s) with PATTERN:
@make target="test" args=["PATTERN=util"]
PATTERN supports shorthand - util expands to test/**/*util*_spec.lua. Full paths also work:
@make target="test" args=["PATTERN=test/util_spec.lua"]
Writing tests
local lu = require('luaunit')
TestExample = {}
function TestExample:test_something()
lu.assertEquals(1 + 1, 2)
end
return TestExample
CI runs on push to main/master and PRs, across Neovim nightly/stable, ubuntu/windows/macos.
Test configuration
Tests must use temporary directories - never pollute real user data or config files.
test/minimal_init.lua sets up the plugin with a temporary cache path. Tests that need their own configuration should set up buffer variables or config files in a temp directory:
local test_dir
function TestExample:setUp()
test_dir = vim.fn.tempname() .. '_altf_test'
vim.fn.mkdir(test_dir, 'p')
-- set up test-specific config as needed
end
function TestExample:tearDown()
if test_dir and vim.fn.isdirectory(test_dir) == 1 then
vim.fn.delete(test_dir, 'rf')
end
end
Rules:
- Use temporary directories for test config files and cache
- Clean up temp dirs in
tearDown - Never write to real user config paths
Project Structure
altf.nvim/
├── lua/altf/
│ ├── init.lua # Core: alt(), get_alt(), parse(), cache(), getConfigPath(), complete()
│ └── util.lua # Utilities: notify(), info(), debug(), unify_path()
├── plugin/
│ └── alrf.lua # User command: :A [type] with bang support
├── doc/
│ └── altf.txt # Vim help documentation
├── test/
│ ├── minimal_init.lua # Headless test config
│ ├── run.lua # Test runner
│ ├── install_deps.lua # Cross-platform dependency installer
│ └── *_spec.lua # Test files
├── Makefile # Build/test targets
├── README.md
├── AGENTS.md
└── CHANGELOG.md # Auto-generated, DO NOT EDIT
Coding Conventions
- Language: Lua (Neovim Lua API)
- Module pattern:
local M = {}...return M - Naming:
snake_casefor functions and variables,CamelCasefor exported table names - Indentation: Tabs (matching existing codebase)
- String quotes: Double quotes
"for strings (matching existing codebase) - Error handling: Use
pcallfor optional dependencies (e.g.,toml,notify,logger) - Vim API: Use
vim.fnfor Ex commands,vim.apifor Neovim API,vim.jsonfor JSON - File paths: Use
util.unify_path()for path normalization