{
  "origin": "https://dev.jiajun.fyi",
  "title": "jiajun.fyi APIs",
  "summary": "The APIs behind jiajun.fyi: one person's library, English practice, recipes and commute tools, with what an agent can call and how.",
  "services": [
    {
      "id": "pih",
      "app": "pih-api",
      "name": "Personal Info Hub · public API",
      "nameZh": "信息库 · 开放 API",
      "host": "pih-api.jiajun.fyi",
      "access": "key",
      "summaryZh": "搜索和读取收藏的一切：文章、帖子、视频文字稿（带时间线）、媒体；收录链接、标星、写备注。给 agent 用的稳定接口。收录链接的服务可登记回调 Webhook（已收录 / 处理完成 / 处理失败），不用轮询。",
      "summary": "Search and read everything the owner collected (articles, posts, video transcripts as timelines, media); collect links, star, add notes. The stable interface for agents. Services that collect links get signed callback webhooks (item.collected / item.ready / item.failed) instead of polling.",
      "auth": "Authorization: Bearer pih_... (scoped key)",
      "openapi": "apps/api/public-api/openapi.json",
      "docs": [
        {
          "label": "llms.txt",
          "url": "https://pih-api.jiajun.fyi/llms.txt"
        },
        {
          "label": "OpenAPI",
          "url": "https://pih-api.jiajun.fyi/openapi.json"
        },
        {
          "label": "Reference",
          "url": "https://pih-api.jiajun.fyi/docs"
        }
      ],
      "groups": [
        {
          "title": "Endpoints",
          "routes": [
            [
              "GET",
              "/search",
              "Search the library",
              "search:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/items",
              "List items",
              "items:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/shots",
              "Videos laid out as shots (切片)",
              "items:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/items/{id}",
              "Get one item",
              "items:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/items/{id}/content",
              "Get an item's content",
              "items:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/items/{id}/media/{mediaId}",
              "Download one media file by its stable address",
              "media:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/items/{id}/timeline",
              "Read a video or episode as a timeline",
              "items:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PUT",
              "/items/{id}/note",
              "Set an item's note",
              "notes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/items/{id}/star",
              "Star or unstar an item",
              "notes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/items/{id}/later",
              "Mark or clear read / watch later",
              "notes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/collect",
              "Collect a link",
              "collect:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/flomo/memos",
              "Write a memo to Flomo",
              "notes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/english/words",
              "List English words",
              "english:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/english/practice",
              "List English practice records",
              "english:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/songbook/songs",
              "List songbook songs with their links",
              "songbook:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/songbook/songs",
              "Add a song to the songbook",
              "songbook:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/songbook/score-takes",
              "Save a recording and its detected notes",
              "songbook:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/songbook/score-takes",
              "List 扒谱结果 (takes saved from 实时扒谱)",
              "songbook:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/songbook/score-takes/{id}",
              "Read one 扒谱结果 with its MusicXML and lyrics",
              "songbook:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/songbook/links/match",
              "Match a batch of songbook links",
              "songbook:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/songbook/songs/{key}/links/{service}",
              "Set a song's link by hand",
              "songbook:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/songbook/tracklists",
              "List tracklists",
              "songbook:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/songbook/tracklists",
              "Ask for a 1001Tracklists set",
              "songbook:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/songbook/tracklists/{id}",
              "Read one tracklist",
              "songbook:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/songbook/tracklists/{id}/reread",
              "Read a stored set page again",
              "songbook:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/songbook/sheets",
              "List 图图乐谱 sheets",
              "songbook:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/songbook/sheets/{key}",
              "Change a song's 图图乐谱 sheet",
              "songbook:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/things/wanted",
              "Record something the owner wants to buy (记到想买)",
              "things:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/things/products",
              "Search 物品 (products)",
              "things:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/things/wanted-webhook",
              "Read the 想买 Webhook address",
              "things:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/things/wanted-webhook",
              "Make a new 想买 Webhook address",
              "things:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/things/wanted.shortcut",
              "Download the signed 记到想买 Shortcut",
              "things:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/restaurants",
              "Search 餐厅 (restaurants)",
              "restaurants:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/restaurants",
              "Add a restaurant (or find it)",
              "restaurants:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/restaurants/{id}",
              "Read one restaurant",
              "restaurants:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/restaurants/{id}",
              "Change a restaurant",
              "restaurants:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/restaurants/{id}/visits",
              "Record a visit (去吃了)",
              "restaurants:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/restaurants/{id}/links",
              "Link two stores (关联的店)",
              "restaurants:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/restaurants/{id}/links/{linkId}",
              "Confirm or remove a link",
              "restaurants:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/restaurants/{id}/reviews",
              "Read a restaurant's reviews (评价)",
              "restaurants:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/restaurants/{id}/reviews",
              "Pin or settle a review listing",
              "restaurants:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/restaurants/{id}/reviews/refresh",
              "Fetch a restaurant's reviews again",
              "restaurants:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/books",
              "List 读书 (WeRead books)",
              "books:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/books/highlights",
              "Search highlights and thoughts (划线、想法)",
              "books:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/books/stats",
              "Read 阅读时长 (reading time)",
              "books:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/books/{id}",
              "Read one book's notes",
              "books:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/books/sync",
              "Sync WeRead now (立即同步)",
              "books:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/people",
              "List 人物 (people)",
              "people:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/people",
              "Add a person (or find them)",
              "people:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/people/{id}",
              "Read one person and their items",
              "people:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/people/{id}",
              "Rename a person, or change aliases or description",
              "people:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/people/{id}/merge",
              "Merge two records of the same person",
              "people:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/people/{id}/items",
              "Link an item to a person",
              "people:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/people/{id}/items/{itemId}",
              "Change or remove a person's item",
              "people:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/recipes",
              "List 菜谱 (recipes)",
              "recipes:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/recipes",
              "Write your own recipe version for a saved post",
              "recipes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/recipes/{id}",
              "Read one recipe",
              "recipes:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/recipes/{id}/versions",
              "List every version of a dish",
              "recipes:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PUT",
              "/recipes/{id}/want",
              "Mark 想做 (want to cook), or take it back",
              "recipes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/recipes/{id}/cooked",
              "Log a 做过 (cooked it)",
              "recipes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/recipes/{id}/plan",
              "Plan the dish for a day (排餐), or take it off",
              "recipes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/recipes/grocery",
              "Add a line to the grocery list (采购清单)",
              "recipes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/recipes/import",
              "Turn saved posts or videos into recipes",
              "recipes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/feedback",
              "Report a problem, a missing capability or an idea",
              "any key",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/feedback",
              "List agent feedback",
              "feedback:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/feedback/{id}",
              "Read one report (by id or FB-12) with its logs and calls",
              "feedback:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/feedback/{id}",
              "Sort, resolve or merge a report (by id or FB-12)",
              "feedback:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/todos",
              "List 待办 (todos)",
              "todos:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/todos",
              "Add a todo",
              "todos:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/todos/{id}",
              "Change a todo, complete, drop or reopen it",
              "todos:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/card-notes",
              "List 卡片笔记 (card notes), newest first",
              "card_notes:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/card-notes",
              "Add a card note",
              "card_notes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/card-notes/tags",
              "List the tags in the card box, with counts",
              "card_notes:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/card-notes/{id}",
              "Read one card note",
              "card_notes:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/card-notes/{id}",
              "Change a card note, or take it back (撤销)",
              "card_notes:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/media",
              "List 图图's photos and videos",
              "tutu:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/media/{id}",
              "Get one of 图图's photos or videos",
              "tutu:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/days",
              "List 图图's daycare days: arrival, pick-up and naps",
              "tutu:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PUT",
              "/tutu/push-device",
              "Turn new-photo notifications on or off for one device",
              "tutu:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/home-logs",
              "List 图图's home logs: sleep, wake-up, meals, poops, photos",
              "tutu:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/tutu/home-logs",
              "Log something at home: fell asleep, woke up, a meal, a poop, a photo",
              "tutu:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/home-logs/{id}",
              "Get one home log",
              "tutu:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/tutu/home-logs/{id}",
              "Change a home log, or take it back (撤销)",
              "tutu:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/tutu/home-logs/{id}/photos",
              "Add a photo to a home log",
              "tutu:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/growth",
              "List 图图's growth measurements",
              "tutu:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/tutu/growth",
              "Add a growth measurement",
              "health:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/growth/chart",
              "图图's growth chart with WHO bands",
              "tutu:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/health/records",
              "List 图图's health records",
              "health:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/tutu/health/records",
              "Add a health record",
              "health:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/health/records/{id}",
              "Get one health record",
              "health:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "PATCH",
              "/tutu/health/records/{id}",
              "Change a health record",
              "health:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/tutu/health/vaccines",
              "图图's vaccines",
              "health:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/connectors",
              "How each 同步源 (sync) stands",
              "items:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/notify",
              "Tell the owner something",
              "notify:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/tikhub",
              "Make one TikHub request through the hub",
              "tikhub:call",
              "apps/api/public-api/openapi.json"
            ],
            [
              "POST",
              "/renders",
              "Render a Blender scene (queued)",
              "renders:write",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/renders/{id}",
              "Read a render: status and progress",
              "renders:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/renders/{id}/frames",
              "List a render's frames",
              "renders:read",
              "apps/api/public-api/openapi.json"
            ],
            [
              "GET",
              "/renders/{id}/frames/{name}",
              "Read one frame",
              "renders:read",
              "apps/api/public-api/openapi.json"
            ]
          ]
        },
        {
          "title": "Callback webhooks",
          "note": "Sent to an HTTPS endpoint the owner registers for your key; see llms.txt「Service callers」.",
          "routes": [
            [
              "EVENT",
              "item.collected",
              "Item collected: fetched, still processing",
              "signed (Standard Webhooks)",
              "apps/api/public-api/openapi.json"
            ],
            [
              "EVENT",
              "item.ready",
              "Item ready: all processing done",
              "signed (Standard Webhooks)",
              "apps/api/public-api/openapi.json"
            ],
            [
              "EVENT",
              "item.failed",
              "Item failed, with reason",
              "signed (Standard Webhooks)",
              "apps/api/public-api/openapi.json"
            ],
            [
              "EVENT",
              "webhook.test",
              "Test event",
              "signed (Standard Webhooks)",
              "apps/api/public-api/openapi.json"
            ]
          ]
        }
      ]
    },
    {
      "id": "pih-internal",
      "app": "hub-api",
      "name": "Personal Info Hub · internal API",
      "nameZh": "信息库 · 内部接口",
      "host": "api.hub.jiajun.fyi",
      "access": "key",
      "summaryZh": "hub 网页、Chrome 插件、pih CLI、MCP 用的 /api。API 密钥按权限范围可调；不保证稳定，能用开放 API 就用开放 API。",
      "summary": "The /api used by the hub web app, the Chrome extension, the pih CLI and MCP. Callable with a scoped key; not a stable contract, so prefer the public API when it covers the task.",
      "auth": "Authorization: Bearer pih_... with the scope in each row; every DELETE and any unlisted route needs admin",
      "stability": "internal",
      "groups": [
        {
          "title": "Items",
          "routes": [
            [
              "GET",
              "/api/items",
              "Item cards, newest first; with q it searches",
              "items:read (search:read with q)",
              "apps/api/src/item-views.ts"
            ],
            [
              "POST",
              "/api/items",
              "Collect a URL",
              "collect:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/items/facets",
              "Counts for the sidebar filters",
              "items:read",
              "apps/api/src/item-views.ts"
            ],
            [
              "GET",
              "/api/items/tags",
              "Top tags",
              "items:read",
              "apps/api/src/item-views.ts"
            ],
            [
              "GET",
              "/api/stats/collected",
              "Items collected per Pacific day and source (?days=30|90)",
              "admin",
              "apps/api/src/collection-stats.ts"
            ],
            [
              "GET",
              "/api/items/{id}",
              "Full item detail (the hub item page)",
              "items:read",
              "apps/api/src/item-views.ts"
            ],
            [
              "POST",
              "/api/items/{id}/star",
              "Star or unstar",
              "notes:write",
              "apps/api/src/item-views.ts"
            ],
            [
              "GET",
              "/api/items/{id}/status",
              "Processing stages",
              "items:read",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/items/{id}/media",
              "Media rehost status",
              "items:read",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/media/{id}",
              "A stored media file (Range supported)",
              "items:read",
              "apps/api/src/item-views.ts"
            ],
            [
              "GET",
              "/api/x-bookmarks/search",
              "Search X bookmarks",
              "search:read",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/integrations/flomo/memos",
              "Write a memo to Flomo",
              "notes:write",
              "apps/api/src/api-router.ts"
            ]
          ]
        },
        {
          "title": "Processing",
          "routes": [
            [
              "POST",
              "/api/items/{id}/media",
              "Queue a media rehost",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/items/{id}/refetch",
              "Fetch the item again",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/items/{id}/replies",
              "Expand comment replies (paid TikHub calls)",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/items/{id}/transcribe",
              "Queue a Whisper transcription",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/items/{id}/reprocess",
              "Run processing again",
              "sync:write",
              "apps/api/src/api-router.ts"
            ]
          ]
        },
        {
          "title": "Collectors and sync",
          "note": "For the owner's own sync clients (extension, pih CLI, hercules jobs).",
          "routes": [
            [
              "POST",
              "/api/import/{source}",
              "Bulk import: browser-bookmarks, x-bookmarks, youtube-saved-videos, bilibili-favorites, instagram-saved-items, xiaohongshu-favorites, xiaohongshu-liked-items",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/source-connectors",
              "List sync sources",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/source-connectors",
              "Create or update a sync source",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/source-connectors/{id}/{action}",
              "sync-result, boost, pause, resume, retry, trigger",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/recordings",
              "Recorded list responses (X bookmarks, Xiaohongshu): store, read, import",
              "sync:write",
              "apps/api/src/recordings.ts"
            ],
            [
              "GET",
              "/api/extension/scrapers/{name}",
              "Extension page recorder source",
              "sync:write",
              "apps/api/src/extension-scrapers.ts"
            ],
            [
              "GET",
              "/api/brightwheel/fetch-plan",
              "Brightwheel fetch plan",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/brightwheel/import-batch",
              "Brightwheel import",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/brightwheel/captures",
              "Brightwheel captures",
              "sync:write",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/storage/objects",
              "List or read private objects (key or prefix)",
              "sync:write",
              "apps/api/src/storage-api.ts"
            ],
            [
              "PUT",
              "/api/storage/objects",
              "Write a private object if absent (never overwrites or deletes); with uploadId&partNumber, one part of a multipart upload",
              "sync:write",
              "apps/api/src/storage-api.ts"
            ],
            [
              "POST",
              "/api/storage/objects",
              "Multipart upload for files over 100 MiB: ?uploads starts, ?uploadId completes (or &abort)",
              "sync:write",
              "apps/api/src/storage-api.ts"
            ],
            [
              "POST",
              "/api/watch-history/items",
              "Report watched titles (Emby)",
              "sync:write",
              "apps/api/src/watch-history.ts"
            ],
            [
              "POST",
              "/api/watch-history/events",
              "Report watch sessions",
              "sync:write",
              "apps/api/src/watch-history.ts"
            ],
            [
              "GET",
              "/api/watch-history/watched",
              "What counts as watched",
              "sync:write",
              "apps/api/src/watch-history.ts"
            ],
            [
              "PUT",
              "/api/watch-history/items/{id}/captions",
              "Upload a title's subtitles",
              "sync:write",
              "apps/api/src/watch-history.ts"
            ],
            [
              "PUT",
              "/api/watch-history/items/{id}/audio",
              "Upload a title's audio for transcription",
              "sync:write",
              "apps/api/src/watch-history.ts"
            ],
            [
              "POST",
              "/api/cue-clips/plan",
              "Plan sentence clips for studied words",
              "sync:write",
              "apps/api/src/cue-clips.ts"
            ],
            [
              "POST",
              "/api/video-stills/plan",
              "Queue a video still for every timed recipe step without one (?item= for one item)",
              "admin",
              "apps/api/src/video-stills.ts"
            ],
            [
              "GET",
              "/api/cue-clips/queue",
              "Clips waiting to be cut",
              "sync:write",
              "apps/api/src/cue-clips.ts"
            ],
            [
              "PUT",
              "/api/cue-clips/{id}/file",
              "Upload a cut clip",
              "sync:write",
              "apps/api/src/cue-clips.ts"
            ],
            [
              "POST",
              "/api/cue-clips/{id}/failed",
              "Mark a clip failed",
              "sync:write",
              "apps/api/src/cue-clips.ts"
            ],
            [
              "POST",
              "/api/jobs/claim",
              "Claim this Mac's most urgent queued jobs (video_rehost, upgrade_video), leased",
              "sync:write",
              "apps/api/src/jobs-api.ts"
            ],
            [
              "POST",
              "/api/jobs/{id}/heartbeat",
              "Renew a claimed job's lease, with its progress",
              "sync:write",
              "apps/api/src/jobs-api.ts"
            ],
            [
              "POST",
              "/api/jobs/release",
              "Give claimed jobs back untouched",
              "sync:write",
              "apps/api/src/jobs-api.ts"
            ],
            [
              "GET",
              "/api/jobs/overview",
              "Jobs queue: backlog by status, runner and type; failures; attention; quotas",
              "admin",
              "apps/api/src/jobs-api.ts"
            ],
            [
              "GET",
              "/api/jobs",
              "One group of jobs (status, runner, type, error prefix)",
              "admin",
              "apps/api/src/jobs-api.ts"
            ],
            [
              "POST",
              "/api/jobs/{id}/retry",
              "Run a job again now",
              "admin",
              "apps/api/src/jobs-api.ts"
            ],
            [
              "POST",
              "/api/jobs/{id}/cancel",
              "Call a job off",
              "admin",
              "apps/api/src/jobs-api.ts"
            ],
            [
              "POST",
              "/api/jobs/bulk",
              "Retry or close a whole failure group",
              "admin",
              "apps/api/src/jobs-api.ts"
            ],
            [
              "POST",
              "/api/items/{id}/video-rehost",
              "Register a rehosted video",
              "sync:write",
              "apps/api/src/video-rehost.ts"
            ],
            [
              "POST",
              "/api/items/{id}/captions/punctuate",
              "Punctuate machine captions",
              "sync:write",
              "apps/api/src/video-rehost.ts"
            ],
            [
              "GET",
              "/api/captions/readable-pending",
              "Captions waiting for punctuation",
              "sync:write",
              "apps/api/src/video-rehost.ts"
            ]
          ]
        },
        {
          "title": "Photo prints (冲印)",
          "note": "Which photos were printed. The Google Photos extension uses its own key; tutu.jiajun.fyi goes through its Access login.",
          "routes": [
            [
              "GET",
              "/api/photo-prints",
              "待冲印, 待确认 and every print batch with its photos",
              "photo_prints:read",
              "apps/api/src/photo-prints.ts"
            ],
            [
              "POST",
              "/api/photo-prints",
              "Add photos to 待冲印 ({photos: [{mediaKey | publicId, takenAt?, thumbUrl?}]}); status unconfirmed for an album import",
              "photo_prints:write",
              "apps/api/src/photo-prints.ts"
            ],
            [
              "POST",
              "/api/photo-prints/status",
              "Was each photo printed or waiting? (by media key, short id or taken time)",
              "photo_prints:read",
              "apps/api/src/photo-prints.ts"
            ],
            [
              "POST",
              "/api/photo-prints/batches",
              "Record a print batch: date, vendor, size for the chosen photos",
              "photo_prints:write",
              "apps/api/src/photo-prints.ts"
            ],
            [
              "PATCH",
              "/api/photo-prints/{id}",
              "Move a 待确认 photo to 待冲印",
              "photo_prints:write",
              "apps/api/src/photo-prints.ts"
            ]
          ]
        },
        {
          "title": "Restaurants (餐厅)",
          "note": "The same record as the public API's /restaurants; agents use that one. Deletes are admin only.",
          "routes": [
            [
              "GET",
              "/api/restaurants",
              "List restaurants (?q=&status=want|been&area=&cuisine=&links=unconfirmed|review)",
              "restaurants:read",
              "apps/api/src/restaurants.ts"
            ],
            [
              "GET",
              "/api/restaurants/{id}",
              "One restaurant with its linked stores and visits",
              "restaurants:read",
              "apps/api/src/restaurants.ts"
            ],
            [
              "POST",
              "/api/restaurants",
              "Add a restaurant, or find the one already there (same name + place) and fill in what it lacked; another place is another store, linked to the same-name ones",
              "restaurants:write",
              "apps/api/src/restaurants.ts"
            ],
            [
              "PATCH",
              "/api/restaurants/{id}",
              "Change fields",
              "restaurants:write",
              "apps/api/src/restaurants.ts"
            ],
            [
              "POST",
              "/api/restaurants/{id}/visits",
              "Record a visit; the restaurant becomes 去过",
              "restaurants:write",
              "apps/api/src/restaurants.ts"
            ],
            [
              "POST",
              "/api/restaurants/{id}/links",
              "Link another store (关联的店, 已确认)",
              "restaurants:write",
              "apps/api/src/restaurants.ts"
            ],
            [
              "PATCH",
              "/api/restaurants/{id}/links/{linkId}",
              "Confirm a link, mark it 待清洗, or remove it",
              "restaurants:write",
              "apps/api/src/restaurants.ts"
            ],
            [
              "DELETE",
              "/api/restaurants/{id}",
              "Remove a restaurant recorded by mistake, with its visits, links and reviews",
              "admin",
              "apps/api/src/restaurants.ts"
            ],
            [
              "DELETE",
              "/api/restaurants/visits/{id}",
              "Remove one visit",
              "admin",
              "apps/api/src/restaurants.ts"
            ]
          ]
        },
        {
          "title": "Books (读书)",
          "note": "WeRead (微信读书), synced read-only by the API; the same record as the public API's /books. Private books need ?includePrivate=true. The key is set on jiajun.fyi/admin/settings (管理 → 设置 → 微信读书).",
          "routes": [
            [
              "GET",
              "/api/books",
              "Books (?status=reading|finished|unread|all&q=&includePrivate=&cursor=&limit=), with counts and sync state",
              "books:read",
              "apps/api/src/books.ts"
            ],
            [
              "GET",
              "/api/books/{id}",
              "One book: highlights by chapter, thoughts under them, reviews",
              "books:read",
              "apps/api/src/books.ts"
            ],
            [
              "GET",
              "/api/books/highlights",
              "Search highlights and thoughts (?q=&bookId=)",
              "books:read",
              "apps/api/src/books.ts"
            ],
            [
              "GET",
              "/api/books/stats",
              "Reading time (?range=week|month|year|total)",
              "books:read",
              "apps/api/src/books.ts"
            ],
            [
              "POST",
              "/api/books/sync",
              "Sync WeRead now (立即同步)",
              "books:write",
              "apps/api/src/books.ts"
            ],
            [
              "GET",
              "/api/settings/weread",
              "Key status (last four characters only), sync state, counts",
              "admin",
              "apps/api/src/books-sync.ts"
            ],
            [
              "PUT",
              "/api/settings/weread",
              "Save the wrk- key (encrypted) and test it",
              "admin",
              "apps/api/src/books-sync.ts"
            ],
            [
              "POST",
              "/api/settings/weread/test",
              "Test the saved key",
              "admin",
              "apps/api/src/books-sync.ts"
            ],
            [
              "DELETE",
              "/api/settings/weread",
              "Remove the key",
              "admin",
              "apps/api/src/books-sync.ts"
            ]
          ]
        },
        {
          "title": "People (人物)",
          "note": "People from the library (interview guests, hosts, authors, subjects) with their items; the same record as the public API's /people. New items are read by 人物识别 after their summary.",
          "routes": [
            [
              "GET",
              "/api/people",
              "People, most items first (?q=&role=&cursor=&limit=)",
              "people:read",
              "apps/api/src/people.ts"
            ],
            [
              "GET",
              "/api/people/{id}",
              "One person with their items",
              "people:read",
              "apps/api/src/people.ts"
            ],
            [
              "POST",
              "/api/people",
              "Add, or find the one already there by name or alias",
              "people:write",
              "apps/api/src/people.ts"
            ],
            [
              "PATCH",
              "/api/people/{id}",
              "Rename, aliases, description, link",
              "people:write",
              "apps/api/src/people.ts"
            ],
            [
              "POST",
              "/api/people/{id}/merge",
              "Fold another person into this one ({personId})",
              "people:write",
              "apps/api/src/people.ts"
            ],
            [
              "POST",
              "/api/people/{id}/items",
              "Link an item ({itemId, role})",
              "people:write",
              "apps/api/src/people.ts"
            ],
            [
              "PATCH",
              "/api/people/{id}/items/{itemId}",
              "Change the role, or remove the link ({removed: true})",
              "people:write",
              "apps/api/src/people.ts"
            ],
            [
              "POST",
              "/api/people/detections",
              "Import the backfill's detections (scripts/people-backfill.mjs)",
              "admin",
              "apps/api/src/people.ts"
            ],
            [
              "DELETE",
              "/api/people/{id}",
              "Remove a person recorded by mistake (items stay)",
              "admin",
              "apps/api/src/people.ts"
            ]
          ]
        },
        {
          "title": "Todos (待办)",
          "note": "The owner's todo list, kept on the hub's 待办 page; the same record as the public API's /todos. Each todo names who added it (owner or the key). Nothing deletes one.",
          "routes": [
            [
              "GET",
              "/api/todos",
              "Todos: open first by priority and due date (?status=&priority=&tag=&q=&cursor=&limit=)",
              "todos:read",
              "apps/api/src/todos.ts"
            ],
            [
              "POST",
              "/api/todos",
              "Add ({title, note?, priority?, dueDate?, tags?})",
              "todos:write",
              "apps/api/src/todos.ts"
            ],
            [
              "PATCH",
              "/api/todos/{id}",
              "Change any field, or status",
              "todos:write",
              "apps/api/src/todos.ts"
            ],
            [
              "POST",
              "/api/todos/{id}/complete",
              "Mark done (also reopen, drop)",
              "todos:write",
              "apps/api/src/todos.ts"
            ],
            [
              "POST",
              "/api/todos/reorder",
              "Hand order ({ids}, first to last)",
              "todos:write",
              "apps/api/src/todos.ts"
            ]
          ]
        },
        {
          "title": "Admin",
          "note": "Owner tools. A key needs admin; backups take the internal token only.",
          "routes": [
            [
              "GET",
              "/api/api-keys",
              "List API keys",
              "admin",
              "apps/api/src/api-keys.ts"
            ],
            [
              "POST",
              "/api/api-keys",
              "Create an API key (shown once)",
              "admin",
              "apps/api/src/api-keys.ts"
            ],
            [
              "POST",
              "/api/api-keys/{id}/revoke",
              "Revoke a key",
              "admin",
              "apps/api/src/api-keys.ts"
            ],
            [
              "GET",
              "/api/api-keys/{id}/calls",
              "A key's recent calls",
              "admin",
              "apps/api/src/api-keys.ts"
            ],
            [
              "GET",
              "/api/agents",
              "The owner's agents (jiajun.fyi/agent) with their key state",
              "agents:manage",
              "apps/api/src/agents.ts"
            ],
            [
              "POST",
              "/api/agents",
              "Create an agent and its pih_ key (shown once; never admin, always expires)",
              "agents:manage",
              "apps/api/src/agents.ts"
            ],
            [
              "PATCH",
              "/api/agents/{id}",
              "Change an agent's permissions and its key's scopes in place",
              "agents:manage",
              "apps/api/src/agents.ts"
            ],
            [
              "POST",
              "/api/agents/{id}/{action}",
              "rotate (new key, same scopes, old revoked) or revoke",
              "agents:manage",
              "apps/api/src/agents.ts"
            ],
            [
              "GET",
              "/api/webhooks",
              "Callback webhook endpoints (?keyId=)",
              "admin",
              "apps/api/src/webhooks.ts"
            ],
            [
              "POST",
              "/api/webhooks",
              "Register an endpoint for a key (signing secret shown once)",
              "admin",
              "apps/api/src/webhooks.ts"
            ],
            [
              "POST",
              "/api/webhooks/{id}/{action}",
              "test, disable, enable, rotate-secret, move (to a new key)",
              "admin",
              "apps/api/src/webhooks.ts"
            ],
            [
              "GET",
              "/api/webhooks/{id}/events",
              "Recent events with every delivery attempt",
              "admin",
              "apps/api/src/webhooks.ts"
            ],
            [
              "POST",
              "/api/webhooks/events/{id}/redeliver",
              "Send an event again",
              "admin",
              "apps/api/src/webhooks.ts"
            ],
            [
              "GET",
              "/api/settings/collect-webhook",
              "Read, rotate (POST) or disable (DELETE) the collect webhook",
              "admin",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/settings/flomo",
              "Flomo settings (PUT, DELETE)",
              "admin",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/model-runs/summary",
              "Model cost summary",
              "admin",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/tikhub/budget",
              "TikHub budget (PUT to change)",
              "admin",
              "apps/api/src/tikhub-budget.ts"
            ],
            [
              "GET",
              "/api/notifications/channels",
              "Notification channels",
              "admin",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/notifications/send",
              "Send a notification",
              "admin",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/notifications/log",
              "Delivery log",
              "admin",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/system/capabilities",
              "System status",
              "admin",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/payloads",
              "Keep a raw payload",
              "admin",
              "apps/api/src/payloads-api.ts"
            ],
            [
              "GET",
              "/api/backup/rows",
              "Table rows for the nightly backup",
              "internal token only",
              "apps/api/src/backup-api.ts"
            ]
          ]
        },
        {
          "title": "No credential",
          "note": "These carry their own proof: a secret in the path, a signature, or a public item.",
          "routes": [
            [
              "GET",
              "/health",
              "Health check",
              "none",
              "apps/api/src/index.ts"
            ],
            [
              "POST",
              "/api/webhook/collect/{secret}",
              "iOS share-sheet collect (GET with ?url= also works)",
              "secret in the URL",
              "apps/api/src/api-router.ts"
            ],
            [
              "POST",
              "/api/webhook/things/{secret}",
              "记到想买 from a Shortcut or any tool: {text} / {url} / an image (GET with ?text= or ?url= also works)",
              "secret in the URL",
              "apps/api/src/things-wanted.ts"
            ],
            [
              "GET",
              "/api/public/media/{id}",
              "Signed media link",
              "signature",
              "apps/api/src/api-router.ts"
            ],
            [
              "GET",
              "/api/public/items/{id}",
              "Public fields of an item marked public",
              "none",
              "apps/api/src/api-router.ts"
            ]
          ]
        }
      ]
    },
    {
      "id": "english",
      "app": "english",
      "name": "English Practice",
      "nameZh": "英语练习",
      "host": "english.jiajun.fyi",
      "access": "login",
      "summaryZh": "英语表达练习、欧路生词本、发音评分、看视频学单词。只认登录；agent 读练习数据走开放 API 的 /english/*。",
      "summary": "Practice records, the Eudic word book, pronunciation scoring, and words in watched videos. Login only; agents read practice data through the public API's /english/*.",
      "auth": "Cloudflare Access (owner login)",
      "groups": [
        {
          "title": "Practice",
          "routes": [
            [
              "GET",
              "/api/english-practice",
              "Practice records (POST adds one)",
              "login",
              "apps/english/worker/english-practice.mjs"
            ],
            [
              "PATCH",
              "/api/english-practice/{id}",
              "Update a record (mastery)",
              "login",
              "apps/english/worker/english-practice.mjs"
            ],
            [
              "GET",
              "/api/english-practice/sync-state",
              "Cursor for the practice sync (PUT moves it)",
              "login",
              "apps/english/worker/english-practice.mjs"
            ],
            [
              "GET",
              "/api/english-practice/sources",
              "Source prompts (POST adds)",
              "login",
              "apps/english/worker/english-practice.mjs"
            ],
            [
              "GET",
              "/api/english-practice/known-terms",
              "Terms already mastered",
              "login",
              "apps/english/worker/english-practice.mjs"
            ]
          ]
        },
        {
          "title": "Words and pronunciation",
          "routes": [
            [
              "GET",
              "/api/eudic-words",
              "Words in a Eudic book, with sync status",
              "login",
              "apps/english/worker/eudic.mjs"
            ],
            [
              "PUT",
              "/api/eudic-words/star",
              "Set a word's mastery",
              "login",
              "apps/english/worker/eudic.mjs"
            ],
            [
              "GET",
              "/api/eudic-words/star-events",
              "A word's mastery history",
              "login",
              "apps/english/worker/eudic.mjs"
            ],
            [
              "GET",
              "/api/pronunciation/tts",
              "Reference audio for a text",
              "login",
              "apps/english/worker/pronunciation.mjs"
            ],
            [
              "GET",
              "/api/pronunciation/attempts",
              "Scored attempts (POST scores a new one)",
              "login",
              "apps/english/worker/pronunciation.mjs"
            ],
            [
              "GET",
              "/api/pronunciation/recording",
              "A recorded attempt",
              "login",
              "apps/english/worker/pronunciation.mjs"
            ],
            [
              "GET",
              "/api/word-clips",
              "Moments in watched videos where a word is spoken",
              "login",
              "apps/english/worker/word-clips.mjs"
            ],
            [
              "GET",
              "/api/word-clips/clip/{id}",
              "A sentence clip",
              "login",
              "apps/english/worker/word-clips.mjs"
            ],
            [
              "GET",
              "/api/word-clips/media/{id}",
              "The full media file",
              "login",
              "apps/english/worker/word-clips.mjs"
            ]
          ]
        }
      ]
    },
    {
      "id": "recipes",
      "app": "recipes",
      "name": "Recipes",
      "nameZh": "菜谱",
      "host": "recipes.jiajun.fyi",
      "access": "login",
      "summaryZh": "从收藏里整理出的菜谱、本周排餐和采购清单。只认登录。",
      "summary": "Recipes extracted from the library, the week's meal plan and the grocery list. Login only.",
      "auth": "Cloudflare Access (owner login)",
      "groups": [
        {
          "title": "Recipes and planning",
          "routes": [
            [
              "GET",
              "/api/recipes",
              "All recipes",
              "login",
              "apps/recipes/worker/recipes.mjs"
            ],
            [
              "GET",
              "/api/recipes/{n}",
              "One recipe",
              "login",
              "apps/recipes/worker/recipes.mjs"
            ],
            [
              "PUT",
              "/api/recipes/{n}/want",
              "Mark as want to cook",
              "login",
              "apps/recipes/worker/recipes.mjs"
            ],
            [
              "POST",
              "/api/recipes/{n}/cooked",
              "Log that it was cooked",
              "login",
              "apps/recipes/worker/recipes.mjs"
            ],
            [
              "GET",
              "/api/items/{id}/recipes",
              "Recipes cut from one library item",
              "login",
              "apps/recipes/worker/recipes.mjs"
            ],
            [
              "GET",
              "/api/plan",
              "The week's meal plan (POST adds, DELETE /api/plan/{n} removes)",
              "login",
              "apps/recipes/worker/recipes.mjs"
            ],
            [
              "GET",
              "/api/grocery",
              "The week's grocery list (POST adds, DELETE /api/grocery/{n} removes)",
              "login",
              "apps/recipes/worker/recipes.mjs"
            ],
            [
              "PUT",
              "/api/grocery/check",
              "Tick grocery items",
              "login",
              "apps/recipes/worker/recipes.mjs"
            ],
            [
              "GET",
              "/api/media/{id}",
              "A recipe's picture or video",
              "login",
              "apps/recipes/worker/recipes.mjs"
            ]
          ]
        }
      ]
    },
    {
      "id": "evals",
      "app": "evals",
      "name": "Evals",
      "nameZh": "测评",
      "host": "evals.jiajun.fyi",
      "access": "login",
      "summaryZh": "我自己做过的模型 / 引擎对比和测试集。只认登录；bench 脚本用 Access 服务令牌 jc-evals 导入，格式见 docs/evaluations.md。",
      "summary": "My own model and engine comparisons, and the test sets they reuse. Login only; bench scripts import with the jc-evals Access service token (docs/evaluations.md).",
      "auth": "Cloudflare Access (owner login, or the jc-evals service token for imports)",
      "groups": [
        {
          "title": "Evaluations and test sets",
          "routes": [
            [
              "GET",
              "/api/evaluations",
              "All evaluations (POST imports one, upsert by slug)",
              "login",
              "apps/evals/worker/evaluations.mjs"
            ],
            [
              "GET",
              "/api/evaluations/{slug}",
              "One evaluation with its samples and files",
              "login",
              "apps/evals/worker/evaluations.mjs"
            ],
            [
              "PUT",
              "/api/evaluations/{slug}/files/{name}",
              "Store a raw file in R2 (GET reads it back)",
              "login",
              "apps/evals/worker/evaluations.mjs"
            ],
            [
              "GET",
              "/api/test-sets",
              "Test sets (POST saves one)",
              "login",
              "apps/evals/worker/evaluations.mjs"
            ],
            [
              "GET",
              "/api/test-sets/{slug}",
              "One test set and the evaluations run on it",
              "login",
              "apps/evals/worker/evaluations.mjs"
            ],
            [
              "GET",
              "/api/test-sets/candidates",
              "Library items that could join a test set",
              "login",
              "apps/evals/worker/evaluations.mjs"
            ]
          ]
        }
      ]
    },
    {
      "id": "caltrain",
      "app": "caltrain",
      "name": "Caltrain Commute",
      "nameZh": "Caltrain 通勤",
      "host": "caltrain.jiajun.fyi",
      "access": "public",
      "summaryZh": "实时 Caltrain 班次和通勤提醒。/status 公开可读；设置页要登录。",
      "summary": "Live Caltrain predictions and commute reminders. /status is public; the settings page needs a login.",
      "auth": "None for /status; /settings behind Cloudflare Access; /api/action takes the hub's internal token",
      "groups": [
        {
          "title": "Commute",
          "routes": [
            [
              "GET",
              "/status",
              "Live train predictions (JSON); with ?from=&to= station ids, any station pair from the timetable",
              "none",
              "apps/caltrain/src/index.ts"
            ],
            [
              "GET",
              "/stations",
              "Station ids and names, north to south",
              "none",
              "apps/caltrain/src/index.ts"
            ],
            [
              "GET",
              "/passings",
              "When commute trains really left the two boarding platforms (last 30 days)",
              "none",
              "apps/caltrain/src/index.ts"
            ],
            [
              "GET",
              "/health",
              "Health check",
              "none",
              "apps/caltrain/src/index.ts"
            ],
            [
              "GET",
              "/settings",
              "Reminder settings (?format=json; POST saves)",
              "login",
              "apps/caltrain/src/index.ts"
            ],
            [
              "POST",
              "/api/action",
              "Button actions from the Feishu bot",
              "internal token",
              "apps/caltrain/src/index.ts"
            ]
          ]
        }
      ]
    },
    {
      "id": "share",
      "app": "share",
      "name": "Share pages",
      "nameZh": "公开分享",
      "host": "share.jiajun.fyi",
      "access": "public",
      "summaryZh": "标为公开的条目的网页。只出 HTML，不是 JSON 接口。",
      "summary": "Web pages for items marked public. HTML only, not a JSON API.",
      "auth": "None",
      "groups": [
        {
          "title": "Pages",
          "routes": [
            [
              "GET",
              "/{id}",
              "The public page of one item",
              "none",
              "apps/share/worker/index.mjs"
            ]
          ]
        }
      ]
    }
  ],
  "elsewhere": [
    {
      "host": "hub.jiajun.fyi",
      "note": "The library's web app (login). Its /api is the internal API above, proxied.",
      "noteZh": "信息库网页（需登录）。它的 /api 就是上面的内部接口，经它转发。"
    },
    {
      "host": "api.jiajun.fyi",
      "note": "Media gateway to the home inference machines (transcription, chat, page fetch). Its own key; used by the library's jobs, not by agents.",
      "noteZh": "家里推理机的媒体网关（转写、对话模型、代抓网页）。用自己的密钥，给信息库的后台任务用，不给 agent。"
    },
    {
      "host": "suanming.jiajun.fyi",
      "note": "Divination research desk: content library, crawl jobs, charts (login). Its /api serves only its own page; no API keys.",
      "noteZh": "算命数据台：内容库、爬取任务、排盘（需登录）。/api 只给自己的页面用，不发 API 密钥。"
    },
    {
      "host": "jiajun.fyi",
      "note": "Directory of every service (login).",
      "noteZh": "所有服务的导航页（需登录）。"
    },
    {
      "host": "admin.jiajun.fyi",
      "note": "The library's admin site (owner login only). Its /api is the internal API above, proxied.",
      "noteZh": "信息库的管理站（只有本人能登录）。它的 /api 就是上面的内部接口，经它转发。"
    }
  ]
}
