magik 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 56ebbcd6428e1b8b1f0a631a8e4decba6ebef0a1cdf478ba5c25741dde60d0bd
4
+ data.tar.gz: f306adb846dfdfd6520f623272bdf525051e66ed5f86a3202c80c360a429e37a
5
+ SHA512:
6
+ metadata.gz: 31cb4e39c90b52b75ee6a4aa4dccb60efe0ae45b441404efc0057bdea3ec74a44a35d75e9186b9c977229a9b24f12daca8975021f0b4f21f809f439a9926bdcb
7
+ data.tar.gz: c080593fd7f90194b23a6c2c921d419c49b816c84e6862c20af544c4c008f793aab1a718dbf78ddac3e7d3c4909ee9b9411169dcd77ebc8e3ded54e8765b78cc
data/CHANGELOG.md ADDED
@@ -0,0 +1,90 @@
1
+ # Changelog
2
+
3
+ All notable changes to Magik. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ Magik is **one gem** with subsystem modules — there is no lockstep across packages and no
8
+ per-package version. The single version lives in
9
+ [`lib/magik/version.rb`](lib/magik/version.rb); [`PUBLISHING.md`](PUBLISHING.md) owns how it is
10
+ stamped and released.
11
+
12
+ **Semver does not apply below 0.1.0.** Anything in a `0.0.x` release may change or disappear
13
+ without notice, and `0.0.1` in particular ships no API at all.
14
+
15
+ `## [Unreleased]` is the release notes — write the entry as the change lands, not at release time.
16
+
17
+ ## [Unreleased]
18
+
19
+ Nothing yet.
20
+
21
+ ## [0.0.1] - 2026-08-26
22
+
23
+ **A name reservation and the repository's ground work. No framework functionality.**
24
+
25
+ This release exists so the gem name `magik` is held on RubyGems and so the release path is proven
26
+ end to end before there is anything worth releasing. Installing it gives you a version constant and
27
+ a CLI that can print it. Nothing else.
28
+
29
+ What is explicitly **not** in this release: `App.define`, `model`, `migrate`, `component`, `screen`,
30
+ `action`, `channel`, `job`, `ledger`, `api`, `auth`, `billing`, `admin_panel`, the router, the
31
+ server, the test DSL, and every generator. Every one of them is
32
+ [specified](docs/idea/00-build-spec.md) and unimplemented. See the status callout in
33
+ [`README.md`](README.md).
34
+
35
+ ### Added
36
+
37
+ - **The gem skeleton**, with **zero runtime dependencies** — [`magik.gemspec`](magik.gemspec),
38
+ `Gemfile`, [`Rakefile`](Rakefile), `lib/magik.rb`, [`lib/magik/version.rb`](lib/magik/version.rb)
39
+ and `exe/magik`. `required_ruby_version` is `">= 3.2"`; TruffleRuby is the production runtime
40
+ target and CRuby is supported for tooling and development. `lib/magik.rb` is plain `autoload` over
41
+ a `Magik::SUBSYSTEMS` map, so requiring the gem reads one file. The gems Magik intends to wrap are
42
+ listed in the gemspec as comments, to be added by the phase that needs each one.
43
+ - **`Magik::Error`** — the `MAGIK_*` error-code convention, implemented and tested rather than
44
+ described: a stable code, a one-sentence cause, a runnable `fix:` line, a deterministic rendered
45
+ message, and `#to_h` for `--json`. Three subclasses cover the CLI's own failures.
46
+ - **`magik version` and `magik help`** — a working CLI, both with `--json`. `help` lists every
47
+ command the spec names and marks each `ready` or `planned`, because "not built yet" and "not a
48
+ command" are different facts.
49
+ - **19 spec-only subsystem stubs** under `lib/magik/`, one per planned subsystem: `core`, `model`,
50
+ `schema`, `render`, `action`, `router`, `realtime`, `jobs`, `ledger`, `api`, `auth`, `billing`,
51
+ `admin`, `i18n`, `pwa`, `notify`, `testing`, `domains`, `check`. Each documents its `SPEC_PHASE`,
52
+ its `DSL_SURFACE` verbatim from the spec, and a `STATUS`; every `.define` raises
53
+ `NotImplementedError` naming the spec rather than returning a plausible empty answer. `cli` is the
54
+ twentieth subsystem and the only one with real behaviour.
55
+ - **The build spec**, [`docs/idea/00-build-spec.md`](docs/idea/00-build-spec.md), as the source of
56
+ truth, plus the `docs/idea/`, [`docs/architecture/`](docs/architecture/) and
57
+ [`docs/ops/README.md`](docs/ops/README.md) documentation sets, the [`wiki/`](wiki/) reference
58
+ manual, [`ROADMAP.md`](ROADMAP.md) and [`llms.txt`](llms.txt).
59
+ - **The agent workflow** — [`CLAUDE.md`](CLAUDE.md), [`AGENTS.md`](AGENTS.md) and
60
+ [`.claude/`](.claude/README.md) with its agents and slash commands.
61
+ - **The developer environment** — `bin/setup`, `bin/check` (the gate, with `--only`, `--json` and
62
+ `--list`), `bin/dev`, `bin/console`, `bin/release` (a release pre-flight that prints and never
63
+ publishes), `docker/compose.yml`, [`.devcontainer/`](.devcontainer/) and
64
+ [`lefthook.yml`](lefthook.yml).
65
+ - **Minitest** as the test framework, under `test/` as `*_test.rb`, run by `rake test` — and passing
66
+ on bare Ruby, with no bundle installed. Never RSpec: a spec decision.
67
+ - **`rake -T`** — `build`, `check`, `docs:coverage`, `rubocop`, `test`, `yard`. The RuboCop and YARD
68
+ tasks are defined even when their gem is absent, and abort with an install hint rather than
69
+ passing vacuously.
70
+ - **RuboCop** (with `rubocop-minitest`, `rubocop-rake`, `rubocop-performance`) via
71
+ [`.rubocop.yml`](.rubocop.yml), and **YARD** via [`.yardopts`](.yardopts).
72
+ - **CI and release plumbing** — [`.github/workflows/ci.yml`](.github/workflows/ci.yml),
73
+ [`release.yml`](.github/workflows/release.yml) and
74
+ [`docs.yml`](.github/workflows/docs.yml), which publishes the YARD docs to
75
+ <https://developerz-ai.github.io/magik/api/>. Releases publish to RubyGems over trusted publishing
76
+ (OIDC), with `rubygems_mfa_required` set on the gem; [`PUBLISHING.md`](PUBLISHING.md) documents
77
+ the one-time manual bootstrap that 0.0.1 itself requires.
78
+ - **Project governance** — [`CONTRIBUTING.md`](CONTRIBUTING.md), [`SECURITY.md`](SECURITY.md),
79
+ [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) and [`LICENSE`](LICENSE) (MIT).
80
+
81
+ ### Notes
82
+
83
+ - **Nothing here has been benchmarked, deployed, or run against a real database.** No number in
84
+ this repository is a measurement.
85
+ - `0.0.1` is published **by hand**: RubyGems cannot attach a trusted publisher to a gem that does
86
+ not exist yet, so the first push is manual and every release after it goes through the workflow.
87
+ [`PUBLISHING.md`](PUBLISHING.md) has the exact steps.
88
+
89
+ [Unreleased]: https://github.com/developerz-ai/magik/compare/v0.0.1...HEAD
90
+ [0.0.1]: https://github.com/developerz-ai/magik/releases/tag/v0.0.1
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 developerz.ai
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.
data/README.md ADDED
@@ -0,0 +1,356 @@
1
+ <h1 align="center">Magik</h1>
2
+
3
+ <p align="center"><strong>The AI-first full-stack Ruby framework: ship a SaaS in record time with an agent doing the typing.</strong></p>
4
+
5
+ <p align="center">One DSL for models, screens, actions, realtime, jobs, ledgers, APIs and admin — server-rendered on TruffleRuby, no frontend framework.</p>
6
+
7
+ <div align="center">
8
+
9
+ [![Gem Version](https://img.shields.io/gem/v/magik.svg)](https://rubygems.org/gems/magik)
10
+ [![CI](https://github.com/developerz-ai/magik/actions/workflows/ci.yml/badge.svg)](https://github.com/developerz-ai/magik/actions/workflows/ci.yml)
11
+ [![Ruby](https://img.shields.io/badge/ruby-%E2%89%A5%203.2-CC342D.svg)](https://www.ruby-lang.org)
12
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
13
+
14
+ [The spec — the source of truth](docs/idea/00-build-spec.md) ·
15
+ [Why AI-first](docs/idea/07-ai-first.md) ·
16
+ [Roadmap](ROADMAP.md) ·
17
+ [Docs](docs/idea/) ·
18
+ [Wiki](wiki/Home.md) ·
19
+ [API reference](https://developerz-ai.github.io/magik/api/) ·
20
+ [llms.txt](llms.txt)
21
+
22
+ </div>
23
+
24
+ > ## Status: pre-alpha, spec only
25
+ >
26
+ > **Magik is not implemented.** This repository is the ground work — the spec, the documentation, the
27
+ > gem skeleton, the CI and the release plumbing. There is no framework behind it yet: no `magik new`,
28
+ > no `model`, no `screen`, no `action`, no server. **Every framework feature named on this page is
29
+ > `planned`**; the short list of things that genuinely run is
30
+ > [what exists today](#what-exists-today).
31
+ >
32
+ > `0.0.1` is a name reservation on RubyGems and nothing more — see [CHANGELOG.md](CHANGELOG.md)
33
+ > and [what exists today](#what-exists-today) for the exact inventory.
34
+ > Nothing here has been benchmarked, deployed, or run against a database, and this file will say so
35
+ > until that changes. `As of 2026-08-26`; re-derive with `ruby -Ilib exe/magik version --json` and
36
+ > `gem list -r magik --all`.
37
+
38
+ > **If you are a coding agent, start with [`llms.txt`](llms.txt)** — the whole repository as one link
39
+ > map, and the shortest route to knowing which parts exist. Then read
40
+ > [`CLAUDE.md`](CLAUDE.md), the working contract for changes made inside this repo, and
41
+ > [`.claude/README.md`](.claude/README.md) for the agents and slash commands this repo ships.
42
+
43
+ ## What it is
44
+
45
+ An opinionated, full-stack Ruby framework on TruffleRuby **whose primary developer is an AI agent**.
46
+ One DSL for models, screens (UI), actions (mutations), realtime channels, background jobs, ledgers
47
+ (money), APIs and admin panels. No separate frontend framework: the server renders HTML and htmx
48
+ handles interactivity.
49
+
50
+ The target is **99% of SaaS** — CRUD apps, dashboards, fintech, ecommerce, marketplaces — without
51
+ the author ever having to "graduate" to another stack. Fintech-grade money handling (double-entry
52
+ ledgers, audit trails, idempotent mutations) uses the same DSL grammar as everything else: there is
53
+ no separate "fintech mode".
54
+
55
+ Magik wraps rather than reinvents: Sequel, Que, Rodauth, Shrine, htmx, Falcon/Async, Minitest,
56
+ the money gem. → [the full library list](docs/idea/00-build-spec.md)
57
+
58
+ ## AI-first, and why that shapes every decision
59
+
60
+ The premise: the person shipping the SaaS describes it, and an agent writes it. That is a design
61
+ constraint, not a marketing line — an agent has different failure modes from a human, and the
62
+ architecture decisions below are answers to those failure modes rather than to taste.
63
+
64
+ | An agent's failure mode | Magik's answer | Consequence in the design |
65
+ |---|---|---|
66
+ | **Limited context.** Reading a framework costs the budget the product needed | one grammar for every subsystem — `model`, `screen`, `action`, `job`, `ledger`, `api` all declare the same way. Learn one primitive and you can guess the rest | no second syntax, no plugin API, no configuration dialect. A feature that does not fit the grammar does not ship |
67
+ | **Confident wrongness.** It will write plausible code that is subtly unsafe | guardrails that **refuse to boot**: unbalanced ledgers, `field :card_number`, cross-domain access, cross-request state, an unconverted timestamp. Enforcement is the product | a convention that is not a boot failure is a suggestion. Review cannot be the mechanism when nobody reads every line |
68
+ | **No feedback loop.** A silent wrong default is never noticed | `magik check` — the one command that says whether the app is shippable, and `magik check --scale` for the queries that will hurt later | one command, one verdict. The agent's loop is edit → check → fix, not edit → hope |
69
+ | **Cannot recover from a bare stack trace** | every error carries a stable `MAGIK_*` code, the concrete cause, and a `fix:` line that is a **command you run, never advice** | a failure costs one round-trip instead of a search |
70
+ | **Boilerplate is where it burns tokens and makes mistakes** | zero HTML, JS or CSS written by hand; tests, factories and admin CRUD inferred from the declarations already made | the [example below](#the-dsl-in-one-worked-example) is the whole of a feature |
71
+ | **A wrong guess about the stack is expensive to undo** | convention over configuration, and every opinionated default has a *proven* config-level swap | the agent never has to choose a database, a queue or a cache to start, and is never trapped by not having chosen |
72
+
73
+ **This is a claim about the design, not about a build.** None of it is implemented — read the
74
+ status callout above. The reason it is written down now is that these decisions are cheap today and
75
+ a rewrite later. → [docs/idea/07-ai-first.md](docs/idea/07-ai-first.md)
76
+
77
+ The repository dogfoods the premise: the framework itself is built by agents working from
78
+ [the spec](docs/idea/00-build-spec.md), with [`CLAUDE.md`](CLAUDE.md) as the contract and
79
+ [`.claude/`](.claude/README.md) carrying the agents and slash commands that drive the phases.
80
+
81
+ ## Who it is for, and the range
82
+
83
+ **One framework from a weekend CRUD app to a multi-tenant fintech product** — no lite mode, no
84
+ second stack to graduate to. The small end pays nothing for the large end; the large end is
85
+ configuration the small end never types.
86
+
87
+ | End of the range | The intent | State `As of 2026-08-26` |
88
+ |---|---|---|
89
+ | **small** — a first internal tool, a dashboard | a model, a screen and an action, and the app runs. Zero HTML, JS or CSS written by hand | **not implemented** — the shape below is the target, not a sample you can run |
90
+ | **large** — multi-tenant SaaS, real money | tenant scoping, UUIDv7 keys, double-entry ledgers, audit trails and domain boundaries are in the beginner's app from day one, unused until declared | **not implemented** — [phases 5–9](#phases) |
91
+ | **the escape hatch** | every opinionated default has a config-level swap: DB engine, cache, jobs, search, realtime | **not implemented** — and the spec requires each swap to be *proven working before merge*, never promised |
92
+
93
+ Nothing in the right-hand column is a hedge about quality. It is the literal state of the tree:
94
+ this repository contains no framework code.
95
+
96
+ ## Magik or Ultimate?
97
+
98
+ [**Ultimate**](https://github.com/developerz-ai/ultimate) is this project's sibling, from the same
99
+ authors, built on the same thesis: one uniform primitive grammar, server-authoritative, AI-first,
100
+ batteries included, guardrails as the product. It runs that thesis on **Bun + TypeScript +
101
+ SolidJS**. Magik runs it on **TruffleRuby + Sequel + htmx**.
102
+
103
+ **If you would rather write TypeScript, use Ultimate.** It is a real, released framework with a
104
+ published npm surface and a working gate; Magik is a specification with no implementation behind it.
105
+ That is not a close call today, and this file will not pretend otherwise.
106
+
107
+ Magik exists for the developers on the other side of that preference — people who like Ruby and do
108
+ not want a TypeScript toolchain in their life. The positive case, stated as taste and toolchain
109
+ rather than as an argument about a language:
110
+
111
+ - **Blocks are the natural shape of a declaration DSL.** `model :Product do … end` is Ruby doing
112
+ what Ruby has always been good at. The same thing in TypeScript is object literals and generics.
113
+ - **No compile step.** No `tsconfig`, no bundler, no `dist/`, no build to keep in sync with source.
114
+ Edit, reload.
115
+ - **A small dependency graph.** A handful of mature gems, not an `npm` tree.
116
+ - **No client build either.** htmx is one script tag; there is no component framework, no hydration
117
+ model and no per-route JS budget to think about, because there is barely any JS.
118
+ - **TruffleRuby makes the performance objection stale.** "Ruby is slow" was an argument about
119
+ CRuby's interpreter; a JIT-compiled runtime with real parallelism is a different conversation.
120
+
121
+ Accurate on both sides `As of 2026-08-26` — Ultimate's column is read from its own repository, not
122
+ guessed:
123
+
124
+ | | **Magik** | **Ultimate** |
125
+ |---|---|---|
126
+ | Status | **spec only, nothing implemented** | released and published to npm |
127
+ | Runtime | TruffleRuby (CRuby ≥ 3.2 for tooling) | Bun |
128
+ | Language | Ruby | TypeScript |
129
+ | Data layer | Sequel — explicit queries, no lazy loading | its own `entity` primitive over Postgres, hand-written parameterised SQL |
130
+ | UI | server-rendered HTML + htmx, compiled from the DSL | SolidJS, five render modes, islands, per-route JS budgets |
131
+ | Client build | none | Bun bundler |
132
+ | Realtime | opt-in per screen; Postgres `LISTEN/NOTIFY` by default, Redis swappable | three tiers — channels, live queries, and local-first (deferred) |
133
+ | Offline | **out of scope, permanently** | in scope — a generated service worker, per-route offline strategies |
134
+ | Tests | Minitest, wrapped by a `test` DSL | `bun:test` with six typed test kinds |
135
+ | The gate | `magik check` | `x verify` |
136
+ | For | people who want Ruby's ergonomics and no TS toolchain | people who want end-to-end type safety and a modern JS stack |
137
+
138
+ Neither is a lite version of the other, and neither is planned to converge on the other. Same
139
+ thesis, two populations.
140
+
141
+ ## The intended `magik new` experience — planned
142
+
143
+ **None of this works yet.** It is written down so the shape is fixed before the code is:
144
+
145
+ ```sh
146
+ gem install magik # installs 0.0.1 once it is pushed — a version constant and `magik help`
147
+ magik new shop && cd shop # planned
148
+ bin/setup # planned — dependencies, database, migrations, seeds
149
+ magik server # planned — Falcon, hot reload
150
+ ```
151
+
152
+ The CLI surface the spec commits to: `magik new`, `magik generate model|screen|action|migration`,
153
+ `magik console`, `magik server`, `magik worker`, `magik test`, `magik check`. **`magik help` marks
154
+ each one `ready` or `planned`** — "not built yet" and "not a command" are different facts, and the
155
+ CLI already says which is which:
156
+
157
+ ```sh
158
+ ruby -Ilib exe/magik help # every command, with its status
159
+ ```
160
+
161
+ → [Phase table](#phases) · [the CLI in the DSL surface doc](docs/idea/02-dsl-surface.md) ·
162
+ [the spec's build order](docs/idea/00-build-spec.md)
163
+
164
+ ## The DSL, in one worked example
165
+
166
+ The spec's first success criterion is **a new CRUD SaaS screen in under 30 lines, with zero HTML,
167
+ JS or CSS written**. This is that shape — **the target, not a working sample**. No part of it runs
168
+ today, and the exact names may still move before phase 2 lands.
169
+
170
+ ```ruby
171
+ App.define :Shop do
172
+ model :Product do
173
+ field :name, :string, required: true
174
+ field :price, :money, currency: "USD" # integer cents; a Float is refused by the type
175
+ field :stock, :integer, default: 0
176
+ scope(:in_stock) { where { stock > 0 } } # tenant_id is applied for you
177
+ end
178
+
179
+ screen :Products do
180
+ state :products do
181
+ Product.in_stock
182
+ end
183
+
184
+ body do
185
+ card do
186
+ data_table of: :products, using: :ProductRow, empty: t("products.none")
187
+ end
188
+ end
189
+ end
190
+
191
+ action :restock do |params|
192
+ product = Product.find!(params[:product_id])
193
+ product.update(stock: product.stock + params[:count])
194
+
195
+ redraw :products
196
+ toast t("products.restocked"), level: :success
197
+ end
198
+ end
199
+ ```
200
+
201
+ Twenty-seven lines, plus a four-line `component :ProductRow` whose `button "Restock", action:
202
+ :restock` is what posts to the action. What the spec says that should project into: a Sequel-backed
203
+ model with a UUIDv7 primary key and an automatic `tenant_id`, a page auto-routed from its name and
204
+ rendered as server-side HTML with `hx-*` attributes, a POST endpoint the button is wired to, a
205
+ partial re-render swapped in by `redraw`, and tests inferred from `required:` and the field types.
206
+ **Realtime is not in that list** — a screen stays plain request/response until it declares `live` or
207
+ `channel`, so nothing pays for a websocket it did not ask for.
208
+
209
+ → [the canonical shape of every declaration](docs/idea/02-dsl-surface.md)
210
+
211
+ ## Phases
212
+
213
+ The build order from [the spec](docs/idea/00-build-spec.md). One status column, one value in it.
214
+
215
+ | Phase | Brings | Status |
216
+ |---|---|---|
217
+ | 1 · Foundation | `App.define`, `model`, `migrate`, money type, UUIDv7, tenant injection, the CLI | not implemented |
218
+ | 2 · Rendering & Actions | `component`, `screen`, `action`, the component kit, design tokens and dark mode | not implemented |
219
+ | 3 · Realtime (opt-in) | `live`, `channel`, `broadcast`, `presence`; Postgres `LISTEN/NOTIFY` by default | not implemented |
220
+ | 4 · Jobs & Async | `job` with retries and schedules, a transactional Postgres queue, `magik worker` | not implemented |
221
+ | 5 · Money & Compliance | `ledger` (double-entry, append-only), `audited`, `immutable_after:`, `idempotent_by`, `flow` | not implemented |
222
+ | 6 · API & Integration | `api` resources, incoming and outgoing `webhook`, bearer/api-key/JWT auth, rate limits | not implemented |
223
+ | 7 · Auth, Billing, Admin | `auth` (Rodauth-backed), `billing`, `admin_panel`, `tenant_by :subdomain` | not implemented |
224
+ | 8 · i18n, PWA, Notifications | `locales`, `translatable:`, timezone-safe timestamps, `pwa`, `notification` | not implemented |
225
+ | 9 · Testing | a Minitest-compiling `test` DSL, inferred factories, Ractor-parallel runner, `magik test` | not implemented |
226
+
227
+ Re-derive the status of any subsystem rather than trusting this table: `ruby -Ilib exe/magik help`
228
+ for the CLI's real surface, `rake test` for what is proven, and
229
+ `grep -rln NotImplementedError lib/magik` for what is still a stub.
230
+ → [docs/idea/06-phases.md](docs/idea/06-phases.md) for what each phase contains ·
231
+ [ROADMAP.md](ROADMAP.md) for the sequencing and what a phase must demonstrate before it closes.
232
+
233
+ ## The architecture decisions
234
+
235
+ Twelve non-negotiables, decided before the first line of framework code. They are the reason this
236
+ repository exists in this order — changing one is a change to
237
+ [the spec](docs/idea/00-build-spec.md), not a pull request.
238
+
239
+ | Decision | The rule | Why it is not negotiable |
240
+ |---|---|---|
241
+ | **Runtime** | TruffleRuby. Concurrency via Ractors and Fibers, never a thread per request | the performance ceiling that makes a Ruby framework worth building now. CRuby ≥ 3.2 is supported for tooling and development only |
242
+ | **Server** | Rack + Falcon, async and fiber-based | an async server is a precondition for opt-in realtime on the same process model |
243
+ | **Database** | Sequel, never ActiveRecord. Explicit queries, no lazy-loading magic | an N+1 you cannot see is an N+1 you cannot fix |
244
+ | **No SPA framework** | server-rendered HTML plus htmx attributes, compiled from the DSL. No React, Vue or Ember — ever | one language, one render path, no client build step |
245
+ | **Realtime is opt-in** | per screen, never global. `live` / `channel` turn it on; nothing costs anything until declared | global realtime is what made the previous generation of these frameworks unaffordable |
246
+ | **Multi-tenant by default** | every model auto-scoped by `tenant_id`; UUIDv7 primary keys from day one | sortable, shard-safe, and retrofitting tenancy is a rewrite |
247
+ | **Stateless app servers** | no in-process session or UI state across requests | "add another server" has to stay a config change |
248
+ | **Money** | an integer-cents `:money` type. Floats are refused **at the type level**, not by review | float currency bugs are silent and permanent |
249
+ | **Swap points are mandatory** | DB engine, cache, jobs, search and realtime backends are config-switchable with no app code change, and each swap must be *proven* before merge | magic with no escape hatch is an eventual rewrite. That is the lesson from Meteor |
250
+ | **Domain modules** | `domains/<name>/domain.rb` declares `depends_on`, `exposes`, `publishes_events`; cross-domain model access fails **at boot** | a boundary that is not a boot failure is a suggestion |
251
+ | **Guardrails at boot** | unbalanced ledgers, a `field :card_number`, a domain violation, cross-request state, an unconverted timestamp — each refuses to boot | this enforcement *is* the product |
252
+ | **Errors are instructions** | every failure carries a stable `MAGIK_*` code, a concrete cause and a runnable `fix:` line | a failure should cost one command, not a search |
253
+
254
+ ## The limits, stated loudly
255
+
256
+ Two things Magik will **not** do. They are permanent scope decisions, not gaps waiting on a phase:
257
+
258
+ - **No offline support.** The server is always the single source of truth. There is no local write
259
+ queue, no reconciliation, no conflict resolution. An app that must work on a plane is the wrong
260
+ app for this framework.
261
+ - **No heavy client-side compute.** Canvas editors, games, real-time drawing surfaces, anything
262
+ whose interaction loop cannot survive a server round-trip. The spec's rule is to refuse and say
263
+ so, never to silently degrade.
264
+
265
+ Neither limit is enforced by code yet, because there is no code.
266
+ → [docs/idea/05-limits.md](docs/idea/05-limits.md) · [the spec](docs/idea/00-build-spec.md)
267
+
268
+ ## What exists today
269
+
270
+ The honest inventory, `As of 2026-08-26`. Everything here is real and runnable; nothing else in this
271
+ file is.
272
+
273
+ | What ships | Detail |
274
+ |---|---|
275
+ | **Zero runtime dependencies** | the gem loads nothing but the standard library. The gems Magik intends to wrap are listed in [`magik.gemspec`](magik.gemspec) as comments, to be added by the phase that needs each one |
276
+ | `lib/magik.rb` | plain `autoload` over a `Magik::SUBSYSTEMS` map, so requiring `magik` reads one file |
277
+ | `Magik::Error` | real and tested: a stable `MAGIK_*` code, a cause, and a runnable `fix:` line, with a `to_h` for `--json`. The convention, working, before any catalogue exists |
278
+ | `magik version` · `magik help` | a working CLI, both with `--json`. `help` lists every spec'd command and marks it `ready` or `planned` |
279
+ | 19 subsystem stubs | one per planned subsystem, each exposing `SPEC_PHASE`, `DSL_SURFACE` and `STATUS`, with a `.define` that raises `NotImplementedError` naming the spec |
280
+ | the test suite | Minitest, **passing on bare Ruby with no bundle** — `rake test` |
281
+
282
+ That is the whole of it. There is no `App.define`, no `model`, no `screen`, no `action`, no router,
283
+ no server, no database code.
284
+
285
+ ## Working on the framework itself
286
+
287
+ This repository is the framework, not an app built with it.
288
+
289
+ ```sh
290
+ bin/setup # dependencies and the local toolchain, idempotent
291
+ bin/check # THE GATE — the same steps CI runs. Green means the tree is shippable
292
+ rake test # the suite alone; works on bare Ruby, no bundle needed
293
+ ```
294
+
295
+ | Task | Command |
296
+ |---|---|
297
+ | the gate, as CI runs it | `bin/check` · one step: `bin/check --only test` · as data: `bin/check --json` |
298
+ | every rake task | `rake -T` — `build`, `check`, `docs:coverage`, `rubocop`, `test`, `yard` |
299
+ | tests | `rake test` |
300
+ | lint | `rake rubocop` (RuboCop comes from `bundle install`) |
301
+ | docs | `rake yard` · coverage: `rake docs:coverage` |
302
+ | the CLI, from source | `ruby -Ilib exe/magik version --json` · `ruby -Ilib exe/magik help` |
303
+ | a console | `bin/console` |
304
+ | the CLI against the demo app | `bin/dev` · [`dummy/`](dummy/) |
305
+ | release pre-flight (prints, never publishes) | `bin/release` · [PUBLISHING.md](PUBLISHING.md) |
306
+ | Postgres and friends, in containers | `docker/compose.yml` · [`.devcontainer/`](.devcontainer/) |
307
+
308
+ `rake test` needs nothing but Ruby and Rake. RuboCop and YARD are development dependencies — run
309
+ `bin/setup` (or `bundle install`) before `rake rubocop` or `rake yard`, or the task aborts with the
310
+ install hint rather than pretending to pass.
311
+
312
+ TruffleRuby is the production runtime and is **not** assumed to be installed locally; anything
313
+ TruffleRuby-specific runs in [CI](.github/workflows/ci.yml). Development on CRuby ≥ 3.2 is expected
314
+ and supported.
315
+
316
+ → [CONTRIBUTING.md](CONTRIBUTING.md) for the full loop, the commit convention and the rule that
317
+ every change must trace to a section of the spec.
318
+
319
+ ## Navigate
320
+
321
+ One hop per question.
322
+
323
+ | You want | Go |
324
+ |---|---|
325
+ | **what Magik is, authoritatively** | [docs/idea/00-build-spec.md](docs/idea/00-build-spec.md) — the source of truth; nothing contradicts it |
326
+ | why "AI-first" is a design constraint | [docs/idea/07-ai-first.md](docs/idea/07-ai-first.md) |
327
+ | the agents and slash commands for working here | [.claude/README.md](.claude/README.md) |
328
+ | the TypeScript sibling of this framework | [developerz-ai/ultimate](https://github.com/developerz-ai/ultimate) |
329
+ | the thesis, in full | [docs/idea/01-thesis.md](docs/idea/01-thesis.md) |
330
+ | the DSL surface, phase by phase | [docs/idea/02-dsl-surface.md](docs/idea/02-dsl-surface.md) |
331
+ | the boot-time guardrails | [docs/idea/03-guardrails.md](docs/idea/03-guardrails.md) |
332
+ | the swap points | [docs/idea/04-swap-points.md](docs/idea/04-swap-points.md) |
333
+ | the limits, argued | [docs/idea/05-limits.md](docs/idea/05-limits.md) |
334
+ | why a decision was made | [docs/idea/](docs/idea/) |
335
+ | how a subsystem is meant to work | [docs/architecture/](docs/architecture/) |
336
+ | running an app for real | [docs/ops/README.md](docs/ops/README.md) |
337
+ | the reference manual | [wiki/Home.md](wiki/Home.md) |
338
+ | the generated API docs | [developerz-ai.github.io/magik/api/](https://developerz-ai.github.io/magik/api/) — built by [`docs.yml`](.github/workflows/docs.yml) from `rake yard` |
339
+ | where code goes in an app you build | [wiki/Project-Layout.md](wiki/Project-Layout.md) · [dummy/](dummy/) — an invoicing/billing SaaS |
340
+ | what is planned, in what order | [ROADMAP.md](ROADMAP.md) |
341
+ | the machine-readable repo map | [llms.txt](llms.txt) |
342
+ | the contract for changing this repo | [CLAUDE.md](CLAUDE.md) · [AGENTS.md](AGENTS.md) |
343
+ | how to contribute | [CONTRIBUTING.md](CONTRIBUTING.md) · [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) |
344
+ | reporting a vulnerability | [SECURITY.md](SECURITY.md) |
345
+ | what changed | [CHANGELOG.md](CHANGELOG.md) |
346
+ | how a release is cut and published | [PUBLISHING.md](PUBLISHING.md) |
347
+
348
+ ## Never claimed
349
+
350
+ No adoption numbers. No production deployments. No benchmarks. No passing-test counts. No
351
+ comparison against another framework. None of those exist yet, and this file will keep saying so
352
+ until they do — a number here that no command re-derives is a bug in the documentation.
353
+
354
+ ## License
355
+
356
+ MIT © [developerz.ai](https://developerz.ai) — [LICENSE](LICENSE)
data/exe/magik ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Executable shim for the `magik` command.
5
+ #
6
+ # It does exactly two things: load the library and hand ARGV to
7
+ # Magik::CLI.start, which returns the process exit status. All behaviour —
8
+ # including error rendering and `--json` output — lives in lib/magik/cli.rb so
9
+ # that it is testable without shelling out.
10
+
11
+ require "magik"
12
+
13
+ exit Magik::CLI.start(ARGV)
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Magik
4
+ # Mutation handlers, auto-wired to htmx POST requests.
5
+ #
6
+ # Implements: **Phase 2 — Rendering & Actions** of `docs/idea/00-build-spec.md`.
7
+ #
8
+ # Planned DSL surface, copied from the spec:
9
+ #
10
+ # * `action :name do |params| ... end`
11
+ # * `idempotent_by on actions — dedupes retried mutations`
12
+ #
13
+ # Status: **Not implemented — spec only.** Every entry point below raises
14
+ # {NotImplementedError}. Nothing here reads config, touches a database or
15
+ # emits a byte of HTML.
16
+ #
17
+ # @see Magik::SUBSYSTEMS
18
+ module Action
19
+ # The build-spec phase this subsystem implements.
20
+ # @return [String]
21
+ SPEC_PHASE = "Phase 2 — Rendering & Actions"
22
+
23
+ # The DSL this subsystem will expose, verbatim from the spec.
24
+ # @return [Array<String>]
25
+ DSL_SURFACE = [
26
+ "action :name do |params| ... end",
27
+ "idempotent_by on actions — dedupes retried mutations"
28
+ ].freeze
29
+
30
+ # Implementation status of this subsystem.
31
+ # @return [String]
32
+ STATUS = "Not implemented — spec only"
33
+
34
+ # Entry point for the Action DSL.
35
+ #
36
+ # @param _args [Array] ignored
37
+ # @param _options [Hash] ignored
38
+ # @return [void] never returns
39
+ # @raise [NotImplementedError] always, until Phase 2 lands
40
+ def self.define(*_args, **_options)
41
+ raise NotImplementedError, "Magik::Action is spec-only; see docs/idea/00-build-spec.md"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Magik
4
+ # Auto-generated CRUD admin panels over declared models.
5
+ #
6
+ # Implements: **Phase 7 — Auth, Billing, Admin** of `docs/idea/00-build-spec.md`.
7
+ #
8
+ # Planned DSL surface, copied from the spec:
9
+ #
10
+ # * `admin_panel :Model do list_display; filterable; searchable end`
11
+ #
12
+ # Status: **Not implemented — spec only.** Every entry point below raises
13
+ # {NotImplementedError}. Nothing here reads config, touches a database or
14
+ # emits a byte of HTML.
15
+ #
16
+ # @see Magik::SUBSYSTEMS
17
+ module Admin
18
+ # The build-spec phase this subsystem implements.
19
+ # @return [String]
20
+ SPEC_PHASE = "Phase 7 — Auth, Billing, Admin"
21
+
22
+ # The DSL this subsystem will expose, verbatim from the spec.
23
+ # @return [Array<String>]
24
+ DSL_SURFACE = [
25
+ "admin_panel :Model do list_display; filterable; searchable end"
26
+ ].freeze
27
+
28
+ # Implementation status of this subsystem.
29
+ # @return [String]
30
+ STATUS = "Not implemented — spec only"
31
+
32
+ # Entry point for the Admin DSL.
33
+ #
34
+ # @param _args [Array] ignored
35
+ # @param _options [Hash] ignored
36
+ # @return [void] never returns
37
+ # @raise [NotImplementedError] always, until Phase 7 lands
38
+ def self.define(*_args, **_options)
39
+ raise NotImplementedError, "Magik::Admin is spec-only; see docs/idea/00-build-spec.md"
40
+ end
41
+ end
42
+ end
data/lib/magik/api.rb ADDED
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Magik
4
+ # REST APIs and webhooks in both directions, with auto pagination, filtering and
5
+ # sorting.
6
+ #
7
+ # Implements: **Phase 6 — API & Integration** of `docs/idea/00-build-spec.md`.
8
+ #
9
+ # Planned DSL surface, copied from the spec:
10
+ #
11
+ # * `api :V1 do resource :name do index/show/create/update/destroy end end`
12
+ # * `webhook :incoming, :name do verify_signature; on :event end`
13
+ # * `webhook :outgoing, :name do fires_on; deliver_to; sign_with end`
14
+ # * `auth: :bearer, :api_key, :jwt; rate limiting by plan`
15
+ #
16
+ # Status: **Not implemented — spec only.** Every entry point below raises
17
+ # {NotImplementedError}. Nothing here reads config, touches a database or
18
+ # emits a byte of HTML.
19
+ #
20
+ # @see Magik::SUBSYSTEMS
21
+ module API
22
+ # The build-spec phase this subsystem implements.
23
+ # @return [String]
24
+ SPEC_PHASE = "Phase 6 — API & Integration"
25
+
26
+ # The DSL this subsystem will expose, verbatim from the spec.
27
+ # @return [Array<String>]
28
+ DSL_SURFACE = [
29
+ "api :V1 do resource :name do index/show/create/update/destroy end end",
30
+ "webhook :incoming, :name do verify_signature; on :event end",
31
+ "webhook :outgoing, :name do fires_on; deliver_to; sign_with end",
32
+ "auth: :bearer, :api_key, :jwt; rate limiting by plan"
33
+ ].freeze
34
+
35
+ # Implementation status of this subsystem.
36
+ # @return [String]
37
+ STATUS = "Not implemented — spec only"
38
+
39
+ # Entry point for the API DSL.
40
+ #
41
+ # @param _args [Array] ignored
42
+ # @param _options [Hash] ignored
43
+ # @return [void] never returns
44
+ # @raise [NotImplementedError] always, until Phase 6 lands
45
+ def self.define(*_args, **_options)
46
+ raise NotImplementedError, "Magik::API is spec-only; see docs/idea/00-build-spec.md"
47
+ end
48
+ end
49
+ end