Laravel's application shape, in async Python.
A full-stack web framework on FastAPI and Starlette — routing, validation, an ORM, a view engine, auth, queues, mail, cache, events, a scheduler, and a first-class CLI — arranged the way Laravel arranges them, and asynchronous all the way down.
Why Almasix
Python has excellent HTTP libraries and very few opinions about what an application looks like.
Almasix supplies the opinions. It takes the conventions that make a Laravel codebase legible on
first read — the directory layout, service providers, facades, fluent builders, Route groups,
Eloquent-style models, Blade-style templates, Smith console commands — and implements them in
modern Python. Requests, the ORM, queue workers, and the scheduler all run on asyncio, and the
FastAPI application underneath is never taken away from you.
It is a parity project, not an homage. Each area of the framework is built against the
corresponding page of Laravel's documentation, method by method, and every deliberate divergence
is named in Almasix's own page for that feature — so Str, Collection, the query builder, and the
scheduler behave the way your muscle memory expects, while async/await, type hints, context
managers, and dataclasses are used where Python has the better answer.
| Piece | What it is |
|---|---|
Almasix (almasix) |
the framework |
almasix new |
the application installer |
Smith (python smith …) |
the in-app CLI — prefer python smith serve / make:model / loupe; bare smith only after pip install -e . of the app |
| Prism (almasix.prism) | the view engine — .prism.html templates, directives, components, stacks |
| Articulate (almasix.orm) | the ORM — models, relationships, migrations, pagination, on SQLAlchemy Core |
A tour in five files
Routes are declarative and grouped, controllers are plain classes, and route names and middleware sit where you'd look for them:
# routes/web.py
from app.http.controllers.post_controller import PostController
from almasix.routing import Route
with Route.group(middleware=["web"]):
Route.get("/posts", [PostController, "index"], name="posts.index")
Route.get("/posts/{post}", [PostController, "show"], name="posts.show")
Models carry their own casts, scopes, and relationships:
# app/models/post.py
from app.models.user import User
from almasix.orm import Model, SoftDeletes, relation
class Post(SoftDeletes, Model):
fillable = ("title", "body", "published")
casts = {"published": "bool", "published_at": "datetime"}
def scope_published(query):
return query.where("published", True)
@relation
def author(self):
return self.belongs_to(User)
Controllers read like their Laravel counterparts, with await at the edges:
# app/http/controllers/post_controller.py
from app.models.post import Post
from almasix.prism import view
from almasix.http import Controller
class PostController(Controller):
async def index(self):
posts = await Post.query().published().with_("author").latest().get()
return view("posts.index", {"posts": posts})
Templates are Prism — Blade's directives, compiled to Python:
{{-- resources/views/posts/index.prism.html --}}
@extends('layouts.app')
@section('content')
@foreach(posts as post)
<article>
<h2>{{ post.title }}</h2>
<p>by {{ post.author.name }} — {{ post.created_at }}</p>
</article>
@endforeach
@endsection
Console commands and scheduled work are declared together, and run under smith:
# routes/console.py
from almasix.console import Smith, schedule
def send_digest(command) -> int:
command.info("digest sent")
return 0
Smith.command("digest:send", send_digest).purpose("Mail yesterday's digest")
schedule.command("digest:send").daily_at("07:00").timezone("Africa/Nairobi").without_overlapping()
schedule.command("model:prune").daily().on_one_server()
Getting started
Create an application
python -m venv .venv && source .venv/bin/activate
pip install almasix
almasix new blog
cd blog
pip install -e . # the framework requirement is already satisfied
python smith serve # always works; bare `smith` also works after this install
almasix new writes a complete application: app/, bootstrap/, config/, routes/,
resources/views with error pages, database/migrations, storage/, a Vite config, and a root
smith script. Prefer python smith … from the app root (same idea as php artisan).
Installing the application (pip install -e .) also links a smith console script into that
virtualenv. Installing only the framework gives you the global almasix command — not smith.
Work on the framework
git clone https://github.com/almasix-dev/almasix.git && cd almasix
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
make test # full unit + smoke suite
make test-cov # the same, with the coverage gate
make lint # ruff
make docs # the documentation site, locally
What ships today
The framework is built in milestones, each closed against a Laravel documentation page. Closed today:
- The basics — routing and route groups, controllers, middleware and aliases, requests and responses, session, CSRF, validation with form requests, URL generation, error handling and the debug page, logging, asset bundling.
- Prism views — layouts and sections, includes, control directives, components and slots,
stacks, and a
dd()dump page. - Articulate ORM — models with casts and serialization, the whole relationship surface, eager loading, soft deletes, pruning, migrations, seeding, pagination, and streaming reads through lazy collections.
- Digging deeper — the Smith console with prompts and closure commands, the task scheduler
(frequencies, constraints, hooks, sub-minute tasks), cache, Redis, queues and workers, mail,
notifications, events, the filesystem, collections, helpers and
Str, the HTTP client, localization, and encryption. - Security — authentication guards and providers, hashing, gates and policies, email verification, password confirmation and resets.
Every closed milestone ships four things: the implementation, tests, a documentation page, and a runnable demonstration in the living example app.
Documentation
website/ holds 54 pages of application-developer documentation (Astro Starlight),
written to follow Laravel's structure page for page — including a section per method for
collections,
strings, and
helpers. Read it at
almasix-dev.github.io/almasix, or run make docs for a
local copy at http://localhost:4321.
examples/progress is the living example — a real Almasix application that
demonstrates each closed milestone through routes you can visit and smith progress:* commands you
can run. Its /progress page is the project's milestone board.
How the project is built
docs/PLAN.md is the binding architecture and milestone document: 51
milestones, each mapped to the Laravel documentation it must match, with the parity audit and the
named deviations recorded in place. docs/SMOKE.md records the exit criteria
that close a milestone.
The gates are enforced in CI on Python 3.11, 3.12, and 3.13:
| Gate | Command |
|---|---|
| Lint + format (pinned ruff) | make lint |
| Milestone smoke tests | make smoke |
| Contract regressions | make regression |
| Full suite, coverage ≥ 98% (aim 100%) | make test-cov |
make lint runs ruff check and ruff format --check against an exact
ruff==0.16.6 pin and an explicit rule selection (E4,E7,E9,F,I,UP,B,RUF100).
Currently 1,886 tests at 99.38% coverage.
Status
M39 docs journey and M38 deployment ops closed on the stability track (after M51, M44, and the M25 Mongo audit). Package version is 0.5.1 in-tree — tag/publish when you cut the GitHub Release. Next up: M37 — API tokens. See docs/PLAN.md.
Repository layout
src/almasix/
framework/ # Application, container, providers, bootstrap
config/ # env + config repository
http/ # kernel, request, response, middleware
routing/ # Route DSL → FastAPI bridge
validation/ # form requests, rules, messages
orm/ # Articulate — models, relations, builder, migrations
prism/ # Prism views — compiler, directives, components
auth/ # guards, providers, gates and policies
console/ # Smith commands, prompts, scheduler, loupe
queue/ # jobs, dispatcher, workers, failed jobs
cache/ # cache repository and stores
mail/ # mailables and transports
notifications/ # channels and notifiables
events/ # dispatcher, listeners, subscribers
filesystem/ # Storage disks
client/ # HTTP client
support/ # collections, helpers, Str, Number
translation/ # __(), trans_choice(), locales
installer/ # almasix new
smith/ # the smith CLI
docs/ # PLAN.md, SMOKE.md — the binding project documents
website/ # the documentation site (Astro Starlight)
examples/ # the living example application
tests/ # unit, smoke, and regression suites
smith # root script → run as `python smith …`
Contributing
Read docs/PLAN.md first — it is the source of truth for what belongs where and
what parity means for the area you are touching. Work in milestone order, keep the coverage gate
green, add the documentation page alongside the code, and extend
examples/progress so the new surface can be demonstrated, not just claimed.
License
MIT © Almasix Contributors
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file almasix-0.5.1.tar.gz.
File metadata
- Download URL: almasix-0.5.1.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e34bd0a44b32f94b939543b084d285b8c11f5cc3a22fc76eefc1c91d6e143681
|
|
| MD5 |
d524e0128bcbd548d7b451780528dc47
|
|
| BLAKE2b-256 |
4070e2718c9e0a497b7a4dd3e59de196a9ff4384b4e1ba1a5abc98d1fceb5f16
|
Provenance
The following attestation bundles were made for almasix-0.5.1.tar.gz:
Publisher:
publish.yml on almasix-dev/almasix
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
almasix-0.5.1.tar.gz -
Subject digest:
e34bd0a44b32f94b939543b084d285b8c11f5cc3a22fc76eefc1c91d6e143681 - Sigstore transparency entry: 2779993353
- Sigstore integration time:
-
Permalink:
almasix-dev/almasix@d286d7991ae3186099f40d5a29853e2d8ed4688e -
Branch / Tag:
refs/tags/v0.5.1 - Owner: https://github.com/almasix-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d286d7991ae3186099f40d5a29853e2d8ed4688e -
Trigger Event:
release
-
Statement type:
File details
Details for the file almasix-0.5.1-py3-none-any.whl.
File metadata
- Download URL: almasix-0.5.1-py3-none-any.whl
- Upload date:
- Size: 881.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa356414d6912517711556c999c03d95d267cc6c8c4d87033999dee4fa7a8080
|
|
| MD5 |
d514dec5e0cb09b35c17967dbb56bc63
|
|
| BLAKE2b-256 |
d4860095f9fa3e0daa36c3bbd6cedf0888ab0461e7efe76337fb06d2d57afda9
|
Provenance
The following attestation bundles were made for almasix-0.5.1-py3-none-any.whl:
Publisher:
publish.yml on almasix-dev/almasix
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
almasix-0.5.1-py3-none-any.whl -
Subject digest:
aa356414d6912517711556c999c03d95d267cc6c8c4d87033999dee4fa7a8080 - Sigstore transparency entry: 2779993429
- Sigstore integration time:
-
Permalink:
almasix-dev/almasix@d286d7991ae3186099f40d5a29853e2d8ed4688e -
Branch / Tag:
refs/tags/v0.5.1 - Owner: https://github.com/almasix-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d286d7991ae3186099f40d5a29853e2d8ed4688e -
Trigger Event:
release
-
Statement type: