)]}'
{
  "log": [
    {
      "commit": "a04fecf66f900bcd7936f25e7862b594c7abb578",
      "tree": "efa578043f5edb3c87cfd1268cd37d03696d212e",
      "parents": [
        "aa2b1271740563b956184c001882eb2dae771431"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 15 23:45:26 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 15 23:45:26 2026 -0500"
      },
      "message": "Add GPU-box hosting tree for Vast vLLM fleet.\n\nStock Vast vLLM image plus pinned on-start: fetch servers.yaml from\nasfquart and launch vllm serve. Runbooks live next to scripts under\nhosting/. Control-plane config endpoint is still to come.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "aa2b1271740563b956184c001882eb2dae771431",
      "tree": "025f552fe04b804b1a75eb6f5e399e3d932f5be6",
      "parents": [
        "bef7b36684b8e5419df24f99619c212037f5dda7"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 15 22:26:09 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 15 22:26:09 2026 -0500"
      },
      "message": "Initial draft of multi-vLLM architecture.\n\nRun many vLLMs on many instances. Configuration dynamically fetched\nfrom the LLMAO instance/server.\n\nCo-Authored-By: Claude Sonnet 5\n"
    },
    {
      "commit": "bef7b36684b8e5419df24f99619c212037f5dda7",
      "tree": "a9f277c84a096ed2614c4d881b13fe26a112d8e7",
      "parents": [
        "9b06fd1fdd4d625d622469a18ab8a2259826c752"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Thu Aug 13 03:31:14 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Thu Aug 13 03:31:14 2026 -0500"
      },
      "message": "Replace invented budget_type with team grantor.\n\nGrantor is who authorized the project dollar ceiling (LDAP remains SoT\nfor the project itself). First cfg default is Free Tier, stored on the\nLiteLLM team as metadata.grantor (teams accept metadata like keys).\nProjects list shows Grantor instead of Type/unknown.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "9b06fd1fdd4d625d622469a18ab8a2259826c752",
      "tree": "a6e932a6c8465781660a2c64a341ace7135e7d8e",
      "parents": [
        "467bd3dcb8835df7bc059ce3d9c476815982acae"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 19:48:16 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 19:48:16 2026 -0500"
      },
      "message": "Fold GET chrome into @page(title\u003d) and inject result.\n\nHandlers no longer call basic_info or set a static title. The decorator\nbuilds basic_info(title), passes result\u003d into the view, reuses that\nobject on Authz/backend errors, and attaches flashes last.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "467bd3dcb8835df7bc059ce3d9c476815982acae",
      "tree": "0ba9e021ba1bc51f91296606543267ef4a6a8f1e",
      "parents": [
        "29a76e2ea16d15fcdca9f5817013790c9a41fd86"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 19:06:58 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 19:06:58 2026 -0500"
      },
      "message": "Raise AuthzError from current_identity when unsigned.\n\nCallers sat behind @require and still asserted ident is not None.\nMissing session is now AuthzError so page_errors and API 403 paths\nhandle it without per-site asserts.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "29a76e2ea16d15fcdca9f5817013790c9a41fd86",
      "tree": "dc31a4bafb9ebabb36e2596379ddfd509eb42495",
      "parents": [
        "763bfb9c58bf0a1e76c1b1b91cd595b2ff0604b5"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 18:55:44 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 18:55:44 2026 -0500"
      },
      "message": "Show GET page errors as flashes via page_errors.\n\nbasic_info no longer drains Quart flashes up front, so a flash() after\nthat call (including from the decorator) is still visible: page_errors\ncatches AuthzError/BackendUnavailable, flashes, then attaches messages\nimmediately before use_template renders. Drop result.error and the\nper-template error alerts; policy denials raise AuthzError.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "763bfb9c58bf0a1e76c1b1b91cd595b2ff0604b5",
      "tree": "1b60bf0cdb13ce0224408634998379a407592eb3",
      "parents": [
        "2f278e6703b357f1dc0b7470cb4e2c581cfd142a"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 18:14:06 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 18:14:06 2026 -0500"
      },
      "message": "Improve the flash box when a key is created. Focus on the key itself,\nmove details to lower addenda. Remove the \"Create Another\" since we\nnow use a Flash on a page where \"Create\" is present. Add a [Copy]\nbutton, with auto-dismiss popup text.\n\nDesigned-with: Claude Sonnet 5\n"
    },
    {
      "commit": "2f278e6703b357f1dc0b7470cb4e2c581cfd142a",
      "tree": "bb5110e305cd8869a2255583bc6b4a10e3b77308",
      "parents": [
        "30eef4c66a4c78c1ba76bf0f16c92db84bb3a6e9"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 17:21:52 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 17:21:52 2026 -0500"
      },
      "message": "Pass EZT booleans via ezt.boolean() so if-any works.\n\nEZT stringifies values for [if-any]; False becomes \"False\", which is\nnon-empty, so personal key flashes always showed automation copy\n(Created by / teammate blurb). ezt.boolean() yields \"yes\" or None.\nSame wrapping for other template flags (steward, automation nav, models).\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "30eef4c66a4c78c1ba76bf0f16c92db84bb3a6e9",
      "tree": "0786c49c3994ddd81a911018320ba764e1c0f3ef",
      "parents": [
        "b767dddc21c0063eb7cf6b0c292b627c7067e722"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 17:12:15 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 17:12:15 2026 -0500"
      },
      "message": "Use STeVe-style POST /do-* actions with 303 redirects.\n\nMutations no longer return HTML (address bar stayed on the POST URL).\nCreate/revoke are POST /do-create-key, /do-create-other-key, and\n/do-revoke-key, then 303 to a GET display. Status uses flash helpers;\nthe one-time PAT secret is a raw HTML flash from flash_key_created.ezt\n(alert-warning, not alert-raw).\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "b767dddc21c0063eb7cf6b0c292b627c7067e722",
      "tree": "da8bdf79d684c8dae4d0fc9803d0df7ae581ec43",
      "parents": [
        "31c3ba7e295996369ba3adca6ae9de8ef5ade2a2"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 16:18:44 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Aug 12 16:18:44 2026 -0500"
      },
      "message": "Replace image in navbar with llmao-logo.svg\n\naccidental test/change slipped in. Revert."
    },
    {
      "commit": "31c3ba7e295996369ba3adca6ae9de8ef5ade2a2",
      "tree": "e6758c83f38d4cc084d51bc30f3b3489482be657",
      "parents": [
        "d6f7fe17772468d560bdd486a31bf3d1acdfe750"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 16:15:28 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 16:15:28 2026 -0500"
      },
      "message": "Add Projects list page and member-gated stub.\n\nShow /projects from list_projects_for (used, budget, %, steward vs\nmember) and link to a stub /projects/\u003cname\u003e until the overview ships.\nNavbar includes Projects. Brand image is static/image.png.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "d6f7fe17772468d560bdd486a31bf3d1acdfe750",
      "tree": "0c48c7177667a8c1a3a9a6df9b7c5c047232a30b",
      "parents": [
        "d6b7f38b653944c8aedbfc132400ee4a74df2314"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 14:40:56 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 14:40:56 2026 -0500"
      },
      "message": "add clone commit hash into the footer, using dunamai\n"
    },
    {
      "commit": "d6b7f38b653944c8aedbfc132400ee4a74df2314",
      "tree": "6001a4ac58ec95e598fb517da794f7a8efdbb587",
      "parents": [
        "a6cac0cd2f9d830476b576e8929c908cf3063ca5"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 00:01:29 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 12 00:01:29 2026 -0500"
      },
      "message": "source to create favicon.ico\n"
    },
    {
      "commit": "a6cac0cd2f9d830476b576e8929c908cf3063ca5",
      "tree": "b1048233f806fa60c426622539adafad324af9f7",
      "parents": [
        "e8cb1c21e4957dc830b9b097cafa9f1ede1b3e37"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 23:58:34 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 23:58:34 2026 -0500"
      },
      "message": "Use brand logo in navbar with dark grey bar.\n\nReplace the CPU icon with llmao-logo.svg and use #343a40 so the\nlogo disc edge stays visible; brighten nav link colors slightly.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "e8cb1c21e4957dc830b9b097cafa9f1ede1b3e37",
      "tree": "ad0a28a5184f7210884d0fdcbcf187621c3d5e8d",
      "parents": [
        "9c64a49c4d633d539c9725c3604655e9182e5876"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 23:28:53 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 23:28:53 2026 -0500"
      },
      "message": "update the favicon\n"
    },
    {
      "commit": "9c64a49c4d633d539c9725c3604655e9182e5876",
      "tree": "cff356e98c70e5cd2c1f63343a41f91164283229",
      "parents": [
        "a568cba97ec13f944baa1dbdcc7aa27df589fc3c"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 22:51:36 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 22:51:36 2026 -0500"
      },
      "message": "Add P0.1 project budget seam (list + overview, no HTML).\n\nExpose list_projects_for and project_overview with people vs automation\nspend from keys; ensure_team on list/overview so project budgets always\nexist. budget_duration is required via cfg fallback; budget_type unknown\nis provisional.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "a568cba97ec13f944baa1dbdcc7aa27df589fc3c",
      "tree": "936cc35409f3a8ef82bc49dfc55bb82d460c805c",
      "parents": [
        "59d4b08296dc4c8705827a66925041bac669df74"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 18:52:24 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 18:52:24 2026 -0500"
      },
      "message": "Document project-centered product path and doc split.\n\nPoint README at how-to only; put phased UX backlog (Projects, budgets,\nhome signals, reports) in STATUS; keep product concepts in rai-private\ndesign. Thin “done” so STATUS tracks planned work, not a code mirror.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "59d4b08296dc4c8705827a66925041bac669df74",
      "tree": "1e67c6600dee4396ef7e111392904e9e8cd6a453",
      "parents": [
        "46c32bb94b73ff58a11bdcdf3cea427aa538b02a"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 15:27:56 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 15:27:56 2026 -0500"
      },
      "message": "Fix Models detail modal empty fields from multiline notes.\n\nCollapse free-text to one line for HTML data-* attributes so EZT/HTML\nescaping can keep attributes intact. Simplify hosting_label to use the\nredacted row; harden boolean data-attribute checks in JS.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "46c32bb94b73ff58a11bdcdf3cea427aa538b02a",
      "tree": "4c4ff6223146bd604555e82d967f1ce6d36ddcd2",
      "parents": [
        "83c68ad8d58921708e9725e4cd73710e564d9bb9"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 11:40:16 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 11:40:16 2026 -0500"
      },
      "message": "Add Models page with inventory table and detail modal.\n\nShow public model_list fields for signed-in users; redact supply-path\ndetails (weights, provider, provenance) for non-site-admins. Overview\ntable plus Bootstrap details modal; site admins see full public model_info.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "83c68ad8d58921708e9725e4cd73710e564d9bb9",
      "tree": "77bd8b0b32561748ad0f776217a9f2fc525e4cf9",
      "parents": [
        "5be037b0db584369241bc61e085837debf576b51"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 09:55:51 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 09:55:51 2026 -0500"
      },
      "message": "Store purpose in metadata.purpose, not key_alias.\n\nLiteLLM key_alias is globally unique, so free-text purposes like \"cron\"\ncannot live there. Purpose is optional (per design); omit key_alias on\ncreate and read purpose only from metadata.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "5be037b0db584369241bc61e085837debf576b51",
      "tree": "ce1cb089bbcb3309731ea84bf6d251e99b67f6ad",
      "parents": [
        "4cc30bff2824b49107fbb43299b430334bffda18"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 07:27:30 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 07:27:30 2026 -0500"
      },
      "message": "In-process team_id cache with fail-fast warm; drop StateStore.\n\nCache only project→team_id (immutable pair), fill at before_serving via\nteam/list. team_info uses team/info on cache hit or list-row data on miss.\nInstantiate LiteLLMBackend directly; remove disk state store and make_backend.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "4cc30bff2824b49107fbb43299b430334bffda18",
      "tree": "3745ca1e2eb55edeac7469ea89586fe943fdddbe",
      "parents": [
        "b51fff025d9c646d1e2a5c9715bf3a19c3f88dbf"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 06:37:12 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 06:37:12 2026 -0500"
      },
      "message": "Speak project in Backend API; hide LiteLLM team_id from Seam.\n\ncreate_key and list_keys take LDAP project names; LiteLLMBackend maps\nteam_alias to opaque team_id internally. MockBackend uses project as the\nteam identity. Drop ensure_project_team from the seam.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "b51fff025d9c646d1e2a5c9715bf3a19c3f88dbf",
      "tree": "46b6fbd2308a15a3249c8c3ac168450b28f637d9",
      "parents": [
        "f93a1a41bc3b0e288c2ee21bdf568151551ef38d"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 05:35:33 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 05:35:33 2026 -0500"
      },
      "message": "Use in-memory dict for MockBackend test state.\n\nDrop StateStore from the test double so offline tests do not touch disk.\nKeep product LiteLLMBackend on StateStore for the team-id cache only.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "f93a1a41bc3b0e288c2ee21bdf568151551ef38d",
      "tree": "a40b9c6ff7fe8c01ac6a2e54d4e828bd91230011",
      "parents": [
        "fbff4b1dcd4d5ff788605057c44fce9f9480ee90"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 04:54:18 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 04:54:18 2026 -0500"
      },
      "message": "Split PAT UX into My Keys and Other Keys.\n\nPersonal keys stay on /keys with a single list call. Automation keys move\nto /keys/other (PMC/site admin only), so normal page loads avoid N\nper-project queries. Separate create flows and after_path revoke redirects.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "fbff4b1dcd4d5ff788605057c44fce9f9480ee90",
      "tree": "02d9ddd9235483a4d2b3c8a72b59aeffbe4015f4",
      "parents": [
        "b1aee8b7c405ad660a8c1706de2dece59aa084ce"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 04:52:14 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Tue Aug 11 04:52:14 2026 -0500"
      },
      "message": "Tweak suppression of DEBUG messages\n"
    },
    {
      "commit": "b1aee8b7c405ad660a8c1706de2dece59aa084ce",
      "tree": "100e7a09c7809da9064c3bfab7cd7759dcb9cdb9",
      "parents": [
        "dac5ab73ee9d3d61ccddc0ad626d9729caa8c2f4"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Mon Aug 10 00:49:39 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Mon Aug 10 00:49:39 2026 -0500"
      },
      "message": "Record created_by on automation keys (who saw the secret).\n\nStore metadata.created_by as the ASF uid that minted the key, require it\nwhen user is null, and show Created by in the keys list so other PMCs know\nwho to ask for the secret.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "dac5ab73ee9d3d61ccddc0ad626d9729caa8c2f4",
      "tree": "edd8c8c16898af9b84c3323ea2a9acb24ac8a517",
      "parents": [
        "3c1be3be5860e0b2b74f3e642ae9cf0d85f715bd"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Mon Aug 10 00:29:23 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Mon Aug 10 00:29:23 2026 -0500"
      },
      "message": "Align KeyInfo with design PAT vocabulary (project, user, purpose).\n\nRename key fields to match §5.1: purpose (was key_alias), user (was\nuser_id), token_id (list/delete id, not the secret). Drop kind; automation\nis user is None. Map LiteLLM wire names only at the backend boundary.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "3c1be3be5860e0b2b74f3e642ae9cf0d85f715bd",
      "tree": "41b5b2a2197afe48f3751c6fc75c5cacc41882b1",
      "parents": [
        "3afbeb36546e752b93c5e71374f0667a3ee66cfc"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 23:47:35 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 23:47:35 2026 -0500"
      },
      "message": "Use metadata.project for key project labels (required).\n\nKeyInfo.project is the ASF LDAP name from metadata.project, always set on\ncreate. Stop falling back to team_id UUIDs in the keys UI; fail if project\nmetadata is missing.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "3afbeb36546e752b93c5e71374f0667a3ee66cfc",
      "tree": "b870ae7917f6fc7669606672258eac27facd2a23",
      "parents": [
        "f1d67b16a8eed9c3e7691ae8b09d350e565121d4"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 22:57:18 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 22:57:18 2026 -0500"
      },
      "message": "Remove litellm mock/proxy app mode; mock is tests-only.\n\nAlways construct LiteLLMBackend so local run matches production (LiteLLM +\nPostgres). Drop litellm.mode, require_proxy_mode, and UI mode gates. Move\nMockBackend to tests/mock_backend.py for offline seam tests only.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "f1d67b16a8eed9c3e7691ae8b09d350e565121d4",
      "tree": "fed7f40a910deac0a4cd5e05558b92d06c555a93",
      "parents": [
        "5a6fce2756a7dd721e6b2a69053fd0dd30656570"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 22:21:42 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 22:21:42 2026 -0500"
      },
      "message": "Gate seam methods with require_* decorators.\n\nReplace imperative require_proxy_mode/member/admin checks with module-level\ndecorators so policy lives on the method. Gate team_status with require_member\n(identity arg) so the budget API only calls seam and maps AuthzError.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "5a6fce2756a7dd721e6b2a69053fd0dd30656570",
      "tree": "75f48ec78d85484eef2f945ab25fe83c4408fffe",
      "parents": [
        "68af023187ab004e7270eedd1e79252bbcb5bd8d"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 12:01:25 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 12:01:25 2026 -0500"
      },
      "message": "Add team status email for post-import progress (4–9 Aug).\n\nPlain-text note for Tooling/RAI and bystanders: RAI framing, uv through\nPAT UX, multi-repo pointers, and open next steps. Ready to paste into mail.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "68af023187ab004e7270eedd1e79252bbcb5bd8d",
      "tree": "9185db27081dba948e77eb1b475d8eab2b006f7a",
      "parents": [
        "718cf607c6eecc3571f41a411c82464b0a88a74d"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 11:22:57 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 11:22:57 2026 -0500"
      },
      "message": "Note planned Models and Reports top-nav UX.\n\nRecord backlog for a user-scoped model browser and report surfaces\n(PMC by-user usage, self-hosted utilization, Board roll-ups, donated\ncredit burn-down, Commons abuse histograms). Not implemented yet.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "718cf607c6eecc3571f41a411c82464b0a88a74d",
      "tree": "ece6e43bf097e5eca9ced4ecf28085db4cf79e91",
      "parents": [
        "c76bc93f54b040e8d6eb508e2d48b6cef4c66280"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 10:20:37 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 10:20:37 2026 -0500"
      },
      "message": "Serve site favicon at /favicon.ico (STeVe-style).\n\nAdd static/favicon.ico and a dedicated route so browsers that request\n/favicon.ico get the asset without depending on static path rewriting.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "c76bc93f54b040e8d6eb508e2d48b6cef4c66280",
      "tree": "9beb66b1b6ffab68efdb6ffde51feec03a4c0495",
      "parents": [
        "2431e06c70b6ca760e0a5a81f421bbf5062ccd39"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 07:52:03 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 07:52:03 2026 -0500"
      },
      "message": "Document build status, edge cases, and high-level backlog.\n\nAdd docs/STATUS.md as the detailed status of record, slim the README to a\nsummary plus links, and point ARCHITECTURE at STATUS and open PAT policy.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "2431e06c70b6ca760e0a5a81f421bbf5062ccd39",
      "tree": "76b8adfdefa579c6768f9ad055858d9f96a72292",
      "parents": [
        "d9241b4f18ef81c58767afeb29976caa8c0557b5"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 07:16:55 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 07:16:55 2026 -0500"
      },
      "message": "Quiet noisy HTTP/async loggers in standalone mode.\n\nSet selector_events, hpack, httpcore.http11, sslproto, and asyncio to INFO\nso local runx output stays readable.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "d9241b4f18ef81c58767afeb29976caa8c0557b5",
      "tree": "df1dda122cedabd43c65106c49bf103a7ae801bd",
      "parents": [
        "26d73c8bd97fbf9ce00e0bd13a3460a528ea41c5"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 07:16:55 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sun Aug 09 07:16:55 2026 -0500"
      },
      "message": "Add PAT management UX against live LiteLLM virtual keys.\n\nExtend the async admin client and seam for list/create/revoke of personal\nkeys (user+team+purpose) and admin automation keys (team-only, purpose\nrequired). Team ensure no longer mints a product PAT. Ship EZT pages with\none-time secret display, spend/limit columns, and a revoke confirmation\nmodal.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "26d73c8bd97fbf9ce00e0bd13a3460a528ea41c5",
      "tree": "276363b56b20e137cf43b43314edc236e0308f9b",
      "parents": [
        "a6d49f31e5aa99aadcd77e77ff17bfa9079a7849"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 22:13:43 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 22:13:43 2026 -0500"
      },
      "message": "Add LiteLLM extra-proxy (prisma) and system Postgres setup script.\n\nDepend on litellm[proxy,extra-proxy] plus direct PyYAML and easydict. Add\nbin/setup_litellm_db.py for Ubuntu PostgreSQL: create role/db, generate a\npassword, prisma generate and db push against LiteLLM\u0027s schema. Document\nmake db before make proxy; no container-based DB path.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "a6d49f31e5aa99aadcd77e77ff17bfa9079a7849",
      "tree": "a2996666d97ae773940dc65ed3b8196b0786e303",
      "parents": [
        "0de2bdecfcce1aad8bd1e31e45669b3b4d5fbe36"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 21:34:12 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 21:34:12 2026 -0500"
      },
      "message": "Use model_list.yaml as the single model inventory (LiteLLM include).\n\nReplace catalog.py and the render script with a LiteLLM-native model list\nthat litellm.yaml includes and llmao loads for UX. Port gemma/qwen seed data\ninto model_list.yaml.example with flat model_info metadata; keep api_base\ncleartext and keys as placeholders for eyaml. Fail-fast if the file is\nmissing; add regression tests that LiteLLM preserves model_info extras.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "0de2bdecfcce1aad8bd1e31e45669b3b4d5fbe36",
      "tree": "88ca118d099a67e83e9081c441438a090a9a31b7",
      "parents": [
        "e92428916ba24eb7c561a7ec92a646ef7335e60e"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 18:26:26 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 18:26:26 2026 -0500"
      },
      "message": "Drop Settings; use APP.cfg EasyDict with dotted access.\n\nRemove llmao/config.py and LLMAO_SETTINGS. Wire main, seam, backend, auth,\npages, and API from asfquart app.cfg (and the same EasyDict in tests) so\nconfiguration is one object with cfg.litellm.* / cfg.budgets.* style access.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "e92428916ba24eb7c561a7ec92a646ef7335e60e",
      "tree": "f617452d354f2cd390f4785152d4439a726c5181",
      "parents": [
        "0556caa0cc2d7c61c77a57ee04520e782d27355d"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 17:18:32 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 17:18:32 2026 -0500"
      },
      "message": "Speak to LiteLLM with async httpx instead of sync requests.\n\nMake the admin backend protocol async so Quart handlers do not block the\nevent loop on team/key HTTP. Use a shared httpx.AsyncClient with teardown,\nawait from the seam and API routes, and drop the requests dependency.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "0556caa0cc2d7c61c77a57ee04520e782d27355d",
      "tree": "21fe6cf3fbddae7b7fba6733c7bcf1074bb8f4eb",
      "parents": [
        "a9dd07cd9a9570557ffc8a3342a25c87d2046247"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 16:18:55 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 16:18:55 2026 -0500"
      },
      "message": "Add litellm.yaml example and master-key helper for proxy mode.\n\nIntroduce a root litellm.yaml.example (secrets in gitignored litellm.yaml)\nand a print-only bin/gen-litellm-master-key.sh so the same sk- admin key can\nbe pasted into both LiteLLM and llmao configs. Document PAT metadata as\nLiteLLM-owned, eyaml dual-file secrets, and make proxy require litellm.yaml.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "a9dd07cd9a9570557ffc8a3342a25c87d2046247",
      "tree": "10acd6a435698e9f93132fa20133fa53a0b53f83",
      "parents": [
        "0ebbcb3a40ab2efc9a8d9addcb4e97a2722c11e3"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 14:10:37 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Sat Aug 08 14:10:37 2026 -0500"
      },
      "message": "Add STeVe-style EZT UI shell, static Bootstrap, and ASGI entry.\n\nFold app construction into main.py with run_standalone and run_asgi\n(hypercorn main:llmao_app). Register HTML and JSON routes from pages.py\nand api.py on asfquart.APP. Vendor Bootstrap/icons via bin/fetch-thirdparty.sh\nand replace string-built portal HTML with templates and static assets.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "0ebbcb3a40ab2efc9a8d9addcb4e97a2722c11e3",
      "tree": "3118292b25a07e90be6541a1a3e4a014e64be7e8",
      "parents": [
        "3574489b760c6360d5803fc8578da2739067f1ea"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Fri Aug 07 18:35:18 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Fri Aug 07 18:35:18 2026 -0500"
      },
      "message": "Require asfquart always; run Steve-style with local TLS config.\n\nDrop LLMAO_AUTH_MODE and the dev-login Quart path so identity is always\nasfquart OAuth. Add root main.py, gitignored config.yaml (example committed),\nand certs docs for localhost.apache.org mkcert so sessions and OAuth work\nover HTTPS. Protect budget/usage with @require; keep project scope in the\nseam. Slim tests to offline seam/catalog coverage while auth HTTP is in flux.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "3574489b760c6360d5803fc8578da2739067f1ea",
      "tree": "158eda5082de52c70f59b644b620f567fccec1b8",
      "parents": [
        "b2d248f1f41eb6ca2f3763b3fa747a769636fccd"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Fri Aug 07 17:31:54 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Fri Aug 07 17:31:54 2026 -0500"
      },
      "message": "Cite the rai-private master design; map the multi-repo layout.\n\nPoint README and architecture at apache/rai-private services/llmao as the\nauthoritative product design, and clarify this tree as Tooling’s asfquart seam\nwith Infra Puppet separate. Align vocabulary (PAT \u003d virtual key) without\nduplicating the full design.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "b2d248f1f41eb6ca2f3763b3fa747a769636fccd",
      "tree": "5edc5f2b3aaeb51f7aca6bc6674429ca18681c47",
      "parents": [
        "6840a596351e6eadfb5724775b42bd13bb1c6d72"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Fri Aug 07 16:57:37 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Fri Aug 07 16:57:37 2026 -0500"
      },
      "message": "Strip the chat gateway; reframe llmao as a LiteLLM control plane.\n\nDrop the OpenAI-compatible completion proxy, /v1/models, and the portal chat\nUI so clients talk to LiteLLM directly. Keep ASF auth, project↔team provision,\nand budget/usage reads as the foundation for upcoming virtual-key management.\nRewrite tests and docs around that smaller surface.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "6840a596351e6eadfb5724775b42bd13bb1c6d72",
      "tree": "87c8370d98b6204fa5ba0260cb7c7799cc34a7ed",
      "parents": [
        "22566fc755a82852b2022b20ebbdb49954ea397d"
      ],
      "author": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 05 13:17:26 2026 -0500"
      },
      "committer": {
        "name": "Greg Stein",
        "email": "gstein@gmail.com",
        "time": "Wed Aug 05 13:17:26 2026 -0500"
      },
      "message": "Migrate packaging and dev workflow from pip/venv to uv.\n\nReplace requirements*.txt and pytest.ini with a pyproject.toml (hatchling,\neditable install, pytest config) and a committed uv.lock. Point Makefile and\nDockerfile at uv sync/run so local and image installs share one dependency\nsource; asfquart and litellm[proxy] are declared as runtime deps on PyPI.\n\nCo-authored-by: Grok \u003cgrok@x.ai\u003e\n"
    },
    {
      "commit": "22566fc755a82852b2022b20ebbdb49954ea397d",
      "tree": "07f574df5f802951c808f75d2764c3b7f714a600",
      "parents": [
        "b89a25317107d399d04b442db3b6693ed29db975"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Mon Aug 03 18:53:26 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Mon Aug 03 18:53:26 2026 -0700"
      },
      "message": "Adding thinking and temperature elements in the portal\n"
    },
    {
      "commit": "b89a25317107d399d04b442db3b6693ed29db975",
      "tree": "6218d5e5a0d0763c360ab0ad7719f76d507c818f",
      "parents": [
        "0c42629124b985b1444f4bda9df2a1a3c1cd7d41"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Mon Aug 03 17:18:02 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Mon Aug 03 17:18:02 2026 -0700"
      },
      "message": "Fixing qwen model sizing\n"
    },
    {
      "commit": "0c42629124b985b1444f4bda9df2a1a3c1cd7d41",
      "tree": "4a462a4e07a1e0bf993ce00a9dc11616ee58bfe6",
      "parents": [
        "49fefe9d46c06b09e90700d7d86f1e318eb7262e"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Mon Aug 03 16:50:19 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Mon Aug 03 16:50:19 2026 -0700"
      },
      "message": "Moving llmao config to point to new gemma locaion and revive qwen\n"
    },
    {
      "commit": "49fefe9d46c06b09e90700d7d86f1e318eb7262e",
      "tree": "0f0daeb1d0fb267828ee99db0d6f41c5f447d469",
      "parents": [
        "7ecb6e99f691028b9830b42ba8bb87816f9f5299"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Thu Jul 23 15:15:55 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Thu Jul 23 15:15:55 2026 -0700"
      },
      "message": "Remove Qwen3-8B from the catalog, Gemma is sole GPU resident\n\nThe pipeline consuming this gateway stopped calling the fast tier once its\ndiscovery stage gained per-domain batching, so Qwen was occupying ~12GB of\nVRAM unused and constraining Gemma to --enforce-eager at gpu-util 0.68.\n\n- Qwen CatalogModel commented out (not deleted) with instructions for\n  restoring it alongside the vllm-qwen8b docker::run block in llmao.pp.\n- litellm/config.yaml regenerated: only the selfhost/gemma4-26b route remains.\n\nNote the accompanying llmao.pp change gives Gemma the full card:\ngpu-memory-utilization 0.90, max-model-len 131072, max-num-seqs 16, and no\n--enforce-eager. CUDA graph capture completes in ~4s on the solo config, so\nthe hang that originally motivated eager mode was VRAM starvation rather than\na model or engine bug.\n"
    },
    {
      "commit": "7ecb6e99f691028b9830b42ba8bb87816f9f5299",
      "tree": "5c93db40e2fe469289d42e99ff38c80d16cf873f",
      "parents": [
        "98243cb7ec3b6ec5f2e605938f19dd8deede8563"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Fri Jul 17 23:12:12 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Fri Jul 17 23:12:12 2026 -0700"
      },
      "message": "Changing proxy IP\n"
    },
    {
      "commit": "98243cb7ec3b6ec5f2e605938f19dd8deede8563",
      "tree": "62d3c387a3d5c3e1c491a7636b0293307bdaf440",
      "parents": [
        "9b95a705a74d8e211b4141ca1c0cd5ae5870cba6"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Fri Jul 17 22:49:37 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Fri Jul 17 22:49:37 2026 -0700"
      },
      "message": "expose litellm proxy on loopback for machine callers\n\nllmao authenticates humans: Apache vhost -\u003e Quart app -\u003e ASF OAuth. The\nmachine path is asfquart PATs, and make_token_handler is a Phase 1.x stub\nreturning None for every token, so no bearer can resolve to a session.\nLLMAO_LITELLM_MASTER_KEY is not the credential either -- that is llmao\u0027s own\nkey to its proxy on the internal bridge. Machine-to-machine access is\nunimplemented, not misconfigured.\n\nBind litellm-proxy to 127.0.0.1:4000 so a host vhost can front it for callers\nthat cannot authenticate through the app (gofannon\u0027s ASVS agents). This is a\ndeliberate bypass of llmao\u0027s identity layer: litellm\u0027s own virtual keys and\nspend logs account for the traffic instead, so it stays attributable and\nrevocable.\n\nProvision a per-caller key rather than handing out the master key:\n\n    curl -X POST http://127.0.0.1:4000/key/generate       -H Authorization:Bearer:sk-8ff67d84381b3962e7f33bd5512bb4c44ef98bafe459636e       -d {models:[selfhost/qwen3-8b,selfhost/gemma4-26b],key_alias:gofannon-asvs}\n\nThe proper fix is implementing token_handler against a PAT store, at which\npoint callers can go through the app and this binding can go away.\n"
    },
    {
      "commit": "9b95a705a74d8e211b4141ca1c0cd5ae5870cba6",
      "tree": "1e083996c1336c900f16ebb056bd2c787575611f",
      "parents": [
        "d4066f1ed22dcc089e776c39736616d4960c15bd"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Fri Jul 17 17:57:06 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Fri Jul 17 17:57:06 2026 -0700"
      },
      "message": "Adding git install to Dockerfile\n"
    },
    {
      "commit": "d4066f1ed22dcc089e776c39736616d4960c15bd",
      "tree": "93909ab63731f85bf0debbe080a0bb71cc5fbe60",
      "parents": [
        "617f6e7b478221101d94482b039b859aadec5972"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Fri Jul 17 17:51:36 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Fri Jul 17 17:51:36 2026 -0700"
      },
      "message": "Adding asfquart\n"
    },
    {
      "commit": "617f6e7b478221101d94482b039b859aadec5972",
      "tree": "4af474c41897265167a82ed060a385ed5f9613c8",
      "parents": [
        "6576472de8c5b89f1321e863460e0f6469069366"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Wed Jul 08 09:34:40 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Wed Jul 08 09:34:40 2026 -0700"
      },
      "message": "Two-model self-host catalog: FP8 checkpoints, drop coder\n\n- catalog.py: point Gemma at RedHatAI/gemma-4-26B-A4B-it-FP8-Dynamic and the\n  8B at Qwen/Qwen3-8B-FP8 (pre-quantized). Document the FP8/eager/vLLM-0.19.1\n  requirements and the 8B thinking-mode note in each entry.\n- catalog.py: remove the Qwen 3.6-27B coder from the resident set; leave a\n  comment recording it as a rotation candidate (Qwen/Qwen3.6-27B-FP8,\n  vLLM \u003e\u003d0.19.0) since one L40S cannot co-host three models this size.\n- litellm/config.yaml: regenerate for the two remaining models.\n"
    },
    {
      "commit": "6576472de8c5b89f1321e863460e0f6469069366",
      "tree": "e17ef622e59489b3d4411ba0c056bb87908b8750",
      "parents": [
        "5281fc6b31e3297ae667c9350690437ca3609d70"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Tue Jul 07 16:44:26 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Tue Jul 07 16:44:26 2026 -0700"
      },
      "message": "Self-host only catalog; add litellm Postgres; bump vLLM to 0.11.0\n"
    },
    {
      "commit": "5281fc6b31e3297ae667c9350690437ca3609d70",
      "tree": "4a7c02681f736f80d5a7297f67baa017a67c0c4c",
      "parents": [
        "406c5c9c082e8f1d48b8022dc7c753dfa7b138f8"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Tue Jul 07 13:36:46 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Tue Jul 07 13:36:46 2026 -0700"
      },
      "message": "Remove upstream providers from the catalog (self-host only)\n\nDrop the Anthropic and Bedrock entries so the PoC catalog lists only the\nthree self-hosted vLLM models. With the providers listed but their keys\nunset, those models showed up in the portal and failed only when selected;\nremoving them keeps the portal to what actually works.\n\n- llmao/catalog.py: remove the anthropic and bedrock CatalogModel entries;\n  CATALOG is now gemma4-26b, qwen3.6-27b, qwen3-8b.\n- litellm/config.yaml: regenerated from the catalog (no external blocks).\n- llmao/litellm_client.py: mock price map keyed to the self-host backends.\n  Priced nominally (not zero) so budget enforcement stays exercisable in\n  tests; real self-host cost accounting is the advisor layer\u0027s job.\n- tests/test_phase1.py: use self-host/gemma4-26b as the test model in place\n  of the removed anthropic/claude-haiku.\n- infra/docker/docker-compose.yml: drop the ANTHROPIC and BEDROCK env\n  passthroughs.\n\nThe renderer PROVIDER_ENV map is left in place (dormant) so a provider can\nbe reinstated later by adding a catalog entry, without renderer changes.\n"
    },
    {
      "commit": "406c5c9c082e8f1d48b8022dc7c753dfa7b138f8",
      "tree": "50222bf8c7b71dc4c613b024b26372556eddda61",
      "parents": [
        "859881b32d937adb457d47a213b482286caf45b4",
        "5932f75293c8aba3202d2a6db53c6bf889645a97"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Mon Jul 06 21:34:22 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jul 06 21:34:22 2026 -0700"
      },
      "message": "Merge pull request #1 from andrewmusselman/renaming\n\nRename hayward → llmao; add vLLM self-host tier and Docker/compose stack"
    },
    {
      "commit": "5932f75293c8aba3202d2a6db53c6bf889645a97",
      "tree": "50222bf8c7b71dc4c613b024b26372556eddda61",
      "parents": [
        "859881b32d937adb457d47a213b482286caf45b4"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Mon Jul 06 21:29:25 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Mon Jul 06 21:29:25 2026 -0700"
      },
      "message": "Rename hayward to llmao; add GPU model-host catalog and Docker compose\n"
    },
    {
      "commit": "859881b32d937adb457d47a213b482286caf45b4",
      "tree": "3c991679b9ec43ee77dfb6358188e1ea83c1bf51",
      "parents": [
        "f1ef7b16ff7dd8d3d68f49c1167be6a526c31186"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Fri Jun 12 14:41:57 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jun 12 14:41:57 2026 -0700"
      },
      "message": "Revise terminal command instructions in README\n\nUpdated README with terminal commands for litellm proxy and Hayward."
    },
    {
      "commit": "f1ef7b16ff7dd8d3d68f49c1167be6a526c31186",
      "tree": "b7b5ee3a1e301d8ded17c4ffbf455a73740f38e6",
      "parents": [
        "a31f71ca0672ab9ed0280db4b667c7e9daf51c32"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Thu Jun 11 11:55:24 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Thu Jun 11 11:57:14 2026 -0700"
      },
      "message": "Adding screenshot\n"
    },
    {
      "commit": "a31f71ca0672ab9ed0280db4b667c7e9daf51c32",
      "tree": "7f8a5e371b93784f48409ef7d449213c00de4a7b",
      "parents": [
        "55cbe98cbb0923010ea4c2d247ea20484fc46bb6"
      ],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Thu Jun 11 11:39:57 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Thu Jun 11 11:39:57 2026 -0700"
      },
      "message": "Harden gateway error handling and make request timeout configurable\n\nSlow local models (modest GPUs, or reasoning models that think before\nanswering) could exceed the hard-coded 120s proxy timeout, and on failure\nthe chat route let the exception reach Quart\u0027s default HTML 500 page.\n\n- Add HAYWARD_REQUEST_TIMEOUT_S (default 600s), replacing the hard-coded\n  120s wait in ProxyBackend.chat.\n- Introduce BackendUnavailable; convert proxy timeouts/connection errors\n  into a clean 504 JSON response instead of an unhandled exception.\n- Add a JSON catch-all for unhandled errors on /v1/* routes so the API\n  never returns HTML.\n- Harden the portal\u0027s send() to parse responses defensively and show a\n  readable message on timeout (504) or any non-JSON body.\n- Add a regression test asserting a backend timeout yields JSON 504.\n- README: document the 504 code, the timeout knob, and slow-model guidance.\n\nNote: litellm /team/info 500s under a DB-less proxy are left as-is\n(cosmetic; real per-team spend needs Postgres).\n"
    },
    {
      "commit": "55cbe98cbb0923010ea4c2d247ea20484fc46bb6",
      "tree": "686207a387b4c64da4d9b2918634eaaf1269af5a",
      "parents": [],
      "author": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Wed Jun 10 14:49:42 2026 -0700"
      },
      "committer": {
        "name": "Andrew Musselman",
        "email": "andrew.musselman@gmail.com",
        "time": "Wed Jun 10 14:49:42 2026 -0700"
      },
      "message": "Initial commit: Hayward Phase 1 LLM gateway\n"
    }
  ]
}
