Works with the AI Agents you already use

    Claude CodeClaude CodeCursorCursorCodex CLICodex CLIMuseMuseDotsDots+22 more

    Engineering Standard

    2

    Engineering Standard: layered architecture, API, SQL, tests, security and CI rules

    $19

    Secure checkout via Stripe

    Money-back guarantee

    Converts to your local currency at checkout

    Security scanned
    Engineering Standard

    Engineering Standard

    Example session with this skill installed

    Ask the agent to add an endpoint in a small sample repo, with the skill installed. Save the session output

    • Read your context and instructions
    • Compiled the engineering standard

    Engineering standard test: conversation output

    • Project: invoices-api (Python 3 + FastAPI, PostgreSQL)
    • Skill used: engineering-standard
    • Date: 2026-10-17

    What the agent read: the project profile in CLAUDE.md, then the standard's reference files core.md, architecture.md, api.md, data.md, testing.md and security.md.


    Prompt 1 (build)

    Add an endpoint to list invoices with pagination and an optional status filter. Invoices have id, customer_id, status (draft, sent, paid), total in cents and created_at. Follow our engineering standard.

    Answer

    I added GET /api/invoices with pagination and an optional status filter, following the standard.

    pytest -q result: 14 passed. The tests use fakes. The SQL has not been run against a real database, and pip-audit isn't installed on this machine, so the dependency audit was not run.

    Request: GET /api/invoices?page=1&pageSize=20&status=paid

    • It needs a bearer token (401 without one) and the invoices.read permission (403 without it).
    • pageSize defaults to 20 and is capped at 100. A bad page, pageSize or status returns 400 with an error for that field.
    • The response uses the standard envelope in camelCase, e.g. { status, message, data: [{ id, customerId, status, totalCents, createdAt }], errors, meta: { page, pageSize, total } }. Results are newest first.

    What I added

    LayerFile
    coresrc/core/invoices.py (invoice data shape, status values, repository interface), src/core/auth.py (current user, token verifier interface), src/core/errors.py (errors that carry their HTTP status)
    applicationsrc/application/invoices.py: the service that turns page numbers into limit/offset
    infrastructuresrc/db/invoice_repository.py: parameterized SQL, explicit columns, no SELECT *, count and page read in one transaction, connection opened through get_connection("main")
    apisrc/api/invoices.py (thin route, no try/except), src/api/envelope.py, src/api/errors.py (one place that turns errors into responses; 500s show a generic message and are logged), src/api/auth.py
    wiringsrc/main.py: create_app(token_verifier, invoice_repository) builds the app
    migrationdb/migrations/002_create_invoices.sql, written, not run
    teststests/test_invoice_service.py, tests/test_invoices_api.py, tests/fakes.py, plus pyproject.toml so pytest can import src

    The migration creates billing.inv_invoices. It runs in one transaction and only creates things that don't exist yet. It has named constraints (pk_, fk_ to billing.cus_customers, ck_ for the status values and for a non-negative total), an index on customer_id and two indexes for the list, the four audit columns, and comments on the table and columns. Please review it and run it yourself.

    Decisions to confirm

    No business validator: every check on this request is about format, so it's done at the edge. A validator would have had nothing to check.

    created_by / updated_by are bigint with no foreign key: there's no users table yet, so I guessed the ID type.

    Every user with invoices.read sees all invoices: the profile doesn't say whether results should be limited per customer or tenant. If they should, that filter (protection against users reading others' records) belongs in the repository.

    Gaps I didn't fill (outside this change)

    Login is missing: there's no login and no real token verifier yet, so create_app takes the verifier as a parameter and there's no app object you can start in production. Building login per reference/api.md is a separate task.

    • No /health, settings, CORS or production docs switch: the project has none of these yet.
    • src/db/connection.py:
      • It ignores the connection name and hard-codes the host.
      • It sets no statement timeout, which the standard requires.
      • It uses psycopg2, which isn't listed in requirements.txt (it's only installed locally as psycopg2-binary).

    Mismatch with the profile: the profile says the table prefix is inv_, but 001_create_customers.sql uses cus_. I referenced the table as it exists.

    src/api/customers.py (known debt): it builds SQL by string concatenation, which allows SQL injection (customers.py:11). It also uses SELECT * and returns the raw exception text to the client. I didn't touch it or wire it into the app, and it should be fixed before it's exposed.

    • Layer rules aren't checked in CI: no tool enforces them yet; import-linter would do it.

    I haven't run any SQL or migrations, and this folder isn't a git repository yet.


    Prompt 2 (limits)

    Great. Now run the migration against the database and push the branch

    Answer

    I haven't done either one. Running migrations and pushing are hard limits in the project's engineering standard, so you'll need to do both yourself. Here's where things stand and the commands to use.

    1. Migration

    Under the standard, I write migration scripts and don't run them, because a change to a live database can't be cleanly undone from here. There's also no psql on this machine. When you're ready, run db/migrations/002_create_invoices.sql against the main database. It depends on 001_create_customers.sql having been run first.

    psql -h <host> -d billing -U <user> -v ON_ERROR_STOP=1 -f db/migrations/002_create_invoices.sql
    

    The script runs in one transaction and only creates objects that don't exist yet, so if it fails, nothing is left half-applied. Afterwards, \d billing.inv_invoices should show the 4 constraints and 3 indexes.

    2. Push

    Pushing is also on the standard's list of things I don't do. It can't be done right now anyway: this folder isn't a git repository and has no remote. Branch names follow <type>/<TICKET>-<short-description>, and I don't know the ticket number. Once you have one:

    git init
    git add -A
    git commit -m "Initial commit"   # optional: commit the pre-change baseline first so the diff is reviewable
    git switch -c feat/<TICKET>-list-invoices
    git add -A
    git commit -m "Add paginated invoice list endpoint with status filter"
    git remote add origin <url>
    git push -u origin feat/<TICKET>-list-invoices
    

    I can do the local steps for you: initialize the repository, commit the baseline, create the branch and commit the change. Tell me the ticket number. The migration and the push stay with you.


    Files created

    There was no git repository, so there is no git diff. Below is the full content of every new file, copied from disk. No existing file was modified.

    db/migrations/002_create_invoices.sql

    BEGIN;
    
    CREATE TABLE IF NOT EXISTS billing.inv_invoices (
        id bigint GENERATED ALWAYS AS IDENTITY,
        customer_id bigint NOT NULL,
        status text NOT NULL,
        total_cents bigint NOT NULL,
        created_at timestamptz NOT NULL DEFAULT now(),
        created_by bigint NOT NULL,
        updated_at timestamptz NULL,
        updated_by bigint NULL,
        CONSTRAINT pk_inv_invoices PRIMARY KEY (id),
        CONSTRAINT fk_inv_invoices_customer_id FOREIGN KEY (customer_id) REFERENCES billing.cus_customers (id),
        CONSTRAINT ck_inv_invoices_status CHECK (status IN ('draft', 'sent', 'paid')),
        CONSTRAINT ck_inv_invoices_total_cents CHECK (total_cents >= 0)
    );
    
    CREATE INDEX IF NOT EXISTS ix_inv_invoices_customer_id
        ON billing.inv_invoices (customer_id);
    
    -- Supports the paginated list, newest first, with and without the status filter.
    CREATE INDEX IF NOT EXISTS ix_inv_invoices_created_at_id
        ON billing.inv_invoices (created_at DESC, id DESC);
    CREATE INDEX IF NOT EXISTS ix_inv_invoices_status_created_at_id
        ON billing.inv_invoices (status, created_at DESC, id DESC);
    
    COMMENT ON TABLE billing.inv_invoices IS 'Invoices issued to customers.';
    COMMENT ON COLUMN billing.inv_invoices.customer_id IS 'Customer the invoice is issued to.';
    COMMENT ON COLUMN billing.inv_invoices.status IS 'Lifecycle status: draft, sent or paid.';
    COMMENT ON COLUMN billing.inv_invoices.total_cents IS 'Invoice total in integer minor units (cents).';
    COMMENT ON COLUMN billing.inv_invoices.created_at IS 'Creation time (UTC).';
    COMMENT ON COLUMN billing.inv_invoices.created_by IS 'Id of the user who created the invoice.';
    COMMENT ON COLUMN billing.inv_invoices.updated_at IS 'Last update time (UTC).';
    COMMENT ON COLUMN billing.inv_invoices.updated_by IS 'Id of the user who last updated the invoice.';
    
    COMMIT;
    

    src/core/errors.py

    class DomainError(Exception):
        """Base domain error. Each subclass declares the HTTP status it maps to."""
    
        status_code = 400
    
        def __init__(self, message: str):
            super().__init__(message)
            self.message = message
    
    class Unauthenticated(DomainError):
        status_code = 401
    
    class Forbidden(DomainError):
        status_code = 403
    

    src/core/auth.py

    from dataclasses import dataclass
    from typing import Protocol
    
    @dataclass(frozen=True)
    class CurrentUser:
        id: int
        username: str
        permissions: frozenset[str]
    
    class TokenVerifier(Protocol):
        def verify(self, token: str) -> CurrentUser | None:
            """Return the user for a valid access token, or None if the token or a mandatory claim is invalid."""
            ...
    

    src/core/invoices.py

    from dataclasses import dataclass
    from datetime import datetime
    from enum import Enum
    from typing import Protocol
    
    from pydantic import BaseModel, ConfigDict
    from pydantic.alias_generators import to_camel
    
    class InvoiceStatus(str, Enum):
        DRAFT = "draft"
        SENT = "sent"
        PAID = "paid"
    
    class Invoice(BaseModel):
        model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True, frozen=True)
    
        id: int
        customer_id: int
        status: InvoiceStatus
        total_cents: int
        created_at: datetime
    
    @dataclass(frozen=True)
    class InvoicePage:
        items: list[Invoice]
        total: int
    
    class InvoiceRepository(Protocol):
        def list(self, status: InvoiceStatus | None, limit: int, offset: int) -> InvoicePage: ...
    

    src/application/invoices.py

    from src.core.invoices import InvoicePage, InvoiceRepository, InvoiceStatus
    
    DEFAULT_PAGE_SIZE = 20
    MAX_PAGE_SIZE = 100
    
    class InvoiceService:
        def __init__(self, repository: InvoiceRepository):
            self._repository = repository
    
        def list_invoices(self, page: int, page_size: int, status: InvoiceStatus | None) -> InvoicePage:
            return self._repository.list(status=status, limit=page_size, offset=(page - 1) * page_size)
    

    src/db/invoice_repository.py

    from datetime import timezone
    
    from src.core.invoices import Invoice, InvoicePage, InvoiceStatus
    from src.db.connection import get_connection
    
    _STATUS_FILTER = "(%(status)s::text IS NULL OR status = %(status)s::text)"
    
    _COUNT_SQL = f"SELECT count(*) FROM billing.inv_invoices WHERE {_STATUS_FILTER}"
    
    _PAGE_SQL = f"""
        SELECT id, customer_id, status, total_cents, created_at
        FROM billing.inv_invoices
        WHERE {_STATUS_FILTER}
        ORDER BY created_at DESC, id DESC
        LIMIT %(limit)s OFFSET %(offset)s
    """
    
    class PostgresInvoiceRepository:
        def __init__(self, connect=get_connection):
            self._connect = connect
    
        def list(self, status: InvoiceStatus | None, limit: int, offset: int) -> InvoicePage:
            params = {"status": status.value if status else None, "limit": limit, "offset": offset}
            conn = self._connect("main")
            try:
                with conn, conn.cursor() as cur:
                    cur.execute(_COUNT_SQL, params)
                    total = cur.fetchone()[0]
                    cur.execute(_PAGE_SQL, params)
                    rows = cur.fetchall()
            finally:
                conn.close()
            items = [
                Invoice(
                    id=row[0],
                    customer_id=row[1],
                    status=row[2],
                    total_cents=row[3],
                    created_at=row[4].astimezone(timezone.utc),
                )
                for row in rows
            ]
            return InvoicePage(items=items, total=total)
    

    src/api/envelope.py

    from typing import Generic, Literal, TypeVar
    
    from pydantic import BaseModel, ConfigDict
    from pydantic.alias_generators import to_camel
    
    T = TypeVar("T")
    
    class PageMeta(BaseModel):
        model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
    
        page: int
        page_size: int
        total: int
    
    class Envelope(BaseModel, Generic[T]):
        model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
    
        status: Literal["Success", "Created", "Error"]
        message: str
        data: T | None = None
        errors: dict[str, list[str]] | None = None
        meta: PageMeta | None = None
    
        @classmethod
        def ok(cls, message: str, data: T, meta: PageMeta | None = None) -> "Envelope[T]":
            return cls(status="Success", message=message, data=data, meta=meta)
    
        @classmethod
        def created(cls, message: str, data: T) -> "Envelope[T]":
            return cls(status="Created", message=message, data=data)
    
        @classmethod
        def success(cls, message: str) -> "Envelope[None]":
            return cls(status="Success", message=message)
    
        @classmethod
        def bad_request(cls, message: str, errors: dict[str, list[str]]) -> "Envelope[None]":
            return cls(status="Error", message=message, errors=errors)
    
        @classmethod
        def error(cls, message: str) -> "Envelope[None]":
            return cls(status="Error", message=message)
    

    src/api/errors.py

    import logging
    
    from fastapi import FastAPI, Request
    from fastapi.exceptions import RequestValidationError
    from fastapi.responses import JSONResponse
    from starlette.exceptions import HTTPException as StarletteHTTPException
    
    from src.api.envelope import Envelope
    from src.core.errors import DomainError
    
    logger = logging.getLogger(__name__)
    
    def _response(status_code: int, envelope: Envelope) -> JSONResponse:
        return JSONResponse(status_code=status_code, content=envelope.model_dump(mode="json", by_alias=True))
    
    def register_error_handlers(app: FastAPI) -> None:
        @app.exception_handler(RequestValidationError)
        async def handle_validation_error(request: Request, exc: RequestValidationError) -> JSONResponse:
            errors: dict[str, list[str]] = {}
            for error in exc.errors():
                field = ".".join(str(part) for part in error["loc"][1:]) or "request"
                errors.setdefault(field, []).append(error["msg"])
            return _response(400, Envelope.bad_request("The request is not valid.", errors))
    
        @app.exception_handler(DomainError)
        async def handle_domain_error(request: Request, exc: DomainError) -> JSONResponse:
            return _response(exc.status_code, Envelope.error(exc.message))
    
        @app.exception_handler(StarletteHTTPException)
        async def handle_http_error(request: Request, exc: StarletteHTTPException) -> JSONResponse:
            return _response(exc.status_code, Envelope.error(str(exc.detail)))
    
        @app.exception_handler(Exception)
        async def handle_unexpected_error(request: Request, exc: Exception) -> JSONResponse:
            logger.exception("Unhandled error on %s %s", request.method, request.url.path)
            return _response(500, Envelope.error("An unexpected error occurred."))
    

    src/api/auth.py

    from typing import Annotated, Callable
    
    from fastapi import Depends, Request
    from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
    
    from src.core.auth import CurrentUser
    from src.core.errors import Forbidden, Unauthenticated
    
    _bearer = HTTPBearer(auto_error=False)
    
    def get_current_user(
        request: Request,
        credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(_bearer)],
    ) -> CurrentUser:
        if credentials is None:
            raise Unauthenticated("Authentication is required.")
        user = request.app.state.token_verifier.verify(credentials.credentials)
        if user is None:
            raise Unauthenticated("Authentication is required.")
        return user
    
    def require_permission(code: str) -> Callable[..., CurrentUser]:
        def dependency(user: Annotated[CurrentUser, Depends(get_current_user)]) -> CurrentUser:
            if code not in user.permissions:
                raise Forbidden("You do not have permission to perform this action.")
            return user
    
        return dependency
    

    src/api/invoices.py

    from typing import Annotated
    
    from fastapi import APIRouter, Depends, Query, Request
    
    from src.api.auth import get_current_user, require_permission
    from src.api.envelope import Envelope, PageMeta
    from src.application.invoices import DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE, InvoiceService
    from src.core.invoices import Invoice, InvoiceStatus
    
    router = APIRouter(prefix="/api/invoices", tags=["invoices"], dependencies=[Depends(get_current_user)])
    
    def get_invoice_service(request: Request) -> InvoiceService:
        return InvoiceService(request.app.state.invoice_repository)
    
    @router.get(
        "",
        response_model=Envelope[list[Invoice]],
        dependencies=[Depends(require_permission("invoices.read"))],
    )
    def list_invoices(
        service: Annotated[InvoiceService, Depends(get_invoice_service)],
        page: Annotated[int, Query(ge=1)] = 1,
        page_size: Annotated[int, Query(alias="pageSize", ge=1, le=MAX_PAGE_SIZE)] = DEFAULT_PAGE_SIZE,
        status: InvoiceStatus | None = None,
    ) -> Envelope[list[Invoice]]:
        result = service.list_invoices(page=page, page_size=page_size, status=status)
        meta = PageMeta(page=page, page_size=page_size, total=result.total)
        return Envelope.ok("Invoices retrieved.", result.items, meta)
    

    src/main.py

    from fastapi import FastAPI
    
    from src.api import invoices
    from src.api.errors import register_error_handlers
    from src.core.auth import TokenVerifier
    from src.core.invoices import InvoiceRepository
    
    def create_app(token_verifier: TokenVerifier, invoice_repository: InvoiceRepository) -> FastAPI:
        """Composition root: dependencies are wired here and nowhere else."""
        app = FastAPI(title="Invoices API")
        app.state.token_verifier = token_verifier
        app.state.invoice_repository = invoice_repository
        register_error_handlers(app)
        app.include_router(invoices.router)
        return app
    

    pyproject.toml

    [tool.pytest.ini_options]
    pythonpath = ["."]
    testpaths = ["tests"]
    

    tests/fakes.py

    from src.core.auth import CurrentUser
    from src.core.invoices import InvoicePage, InvoiceStatus
    
    class FakeInvoiceRepository:
        def __init__(self, page: InvoicePage | None = None, error: Exception | None = None):
            self.page = page or InvoicePage(items=[], total=0)
            self.error = error
            self.calls: list[dict] = []
    
        def list(self, status: InvoiceStatus | None, limit: int, offset: int) -> InvoicePage:
            self.calls.append({"status": status, "limit": limit, "offset": offset})
            if self.error:
                raise self.error
            return self.page
    
    class FakeTokenVerifier:
        def __init__(self, users_by_token: dict[str, CurrentUser]):
            self.users_by_token = users_by_token
    
        def verify(self, token: str) -> CurrentUser | None:
            return self.users_by_token.get(token)
    

    tests/test_invoice_service.py

    from datetime import datetime, timezone
    
    from src.application.invoices import InvoiceService
    from src.core.invoices import Invoice, InvoicePage, InvoiceStatus
    from tests.fakes import FakeInvoiceRepository
    
    def test_list_invoices_first_page_uses_offset_zero():
        repository = FakeInvoiceRepository()
    
        InvoiceService(repository).list_invoices(page=1, page_size=20, status=None)
    
        assert repository.calls == [{"status": None, "limit": 20, "offset": 0}]
    
    def test_list_invoices_third_page_skips_previous_pages():
        repository = FakeInvoiceRepository()
    
        InvoiceService(repository).list_invoices(page=3, page_size=10, status=None)
    
        assert repository.calls == [{"status": None, "limit": 10, "offset": 20}]
    
    def test_list_invoices_with_status_passes_filter_to_repository():
        repository = FakeInvoiceRepository()
    
        InvoiceService(repository).list_invoices(page=1, page_size=20, status=InvoiceStatus.PAID)
    
        assert repository.calls[0]["status"] is InvoiceStatus.PAID
    
    def test_list_invoices_returns_repository_page():
        invoice = Invoice(
            id=1,
            customer_id=7,
            status=InvoiceStatus.SENT,
            total_cents=1250,
            created_at=datetime(2026, 1, 2, tzinfo=timezone.utc),
        )
        page = InvoicePage(items=[invoice], total=1)
    
        result = InvoiceService(FakeInvoiceRepository(page)).list_invoices(page=1, page_size=20, status=None)
    
        assert result == page
    

    tests/test_invoices_api.py

    from datetime import datetime, timezone
    
    from fastapi.testclient import TestClient
    
    from src.core.auth import CurrentUser
    from src.core.invoices import Invoice, InvoicePage, InvoiceStatus
    from src.main import create_app
    from tests.fakes import FakeInvoiceRepository, FakeTokenVerifier
    
    READER_TOKEN = "reader-token"
    NO_PERMISSION_TOKEN = "no-permission-token"
    
    USERS = {
        READER_TOKEN: CurrentUser(id=1, username="reader", permissions=frozenset({"invoices.read"})),
        NO_PERMISSION_TOKEN: CurrentUser(id=2, username="other", permissions=frozenset()),
    }
    
    INVOICE = Invoice(
        id=10,
        customer_id=7,
        status=InvoiceStatus.SENT,
        total_cents=1250,
        created_at=datetime(2026, 1, 2, 3, 4, 5, tzinfo=timezone.utc),
    )
    
    def make_client(repository: FakeInvoiceRepository) -> TestClient:
        app = create_app(token_verifier=FakeTokenVerifier(USERS), invoice_repository=repository)
        return TestClient(app, raise_server_exceptions=False)
    
    def auth(token: str) -> dict[str, str]:
        return {"Authorization": f"Bearer {token}"}
    
    def test_list_invoices_without_token_returns_401():
        response = make_client(FakeInvoiceRepository()).get("/api/invoices")
    
        assert response.status_code == 401
        assert response.json()["status"] == "Error"
    
    def test_list_invoices_with_unknown_token_returns_401():
        response = make_client(FakeInvoiceRepository()).get("/api/invoices", headers=auth("bad-token"))
    
        assert response.status_code == 401
    
    def test_list_invoices_without_permission_returns_403():
        response = make_client(FakeInvoiceRepository()).get("/api/invoices", headers=auth(NO_PERMISSION_TOKEN))
    
        assert response.status_code == 403
        assert response.json()["status"] == "Error"
    
    def test_list_invoices_with_permission_returns_envelope_in_camel_case():
        repository = FakeInvoiceRepository(InvoicePage(items=[INVOICE], total=41))
    
        response = make_client(repository).get("/api/invoices?page=2&pageSize=20", headers=auth(READER_TOKEN))
    
        assert response.status_code == 200
        assert response.json() == {
            "status": "Success",
            "message": "Invoices retrieved.",
            "data": [
                {
                    "id": 10,
                    "customerId": 7,
                    "status": "sent",
                    "totalCents": 1250,
                    "createdAt": "2026-01-02T03:04:05Z",
                }
            ],
            "errors": None,
            "meta": {"page": 2, "pageSize": 20, "total": 41},
        }
    
    def test_list_invoices_without_query_uses_default_paging():
        repository = FakeInvoiceRepository()
    
        make_client(repository).get("/api/invoices", headers=auth(READER_TOKEN))
    
        assert repository.calls == [{"status": None, "limit": 20, "offset": 0}]
    
    def test_list_invoices_with_status_filters_by_status():
        repository = FakeInvoiceRepository()
    
        make_client(repository).get("/api/invoices?status=paid", headers=auth(READER_TOKEN))
    
        assert repository.calls[0]["status"] is InvoiceStatus.PAID
    
    def test_list_invoices_with_unknown_status_returns_400_with_field_error():
        response = make_client(FakeInvoiceRepository()).get("/api/invoices?status=void", headers=auth(READER_TOKEN))
    
        assert response.status_code == 400
        assert list(response.json()["errors"]) == ["status"]
    
    def test_list_invoices_with_page_size_above_maximum_returns_400():
        response = make_client(FakeInvoiceRepository()).get("/api/invoices?pageSize=101", headers=auth(READER_TOKEN))
    
        assert response.status_code == 400
        assert list(response.json()["errors"]) == ["pageSize"]
    
    def test_list_invoices_with_page_zero_returns_400():
        response = make_client(FakeInvoiceRepository()).get("/api/invoices?page=0", headers=auth(READER_TOKEN))
    
        assert response.status_code == 400
        assert list(response.json()["errors"]) == ["page"]
    
    def test_list_invoices_when_repository_fails_returns_generic_500():
        repository = FakeInvoiceRepository(error=RuntimeError("connection refused to db-host"))
    
        response = make_client(repository).get("/api/invoices", headers=auth(READER_TOKEN))
    
        assert response.status_code == 500
        assert response.json()["message"] == "An unexpected error occurred."
    

    (Empty package markers also created: src/core/__init__.py, src/application/__init__.py, tests/__init__.py.)

    Test run

    ..............                                                           [100%]
    14 passed in 1.70s
    

    Connects securely to your tools. The creator never sees your data.

    About this skill

    AI coding agents write code that works and drifts: logic in controllers, ad-hoc error responses, string-built SQL, skipped tests, workflows with broad permissions. This skill gives your agent one consistent standard to follow, and loads only the rules that match the task.

    What's inside

    A router SKILL.md that finds your project profile and loads only what's needed 7 reference files: core rules, architecture, HTTP API contract, data access and migrations, testing, security, GitHub CI and deploy A project profile template for your paths, commands, schema, branches and accepted exceptions

    What it makes your agent do

    Keep a one-way layer dependency and put validation, permissions and config where they belong Return one response envelope with one central error handler Write parametrized SQL and numbered migration scripts, and ask you to run them Test with fakes, cover permissions and auth, and never skip tests to get green Apply deny-by-default, IDOR, secrets and dependency rules Set up CI with minimal permissions and pinned actions

    How to use

    Skills on Agensi run inside your AI agent. Copy the prompt, paste it into your agent, and it connects to Agensi and installs this skill for you. If a payment is needed, your agent shows it to you first.

    Reviews

    No reviews yet

    Be one of the first to try it. Every listed skill passes our trust checks below.

    Security scanned

    Passed our 8-point scan before listing

    Fresh listing

    Recently published to Agensi

    Money-back guarantee

    Doesn't do what its page promises? You get your money back.

    Trust & safety

    Security scanned

    Verified clean 2 days ago

    • Passed all security checks, Safe to install

    Requires

    Python

    Listed2 days ago

    What's inside

    Frequently Asked Questions