agentleFS
xsovad06xsovad06/sova/.claude/skills/database-patterns/SKILL.md

database-patterns

Skill3 starsChanged 4 days agoApache-2.0View on GitHub

SOVA database conventions (async SQLAlchemy 2.0, ORM models, session management, migrations, JSON column gotchas). Auto-activates when working on sova/db/ models, session code, or Alembic migrations.

5 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

7 rules. 0 are common, 1 is distinctive, and 6 are very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 1

    Distinctive

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When working on sova/db/, ORM models, or migrations, follow these conventions.

    line 9
  2. Distinctive:

    Always use the async context manager:

    line 13
  3. Very specific:

    Never acquire sessions without async with: it leaks on exception.

    line 18
  4. Very specific:

    Use if not handoff: to catch both None and {}

    line 33
  5. Very specific:

    Use TASK_RUN_TERMINAL for DB queries.

    line 43
  6. Very specific:

    Always use batch_alter_table (SQLite requires it)

    line 51
  7. Very specific:

    Use idempotent helpers: _column_exists(), _table_exists(), _index_exists()

    line 52

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

SOVA Database Patterns

When working on sova/db/, ORM models, or migrations, follow these conventions. Reference: docs/database-guidelines.md.

Session Management

Always use the async context manager:

async with await get_session() as session:
    result = await session.execute(select(TaskRun))

Never acquire sessions without async with: it leaks on exception. All factories use expire_on_commit=False.

ORM Model Conventions (sova/db/models.py)

  • Type-annotated columns: Mapped[str] with mapped_column(String(50))
  • Money: Numeric(10, 6) with Decimal("0") default
  • Timestamps: DateTime(timezone=True) with lambda: datetime.now(timezone.utc)
  • FK constants: _FK_TASK_RUNS_ID = "task_runs.id"
  • Indexes in __table_args__: Index("ix_{table}_{column}", "column")
  • Input normalization: @validates decorator (e.g., strip # from issue numbers)

JSON Column NULL Gotcha

SQLAlchemy JSON defaults to none_as_null=False. Python None becomes JSON "null", not SQL NULL.

  • TaskRun.handoff_json.isnot(None) only catches SQL NULLs
  • Use if not handoff: to catch both None and {}

Terminal Status Sets

_TERMINAL = frozenset({TaskStatus.DONE, TaskStatus.FAILED, TaskStatus.REJECTED})  # state machine
TASK_RUN_TERMINAL = frozenset(
    {"done", "failed", "rejected", "interrupted", "paused", "awaiting_approval"}
)  # DB queries, sova/core/state.py

Use TASK_RUN_TERMINAL for DB queries. Always guard finalization:

if task_run.status in TASK_RUN_TERMINAL:
    return  # don't overwrite, but still update cost

Migrations

  • Always use batch_alter_table (SQLite requires it)
  • Use idempotent helpers: _column_exists(), _table_exists(), _index_exists()
  • Sequential numbering (currently up to 034), not Alembic UUIDs
  • Engine disposal after migration for file-backed SQLite (stale schema cache)
  • Self-healing: if Alembic fails, drops corrupted alembic_version, runs create_all + stamps head

Multi-Project

get_session(project_dir=...) routes to per-project engine. Each project gets its own .claude/sova.db.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.