1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# Unified dev commands for alix. Run `make <target>`.
#
# Formatting goes through the NIGHTLY toolchain on purpose: this repo's
# rustfmt.toml uses nightly-only options, so plain `cargo fmt` (stable) can't
# apply the config and reformats by different rules. (A cargo alias can't pick a
# toolchain — `+nightly` is handled by rustup before cargo sees it — which is
# why these live in a Makefile rather than .cargo/config.toml.)
:
# Compile the workspace.
:
# Compile the lean core only: no AI backends, no web server. This is the guard
# that keeps the lib buildable AI/server-free for the future mobile client (see
# CONTRIBUTING.md).
:
# Run the test suite — the primary gate.
:
# Lint, including tests and examples.
:
# Syntax-check the JS embedded in the served HTML assets (assets/web/*.html).
# That JS is shipped as static strings, so cargo never parses it — this catches a
# syntax error the Rust gates can't see. Needs node; a no-op (not a failure) when
# node isn't installed, so it never blocks a cargo-only contributor or CI. Not
# wired into `check` for that reason — run it deliberately, like fmt.
:
# Format with the nightly toolchain (NOT stable `cargo fmt`).
:
# Verify formatting without writing.
:
# Wrap over-long lines in ROADMAP.md (or files passed via ARGS) onto the
# roadmap's 13-space continuation indent. Wrap-only: lines already within
# width are never touched, so hand-made breaks don't churn. Stdlib python3.
:
# Roadmap stats, read-only: items by state (done/partial/open) and the open
# items split by priority. The deterministic half of a roadmap audit; whether
# an "open" item is secretly already shipped still needs a reader (see
# CLAUDE.md's roadmap-drift note). Run from a checkout that has ROADMAP.md.
:
# The gates that must stay green before work is done. (fmt is intentionally
# separate — formatting uses nightly and is run deliberately, not as a gate.)
:
# Full CI parity, run the way GitHub does (see .github/workflows/ci.yml): the
# nightly fmt check, then clippy + tests under `-Dwarnings`, then coverage with
# the warnings gate cleared (coverage instruments its own flags). A green
# `make ci` predicts a green CI — so this is the pre-push / pre-release gate.
# It's heavier than `make check` (adds nightly fmt + a full coverage run, and the
# -Dwarnings/coverage flag split forces a recompile between steps), which is why
# `make check` stays the fast, lenient inner-loop gate rather than carrying these.
:
# Test coverage (needs cargo-llvm-cov: `cargo install cargo-llvm-cov`). Prints a
# per-file summary and writes a browsable report to target/llvm-cov/html/. A
# flashlight for untested branches — especially the AI plumbing's error paths —
# not a gate to chase a number. Nightly toolchain (matching coverage-lcov
# below): a few genuinely-untestable arms are marked
# `#[cfg_attr(coverage_nightly, coverage(off))]` (see `src/lib.rs`), which only
# takes effect under nightly — running this on stable would silently count
# those lines as missed instead of excluded.
:
# Coverage in lcov format for the Codecov upload (see .github/workflows/ci.yml
# and codecov.yml). Same nightly toolchain as `coverage` above. Writes
# lcov.info at the repo root (gitignored).
:
# Grader calibration (tests/calibrate.rs): the REAL grade prompt vs labeled
# adversarial answers, to catch a lenient grader. Needs the claude CLI logged in;
# makes real, costed calls. Off the normal gate: run before shipping a change
# to grade_prompt.
:
# Run the binary, e.g. `make run ARGS="stats mydeck.txt"`.
:
# Run the web frontend: the in-browser deck picker. ARGS may name a decks
# folder or workspace to serve as a scoped root, plus launcher flags,
# e.g. `make web ARGS="~/decks-test --lan"`.
:
# `web` with per-request stderr logging (ALIX_HTTP_LOG), the diagnostic net
# for {#server-subresource-stall}: when a page load hangs, the log decides
# whether the stuck request ever left tiny_http's connection reader.
:
# The mobile siblings of `web`: run the alix mobile app (apps/mobile) on a
# phone or tablet emulator (booting that AVD first if needed; the script
# resolves AVDs by name, so both can run side by side), or as a native Linux
# desktop window (fastest loop: hot reload, no emulator). flutter compiles the
# embedded Rust core through cargokit either way. Needs the frb toolchain and,
# for the emulators, ANDROID_HOME (see docs/dev/frb-bridge-setup.md).
:
:
:
# Assert the frb toolchain-alignment invariants (codegen/Dart/Rust version
# pins, the two template patches, the NDK the build uses) and fail on drift.
# Cheap and local; the mobile CI runs it before building.
:
# One-way copy of a host decks folder into the running emulator's alix app
# (dev-only, debug build). Restart the app to re-list. Progress made on the
# emulator never syncs back.
:
# The mobile test suite against the REAL embedded core, no emulator: builds
# the bridge dylib (frb's test loader reads rust/target/release/), runs the
# Dart unit + widget tests, then the full-app integration test in a Linux
# window. Time is injected through the bridge, so nothing sleeps. The
# on-Android tier of the same suite is the weekly mobile-drift workflow's
# to grow.
:
# The release APK (one arm64 artifact, matching the mobile-release workflow);
# debug-signed unless android/key.properties exists. Smoke-install this on a
# real phone before tagging mobile-vX.Y.Z (see RELEASING.md).
:
# Serve the user manual (docs/book) with live reload and open it in the browser.
# Requires mdBook: `cargo install mdbook`.
:
# Preview the presentation slides (site/slides.html) locally. Same server as
# `make site`, pointed at the slides URL.
:
# Serve the alix.study landing page locally for a quick preview (static files from
# site/). Needs python3. The /book/ link only resolves on the deployed Pages
# site — use `make book` to preview the manual itself.
#
# The "What's new" page (whatsnew.html) and the landing-page teaser are
# generated from CHANGELOG.md at build time (scripts/site-changelog.py; see
# the pages workflow for the real deploy-time run), so a local preview needs
# a generated copy too. Rather than write into the tracked site/ directory,
# this copies it into gitignored _site/ first (the same scratch directory
# name and pattern the pages workflow uses) and serves that.
:
# Install `alix` from this checkout.
:
# Remove build artifacts.
:
# Remove spent subagent-driven-development scratch (task briefs/reports, review
# packages, the ledger) but keep the dir + its .gitignore. The artifacts are
# gitignored and recoverable from git log, so this is safe to run anytime — it's
# how an SDD run cleans up after its branch lands (see CLAUDE.md).
:
# Release heartbeat: report whether shipped work has piled up unreleased (entries
# under CHANGELOG's [Unreleased] + days since the last vX.Y.Z tag) and flag when a
# release looks due. Informational; run at the start of a session (see CLAUDE.md).
# The policy it backstops is in RELEASING.md.
:
# Probe all four backends end-to-end (real tiny request through each installed
# CLI). Needs each CLI installed and the maintainer's own logins configured.
:
# Playwright end-to-end smoke suite for the alix web clients (e2e/): drives
# real `alix` servers (Chromium only) and asserts a click reaches the server —
# request, response, and screen, with zero uncaught page errors. Deliberately
# NOT part of `check` (needs Node + a browser download, and is slower) — run
# it deliberately, like `calibrate`. See e2e/README.md.
:
# Regenerate the landing-page carousel screenshots (site/img/shot-*.png) from
# a fresh copy of ~/alix-demo and ~/alix-kids — never the originals directly
# (see e2e/shots/capture.cjs's own header). Makes real Claude calls (deck
# augmentation, the tutor, the exam): a few minutes, and needs the `claude`
# CLI logged in. Not part of `make e2e`/CI — run it deliberately, around a
# release, when the app's look has changed enough that the carousel is
# stale. `make shots ONLY=6` re-shoots one slide (comma-separated for
# several); ARGS="--fresh" forces a clean re-copy of the demo/kids dirs.
:
# Download numbers: GitHub release assets + crates.io, in a terminal table.
# Read-only, no auth needed, stdlib python3. Run deliberately (network call),
# like heartbeat.
:
# Local, gitignored maintainer-only targets (e.g. wish-triage). The leading `-`
# makes this a silent no-op for anyone whose tree doesn't have the file.
-include