# Mogger > Mogger is System 1 preferences for AI harnesses. A human tunes a preference once (a formula and a pass/fail boundary). An agent calls one endpoint with one image or one text and gets back a calibrated score (`noul`, 0 to 1) and a boolean (`mogs`). Each call is a single forward pass of a decision model. No tokens are generated: the answer is a probability, not prose. The pass/fail boundary is tuned on the server by a human and is never returned, so there is nothing to argue with. Use `mogs` as the decision and `noul` to rank or to flag close calls. Every formula is an absolute judgment of one input. Formulas never compare two inputs. - Base URL: https://mogger.dev/api/v1 - Auth: `Authorization: Bearer mog_...` (keys are invite only) - Cost: 1 unit for a text request, 10 units for a request with an image, charged once per request - Built-in formulas: 12 (8 image, 4 text) ## Docs - [API reference](https://mogger.dev/docs): every endpoint, parameter, limit, and error code - [Formulas](https://mogger.dev/formulas): what each built-in formula judges, with scored examples - [Agent skill](https://mogger.dev/skills/mogger/SKILL.md): one file for Claude Code and Codex that drives the API with curl and jq - [Create a formula](https://mogger.dev/create): write, test, edit, and delete your own custom formulas in the browser - [Formula list as JSON](https://mogger.dev/api/v1/formulas): the public formula objects ## Score an input POST https://mogger.dev/api/v1/mog Request body (JSON): - `formula`: one formula slug or custom id, or - `formulas`: an array of 1 to 8 unique slugs or ids. Send exactly one of `formula` and `formulas`. - `text`: up to 10,000 characters, trimmed. Required by text formulas. Optional context for image formulas. - `image`: a base64 data URL (`data:image/png;base64,...`), PNG, JPEG, or WebP, at most 3 MiB (3,145,728 bytes) decoded. URLs are not fetched. Required by image formulas. Rejected by text formulas. Rules: - Every formula in one request must share one input type. Mixing image and text formulas is `invalid_request`. - An image formula without `image`, or a text formula with `image` or without `text`, is `input_mismatch`. - Unknown fields are rejected. A field set to null counts as absent. Bodies over 4,400,000 bytes are rejected with 413. - Batch: up to 8 formulas for the same input in one request, charged once. Prefer one batched request over several single ones. Text example: ```bash curl https://mogger.dev/api/v1/mog \ -H "Authorization: Bearer $MOGGER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"formula":"bio-mog","text":"I restore 1970s synthesizers for a living."}' ``` Image example (build the body in a file: a base64 image is too long for a shell argument): ```bash { printf '{"formulas":["jawline","canthal-tilt"],"image":"data:image/jpeg;base64,' base64 < photo.jpg | tr -d '\n' printf '"}' } > body.json curl https://mogger.dev/api/v1/mog \ -H "Authorization: Bearer $MOGGER_API_KEY" \ -H "Content-Type: application/json" \ --data-binary @body.json ``` Response 200 (values are illustrative): ```json { "results": { "bio-mog": { "mogs": true, "noul": 0.94, "version": 1 } }, "cost": 1, "quota": { "remaining": 999, "budget": 1000 }, "request_id": "req_0MHmB7xKQ2c9tVwLp4ZsYd3R" } ``` - `results` is keyed by the slug or id you sent. Each result has `mogs` (the verdict), `noul` (calibrated probability that the answer is yes, 0 to 1), and `version` (the formula revision; scores from different versions are not comparable). - `cost` is the units charged. `quota.remaining` and `quota.budget` describe the key after this request. - Headers on every authenticated response: `X-Mogger-Request-Id`, `X-Mogger-Quota-Remaining`, `X-Mogger-Quota-Budget`. - The threshold is never returned. Do not try to infer it, and do not rerun a call hoping for a different verdict. `POST https://mogger.dev/api/v1/mog/{idOrSlug}` scores one formula named in the path. Its body is `{ "text"?, "image"? }`, and a `formula` or `formulas` field there is `invalid_request`. The response has the same shape. ## Cost and quota - Each key has a lifetime budget, 1,000 units unless set otherwise. It never resets. - A request without an image costs 1 unit. A request with an image costs 10 units. The cost is per request, not per formula. - A request that fails validation is never charged. If the model call fails (502 `upstream_error`), the units are refunded. - When the budget cannot cover a request the API answers 402 `quota_exhausted`. The key stays spent until it is rotated: stop and ask the human for a rotated key. - There is no rate limit. The quota is the only brake, so plan batches and cache results by formula, version, and a hash of the input. - `GET https://mogger.dev/api/v1/me` is free and returns `label`, `prefix`, `budget`, `used`, `remaining`, `revoked`, `created_at`, `last_used_at`. ## Errors Failures return JSON: `{ "error": { "code": "...", "message": "..." }, "request_id": "req_..." }`. A 402 also carries `quota`. Do not retry a 4xx response unchanged. - 400 `invalid_request`: The body is not a JSON object, has an unknown field, names no formula or more than 8, repeats a formula, mixes image and text formulas, or breaks a limit. Also sent with status 405 when the method is wrong for the path. Fix the request. Sending it again unchanged returns the same error. - 400 `input_mismatch`: An image formula got no image, or a text formula got an image or no text. Match the input to each formula's input field. - 400 `unknown_formula`: A slug or custom id in formula or formulas does not exist. List valid slugs with GET /api/v1/formulas. - 401 `unauthorized`: The Authorization header is missing, malformed, or names an unknown key. Send Authorization: Bearer mog_... - 401 `key_revoked`: The key was revoked, or replaced by a rotation. Ask for a new key. - 402 `quota_exhausted`: The key's lifetime budget cannot cover this request. The body also carries quota. Stop. Ask for a rotated key. A cheaper text request may still fit. - 403 `forbidden`: A key other than the creator's tried to edit or delete a custom formula. Use the key that created the formula. - 404 `not_found`: No endpoint at that path, no formula with that slug, or a custom id requested without a key. Check the path. Send a key to read a custom formula. - 409 `formula_limit_reached`: The key already owns 25 custom formulas. Delete one before creating another. - 413 `payload_too_large`: The body is over 4,400,000 bytes, or the decoded image is over 3 MiB (3,145,728 bytes). Downscale the image. 1024 px on the long side is plenty. - 500 `internal_error`: An unexpected fault on the server. Retry once after a short wait, then report the request_id. - 502 `upstream_error`: The scoring model call failed. Nothing is charged: the units are refunded. Retry with backoff. ## Formulas Send the slug as `formula`. Details for one formula: `GET https://mogger.dev/api/v1/formulas/{slug}`. ### Image formulas (send `image`) - [Jawline](https://mogger.dev/formulas/jawline): `jawline`, image input. Does the jaw draw one clean, defined line from ear to chin? - [Canthal Tilt](https://mogger.dev/formulas/canthal-tilt): `canthal-tilt`, image input. Do the outer corners of the eyes sit higher than the inner corners? - [Hunter Eyes](https://mogger.dev/formulas/hunter-eyes): `hunter-eyes`, image input. Deep-set, hooded, horizontal eyes under a low, straight brow. - [Hairline](https://mogger.dev/formulas/hairline): `hairline`, image input. A low, straight, dense hairline with no retreat at the temples. - [Skin](https://mogger.dev/formulas/skin): `skin`, image input. Clear, even, smooth facial skin with a healthy finish. - [Overall Face](https://mogger.dev/formulas/overall-face): `overall-face`, image input. The whole face, judged at once: structure, proportion, and harmony. - [Fit Check](https://mogger.dev/formulas/fit-check): `fit-check`, image input. Does the outfit fit, hold together, and look deliberate? - [Physique](https://mogger.dev/formulas/physique): `physique`, image input. Muscle, leanness, and proportion, judged on what the frame shows. ### Text formulas (send `text`) - [Bio Mog](https://mogger.dev/formulas/bio-mog): `bio-mog`, text input. Does a profile bio give a stranger a reason to care in one read? - [Tweet Mog](https://mogger.dev/formulas/tweet-mog): `tweet-mog`, text input. Would this single post stop the scroll and earn the repost? - [Resume Mog](https://mogger.dev/formulas/resume-mog): `resume-mog`, text input. Would a hiring manager stop skimming and book the interview? - [Codebase Mog](https://mogger.dev/formulas/codebase-mog): `codebase-mog`, text input. Would a senior engineer read this code and merge it as is? ## Custom formulas Any valid key can capture a preference as its own formula and call it by id. Creating, editing, listing, and deleting cost 0 units. Scoring costs the same as a built-in formula and bills the caller's key. - `POST https://mogger.dev/api/v1/formulas` creates one. Body: `title` (1 to 80 characters, display only, never sent to the model), `prompt` (10 to 2,000 characters, one absolute yes or no question about one input), `input` (`text` or `image`), optional `criteria` (`{ "true": "...", "false": "..." }`, each up to 500 characters). Returns 201 with `id` (like `f_7Kq2xW9pLm`) and `url`. - `GET https://mogger.dev/api/v1/formulas/mine` lists the formulas your key created, newest first. - `GET https://mogger.dev/api/v1/formulas/{id}` needs a key. The creator sees `prompt` and `criteria` until the formula is locked. Other keys see `id`, `title`, `input`, `version`, and `url`. - `PATCH https://mogger.dev/api/v1/formulas/{id}` updates fields (creator only, otherwise 403 `forbidden`). Changing `prompt`, `input`, or `criteria` bumps `version`. A `title` edit does not. - `DELETE https://mogger.dev/api/v1/formulas/{id}` deletes it for good (creator only). Returns `{ "id": "...", "deleted": true }`. - `POST https://mogger.dev/api/v1/formulas/{id}/lock` locks it for good (creator only, no body, idempotent). After that no response returns `prompt` or `criteria`, not even to the creator, only `title` can change, and scoring by id keeps working. Every custom formula view carries `locked` and `locked_at`. - Score it with `POST https://mogger.dev/api/v1/mog/{id}`, or put the id in `formula` or `formulas` next to built-in formulas of the same input type (8 at most, charged once). - A key can own 25 custom formulas (409 `formula_limit_reached`). Custom formulas are unlisted. The id works as a capability: anyone holding it can score with it on their own key. Rotating a key keeps ownership. - The global pass/fail boundary applies to custom formulas. Creators never see or set it. ## Install for your harness One command installs the Mogger skill for Claude Code and Codex and saves your key: ```bash curl -fsSL https://mogger.dev/install.sh | sh ``` Manual install: download [SKILL.md](https://mogger.dev/skills/mogger/SKILL.md) to `~/.claude/skills/mogger/SKILL.md` or `~/.codex/skills/mogger/SKILL.md`, then set `MOGGER_API_KEY`. The skill also reads the key from `${XDG_CONFIG_HOME:-$HOME/.config}/mogger/key`. Never print the key or paste it into chat. ## Get a key Keys are invite only. The human you work for can request one by email: keys@mogger.dev. A key is `mog_` plus 32 letters and digits. Mogger stores only its hash and shows the key once, so a lost key is replaced, not recovered. ## Optional - [llms.txt](https://mogger.dev/llms.txt), [ai.txt](https://mogger.dev/ai.txt), [si.txt](https://mogger.dev/si.txt): this file, byte for byte - [Example image credits](https://mogger.dev/examples/ATTRIBUTION.md): sources and licenses for the demo images