max / quasi
12 files changed,
+306 insertions,
-0 deletions
| @@ -1,0 +1,7 @@ | |||
| 1 | + | target/ | |
| 2 | + | Cargo.lock.bak | |
| 3 | + | *.swp | |
| 4 | + | .DS_Store | |
| 5 | + | CLAUDE.md | |
| 6 | + | CLAUDE.local.md | |
| 7 | + | .claude/ |
| @@ -1,0 +1,55 @@ | |||
| 1 | + | # Contributing | |
| 2 | + | ||
| 3 | + | Solo project. External contributions aren't accepted yet, the design is still | |
| 4 | + | moving. When that changes this file will grow. | |
| 5 | + | ||
| 6 | + | ## Working in this repo | |
| 7 | + | ||
| 8 | + | - Design and load-bearing decisions live in `~/Wiki/quasi-overview.md`, not here. | |
| 9 | + | - Work backlog is in GoingsOn (project `quasicoherent`), not `todo.md`. | |
| 10 | + | - Rust 2024 edition, latest stable toolchain. | |
| 11 | + | - `cargo deny check` must pass before commit. No GPL/LGPL/AGPL, ever. | |
| 12 | + | - `cargo fmt` + `cargo clippy --all-targets` clean. | |
| 13 | + | - Commits are concise, imperative, no emoji. | |
| 14 | + | ||
| 15 | + | ## The rule this repo exists to hold | |
| 16 | + | ||
| 17 | + | **Nothing in `quasi-router` may import a host crate.** Not `tauri`, not `axum`, | |
| 18 | + | not `wry`. Those are adapters written on top of the router, and the moment one | |
| 19 | + | of them appears in its dependency tree the stack has a host again. | |
| 20 | + | ||
| 21 | + | The same rule applies one level up: the router returns a description, never | |
| 22 | + | markup. A route that returns HTML is a webview route wearing a neutral name. | |
| 23 | + | ||
| 24 | + | ## Admitting a new boundary | |
| 25 | + | ||
| 26 | + | quasi owns seams, not vendors. Before adding a crate or a trait that wraps a | |
| 27 | + | dependency, answer one question: | |
| 28 | + | ||
| 29 | + | **Which two implementations does this have, today or already committed to?** | |
| 30 | + | ||
| 31 | + | If the answer is one, it is an indirection and it does not belong here yet. The | |
| 32 | + | lesson is recorded in `~/Wiki/makeover-geometry.md`: the hardest open question | |
| 33 | + | in that crate only got answered because a second consumer forced it, and the | |
| 34 | + | window to move the API shut within 48 hours of adoptions landing. Boundaries | |
| 35 | + | enter when the second implementation exists, not when it is imagined. | |
| 36 | + | ||
| 37 | + | Two further exclusions, both deliberate: | |
| 38 | + | ||
| 39 | + | - Ubiquitous and stable with no plausible alternative (`tokio`, `serde`, | |
| 40 | + | `tracing`, `chrono`, `uuid`, `thiserror`). Wrapping buys nothing. | |
| 41 | + | - Dependencies whose value *is* their API surface. `sqlx`'s compile-time-checked | |
| 42 | + | queries are the reason to use it, so quasi configures the driver and runs the | |
| 43 | + | migrations and queries stay written against `sqlx`. | |
| 44 | + | ||
| 45 | + | ## Adding a component crate | |
| 46 | + | ||
| 47 | + | Crates are scaffolded when they start, not up front: | |
| 48 | + | ||
| 49 | + | ``` | |
| 50 | + | cargo new --lib crates/quasi-host-tauri | |
| 51 | + | ``` | |
| 52 | + | ||
| 53 | + | Then add it to `Cargo.toml`'s `[workspace] members`, add the `[lints] workspace | |
| 54 | + | = true` block, and inherit `edition` / `rust-version` / `authors` / `repository` | |
| 55 | + | / `license` from `[workspace.package]`. |
| @@ -1,0 +1,11 @@ | |||
| 1 | + | # This file is automatically @generated by Cargo. | |
| 2 | + | # It is not intended for manual editing. | |
| 3 | + | version = 4 | |
| 4 | + | ||
| 5 | + | [[package]] | |
| 6 | + | name = "quasi" | |
| 7 | + | version = "0.0.0" | |
| 8 | + | ||
| 9 | + | [[package]] | |
| 10 | + | name = "quasi-router" | |
| 11 | + | version = "0.0.0" |
| @@ -1,0 +1,32 @@ | |||
| 1 | + | [workspace] | |
| 2 | + | resolver = "3" | |
| 3 | + | members = [ | |
| 4 | + | "crates/quasi", | |
| 5 | + | "crates/quasi-router", | |
| 6 | + | ] | |
| 7 | + | ||
| 8 | + | [workspace.dependencies] | |
| 9 | + | ||
| 10 | + | [workspace.package] | |
| 11 | + | edition = "2024" | |
| 12 | + | rust-version = "1.85" | |
| 13 | + | authors = ["Max Johnson <me@maxj.phd>"] | |
| 14 | + | repository = "https://makenot.work/git/max/quasi" | |
| 15 | + | license = "MIT" | |
| 16 | + | ||
| 17 | + | [workspace.lints.rust] | |
| 18 | + | unsafe_code = "forbid" | |
| 19 | + | ||
| 20 | + | [workspace.lints.clippy] | |
| 21 | + | pedantic = { level = "warn", priority = -1 } | |
| 22 | + | module_name_repetitions = "allow" | |
| 23 | + | missing_errors_doc = "allow" | |
| 24 | + | missing_panics_doc = "allow" | |
| 25 | + | ||
| 26 | + | [profile.release] | |
| 27 | + | lto = "thin" | |
| 28 | + | codegen-units = 1 | |
| 29 | + | strip = "symbols" | |
| 30 | + | ||
| 31 | + | [profile.dev] | |
| 32 | + | opt-level = 1 |
| @@ -1,0 +1,21 @@ | |||
| 1 | + | MIT License | |
| 2 | + | ||
| 3 | + | Copyright (c) 2026 Max Johnson | |
| 4 | + | ||
| 5 | + | Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 6 | + | of this software and associated documentation files (the "Software"), to deal | |
| 7 | + | in the Software without restriction, including without limitation the rights | |
| 8 | + | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 9 | + | copies of the Software, and to permit persons to whom the Software is | |
| 10 | + | furnished to do so, subject to the following conditions: | |
| 11 | + | ||
| 12 | + | The above copyright notice and this permission notice shall be included in all | |
| 13 | + | copies or substantial portions of the Software. | |
| 14 | + | ||
| 15 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 16 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 17 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 18 | + | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 19 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 20 | + | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 21 | + | SOFTWARE. |
| @@ -1,0 +1,71 @@ | |||
| 1 | + | # quasi | |
| 2 | + | ||
| 3 | + | quasicoherent: the stack every Make Creative app is built on. `quasi` for short, | |
| 4 | + | and that is what you type. | |
| 5 | + | ||
| 6 | + | A quasi-coherent sheaf is determined by local module data on an affine cover and | |
| 7 | + | glues, with no finiteness demanded of the pieces. That is the architecture: one | |
| 8 | + | description per host context, agreeing on overlaps, renderers free to be unalike. | |
| 9 | + | ||
| 10 | + | ## What it is | |
| 11 | + | ||
| 12 | + | ``` | |
| 13 | + | request (path + params) | |
| 14 | + | -> router this repo, imports no host crate | |
| 15 | + | -> description makeover-layout | |
| 16 | + | -> renderer webview | tui | egui | |
| 17 | + | -> host adapter axum route | Tauri protocol | wry | direct call | |
| 18 | + | ``` | |
| 19 | + | ||
| 20 | + | The router answers with what a screen *is*. The host decides how that becomes | |
| 21 | + | pixels. One codebase reaches desktop, iOS, a terminal, egui, and a hosted web | |
| 22 | + | app, because the host is the boundary that stops mattering. | |
| 23 | + | ||
| 24 | + | ## What it owns | |
| 25 | + | ||
| 26 | + | Seams, not vendors. quasi owns the boundaries between code we own and the major | |
| 27 | + | dependencies underneath it, and the test for admitting one is: | |
| 28 | + | ||
| 29 | + | **Name two implementations that exist or are already committed to.** A boundary | |
| 30 | + | with one implementation forever is not a boundary, it is an indirection. | |
| 31 | + | ||
| 32 | + | By that test, in scope: the host (Tauri, wry, axum, direct call), the renderer | |
| 33 | + | (webview, tui, egui, via `makeover-layout`), database configuration and | |
| 34 | + | migration across SQLite and Postgres, and eventually a shared session and auth | |
| 35 | + | layer, which the server has and the desktop apps do not. | |
| 36 | + | ||
| 37 | + | Out of scope, deliberately: `tokio`, `serde`, `tracing`, `chrono`, `uuid`, | |
| 38 | + | `thiserror`. Ubiquitous, stable, and with no second implementation anyone would | |
| 39 | + | adopt, so wrapping them costs a translation tax and returns nothing. | |
| 40 | + | ||
| 41 | + | Also out of scope: anything whose value *is* its API surface. `sqlx`'s | |
| 42 | + | compile-time-checked query macros are the reason to use `sqlx`, so quasi owns | |
| 43 | + | which driver is configured and how migrations run, and queries stay written | |
| 44 | + | against `sqlx` directly. | |
| 45 | + | ||
| 46 | + | Boundaries already owned elsewhere stay where they are and are referenced rather | |
| 47 | + | than absorbed: `makeover` and `makeover-geometry` for colour and spacing, | |
| 48 | + | `synckit` for sync, `s3-storage` for blobs, `docengine` for rendered content, | |
| 49 | + | `tagtree` for tags. One repo per project. quasi names the stack and fills the | |
| 50 | + | seams that have no owner. | |
| 51 | + | ||
| 52 | + | ## Layout | |
| 53 | + | ||
| 54 | + | - `crates/quasi-router/` — the host-agnostic router. The keystone. | |
| 55 | + | - `crates/quasi/` — the scaffolder binary. | |
| 56 | + | ||
| 57 | + | Crates are added when their component starts, not up front. | |
| 58 | + | ||
| 59 | + | ## Status | |
| 60 | + | ||
| 61 | + | Nothing implemented. The repo exists so the boundary rule has a home and the | |
| 62 | + | router has somewhere to land. Both crates are stubs. | |
| 63 | + | ||
| 64 | + | The description layer this depends on is not written either, and the order of | |
| 65 | + | work runs vocabulary first, then renderers, then this. Design and sequencing | |
| 66 | + | live in the wiki note `quasi-overview`; the backlog is in GoingsOn under project | |
| 67 | + | `quasicoherent`. | |
| 68 | + | ||
| 69 | + | ## Licence | |
| 70 | + | ||
| 71 | + | MIT. |
| @@ -1,0 +1,15 @@ | |||
| 1 | + | [package] | |
| 2 | + | name = "quasi-router" | |
| 3 | + | version = "0.0.0" | |
| 4 | + | description = "Host-agnostic router: a request in, a renderer-agnostic description out" | |
| 5 | + | edition.workspace = true | |
| 6 | + | rust-version.workspace = true | |
| 7 | + | authors.workspace = true | |
| 8 | + | repository.workspace = true | |
| 9 | + | license.workspace = true | |
| 10 | + | publish = false | |
| 11 | + | ||
| 12 | + | [lints] | |
| 13 | + | workspace = true | |
| 14 | + | ||
| 15 | + | [dependencies] |
| @@ -1,0 +1,18 @@ | |||
| 1 | + | //! Host-agnostic routing: a request in, a renderer-agnostic description out. | |
| 2 | + | //! | |
| 3 | + | //! <!-- wiki: quasi-overview --> | |
| 4 | + | //! | |
| 5 | + | //! The keystone of the stack. A route answers with what a screen *is*, expressed | |
| 6 | + | //! in `makeover-layout`'s vocabulary, and the host decides how that becomes | |
| 7 | + | //! pixels. Returning markup instead would pin every consumer to a webview and | |
| 8 | + | //! hand the terminal and egui renderers an adapter, which is the failure the | |
| 9 | + | //! description layer exists to prevent. | |
| 10 | + | //! | |
| 11 | + | //! Nothing here may import a host crate. `tauri`, `axum` and `wry` are all thin | |
| 12 | + | //! adapters written on top of this, never dependencies of it. That rule is what | |
| 13 | + | //! keeps a host repriceable per app instead of welded into the view layer, and | |
| 14 | + | //! it is what lets the same route serve a desktop protocol handler and an HTTP | |
| 15 | + | //! endpoint with no second implementation. | |
| 16 | + | //! | |
| 17 | + | //! Not written yet. The vocabulary this returns has to exist first, and the | |
| 18 | + | //! order of work is on the wiki note. |
| @@ -1,0 +1,19 @@ | |||
| 1 | + | [package] | |
| 2 | + | name = "quasi" | |
| 3 | + | version = "0.0.0" | |
| 4 | + | description = "Scaffolder for the quasicoherent stack" | |
| 5 | + | edition.workspace = true | |
| 6 | + | rust-version.workspace = true | |
| 7 | + | authors.workspace = true | |
| 8 | + | repository.workspace = true | |
| 9 | + | license.workspace = true | |
| 10 | + | publish = false | |
| 11 | + | ||
| 12 | + | [lints] | |
| 13 | + | workspace = true | |
| 14 | + | ||
| 15 | + | [[bin]] | |
| 16 | + | name = "quasi" | |
| 17 | + | path = "src/main.rs" | |
| 18 | + | ||
| 19 | + | [dependencies] |
| @@ -1,0 +1,15 @@ | |||
| 1 | + | //! Scaffolder for the quasicoherent stack. | |
| 2 | + | //! | |
| 3 | + | //! <!-- wiki: quasi-overview --> | |
| 4 | + | //! | |
| 5 | + | //! The `create-t3-app` equivalent: produce a running app with a router, a | |
| 6 | + | //! description, renderers wired, migrations, themes materialised and a Bento | |
| 7 | + | //! config. Without it the stack is documentation about repos that happen to | |
| 8 | + | //! agree. | |
| 9 | + | //! | |
| 10 | + | //! Not written yet. It cannot generate a stack that does not exist, so it | |
| 11 | + | //! follows the router rather than leading it. | |
| 12 | + | ||
| 13 | + | fn main() { | |
| 14 | + | println!("quasi: not implemented yet. See wiki note quasi-overview."); | |
| 15 | + | } |
| @@ -1,0 +1,38 @@ | |||
| 1 | + | # cargo-deny config. Load-bearing rule: NEVER GPL/LGPL/AGPL. | |
| 2 | + | # Per `~/Code/CLAUDE.md`, taking on a copyleft dep is incompatible with the | |
| 3 | + | # ecosystem's licensing plan (MIT for tooling, PolyForm-NC for products). | |
| 4 | + | ||
| 5 | + | [graph] | |
| 6 | + | all-features = true | |
| 7 | + | ||
| 8 | + | [advisories] | |
| 9 | + | version = 2 | |
| 10 | + | yanked = "deny" | |
| 11 | + | ||
| 12 | + | [licenses] | |
| 13 | + | version = 2 | |
| 14 | + | confidence-threshold = 0.9 | |
| 15 | + | allow = [ | |
| 16 | + | "MIT", | |
| 17 | + | "MIT-0", | |
| 18 | + | "Apache-2.0", | |
| 19 | + | "Apache-2.0 WITH LLVM-exception", | |
| 20 | + | "BSD-2-Clause", | |
| 21 | + | "BSD-3-Clause", | |
| 22 | + | "ISC", | |
| 23 | + | "Zlib", | |
| 24 | + | "Unicode-3.0", | |
| 25 | + | "Unicode-DFS-2016", | |
| 26 | + | "MPL-2.0", | |
| 27 | + | "CC0-1.0", | |
| 28 | + | "BSL-1.0", | |
| 29 | + | ] | |
| 30 | + | ||
| 31 | + | [bans] | |
| 32 | + | multiple-versions = "warn" | |
| 33 | + | wildcards = "deny" | |
| 34 | + | ||
| 35 | + | [sources] | |
| 36 | + | unknown-registry = "deny" | |
| 37 | + | unknown-git = "deny" | |
| 38 | + | allow-registry = ["https://github.com/rust-lang/crates.io-index"] |
| @@ -1,0 +1,4 @@ | |||
| 1 | + | [toolchain] | |
| 2 | + | channel = "stable" | |
| 3 | + | components = ["rustfmt", "clippy"] | |
| 4 | + | profile = "minimal" |