Merge requests and CI for knitting patterns. A designer pastes a written pattern; a Gemini agent (Vertex AI) turns it into a real GitLab project through the GitLab MCP server; a deterministic pipeline test-knits every row of every size in software and goes red at the exact row where the stitch math breaks. Revisions are merge requests, tester feedback is row-pinned issues, merged fixes regenerate the public errata page, versions are tagged releases, and a green check earns the listing badge. Red is math, never opinion. The merge button is always the human's.
Built for the Google Cloud Rapid Agent hackathon, GitLab track: the product's AI is Gemini on Vertex AI; the agent's hands are GitLab's MCP server; the product's surfaces — merge requests, CI, issues, releases, Pages — are GitLab.
paste / drop a pattern
│
┌──────────────▼──────────────┐
│ web/ (static, no build) │ 8 screens, plain ES modules
│ fabric renderer (canvas) │ chart + simulated fabric
└──────┬───────────────┬──────┘
│ /api/* │ imports /core/*.js directly
┌──────▼──────┐ ┌──────▼──────┐
│ server/ │ │ core/ │ deterministic checker —
│ Express │ │ notation + │ plain math, zero AI,
│ │ │ checker + │ zero dependencies
│ Gemini │ │ fabric │
│ (Vertex AI) │ └──────▲──────┘
│ + │ │ bundled into tools/check.cjs
│ GitLab MCP │ ┌──────┴──────────────────────────┐
└──────┬──────┘ │ every created pattern project │
│ MCP │ runs the SAME checker in real │
┌──────▼──────┐ │ GitLab CI on every commit/MR │
│ gitlab.com │◄┘ → verdict.json, badge.svg, │
│ (the DB) │ errata page on GitLab Pages │
└─────────────┘
core/— the product's heart, dependency-free ES modules that run in Node and the browser identically:notation.jstokenizes a written row (k2, *yo, k2tog, k6; rep from * to last 5 sts…, per-size parens, bracketed per-size groups, claims like— 124 sts) into stitch operations. Deterministic; unknown tokens are reported, never guessed.checker.jswalks every row for every size, tracking stitch counts through increases/decreases/repeats/taught stitches, validating repeat divisibility and the pattern's own "you should have N sts" claims. It fails with the exact row, expected and produced counts, per size — in the errata genre:Row 31, size S: expected 88 sts, instructions produce 86.Rows it cannot check are reported as skipped, never silently passed.fabric.jsrenders the row walk: a standard knitting chart (CYC symbols) and a simulated fabric where each stitch is drawn — the test knit animates row by row, and when the math breaks the failure is visible in the fabric itself at the failing row. Merge-request diffs render as two swatches side by side with changed rows highlighted.demo/— Marram, the demo cardigan (214 rows, 9 sizes) in its v1.0 (shipped bug at Row 31), v1.2 (current) and Row-47-rewrite (the open red MR) forms.
server/— Express. Servesweb/andcore/, plus the JSON API.gemini.js— the agent's language: Gemini via Vertex AI (@google/genai) parses pasted text into structured rows and numbered questions (it flags, it never guesses), translates diffs and pipeline results into knitting language, drafts fix proposals, MR descriptions and release notes.gitlab.js— the agent's hands: an MCP client. It speaks to GitLab's official hosted MCP server (/api/v4/mcp) and falls back to a bundled stdio GitLab MCP server using the same token. Create project, commit, open MR, file issues, read pipelines — every receipt in the UI links the real GitLab object.ci/— what gets committed into every created pattern project: a.gitlab-ci.ymlandtools/check.cjs(the samecore/checker, bundled bynpm run build:ci), so the red/green verdict comes from real pipelines on real runners; CI also regenerates the badge SVG and the public errata page (GitLab Pages).demo.js— seeds/resets the Marram demo project (real project, real red/green pipelines, real MRs and issues — only the history is staged).
web/— eight screens, static HTML + ES modules, no framework, no build step. Wool paper, charcoal ink, two typefaces, the community's chart symbols as the only icon set. Installable as a PWA.
The GitLab project is the database: pattern source and history, MRs, row-pinned issues, releases, errata page, badge. The browser's localStorage holds the visitor's pattern list, their optional GitLab token, and a tester's size pick — that is the complete client state. The server stores nothing about the user.
npm install
cp .env.example .env # fill GITLAB_TOKEN + GOOGLE_CLOUD_PROJECT (see below)
npm run build:ci # bundle the checker for CI commits
npm start # http://localhost:4400node core/checker.test.js runs the checker's acceptance tests (the canon
Marram record: v1.0 red at Row 31 size S, v1.2 green across 9 sizes, the
Row 47 rewrite red for size M).
| Env var | Default | What it does |
|---|---|---|
PORT |
4400 |
Server port (Cloud Run sets this itself). |
GITLAB_TOKEN |
— | Service PAT (api scope) used when a visitor brings no token; their pattern lands in the public sandbox group. |
GITLAB_SANDBOX_GROUP |
groupgooglerapid |
The public sandbox group path on GitLab. |
GITLAB_SANDBOX_GROUP_ID |
— | Numeric id of the sandbox group (optional; skips one lookup). |
GITLAB_URL |
https://gitlab.com |
GitLab instance base URL. |
GITLAB_MCP_MODE |
auto |
auto tries the official hosted MCP server first, then falls back to the bundled stdio MCP server; hosted/stdio force one. |
GOOGLE_GENAI_USE_VERTEXAI |
true |
Use Vertex AI with Application Default Credentials. |
GOOGLE_CLOUD_PROJECT |
— | Google Cloud project for Vertex AI. |
GOOGLE_CLOUD_LOCATION |
us-central1 |
Vertex AI region. |
GEMINI_API_KEY |
— | Optional fallback when ADC is unavailable (still Gemini). |
GEMINI_MODEL |
gemini-2.5-flash |
The model behind the agent. |
PUBLIC_BASE_URL |
http://localhost:4400 |
Public URL used in share links and badge embed snippets. |
DEMO_PROJECT_PATH |
marram |
Path of the seeded demo project inside the sandbox group. |
Users who bring their own GitLab personal access token (Notions screen) have
it stored in their browser only; it rides along as an x-gitlab-token header
and casts-on land in their own namespace. It never touches server storage.
gcloud run deploy gauge --source . \
--region us-central1 --allow-unauthenticated \
--set-env-vars GITLAB_TOKEN=...,GITLAB_SANDBOX_GROUP=...,GOOGLE_GENAI_USE_VERTEXAI=true,GOOGLE_CLOUD_PROJECT=...,GOOGLE_CLOUD_LOCATION=us-central1,PUBLIC_BASE_URL=https://<service-url>The container is stateless by design — everything durable lives in GitLab.
- Works on written row-by-row instructions in a supported stitch vocabulary. What the agent cannot normalize it flags as a question instead of guessing.
- Chart images are refused honestly; written form only in v1.
- Brioche, complex colorwork and some short-row constructions are skipped, not guessed — the verdict reports the gap count.
- The checker checks math and the pattern's own claims. It cannot judge fit, gauge or drape — that's what human test knitters are for. Gauge frees them to do exactly that.
- GitLab's MCP server is Beta; when a call fails the receipt shows the raw reason and retries only the failed call.
- GitLab.com runs CI for identity-verified accounts only. If the service
account isn't verified yet, pipelines are still created (and linked) but
won't execute; Gauge then runs the same deterministic checker server-side
for the verdict — identical math, clearly the same code CI runs
(
tools/check.cjs). Verify the account once and pipelines run on the next push. - Patterns cast on without a token land in a public sandbox group, and the UI says so before the paste. Sellers: bring your own token first.
MIT