Skip to content

Best Practices for Organizing Rules

See also: Organizing Katas

Understanding the Foundation

Before diving into best practices, it's crucial to understand how scopes and categories work together:

  • Categories form a universal namespace: A category like development.coding.python.testing has the same meaning across all scopes. Categories are NOT scope-specific.

  • Multiple scopes can contain rules for the same category: For example, python-general, team-backend, and project-api might all have rules for development.coding.python.testing.

  • Scopes are organizational contexts: They group related categories and rules for specific purposes (company-wide standards, team conventions, project-specific requirements).

  • Scope inheritance merges rules: When you request rules from a scope with parents, you get merged results for each category across the inheritance chain.

This universal category namespace ensures consistency: when different scopes add rules to development.security, they're all contributing to the same logical category.


Part I: Organizational Foundations

1. Understanding Universal vs Conditional Categories

Universal categories - Always apply when their domain is relevant:

development.coding.quality → Always applies when writing code
development.coding.python → Always applies when writing Python
general → Always applies

Conditional categories - Only apply when explicitly chosen or context matches:

development.architecture_patterns.clean_architecture → ONLY when pattern chosen
development.coding.testing → ONLY when writing tests
development.lifecycle.review → ONLY during review phase

Rule: Clearly separate universal from conditional in your hierarchy. Don't mix them at the same level.

Anti-pattern:

development.coding
  ├── architecture (universal - SOLID, DRY)
  └── clean_architecture (conditional - specific pattern)

Better:

development.coding
  └── architecture (universal - SOLID, DRY)

development.architecture_patterns
  └── clean_architecture (conditional - specific pattern)

2. Designing Hierarchical Structures

Use Aggregator Categories with "Do Not Use Directly" Warnings

Purpose: Provide logical grouping without forcing over-fetching

development.coding [DO NOT USE DIRECTLY; pick relevant subcategories]
  ├── core (universal code rules)
  ├── python (language-specific)
  ├── security (security rules)
  └── testing (conditional - when writing tests)

Benefit: Users can:

  • Fetch development.coding.python (specific)
  • Skip development.coding.testing (conditional)
  • Avoid accidentally fetching everything under development.coding

Hierarchical Inclusion is Automatic

Remember: Fetching a parent includes ALL children.

Implication:

  • Place conditional categories as siblings, not children of universal categories
  • If a parent has mixed universal/conditional children, users can't selectively exclude

Example problem:

development.coding.python (universal for Python)
  ├── implementation (universal)
  ├── quality (universal)
  └── testing (conditional - ONLY when writing tests)

Fetching development.coding.python forces inclusion of testing rules even when not writing tests.

Solutions:

  1. Document clearly that testing is conditionally included
  2. Move testing to sibling: development.coding.python_testing
  3. Support exclusion in API: exclude=["development.coding.python.testing"]

3. Splitting and Merging Categories

When to Split

Split categories when:

  1. Different applicability conditions
development.coding.python.implementation (always for Python)
development.coding.python.testing (only when writing tests)
  1. Different granularity needed
development.coding.security.design (architectural patterns)
development.coding.security.implementation (coding practices)
  1. Rules serve different phases/activities
development.lifecycle.implementation
development.lifecycle.review
development.lifecycle.deployment
  1. Domain-specific rules exist
development.domain_specific.web_applications
development.domain_specific.apis
development.domain_specific.cli_tools

Don't Split When:

  • Rules always apply together - Keep them in one category
  • Only 1-2 rules exist - Too granular; merge into parent
  • Split creates ambiguity - Which category gets which rule?

When to Merge

Merge categories when:

  1. Always fetched together
# Before: Always fetch both
development.coding.core
development.coding.standards

# After: Merged
development.coding.core
  1. Redundant scoping
# Before: Confusing split
security (top-level universal)
development.coding.security.global (also universal?)

# After: Clarify relationship or merge
development.security.core (all universal security)
  ├── mindset (high-level principles)
  └── implementation (coding practices)
  1. Single rule in category
# Before: Wasteful
development.architecture_patterns.core
  → Rule: "Prefer well-known patterns"

# After: Move to parent or merge
development.architecture_patterns
  → Description includes this guidance

4. Naming Conventions

Use Descriptive, Unambiguous Names

Avoid:

  • global - ambiguous; use universal (applies across all scopes) or core (base rules for this domain) instead
  • common - vague
  • misc - catch-all anti-pattern

Prefer:

  • core - base rules for this category domain
  • universal - applies across all scopes when this domain is relevant
  • implementation - during active coding
  • design - architectural level

Use "Aggregated" in Descriptions for Parent Categories

development.coding.python
  Description: "Aggregated rules that apply when the task involves Python programming"

Signals that this is a logical grouping with subdivisions.


Part II: Writing Effective Content

5. Writing Clear Descriptions

Format: "[Applicability] [What it contains]"

Universal category:

development.coding.quality
  Description: "Code quality standards applied during implementation"

Conditional category:

development.coding.testing
  Description: "Rules for writing and structuring tests. Apply when creating test code"

Conditional pattern (emphasize):

development.architecture_patterns.clean_architecture
  Description: "Clean architecture rules. **ONLY apply when implementing clean architecture pattern**"

Use Bold for Critical Conditions

Make conditions unmissable:

  • "ONLY apply when..."
  • "DO NOT use directly; always pick the relevant subcategories"
  • "Security must be enforced"

Be Explicit About Timing/Context

Good:

  • "Apply when writing Python tests"
  • "During active code development"
  • "When designing system architecture"
  • "For all code handling user input"

Bad:

  • "For testing" (writing tests or running tests?)
  • "Python rules" (all Python contexts or specific ones?)
  • "Architecture" (designing it or following a pattern?)

Common Ambiguity Sources

Avoid these patterns:

  1. "Rules related to X" - Too vague

    • Better: "Rules for writing X" or "Rules applied when X"
  2. "When appropriate" - Who decides?

    • Better: "When {specific condition}" or "Unless explicitly excluded"
  3. "General" or "Common" - General within what scope?

    • Better: "Universal" or "Core" with explicit scope
  4. Passive voice - "Rules that are applied..."

    • Better: "Apply these rules when..."

Test Your Descriptions

Ask: "Can someone reading this description know EXACTLY when to include this category?"

# Ambiguous
development.coding.testing
  Description: "Testing rules"

# Clear
development.coding.testing
  Description: "Rules for writing and structuring tests. Apply when creating test code (test_*.py, *_test.py files)"

6. Writing Actionable Rules

Use MUST/SHOULD Consistently

MUST - Non-negotiable requirements (use commandments):

- MUST: No code comments in generated code
- MUST: Security by default
- MUST: Follow SOLID principles

SHOULD - Strong recommendations (use suggestions):

- SHOULD: Prefer pytest for testing
- SHOULD: Use ruff for linting
- SHOULD: Use English in code

Make Rules Actionable

# Bad (not actionable)
- SHOULD: Write good tests
- MUST: Be secure

# Good (actionable)
- SHOULD: Use pytest.mark.parametrize for tests with multiple input scenarios
- MUST: Validate and sanitize all user inputs before processing

One Concern Per Rule

# Bad (multiple concerns)
- MUST: Use type hints and validate them with mypy, and also use ruff for linting

# Good (separated)
- SHOULD: Use statically-typed code
- SHOULD: Use mypy to validate typing
- SHOULD: Use ruff for linting

Part III: Common Organizational Patterns

7. Security Categories

Security Deserves Multiple Locations

Pattern:

security (top-level category)
  → "Universal security mindset. ALWAYS applies across all scopes"
  → High-level: Security is first-class citizen

development.coding.security
  ├── core: "Universal security requirements for code"
  ├── design: "Security architecture patterns"
  └── implementation: "Secure coding practices"

Why both?

  • Top-level security category: Ensures security is NEVER forgotten (always included)
  • development.coding.security category: Specific implementation requirements

Security Should Be

  • Mandatory (MUST, not SHOULD)
  • Explicit in descriptions ("Critical for web applications, APIs...")
  • Subdivided by concern (design vs implementation)
  • Referenced in domain-specific categories (web apps mention OWASP, CORS, etc.)

8. Language-Specific Organization

Pattern: coding.{language}.{aspect}

development.coding.python
  ├── implementation (tooling, structure, conventions)
  ├── quality (linting, type checking)
  └── testing (test framework practices)

development.coding.javascript
  ├── implementation (npm, ESLint, project structure)
  ├── quality (TypeScript, strict mode)
  └── testing (Jest patterns)

Benefits:

  • Consistent across languages
  • Easy to add new languages
  • Clear aspect separation

Alternative (if many languages):

development.coding.languages
  ├── python.*
  ├── javascript.*
  └── rust.*

Part IV: Scope-Level Design

9. Designing Scopes

When to Create Separate Scopes

Create separate scopes when:

  1. Different teams/projects with distinct rule sets
backend-team (scope)
frontend-team (scope)
ml-team (scope)
  1. Different enforcement levels
company-wide (scope) → mandatory for everyone
team-backend (scope) → specific to backend team
project-xyz (scope) → overrides for specific project
  1. Different domains with non-overlapping rules
development (scope) → coding rules
operations (scope) → deployment, monitoring
documentation (scope) → writing docs

Scope Composition and Inheritance

Design scopes to be composable:

Query: get_rules(scopes=["company-wide", "development", "python-web"])

Result: Merged rules from all three scopes

This allows:

  • Company-wide universal policies
  • Development-specific coding standards
  • Project-specific overrides

Part V: Quality Assurance

10. Anti-Patterns to Avoid

Catch-All Categories

development.coding.misc
development.other

Sign of poor organization.

Deeply Nested Hierarchies (>4 levels)

development.coding.languages.python.frameworks.django.testing.unit

Too granular; hard to navigate.

Duplicated Rules

Same rule in multiple categories without clear reason.

Circular Dependencies

Category A includes rules about when to use Category B.

Implementation Details in Descriptions

Description: "Stored in database table rules_python"

Keep descriptions user-focused.

11. Maintenance Guidelines

Regular Audits

  1. Check for orphaned rules - Rules that don't fit their category
  2. Verify applicability - Do descriptions still match rule content?
  3. Remove dead rules - Deprecated tools, outdated practices
  4. Consolidate sparse categories - <3 rules might belong elsewhere

Versioning Strategy

Consider versioning for rule changes:

development.coding.python.v2
development.coding.python.v1 (deprecated)

Or use scope versioning:

development-2024 (scope)
development-2025 (scope)

12. Quick Reference Checklist

When creating scopes/categories/rules, verify:

  • [ ] Applicability is crystal clear - No guessing when to include
  • [ ] Universal and conditional are separated - Different hierarchy levels
  • [ ] Names are descriptive and unambiguous - No "global", "misc", "common"
  • [ ] Descriptions state WHEN to apply - "Apply when..." or "ONLY when..."
  • [ ] Security is mandatory and explicit - MUST rules, multiple locations
  • [ ] Hierarchies are logical - Max 3-4 levels deep
  • [ ] Parent categories have warnings - "DO NOT USE DIRECTLY" where needed
  • [ ] Rules are actionable - Specific, measurable, implementable
  • [ ] MUST vs SHOULD is consistent - Clear distinction
  • [ ] One concern per rule - No compound requirements
  • [ ] No catch-all categories - Everything has a proper home
  • [ ] Language-specific rules follow consistent pattern - Same structure for each language

For kata-specific checklist, see Organizing Katas