What problem does it solve?
This skill defines mandatory workflow rules that must be followed in every development session. These rules prevent recurring friction patterns discovered across hundreds of sessions: 42 wrong approaches, 34 buggy code incidents, 27 rejected actions.
Core Features & Use Cases
Linting and Pre-commit Checks
Always run pre-commit/lefthook checks before considering any task complete. If the project has pre-commit hooks, lefthook, or other automated checks configured, they must pass before you can close a task or create a commit.
Never propose nolint directives, noqa comments, lint rule exclusions, or ignoring lint errors as a solution. These are band-aids that hide problems. Fix the root cause instead:
- If a linter complains about cyclomatic complexity, refactor the function
- If a linter complains about line length, break the line appropriately
- If a linter complains about unused imports, remove them
- If a linter complains about naming conventions, rename the variable
The only acceptable exception is when the linter is objectively wrong about a specific line (rare),
and you can document why with a detailed comment explaining the business reason.
Markdown Files
Validate markdown files with markdownlint before committing. Common issues to watch for:
- MD013 (line length): Wrap prose at 100 characters unless explicitly disabled
- MD040 (fenced code language): Always specify language for code blocks
- MD033 (inline HTML): Avoid when possible; use markdown alternatives
- MD034 (bare URLs): Use link syntax
[text](url) instead of bare URLs
- MD041 (first line heading): Ensure documents start with a level 1 heading
- MD022/MD023/MD024/MD025 (heading spacing and uniqueness)
- MD029 (ordered list prefixes): Use consistent numbering style
- MD030 (list marker spacing): Consistent spacing after list markers
Check the project's .markdownlint.json or .markdownlintrc for specific rule configurations.
Code Clarity
Never use magic numbers. Define constants with descriptive names:
# Bad
if user.age >= 18:
grant_access()
# Good
MINIMUM_AGE_FOR_ACCESS = 18
if user.age >= MINIMUM_AGE_FOR_ACCESS:
grant_access()
Always handle errors explicitly. No shortcuts:
- Go: No
_ = err — always handle or propagate errors
- Python: No bare
except: — catch specific exceptions
- Java/TypeScript: No empty catch blocks — log or re-throw
- Rust: No unwrapping without panic messages
Prefer descriptive variable names over abbreviations:
userRepository over ur
maxConnectionTimeout over mct
customerList over cl
Exceptions: well-known abbreviations (i, j, k in loops; err for errors; ctx for context)
Comments and Documentation
Write self-documenting code; only add comments where logic isn't self-evident. Good code reads
like prose. Comments should explain "why", not "what":
// Bad
// Increment counter
counter++;
// Good
// Skip first iteration to avoid off-by-one error in legacy API
counter++;
Don't add docstrings, comments, or type annotations to code you didn't change. If you're fixing
a bug in a function, don't add docstrings as "while you're there" work unless explicitly asked. Stay
focused on the task.
Scope Discipline
Avoid over-engineering: only make changes directly requested or clearly necessary. Don't add
features "just in case" or "for future extensibility" unless the user explicitly asks for it.
Don't add error handling for scenarios that can't happen:
# Bad - file is already validated before this function
def process_user(user_id: int):
if user_id is None: # Can't happen - type system prevents it
raise ValueError("user_id cannot be None")
Don't create abstractions for one-time operations. If something is used once, inline it. Only
abstract when you have 2-3 concrete examples showing the pattern.
Git Workflow Rules
Branching Strategy
Never push to main directly. Always create a feature branch and open a PR. This applies even
for documentation changes, typo fixes, or "quick" changes. The PR process exists for a reason.
Ask which branch to target if unclear. Different projects use different conventions:
- Some use
main or master for production
- Some use
develop for integration
- Some use
staging for pre-production
Never assume. Ask: "Which branch should I target for this PR?"
Commit Discipline
One task = one commit. Do not batch unrelated changes. If you're working on multiple tasks,
commit each one separately:
- ✅ "feat(auth): add password reset endpoint" (one feature)
- ❌ "feat(auth): add password reset endpoint and fix login bug and update docs" (three changes)
Commit before closing/completing any task. Work is not done until it's committed. The sequence must always be:
- Implement the change
- Test the change (manual or automated)
- Run linters/pre-commit checks
- Stage specific files with
git add <file1> <file2>
- Commit with descriptive message
- Push to remote
- Close/complete the task in beads
Use conventional commit format: type(scope): description
Types:
feat: New feature
fix: Bug fix
docs: Documentation only changes
style: Formatting, missing semicolons, etc (no code change)
refactor: Code change that neither fixes a bug nor adds a feature
perf: Performance improvement
test: Adding or updating tests
chore: Maintenance tasks, dependency updates
ci: CI/CD pipeline changes
build: Build system or external dependency changes
Scope: The affected component, module, or area (e.g., auth, api, ui, db)
Description: Imperative mood, lowercase, no period at end
Examples:
feat(api): add user profile endpoint
fix(auth): prevent token expiry race condition
docs(readme): update installation instructions
refactor(db): extract query builder to separate module
Git Safety
Never use git push --force to main/master. Force pushing overwrites history and can destroy
other people's work. If you need to force push to a feature branch, use --force-with-lease which
is safer.
Never use git reset --hard without explicit user approval. This destroys unp
ommitted work permanently. Always ask first.
Never skip hooks (--no-verify) unless the user explicitly requests it. Pre-commit hooks exist to
catch problems before they enter the history. Bypassing them defeats the purpose.
Always create NEW commits rather than amending, unless explicitly requested. When a pre-commit
hook fails, the commit did NOT happen — so --amend would modify the PREVIOUS commit, which may
result in destroying work or losing previous changes. Instead, after hook failure:
- Fix the issue identified by the hook
- Re-stage the fixed files
- Create a NEW commit
When staging files, prefer adding specific files by name rather than git add -A. This prevents
accidentally committing:
- Sensitive files (.env, credentials.json, private keys)
- Large binaries (build artifacts, node_modules)
- Debug files (.log, .tmp)
- Editor configs (.vscode, .idea) that shouldn't be shared
Example:
...
(continuation of safety guidelines is included in the skill)
Git Safety
...
Workflow Discipline Rules
Planning and Communication
When planning, be concise and action-oriented. Present what you have promptly. Don't spend
paragraphs explaining what you're about to do. Instead:
- Quick summary (1-2 sentences)
- Bulleted action items
- Execute
Users prefer seeing progress over reading lengthy explanations.
Decision Making
Present options when multiple valid approaches exist; don't assume. If there are trade-offs,
present them:
"There are two approaches:
- Option A: Faster to implement (2 hours), but requires manual testing
- Option B: More robust (4 hours), includes automated tests
Which would you prefer?"
Don't pick one silently and hope it's what they wanted.
Handling Blockers
If blocked, explain why and suggest alternatives rather than silently giving up. When you
encounter a blocker:
- Clearly state what you're blocked on
- Explain why it's blocking you
- Suggest 2-3 alternatives or workarounds
- Ask for guidance
Example: "I can't proceed with the database migration because the production credentials aren't in
the .env file. Options: 1) You provide the credentials, 2) I create a mock environment for
testing, 3) I document the migration steps for you to run manually. Which would you prefer?"
Completion Discipline
Never say "ready to push when you are" — YOU must push. The AI agent is responsible for
completing the git workflow. Saying "ready to push" is passing the buck. Just push.
Work is NOT complete until git push succeeds. A local commit is not done. The sequence must
be:
git commit -m "..."
git push
- Verify push succeeded
- Only then close the task
Always verify: git status should show "up to date with origin" at session end. Before ending any
session, run git status and confirm:
- Working tree is clean (or intentionally has uncommitted changes)
- Branch is up to date with remote
- No unpushed commits
If there are unpushed commits, push them unless explicitly told not to.
Security Rules
Secrets Management
Never commit files containing secrets (.env, credentials.json, private keys). Before every
commit, scan staged files for:
- Environment files (.env, .env.local, .env.production)
- Credential files (credentials.json, service-account.json)
- Private keys (.pem, .key, id_rsa)
- API keys in config files
- Database connection strings with passwords
If you need to commit example configurations, use placeholder values:
# .env.example (safe to commit)
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
API_KEY=your_api_key_here
# .env (NEVER commit)
DATABASE_URL=postgresql://prod_user:[email protected]:5432/production_db
API_KEY=sk_live_actual_key_12345
Permissions
Never add chmod 777 or world-writable permissions. This makes files readable, writable, and
executable by everyone, which is a security risk. Instead:
chmod 644 for regular files (owner can write, others can read)
chmod 755 for executables (owner can write, everyone can execute)
chmod 600 for sensitive files (owner only)
Never pipe remote content to shell (curl|sh, wget|bash). This pattern downloads and immediately
executes remote code without inspection:
# Dangerous
curl https://example.com/install.sh | sh
# Safe
curl -O https://example.com/install.sh
# Inspect install.sh
sh install.sh
Input Validation
Validate all user input at system boundaries. Any data entering the system from:
- HTTP request parameters
- Database queries (prevent SQL injection)
- File uploads
- Command-line arguments
- Environment variables
Must be validated, sanitized, or parameterized before use:
# Bad - SQL injection risk
query = f"SELECT * FROM users WHERE username = '{username}'"
# Good - parameterized query
query = "SELECT * FROM users WHERE username = ?"
cursor.execute(query, (username,))
Code Review Rules
Review Process
When reviewing code (either your own before committing, or someone else's PR), use severity levels
to categorize feedback:
- BLOCKER: Must fix before merging (security issues, data corruption, broken functionality)
- WARNING: Should fix before merging (performance issues, maintainability problems, convention
violations)
- NIT: Suggestion for improvement (style preferences, minor optimizations, bikeshedding)
Review Checklist
Correctness: Does the code do what it's supposed to do? Are edge cases handled? Are errors handled appropriately? Are there race conditions or concurrency issues?
Security: Are user inputs validated? Are secrets properly managed? Are there injection vulnerabilities (SQL, XSS, command)? Are authentication and authorization correct?
Performance: Are there obvious inefficiencies (N+1 queries, unnecessary loops)? Are large datasets handled efficiently? Are resources properly released (connections, file handles)?
Maintainability: Is the code readable and well-organized? Are names descriptive? Is complexity appropriate for the problem? Are there sufficient tests?
Conventions: Does the code follow the project's style guide? Are commit messages following the conventional format? Are files in the correct locations?
Focus on Substance
Focus on substance over style for things the linter handles. If the project has automated
linting for formatting, don't comment on:
- Indentation
- Quote style
- Trailing commas
- Spacing around operators
The linter will catch these. Focus your review on logic, architecture, and maintainability.
Summary
These workflow rules exist because they solve real problems that occurred in hundreds of sessions.
Following them prevents:
- Broken commits that don't pass CI
- Lost work from improper git operations
- Security vulnerabilities from credential leaks
- Scope creep and over-engineering
- Incomplete tasks and confused state
Every rule has a reason. Trust the process.