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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,5 @@ marimo/_static/
marimo/_lsp/
__marimo__/
.idea
.pi
.pi
.dev
22 changes: 7 additions & 15 deletions skills/alembic-migrations/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,11 @@ Alembic only detects models that are **imported at runtime**.
A canonical module must import every ORM model so metadata is complete.

Do not assume `app/`. Use the project's existing `Base` definition --
typically at `{pkg_name}/models/base.py` (see sqlalchemy-models skill).
typically at `{pkg_name}/db/base.py` (see sqlalchemy-models skill).

Example:

```python
# {pkg_name}/models/base.py
from sqlalchemy.orm import DeclarativeBase


class Base(DeclarativeBase):
pass


# {pkg_name}/models/__init__.py
from {pkg_name}.models.user import User
from {pkg_name}.models.order import Order
Expand All @@ -61,7 +53,7 @@ from {pkg_name}.models.order import Order
Alembic must reference:

```python
from {pkg_name}.models.base import Base
from {pkg_name}.db.base import Base

target_metadata = Base.metadata
```
Expand Down Expand Up @@ -179,7 +171,7 @@ Before generating anything:
exist. If they do, **modify the existing configuration** rather than
reinitializing. Never run `alembic init` if `alembic/` already exists.
2. Identify where `Base` is defined. If the project used the
sqlalchemy-models skill, it will be at `{pkg_name}/models/base.py`.
sqlalchemy-models skill, it will be at `{pkg_name}/db/base.py`.
3. Identify which module imports all models (typically
`{pkg_name}/models/__init__.py`). This is the module env.py must import.
4. Note the existing package root. For fastapi-init projects it is
Expand Down Expand Up @@ -238,7 +230,7 @@ from alembic import context
from sqlalchemy import engine_from_config, pool

from {pkg_name}.core.config import settings
from {pkg_name}.models.base import Base
from {pkg_name}.db.base import Base
import {pkg_name}.models # noqa: F401 — ensures all models are imported

config = context.config
Expand Down Expand Up @@ -280,9 +272,9 @@ else:
run_migrations_online()
```

**Naming conventions**: Projects should configure SQLAlchemy
`naming_convention` on `MetaData`. This is typically defined where
`Base` is created (see sqlalchemy-models skill) -- not here.
**Naming conventions**: The naming convention is defined on `Base` in
`db/base.py` (see sqlalchemy-models skill) and is picked up
automatically by Alembic through `target_metadata = Base.metadata`.

**Async note**: Alembic migrations run synchronously even in async
applications.
Expand Down
12 changes: 7 additions & 5 deletions skills/background-jobs-boundaries/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,22 @@ Example pattern:
from fastapi import BackgroundTasks

@app.post("/users/{user_id}/welcome")
def send_welcome(user_id: int, background_tasks: BackgroundTasks):
async def send_welcome(user_id: int, background_tasks: BackgroundTasks):
background_tasks.add_task(send_welcome_email, user_id)
return {"status": "scheduled"}


def send_welcome_email(user_id: int):
with SessionLocal() as session:
user = session.get(User, user_id)
async def send_welcome_email(user_id: int):
async with AsyncSessionLocal() as session:
user = await session.get(User, user_id)
if not user:
return

email_service.send_welcome(user.email)
await email_service.send_welcome(user.email)
```

Background task functions must be `async def` when using async sessions. FastAPI runs async background tasks in the event loop, so this works without threads. For CPU-heavy or truly blocking work, use a real job queue instead.

Key properties:

- Task arguments are **IDs or primitives**
Expand Down
107 changes: 4 additions & 103 deletions skills/code-quality/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ developer with exact commands to verify it works.
- Keep the quality contract **easy to run locally** and **easy to mirror in CI**.
- Prefer **incremental adoption** in existing repos when a big-bang migration is unnecessary.
- Keep configuration centralized where practical, preferably in `pyproject.toml`.
- Prefer narrow rule-level ignores over broad file-level ignores. Document non-obvious ignores briefly. A large ignore list signals stack drift.

**MUST NOT:**

Expand Down Expand Up @@ -117,7 +118,9 @@ This stack is preferred because it is:
and existing suppressions.
5. **Call out removals** — explicitly name overlapping tools to delete and why.
6. **End with verification commands** — exact `ruff`, `pre-commit`, and
markdownlint commands to confirm the stack is working.
markdownlint commands to confirm the stack is working. CI quality steps
should mirror these: Ruff check, Ruff format check, Markdown lint, and
tests (if present).

---

Expand Down Expand Up @@ -258,108 +261,6 @@ Examples:

---

# Migration Bias

When the user wants to simplify or modernize tooling, the preferred migration target is:

- **Ruff**
- **pre-commit**
- **Markdown lint**
- minimal sanity hooks

Migration should aim to:

- remove redundancy
- reduce tool count
- preserve developer ergonomics
- preserve CI clarity
- keep adoption understandable

When migrating to Ruff, prefer to remove overlapping tools rather than run both indefinitely.

---

# Config Discipline

Prefer `pyproject.toml` as the canonical configuration home for:

- Ruff
- pytest, when applicable
- other Python tooling that supports it

Use separate config files only when a tool truly requires them.

Do not create config sprawl.

---

# Pre-commit Discipline

Pre-commit should be:

- fast enough that developers will actually use it
- aligned with the repo's real standards
- limited to checks with strong signal

Do not overload pre-commit with slow, redundant, or low-value hooks.

Pre-commit is an enforcement layer, not a philosophy engine.

---

# CI Discipline

CI should mostly replay the same code-health contract expected locally.

Recommended CI quality steps:

- Ruff check
- Ruff format check
- Markdown lint
- tests, if present

Avoid introducing style tools in CI that developers are not expected to run locally.

---

# Ignore Philosophy

Use a minimal-ignore approach.

Rules:

- prefer fixing code over expanding ignore lists
- prefer narrow rule-level ignores over broad file-level ignores
- document non-obvious ignores briefly
- do not accumulate unexplained exceptions

A large ignore list is usually a signal that the stack is drifting.

---

# Adoption Philosophy

This skill should make the stack **easy to adopt**.

Preferred adoption characteristics:

- quick install
- one obvious command path
- one obvious config location
- one obvious local enforcement layer
- one obvious CI replay

For existing repos, favor changes that are:

- understandable
- reviewable
- low-drama
- easy to roll out incrementally

Do not require perfection before adoption begins.

---

# Verification Expectations

When proposing or applying this stack, end with exact commands such as:
Expand Down
Loading
Loading