{
  "$schema": "schema.ts",
  "version": "1",
  "generatedAt": "2026-09-02T22:23:35.396Z",
  "site": {
    "name": "mothermachine",
    "slogan": "Ninety percent built. Ten percent yours.",
    "description": "A directory of apps built with AI, each wired to its GitHub source. Every listing says what it runs on, what it needs, and what to change to make it yours.",
    "baseUrl": null,
    "notes": "URLs are relative to the site root until a domain is set. Keys are never stored; listings hold env var names only."
  },
  "vocabulary": {
    "formFactor": {
      "definition": "What the thing is. Filter on this first.",
      "values": {
        "web-app": {
          "label": "Web app"
        },
        "cli": {
          "label": "CLI"
        },
        "api": {
          "label": "API / service"
        },
        "library": {
          "label": "Library"
        },
        "desktop": {
          "label": "Desktop app"
        },
        "mobile": {
          "label": "Mobile app"
        },
        "skill": {
          "label": "Skill"
        },
        "mcp-server": {
          "label": "MCP server"
        },
        "agent": {
          "label": "Agent"
        },
        "workflow": {
          "label": "Workflow"
        },
        "extension": {
          "label": "Extension"
        }
      }
    },
    "executionModel": {
      "definition": "Whether a model runs at runtime. deterministic: no model. ai-inferential: a model is called open-endedly. hybrid: fixed orchestration with a model doing bounded work (most skills and agents).",
      "values": {
        "deterministic": {
          "label": "Deterministic"
        },
        "ai-inferential": {
          "label": "AI inferential"
        },
        "hybrid": {
          "label": "Hybrid"
        }
      }
    },
    "provenance": {
      "definition": "How the code was written. Recorded, never used for sorting.",
      "values": {
        "vibe-coded": {
          "label": "Vibe-coded"
        },
        "human-written": {
          "label": "Human-written"
        },
        "mixed": {
          "label": "Mixed"
        }
      }
    },
    "tier": {
      "definition": "open-source: anyone can list a public repo and the repo's license governs. paid: sold by the verified repo owner.",
      "values": {
        "open-source": {
          "label": "Open source"
        },
        "paid": {
          "label": "Paid"
        }
      }
    },
    "effort": {
      "definition": "How much work it is to make the app yours. config-only: set env vars, config or prompt files. light-edit: small code edits in named files. fork-and-modify: a starter kit; expect real changes.",
      "values": {
        "config-only": {
          "label": "Config only",
          "order": 0
        },
        "light-edit": {
          "label": "Light edit",
          "order": 1
        },
        "fork-and-modify": {
          "label": "Fork and modify",
          "order": 2
        }
      }
    },
    "distKind": {
      "definition": "How you get it. source: clone the repo. binary: download a build. container: pull an image. one-click: deploy to a host. hosted: use a running instance. installable: run an install command.",
      "values": {
        "source": {
          "label": "Clone source"
        },
        "binary": {
          "label": "Download"
        },
        "container": {
          "label": "Pull image"
        },
        "one-click": {
          "label": "Deploy"
        },
        "hosted": {
          "label": "Open app"
        },
        "installable": {
          "label": "Install"
        }
      }
    }
  },
  "count": 8,
  "listings": [
    {
      "id": "quill-mcp",
      "slug": "quill-mcp",
      "url": "app.html?slug=quill-mcp",
      "name": "Quill MCP",
      "tagline": "MCP server that gives an agent read/write access to a local notes folder.",
      "description": "Exposes create, search, and update tools over a directory of markdown notes. Fixed tool surface; the model decides what to write, the server decides what's allowed.",
      "tier": "open-source",
      "ownerVerified": true,
      "capabilities": [
        "adaptable"
      ],
      "gotchas": [],
      "formFactor": {
        "value": "mcp-server",
        "source": "detected",
        "confirmed": false,
        "evidence": "found mcp.json and @modelcontextprotocol/sdk in package.json"
      },
      "executionModel": {
        "value": "hybrid",
        "source": "detected",
        "confirmed": false,
        "evidence": "MCP tool surface with no model calls of its own"
      },
      "provenance": {
        "value": "vibe-coded",
        "source": "submitter",
        "confirmed": false
      },
      "codeStack": {
        "value": {
          "languages": [
            "TypeScript"
          ],
          "frameworks": [
            "@modelcontextprotocol/sdk"
          ],
          "packageManager": "pnpm"
        },
        "source": "submitter",
        "confirmed": false
      },
      "modelStack": {
        "value": {
          "providers": [
            "any MCP client"
          ],
          "requiredKeys": [],
          "tools": [
            "notes.create",
            "notes.search",
            "notes.update"
          ]
        },
        "source": "submitter",
        "confirmed": false
      },
      "repos": [
        {
          "id": "example/quill-mcp",
          "defaultBranch": "main",
          "url": "https://github.com/example/quill-mcp",
          "owner": "example",
          "name": "quill-mcp",
          "license": "MIT",
          "stars": 412,
          "lastCommit": "2026-08-19"
        }
      ],
      "distributions": [
        {
          "kind": "installable",
          "command": "npx quill-mcp --dir ~/notes"
        },
        {
          "kind": "source",
          "repoId": "example/quill-mcp"
        }
      ],
      "customization": {
        "summary": "Point it at a different folder with --dir. Tool names and the allow-list of subfolders live in config.json. No model choice to make; your MCP client brings the model.",
        "envVars": [],
        "configFiles": [
          "config.json"
        ],
        "promptFiles": [],
        "effort": "config-only",
        "editCount": 1
      },
      "useWhen": [
        "you want an agent to read and write your markdown notes",
        "you keep notes in a folder, not an app"
      ],
      "accounts": [],
      "updatedAt": "2026-08-19"
    },
    {
      "id": "ledgerline",
      "slug": "ledgerline",
      "url": "app.html?slug=ledgerline",
      "name": "Ledgerline",
      "tagline": "Personal finance dashboard that reads CSV bank exports.",
      "description": "Drop in exported statements, get categorised spend, monthly trends, and a budget view. Runs entirely in the browser; nothing leaves your machine.",
      "tier": "open-source",
      "ownerVerified": false,
      "capabilities": [
        "adaptable"
      ],
      "gotchas": [],
      "formFactor": {
        "value": "web-app",
        "source": "detected",
        "confirmed": false,
        "evidence": "next.config.js present"
      },
      "executionModel": {
        "value": "deterministic",
        "source": "detected",
        "confirmed": false,
        "evidence": "no model SDK in dependencies"
      },
      "provenance": {
        "value": "vibe-coded",
        "source": "submitter",
        "confirmed": false
      },
      "codeStack": {
        "value": {
          "languages": [
            "TypeScript"
          ],
          "frameworks": [
            "Next.js",
            "Tailwind"
          ],
          "packageManager": "npm",
          "database": [
            "IndexedDB"
          ],
          "hostingTarget": [
            "Vercel"
          ]
        },
        "source": "submitter",
        "confirmed": false
      },
      "repos": [
        {
          "id": "example/ledgerline",
          "defaultBranch": "main",
          "url": "https://github.com/example/ledgerline",
          "owner": "example",
          "name": "ledgerline",
          "license": "Apache-2.0",
          "stars": 1290,
          "lastCommit": "2026-08-28"
        }
      ],
      "distributions": [
        {
          "kind": "one-click",
          "provider": "vercel",
          "url": "https://vercel.com/new"
        },
        {
          "kind": "hosted",
          "url": "https://ledgerline.example"
        },
        {
          "kind": "source",
          "repoId": "example/ledgerline"
        }
      ],
      "customization": {
        "summary": "Category rules are a plain JSON map in lib/categories.json. Bank formats are parsers in lib/parsers; add one file per bank.",
        "envVars": [],
        "configFiles": [
          "lib/categories.json"
        ],
        "promptFiles": [],
        "effort": "light-edit",
        "editCount": 1
      },
      "useWhen": [
        "you export CSV statements from your bank",
        "you want spending categories without handing a service your logins"
      ],
      "accounts": [],
      "updatedAt": "2026-08-28"
    },
    {
      "id": "briefcase",
      "slug": "briefcase",
      "url": "app.html?slug=briefcase",
      "name": "Briefcase",
      "tagline": "Turns a folder of contracts into a searchable clause index.",
      "description": "Chunks PDFs, extracts clauses with a model, stores embeddings locally, and gives you a search UI. Extraction prompts are versioned and editable.",
      "tier": "paid",
      "ownerVerified": true,
      "capabilities": [
        "adaptable"
      ],
      "gotchas": [],
      "price": {
        "amount": 49,
        "currency": "USD",
        "deliverable": "private-repo"
      },
      "formFactor": {
        "value": "desktop",
        "source": "detected",
        "confirmed": false,
        "evidence": "tauri.conf.json present"
      },
      "executionModel": {
        "value": "ai-inferential",
        "source": "detected",
        "confirmed": false,
        "evidence": "@anthropic-ai/sdk imported in src/extract.ts"
      },
      "provenance": {
        "value": "mixed",
        "source": "submitter",
        "confirmed": false
      },
      "codeStack": {
        "value": {
          "languages": [
            "TypeScript",
            "Rust"
          ],
          "frameworks": [
            "Tauri",
            "React"
          ],
          "packageManager": "pnpm",
          "database": [
            "SQLite"
          ]
        },
        "source": "submitter",
        "confirmed": false
      },
      "modelStack": {
        "value": {
          "providers": [
            "anthropic"
          ],
          "models": [
            "claude-sonnet-4-6"
          ],
          "requiredKeys": [
            "ANTHROPIC_API_KEY"
          ],
          "promptLocations": [
            "src/prompts/"
          ]
        },
        "source": "submitter",
        "confirmed": false
      },
      "repos": [
        {
          "id": "example/briefcase",
          "defaultBranch": "main",
          "url": "https://github.com/example/briefcase",
          "owner": "example",
          "name": "briefcase",
          "license": "Proprietary",
          "stars": null,
          "lastCommit": "2026-08-30"
        }
      ],
      "distributions": [
        {
          "kind": "binary",
          "platform": "macos",
          "url": "https://github.com/example/briefcase/releases/latest",
          "signed": true
        },
        {
          "kind": "binary",
          "platform": "windows",
          "url": "https://github.com/example/briefcase/releases/latest",
          "signed": false
        }
      ],
      "customization": {
        "summary": "Swap the model in src/config.ts. Every extraction prompt is a markdown file in src/prompts and hot-reloads in dev. The clause taxonomy is a YAML file you can extend.",
        "envVars": [
          "ANTHROPIC_API_KEY"
        ],
        "configFiles": [
          "src/config.ts",
          "taxonomy.yaml"
        ],
        "promptFiles": [
          "src/prompts/*.md"
        ],
        "effort": "light-edit",
        "editCount": 4
      },
      "useWhen": [
        "you have a folder of PDF contracts to search by clause",
        "you need clause extraction you can audit and edit"
      ],
      "accounts": [
        "Anthropic API"
      ],
      "updatedAt": "2026-08-30"
    },
    {
      "id": "changelog-skill",
      "slug": "changelog-skill",
      "url": "app.html?slug=changelog-skill",
      "name": "Changelog skill",
      "tagline": "A Claude skill that drafts release notes from merged PRs.",
      "description": "Reads PR titles and bodies since the last tag, groups them, writes a changelog in your house style. Style rules live in SKILL.md.",
      "tier": "open-source",
      "ownerVerified": true,
      "capabilities": [
        "adaptable"
      ],
      "gotchas": [],
      "formFactor": {
        "value": "skill",
        "source": "detected",
        "confirmed": false,
        "evidence": "SKILL.md at repo root"
      },
      "executionModel": {
        "value": "hybrid",
        "source": "detected",
        "confirmed": false,
        "evidence": "script fetches, model writes"
      },
      "provenance": {
        "value": "vibe-coded",
        "source": "submitter",
        "confirmed": false
      },
      "codeStack": {
        "value": {
          "languages": [
            "Markdown",
            "Python"
          ],
          "frameworks": [],
          "packageManager": "none"
        },
        "source": "submitter",
        "confirmed": false
      },
      "modelStack": {
        "value": {
          "providers": [
            "anthropic"
          ],
          "requiredKeys": [
            "GITHUB_TOKEN"
          ],
          "promptLocations": [
            "SKILL.md"
          ]
        },
        "source": "submitter",
        "confirmed": false
      },
      "repos": [
        {
          "id": "example/changelog-skill",
          "defaultBranch": "main",
          "url": "https://github.com/example/changelog-skill",
          "owner": "example",
          "name": "changelog-skill",
          "license": "MIT",
          "stars": 230,
          "lastCommit": "2026-07-11"
        }
      ],
      "distributions": [
        {
          "kind": "installable",
          "command": "npx skills add example/changelog-skill"
        },
        {
          "kind": "source",
          "repoId": "example/changelog-skill"
        }
      ],
      "customization": {
        "summary": "Edit the style section of SKILL.md. That's it. The PR-fetching script is deterministic and rarely needs touching.",
        "envVars": [
          "GITHUB_TOKEN"
        ],
        "configFiles": [],
        "promptFiles": [
          "SKILL.md"
        ],
        "effort": "config-only",
        "editCount": 2
      },
      "useWhen": [
        "you write release notes from merged pull requests",
        "you want a house style enforced automatically"
      ],
      "accounts": [
        "GitHub"
      ],
      "updatedAt": "2026-07-11"
    },
    {
      "id": "tidyshot",
      "slug": "tidyshot",
      "url": "app.html?slug=tidyshot",
      "name": "Tidyshot",
      "tagline": "CLI that renames and sorts screenshots by what's in them.",
      "description": "Runs a local vision model over your screenshots folder and files them by app, date, and content. No API key needed.",
      "tier": "open-source",
      "ownerVerified": false,
      "capabilities": [
        "adaptable"
      ],
      "gotchas": [],
      "formFactor": {
        "value": "cli",
        "source": "detected",
        "confirmed": false,
        "evidence": "typer entry point in pyproject.toml"
      },
      "executionModel": {
        "value": "ai-inferential",
        "source": "detected",
        "confirmed": false,
        "evidence": "transformers pipeline in classify.py"
      },
      "provenance": {
        "value": "vibe-coded",
        "source": "submitter",
        "confirmed": false
      },
      "codeStack": {
        "value": {
          "languages": [
            "Python"
          ],
          "frameworks": [
            "Typer"
          ],
          "packageManager": "uv"
        },
        "source": "submitter",
        "confirmed": false
      },
      "modelStack": {
        "value": {
          "providers": [
            "local"
          ],
          "models": [
            "moondream2"
          ],
          "requiredKeys": []
        },
        "source": "submitter",
        "confirmed": false
      },
      "repos": [
        {
          "id": "example/tidyshot",
          "defaultBranch": "main",
          "url": "https://github.com/example/tidyshot",
          "owner": "example",
          "name": "tidyshot",
          "license": "MIT",
          "stars": 88,
          "lastCommit": "2026-06-02"
        }
      ],
      "distributions": [
        {
          "kind": "installable",
          "command": "uvx tidyshot ~/Desktop"
        },
        {
          "kind": "source",
          "repoId": "example/tidyshot"
        }
      ],
      "customization": {
        "summary": "Naming template and folder rules are in tidyshot.toml. To use a hosted model instead of local, set provider in the same file and add a key.",
        "envVars": [],
        "configFiles": [
          "tidyshot.toml"
        ],
        "promptFiles": [
          "tidyshot/prompt.txt"
        ],
        "effort": "config-only",
        "editCount": 2
      },
      "useWhen": [
        "your screenshots folder is a mess",
        "you want files named by what's in them, offline"
      ],
      "accounts": [],
      "updatedAt": "2026-06-02"
    },
    {
      "id": "gatekeep",
      "slug": "gatekeep",
      "url": "app.html?slug=gatekeep",
      "name": "Gatekeep",
      "tagline": "Docker image that puts a signup form and rate limit in front of any API.",
      "description": "Reverse proxy with API keys, quotas, and a tiny admin page. Point it at your upstream and ship.",
      "tier": "open-source",
      "ownerVerified": true,
      "capabilities": [
        "adaptable"
      ],
      "gotchas": [],
      "formFactor": {
        "value": "api",
        "source": "detected",
        "confirmed": false,
        "evidence": "Dockerfile and HTTP handlers, no UI beyond /admin"
      },
      "executionModel": {
        "value": "deterministic",
        "source": "detected",
        "confirmed": false,
        "evidence": "no model SDK in go.mod"
      },
      "provenance": {
        "value": "human-written",
        "source": "submitter",
        "confirmed": false
      },
      "codeStack": {
        "value": {
          "languages": [
            "Go"
          ],
          "frameworks": [],
          "packageManager": "go mod",
          "database": [
            "SQLite"
          ],
          "hostingTarget": [
            "Docker"
          ]
        },
        "source": "submitter",
        "confirmed": false
      },
      "repos": [
        {
          "id": "example/gatekeep",
          "defaultBranch": "main",
          "url": "https://github.com/example/gatekeep",
          "owner": "example",
          "name": "gatekeep",
          "license": "MIT",
          "stars": 2040,
          "lastCommit": "2026-08-25"
        }
      ],
      "distributions": [
        {
          "kind": "container",
          "image": "ghcr.io/example/gatekeep:latest"
        },
        {
          "kind": "source",
          "repoId": "example/gatekeep"
        }
      ],
      "customization": {
        "summary": "All settings are environment variables. Quota tiers are a JSON blob in one of them.",
        "envVars": [
          "UPSTREAM_URL",
          "ADMIN_TOKEN",
          "QUOTAS_JSON"
        ],
        "configFiles": [],
        "promptFiles": [],
        "effort": "config-only",
        "editCount": 3
      },
      "useWhen": [
        "you need API keys and rate limits in front of an existing API",
        "you want a signup form without building auth"
      ],
      "accounts": [],
      "updatedAt": "2026-08-25"
    },
    {
      "id": "roster-agent",
      "slug": "roster-agent",
      "url": "app.html?slug=roster-agent",
      "name": "Roster agent",
      "tagline": "Agent that fills shift gaps by texting a staff list.",
      "description": "Watches a schedule sheet, finds open shifts, messages eligible staff in order, and confirms the first yes. Escalation rules are deterministic; the wording is the model's.",
      "tier": "open-source",
      "ownerVerified": false,
      "capabilities": [
        "adaptable"
      ],
      "gotchas": [],
      "formFactor": {
        "value": "agent",
        "source": "detected",
        "confirmed": false,
        "evidence": "long-running loop with tool calls in agent/loop.py"
      },
      "executionModel": {
        "value": "hybrid",
        "source": "detected",
        "confirmed": false,
        "evidence": "rules.py gates every model action"
      },
      "provenance": {
        "value": "vibe-coded",
        "source": "submitter",
        "confirmed": false
      },
      "codeStack": {
        "value": {
          "languages": [
            "Python"
          ],
          "frameworks": [
            "FastAPI"
          ],
          "packageManager": "uv",
          "database": [
            "Postgres"
          ],
          "hostingTarget": [
            "Railway"
          ]
        },
        "source": "submitter",
        "confirmed": false
      },
      "modelStack": {
        "value": {
          "providers": [
            "openai",
            "anthropic"
          ],
          "requiredKeys": [
            "OPENAI_API_KEY",
            "TWILIO_SID",
            "TWILIO_TOKEN"
          ],
          "promptLocations": [
            "agent/prompts/"
          ],
          "tools": [
            "sheet.read",
            "sms.send",
            "sms.wait"
          ]
        },
        "source": "submitter",
        "confirmed": false
      },
      "repos": [
        {
          "id": "example/roster-agent",
          "defaultBranch": "main",
          "url": "https://github.com/example/roster-agent",
          "owner": "example",
          "name": "roster-agent",
          "license": "AGPL-3.0",
          "stars": 156,
          "lastCommit": "2026-08-14"
        }
      ],
      "distributions": [
        {
          "kind": "one-click",
          "provider": "railway",
          "url": "https://railway.app/new"
        },
        {
          "kind": "source",
          "repoId": "example/roster-agent"
        }
      ],
      "customization": {
        "summary": "Eligibility and escalation order are Python in agent/rules.py and worth reading before you deploy. Message tone is in agent/prompts. Sheet columns are mapped in config.yaml.",
        "envVars": [
          "OPENAI_API_KEY",
          "TWILIO_SID",
          "TWILIO_TOKEN"
        ],
        "configFiles": [
          "config.yaml",
          "agent/rules.py"
        ],
        "promptFiles": [
          "agent/prompts/*.md"
        ],
        "effort": "fork-and-modify",
        "editCount": 6
      },
      "useWhen": [
        "you fill open shifts by texting staff",
        "your schedule lives in a spreadsheet"
      ],
      "accounts": [
        "OpenAI API",
        "Twilio"
      ],
      "updatedAt": "2026-08-14"
    },
    {
      "id": "hushlink",
      "slug": "hushlink",
      "url": "app.html?slug=hushlink",
      "name": "Hushlink",
      "tagline": "Chrome extension that strips tracking parameters from links you copy.",
      "description": "Cleans utm_ and friends on copy, with a per-site allow-list. Nothing phones home.",
      "tier": "open-source",
      "ownerVerified": true,
      "capabilities": [
        "adaptable"
      ],
      "gotchas": [],
      "formFactor": {
        "value": "extension",
        "source": "detected",
        "confirmed": false,
        "evidence": "manifest.json with manifest_version 3"
      },
      "executionModel": {
        "value": "deterministic",
        "source": "detected",
        "confirmed": false,
        "evidence": "no network calls"
      },
      "provenance": {
        "value": "vibe-coded",
        "source": "submitter",
        "confirmed": false
      },
      "codeStack": {
        "value": {
          "languages": [
            "JavaScript"
          ],
          "frameworks": [
            "Manifest V3"
          ],
          "packageManager": "none"
        },
        "source": "submitter",
        "confirmed": false
      },
      "repos": [
        {
          "id": "example/hushlink",
          "defaultBranch": "main",
          "url": "https://github.com/example/hushlink",
          "owner": "example",
          "name": "hushlink",
          "license": "MIT",
          "stars": 610,
          "lastCommit": "2026-05-20"
        }
      ],
      "distributions": [
        {
          "kind": "hosted",
          "url": "https://chromewebstore.google.com"
        },
        {
          "kind": "source",
          "repoId": "example/hushlink"
        }
      ],
      "customization": {
        "summary": "The parameter list is one array at the top of clean.js.",
        "envVars": [],
        "configFiles": [
          "clean.js"
        ],
        "promptFiles": [],
        "effort": "config-only",
        "editCount": 1
      },
      "useWhen": [
        "you copy links and don't want tracking parameters along for the ride",
        "you want a per-site allow-list"
      ],
      "accounts": [],
      "updatedAt": "2026-05-20"
    }
  ]
}
