{
  "id": "sqlalchemy-2-style-guard",
  "type": "loadout",
  "title": "SQLAlchemy 2 guard against 1.x and legacy Query code",
  "summary": "Stop agents writing engine.execute, select([...]), row[\"name\"] and session.query into SQLAlchemy 2 projects, and catch writes that are never committed.",
  "description": "SQLAlchemy 2.0 has been out since January 2023, but agents still write 1.x code: engine.execute(\"...\"), plain SQL strings, select([...]), row[\"name\"], MetaData(bind=), autocommit=True, and untyped Column models behind declarative_base(). The removed APIs fail at once. session.query() keeps running as the legacy Query API, so it spreads. The costly change is silent: 2.x has no autocommit, so an insert inside engine.connect() with no commit is rolled back when the block ends, and nothing reports it.\n\nThis loadout pairs a short Cursor rule and AGENTS.md (a never/always table) with a skill that checks the work. A standard-library Python scanner reports removed 1.x APIs and legacy Query calls as errors, and untyped columns, backref, lazy=\"dynamic\" and writes inside connect() as warnings. Then the tests run with SADeprecationWarning raised as an error and read every write back in a new session. The verifier runs both against a 2.0-style app on the pinned SQLAlchemy 2.1.6 and a 1.x sample, and shows SQLAlchemy refusing the sample's removed calls and rolling back its uncommitted write.\n",
  "highlights": [
    "Never/always table for 2.0-style SQLAlchemy in a .py-scoped Cursor rule",
    "Scanner flags removed 1.x APIs and legacy session.query as errors",
    "Warns on writes inside engine.connect() that are never committed",
    "Typed Mapped models, back_populates and WriteOnlyMapped instead of legacy forms",
    "Tests run with SADeprecationWarning as an error and read writes back"
  ],
  "version": "1.0.0",
  "license": "MIT",
  "author": {
    "name": "SetupBay",
    "url": "https://setupbay.com"
  },
  "credits": [
    {
      "title": "SQLAlchemy docs: SQLAlchemy 2.0 migration guide",
      "url": "https://docs.sqlalchemy.org/en/21/changelog/migration_20.html"
    },
    {
      "title": "SQLAlchemy docs: ORM querying guide",
      "url": "https://docs.sqlalchemy.org/en/21/orm/queryguide/index.html"
    },
    {
      "title": "SQLAlchemy docs: working with transactions and the DBAPI",
      "url": "https://docs.sqlalchemy.org/en/21/tutorial/dbapi_transactions.html"
    },
    {
      "title": "SQLAlchemy 2.1.6 on PyPI (released 21 Oct 2026)",
      "url": "https://pypi.org/project/SQLAlchemy/2.1.6/"
    }
  ],
  "categories": [
    "web-app",
    "data"
  ],
  "stacks": [
    "sqlalchemy",
    "python",
    "pytest"
  ],
  "files": [
    {
      "path": "AGENTS.md",
      "role": "instructions",
      "description": "SQLAlchemy 2 version facts, rules and the done checklist.",
      "skill": null,
      "agent": null,
      "install_to": {
        "claude-code": "AGENTS.md",
        "codex": "AGENTS.md",
        "cursor": "AGENTS.md",
        "gemini-cli": "AGENTS.md",
        "antigravity-cli": "AGENTS.md",
        "copilot": "AGENTS.md"
      },
      "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/AGENTS.md",
      "raw_latest_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/latest/AGENTS.md",
      "bytes": 2244,
      "lang": "markdown",
      "content": "# AGENTS.md: SQLAlchemy 2 project (1.x and legacy Query guard)\n\nThis project uses **SQLAlchemy 2.x** (`sqlalchemy>=2.1,<3`) in **2.0 style**: typed `Mapped[]` models,\n`select()` statements and explicit transactions. Most SQLAlchemy code you have seen is 1.x. Some of it was removed,\nsome still runs as the \"legacy\" Query API, and one change loses writes without an error.\n\n## Version facts\n- Check the pin first: `uv pip show sqlalchemy`.\n- Removed in 2.0: `engine.execute()`, plain SQL strings in `execute()` (use `text()`), `select([...])`,\n  `MetaData(bind=)`, `autocommit=True`, and string keys on rows (`row[\"name\"]`).\n- No autocommit: `with engine.connect() as conn:` rolls back anything you didn't `conn.commit()`. Use\n  `with engine.begin() as conn:` for writes. Sessions work the same way: `with Session(engine) as s, s.begin():`.\n- `session.query(...)` still runs but is legacy. New code uses `session.scalars(select(...))` / `session.execute(...)`.\n- If you're not sure of an API, check the 2.0 migration guide (https://docs.sqlalchemy.org/en/21/changelog/migration_20.html)\n  instead of copying 1.x answers.\n\n## Rules\n- Models: `class Base(DeclarativeBase): pass`, then `name: Mapped[str] = mapped_column(String(80))`.\n  `Mapped[str | None]` for nullable columns.\n- Relationships: `relationship(back_populates=...)` on both sides. Use `lazy=\"raise\"` or `selectinload` when N+1\n  queries matter. Use `WriteOnlyMapped` for big collections, not `lazy=\"dynamic\"`.\n- Queries: `select(User).where(User.name == name)`, then `session.scalars(stmt).all()` or `.one_or_none()`.\n  Use `session.get(User, pk)` for primary keys.\n- Raw SQL only through `text(\"... :name\")` with bound parameters. Never use f-strings.\n- Writes happen inside `engine.begin()` or `session.begin()`, or are followed by an explicit commit.\n- Don't upgrade or downgrade SQLAlchemy without asking the human.\n\n## Before you say \"done\"\n1. Run the `sqlalchemy-2-guard` scanner on the files you touched. It must report `0 error(s)`. Read every `warn`.\n2. Run the tests with SQLAlchemy's own warnings as errors:\n   `uv run pytest -q -W error::sqlalchemy.exc.SADeprecationWarning`.\n3. For every write path you touched, say which test shows the row is really there afterwards.\n"
    },
    {
      "path": "CLAUDE.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Claude Code.",
      "skill": null,
      "agent": "claude-code",
      "install_to": {
        "claude-code": "CLAUDE.md",
        "codex": null,
        "cursor": null,
        "gemini-cli": null,
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/CLAUDE.md",
      "raw_latest_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/latest/CLAUDE.md",
      "bytes": 401,
      "lang": "markdown",
      "content": "# CLAUDE.md\n\n@AGENTS.md\n\n## Claude Code notes\n\n- Skills from this loadout live in `.claude/skills/`: `sqlalchemy-2-guard`. Use them when their description matches the task.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From SetupBay \"SQLAlchemy 2 guard against 1.x and legacy Query code\" v1.0.0 — https://setupbay.com/loadouts/sqlalchemy-2-style-guard/ -->\n"
    },
    {
      "path": "GEMINI.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Gemini CLI.",
      "skill": null,
      "agent": "gemini-cli",
      "install_to": {
        "claude-code": null,
        "codex": null,
        "cursor": null,
        "gemini-cli": "GEMINI.md",
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/GEMINI.md",
      "raw_latest_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/latest/GEMINI.md",
      "bytes": 402,
      "lang": "markdown",
      "content": "# GEMINI.md\n\n@./AGENTS.md\n\n## Gemini CLI notes\n\n- Skills from this loadout live in `.agents/skills/`: `sqlalchemy-2-guard`. Use them when their description matches the task.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From SetupBay \"SQLAlchemy 2 guard against 1.x and legacy Query code\" v1.0.0 — https://setupbay.com/loadouts/sqlalchemy-2-style-guard/ -->\n"
    },
    {
      "path": ".cursor/rules/sqlalchemy-2-style.mdc",
      "role": "rules",
      "description": "Never/always table for Python files.",
      "skill": null,
      "agent": null,
      "install_to": {
        "claude-code": null,
        "codex": null,
        "cursor": ".cursor/rules/sqlalchemy-2-style.mdc",
        "gemini-cli": null,
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/.cursor/rules/sqlalchemy-2-style.mdc",
      "raw_latest_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/latest/.cursor/rules/sqlalchemy-2-style.mdc",
      "bytes": 1196,
      "lang": "markdown",
      "content": "---\ndescription: SQLAlchemy 2.0 style only; no removed 1.x APIs or legacy Query code\nglobs: \"**/*.py\"\nalwaysApply: false\n---\n\nThis project uses SQLAlchemy 2.x in 2.0 style. There is no autocommit.\n\n| Never (1.x / legacy) | Always (2.0 style) |\n|---|---|\n| `engine.execute(\"select ...\")` | `with engine.begin() as conn: conn.execute(text(\"...\"), params)` |\n| `conn.execute(\"raw sql\")` | `conn.execute(text(\"... :id\"), {\"id\": 1})` |\n| `select([User.id])` | `select(User.id)` |\n| `session.query(User).filter_by(name=n).all()` | `session.scalars(select(User).where(User.name == n)).all()` |\n| `session.query(User).get(1)` | `session.get(User, 1)` |\n| `row[\"name\"]` | `row.name` or `row._mapping[\"name\"]` |\n| `declarative_base()`, `id = Column(Integer, ...)` | `class Base(DeclarativeBase)`, `id: Mapped[int] = mapped_column(primary_key=True)` |\n| `relationship(backref=\"x\")`, `lazy=\"dynamic\"` | `back_populates=` both sides, `WriteOnlyMapped` |\n| `MetaData(bind=engine)`, `autocommit=True` | pass the engine; `with Session(engine) as s, s.begin():` |\n| writes inside `engine.connect()` with no commit | `engine.begin()` |\n\n- After editing, run the `sqlalchemy-2-guard` skill's scanner and the tests.\n"
    },
    {
      "path": "skills/sqlalchemy-2-guard/SKILL.md",
      "role": "skill",
      "description": "Scan for 1.x and legacy SQLAlchemy code, then run the tests with deprecations as errors.",
      "skill": "sqlalchemy-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/sqlalchemy-2-guard/SKILL.md",
        "codex": ".agents/skills/sqlalchemy-2-guard/SKILL.md",
        "cursor": ".agents/skills/sqlalchemy-2-guard/SKILL.md",
        "gemini-cli": ".agents/skills/sqlalchemy-2-guard/SKILL.md",
        "antigravity-cli": ".agents/skills/sqlalchemy-2-guard/SKILL.md",
        "copilot": ".agents/skills/sqlalchemy-2-guard/SKILL.md"
      },
      "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/SKILL.md",
      "raw_latest_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/latest/skills/sqlalchemy-2-guard/SKILL.md",
      "bytes": 2427,
      "lang": "markdown",
      "content": "---\nname: sqlalchemy-2-guard\ndescription: Check Python for SQLAlchemy 1.x APIs removed in 2.0, legacy session.query code, untyped models and writes that are never committed, before saying a database change is done. Use after writing or editing SQLAlchemy models, queries or transactions, when SQLAlchemy raises ObjectNotExecutableError or ArgumentError, or when porting 1.x snippets.\n---\n\n# SQLAlchemy 2 guard\n\nSQLAlchemy 2.0 came out in January 2023, and agents still write 1.x: `engine.execute(\"...\")`, `select([...])`,\n`row[\"name\"]`, `session.query()`, `declarative_base()` with untyped `Column`s. The removed APIs fail at once.\n`session.query()` keeps working as legacy code. The dangerous change is quiet: there is no autocommit, so a write\ndone inside `engine.connect()` without `commit()` is rolled back when the block ends, and no error is raised.\n\n## 1. Confirm the version\n- `uv run python -c \"import sqlalchemy; print(sqlalchemy.__version__)\"` should print `2.x`. If it prints `1.4`,\n  ask before migrating. 1.4 with `SQLALCHEMY_WARN_20=1` is the stepping stone.\n\n## 2. Scan\n```bash\npython3 .agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py app tests\n```\n(Use the path the skill was installed to: `.claude/skills/...` for Claude Code, `.agents/skills/...` for the others.)\n\n- Every `error` line is removed 1.x code or the legacy Query API. Fix it with the replacement the line gives.\n  `references/migration-table.md` has before/after code.\n- `connect-then-write` warnings: if the block writes, switch to `engine.begin()` or call `conn.commit()`. If it only\n  reads, add `# guard: ok`. That comment silences warnings, never errors.\n- `untyped-column` and `backref` warnings: convert the model to `Mapped[]` / `mapped_column` and `back_populates`.\n  These conversions don't change the schema. Run `alembic check` (or compare `CREATE TABLE` output) to confirm.\n\n## 3. Let SQLAlchemy check it\n```bash\nuv run pytest -q -W error::sqlalchemy.exc.SADeprecationWarning\n```\n- Legacy calls such as `Query.get()` warn `LegacyAPIWarning`, a subclass of `SADeprecationWarning`, so they fail here.\n- Every write test should read the row back in a **new** session or connection. If it reads it back in the same\n  one, an uncommitted write still looks fine.\n\n## 4. Report\nSay how many 1.x calls you replaced, which write paths you checked for commits and with which test, and that the\nscanner and the tests were clean.\n"
    },
    {
      "path": "skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
      "role": "reference",
      "description": "Read-only scanner for removed and legacy SQLAlchemy APIs and uncommitted writes.",
      "skill": "sqlalchemy-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
        "codex": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
        "cursor": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
        "gemini-cli": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
        "antigravity-cli": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
        "copilot": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py"
      },
      "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
      "raw_latest_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/latest/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
      "bytes": 6208,
      "lang": "markdown",
      "content": "#!/usr/bin/env python3\n\"\"\"Find SQLAlchemy 1.x code (and the legacy Query API) in a project on SQLAlchemy 2.x.\n\nUsage: python3 sqlalchemy2_guard.py [PATH ...]        (default: the current folder)\n       python3 sqlalchemy2_guard.py --list            (print every rule)\n\nA \"guard: ok\" comment on a line silences its warnings (never its errors).\nPrints one line per finding:  path:line: level [rule] what is wrong -> what to use\nExit 0 when nothing at \"error\" level is found, 1 when something is, 2 on bad usage.\nStandard library only. Read-only: it never edits a file and makes no network calls.\n\"\"\"\nimport fnmatch\nimport os\nimport re\nimport sys\n\n# (rule id, level, regex, message, file patterns). Patterns run against each line with comments removed.\nRULES = [\n    ('engine-execute', 'error', '\\\\b(engine|eng|db_engine|self\\\\.engine)\\\\.execute\\\\(',\n     'Engine.execute() was removed in 2.0 -> with engine.begin() as conn: conn.execute(text(...))', []),\n    ('select-list', 'error', '\\\\bselect\\\\(\\\\s*\\\\[',\n     'select([a, b]) was removed -> select(a, b)', []),\n    ('string-sql', 'error', '\\\\.execute\\\\(\\\\s*[frbu]*[\\\\\"\\']',\n     'executing a plain SQL string was removed -> conn.execute(text(\"...\"), {\"name\": value})', []),\n    ('metadata-bind', 'error', '\\\\bMetaData\\\\([^)]*\\\\bbind\\\\s*=',\n     'MetaData(bind=...) was removed -> pass the engine or connection explicitly', []),\n    ('autocommit', 'error', '\\\\bautocommit\\\\s*=\\\\s*True',\n     'Session/sessionmaker(autocommit=True) was removed -> with Session(engine) as s, s.begin(): ...', []),\n    ('row-string-key', 'error', '\\\\b(row|r|result_row|record)\\\\[\\\\s*[\\\\\"\\']',\n     \"rows are tuples: row['name'] fails -> row.name or row._mapping['name']\", []),\n    ('ext-declarative', 'error', 'sqlalchemy\\\\.ext\\\\.declarative\\\\s+import\\\\s+[^#]*declarative_base',\n     'sqlalchemy.ext.declarative.declarative_base moved -> class Base(DeclarativeBase): pass', []),\n    ('query-get', 'error', '\\\\.query\\\\([^)]*\\\\)\\\\.get\\\\(',\n     'Query.get() is legacy -> session.get(Model, pk)', []),\n    ('legacy-query', 'error', '\\\\b(session|db|s|sess|self\\\\.session|db\\\\.session)\\\\.query\\\\(',\n     'session.query() is the legacy Query API (still runs) -> session.scalars(select(Model).where(...))', []),\n    ('orm-relation', 'error', '\\\\borm\\\\.relation\\\\(|\\\\brelation\\\\(',\n     'relation() -> relationship()', []),\n    ('declarative-base-fn', 'warn', '\\\\bdeclarative_base\\\\(\\\\s*\\\\)',\n     'declarative_base() works but 2.0 style is class Base(DeclarativeBase): pass, with Mapped[] annotations', []),\n    ('untyped-column', 'warn', '^\\\\s+\\\\w+\\\\s*=\\\\s*(sa\\\\.)?Column\\\\(',\n     'Column() in a mapped class -> name: Mapped[str] = mapped_column(...) so types reach the type checker', []),\n    ('backref', 'warn', '\\\\bbackref\\\\s*=',\n     'backref= -> relationship(back_populates=...) on both sides, so both attributes are visible', []),\n    ('future-flag', 'warn', '\\\\bfuture\\\\s*=\\\\s*True',\n     'future=True does nothing on 2.x; remove it', []),\n    ('dynamic-loader', 'warn', 'lazy\\\\s*=\\\\s*[\\\\\"\\']dynamic[\\\\\"\\']',\n     \"lazy='dynamic' is legacy -> WriteOnlyMapped[...] with lazy='write_only'\", []),\n    ('connect-then-write', 'warn', 'with\\\\s+\\\\w+\\\\.connect\\\\(\\\\)\\\\s+as\\\\s+\\\\w+\\\\s*:',\n     'engine.connect() does not commit: writes are rolled back unless you call conn.commit() -> use engine.begin() for writes', []),\n]\nFILES = ['*.py']\nCOMMENT = '#'\nSKIP_DIRS = {\".git\", \".venv\", \"venv\", \"node_modules\", \"__pycache__\", \".agents\", \".claude\", \".cursor\", \"dist\", \"build\", \"target\", \".godot\"}\nCOMPILED = [(rid, lvl, re.compile(rx), msg, globs) for rid, lvl, rx, msg, globs in RULES]\n\n\ndef strip_comment(line):\n    \"\"\"Drop a trailing comment, leaving string literals alone.\"\"\"\n    q = None\n    i = 0\n    while i < len(line):\n        c = line[i]\n        if q:\n            if c == \"\\\\\":\n                i += 2\n                continue\n            if c == q:\n                q = None\n        elif c in \"\\\"'`\":\n            q = c\n        elif line.startswith(COMMENT, i):\n            return line[:i]\n        i += 1\n    return line\n\n\ndef wanted(name):\n    return any(fnmatch.fnmatch(name, g) for g in FILES)\n\n\ndef walk(paths):\n    for p in paths:\n        if os.path.isfile(p):\n            yield p\n            continue\n        for root, dirs, files in os.walk(p):\n            dirs[:] = sorted(d for d in dirs if d not in SKIP_DIRS)\n            for f in sorted(files):\n                if wanted(f):\n                    yield os.path.join(root, f)\n\n\ndef scan(path):\n    out = []\n    name = os.path.basename(path)\n    try:\n        with open(path, encoding=\"utf-8\", errors=\"replace\") as fh:\n            lines = fh.read().splitlines()\n    except OSError as e:\n        return [(path, 0, \"error\", \"unreadable\", str(e))]\n    for n, raw in enumerate(lines, 1):\n        code = strip_comment(raw)\n        if not code.strip():\n            continue\n        accepted = \"guard: ok\" in raw  # a person accepted the warnings on this line\n        for rid, lvl, rx, msg, globs in COMPILED:\n            if accepted and lvl == \"warn\":\n                continue\n            if globs and not any(fnmatch.fnmatch(name, g) for g in globs):\n                continue\n            if rx.search(code):\n                out.append((path, n, lvl, rid, msg))\n    return out\n\n\ndef main(argv):\n    if \"--list\" in argv:\n        for rid, lvl, _, msg, globs in RULES:\n            print(f\"{lvl:5} [{rid}] {msg}\" + (f\"  (only {', '.join(globs)})\" if globs else \"\"))\n        return 0\n    if any(a.startswith(\"-\") for a in argv):\n        print(__doc__)\n        return 2\n    paths = argv or [\".\"]\n    for p in paths:\n        if not os.path.exists(p):\n            print(f\"no such path: {p}\", file=sys.stderr)\n            return 2\n    files = list(walk(paths))\n    findings = []\n    for f in files:\n        findings.extend(scan(f))\n    for path, n, lvl, rid, msg in findings:\n        print(f\"{os.path.relpath(path)}:{n}: {lvl} [{rid}] {msg}\")\n    errors = sum(1 for x in findings if x[2] == \"error\")\n    warns = sum(1 for x in findings if x[2] == \"warn\")\n    print(f\"sqlalchemy2_guard: {len(files)} file(s), {errors} error(s), {warns} warning(s)\")\n    return 1 if errors else 0\n\n\nif __name__ == \"__main__\":\n    sys.exit(main(sys.argv[1:]))\n"
    },
    {
      "path": "skills/sqlalchemy-2-guard/references/migration-table.md",
      "role": "reference",
      "description": "SQLAlchemy 1.x to 2.0 style table, including transactions.",
      "skill": "sqlalchemy-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/sqlalchemy-2-guard/references/migration-table.md",
        "codex": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md",
        "cursor": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md",
        "gemini-cli": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md",
        "antigravity-cli": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md",
        "copilot": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md"
      },
      "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/migration-table.md",
      "raw_latest_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/latest/skills/sqlalchemy-2-guard/references/migration-table.md",
      "bytes": 2233,
      "lang": "markdown",
      "content": "# SQLAlchemy 1.x → 2.0 style table\n\nFrom the SQLAlchemy 2.0 migration guide (https://docs.sqlalchemy.org/en/21/changelog/migration_20.html) and the\nORM querying guide. Checked against SQLAlchemy 2.1.6.\n\n## Removed in 2.0 (raises)\n\n| 1.x | 2.x | Error on 2.1.6 |\n|---|---|---|\n| `engine.execute(\"select 1\")` | `with engine.connect() as c: c.execute(text(\"select 1\"))` | `AttributeError` |\n| `conn.execute(\"select 1\")` | `conn.execute(text(\"select 1\"))` | `ObjectNotExecutableError` |\n| `select([User.id, User.name])` | `select(User.id, User.name)` | `ArgumentError` |\n| `MetaData(bind=engine)` | `MetaData()`; pass the engine to `create_all(engine)` | `TypeError` |\n| `Session(engine, autocommit=True)` | `with Session(engine) as s, s.begin(): ...` | `ArgumentError` |\n| `row[\"name\"]` | `row.name`, `row._mapping[\"name\"]` | `TypeError` |\n\n## Legacy (still runs, warns or is discouraged)\n\n| 1.x | 2.0 style |\n|---|---|\n| `session.query(User).all()` | `session.scalars(select(User)).all()` |\n| `session.query(User).filter_by(name=n).first()` | `session.scalars(select(User).filter_by(name=n)).first()` |\n| `session.query(User).get(1)` (`LegacyAPIWarning`) | `session.get(User, 1)` |\n| `session.query(func.count(User.id)).scalar()` | `session.scalar(select(func.count(User.id)))` |\n| `from sqlalchemy.ext.declarative import declarative_base` (`MovedIn20Warning`) | `class Base(DeclarativeBase): pass` |\n| `id = Column(Integer, primary_key=True)` | `id: Mapped[int] = mapped_column(primary_key=True)` |\n| `name = Column(String, nullable=True)` | `name: Mapped[str \\| None] = mapped_column(String(80))` |\n| `relationship(\"Post\", backref=\"author\")` | `posts: Mapped[list[\"Post\"]] = relationship(back_populates=\"author\")` on both sides |\n| `lazy=\"dynamic\"` | `posts: WriteOnlyMapped[\"Post\"] = relationship()` |\n| `create_engine(url, future=True)` | `create_engine(url)` |\n\n## Transactions: writes that vanish\n\n| Code | What happens on 2.x | Fix |\n|---|---|---|\n| `with engine.connect() as c: c.execute(insert_stmt)` | rolled back at the end of the block | `with engine.begin() as c:` or `c.commit()` |\n| `s = Session(engine); s.add(u)` and no commit | discarded when the session closes | `with Session(engine) as s, s.begin(): s.add(u)` |\n"
    },
    {
      "path": "skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
      "role": "reference",
      "description": "A SQLAlchemy 1.x module for checking the guard.",
      "skill": "sqlalchemy-2-guard",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
        "codex": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
        "cursor": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
        "gemini-cli": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
        "antigravity-cli": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
        "copilot": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt"
      },
      "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
      "raw_latest_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/latest/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
      "bytes": 964,
      "lang": "markdown",
      "content": "# A SQLAlchemy 1.3/1.4 module, used to check the guard. Each line is removed, legacy or silently different in 2.x.\nfrom sqlalchemy import Column, Integer, MetaData, String, create_engine, select\nfrom sqlalchemy.ext.declarative import declarative_base\nfrom sqlalchemy.orm import relationship, sessionmaker\nengine = create_engine(\"sqlite:///app.db\", future=True)\nmeta = MetaData(bind=engine)\nBase = declarative_base()\nclass User(Base):\n    __tablename__ = \"users\"\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    posts = relationship(\"Post\", backref=\"author\", lazy=\"dynamic\")\nSession = sessionmaker(bind=engine, autocommit=True)\nsession = Session()\nadmins = session.query(User).filter_by(name=\"admin\").all()\none = session.query(User).get(1)\nrows = engine.execute(\"select id, name from users\")\nfor row in rows:\n    print(row[\"name\"])\nids = select([User.id])\nwith engine.connect() as conn:\n    conn.execute(text(\"update users set name = 'x'\"))\n"
    }
  ],
  "requires": {
    "tools": [
      "python3",
      "uv"
    ],
    "env": [],
    "mcp": []
  },
  "tested": {
    "status": "untested",
    "last_run": null,
    "fixture": null,
    "per_agent": {
      "claude-code": "untested",
      "codex": "untested",
      "cursor": "untested",
      "gemini-cli": "untested",
      "antigravity-cli": "untested",
      "copilot": "untested"
    }
  },
  "security": {
    "scanned": true,
    "scanner": "intake-precheck/2",
    "verdict": "clean",
    "network": true,
    "scripts": [
      "sqlalchemy2_guard.py"
    ],
    "notes": "The scanner only reads .py files and prints findings; it never edits files and makes no network calls. Running the tests with uv may download the pinned packages."
  },
  "featured": false,
  "deprecated": false,
  "last_checked": "2026-10-29",
  "published": "2026-10-29",
  "updated": "2026-10-29",
  "compatibility": {
    "claude-code": "native",
    "codex": "native",
    "cursor": "native",
    "gemini-cli": "native",
    "antigravity-cli": "native",
    "copilot": "native"
  },
  "counts": {
    "rules": 2,
    "skills": 1,
    "mcp": 0
  },
  "url": "https://setupbay.com/loadouts/sqlalchemy-2-style-guard/",
  "api_url": "https://setupbay.com/api/loadouts/sqlalchemy-2-style-guard.json",
  "verification": {
    "level": "verified-install",
    "status": "verified",
    "label": "Verified install",
    "verified": true,
    "checked_at": "2026-10-29T12:21:46Z",
    "commit": "783d9eb22f6c3127aa49a46a83860bc795db3892",
    "content_current": true,
    "agent_tests": "not-run",
    "counts": {
      "pass": 9,
      "fail": 0,
      "skip": 0,
      "not_applicable": 1
    },
    "meaning": "Level 1: automated checks on the files (parse, install paths, MCP config, safety scan, references, size, licence, starter build). No AI agent was run.",
    "checks": [
      {
        "id": "listing",
        "name": "Listing",
        "status": "pass",
        "summary": "Schema valid; 8 files declared, none missing or extra",
        "details": [
          "tested.status: untested (agent tests are separate from Level 1)"
        ]
      },
      {
        "id": "parse",
        "name": "Files parse",
        "status": "pass",
        "summary": "All 8 files parse; front matter valid",
        "details": []
      },
      {
        "id": "adapters",
        "name": "Adapters",
        "status": "pass",
        "summary": "CLAUDE.md and GEMINI.md import AGENTS.md and are up to date",
        "details": [
          "CLAUDE.md: matches the generator",
          "GEMINI.md: matches the generator"
        ]
      },
      {
        "id": "install-paths",
        "name": "Install paths",
        "status": "pass",
        "summary": "Correct paths for all 6 agents; layouts re-discovered",
        "details": [
          "Claude Code: 6 files, 1 skill in .claude/skills/",
          "Codex CLI: 5 files, 1 skill in .agents/skills/",
          "Cursor: 6 files, 1 skill in .agents/skills/, 1 rule",
          "Gemini CLI: 6 files, 1 skill in .agents/skills/",
          "Antigravity CLI: 5 files, 1 skill in .agents/skills/",
          "GitHub Copilot: 5 files, 1 skill in .agents/skills/"
        ]
      },
      {
        "id": "mcp",
        "name": "MCP config",
        "status": "n/a",
        "summary": "No MCP servers in this loadout",
        "details": []
      },
      {
        "id": "safety",
        "name": "Safety scan",
        "status": "pass",
        "summary": "Clean: no credentials, risky shell, hidden text or covert instructions",
        "details": [
          "Scanner intake-precheck/2: verdict clean; network no (listing says yes)"
        ]
      },
      {
        "id": "references",
        "name": "References",
        "status": "pass",
        "summary": "2 references between files resolve for every agent",
        "details": []
      },
      {
        "id": "size",
        "name": "Size limits",
        "status": "pass",
        "summary": "8 files, 15.7 KB total; largest skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py 6.1 KB",
        "details": [
          "Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule"
        ]
      },
      {
        "id": "licence",
        "name": "Licence",
        "status": "pass",
        "summary": "MIT, by SetupBay; text in the repository LICENSE",
        "details": []
      },
      {
        "id": "starter-build",
        "name": "Starter build",
        "status": "pass",
        "summary": "sqlalchemy2_guard.py passes a 2.0-style data layer and flags every 1.x line in the skill's sample: 10 removed or legacy calls as errors, 7 warnings including a write inside engine.connect(). The pinned SQLAlchemy 2.1.6 runs the app's tests with SADeprecationWarning as an error, refuses the sample's ",
        "details": [
          "Applied 12 loadout files at every agent's paths",
          "✓ scanner: the 2.0-style app and tests are clean: bash -c python3 .agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py app tests; echo \"exit=$?\"",
          "✓ scanner: the 1.x sample is flagged line by line: bash -c mkdir -p /tmp/sqlalchemy1-sample && cp .claude/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt /tmp/sqlalchemy1-sample/models1.py && python3 .claude/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py /tmp/sqlalchemy1-sample; echo \"exit=$?\"",
          "✓ pytest on SQLAlchemy 2.1.6 with SADeprecationWarning as an error: uv run --python 3.12 pytest -q -p no:cacheprovider -W error::sqlalchemy.exc.SADeprecationWarning",
          "✓ SQLAlchemy 2.1.6 on the sample's 1.x calls: uv run --python 3.12 python legacy_probe.py",
          "Covers: The scanner's rules for removed 1.x APIs, the legacy Query API and 1.x model style, against a real 1.x module",
          "Covers: No false positives on typed DeclarativeBase models with back_populates, lazy='raise', selectinload, session.get, text() with bound parameters and engine.begin()",
          "Covers: SQLAlchemy 2.1.6 as the second check: removed calls are refused, Query.get() warns LegacyAPIWarning (an error in the tests), and an uncommitted write in connect() is rolled back",
          "Covers: Not covered: Postgres-specific behaviour and Alembic migrations (the fixture uses in-memory SQLite)"
        ]
      }
    ]
  },
  "install": {
    "claude-code": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "CLAUDE.md",
          "target": "CLAUDE.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/CLAUDE.md",
          "role": "adapter"
        },
        {
          "path": "skills/sqlalchemy-2-guard/SKILL.md",
          "target": ".claude/skills/sqlalchemy-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "target": ".claude/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/migration-table.md",
          "target": ".claude/skills/sqlalchemy-2-guard/references/migration-table.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/migration-table.md",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "target": ".claude/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/sqlalchemy-2-style-guard/claude-code.zip"
    },
    "codex": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/sqlalchemy-2-guard/SKILL.md",
          "target": ".agents/skills/sqlalchemy-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "target": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/migration-table.md",
          "target": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/migration-table.md",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "target": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/sqlalchemy-2-style-guard/codex.zip"
    },
    "cursor": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": ".cursor/rules/sqlalchemy-2-style.mdc",
          "target": ".cursor/rules/sqlalchemy-2-style.mdc",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/.cursor/rules/sqlalchemy-2-style.mdc",
          "role": "rules"
        },
        {
          "path": "skills/sqlalchemy-2-guard/SKILL.md",
          "target": ".agents/skills/sqlalchemy-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "target": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/migration-table.md",
          "target": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/migration-table.md",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "target": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/sqlalchemy-2-style-guard/cursor.zip"
    },
    "gemini-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "GEMINI.md",
          "target": "GEMINI.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/GEMINI.md",
          "role": "adapter"
        },
        {
          "path": "skills/sqlalchemy-2-guard/SKILL.md",
          "target": ".agents/skills/sqlalchemy-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "target": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/migration-table.md",
          "target": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/migration-table.md",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "target": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/sqlalchemy-2-style-guard/gemini-cli.zip"
    },
    "antigravity-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/sqlalchemy-2-guard/SKILL.md",
          "target": ".agents/skills/sqlalchemy-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "target": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/migration-table.md",
          "target": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/migration-table.md",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "target": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/sqlalchemy-2-style-guard/antigravity-cli.zip"
    },
    "copilot": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/sqlalchemy-2-guard/SKILL.md",
          "target": ".agents/skills/sqlalchemy-2-guard/SKILL.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "target": ".agents/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/scripts/sqlalchemy2_guard.py",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/migration-table.md",
          "target": ".agents/skills/sqlalchemy-2-guard/references/migration-table.md",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/migration-table.md",
          "role": "reference"
        },
        {
          "path": "skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "target": ".agents/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "raw_url": "https://setupbay.com/raw/sqlalchemy-2-style-guard/1.0.0/skills/sqlalchemy-2-guard/references/sqlalchemy1-sample.py.txt",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://setupbay.com/download/sqlalchemy-2-style-guard/copilot.zip"
    }
  },
  "source_zip_url": "https://setupbay.com/download/sqlalchemy-2-style-guard/source.zip",
  "claude_code_plugin": {
    "name": "sqlalchemy-2-style-guard",
    "marketplace_url": "https://setupbay.com/marketplace.json",
    "install": [
      "/plugin marketplace add https://setupbay.com/marketplace.json",
      "/plugin install sqlalchemy-2-style-guard@setupbay"
    ],
    "zip_url": "https://setupbay.com/plugins/sqlalchemy-2-style-guard.zip",
    "sha256": "992aa8b38418d06849faf095aeb45c7ba5bdc80f6ef88ea2d759cf622bcdd457",
    "carries": [
      "skills"
    ],
    "note": "Plugins do not carry project rules (AGENTS.md, CLAUDE.md); install those from install.claude-code."
  }
}