Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
294 changes: 294 additions & 0 deletions .agents/skills/_legacy/dignified-python-local/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
---
name: dignified-python-313
description: This skill should be used when editing Python code in the erk codebase. Use when writing, reviewing, or refactoring Python to ensure adherence to LBYL exception handling patterns, Python 3.13+ type syntax (list[str], str | None), pathlib operations, ABC-based interfaces, absolute imports, and explicit error boundaries at CLI level. Also provides production-tested code smell patterns from Dagster Labs for API design, parameter complexity, and code organization. Essential for maintaining erk's dignified Python standards.
---

# Dignified Python - Python 3.13+ Coding Standards

Write explicit, predictable code that fails fast at proper boundaries.

---

## Quick Reference - Check Before Coding

| If you're about to write... | Check this rule |
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `try:` or `except:` | → [Exception Handling](#1-exception-handling---never-for-control-flow-) - Default: let exceptions bubble |
| `from __future__ import annotations` | → **FORBIDDEN** - Python 3.13+ doesn't need it |
| `List[...]`, `Dict[...]`, `Union[...]` | → Use `list[...]`, `dict[...]`, `X \| Y` |
| `dict[key]` without checking | → Use `if key in dict:` or `.get()` |
| `path.resolve()` or `path.is_relative_to()` | → Check `path.exists()` first |
| `typing.Protocol` | → Use `abc.ABC` instead |
| `from .module import` | → Use absolute imports only |
| `__all__ = ["..."]` in `__init__.py` | → See references/core-standards.md#code-in-**init**py-and-**all**-exports |
| `print(...)` in CLI code | → Use `click.echo()` |
| `subprocess.run(...)` | → Add `check=True` |
| `@property` with I/O or expensive computation | → See references/core-standards.md#performance-expectations |
| Function with many optional parameters | → See references/code-smells-dagster.md |
| `repr()` for sorting or hashing | → See references/code-smells-dagster.md |
| Context object passed everywhere | → See references/code-smells-dagster.md |
| Function with 10+ local variables | → See references/code-smells-dagster.md |
| Class with 50+ methods | → See references/code-smells-dagster.md |

---

## CRITICAL RULES (Top 6)

### 1. Exception Handling - NEVER for Control Flow 🔴

**ALWAYS use LBYL (Look Before You Leap), NEVER EAFP**

```python
# ✅ CORRECT: Check before acting
if key in mapping:
value = mapping[key]
else:
handle_missing_key()

# ❌ WRONG: Using exceptions for control flow
try:
value = mapping[key]
except KeyError:
handle_missing_key()
```

**Details**: See `references/core-standards.md#exception-handling` for complete patterns

### 2. Type Annotations - Python 3.13+ Syntax Only 🔴

**FORBIDDEN**: `from __future__ import annotations`

```python
# ✅ CORRECT: Modern Python 3.13+ syntax
def process(items: list[str]) -> dict[str, int]: ...
def find_user(id: int) -> User | None: ...

# ❌ WRONG: Legacy syntax
from typing import List, Dict, Optional
def process(items: List[str]) -> Dict[str, int]: ...
```

**Details**: See `references/core-standards.md#type-annotations` for all patterns

### 3. Path Operations - Check Exists First 🔴

```python
# ✅ CORRECT: Check exists first
if path.exists():
resolved = path.resolve()

# ❌ WRONG: Using exceptions
try:
resolved = path.resolve()
except OSError:
pass
```

**Details**: See `references/core-standards.md#path-operations`

### 4. Dependency Injection - ABC Not Protocol 🔴

```python
# ✅ CORRECT: Use ABC
from abc import ABC, abstractmethod

class MyOps(ABC):
@abstractmethod
def operation(self) -> None: ...

# ❌ WRONG: Using Protocol
from typing import Protocol
```

**Details**: See `references/core-standards.md#dependency-injection`

### 5. Imports - Module-Level and Absolute 🔴

**ALL imports must be at module level unless preventing circular imports**

```python
# ✅ CORRECT: Module-level, absolute imports
from erk.config import load_config
from pathlib import Path
import click

# ❌ WRONG: Inline imports (unless for circular import prevention)
def my_function():
from erk.config import load_config # WRONG unless circular import
return load_config()

# ❌ WRONG: Relative imports
from .config import load_config
```

**Exception**: Inline imports are ONLY acceptable when preventing circular imports. Always document why:

```python
def create_context():
# Inline import to avoid circular dependency with tests
from tests.fakes.gitops import FakeGitOps
return FakeGitOps()
```

**Details**: See `references/core-standards.md#imports`

### 6. No Silent Fallback Behavior 🔴

```python
# ❌ WRONG: Silent fallback
try:
result = primary_method()
except:
result = fallback_method() # Untested, brittle

# ✅ CORRECT: Let error bubble up
result = primary_method()
```

**Details**: See `references/core-standards.md#anti-patterns`

---

## When to Load References

### Load `references/core-standards.md` when:

- Writing exception handling code (LBYL patterns)
- Working with type annotations (Python 3.13+ syntax)
- Implementing path operations (exists() checks)
- Creating ABC interfaces (dependency injection)
- Organizing imports (absolute imports, module-level)
- Working with CLI code (Click patterns)
- Using dataclasses and immutability
- Avoiding anti-patterns (silent fallback, exception swallowing)
- Implementing `@property` or `__len__` (performance expectations)

### Load `references/code-smells-dagster.md` when:

- Designing function APIs (default parameters, keyword arguments)
- Managing parameter complexity (parameter anxiety, invalid combinations)
- Refactoring large functions/classes (god classes, local variables)
- Working with context managers (assignment patterns)
- Using `repr()` programmatically (string representation abuse)
- Passing context objects (context coupling)
- Dealing with error boundaries (early validation)

### Load `references/patterns-reference.md` when:

- Developing CLI commands with Click
- Working with file I/O and pathlib
- Implementing dataclasses and frozen structures
- Managing subprocess operations
- Reducing code nesting (early returns, helper functions)

---

## Progressive Disclosure Guide

This skill uses a three-level loading system:

1. **This file (SKILL.md)**: Core rules and navigation (~350 lines)
2. **Reference files**: Detailed patterns and examples (loaded as needed)
3. **Quick lookup**: Use the tables above to find what you need

The agent loads reference files only when needed based on the current task. The reference files contain:

- **`core-standards.md`**: Foundational Python patterns from this skill
- **`code-smells-dagster.md`**: Production-tested anti-patterns from Dagster Labs
- **`patterns-reference.md`**: Common implementation patterns and examples

---

## Philosophy

**Write dignified Python code that:**

- Fails fast at proper boundaries (not deep in the stack)
- Makes invalid states unrepresentable (use the type system)
- Expresses intent clearly (LBYL over EAFP)
- Minimizes cognitive load (explicit over implicit)
- Enables confident refactoring (test what you build)

**Default stances:**

- Let exceptions bubble up (handle at boundaries only)
- Break APIs and migrate immediately (no unnecessary backwards compatibility)
- Check conditions proactively (LBYL)
- Use modern Python 3.13+ syntax

---

## Quick Decision Tree

**About to write Python code?**

1. **Using `try/except`?**
- Can you use LBYL instead? → Do that
- Is this an error boundary? → OK to handle
- Otherwise → Let it bubble

2. **Using type hints?**
- Use `list[str]`, `str | None`, not `List`, `Optional`
- NO `from __future__ import annotations`

3. **Working with paths?**
- Check `.exists()` before `.resolve()`
- Use `pathlib.Path`, not `os.path`

4. **Writing CLI code?**
- Use `click.echo()`, not `print()`
- Exit with `raise SystemExit(1)`

5. **Too many parameters?**
- See `references/code-smells-dagster.md#parameter-anxiety`

6. **Class getting large?**
- See `references/code-smells-dagster.md#god-classes`

---

## Checklist Before Writing Code

Before writing `try/except`:

- [ ] Can I check the condition proactively? (LBYL)
- [ ] Is this at an error boundary? (CLI/API level)
- [ ] Am I adding meaningful context or just hiding the error?

Before using type hints:

- [ ] Am I using Python 3.13+ syntax? (`list`, `dict`, `|`)
- [ ] Have I removed all `typing` imports except essentials?

Before path operations:

- [ ] Did I check `.exists()` before `.resolve()`?
- [ ] Am I using `pathlib.Path`?
- [ ] Did I specify `encoding="utf-8"`?

Before adding backwards compatibility:

- [ ] Did the user explicitly request it?
- [ ] Is this a public API?
- [ ] Default: Break and migrate immediately

---

## Common Patterns Summary

| Scenario | Preferred Approach | Avoid |
| --------------------- | ----------------------------------------- | ------------------------------------------- |
| **Dictionary access** | `if key in dict:` or `.get(key, default)` | `try: dict[key] except KeyError:` |
| **File existence** | `if path.exists():` | `try: open(path) except FileNotFoundError:` |
| **Type checking** | `if isinstance(obj, Type):` | `try: obj.method() except AttributeError:` |
| **Value validation** | `if is_valid(value):` | `try: process(value) except ValueError:` |
| **Path resolution** | `if path.exists(): path.resolve()` | `try: path.resolve() except OSError:` |

---

## References

- **Core Standards**: `references/core-standards.md` - Detailed LBYL patterns, type annotations, imports
- **Code Smells**: `references/code-smells-dagster.md` - Production-tested anti-patterns
- **Pattern Reference**: `references/patterns-reference.md` - CLI, file I/O, dataclasses
- Python 3.13 docs: https://docs.python.org/3.13/
50 changes: 50 additions & 0 deletions .agents/skills/context-doc-maintainer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
name: context-doc-maintainer
description: Automated agent workflow for reviewing and updating project agent context files when code changes are made.
license: MIT
---

# Context Documentation Maintainer

Use this skill when code changes require updates to agent-facing context files, project maps, skill instructions, PR templates, or repository guidance under `.agents/`.

## Scope

- Keep `.agents/` context aligned with current architecture, commands, and conventions.
- Update skill files only when code changes alter the workflow the skill describes.
- Preserve concise, task-oriented context; avoid duplicating detailed docs already available elsewhere.
- Do not update generated artifacts, secrets, local environment files, or unrelated documentation.

## Workflow

1. **Inspect changes**
- Run `git status --short`.
- Compare against the PR base with `git diff <base>...HEAD --stat` and `git diff <base>...HEAD --name-status` when a base is known.
- Categorize changes by domain: Dagster, dbt, API, frontend, tests, infrastructure, or docs.

2. **Map context impact**
- Update `.agents/skills/*/SKILL.md` when a workflow, command, path, or convention changed.
- Update `.agents/skills/*/references/*.md` when detailed domain guidance changed.
- Update `.agents/AGENTS.md` or repo-level `AGENTS.md` only for broad project conventions or architecture shifts.
- Update `.agents/skills/context-doc-maintainer/templates/pr_template.md` only when the PR handoff structure changes.

3. **Edit context**
- Keep each `SKILL.md` lean and directly actionable.
- Prefer linking to reference files over embedding long examples.
- Use `.agents/` paths for project agent context.
- Avoid stale product-specific wording unless the skill is explicitly about that product.

4. **Validate**
- Check frontmatter includes `name` and `description`.
- Search for stale product/path references with ripgrep before handoff.
- Check for prohibited auxiliary docs: `find .agents/skills -name README.md -o -name CHANGELOG.md -o -name INSTALLATION_GUIDE.md -o -name QUICK_REFERENCE.md`.
- Run `git diff --check`.

5. **Handoff**
- Summarize which context files changed and why.
- Call out validation that could not run and the exact blocker.
- Do not create commits, PRs, or merges unless the user explicitly asks.

## PR Template

Use `templates/pr_template.md` when creating a documentation-only PR for context updates.
36 changes: 36 additions & 0 deletions .agents/skills/context-doc-maintainer/templates/pr_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Update Agent Context Documentation

## Summary

Automated documentation updates based on recent code changes.

## Code Changes Analyzed

**Commit Range**: {{BASE_BRANCH}}...{{CURRENT_BRANCH}}
**Files Changed**: {{FILES_CHANGED}}
**Additions**: +{{ADDITIONS}} lines
**Deletions**: -{{DELETIONS}} lines

### Key Code Changes

{{CHANGE_SUMMARY}}

## Documentation Updates

{{UPDATE_DETAILS}}

## Validation Results

{{VALIDATION_SUMMARY}}

## Review Checklist

- [ ] Documentation accurately reflects code changes
- [ ] No sensitive information exposed
- [ ] Markdown formatting is correct
- [ ] Section placements are appropriate
- [ ] Project structure tree matches filesystem

---

🤖 Generated with an agent-assisted workflow.
Loading
Loading