Agent skill

Sqlalchemy

by kid-sid in kid-sid/claude-spellbook

A skill your agent uses when using async SQLAlchemy 2.0 — defining models, writing queries, managing async sessions, loading relationships without N+1, or setting up and debugging Alembic migrations.

MITAuto-check passedDatabases

Install Sqlalchemy

skills CLI
$ npx skills add kid-sid/claude-spellbook --skill sqlalchemy -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install kid-sid/claude-spellbook sqlalchemy --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/kid-sid/claude-spellbook.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/sqlalchemy .claude/skills/sqlalchemy && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
sqlalchemy
GitHub stars
189
Token cost
~3.5k tokens
SKILL.md length
493 words
Files
1
Skills in repo
54
Repo updated
First seen
Licence
MIT

At a glance

A skill your agent uses when using async SQLAlchemy 2.0 — defining models, writing queries, managing async sessions, loading relationships without N+1, or setting up and debugging Alembic migrations.

  • Using async SQLAlchemy 2.0 — defining models
  • SKILL.md covers When to Activate, Model Definition (SQLAlchemy…, Engine and Session Factory and Dependency (FastAPI), plus 8 more sections
  • Calls make
  • Writing queries

What it does

Sqlalchemy is an agent skill from kid-sid/claude-spellbook. Use when using async SQLAlchemy 2.0 — defining models, writing queries, managing async sessions, loading relationships without N+1, or setting up and debugging Alembic migrations.

Its SKILL.md is about 3.5k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Databases, covering ORMs and data access and Database migrations. It works with SQLAlchemy. The repository describes itself as: A curated collection of skills, prompts, and workflows that extend Claude's capabilities — your personal grimoire for AI-powered development. The licence is MIT.

When your agent uses it

  • Using async SQLAlchemy 2.0 — defining models
  • Writing queries
  • Managing async sessions
  • Loading relationships without N+1

Example prompts

  • “/sqlalchemy”

Requirements

  • Python 3

What it can do on your machine

Read from SKILL.md and the folder at commit a7c2ac9. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • make

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Sqlalchemy loads about 3.5k tokens when it runs. Until then it costs about 48 tokens; SKILL.md has 493 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~48
When it runs · the whole SKILL.md, loaded when a task matches
~3.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from kid-sid/claude-spellbook at commit a7c2ac9, republished under its MIT licence (© kid-sid). 493 words, ~3,455 tokens.

Download SKILL.mdSave it as .claude/skills/sqlalchemy/SKILL.md (or your agent's skills folder).
name
sqlalchemy
description
Use when using async SQLAlchemy 2.0 — defining models, writing queries, managing async sessions, loading relationships without N+1, or setting up and debugging Alembic migrations.

SQLAlchemy 2.0 — Async Patterns

Modern SQLAlchemy 2.0 with full async support (asyncpg) and Alembic migrations.

When to Activate

  • Defining ORM models with Mapped / mapped_column
  • Writing async queries (select, join, filter, order_by)
  • Managing async sessions (AsyncSession, async_sessionmaker)
  • Handling relationships and loading strategies (selectin, joined, lazy)
  • Running database transactions or bulk operations
  • Writing or debugging Alembic migrations
  • Converting between ORM models and domain entities

Model Definition (SQLAlchemy 2.0 style)

python
from datetime import datetime
from uuid import UUID, uuid4
from sqlalchemy import String, ForeignKey, Text, TIMESTAMP, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from sqlalchemy.dialects.postgresql import UUID as PGUUID, JSONB


class Base(DeclarativeBase):
    pass


class UserORM(Base):
    __tablename__ = "users"

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, index=True)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    role: Mapped[str] = mapped_column(String(50), nullable=False, default="user")
    metadata_: Mapped[dict] = mapped_column("metadata", JSONB, nullable=False, default=dict)
    created_at: Mapped[datetime] = mapped_column(
        TIMESTAMP(timezone=True), server_default=func.now(), nullable=False
    )
    updated_at: Mapped[datetime] = mapped_column(
        TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now()
    )

    # Relationship — loads orders when accessed
    orders: Mapped[list["OrderORM"]] = relationship("OrderORM", back_populates="user")


class OrderORM(Base):
    __tablename__ = "orders"

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    user_id: Mapped[UUID] = mapped_column(
        PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True
    )
    status: Mapped[str] = mapped_column(String(50), nullable=False, default="pending")
    total: Mapped[float] = mapped_column(nullable=False)
    created_at: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())

    user: Mapped["UserORM"] = relationship("UserORM", back_populates="orders")

Key rules:

  • Mapped[T] declares the Python type; mapped_column() declares the column config
  • nullable=False is explicit — Mapped[str] without it is still nullable in older versions
  • Use PGUUID(as_uuid=True) so SQLAlchemy returns Python UUID objects, not strings
  • index=True on FK columns — always

Engine and Session Factory

python
# config/database.py
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker

# asyncpg driver — fastest PostgreSQL async driver
engine = create_async_engine(
    "postgresql+asyncpg://user:pass@localhost:5432/mydb",
    pool_size=10,           # max persistent connections
    max_overflow=20,        # extra connections above pool_size under load
    pool_pre_ping=True,     # test connections before use (handles dropped connections)
    echo=False,             # set True to log all SQL (dev only)
)

# Session factory — reuse this, don't recreate per request
AsyncSessionLocal = async_sessionmaker(
    engine,
    class_=AsyncSession,
    expire_on_commit=False,   # keep attributes accessible after commit
    autoflush=False,
)

Dependency (FastAPI)

python
# api/dependencies.py
from sqlalchemy.ext.asyncio import AsyncSession
from config.database import AsyncSessionLocal

async def get_db() -> AsyncSession:
    async with AsyncSessionLocal() as session:
        try:
            yield session
            await session.commit()
        except Exception:
            await session.rollback()
            raise

FastAPI caches this dependency within a request — one session per request.


CRUD Patterns

python
from sqlalchemy import select, update, delete
from sqlalchemy.ext.asyncio import AsyncSession

class UserCRUD:
    def __init__(self, session: AsyncSession):
        self.session = session

    async def get(self, user_id: UUID) -> UserORM | None:
        result = await self.session.execute(
            select(UserORM).where(UserORM.id == user_id)
        )
        return result.scalar_one_or_none()

    async def get_by_email(self, email: str) -> UserORM | None:
        result = await self.session.execute(
            select(UserORM).where(UserORM.email == email)
        )
        return result.scalar_one_or_none()

    async def list(self, skip: int = 0, limit: int = 100) -> list[UserORM]:
        result = await self.session.execute(
            select(UserORM).order_by(UserORM.created_at.desc()).offset(skip).limit(limit)
        )
        return list(result.scalars().all())

    async def create(self, email: str, name: str, role: str = "user") -> UserORM:
        user = UserORM(email=email, name=name, role=role)
        self.session.add(user)
        await self.session.flush()   # assigns ID without committing
        await self.session.refresh(user)
        return user

    async def update(self, user_id: UUID, **kwargs) -> UserORM | None:
        await self.session.execute(
            update(UserORM).where(UserORM.id == user_id).values(**kwargs)
        )
        return await self.get(user_id)

    async def delete(self, user_id: UUID) -> None:
        await self.session.execute(
            delete(UserORM).where(UserORM.id == user_id)
        )

    async def count(self, role: str | None = None) -> int:
        from sqlalchemy import func
        q = select(func.count()).select_from(UserORM)
        if role:
            q = q.where(UserORM.role == role)
        result = await self.session.execute(q)
        return result.scalar_one()

Joins and Complex Queries

python
from sqlalchemy import select, and_, or_, func
from sqlalchemy.orm import selectinload, joinedload

# JOIN — users with their order count
result = await session.execute(
    select(UserORM, func.count(OrderORM.id).label("order_count"))
    .outerjoin(OrderORM, UserORM.id == OrderORM.user_id)
    .group_by(UserORM.id)
    .order_by(func.count(OrderORM.id).desc())
)
rows = result.all()   # list of (UserORM, order_count) tuples

# Relationship loading — selectinload avoids N+1
result = await session.execute(
    select(UserORM)
    .options(selectinload(UserORM.orders))   # one extra query for all orders
    .where(UserORM.role == "admin")
)
users = result.scalars().all()
for user in users:
    print(user.orders)   # no extra query

# joinedload — single JOIN query (good for to-one relationships)
result = await session.execute(
    select(OrderORM)
    .options(joinedload(OrderORM.user))
    .where(OrderORM.status == "pending")
)
orders = result.unique().scalars().all()

# Filtering with operators
result = await session.execute(
    select(UserORM).where(
        and_(
            UserORM.role.in_(["admin", "manager"]),
            UserORM.created_at > datetime(2024, 1, 1),
            or_(
                UserORM.name.ilike("%alice%"),
                UserORM.email.ilike("%alice%"),
            ),
        )
    )
)

# JSONB filtering
result = await session.execute(
    select(UserORM).where(
        UserORM.metadata_["plan"].astext == "pro"
    )
)

Loading Strategies

StrategyWhen to useExtra queries
selectinloadOne-to-many, loading multiple parents1 extra per relationship
joinedloadMany-to-one (loading parent from child)0 extra (JOIN)
lazy="raise"Default in strict mode — force explicit loadingRaises if accessed
lazy="noload"Never load — when you never need the relation0
python
# Set default loading per model
class OrderORM(Base):
    user: Mapped["UserORM"] = relationship(
        "UserORM",
        back_populates="orders",
        lazy="raise",    # must explicitly use joinedload/selectinload in queries
    )

Transactions

python
# Session auto-handles transaction — commit/rollback in dependency

# Explicit savepoint (nested transaction)
async with session.begin_nested():
    session.add(obj)
    # rolls back to savepoint on exception, not the whole transaction

# Bulk insert (much faster than add() in a loop)
await session.execute(
    UserORM.__table__.insert(),
    [{"email": f"user{i}@test.com", "name": f"User {i}"} for i in range(1000)],
)

# Upsert (PostgreSQL ON CONFLICT)
from sqlalchemy.dialects.postgresql import insert

stmt = insert(UserORM).values(email="alice@example.com", name="Alice")
stmt = stmt.on_conflict_do_update(
    index_elements=["email"],
    set_={"name": stmt.excluded.name, "updated_at": func.now()},
)
await session.execute(stmt)

Alembic Migrations

Setup
bash
# In agentex/:
alembic init alembic           # creates alembic/ dir + alembic.ini
# or with make:
make migration NAME="add_users_table"
make apply-migrations

alembic/env.py — connect to async engine and point at your models:

python
from sqlalchemy.ext.asyncio import async_engine_from_config
from adapters.orm import Base    # import your Base so models are registered

target_metadata = Base.metadata

def run_migrations_online():
    connectable = async_engine_from_config(config.get_section(config.config_ini_section))
    # ... standard async alembic boilerplate
Migration file patterns
python
# Auto-generated migration — review before applying
def upgrade() -> None:
    op.create_table(
        "users",
        sa.Column("id", pg.UUID(as_uuid=True), primary_key=True),
        sa.Column("email", sa.String(255), nullable=False),
        sa.Column("created_at", sa.TIMESTAMP(timezone=True), server_default=sa.text("now()")),
    )
    op.create_index("ix_users_email", "users", ["email"], unique=True)

def downgrade() -> None:
    op.drop_table("users")

# Add column safely (large tables)
def upgrade() -> None:
    # Step 1: add nullable first (no table lock)
    op.add_column("orders", sa.Column("shipped_at", sa.TIMESTAMP(timezone=True), nullable=True))
    # Step 2: backfill (do in batches in a separate migration or via cron)
    # Step 3: add NOT NULL constraint after backfill

# Create index concurrently (no table lock)
def upgrade() -> None:
    op.execute("CREATE INDEX CONCURRENTLY idx_orders_user_id ON orders(user_id)")

def downgrade() -> None:
    op.execute("DROP INDEX CONCURRENTLY idx_orders_user_id")

# Data migration
def upgrade() -> None:
    op.execute("UPDATE users SET role = 'member' WHERE role = 'user'")

Entity Conversion

Keep ORM models separate from domain entities. Convert at the adapter boundary:

python
# adapters/crud_store/users.py
from domain.entities.user import User
from adapters.orm import UserORM

def convert_user_to_entity(orm: UserORM) -> User:
    return User(
        id=orm.id,
        email=orm.email,
        name=orm.name,
        role=orm.role,
        created_at=orm.created_at,
    )

class UserRepository:
    async def get(self, user_id: UUID) -> User | None:
        orm = await UserCRUD(self.session).get(user_id)
        return convert_user_to_entity(orm) if orm else None

Red Flags

  • Old-style Column() declarations — Column(String, nullable=False) without Mapped[T] loses the Python type information that mypy and editors rely on; use Mapped[str] = mapped_column(String(255), nullable=False) in all new SQLAlchemy 2.0 code
  • Accessing relationships without explicit loading — accessing user.orders in an async context without selectinload or joinedload raises MissingGreenlet or emits implicit lazy SQL that blocks the event loop; always declare the loading strategy in the query
  • Creating a new AsyncSession per query — instantiating a session for each database call bypasses connection pooling and transaction batching; create one session per request via the FastAPI dependency
  • Missing pool_pre_ping=True — without it, connections dropped by the database (idle timeout, network reset) are handed to the application as stale; the first query fails with a connection error rather than transparently reconnecting
  • expire_on_commit=False missing — by default SQLAlchemy expires all attributes after commit; accessing them in an async context after the session commits triggers lazy loads that fail; set expire_on_commit=False in async_sessionmaker
  • Missing index=True on foreign key columns — SQLAlchemy does not auto-index FK columns; every JOIN or filter on a FK without an index is a sequential scan
  • ORM models imported in the domain layer — importing UserORM in use cases or domain entities couples the business logic to the database schema; all ORM ↔ entity conversion belongs in the adapter layer
Show full SKILL.md (74 more words)Show less

Checklist

  • Mapped[T] + mapped_column() used (not old Column() style)
  • FK columns have index=True
  • async_sessionmaker with expire_on_commit=False for async
  • pool_pre_ping=True on engine to handle dropped connections
  • selectinload / joinedload explicit in every query that accesses a relationship
  • flush() used after add() to get DB-generated ID without committing
  • Alembic migrations add nullable columns first, then backfill, then add NOT NULL
  • CREATE INDEX CONCURRENTLY used for large tables
  • ORM models never imported in domain layer — conversion happens in adapter

© kid-sid, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/sqlalchemy of kid-sid/claude-spellbook.

Open the folder on GitHubat commit a7c2ac9

Compare with similar skills

Sqlalchemy next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Sqlalchemy compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Sqlalchemy this skillkid-sid/claude-spellbook189—~3.5kAutomated safety check: PassMIT
Change Database Schemamartin-ueding/geo-activity-playground100—~225Automated safety check: PassCustom licence
Specx Sqlalchemy Migrationsmaksimzayats/specx202—~822Automated safety check: PassMIT
Specx Add Infrastructure Adaptermaksimzayats/specx202—~1kAutomated safety check: PassMIT
Python Database Patternsaiskillstore/marketplace4301 repos~1.2kAutomated safety check: NotesNone
DB Connectionaiskillstore/marketplace430—~3.5kAutomated safety check: NotesNone

Similar skills

  • Change Database Schema

    martin-ueding/geo-activity-playground

    How to change the SQLAlchemy data model and generate the matching Alembic migration.

    100 GitHub stars~225 tokensUpdated 10 days ago
    DatabasesAuto-check passed
  • Specx Sqlalchemy Migrations

    maksimzayats/specx

    Add or repair Alembic migrations for specx SQLAlchemy services.

    202 GitHub stars~822 tokensUpdated 2 mo ago
    DatabasesAuto-check passed
  • Add technical infrastructure adapters for specx core scopes.

    202 GitHub stars~1k tokensUpdated 2 mo ago
    DatabasesAuto-check passed
  • Python Database Patterns

    aiskillstore/marketplace

    SQLAlchemy and database patterns for Python. An agent skill from aiskillstore/marketplace.

    430 GitHub starsUsed in 1 repo~1.2k tokens
    DatabasesAuto-check: notes
  • DB Connection

    aiskillstore/marketplace

    A skill your agent uses when setting up database connections, especially for Neon PostgreSQL.

    430 GitHub stars~3.5k tokensUpdated today
    DatabasesAuto-check: notes
  • DB Migrations

    kurealnum/dotfiles

    A skill your agent uses when generating or regenerating Drizzle migration files, changing database schema tables or columns, resolving migration sequence conflicts after rebase, reviewing migration…

    290 GitHub stars~820 tokensUpdated 5 mo ago
    DatabasesAuto-check passed

More from kid-sid/claude-spellbook

All 54 skills in this repo
  • Accessibility

    kid-sid/claude-spellbook

    A skill your agent uses when building or reviewing UI components for keyboard and screen reader compatibility, adding ARIA to custom widgets, auditing a page for WCAG AA conformance, or preparing…

    189 GitHub stars~3.2k tokensUpdated 2 mo ago
    Auto-check passed
  • Agentex

    kid-sid/claude-spellbook

    A skill your agent uses when building, wiring, or debugging an Agentex agent — choosing agent type, configuring acp.py and manifest.yaml, using adk.messages or adk.state, or resolving…

    189 GitHub stars~2.2k tokensUpdated 2 mo ago
    Auto-check: notes
  • AI Engineer

    kid-sid/claude-spellbook

    A skill your agent uses when building production LLM applications — designing RAG pipelines, choosing vector databases, implementing agent orchestration, optimizing cost, or adding AI safety…

    189 GitHub stars~3.7k tokensUpdated 2 mo ago
    Auto-check passed
  • Angular

    kid-sid/claude-spellbook

    A skill your agent uses when building or refactoring Angular applications — choosing between signals, RxJS, and NgRx for state, configuring routing with guards and lazy loading, optimizing change…

    189 GitHub stars~5k tokensUpdated 2 mo ago
    Auto-check passed
  • API Design

    kid-sid/claude-spellbook

    A skill your agent uses when designing new REST endpoints, reviewing an existing API contract, adding pagination or filtering, planning a versioning strategy, or building a public or partner-facing…

    189 GitHub stars~3.6k tokensUpdated 2 mo ago
    Auto-check passed
  • Auth

    kid-sid/claude-spellbook

    A skill your agent uses when implementing login flows, issuing or validating JWTs, setting up OAuth2/OIDC with a provider, designing role-based or attribute-based access control, securing API…

    189 GitHub stars~3.2k tokensUpdated 2 mo ago
    Auto-check passed

Works with

Categories

Questions about Sqlalchemy

What does Sqlalchemy do?

A skill your agent uses when using async SQLAlchemy 2.0 — defining models, writing queries, managing async sessions, loading relationships without N+1, or setting up and debugging Alembic migrations. Sqlalchemy is an agent skill from kid-sid/claude-spellbook.0 — defining models, writing queries, managing async sessions, loading relationships without N+1, or setting up and debugging Alembic migrations.

When should I use Sqlalchemy?

Sqlalchemy fits situations like: using async SQLAlchemy 2.0 — defining models; writing queries; managing async sessions; loading relationships without N+1.

How do I install Sqlalchemy in Claude Code?

Run `npx skills add kid-sid/claude-spellbook --skill sqlalchemy -a claude-code`. Or copy the skill folder (skills/sqlalchemy in kid-sid/claude-spellbook) into .claude/skills/sqlalchemy in your project. Claude Code loads it when a task matches its description.

How do I install Sqlalchemy in Codex?

Run `npx skills add kid-sid/claude-spellbook --skill sqlalchemy -a codex`. Or copy the skill folder (skills/sqlalchemy in kid-sid/claude-spellbook) into .agents/skills/sqlalchemy in your project. Codex loads it when a task matches its description.

Can I use Sqlalchemy in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add kid-sid/claude-spellbook --skill sqlalchemy -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/sqlalchemy, .gemini/skills/sqlalchemy, .github/skills/sqlalchemy and .opencode/skills/sqlalchemy in your project.

What does Sqlalchemy need to run?

Going by SKILL.md and its folder, Sqlalchemy needs the command-line tools its instructions call (make). Our summary lists: Python 3.

Does Sqlalchemy access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Sqlalchemy safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Sqlalchemy use?

Sqlalchemy is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Sqlalchemy use?

About 3.5k tokens (SKILL.md is roughly 14k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Sqlalchemy?

Skills that share tags, products or a category with Sqlalchemy: Change Database Schema (martin-ueding/geo-activity-playground, 100 stars), Specx Sqlalchemy Migrations (maksimzayats/specx, 202 stars), Specx Add Infrastructure Adapter (maksimzayats/specx, 202 stars) and Python Database Patterns (aiskillstore/marketplace, 430 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Sqlalchemy?

kid-sid (a GitHub user) maintains it in kid-sid/claude-spellbook, which has 189 GitHub stars. The repository holds 54 skills in this directory. The repository was last updated on August 5, 2026.

Source: kid-sid/claude-spellbook on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.