Model or dataset
level09/enferno avatar
level09/enferno

Enferno: a Flask framework where a coding agent builds the app

Lean Flask framework built for coding agents: Vue 3 + Vuetify with no build step, production-ready auth (2FA, passkeys, OAuth), AGENTS.md, an agent skill and a read-only MCP server. No webpack, no node_modules, just Python.

568 stars80 forksHTMLMIT

At a glance

What is it?
Enferno is a Flask starter that ships an AGENTS.md, an agent skill and a read-only MCP server so a coding agent can build and verify a Vue 3 and Vuetify application without a JavaScript build step. The test suite is the part that makes it interesting, because it is written to catch the specific mistakes agents make.
Who is it for?
Adopt Enferno if you are commissioning application code from a coding agent and want the stack, the conventions and the checks already pinned down, since that is precisely the problem it targets. Do not adopt it if you want a general Flask framework with a large community, because it is a starter shaped around a specific workflow.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly HTML, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The premise is that agents forget things

The framing sentence is unusually direct for a starter kit: a Flask framework built for coding agents. You describe the app, your agent builds it on a stack it already understands, and a test suite tells it when it got something wrong.

The stack is plain Python, Vue 3 and Vuetify with no build step, and production auth out of the box. The claim is no webpack, no node_modules, and nothing for the agent to configure. The vendor script, vendor.sh, pins the frontend assets instead of compiling them, which is the mechanism behind that promise.

What makes this more than a code generator is the second half of the sentence, the test suite. The README's section on how the agent checks its work names the failure modes it targets: agents write code fast, but they also forget migrations and leave routes unprotected. The suite is built around exactly those mistakes, and the fact that it is described as catching the mistakes agents actually make tells you the author was watching a coding agent work and writing the checks around what went wrong.

The primary language of the repository is listed as HTML, which is a fair reflection of a project whose deliverable is mostly templates and vendored assets. The licence is MIT, the default branch is master, and the homepage is https://enferno.io with documentation at https://docs.enferno.io.

The recent releases show the direction of travel: v14.0.0 for Vuetify 4 and an accessible theme on 2026-10-15, v13.3.1 for setup fixes on 2026-10-14, and v13.3.0 for agent tooling, tests and security on 2026-10-12.

The four artefacts an agent gets

The section on how the agent knows Enferno is a table, and the table is the design.

The AGENTS.md gives the agent the stack, layout, commands, routes and hard rules in about 100 lines, and it is read automatically in every session. The enferno-dev skill gives full patterns for models, APIs, Vue pages, dialogs, migrations and upgrades, and it is loaded only when a task needs it. The flask mcp command gives live routes, the schema with row counts, the migration revision and the audit log, read-only, and it is for when the agent needs the real state rather than the docs. The /llms.txt endpoint gives a short description of your app for LLM tools, and you edit it to describe what you build.

That last one is a nice detail. The framework does not assume the agent already knows what your application is, so it gives you a file to write that in.

The skill lives in .agents/skills/, described as the shared location for Codex, Cursor, Copilot and Gemini CLI, with .claude/skills linking to it for Claude Code. The skill can be installed into another project with npx skills add level09/enferno, which is what makes the conventions portable beyond this repository.

MCP is opt-in rather than on by default. You install it with uv sync --extra dev --extra mcp, and .mcp.json is what lets MCP-aware agents offer to connect. The opt-in design is deliberate and it matters for a security posture: a server that can read your live schema and audit log should be something you turn on, not something that starts with the app.

The test suite as an agent safety net

This is the section that makes the project worth an engineer's time, and the checks are specific.

Every protected route rejects anonymous users, and every admin route rejects non-admins, including routes the agent just added. Models match migrations, so changing a model without flask db migrate makes the suite fail. CSRF is enforced on the admin API, and a valid token still works. The auth flows are covered: login, wrong password, POST-only logout and audited admin CRUD. And setup.sh is tested in every mode without touching your .env.

The last two of those are the ones a human reviewer would appreciate. Testing that a valid CSRF token still works catches the class of fix where a developer disables CSRF to make the failing test go away. Testing setup.sh in every mode catches the case where the setup path works on a developer laptop with a terminal but not in CI.

The performance and coverage story is also specific. The app tests run on in-memory SQLite in about two seconds and the setup.sh tests add about ten, so the whole suite is cheap enough to run on every agent turn rather than at the end of a task. CI runs them on PostgreSQL across Python 3.11 to 3.14. You can set TEST_DATABASE_URI to use PostgreSQL locally, and the documentation warns that it must be a disposable database because the suite drops every table.

There is a second layer that tests cannot express, and AGENTS.md holds it: Tabler icons only, POST-only logout, migrations reviewed by hand, and a real browser check after a frontend upgrade. The project is explicit that the rules tests cannot check live in the file the agent reads at the start of every session, which is a sensible division of labour between machine-checkable and human-judgement rules.

Getting it running, by hand or by prompt

The Start section offers two routes, and the first one is the unusual one.

The first route is a prompt you paste into Claude Code, Codex, Cursor or any coding agent.

bash
Clone https://github.com/level09/enferno into ./myapp, follow its AGENTS.md
to set it up, create an admin user, start it on port 5001 and run the tests.

The by-hand route is the usual clone and setup sequence.

bash
git clone https://github.com/level09/enferno.git myapp && cd myapp
./setup.sh                    # Installs deps, generates .env with secrets
uv run flask create-db        # Create the database
uv run flask install          # Create an admin user
uv run flask run              # http://localhost:5000

The setup script behaviour is designed for exactly this split. It never prompts when there is no terminal, so agents and CI run it with flags: --full adds Redis and Celery, and --docker configures the Compose stack.

That single property is what makes the agent route viable. A setup script that asks a question on a terminal is a script an agent cannot finish, and the whole premise of the project depends on the setup being runnable unattended.

The README then shows what the follow-up requests look like, and they are ordinary feature requests rather than anything clever: add a Product model with name, price and category, an admin page to manage it and a migration, or let users export the activity log as CSV, or add a status column to users and show it as a chip in the users table. The point of the framework is that these can be pasted straight into an agent.

The stack in the box, and the optional pieces

The list of what ships is short enough to read as a decision list.

The frontend is Vue 3, Vuetify 4 and axios, vendored and pinned by vendor.sh, with no build step. Auth covers login, registration, password recovery, TOTP 2FA, passkeys through WebAuthn, recovery codes, and Google and GitHub OAuth. The admin side has users, roles and an audit log of admin actions. The database layer is SQLAlchemy 2 with Alembic migrations, SQLite by default and PostgreSQL when you want it. The UI includes a collapsible sidebar, dark mode, Tabler icons, data tables, dialogs and notifications.

The optional extras are separate and map to the extras in the project metadata. Redis sessions and Celery come with --extra full, MCP with --extra mcp, and uWSGI with --extra wsgi. That last one matters for the Docker deployment, because the container image runs uWSGI rather than the development server.

The dependency list in the project metadata is a good place to see how much production hardening is already done. flask-security-too is pinned at 5.9.1 or newer, and the comment in the metadata explains why: 5.9.0 fixes one advisory and 5.9.1 fixes another, an open redirect. webauthn and cryptography are there for the passkey support, and nh3 is the sanitiser alongside it. flask-session, flask-login, flask-wtf, flask-caching and flask-dance cover the session, login, form, cache and OAuth wiring.

The requirements are Python 3.11 or newer and uv, and the project metadata declares the same floor, with pytest, ruff and pre-commit in the dev group and hatchling as the build backend.

Deployment, and the two paths it supports

The Docker path runs the full stack with PostgreSQL, Redis, Celery and nginx.

bash
./setup.sh --docker
docker compose up --build

Compose requires DB_PASSWORD and REDIS_PASSWORD, which setup.sh --docker generates, and the documentation says to keep the credentials an existing installation already uses. Database and Redis ports stay internal to the Compose network.

The compose file itself makes the isolation explicit. The website service is the only one with a published port, 8000 mapped to 5000, and the redis and postgres services declare no ports at all, only internal ones. The passwords are required rather than defaulted, with an error message pointing at the setup script if they are missing, which is a sensible way to stop a deployment from silently starting with an empty password.

For a single VPS the README points at Ignite, which handles Caddy and automatic SSL.

bash
curl -sSL https://raw.githubusercontent.com/level09/ignite/main/ignite.sh | sudo DOMAIN=your-domain.com bash

The container image is built from python:3.13-slim in two stages, with uv handling the dependency sync in the builder and only the virtual environment copied into the runtime stage. The final command runs uWSGI with two processes and two threads on port 5000, and a healthcheck curls the application root. The user is created with a fixed uid of 1000 so the mounted source directories have predictable ownership.

The configuration surface is small, and setup.sh writes a .env with generated secrets. The values you are most likely to change are FLASK_DEBUG, which should be 0 in production, the optional SQLALCHEMY_DATABASE_URI for PostgreSQL, and the optional REDIS_URL and CELERY_BROKER_URL for background tasks.

Where Enferno is the wrong choice

There are three limits, and the first one is about the shape of the project rather than the code.

The first is that this is a starter kit with an opinionated workflow, not a general Flask framework. The conventions are deliberately fixed: Tabler icons only, POST-only logout, migrations reviewed by hand, Vuetify rather than any other component library, and a vendored frontend with no build step. If you want Tailwind, or a different component library, or a JavaScript toolchain with real bundling, you are fighting the framework from the first commit. The no-build-step decision in particular is a real constraint once your frontend needs anything beyond what is vendored.

The second is the upgrade path. The dependencies are pinned with minimum versions, several of them with recent security advisories in the comments, and the AGENTS.md rules include a real browser check after a frontend upgrade. That suggests a project that expects to be upgraded carefully rather than continuously, which is the right instinct for something an agent is editing, but it does mean you are signing up to follow the project's release notes rather than pinning a known-good version and forgetting about it.

The third is that the test suite is a floor, not a guarantee. It checks that every protected route rejects anonymous users, that models match migrations, that CSRF is enforced, that the auth flows behave, and that setup.sh runs in every mode. It does not check whether the feature you asked for is correct, and it cannot, because the tests were written before the feature existed. A green suite means the agent did not break the parts it was told about, not that the new page is right.

For comparison, the project names two related tools. ReadyKit adds Stripe, workspaces and teams on top of Enferno. STK is the same philosophy on Quart, async Flask, with native WebSockets. Both are worth knowing about if the Quart route or the payments route is the one you actually need, and the third-party ecosystem around plain Flask remains the safer bet for a long-lived application with a large team.

Editorial conclusion

Adopt Enferno if you are commissioning application code from a coding agent and want the stack, the conventions and the checks already pinned down, since that is precisely the problem it targets. Do not adopt it if you want a general Flask framework with a large community, because it is a starter shaped around a specific workflow. Before you build on it, read AGENTS.md and the enfemo-dev skill yourself, and note the last push was on 2026-10-20 with release v14.0.0 on 2026-10-15.

Frequently asked questions

What is Enferno and who is it built for?

Enferno is a Flask framework built for coding agents, using plain Python, Vue 3 and Vuetify with no build step, and it ships production auth out of the box. The idea is that you describe the app and an agent builds it on a stack it already understands.

How do I start a new Enferno project?

Clone the repository and run ./setup.sh, which installs dependencies and generates a .env with secrets, then run uv run flask create-db, uv run flask install to create an admin user, and uv run flask run to serve it on http://localhost:5000. The README also gives a single prompt you can paste into Claude Code, Codex or Cursor.

What does AGENTS.md give a coding agent?

The stack, layout, commands, routes and hard rules, in about 100 lines, read automatically in every session. The full patterns for models, APIs, Vue pages, dialogs, migrations and upgrades live in a separate skill that is loaded only when a task needs it.

What does the Enferno test suite check?

That every protected route rejects anonymous users and every admin route rejects non-admins, that models match migrations, that CSRF is enforced on the admin API while a valid token still works, the auth flows including POST-only logout and audited admin CRUD, and that setup.sh runs in every mode without touching your .env.

Is the Enferno MCP server read-only and how do I enable it?

Yes, the flask mcp command is read-only and exposes live routes, the schema with row counts, the migration revision and the audit log. It is opt-in: install it with uv sync --extra dev --extra mcp, and .mcp.json is what lets MCP-aware agents offer to connect.

Official sources

  1. level09/enferno on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/level09-enferno.svg)](https://hysenlabs.com/projects/level09-enferno)

Was this useful?