From 749b9cdf91d069e34fd0c106ed808c6192f8b162 Mon Sep 17 00:00:00 2001 From: Hadrien David Date: Thu, 26 Feb 2026 14:01:55 -0500 Subject: [PATCH] chore: update beads config --- .beads/hooks/post-checkout | 4 +--- .beads/hooks/post-merge | 4 ++-- .beads/hooks/pre-commit | 4 ++-- .beads/hooks/pre-push | 19 ------------------- .beads/hooks/prepare-commit-msg | 24 ------------------------ .beads/issues.jsonl | 6 ------ .gitignore | 3 +++ 7 files changed, 8 insertions(+), 56 deletions(-) delete mode 100755 .beads/hooks/pre-push delete mode 100755 .beads/hooks/prepare-commit-msg delete mode 100644 .beads/issues.jsonl diff --git a/.beads/hooks/post-checkout b/.beads/hooks/post-checkout index c80444f..9291878 100755 --- a/.beads/hooks/post-checkout +++ b/.beads/hooks/post-checkout @@ -4,7 +4,7 @@ # # bd (beads) post-checkout hook - thin shim # -# This shim delegates to 'bd hook post-checkout' which contains +# This shim delegates to 'bd hooks post-checkout' which contains # the actual hook logic. This pattern ensures hook behavior is always # in sync with the installed bd version - no manual updates needed. # @@ -19,5 +19,3 @@ if ! command -v bd >/dev/null 2>&1; then # Silently skip - post-checkout is called frequently exit 0 fi - -exec bd hook post-checkout "$@" diff --git a/.beads/hooks/post-merge b/.beads/hooks/post-merge index 7b501e3..a4783b9 100755 --- a/.beads/hooks/post-merge +++ b/.beads/hooks/post-merge @@ -4,7 +4,7 @@ # # bd (beads) post-merge hook - thin shim # -# This shim delegates to 'bd hook post-merge' which contains +# This shim delegates to 'bd hooks post-merge' which contains # the actual hook logic. This pattern ensures hook behavior is always # in sync with the installed bd version - no manual updates needed. # @@ -21,4 +21,4 @@ if ! command -v bd >/dev/null 2>&1; then exit 0 fi -exec bd hook post-merge "$@" +exec bd hooks post-merge "$@" diff --git a/.beads/hooks/pre-commit b/.beads/hooks/pre-commit index 438b6aa..d5da014 100755 --- a/.beads/hooks/pre-commit +++ b/.beads/hooks/pre-commit @@ -4,7 +4,7 @@ # # bd (beads) pre-commit hook — thin shim # -# Delegates to 'bd hook pre-commit' which contains the actual hook logic. +# Delegates to 'bd hooks pre-commit' which contains the actual hook logic. # This pattern ensures hook behavior is always in sync with the installed # bd version — no manual updates needed. # @@ -22,4 +22,4 @@ if ! command -v bd >/dev/null 2>&1; then exit 0 fi -exec bd hook pre-commit "$@" +exec bd hooks pre-commit "$@" diff --git a/.beads/hooks/pre-push b/.beads/hooks/pre-push deleted file mode 100755 index 5591303..0000000 --- a/.beads/hooks/pre-push +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env sh -# bd-shim v1 -# bd-hooks-version: 0.55.4 -# -# bd (beads) pre-push hook - thin shim -# -# This shim delegates to 'bd hooks run pre-push' which contains -# the actual hook logic. This pattern ensures hook behavior is always -# in sync with the installed bd version - no manual updates needed. - -# Check if bd is available -if ! command -v bd >/dev/null 2>&1; then - echo "Warning: bd command not found in PATH, skipping pre-push hook" >&2 - echo " Install bd: brew install beads" >&2 - echo " Or add bd to your PATH" >&2 - exit 0 -fi - -exec bd hooks run pre-push "$@" diff --git a/.beads/hooks/prepare-commit-msg b/.beads/hooks/prepare-commit-msg deleted file mode 100755 index 316ab46..0000000 --- a/.beads/hooks/prepare-commit-msg +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env sh -# bd-shim v1 -# bd-hooks-version: 0.48.0 -# -# bd (beads) prepare-commit-msg hook - thin shim -# -# This shim delegates to 'bd hooks run prepare-commit-msg' which contains -# the actual hook logic. This pattern ensures hook behavior is always -# in sync with the installed bd version - no manual updates needed. -# -# Arguments: -# $1 = path to the commit message file -# $2 = source of commit message (message, template, merge, squash, commit) -# $3 = commit SHA-1 (if -c, -C, or --amend) - -# Check if bd is available -if ! command -v bd >/dev/null 2>&1; then - echo "Warning: bd command not found in PATH, skipping prepare-commit-msg hook" >&2 - echo " Install bd: brew install beads" >&2 - echo " Or add bd to your PATH" >&2 - exit 0 -fi - -exec bd hooks run prepare-commit-msg "$@" diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl deleted file mode 100644 index 51223f9..0000000 --- a/.beads/issues.jsonl +++ /dev/null @@ -1,6 +0,0 @@ -{"id":"fastsqla-0nf","title":"Add Agent Skills to FastSQLA","description":"Add Agent Skills (agentskills.io) to FastSQLA so AI coding agents can discover and use FastSQLA more effectively. Skills are SKILL.md files in folders under skills/ that teach agents how to perform specific tasks with the library. Each skill follows the Agent Skills spec: YAML frontmatter (name, description) + markdown instructions with progressive disclosure.\n\n## Skills to create\n\n1. **fastsqla-setup** — Installation, env var configuration, lifespan setup, composing lifespans\n2. **fastsqla-session** — Session dependency, open_session(), flush vs commit, IntegrityError handling\n3. **fastsqla-pagination** — Paginate dependency, Page/Item/Collection models, new_pagination() customization\n4. **fastsqla-models** — Base (DeclarativeBase + DeferredReflection), SQLModel integration, reflection patterns\n5. **fastsqla-testing** — Fixture chains, ASGI testing with httpx + asgi-lifespan, teardown, SQLModel test marks\n\n## Directory structure\n\n```\nskills/\n├── fastsqla-setup/\n│ └── SKILL.md\n├── fastsqla-session/\n│ └── SKILL.md\n├── fastsqla-pagination/\n│ └── SKILL.md\n├── fastsqla-models/\n│ └── SKILL.md\n└── fastsqla-testing/\n └── SKILL.md\n```\n\n## References\n\n- Spec: https://agentskills.io/specification\n- Examples: https://github.com/anthropics/skills\n- FastSQLA source: src/fastsqla.py (single 437-line module)","status":"in_progress","priority":2,"issue_type":"epic","owner":"hadrien@ectobal.com","created_at":"2026-02-26T17:32:20Z","created_by":"Hadrien David","updated_at":"2026-02-26T17:35:40Z"} -{"id":"fastsqla-0nf.1","title":"Create fastsqla-setup skill","description":"Create `skills/fastsqla-setup/SKILL.md` covering:\n\n- Installation (`pip install FastSQLA`, optional `[sqlmodel]` extra)\n- Required async driver packages (asyncpg, aiosqlite, aiomysql) and URL schemes\n- **Environment variable configuration** (`fastsqla.lifespan`): `SQLALCHEMY_URL` required, all `SQLALCHEMY_*` env vars passed to `async_engine_from_config`, case-insensitive\n- **Programmatic configuration** (`new_lifespan()`): same args as `create_async_engine`\n- **Composing multiple lifespans** with `AsyncExitStack` pattern\n- What the lifespan does on startup (engine creation, `Base.prepare()`, `SessionFactory.configure()`) and shutdown\n- Warning about stray `SQLALCHEMY_*` env vars\n- Startup error message when URL is missing\n\n## Acceptance criteria\n\n- SKILL.md has valid frontmatter (name matches directory, description \u003c 1024 chars)\n- Content \u003c 500 lines\n- Covers both env var and programmatic setup paths\n- Includes lifespan composition example","status":"in_progress","priority":2,"issue_type":"task","owner":"hadrien@ectobal.com","estimated_minutes":30,"created_at":"2026-02-26T17:32:31Z","created_by":"Hadrien David","updated_at":"2026-02-26T17:35:43Z","dependencies":[{"issue_id":"fastsqla-0nf.1","depends_on_id":"fastsqla-0nf","type":"parent-child","created_at":"2026-02-26T12:32:30Z","created_by":"Hadrien David","metadata":"{}"}]} -{"id":"fastsqla-0nf.2","title":"Create fastsqla-session skill","description":"Create `skills/fastsqla-session/SKILL.md` covering:\n\nThis is the **highest-value skill** — session management is the most error-prone area for users.\n\n- **Session dependency** (`Session`): type annotation for endpoint injection, auto-commit on success, rollback on exception, close always\n- **flush() vs commit()**: never call `session.commit()` in endpoints, use `session.flush()` to get server-generated data (auto-increment IDs). Include correct and incorrect examples.\n- **IntegrityError handling**: catch after `flush()`, re-raise as `HTTPException` to trigger automatic rollback. Explain why silent catch leaves session in broken state.\n- **open_session()**: async context manager for background tasks, scripts, startup routines. Same commit/rollback/close semantics. Document the edge case: if context body succeeds but `commit()` fails, it rolls back and re-raises.\n- Summary of rules\n\n## Source reference\n\nSession lifecycle: `src/fastsqla.py:205-258` (`open_session`)\nSession dependency: `src/fastsqla.py:260-320` (`new_session`, `Session`)\n\n## Acceptance criteria\n\n- SKILL.md has valid frontmatter\n- Content \u003c 500 lines\n- Includes both correct and incorrect code examples for flush vs commit\n- Covers IntegrityError pattern from test_session_dependency.py","status":"in_progress","priority":1,"issue_type":"task","owner":"hadrien@ectobal.com","estimated_minutes":30,"created_at":"2026-02-26T17:32:42Z","created_by":"Hadrien David","updated_at":"2026-02-26T17:35:44Z","dependencies":[{"issue_id":"fastsqla-0nf.2","depends_on_id":"fastsqla-0nf","type":"parent-child","created_at":"2026-02-26T12:32:42Z","created_by":"Hadrien David","metadata":"{}"}]} -{"id":"fastsqla-0nf.3","title":"Create fastsqla-pagination skill","description":"Create `skills/fastsqla-pagination/SKILL.md` covering:\n\n- **Response models**: `Page[T]` (data + meta with offset/total_items/total_pages/page_number), `Item[T]` (single item), `Collection[T]` (unpaginated list)\n- **Default Paginate dependency**: adds `offset` (default 0, min 0) and `limit` (default 10, min 1, max 100) query params. Show basic usage with `select(Model)`.\n- **Adding filters**: combine Paginate with additional query parameters\n- **new_pagination() factory**: 4 parameters (`min_page_size`, `max_page_size`, `query_count_dependency`, `result_processor`)\n- **Custom page sizes**: example with `Annotated[PaginateType, Depends(new_pagination(...))]`\n- **Custom count query**: `query_count_dependency` is a FastAPI dependency returning `int`. Default is `SELECT COUNT(*) FROM (subquery)`. Provide example for joins.\n- **Custom result processor**: default is `lambda r: iter(r.unique().scalars())`. Show `lambda result: iter(result.mappings())` for multi-column select.\n- **PaginateType[T]** type alias: `Callable[[Select], Awaitable[Page[T]]]`\n- **SQLModel example**: models serve as both ORM and response models\n\n## Source reference\n\nPagination: `src/fastsqla.py:323-437`\nTest examples: `tests/integration/test_pagination.py`\n\n## Acceptance criteria\n\n- SKILL.md has valid frontmatter\n- Content \u003c 500 lines\n- Includes both default and custom pagination examples\n- Shows the Annotated + Depends pattern for custom pagination","status":"in_progress","priority":2,"issue_type":"task","owner":"hadrien@ectobal.com","estimated_minutes":30,"created_at":"2026-02-26T17:32:56Z","created_by":"Hadrien David","updated_at":"2026-02-26T17:35:44Z","dependencies":[{"issue_id":"fastsqla-0nf.3","depends_on_id":"fastsqla-0nf","type":"parent-child","created_at":"2026-02-26T12:32:55Z","created_by":"Hadrien David","metadata":"{}"}]} -{"id":"fastsqla-0nf.4","title":"Create fastsqla-models skill","description":"Create `skills/fastsqla-models/SKILL.md` covering:\n\n- **fastsqla.Base**: inherits from `DeclarativeBase` + `DeferredReflection` (`__abstract__ = True`)\n- **Fully declared models**: standard SQLAlchemy ORM with `Mapped` and `mapped_column`\n- **Reflected models**: declare only `__tablename__`, columns auto-reflected from DB during `Base.prepare()` at lifespan startup\n- **How DeferredReflection works**: attributes not available until `Base.prepare()` is called inside a connection during lifespan\n- **Pydantic response models**: separate `BaseModel` with `ConfigDict(from_attributes=True)` when using Base\n- **SQLModel alternative**: `pip install FastSQLA[sqlmodel]`, no need for Base, models are both ORM and Pydantic\n- **SQLModel session swap**: when sqlmodel is installed, FastSQLA silently uses SQLModel's AsyncSession\n- **extend_existing**: `__table_args__ = {'extend_existing': True}` for SQLModel when table already exists\n- **Comparison table**: Base vs SQLModel tradeoffs (reflection, validation, dependencies, relationships)\n\n## Source reference\n\nBase: `src/fastsqla.py:57-85`\nSQLModel import: `src/fastsqla.py:23-27`\n\n## Acceptance criteria\n\n- SKILL.md has valid frontmatter\n- Content \u003c 500 lines\n- Shows both fully declared and reflected model patterns\n- Includes Base vs SQLModel comparison","status":"in_progress","priority":2,"issue_type":"task","owner":"hadrien@ectobal.com","estimated_minutes":25,"created_at":"2026-02-26T17:33:06Z","created_by":"Hadrien David","updated_at":"2026-02-26T17:35:45Z","dependencies":[{"issue_id":"fastsqla-0nf.4","depends_on_id":"fastsqla-0nf","type":"parent-child","created_at":"2026-02-26T12:33:06Z","created_by":"Hadrien David","metadata":"{}"}]} -{"id":"fastsqla-0nf.5","title":"Create fastsqla-testing skill","description":"Create `skills/fastsqla-testing/SKILL.md` covering:\n\n- **Test dependencies**: pytest, pytest-asyncio, pytest-cov, httpx, asgi-lifespan, aiosqlite, faker\n- **pytest config**: `asyncio_mode = 'auto'`, `asyncio_default_fixture_loop_scope = 'function'`\n- **Fixture chain** (critical ordering): `sqlalchemy_url` → `environ` (patched with clear=True) → `engine` → `setup_tear_down` (CREATE TABLE via raw SQL) → `app` (define models + routes) → `client` (LifespanManager + httpx)\n- **ASGI client pattern**: `LifespanManager(app)` triggers startup/shutdown, `ASGITransport` + `AsyncClient` for HTTP\n- **Critical teardown** (autouse fixture): `Base.metadata.clear()` + `clear_mappers()` after every test to prevent model leakage\n- **Direct data verification**: separate `session` fixture bound to same engine for querying DB outside the app\n- **SQLModel test marks**: `@mark.require_sqlmodel` with autouse `check_sqlmodel` fixture that skips when not installed\n- **Table setup**: raw SQL in fixtures, not ORM (tables must exist before Base.prepare)\n\n## Source reference\n\nRoot conftest: `tests/conftest.py`\nIntegration conftest: `tests/integration/conftest.py`\nSession tests: `tests/integration/test_session_dependency.py`\nPagination tests: `tests/integration/test_pagination.py`\nSQLModel tests: `tests/integration/test_sqlmodel.py`\n\n## Acceptance criteria\n\n- SKILL.md has valid frontmatter\n- Content \u003c 500 lines\n- Documents the full fixture chain with dependency ordering\n- Includes teardown fixture (this is the most common testing pitfall)","status":"in_progress","priority":2,"issue_type":"task","owner":"hadrien@ectobal.com","estimated_minutes":30,"created_at":"2026-02-26T17:33:19Z","created_by":"Hadrien David","updated_at":"2026-02-26T17:35:45Z","dependencies":[{"issue_id":"fastsqla-0nf.5","depends_on_id":"fastsqla-0nf","type":"parent-child","created_at":"2026-02-26T12:33:18Z","created_by":"Hadrien David","metadata":"{}"}]} diff --git a/.gitignore b/.gitignore index 82f9275..8d5ec30 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,6 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +.beads/backup +.beads/embeddeddolt +.beads/dolt-server.*