Open-source CMS with a Rust backend. The frontend communicates with the backend exclusively via gRPC (using tonic server-side and Connect / connect-es client-side), served by an axum HTTP server.
| Layer | Technology |
|---|---|
| Backend (gRPC) | Rust · tonic |
| Backend (static) | Rust · axum |
| API protocol | gRPC (Connect protocol) |
| Frontend | TypeScript · connect-es |
| Container | Alpine 3.21 · multi-arch (amd64 / arm64) |
| Port | 8112 |
Browser
├─► connect-es (TypeScript gRPC client) ──► tonic services ──► business logic
└─► static assets (HTML/JS/CSS) ──► axum (file server)
tonic handles all gRPC endpoints. axum is used solely to serve the compiled frontend (web/dist/). All API calls use the Connect protocol, which is compatible with both gRPC and gRPC-Web clients.
lucle supports dynamic plugins via WebAssembly Component Model (wasmtime).
Plugins are .wasm component files loaded at runtime from the filesystem. wasmtime instantiates each component in an isolated sandbox — a plugin crash or misbehavior cannot affect the host process.
plugins/
├── my-plugin.wasm
└── another-plugin.wasm
No host WIT interface is defined yet on the lucle side. The plugin API is expected to evolve as the CMS feature set grows.
Any language that compiles to a WASM component can be used. With Rust:
cargo build --target wasm32-wasip2 --releaseDrop the resulting .wasm file into the plugins directory and restart lucle.
- Rust stable toolchain
protoc— Protocol Buffers compiler- Node.js ≥ 18 and a package manager (npm / pnpm / yarn) for the frontend
- wasmtime is a Rust dependency — no separate install needed
- Docker with BuildKit /
docker buildxfor multi-arch support
cd web
npm install
npm run buildProduces web/dist/.
cargo build --releaseprotoc must be in PATH — tonic-build will invoke it to compile .proto files at build time.
./target/release/lucleThe server starts on http://0.0.0.0:8112.
API contracts live in proto/. After modifying a .proto file, re-run the build to regenerate Rust bindings (via tonic-build) and TypeScript bindings (via buf / protoc-gen-es).
# Rust — handled automatically by build.rs on `cargo build`
# TypeScript
buf generateThe Dockerfile expects pre-built binaries and the compiled frontend to be present locally (produced by CI):
FROM alpine:3.21
WORKDIR /opt/lucle
ARG TARGETARCH
COPY lucle-$TARGETARCH/lucle .
RUN chmod +x lucle
COPY web/dist ./web/dist
EXPOSE 8112
CMD ["./lucle"]docker run -p 8112:8112 lucle:latestlucle/
├── proto/ # Protobuf definitions (source of truth for the API)
├── plugins/ # WASM component plugins (loaded at runtime)
├── src/ # Rust backend
│ ├── main.rs # tonic server setup + axum static file server
│ └── ...
├── web/ # TypeScript frontend
│ ├── src/
│ └── dist/ # Build output (served by lucle at runtime)
├── build.rs # tonic-build invocation
├── Cargo.toml
├── Dockerfile
└── .github/workflows/ # CI — build, test, Docker publish
GitHub Actions builds the Rust binary for amd64 and arm64, the frontend, and publishes a multi-arch Docker image.
Apache License 2.0 — see LICENSE.
README.md Affichage de README.md en cours...