{
  "name": "ai-knowledge-lab",
  "version": "0.4.0",
  "description": "Knowledge Lab tools. Agents: lab_discover then lab_execute. Add domain tools here without editing SKILL.md. Hot Words lifecycle: State → Propose → Validate → Apply → Publish → Observe.",
  "transport_today": "static-http + action urls",
  "transport_next": "mcp-stdio-or-http",
  "skill": "/SKILL.md",
  "meta_tools": [
    "lab_discover",
    "lab_execute"
  ],
  "tools": [
    {
      "name": "lab_discover",
      "kind": "meta",
      "description": "List available Lab capabilities. Call before lab_execute. Catalog grows without changing SKILL.md.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Optional keyword filter (article, issue, subscribe, github…)"
          }
        },
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/discover.json"
      }
    },
    {
      "name": "lab_execute",
      "kind": "meta",
      "description": "Execute a discovered tool by name. Resolve schema from /mcp/tools.json, then hit static.path / path_template / action.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "tool": {
            "type": "string",
            "description": "Exact tool name from lab_discover"
          },
          "args": {
            "type": "object",
            "description": "Arguments for path_template or action body"
          }
        },
        "required": [
          "tool"
        ],
        "additionalProperties": false
      },
      "static": {
        "method": "RESOLVE",
        "registry": "/mcp/tools.json",
        "note": "Substitute path_template args; GET for read tools; follow action.url / mailto for engage tools."
      }
    },
    {
      "name": "lab_hello",
      "kind": "engage",
      "description": "Announce that an agent connected. One anonymous GET that increments a public counter shown on the home page, so the lab can tell whether agents actually use this protocol. No identity, no payload, no lab-side logging. Call once per session. Read the count without incrementing at https://abacus.jasoncameron.dev/get/chengguruchun-lab/agent-connect.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "contract": {
        "sideEffects": [
          "increments public counter chengguruchun-lab/agent-connect"
        ],
        "requiresApproval": false,
        "idempotencyKey": "one call per agent session",
        "rollback": "n/a",
        "timeoutSeconds": 15
      },
      "static": {
        "method": "GET",
        "url": "https://abacus.jasoncameron.dev/hit/chengguruchun-lab/agent-connect",
        "note": "Third-party counter (abacus.jasoncameron.dev). Skip if your policy forbids third-party calls — everything else in this lab still works."
      }
    },
    {
      "name": "lab_list_entries",
      "kind": "read",
      "description": "List knowledge entries from catalog: Articles, Diverse Lab, Times (Hot Words), etc. Filter with type. Projects live under /api/projects.json (+ projects-research / projects-personal); Videos under /api/videos.json (page-only, not in catalog).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Optional filter: Articles | Diverse Lab | Times (Projects/Videos use dedicated APIs)"
          }
        }
      },
      "static": {
        "method": "GET",
        "path": "/api/catalog.json",
        "alt_by_type": "/api/{type-slug}.json"
      }
    },
    {
      "name": "lab_list_articles",
      "kind": "read",
      "description": "List articles only (shorthand for catalog filter Articles).",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/articles.json"
      }
    },
    {
      "name": "lab_list_projects_research",
      "kind": "read",
      "description": "List curated research GitHub repos (static snapshot for agents).",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/projects-research.json"
      }
    },
    {
      "name": "lab_list_projects_personal",
      "kind": "read",
      "description": "List top personal non-fork GitHub repos excluding *.github.io (static snapshot).",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/projects-personal.json"
      }
    },
    {
      "name": "lab_list_projects",
      "kind": "read",
      "description": "Projects overview (research + personal sections). Prefer section APIs for agents.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/projects.json"
      }
    },
    {
      "name": "lab_get_entry",
      "kind": "read",
      "description": "Fetch one entry's canonical Markdown. Prefer the catalog item's `content` or `markdown` field (always a working path). The path_template `/content/{collection}/{id}.md` only works when id equals the file stem. Times ids look like `times-2026-09-w3` while files are `/content/times/2026-09-w3.md` — use catalog `markdown` or `slug` (e.g. slug=2026-09-w3 → /content/times/{slug}.md).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Entry id from catalog, e.g. k8s-to-agent-control-plane"
          }
        },
        "required": [
          "id"
        ]
      },
      "static": {
        "method": "GET",
        "path_template": "/content/{collection}/{id}.md",
        "collections": {
          "Articles": "articles",
          "Diverse Lab": "diverse",
          "Times": "times"
        },
        "resolve_collection_via": "/api/catalog.json",
        "prefer_catalog_fields": [
          "content",
          "markdown"
        ],
        "slug_field": "slug"
      }
    },
    {
      "name": "lab_search_entries",
      "kind": "read",
      "description": "Search published knowledge only: client-filter /api/catalog.json by title, excerpt, and tags. Does not search the Thoughts pipeline; if no sufficient result, query lab_list_thoughts / lab_get_thought.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "tag": {
            "type": "string"
          }
        },
        "required": [
          "query"
        ]
      },
      "static": {
        "method": "GET",
        "path": "/api/catalog.json",
        "client_filter": true
      }
    },
    {
      "name": "lab_list_tags",
      "kind": "read",
      "description": "List tags and entry ids under each tag.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/tags.json"
      }
    },
    {
      "name": "lab_get_about",
      "kind": "read",
      "description": "Owner stance and The Road Here (bio route). HTML page; no private contact beyond published footer.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/about/"
      }
    },
    {
      "name": "lab_follow_github",
      "kind": "engage",
      "description": "Follow / star the owner's GitHub (chengguruchun). Opens the profile for the agent or human to complete follow.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "ACTION",
        "action": "open",
        "url": "https://github.com/chengguruchun",
        "note": "Prefer Follow on the profile; site repo: https://github.com/chengguruchun/chengguruchun.github.io"
      }
    },
    {
      "name": "lab_subscribe_email",
      "kind": "engage",
      "description": "Subscribe to article updates by email. Opens a mailto draft to the owner with a Subscribe subject.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "from_name": {
            "type": "string",
            "description": "Optional subscriber name"
          },
          "note": {
            "type": "string",
            "description": "Optional interest note"
          }
        }
      },
      "static": {
        "method": "ACTION",
        "action": "mailto",
        "to": "chengguruchun@163.com",
        "subject_template": "Subscribe · AI Knowledge Lab",
        "body_template": "Please add me to article updates.\\n\\nName: {from_name}\\nNote: {note}",
        "note": "P0: mailto handshake. Future: dedicated subscribe endpoint without changing SKILL.md."
      }
    },
    {
      "name": "lab_submit_issue",
      "kind": "contribute",
      "description": "Propose an idea / fix / knowledge patch like a GitHub issue. Human reviews; accepted items may merge into the Lab.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string",
            "description": "Markdown proposal: context, ask, links"
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional hints: idea | fix | content | agent"
          }
        },
        "required": [
          "title",
          "body"
        ]
      },
      "static": {
        "method": "ACTION",
        "action": "open",
        "url_template": "https://github.com/chengguruchun/chengguruchun.github.io/issues/new?title={title}&body={body}",
        "note": "P0: GitHub Issues as intake. Review → merge into content/tools. Future: /api/issues without SKILL edits."
      }
    },
    {
      "name": "lab_get_llms_txt",
      "kind": "read",
      "description": "Machine-oriented site map (llms.txt).",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/llms.txt"
      }
    },
    {
      "name": "lab_subscribe_rss",
      "kind": "engage",
      "description": "Subscribe to Lab content via real RSS at /feed.xml (auto-rebuilt by scripts/build_feeds.py + GitHub Action on content push).",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/feed.xml"
      }
    },
    {
      "name": "lab_watch_repo",
      "kind": "engage",
      "description": "Open GitHub Watch settings for the site repo (real subscription). Prefer commits.atom for feed-based watching.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "ACTION",
        "action": "open",
        "url": "https://github.com/chengguruchun/chengguruchun.github.io/subscription",
        "also": {
          "commits_atom": "https://github.com/chengguruchun/chengguruchun.github.io/commits/main.atom",
          "feeds_index": "/api/feeds.json"
        }
      }
    },
    {
      "name": "lab_list_feeds",
      "kind": "read",
      "description": "List all Lab subscription endpoints: content RSS, GitHub Watch URL, commits/releases Atom.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/feeds.json"
      }
    },
    {
      "name": "lab_list_times",
      "kind": "read",
      "description": "Alias of lab_hot_words_state for Times listing. Prefer lab_hot_words_state for Hot Words lifecycle.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/times.json"
      }
    },
    {
      "name": "lab_list_comments",
      "kind": "read",
      "description": "List page comments stored as GitHub Issues containing marker [lab-comment:<pageId>].",
      "inputSchema": {
        "type": "object",
        "properties": {
          "pageId": {
            "type": "string",
            "description": "e.g. physics-ecology-llm"
          }
        },
        "required": [
          "pageId"
        ]
      },
      "static": {
        "method": "GET",
        "url_template": "https://api.github.com/search/issues?q=repo:chengguruchun/chengguruchun.github.io+is:issue+in:body+%22[lab-comment:{pageId}]%22"
      }
    },
    {
      "name": "lab_post_comment",
      "kind": "contribute",
      "description": "Open a GitHub Issue to leave a comment on a Lab page (marker [lab-comment:<pageId>]).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "pageId": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "pageUrl": {
            "type": "string"
          }
        },
        "required": [
          "pageId",
          "body"
        ]
      },
      "static": {
        "method": "ACTION",
        "action": "open",
        "url_template": "https://github.com/chengguruchun/chengguruchun.github.io/issues/new?title={title}&body={body}",
        "body_template": "[lab-comment:{pageId}]\\nPage: {pageUrl}\\nAuthor: {author}\\n\\n{body}"
      }
    },
    {
      "name": "lab_hot_words_status",
      "kind": "read",
      "description": "Deprecated alias of lab_hot_words_state. Prefer lab_hot_words_state.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "static": {
        "method": "GET",
        "path": "/api/times.json"
      }
    },
    {
      "name": "lab_hot_words_list",
      "kind": "read",
      "description": "List Hot Words issues (current + history) from /api/times.json.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "static": {
        "method": "GET",
        "path": "/api/times.json"
      }
    },
    {
      "name": "lab_hot_words_apply",
      "kind": "contribute",
      "description": "Apply an approved Hot Words proposal to the LOCAL workspace only (scripts/hot_words_apply.py). Does NOT commit, push, or publish. Phase: Apply. Monday GitHub Actions auto-publishes the weekly Hot Words run; this tool only mutates the local workspace.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string"
          },
          "word": {
            "type": "string"
          },
          "why": {
            "type": "string"
          },
          "dryRun": {
            "type": "boolean"
          }
        },
        "required": [
          "period",
          "word",
          "why"
        ]
      },
      "contract": {
        "sideEffects": [
          "write_local_files"
        ],
        "requiresApproval": false,
        "idempotencyKey": "period",
        "rollback": "git checkout -- times/ content/times api/times.json content/index.json api/catalog.json",
        "timeoutSeconds": 120
      },
      "static": {
        "method": "ACTION",
        "action": "local",
        "command_template": "python3 scripts/hot_words_apply.py --period {period} --word {word} --why {why}"
      }
    },
    {
      "name": "lab_hot_words_state",
      "kind": "read",
      "description": "Read Hot Words state: current period/word, recent history (api/times.json). Phase: State (no side effects).",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "contract": {
        "sideEffects": [],
        "requiresApproval": false,
        "idempotencyKey": "none",
        "rollback": "n/a",
        "timeoutSeconds": 30
      },
      "static": {
        "method": "GET",
        "path": "/api/times.json"
      }
    },
    {
      "name": "lab_hot_words_run_status",
      "kind": "read",
      "description": "Observe latest Hot Words run manifest (phase, gates, proposal, publish). GET /api/hot-words/runs/latest.json or /api/hot-words/runs/{runId}.json. Prefer this over parsing GitHub Actions logs.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "runId": {
            "type": "string",
            "description": "Optional run id; omit for latest"
          }
        },
        "additionalProperties": false
      },
      "contract": {
        "sideEffects": [],
        "requiresApproval": false,
        "idempotencyKey": "runId|latest",
        "rollback": "n/a",
        "timeoutSeconds": 30
      },
      "static": {
        "method": "GET",
        "path": "/api/hot-words/runs/latest.json"
      }
    },
    {
      "name": "lab_hot_words_propose",
      "kind": "contribute",
      "description": "Propose 3–5 Hot Words candidates with structured evidence when possible. Today: performed inside GitHub Actions (DeepSeek). No local side effects via static HTTP; agents should treat this as the Propose phase contract.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string"
          },
          "context": {
            "type": "object"
          }
        },
        "required": [
          "period"
        ]
      },
      "contract": {
        "sideEffects": [],
        "requiresApproval": false,
        "idempotencyKey": "period + contextHash",
        "rollback": "n/a",
        "timeoutSeconds": 120
      },
      "static": {
        "method": "ACTION",
        "action": "workflow",
        "note": "Embedded in hot-words-weekly.yml DeepSeek step; not a standalone HTTP endpoint yet."
      }
    },
    {
      "name": "lab_hot_words_validate",
      "kind": "read",
      "description": "Validate proposal: schema, duplicate (word or proposalHash), editorial why length, evidence (https URL required to publish), relevance, optional consistency after apply.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string"
          },
          "word": {
            "type": "string"
          },
          "why": {
            "type": "string"
          },
          "candidates": {
            "type": "array"
          },
          "force": {
            "type": "boolean"
          }
        },
        "required": [
          "period",
          "word",
          "why"
        ]
      },
      "contract": {
        "sideEffects": [],
        "requiresApproval": false,
        "idempotencyKey": "period + word",
        "rollback": "n/a",
        "timeoutSeconds": 30
      },
      "static": {
        "method": "ACTION",
        "action": "local",
        "command_template": "python3 scripts/hot_words_validate.py --period {period} --word {word} --why {why}"
      }
    },
    {
      "name": "lab_hot_words_publish",
      "kind": "action",
      "description": "Publish applied Hot Words. HIGH RISK. Autonomous: Actions commit/push after evidence+consistency gates. Review: stop at awaiting_review (workflow_dispatch mode=review). Apply is never publish.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string"
          },
          "proposalId": {
            "type": "string"
          },
          "approval": {
            "type": "boolean",
            "description": "Explicit approval required by contract"
          },
          "mode": {
            "type": "string",
            "enum": [
              "autonomous",
              "review"
            ]
          }
        },
        "required": [
          "period",
          "approval"
        ]
      },
      "contract": {
        "sideEffects": [
          "git_commit",
          "git_push",
          "pages_deploy"
        ],
        "requiresApproval": true,
        "idempotencyKey": "period + proposalId",
        "rollback": "revert_commit",
        "timeoutSeconds": 600
      },
      "static": {
        "method": "ACTION",
        "action": "workflow",
        "workflow": ".github/workflows/hot-words-weekly.yml",
        "note": "Schedule defaults to autonomous. workflow_dispatch can set mode=review."
      }
    },
    {
      "name": "lab_hot_words_feedback",
      "kind": "read",
      "description": "Observe Hot Words feedback + learnHints for next Propose (api/hot-words/feedback.json). Includes lastRun gates, rejected candidates, and signal placeholders (votes/visits/comments).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string"
          }
        }
      },
      "contract": {
        "sideEffects": [],
        "requiresApproval": false,
        "idempotencyKey": "period|latest",
        "rollback": "n/a",
        "timeoutSeconds": 30
      },
      "static": {
        "method": "GET",
        "path": "/api/hot-words/feedback.json"
      }
    },
    {
      "name": "lab_agent_native_status",
      "kind": "read",
      "description": "Observe the latest Agent-native weekly check (surfaces, discover→execute, canonical Markdown, tool parity). GET /api/agent-native/runs/latest.json. Criteria: /api/agent-native/criteria.json.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "contract": {
        "sideEffects": [],
        "requiresApproval": false,
        "idempotencyKey": "runId|latest",
        "rollback": "n/a",
        "timeoutSeconds": 30
      },
      "static": {
        "method": "GET",
        "path": "/api/agent-native/runs/latest.json"
      }
    },
    {
      "name": "lab_list_thoughts",
      "kind": "read",
      "description": "List thought-loop items. Inbound from any Skill-loading agent is stage=topic (distilled chat, not a conclusion). Filter by stage, origin, or route. Only published items are conclusions. Hot Words is a separate weekly loop.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "stage": {
            "type": "string",
            "description": "topic | candidate | validated | article_candidate | published"
          },
          "origin": {
            "type": "string",
            "description": "user | ai | joint | external"
          },
          "route": {
            "type": "string",
            "description": "diverse | articles | videos | projects"
          }
        },
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/thoughts.json",
        "client_filter": true
      }
    },
    {
      "name": "lab_get_thought",
      "kind": "read",
      "description": "Fetch one thought JSON by id. Canonical file is /content/thoughts/{id}.json. Topics are inbound experiments, not articles.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Thought id, e.g. thought-rl-vs-finetune"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path_template": "/content/thoughts/{id}.json"
      }
    },
    {
      "name": "lab_propose_topic",
      "kind": "contribute",
      "description": "File an inbound idea as stage=topic: one distilled sentence plus origin. No transcript. Does not write catalog or Articles. Promote only after gates in /api/thoughts.json.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "thought": {
            "type": "string",
            "description": "One distilled sentence. Not a chat log."
          },
          "origin": {
            "type": "string",
            "description": "user | ai | joint | external"
          },
          "contribution": {
            "type": "string",
            "description": "known | synthesis | extension | original_candidate"
          },
          "source_note": {
            "type": "string",
            "description": "Why this is a topic. Do not paste the transcript."
          }
        },
        "required": [
          "thought",
          "origin"
        ],
        "additionalProperties": false
      },
      "contract": {
        "sideEffects": [
          "content/thoughts/*.json"
        ],
        "requiresApproval": true,
        "idempotencyKey": "thought sentence",
        "rollback": "delete the topic file",
        "timeoutSeconds": 30
      },
      "static": {
        "method": "ACTION",
        "action": "pr",
        "path": "/content/thoughts/",
        "note": "Open a PR with stage=topic JSON. Human review. Never write Articles from this tool."
      }
    },
    {
      "name": "lab_thought_validate",
      "kind": "read",
      "description": "Read field gates[] and model_gates[] on /api/thoughts.json. Field = script. Model = criteria prompt. Pending/stale is not a ship. Do not treat topic or candidate as conclusions.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Optional thought id to inspect"
          }
        },
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/thoughts.json",
        "client_filter": true
      }
    },
    {
      "name": "lab_thought_criteria",
      "kind": "read",
      "description": "Read the living model-gate standard: prompt + axes + changelog. Improve by editing /content/thoughts/criteria.json and bumping version. Old judgements become stale.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/thoughts-criteria.json"
      }
    },
    {
      "name": "lab_thought_judge",
      "kind": "contribute",
      "description": "Run the current criteria prompt on one thought. Write only judgement (criteria_version + verdicts). Do not change stage, route, catalog, or article bodies. Do not paste transcripts.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Thought id to judge"
          },
          "model": {
            "type": "string",
            "description": "Model name that produced the verdicts"
          },
          "criteria_version": {
            "type": "string",
            "description": "Must match /api/thoughts-criteria.json version"
          },
          "verdicts": {
            "type": "array",
            "description": "One verdict per current axis: sharp, evidence_real, route_fit",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "pass": {
                  "type": "boolean"
                },
                "note": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "pass"
              ]
            }
          }
        },
        "required": [
          "id",
          "criteria_version",
          "verdicts"
        ],
        "additionalProperties": false
      },
      "contract": {
        "sideEffects": [
          "content/thoughts/{id}.json judgement"
        ],
        "requiresApproval": true,
        "idempotencyKey": "thought id + criteria_version",
        "rollback": "remove judgement",
        "timeoutSeconds": 60
      },
      "static": {
        "method": "ACTION",
        "action": "pr",
        "path": "/content/thoughts/",
        "note": "Open a PR that only updates judgement. Re-run build_thoughts.py. Never write Articles from this tool."
      }
    },
    {
      "name": "lab_knowledge_status",
      "kind": "read",
      "description": "Read published-knowledge freshness: status, last_verified, next_review, cadence. Times/Hot Words are excluded. stale means overdue, not wrong.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Optional entry id to inspect"
          }
        },
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/knowledge.json",
        "client_filter": true
      }
    },
    {
      "name": "lab_knowledge_due",
      "kind": "read",
      "description": "List registry items that need review (stale / changed / contested). Filter knowledge.due == true.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/knowledge.json",
        "client_filter": true
      }
    },
    {
      "name": "lab_knowledge_criteria",
      "kind": "read",
      "description": "Read the living post-publish verifier standard: prompt + cadence + changelog. Old reports with a different version are stale judgements, not wrong articles.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/knowledge-criteria.json"
      }
    },
    {
      "name": "lab_knowledge_run_status",
      "kind": "read",
      "description": "Observe the latest knowledge lifecycle run manifest.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/knowledge/runs/latest.json"
      },
      "contract": {
        "sideEffects": [],
        "requiresApproval": false,
        "idempotencyKey": "runId|latest",
        "rollback": "n/a",
        "timeoutSeconds": 30
      }
    },
    {
      "name": "lab_knowledge_report",
      "kind": "contribute",
      "description": "Judge one published entry after Observe (cited URL fetch + arXiv lookup). Write only a report under content/knowledge/reports/. Do not change article bodies, catalog stage, or last_verified.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entry_id": {
            "type": "string",
            "description": "Catalog id to verify"
          },
          "criteria_version": {
            "type": "string",
            "description": "Must match /api/knowledge-criteria.json version"
          },
          "verdict": {
            "type": "string",
            "description": "unchanged | changed | insufficient | obsolete"
          },
          "note": {
            "type": "string",
            "description": "One-sentence reason"
          },
          "evidence": {
            "type": "array",
            "description": "changed/obsolete require at least one https URL that this run observed (or that still resolves, for hand-filed reports)",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              },
              "required": [
                "url"
              ]
            }
          },
          "proposed_change": {
            "type": "string",
            "description": "Optional patch description. Not the rewritten article."
          },
          "model": {
            "type": "string"
          }
        },
        "required": [
          "entry_id",
          "criteria_version",
          "verdict"
        ],
        "additionalProperties": false
      },
      "contract": {
        "sideEffects": [
          "content/knowledge/reports/*.json"
        ],
        "requiresApproval": true,
        "idempotencyKey": "entry_id + period",
        "rollback": "delete the report file",
        "timeoutSeconds": 90
      },
      "static": {
        "method": "ACTION",
        "action": "pr",
        "path": "/content/knowledge/reports/",
        "note": "Open a PR with a report JSON only. Run python3 scripts/knowledge_verify.py --file. Never write Articles from this tool."
      }
    },
    {
      "name": "lab_knowledge_review",
      "kind": "contribute",
      "description": "Human decision: keep (refresh last_verified), or pin changed / contested / archived. Does not rewrite the article body.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "decision": {
            "type": "string",
            "description": "keep | changed | contested | archived"
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "decision"
        ],
        "additionalProperties": false
      },
      "contract": {
        "sideEffects": [
          "content/knowledge/overrides/{id}.json"
        ],
        "requiresApproval": true,
        "idempotencyKey": "id + decision + date",
        "rollback": "delete or edit the override",
        "timeoutSeconds": 30
      },
      "static": {
        "method": "ACTION",
        "action": "local",
        "command_template": "python3 scripts/knowledge_review.py --id {id} --decision {decision}",
        "note": "Human only. Rebuilds the registry. Does not ghostwrite."
      }
    },
    {
      "name": "lab_list_critic_runs",
      "kind": "read",
      "description": "List Critic Lab advisory runs (id, article slug, paths to .json/.md).",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path": "/api/critic/runs/index.json"
      }
    },
    {
      "name": "lab_get_critic_run",
      "kind": "read",
      "description": "Fetch one Critic Lab run Markdown (or JSON) by run id / filename stem.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Run id / filename stem from lab_list_critic_runs, e.g. from-llm-to-agent-runtime-ce772183bd74"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false
      },
      "static": {
        "method": "GET",
        "path_template": "/api/critic/runs/{id}.md",
        "alt_path_template": "/api/critic/runs/{id}.json",
        "index": "/api/critic/runs/index.json"
      }
    }
  ],
  "updated": "2026-09-21"
}
