Skip to content

knowledge_base.candidates

Every knowledge record with status candidate under the candidates source class: its class, its assertion, the episode it came from and that episode's branch, and how long it has waited — measured from the derivation that wrote it, then the commit that added it, then its own date — judged against session.freshness; against the policy's cap. A candidate whose episode this checkout does not know is reported with no branch rather than hidden. Ordered by id.

Every knowledge record with status candidate under the candidates source class: its class, its assertion, the episode it came from and that episode's branch, and how long it has waited — measured from the derivation that wrote it, then the commit that added it, then its own date — judged against session.freshness; against the policy's cap. A candidate whose episode this checkout does not know is reported with no branch rather than hidden. Ordered by id.

Exposure

Where this one definition is reachable. Absence is explicit: a surface not listed does not carry it.

surfaceas
MCPtool majordomus_knowledge_candidates
resource majordomus://knowledge-candidates
HTTPGET /api/v1/knowledge/candidates operationId knowledge_base.candidates
command linemajordomus knowledge candidates

Schemas

The canonical input and output, from the Rust types; the MCP tool schema and the OpenAPI parameters and responses are derived from these.

input · Empty

No input.

No properties: the capability takes no input.

JSON Schema
{
  "additionalProperties": false,
  "description": "No input.",
  "title": "Empty",
  "type": "object"
}

output · KnowledgeCandidates

The candidates awaiting review, against the policy's cap.

use majordomus_cli::capability::builtin::knowledge_base::KnowledgeCandidates;
let empty: KnowledgeCandidates = serde_json::from_str(
    r#"{"total":0,"on_this_branch":0,"unattributed":0,"branch":"master","candidates":[],"over_cap":false}"#,
).unwrap();
assert_eq!(empty.total, 0, "an empty queue is an answer");
assert_eq!(empty.cap, None, "and a policy without the key declares no cap");
propertytyperequireddescription
branch string yes The branch this answer is about, or DETACHED.
candidates array no Every candidate, in canonical order of id.
cap integer | null no knowledge.candidates_max_files, when the policy declares it.
findings array no What a reader should know before trusting the above: a malformed record that was skipped, a cap that was exceeded, a policy that declares none. Empty is the good case.
groups array no The candidates and rejected records derived from observations, grouped by what they are about, in order of subject.
on_this_branch integer yes How many of them came from an episode on this checkout's branch.
over_cap boolean yes True when total exceeds cap. False when no cap is declared: nobody wrote one down.
total integer yes How many records carry status: candidate under the candidates class.
unattributed integer yes How many name an episode this checkout knows nothing about.
JSON Schema
{
  "$defs": {
    "AgeSource": {
      "description": "Where the age of a candidate in the review queue was read from. A candidate's `date` is\nthe day of the evidence it came from, deliberately, so that the same evidence yields the\nsame bytes; the day it entered the queue is a different fact and is read from the ledger\nfirst, then from git, and only then from the record.\n\n```\nuse majordomus_cli::capability::builtin::knowledge_base::AgeSource;\nlet from_ledger: AgeSource = serde_json::from_str(r#\"\"derivation\"\"#).unwrap();\nassert_eq!(from_ledger, AgeSource::Derivation);\nassert!(AgeSource::Derivation < AgeSource::Date, \"the ledger is asked before the record\");\n```",
      "oneOf": [
        {
          "const": "derivation",
          "description": "The oldest `knowledge.derived` line in this checkout's ledger whose paths name it.",
          "type": "string"
        },
        {
          "const": "commit",
          "description": "The commit that added the file to this history.",
          "type": "string"
        },
        {
          "const": "date",
          "description": "The record's own `date`, at midnight UTC: the evidence day, not the queue day.",
          "type": "string"
        }
      ]
    },
    "Freshness": {
      "description": "How old a record is, judged against `session.freshness` in the policy.\n\nThis is the second of two independent judgements every record carries, and it exists\nbecause the first one cannot answer this question. `Divergence` says where a record's\ncommit sits relative to HEAD; `advanced` means that commit is an ancestor of this one,\nwhich sounds like agreement and is identically true on the day the record is written and\na month later. Between 2026-09-05 and 2026-09-11 this repository served a handover that\nwas `advanced` and six days dead, and every surface that read this model — MCP, the HTTP\nAPI, the Cockpit — presented its `Next Action` as the thing to do (ADR 0052).\n\nThe thresholds are policy and are read, never restated here: a constant in this file\nwould be a second source of truth for a number the policy owns, and a repository whose\npolicy predates the key is reported as `Freshness::Unknown` naming the missing key\nrather than judged against a default nobody declared.\n\nThe five words divide into two groups, and the division is the one a caller acts on:\n`fresh` and `aging` are current and may be presented as the instruction, `stale` and\n`invalid` must be shown as history, and `unknown` is neither — a record nobody can date\nis not thereby an old record, and treating it as one would quietly discard a briefing\nthat is perfectly good. `Freshness::history` is that division, and it is the only\nplace it is decided.\n\n```\nuse majordomus_cli::capability::builtin::continuity::Freshness;\n\n// the two renderings are one value: the serialised word is the word `as_str` gives,\n// so a reader who met `stale` from MCP and from the command line met one fact\nlet stale = serde_json::to_value(Freshness::Stale).unwrap();\nassert_eq!(stale, serde_json::json!(\"stale\"));\nassert_eq!(stale.as_str(), Some(Freshness::Stale.as_str()));\n\n// and the division a caller acts on: absence of a judgement is not a bad judgement\nassert!(Freshness::Stale.history() && Freshness::Invalid.history());\nassert!(!Freshness::Unknown.history(), \"undated is not old\");\nassert!(!Freshness::Fresh.history() && !Freshness::Aging.history());\n```",
      "oneOf": [
        {
          "const": "fresh",
          "description": "Inside `session.freshness.fresh_minutes`. Current; act on it.",
          "type": "string"
        },
        {
          "const": "aging",
          "description": "Between the two thresholds. Still current, but its age is worth stating.",
          "type": "string"
        },
        {
          "const": "stale",
          "description": "At or beyond `session.freshness.stale_minutes`. History, never current.",
          "type": "string"
        },
        {
          "const": "unknown",
          "description": "Nothing to judge it by: no timestamp, or no thresholds declared.",
          "type": "string"
        },
        {
          "const": "invalid",
          "description": "A timestamp that does not parse, or one in the future.",
          "type": "string"
        }
      ]
    },
    "KnowledgeCandidate": {
      "description": "One candidate record awaiting review: what a reader needs to decide whether to open it.\n\n```\nuse majordomus_cli::capability::builtin::knowledge_base::KnowledgeCandidate;\nlet c: KnowledgeCandidate = serde_json::from_str(r#\"{\n  \"id\": \"e1-0123456789ab\", \"uri\": \"majordomus://knowledge/e1-0123456789ab\",\n  \"path\": \".ai/repo/knowledge/candidates/e1-0123456789ab.md\", \"class\": \"convention\",\n  \"status\": \"candidate\", \"epistemics\": \"decided\", \"title\": \"Tests run in disposable repositories\",\n  \"date\": \"2026-09-12\", \"derived_from\": [\"session:e1\"], \"episode\": \"e1\",\n  \"freshness\": \"unknown\", \"freshness_reason\": \"no timestamp\", \"age_source\": \"date\"\n}\"#).unwrap();\nassert_eq!(c.episode, \"e1\");\nassert_eq!(c.branch, None, \"an episode this checkout never saw has no branch, and says so\");\n```",
      "properties": {
        "about": {
          "description": "What the observation it was derived from is about (ADR 0118); empty for a record\nderived from anything else.",
          "type": "string"
        },
        "age_minutes": {
          "description": "The wait in whole minutes, when it could be measured.",
          "format": "int64",
          "type": [
            "integer",
            "null"
          ]
        },
        "age_source": {
          "$ref": "#/$defs/AgeSource",
          "description": "Where the wait was read from."
        },
        "branch": {
          "default": null,
          "description": "The branch that episode ran on, joined to the tracked session record or, while that\nis not yet written, to the ledger's `session.started` line. `None` when this checkout\nknows nothing about the episode — named rather than hidden, so that a reader can tell\n\"not this branch\" from \"not known here\". Serialised as `null` in that case, never\nomitted.",
          "type": [
            "string",
            "null"
          ]
        },
        "class": {
          "description": "`fact`, `convention`, `constraint`, `memory` or `lesson`.",
          "type": "string"
        },
        "date": {
          "description": "The day of the evidence, `YYYY-MM-DD`.",
          "type": "string"
        },
        "derived_from": {
          "description": "The typed references the record names as its evidence, as declared.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "episode": {
          "description": "The episode the record came from: the `session:` reference, or empty when it names none.",
          "type": "string"
        },
        "epistemics": {
          "description": "`observed`, `inferred` or `decided`.",
          "type": "string"
        },
        "freshness": {
          "$ref": "#/$defs/Freshness",
          "description": "How long it has waited, judged against `session.freshness`."
        },
        "freshness_reason": {
          "description": "Why it was judged that way, in one phrase. Never empty.",
          "type": "string"
        },
        "id": {
          "description": "The record id, which is also its file name.",
          "type": "string"
        },
        "path": {
          "description": "Repository-relative path.",
          "type": "string"
        },
        "route": {
          "description": "Which owner should look first, derived from `about`'s structure; empty without one.",
          "type": "string"
        },
        "status": {
          "description": "Always `candidate` here; carried so that a reader sees the same record shape as `record`.",
          "type": "string"
        },
        "title": {
          "description": "The assertion, in one line.",
          "type": "string"
        },
        "uri": {
          "description": "`majordomus://knowledge/<id>`.",
          "type": "string"
        }
      },
      "required": [
        "id",
        "uri",
        "path",
        "class",
        "status",
        "epistemics",
        "title",
        "date",
        "freshness",
        "freshness_reason",
        "age_source"
      ],
      "type": "object"
    },
    "KnowledgeGroup": {
      "description": "The records under one subject: every candidate awaiting review and every rejected one,\nwith the episodes behind them (ADR 0118). Recurrence is read here, never written: each\nrecord stays one episode's own file, and a group is how several of them read as one thing.\n\n```\nuse majordomus_cli::capability::builtin::knowledge_base::KnowledgeGroup;\nlet g: KnowledgeGroup = serde_json::from_str(\n    r#\"{\"about\":\"lib/a.sh\",\"route\":\"project\",\"candidates\":[\"e1-a\",\"e2-b\"],\"episodes\":[\"e1\",\"e2\"]}\"#,\n).unwrap();\nassert_eq!(g.episodes.len(), 2, \"two episodes observed it\");\nassert!(g.rejected.is_empty(), \"and nobody rejected it\");\n```",
      "properties": {
        "about": {
          "description": "The subject, as written.",
          "type": "string"
        },
        "candidates": {
          "description": "The candidates awaiting review, by id.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "episodes": {
          "description": "The episodes behind all of them, each once, in order.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "rejected": {
          "description": "The records rejected and kept, by id.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "route": {
          "description": "The route of its records.",
          "type": "string"
        }
      },
      "required": [
        "about",
        "route"
      ],
      "type": "object"
    }
  },
  "description": "The candidates awaiting review, against the policy's cap.\n\n```\nuse majordomus_cli::capability::builtin::knowledge_base::KnowledgeCandidates;\nlet empty: KnowledgeCandidates = serde_json::from_str(\n    r#\"{\"total\":0,\"on_this_branch\":0,\"unattributed\":0,\"branch\":\"master\",\"candidates\":[],\"over_cap\":false}\"#,\n).unwrap();\nassert_eq!(empty.total, 0, \"an empty queue is an answer\");\nassert_eq!(empty.cap, None, \"and a policy without the key declares no cap\");\n```",
  "properties": {
    "branch": {
      "description": "The branch this answer is about, or `DETACHED`.",
      "type": "string"
    },
    "candidates": {
      "description": "Every candidate, in canonical order of id.",
      "items": {
        "$ref": "#/$defs/KnowledgeCandidate"
      },
      "type": "array"
    },
    "cap": {
      "description": "`knowledge.candidates_max_files`, when the policy declares it.",
      "format": "uint",
      "minimum": 0,
      "type": [
        "integer",
        "null"
      ]
    },
    "findings": {
      "description": "What a reader should know before trusting the above: a malformed record that was\nskipped, a cap that was exceeded, a policy that declares none. Empty is the good case.",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "groups": {
      "description": "The candidates and rejected records derived from observations, grouped by what they\nare about, in order of subject.",
      "items": {
        "$ref": "#/$defs/KnowledgeGroup"
      },
      "type": "array"
    },
    "on_this_branch": {
      "description": "How many of them came from an episode on this checkout's branch.",
      "format": "uint",
      "minimum": 0,
      "type": "integer"
    },
    "over_cap": {
      "description": "True when `total` exceeds `cap`. False when no cap is declared: nobody wrote one down.",
      "type": "boolean"
    },
    "total": {
      "description": "How many records carry `status: candidate` under the candidates class.",
      "format": "uint",
      "minimum": 0,
      "type": "integer"
    },
    "unattributed": {
      "description": "How many name an episode this checkout knows nothing about.",
      "format": "uint",
      "minimum": 0,
      "type": "integer"
    }
  },
  "required": [
    "total",
    "on_this_branch",
    "unattributed",
    "branch",
    "over_cap"
  ],
  "title": "KnowledgeCandidates",
  "type": "object"
}

Policies

benchmark
required — a target on every transport the exposure declares; the cases are the input type's
cache
disabled — every call runs the handler

Benchmark targets

Derived from the registry for this repository: one requirement per transport, and the cases the input type provides. The whole matrix is on the benchmarks page.

transportstatecasestargets
directcovered1default
mcpcovered1default
httpcovered1default

Claims implemented beside it

Attached by the file that implements each claim; every one links to its page with the implementation and the test that proves it.

Searches the titles and descriptions of every page this site publishes.