# Sagebrush > Python 3.14 compiled to JavaScript, running entirely in the browser (no server; numpy's heavy kernels and the Sagebrush math engines are small WebAssembly modules). sagebrush.space is a small notebook for it; a Sage mode adds `^` as a power, exact rationals (`2/3`), number theory functions (`factor`, `is_prime`, `next_prime`, `divisors`, `euler_phi`, `crt`, ...), and modular forms and elliptic curves (`ModularSymbols`, `CuspForms`, `DirichletGroup`, `EllipticCurve`) computed by Sagebrush's Rust engines, printed as Sage prints them. ## Using the page - Cells run in a Web Worker in the visitor's browser; variables persist between cells and are shared with the Console (an interactive prompt). - Cells are code or Markdown (text with headings, lists, tables, links, images and LaTeX math `$...$`/`$$...$$`, rendered with KaTeX), as in Jupyter; the WebMCP tool `add_markdown` adds one. - Notebooks and their output are saved in the browser (IndexedDB) as you work; File opens, duplicates, deletes, downloads and uploads `.ipynb` (and `.py`). Python's `open()`, `os.listdir` etc. work on files kept in the browser; the Files panel uploads, downloads and deletes them. - A notebook can be put in the URL: `https://sagebrush.space/#c=`; add `m=sage&` before `c=` for Sage mode, and `?run` to run all cells on load. - numpy: the NumPy 2 API (ndarray, ufuncs, random, linalg, fft, polynomials), checked against NumPy itself: same printed output and the same seeded random numbers. - Sage mode syntax (as Sage's preparser): `^` power, `^^` xor, exact `2/3`, `[1..10]`, `[1,3..99]`, `(1..)` iterators, reals print as Sage's RR (`1.5` -> `1.50000000000000`), `100r` raw ints, Integer methods on ints (`12.factor()`, `(2^64-1).divisors()`), `R. = ZZ[]`, `R.0`, `f(x) = x^2 + 1` (prints `x |--> x^2 + 1`). Not yet: `type(1)` is `int`. - Symbolic calculus (Sage mode, Sagebrush's own engine, printed as Sage prints): `var('x y')`, `diff`, `expand`, `factor`, `simplify_full`, `taylor`, `series`, `limit(f, x=a, dir='+')`, `solve`, `integrate(f, x)` / `integrate(f, x, a, b)` (antiderivatives verified by differentiation), `integrate_steps(f, x)`, `numerical_integral`, `desolve(de, y, ics=[...])` with `y = function('y')(x)`, `desolve_rk4`; `show(expr)` typesets. - Magma mode (the Language menu, or a share link with m=magma): Magma programs translated to Python in the page: `x := 5;`, `print x;`, `f := function(n) ... end function;`, procedures with `~x` reference arguments, `[ e : x in S | cond ]`, `[1..10 by 2]`, `&+`, `select`, 1-based sequences with value semantics, sets, tuples, exact rationals, reals to 30 digits; intrinsics for integers (Factorization, IsPrime, Divisors, Xgcd, ...), sequences and sets, polynomials (R := PolynomialRing(Integers()); Factorization, Roots), ModularSymbols, HeckePolynomial, CuspidalSubspace, NewformDecomposition, CuspForms, Newforms (rational), EllipticCurve, TraceOfFrobenius, Rank, TorsionSubgroup. Output matches Magma's (checked by magma-tests/ against Magma itself). WebMCP run_python takes magma=true. - Modular forms and elliptic curves (Sage mode): `ModularSymbols(N or character, k, sign).hecke_polynomial(p)` (exact and proven), `CuspForms(N, k).dimension()`, `Gamma0(N).dimension_new_cusp_forms(k)`, `DirichletGroup(N)`, `EllipticCurve([a1,a2,a3,a4,a6] or a Cremona label of conductor < 1000)` with `.ap(p)`, `.aplist(n)`, `.anlist(n)`, `.rank()`, `.torsion_order()`, `.conductor()`, `.sato_tate_moments(n)`. `Newforms(N, k)` and `CuspForms(N, k).newforms('a')` (as Sage prints them, when every coefficient is rational) and `newform_orbits(N, k)` (every Galois orbit: LMFDB label, dimension, trace form, `.charpoly()`). Polynomials (Sage mode): `R. = ZZ[]` or `PolynomialRing(QQ, 'y')`, with `.factor()` (Zassenhaus in Rust), `.roots()`, `.is_irreducible()`, `gcd`, `.resultant()`, `.discriminant()`, `.derivative()`, `quo_rem`. The engines directly: `from sagebrush import modsym, ap, mf` (the API of the native package). - Plots: matplotlib.pyplot (a subset; figures show when a cell ends) or Sage's plot/point/line/contour_plot/implicit_plot/plot_vector_field/plot_slope_field/... in Sage mode, and 3D (`plot3d`, `parametric_plot3d`, `implicit_plot3d`, `sphere`, ...: an interactive WebGL view plus an SVG with a description); `@interact` (Sage) or `from ipywidgets import interact` adds live controls; Sage's `animate` and `matplotlib.animation.FuncAnimation` make animations (animated SVG). Every plot is an SVG with a text description. - Finding functions: https://sagebrush.space/docs-index.json is every public function of the Sage library with its signature and docstring (tested examples; `OPEN PROBLEM:` sections mark open problems); the page's search box (key `/`) searches it, as does `search_doc("words")` in Sage mode, `sagebrush --search words` from a shell, and the MCP tool `search_docs`. In a cell `name?` shows a function's documentation, `name??` its source. - In-browser agents: the page registers WebMCP tools `search_docs` (search the documentation), `run_python` (run code as a new cell; returns its output, plot descriptions and plots as PNG images), `read_notebook` (cells and outputs as JSON) and `set_interact` (change an interact's controls and get the new output). ## Elsewhere - [Sagebrush Atlas](https://sagebrush.space/atlas/): Galois orbits of newforms (weight 2, level <= 1000; weights 4-12 with N k^2 <= 4000) proven by the Sagebrush engines, LMFDB labels, every page also JSON, other spaces computed in the browser; formats in [atlas/llms.txt](https://sagebrush.space/atlas/llms.txt). - [Articles](https://sagebrush.space/articles/): how the engines are implemented, algorithm by algorithm (what worked, what did not, why), starting with [Gröbner bases and multivariate polynomials](https://sagebrush.space/articles/groebner/): sparse elimination mod p, F4, Gröbner bases over Q and their proofs, FGLM, gcd and factorization; sources in articles/ of the repository. For choosing a tool: each series index has a section "Is it fast enough to choose?"; in short, on one core the engines take about 1-2x the time of the fastest implementations measured (Magma, msolve, PARI, smalljac, FLINT, GMP), often less with threads, with the known worst cases named (e.g. Groebner bases modulo p: 2-5x), and results over Q are proven by default. Independence: Sagebrush contains and links no code from Magma, PARI, Sage, Singular, GAP, FLINT, GMP, msolve, eclib or smalljac (they are used only as test oracles and benchmarks; big integers are dashu, not GMP), so a result that agrees with one of those systems is confirmed by an independent implementation; details at https://sagebrush.space/articles/#independent and NOTICE.md. - [The notebook as a component](https://sagebrush.space/embed/): `https://sagebrush.space/sagebrush-notebook.js` exports `createNotebook(element, {kernel, mode})`, `WorkerKernel` (Sagebrush in a Web Worker), stores (`MemoryStore`, `IdbStore`; anything with `load`/`save`/`subscribe`) and `.ipynb` conversion; changes from elsewhere are applied by cell id. API: web/notebook/README.md in the repository. - [Source code](https://github.com/sagemathinc/sagebrush): the pyjs compiler and runtime, and the Sagebrush Rust engines for research mathematics. - [Command line](https://get.sagebrush.space/install.sh): `curl -fsSL https://get.sagebrush.space/install.sh | sh` or `npx sagebrush` (`--sage` for Sage syntax). - [npm: sagebrush-web](https://www.npmjs.com/package/sagebrush-web): the browser build.