Skip to content

HTTP API: intents

What must become true above the milestones that realise it: each intent's statement, invariants and satisfaction criteria, its stage derived from the plan's milestone status, each criterion's state derived from the evidence ledger, and its verdict derived from those criteria alone. Nothing is stored and nothing transitions; an intent added under the project model is answered by all of these without a registration anywhere.

Rendered from docs/generated/openapi.json, which the executable generates from its capability registry and CI refuses stale. The raw document is at /openapi.json; a running server serves the same document at its own /openapi.json and Swagger UI at /swagger.

intents

What must become true above the milestones that realise it: each intent's statement, invariants and satisfaction criteria, its stage derived from the plan's milestone status, each criterion's state derived from the evidence ledger, and its verdict derived from those criteria alone. Nothing is stored and nothing transitions; an intent added under the project model is answered by all of these without a registration anywhere.

GET /api/v1/intents intents.list

Every intent, with its derived stage and verdict

Every intent the project model declares, each with the status the plan derives for its milestones, the state of the evidence behind each satisfaction criterion, the stage those two derive — declared, planned, executing, verifying or satisfied, or cancelled or superseded when the record says so — and the verdict the criteria alone derive (ADR 0107): satisfied when every criterion is met, unsatisfied when a test or claim criterion is not, unknown when only command or deployment criteria are unmet or none is declared, with the criteria holding it back.

  • query
  • behaviorally_verified
  • benchmark required
  • cache checkout (max_entries=2)
  • MCP tool majordomus_intents
  • MCP resource {"name": "intents", "uri": "majordomus://intents"}
  • $ intent list

No parameters.

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/intents"

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 IntentList Every intent, with its derived stage and verdict: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.
GET /api/v1/intents/binding intents.binding

What a piece of work is bound to before it starts

What a task asks before it starts (ADR 0111): given the issue the work executes, the intent it serves, the paths it will touch, or an exemption class with its reason, one standing — `bound` when the work serves a criterion of a live intent through links the preflight accepts, `maintenance` when its issues sit under milestones no live intent names, `exempt` when the class is one the policy declares under `intent.exemptions` and a reason was given, `refused` otherwise, each refusal with a cause: the preflight's own seven, and nothing_named, unknown_intent, intent_retired, intent_has_no_open_work, issue_outside_intent, ambiguous_intent (paths alone reached more than one intent), unknown_exemption, exemption_without_reason, exemption_names_work. The answer carries what was named, the issues and intents resolved with what each intent asks of the worker, a note when the paths lie outside the named issue's scope, and two pins a later reader compares: `plan_revision`, which moves when the intent, a link or the critique is edited, and `evidence_standing`, which moves when a served criterion's evidence changes state. Nothing is stored.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_intent_binding
  • $ intent binding

Query parameters

nametyperequireddescriptionexamples
issue string no The issue the work executes, by id. first-issue: "I0001"
intent string no The intent the work serves, by id, when the worker names it directly.
paths string no Repository-relative paths the work will touch, separated by commas. first-issue: ""
exemption string no An exemption class the policy declares under `intent.exemptions`.
because string no Why the exemption applies.

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/intents/binding?issue=I0001&paths="

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 IntentBinding What a piece of work is bound to before it starts: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.
GET /api/v1/intents/coverage intents.coverage

Which work carries which criterion, and why each issue exists

The plan read against the intents (ADR 0073): every criterion of every live intent with the live issues that serve it, the milestones they belong to, and its strength — covered, weakly covered when no serving issue requires evidence, observed when the recorded gap saw it already true, or uncovered when nothing in the plan will make it true — and every issue with the reason it exists: the criteria it serves, maintenance under a milestone no intent names, or unexplained under one that realises an intent.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_intent_coverage
  • $ intent coverage

No parameters.

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/intents/coverage"

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 IntentCoverage Which work carries which criterion, and why each issue exists: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.
GET /api/v1/intents/preflight intents.preflight

Which intent a piece of work serves, or why it may not proceed

Given the issue a piece of work executes, or the paths it will touch, one verdict: `serves` when no issue is refused and at least one serves a criterion of a live intent through a link that holds, the plan of each such intent critiqued with no blocking finding open (issues judged maintenance beside it do not change the verdict); `maintenance` when the issues sit under milestones no live intent names and serve nothing, as `intent validate` allows; `refused` otherwise, each refusal with its issue, a cause — unknown_issue, no_issue_covers_paths, issue_serves_nothing, serves_another_intent, serves_unknown_criterion, intent_not_critiqued, open_blocking_finding — in path mode every issue judged and the worst verdict answered. The answer carries, for the intents reached and no others, the statement, the served criteria with the live state of their evidence, the invariants, non-goals and governance, the critique with its open blocking findings, and the recorded gap bounded to those criteria.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_intent_preflight
  • $ intent preflight

Query parameters

nametyperequireddescriptionexamples
issue string no The issue the work executes, by id. When given, the paths are not consulted. first-issue: "I0001"
paths string no Repository-relative paths the work will touch, separated by commas. first-issue: ""

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/intents/preflight?issue=I0001&paths="

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 IntentPreflight Which intent a piece of work serves, or why it may not proceed: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.
POST /api/v1/intents/propose intents.propose

Propose an intent: what must become true

Write a new intent record under `.ai/repo/project/intents/` from a statement of what must become true, with an optional title (the statement's first line when absent) and id (the title's slug when absent). The record names no milestone, criterion or invariant: its stage derives as `declared`, `intent validate` reports the two absences as warnings rather than failures, and no work can serve it until it is planned (ADR 0144). Nothing about its standing is stored. An existing record is refused, never overwritten, and the file appears whole or not at all. The answer names the identity and the file; `intents.record` answers the derived stage once the index holds it.

  • command
  • experimental
  • benchmark waived: destructive
  • cache disabled
  • MCP tool majordomus_intent_propose
  • $ intent propose

Request body — IntentProposeInput, JSON

example a sentence

{"statement":"Every page of the UI answers within 100 ms when warm"}

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s -X POST "http://127.0.0.1:8741/api/v1/intents/propose" -H "content-type: application/json" -d '{"statement":"Every page of the UI answers within 100 ms when warm"}'

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 Proposed Propose an intent: what must become true: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
422 ErrorBody refused: The command was understood and turned down for the reason the message gives.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.
GET /api/v1/intents/record intents.record

One intent, with everything derived about it

One intent in full: its statement and invariants as authored, each milestone with the status the plan derives, each satisfaction criterion with the state of its evidence and the command that reproduces it, the stage, and the verdict the criteria alone derive with the criteria holding it back. The record's own file stays at `majordomus://intent/<id>`.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_intent_record
  • $ intent show

Query parameters

nametyperequireddescriptionexamples
id string yes The intent's id, which is also its file name under `.ai/repo/project/intents/`. first-intent: "a-session-leaves-what-it-observed"

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/intents/record?id=a-session-leaves-what-it-observed"

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 IntentView One intent, with everything derived about it: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.
GET /api/v1/intents/validate intents.validate

What the intent model refuses

Every finding over the intents: an intent naming no milestone or no criterion, a milestone that does not resolve, a criterion with no evidence reference or one that names nothing this repository holds, governance that does not resolve, a successor that is not an intent, a file name that disagrees with its id — each a failure — and a milestone no intent serves, a warning.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_intent_validate
  • $ intent validate

No parameters.

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/intents/validate"

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 IntentValidation What the intent model refuses: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.

Schemas

The components only this tag's operations use. Each row is the type's own field, its doc comment the description; a type another page owns links there.

BindingCause

"unknown_issue" | "no_issue_covers_paths" | "issue_serves_nothing" | "serves_another_intent" | "serves_unknown_criterion" | "intent_not_critiqued" | "open_blocking_finding" | "nothing_named" | "unknown_intent" | "intent_retired" | "intent_has_no_open_work" | "issue_outside_intent" | "ambiguous_intent" | "unknown_exemption" | "exemption_without_reason" | "exemption_names_work"
Why a binding was refused, as a word a reader greps for. The first seven are the preflight's own causes, carried through unchanged; the rest are what only a binding can find.

use majordomus_cli::intent::IntentPreflightCause;
use majordomus_cli::intent_binding::BindingCause;
// a preflight cause keeps its word
assert_eq!(
    serde_json::to_string(&BindingCause::from(IntentPreflightCause::IntentNotCritiqued)).unwrap(),
    serde_json::to_string(&IntentPreflightCause::IntentNotCritiqued).unwrap(),
);
  • unknown_issueThe issue named is not an issue of the plan.
  • no_issue_covers_pathsNo open issue's scope covers any of the paths.
  • issue_serves_nothingThe issue's milestone realises a live intent and the issue serves none of its criteria.
  • serves_another_intentThe issue serves a criterion of an intent whose milestones do not include its own.
  • serves_unknown_criterionThe issue serves an intent or a criterion that does not exist.
  • intent_not_critiquedAn intent the work serves has no critique.
  • open_blocking_findingThe critique of an intent the work serves has a blocking finding still open.
  • nothing_namedNothing was named: no issue, no intent, no paths and no exemption.
  • unknown_intentThe intent named is not an intent of this repository.
  • intent_retiredThe intent named is cancelled or superseded.
  • intent_has_no_open_workThe intent named has no open issue serving it, so there is no work to be bound to.
  • issue_outside_intentThe issue named serves none of the criteria of the intent named beside it.
  • ambiguous_intentPaths alone reached more than one intent; the worker must name the issue.
  • unknown_exemptionThe exemption class is not one the policy declares.
  • exemption_without_reasonAn exemption was given with no reason.
  • exemption_names_workAn exemption was given beside an issue or an intent: work is one or the other.

Used by BindingRefusal

BindingExemption

object
The exemption a binding accepted: the class as the policy declares it, and the reason the worker gave.

use majordomus_cli::intent_binding::BindingExemption;
let e = BindingExemption {
    class: "emergency".into(),
    description: "Restoring a broken trunk".into(),
    because: "master is red on case 500".into(),
};
assert_eq!(e.class, "emergency");
propertytyperequireddescription
class string yes The class id.
description string no What the policy says the class is for.
because string yes The worker's reason.

Used by IntentBinding

BindingRefusal

object
One reason a binding was refused.

use majordomus_cli::intent_binding::{BindingCause, BindingRefusal};
let r = BindingRefusal::new(None, BindingCause::NothingNamed, "name the work".into());
assert!(r.issue.is_none());
assert_eq!(r.cause, BindingCause::NothingNamed);
propertytyperequireddescription
issue string | null no The issue it is about; absent when it is about no one issue.
cause BindingCause → BindingCause yes The cause.
message string yes What is wrong, in one sentence.

Used by IntentBinding

BindingRequest

object
What a worker named when it asked what its work serves. Every field is optional and the combinations are judged, not assumed: an issue alone, an intent alone, an issue beside the intent it should serve, paths alone, or an exemption with its reason.

use majordomus_cli::intent_binding::BindingRequest;
let by_issue = BindingRequest { issue: Some("I0001".into()), ..Default::default() };
assert!(!by_issue.names_nothing());
// blanks are what a query string or a shell variable leaves behind, and name nothing
let blank = BindingRequest { issue: Some("  ".into()), ..Default::default() }.trimmed();
assert!(blank.names_nothing());
propertytyperequireddescription
issue string | null no The issue the work executes.
intent string | null no The intent the work serves, when the worker names it directly.
paths array of string no The paths the work will touch.
exemption string | null no The exemption class, when the work is under no intent on purpose.
because string | null no Why the exemption applies.

Used by IntentBinding

BindingStanding

"bound" | "maintenance" | "exempt" | "refused"
Where a piece of work stands against the intents: the one word a start decides on.

use majordomus_cli::intent_binding::BindingStanding;
assert_eq!(serde_json::to_string(&BindingStanding::Bound).unwrap(), "\"bound\"");
assert!(BindingStanding::Refused.refuses());
assert!(!BindingStanding::Maintenance.refuses());
  • boundThe work serves at least one criterion of a live intent, through links that hold, and each such intent's plan was critiqued with no blocking finding open.
  • maintenanceThe issues the work resolves to sit under milestones no live intent names: derived maintenance, as intent validate allows.
  • exemptThe worker gave an exemption class the policy declares, with a reason.
  • refusedThe work may not start as bound work; every reason is in refusals.

Used by IntentBinding

ConditionState

"satisfied" | "missing" | "conflicting" | "unknown"
The state of one criterion as the gap observed it. Four values, because "not determined" has to be writable: an omitted criterion is refused, and Unknown is never a pass.

use majordomus_cli::intent_review::ConditionState;
assert_eq!(serde_json::to_string(&ConditionState::Conflicting).unwrap(), "\"conflicting\"");
assert_ne!(ConditionState::Unknown, ConditionState::Satisfied);
  • satisfiedAlready true at the observed commit.
  • missingNot true; work is needed.
  • conflictingSomething in the repository contradicts it.
  • unknownNot determined. Never read as satisfied.

Used by GapCondition

CritiqueClass

"missed_requirement" | "unproven_assumption" | "insufficient_work" | "unnecessary_work" | "regression_risk" | "surface_missing" | "delivery_verification"
The class of a critique finding: the question the adversarial pass asked. Closed, so that a review's findings can be counted by question rather than read as prose.

use majordomus_cli::intent_review::CritiqueClass;
assert_eq!(
    serde_json::to_string(&CritiqueClass::DeliveryVerification).unwrap(),
    "\"delivery_verification\""
);
  • missed_requirementDoes the plan miss something the intent requires?
  • unproven_assumptionWhich assumption is unproven?
  • insufficient_workWhich criterion lacks sufficient work?
  • unnecessary_workWhich work item is unnecessary?
  • regression_riskWhat could regress?
  • surface_missingWhich related surface must also change?
  • delivery_verificationWhich deployment or runtime verification is required?

Used by CritiqueFinding

CritiqueFinding

object
One critique finding: what the review found, what it is about, whether it blocks execution, and how it was resolved. class and resolution are None when the record spells one this module does not know, and the _text fields keep what was written.

use majordomus_cli::intent_review::{CritiqueFinding, CritiqueRecord, ResolutionState};
let c = CritiqueRecord::from_metadata("c.yaml", &serde_json::json!({
    "intent": "x",
    "findings": [{"id": "f1", "class": "regression_risk", "subject": "x#a",
                  "blocking": true, "resolution": {"state": "planned", "issue": "I1"}}],
}));
let finding: &CritiqueFinding = &c.findings[0];
assert!(finding.blocking);
assert_eq!(finding.resolution, Some(ResolutionState::Planned));
assert_eq!(finding.issue, "I1");
propertytyperequireddescription
id string yes Unique within the critique.
class CritiqueClass | null → CritiqueClass no The class, or None for a class this module does not know.
class_text string yes As written.
subject string yes <intent>#<criterion>, an issue id or a milestone id.
finding string yes The finding.
blocking boolean yes Whether execution may not start while it is open.
resolution ResolutionState | null → ResolutionState no The resolution, or None for a state this module does not know.
resolution_text string yes As written.
issue string yes The issue that carries it, when planned.
because string yes Why, when rejected.

Used by IntentPreflightCritique

GapCondition

object
One criterion's state against the observations, as the record spells it. state is None when the file names a state this module does not know, and state_text keeps what was written so the finding can quote it.

use majordomus_cli::intent_review::{ConditionState, GapCondition};
let c = GapCondition {
    criterion: "criteria-are-covered".into(),
    state: Some(ConditionState::Missing),
    state_text: "missing".into(),
    because: "nothing relates a criterion to an issue".into(),
    observations: vec!["no-serves-field".into()],
};
assert_eq!(c.state, Some(ConditionState::Missing));
assert!(!c.observations.is_empty());
propertytyperequireddescription
criterion string yes The criterion id of the intent.
state ConditionState | null → ConditionState no The state, or None when the record spells one this module does not know.
state_text string yes As written, so a finding can quote an unknown state.
because string yes Why.
observations array of string yes The observation ids it rests on.

Used by IntentPreflightGap

IntentBinding

object
What a piece of work is bound to: its standing, what was named, the issues and intents it resolved to with what each intent asks of the worker, the two pins, and every refusal.

use majordomus_cli::intent::Intents;
use majordomus_cli::intent_binding::{
    bind, BindingCause, BindingRequest, BindingStanding, IntentBinding,
};
use majordomus_cli::plan::Plan;
use majordomus_cli::policy::IntentPolicy;
#### let plan: Plan = serde_json::from_value(serde_json::json!({
####     "project": {"name": "p", "repository": "o/p", "default_branch": "master",
####                 "active_milestone": ""},
####     "statuses": {"issue": [], "milestone": []},
####     "milestones": [], "issues": [], "waves": [], "edges": [],
####     "milestone_edges": [], "findings": []})).unwrap();
let intents = Intents { intents: vec![], findings: vec![] };
let nothing: IntentBinding =
    bind(&intents, &plan, &[], &[], &IntentPolicy::default(), BindingRequest::default());
assert_eq!(nothing.standing, BindingStanding::Refused);
assert_eq!(nothing.refusals[0].cause, BindingCause::NothingNamed);
// nothing was reached, so there is nothing to pin
assert!(nothing.plan_revision.is_empty() && nothing.evidence_standing.is_empty());
propertytyperequireddescription
standing BindingStanding → BindingStanding yes bound, maintenance, exempt or refused.
named BindingRequest → BindingRequest yes What the worker named, trimmed: the request this answers.
exemption BindingExemption | null → BindingExemption no The exemption accepted, when the standing is exempt.
issues array of IntentPreflightIssue → IntentPreflightIssue yes The issues the work resolved to, each with the preflight's verdict.
intents array of IntentPreflightIntent → IntentPreflightIntent yes The intents the work serves, each with the criteria served, their evidence state, the invariants, the critique and the gap: what the worker is held to.
governance array of string yes The governance of those intents, each entry once.
plan_revision string yes The pin of what the work is for; empty when no intent was reached.
evidence_standing string yes The pin of where the served criteria's evidence stands; empty when no intent was reached.
notes array of string no What a worker should know and no gate refuses on.
refusals array of BindingRefusal → BindingRefusal yes Every reason the binding was refused; empty unless the standing is refused.
refusal string | null no When refused: every refusal's sentence, joined.

Used by intents.binding

IntentCoverage

object
The whole derived coverage: every criterion of every live intent, every issue with the reason it exists, and every finding the two produced. Nothing here is stored; it is derived on each read from the intents and the plan.

use majordomus_cli::intent_plan::{IntentCoverage, IssueOrigin, IssuePurpose};
let coverage = IntentCoverage {
    criteria: vec![],
    issues: vec![IssuePurpose {
        issue: "I0007".into(),
        milestone: "ops".into(),
        origin: IssueOrigin::Maintenance,
        serves: vec![],
        intents: vec![],
    }],
    findings: vec![],
};
assert_eq!(coverage.failures(), 0);
assert_eq!(coverage.purpose("I0007").unwrap().origin, IssueOrigin::Maintenance);
propertytyperequireddescription
criteria array of CriterionCoverage → CriterionCoverage yes Every criterion of every live intent, in intent then declaration order.
issues array of IssuePurpose → IssuePurpose yes Every issue of the plan, in id order, with the reason it exists.
findings array of IntentFinding → IntentFinding yes Every finding, in derivation order.

Used by intents.coverage

IntentList

object
Every intent, with its derived stage and verdict, and how many there are in each: what majordomus intent list, GET /api/v1/intents and the majordomus_intents tool all answer with, out of one derivation.

use majordomus_cli::capability::builtin::intents::IntentList;
let empty = IntentList {
    count: 0,
    stages: std::collections::BTreeMap::new(),
    verdicts: std::collections::BTreeMap::new(),
    intents: vec![],
};
// a repository that declares no intent answers the route, with nothing in it
assert_eq!(empty.count, 0);
propertytyperequireddescription
count integer (uint) yes How many intents.
stages map of integer (uint) yes How many in each stage, keyed by the stage word.
verdicts map of integer (uint) yes How many with each verdict, keyed by the verdict word.
intents array of IntentView → IntentView yes Every intent, in identity order.

Used by intents.list

IntentPreflight

object
Which intent a piece of work serves, whether it is maintenance, or why it may not proceed: the issues it resolved to with a verdict each, every intent reached with its link, what those intents require of the worker, and every refusal with its cause.

use majordomus_cli::intent::{
    IntentPreflight, IntentPreflightCause, IntentPreflightRefusal, IntentPreflightVerdict,
};
let refused = IntentPreflight {
    verdict: IntentPreflightVerdict::Refused,
    issues: vec![],
    matches: vec![],
    intents: vec![],
    governance: vec![],
    refusals: vec![IntentPreflightRefusal::new(
        None,
        IntentPreflightCause::NoIssueCoversPaths,
        "no open issue's scope covers README.md".into(),
    )],
    refusal: Some("no open issue's scope covers README.md".into()),
};
assert_eq!(refused.verdict, IntentPreflightVerdict::Refused);
assert_eq!(refused.refusals[0].cause, IntentPreflightCause::NoIssueCoversPaths);
propertytyperequireddescription
verdict IntentPreflightVerdict → IntentPreflightVerdict yes serves, maintenance or refused: refused when any issue is, else serves when any issue serves an intent, else maintenance.
issues array of IntentPreflightIssue → IntentPreflightIssue yes The issues the work was resolved to — the one named, or the open issues whose scope covers a path — each with its own verdict.
matches array of IntentPreflightMatch → IntentPreflightMatch yes Every intent an issue serves, with the link.
intents array of IntentPreflightIntent → IntentPreflightIntent yes The intents the work serves, and no other, each with what it asks of the worker.
governance array of string yes The governance of those intents, each entry once, in first-seen order.
refusals array of IntentPreflightRefusal → IntentPreflightRefusal yes Every reason the preflight refused, in issue order; empty unless the verdict is refused.
refusal string | null no When refused: every refusal's sentence, joined, for a reader who wants one line.

Used by intents.preflight

IntentPreflightCause

"unknown_issue" | "no_issue_covers_paths" | "issue_serves_nothing" | "serves_another_intent" | "serves_unknown_criterion" | "intent_not_critiqued" | "open_blocking_finding"
Why a preflight refused, as a word a reader greps for.

use majordomus_cli::intent::IntentPreflightCause;
assert_eq!(
    serde_json::to_string(&IntentPreflightCause::OpenBlockingFinding).unwrap(),
    "\"open_blocking_finding\""
);
assert_ne!(
    IntentPreflightCause::IntentNotCritiqued,
    IntentPreflightCause::IssueServesNothing
);
  • unknown_issueThe issue named is not an issue of the plan.
  • no_issue_covers_pathsNo open issue's scope covers any of the paths.
  • issue_serves_nothingThe issue's milestone realises a live intent and the issue serves none of its criteria.
  • serves_another_intentThe issue serves a criterion of an intent whose milestones do not include its own.
  • serves_unknown_criterionThe issue serves an intent or a criterion that does not exist, or a token that is not <intent>#<criterion>.
  • intent_not_critiquedAn intent the issue serves has no critique: its plan was never reviewed.
  • open_blocking_findingThe critique of an intent the issue serves has a blocking finding still open.

Used by IntentPreflightRefusal

IntentPreflightCritique

object
The critique of an intent as a preflight reads it: where it is, when and by whom the plan was reviewed, and the blocking findings still open.

use majordomus_cli::intent::IntentPreflightCritique;
let c = IntentPreflightCritique {
    source: ".ai/repo/project/critiques/x.yaml".into(),
    reviewed_at: "c3f20da".into(),
    reviewed_by: "another session".into(),
    open_blocking: vec![],
};
assert!(c.open_blocking.is_empty());
propertytyperequireddescription
source string yes Repository-relative path of the record.
reviewed_at string yes The commit the plan was reviewed at.
reviewed_by string yes Who or what reviewed it.
open_blocking array of CritiqueFinding → CritiqueFinding yes Every blocking finding whose resolution is open; work may not start while one is.

Used by IntentPreflightIntent

IntentPreflightGap

object
The recorded gap of an intent as a preflight reads it, bounded to the criteria the work serves: what was observed of each, at which commit, and the risks.

use majordomus_cli::intent::IntentPreflightGap;
let g = IntentPreflightGap {
    source: ".ai/repo/project/gaps/x.yaml".into(),
    observed_at: "c3f20da".into(),
    conditions: vec![],
    risks: vec!["the schema may refuse old records".into()],
};
assert_eq!(g.risks.len(), 1);
propertytyperequireddescription
source string yes Repository-relative path of the record.
observed_at string yes The commit the observations were made on.
conditions array of GapCondition → GapCondition yes The gap's answer for each criterion the work serves, in the gap's order.
risks array of string yes The risks it recorded.

Used by IntentPreflightIntent

IntentPreflightIntent

object
One intent the work is held to, with what a worker needs before touching it: the statement, the criteria the work serves with the live state of their evidence, the invariants and non-goals, the governance, the critique and the gap. Only the intents the work reaches are carried, never every intent.

use majordomus_cli::intent::{IntentPreflightIntent, IntentStage};
let i = IntentPreflightIntent {
    id: "x".into(),
    title: "X".into(),
    stage: IntentStage::Planned,
    statement: "It becomes true.".into(),
    criteria: vec![],
    invariants: vec![],
    non_goals: vec![],
    governance: vec![],
    critique: None,
    gap: None,
};
// no critique recorded is carried as an absence, never as an empty review
assert!(i.critique.is_none());
propertytyperequireddescription
id string yes The identity.
title string yes One line.
stage IntentStage → IntentStage yes Its derived stage.
statement string yes What must become true.
criteria array of IntentCriterion → IntentCriterion yes The criteria the work serves, each with the state of its evidence now, in the intent's order.
invariants array of string yes What must stay true.
non_goals array of string yes What is deliberately not required.
governance array of string yes The governance a worker on this intent loads.
critique IntentPreflightCritique | null → IntentPreflightCritique no The critique of its plan; absent when none was ever recorded.
gap IntentPreflightGap | null → IntentPreflightGap no Its recorded gap, bounded to the criteria above; absent when none was recorded.

Used by IntentBinding IntentPreflight

IntentPreflightIssue

object
One issue the work resolved to, and what the preflight concluded about it.

use majordomus_cli::intent::{IntentPreflightIssue, IntentPreflightVerdict};
let i = IntentPreflightIssue {
    issue: "I0007".into(),
    milestone: "ops".into(),
    verdict: IntentPreflightVerdict::Maintenance,
    serves: vec![],
    intents: vec![],
};
// a milestone no intent names carries maintenance, which is not a refusal
assert_eq!(i.verdict, IntentPreflightVerdict::Maintenance);
propertytyperequireddescription
issue string yes The issue id.
milestone string yes Its milestone.
verdict IntentPreflightVerdict → IntentPreflightVerdict yes What the preflight concluded about this issue.
serves array of string yes The <intent>#<criterion> references it declares, as declared.
intents array of string yes The live intents whose milestones include its milestone, sorted.

Used by IntentBinding IntentPreflight

IntentPreflightMatch

object
One intent a piece of work serves, and the link that says so: issue to the criteria it declares in serves, each criterion's intent naming the issue's milestone.

use majordomus_cli::intent::{IntentPreflightMatch, IntentStage};
let m = IntentPreflightMatch {
    intent: "intent-lifecycle".into(),
    title: "Work is traceable to the intent it serves".into(),
    stage: IntentStage::Executing,
    milestone: "intent-lifecycle".into(),
    issue: "I1900".into(),
    criteria: vec!["stage-is-derived".into()],
};
assert_eq!(m.issue, "I1900");
propertytyperequireddescription
intent string yes The intent.
title string yes Its title.
stage IntentStage → IntentStage yes Its derived stage.
milestone string yes The milestone that links the work to it.
issue string yes The issue that links the work to that milestone.
criteria array of string yes The criteria of the intent the issue declares it serves, in the intent's order.

Used by IntentPreflight

IntentPreflightRefusal

object
One reason a preflight refused: which issue, the cause, and one sentence of what is wrong.

use majordomus_cli::intent::{IntentPreflightCause, IntentPreflightRefusal};
let r = IntentPreflightRefusal::new(
    Some("I1900"),
    IntentPreflightCause::IntentNotCritiqued,
    "intent x has no critique".into(),
);
assert_eq!(r.cause, IntentPreflightCause::IntentNotCritiqued);
assert_eq!(r.issue.as_deref(), Some("I1900"));
propertytyperequireddescription
issue string | null no The issue it is about; absent when no issue was resolved at all.
cause IntentPreflightCause → IntentPreflightCause yes The cause.
message string yes What is wrong, in one sentence.

Used by IntentPreflight

IntentPreflightVerdict

"serves" | "maintenance" | "refused"
What a preflight concluded, about one issue or about the whole piece of work.

use majordomus_cli::intent::IntentPreflightVerdict;
// the words every surface answers with
assert_eq!(
    serde_json::to_string(&IntentPreflightVerdict::Maintenance).unwrap(),
    "\"maintenance\""
);
assert_ne!(IntentPreflightVerdict::Serves, IntentPreflightVerdict::Refused);
  • servesThe work serves at least one criterion of a live intent, every link holds, and the plan of every intent it serves was critiqued with no blocking finding left open.
  • maintenanceThe work sits under milestones no live intent names and serves no criterion of a live intent: operational work, allowed where majordomus intent validate allows it.
  • refusedA link is missing or points at nothing, or an intent it serves may not be executed yet.

Used by IntentPreflight IntentPreflightIssue

IntentProposeInput

object
The input of intents.propose: what must become true, and optionally its title and id.

No milestone, criterion or invariant: a proposal says what is wanted, and planning it is a separate act (ADR 0144). No timestamp either: the record is dated when it is written.

use majordomus_cli::capability::builtin::intents::IntentProposeInput;
let i: IntentProposeInput =
    serde_json::from_str(r#"{"statement": "The UI answers within 100 ms warm"}"#).unwrap();
assert_eq!(i.title, None);
// a field the input does not have is refused, never ignored
assert!(serde_json::from_str::<IntentProposeInput>(r#"{"statement": "s", "stage": "x"}"#).is_err());
propertytyperequireddescription
statement string yes What must become true, in the proposer's words; kept verbatim.
title string | null no One line naming it; the statement's first line when absent.
id string | null no The identity and file name; the title's slug when absent.

Used by intents.propose

IntentValidation

object
What the intent model refuses: whether it is valid, how many intents were examined, and every finding with its level. Warnings are reported and do not make it invalid.

use majordomus_cli::capability::builtin::intents::IntentValidation;
let v = IntentValidation {
    valid: true,
    intents: 2,
    failures: 0,
    warnings: 20,
    findings: vec![],
};
// twenty warnings and no failure is a valid model
assert!(v.valid);
propertytyperequireddescription
valid boolean yes True when no finding is a failure. Warnings do not make it false.
intents integer (uint) yes How many intents were examined.
failures integer (uint) yes How many findings are failures.
warnings integer (uint) yes How many findings are warnings.
findings array of IntentFinding → IntentFinding yes Every finding.

Used by intents.validate

IssueOrigin

"intent" | "maintenance" | "unexplained"
Why an issue exists: because it serves a criterion, because it is maintenance under a milestone no intent names, or because nobody said — which is a failure under an intent.

use majordomus_cli::intent_plan::IssueOrigin;
assert_eq!(serde_json::to_string(&IssueOrigin::Maintenance).unwrap(), "\"maintenance\"");
// work under no intent is legitimate and says so; it is never given an invented intent
assert_ne!(IssueOrigin::Maintenance, IssueOrigin::Unexplained);
  • intentIt serves at least one criterion of a declared intent.
  • maintenanceIts milestone is named by no intent: maintenance or operational work, stated as such.
  • unexplainedIts milestone realises an intent, but it names nothing it serves.

Used by IssuePurpose

IssuePurpose

object
The answer to "why does this issue exist?": the criteria it declares it serves, the intents whose milestones contain it, and which of the three origins that adds up to.

use majordomus_cli::intent_plan::{IssueOrigin, IssuePurpose};
let purpose = IssuePurpose {
    issue: "I1901".into(),
    milestone: "intent-planning".into(),
    origin: IssueOrigin::Intent,
    serves: vec!["intent-planning#criteria-are-covered".into()],
    intents: vec!["intent-planning".into()],
};
assert_eq!(purpose.origin, IssueOrigin::Intent);
assert_eq!(purpose.serves.len(), 1);
propertytyperequireddescription
issue string yes The issue id.
milestone string yes Its milestone.
origin IssueOrigin → IssueOrigin yes Which kind of reason it has.
serves array of string yes The <intent>#<criterion> references it declares, as declared.
intents array of string yes The intents whose milestones include this issue's milestone, sorted.

Used by IntentCoverage

Proposed

object
What propose wrote: the identity, the file, and the record as it now reads.

use majordomus_cli::intent::Proposed;
let p: Proposed = serde_json::from_str(
    r#"{"id": "fast-ui", "path": ".ai/repo/project/intents/fast-ui.yaml",
        "title": "Fast UI", "statement": "The UI answers at once"}"#,
)
.unwrap();
// the path is the identity under the intents directory: one answer to where it lives
assert_eq!(p.path, format!(".ai/repo/project/intents/{}.yaml", p.id));
propertytyperequireddescription
id string yes The identity, which is also the file name.
path string yes Repository-relative path of the record written.
title string yes One line.
statement string yes What must become true, as it was given.

Used by intents.propose

ResolutionState

"open" | "planned" | "rejected"
How a critique finding was resolved: not yet, by planning work that serves the intent, or by rejecting it with a reason. A blocking finding left Open refuses execution.

use majordomus_cli::intent_review::ResolutionState;
assert_eq!(serde_json::to_string(&ResolutionState::Planned).unwrap(), "\"planned\"");
assert_ne!(ResolutionState::Open, ResolutionState::Rejected);
  • openNot yet resolved.
  • plannedCarried by an issue.
  • rejectedJudged not to apply, with a reason.

Used by CritiqueFinding

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