Skip to content

HTTP API: devtask

An issue and a milestone read as work to be done rather than as metadata: what a person authored, where the plan graph puts it, what happened to it locally, where its external projection stands, and whether a worker may start it — with the origin of every value on the value. Nothing here is a second project model: the records are the canonical ones, the status and the graph are `plan`'s, the branches and commits are `trace`'s, the readiness vocabulary refines three canonical statuses without replacing any, and the projection onto GitHub stays `scripts/github-sync`'s. Nothing here writes anything, which is what makes a user-authored GitHub value safe from it.

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.

devtask

An issue and a milestone read as work to be done rather than as metadata: what a person authored, where the plan graph puts it, what happened to it locally, where its external projection stands, and whether a worker may start it — with the origin of every value on the value. Nothing here is a second project model: the records are the canonical ones, the status and the graph are `plan`'s, the branches and commits are `trace`'s, the readiness vocabulary refines three canonical statuses without replacing any, and the projection onto GitHub stays `scripts/github-sync`'s. Nothing here writes anything, which is what makes a user-authored GitHub value safe from it.

GET /api/v1/devtask/issue devtask.issue

One issue as an executable development task

Identity, title, intent, status, milestone, acceptance criteria, dependencies, blockers, the commits its own evidence names and the commits git found, its branches, the sessions that worked on it, its readiness and everything wrong with its records — each field carrying whether a person authored it (`explicit`), a machine worked it out by a rule that cannot be wrong (`derived`), a machine worked it out by a rule that can (`inferred`, with the rule stated), or it is not available at all (`unknown`, with the reason). A key the record does not carry is `unknown`, never an empty string: `objective: ""` and a record with no objective are the same string and different facts. An id the model does not declare is answered, not refused. `git: false` answers from the records alone, which is what a comparison across machines wants.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_devtask
  • $ devtask issue

Query parameters

nametyperequireddescriptionexamples
issue string yes The issue id, as the canonical model spells it (`I0901`). An id the model does not declare is answered with `declared: false` and every canonical field `unknown`, never refused and never answered with empty strings that read as authored. records-only: "I0001"with-git: "I0001"
git boolean no Consult git for the branches and commits that realised it. Default: yes. Set it to false for a deterministic answer that depends on the records alone — which is what a generated document or a comparison across machines wants. records-only: falsewith-git: true

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/devtask/issue?issue=I0001&git=false"

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 DevTask One issue as an executable development task: 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/devtask/milestone devtask.milestone

One milestone as an executable dependency graph

Every issue of the milestone as a node with its readiness, its wave and what waits on it; every dependency edge with at least one end inside, the crossing ones marked; the issues partitioned into ready, blocked, waiting, active, review, completion-blocked, complete and cancelled; the critical blockers ordered by how much unfinished work each holds back; the startable work partitioned into subsets that may genuinely run at the same time — same wave, each parallel-safe, no two sharing a scope path — with each serialisation naming the path that caused it; every dependency cycle as its strongly connected component; and every finding about the milestone or its issues. A pure function of the canonical records: no git, no clock, no network, every list in canonical order, so two runs on two machines produce the same bytes. A work surface reading this derives nothing itself.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_devtask_milestone
  • $ devtask milestone

Query parameters

nametyperequireddescriptionexamples
milestone string yes The milestone id, as the canonical model spells it. An id the model does not declare is answered with an empty graph and every field `unknown`, not refused. first-milestone: "M000"

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/devtask/milestone?milestone=M000"

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 MilestoneGraph One milestone as an executable dependency graph: 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.

AttestationTally

object
How much of one answer was authored, and how much a machine worked out.

Not decoration: it is the measurement that makes the provenance discipline checkable from outside. A task whose declaration is mostly unknown is a placeholder however complete its derived half looks, and this is the number that says so.

propertytyperequireddescription
explicit integer (uint32) yes Fields a person authored in the canonical record.
derived integer (uint32) yes Fields worked out by a rule that cannot be wrong about a readable repository.
inferred integer (uint32) yes Fields worked out by a rule that can be wrong.
unknown integer (uint32) yes Fields not available at all.

Used by DevTask

AttestedCount

object
A count with its provenance. Separate from AttestedText because a wave, a commit tally and an evidence count are numbers a caller does arithmetic on, and a number rendered as a string is a number every client has to parse back.
propertytyperequireddescription
value integer | null no The number, absent exactly when the provenance is unknown.
provenance FieldProvenance → FieldProvenance yes Where it came from.
source string yes The one place a reader goes to check it.
reason string | null no Why the provenance is what it is, when that is worth a sentence.

Used by DevTaskExecution DevTaskPosition MilestoneGraph

AttestedList

object
A list with its provenance. The distinction a bare Vec cannot make is the one that matters here: depends_on: [] in the record is an authored empty list, and a record with no depends_on key is unknown. Both are empty; only one is a statement.
propertytyperequireddescription
values array of string yes The items, in the order the record or the derivation produced them. Empty for an authored empty list and for an unknown field alike; provenance tells them apart.
provenance FieldProvenance → FieldProvenance yes Where they came from.
source string yes The one place a reader goes to check them.
reason string | null no Why the provenance is what it is, when that is worth a sentence.

Used by DevTaskDeclaration DevTaskExecution DevTaskPosition MilestoneGraph

AttestedText

object
One scalar with its provenance: the unit every field of a development task is made of.

The invariant the constructors enforce, and AttestedText::is_consistent states, is that a value is present exactly when the provenance is not FieldProvenance::Unknown. Without it the shape can express "unknown, and here is the value", which is the defect this whole module exists to prevent.

propertytyperequireddescription
value string | null no The value, absent exactly when the provenance is unknown.
provenance FieldProvenance → FieldProvenance yes Where it came from.
source string yes The one place a reader goes to check it: a repository-relative path with the key it was read from, a capability id, or a command. Never a machine path.
reason string | null no Why the provenance is what it is, when that is worth a sentence: always for unknown and for inferred, and omitted otherwise.

Used by DevTaskDeclaration DevTaskExecution DevTaskPosition DevTaskSynchronisation MilestoneGraph

Blocker

object
One thing standing between a task and being startable, with what to do about it.
propertytyperequireddescription
kind BlockerKind → BlockerKind yes What kind of thing it is.
subject string yes The thing: an issue id, a milestone id, an evidence token.
detail string yes What is wrong, in one line a person can act on.

Used by ReadinessVerdict

BlockerKind

"issue" | "milestone" | "evidence" | "reference" | "cycle"
What kind of thing is holding a task back. The five are the five the canonical model can actually produce; there is no other.
  • issueAn issue this one depends on that is not DONE.
  • milestoneThe milestone gate: an outcome this one's milestone requires is not DONE.
  • evidenceA required evidence token the record does not carry, with completion recorded.
  • referenceA dependency that resolves to nothing: the model has no such issue.
  • cycleA dependency cycle this task is in or downstream of, so it can never become ready.

Used by Blocker

CriticalBlocker

object
One unfinished issue that holds back downstream work, and how much.
propertytyperequireddescription
issue string yes The issue.
readiness TaskReadiness → TaskReadiness yes Where it stands, which is what says whether unblocking it is work or a decision.
blocks array of string yes The unfinished issues that wait on it, directly or through another, in canonical order.
weight integer (uint32) yes How many that is. The number the list is ordered by.

Used by MilestoneGraph

DevTask

object
One issue as an executable development task: what was authored, where it sits, what has happened to it, where its external projection stands, and whether a worker may start it.
propertytyperequireddescription
issue string yes The issue id, as asked for.
declared boolean yes Whether the canonical model declares it. False is answered rather than refused, with every canonical field unknown: a typo that read as "nothing has been authored" is the one answer this must never give.
record string | null no Repository-relative path of the canonical record, when there is one.
declaration DevTaskDeclaration → DevTaskDeclaration yes What a person authored.
position DevTaskPosition → DevTaskPosition yes Where the plan graph puts it.
execution DevTaskExecution → DevTaskExecution yes What happened locally.
synchronisation DevTaskSynchronisation → DevTaskSynchronisation yes Where the external projection stands.
readiness ReadinessVerdict → ReadinessVerdict yes Whether it can be worked on, and what is in the way.
diagnostics array of DevTaskDiagnostic → DevTaskDiagnostic yes Everything wrong with its records.
attestation AttestationTally → AttestationTally yes How much of the answer was authored and how much a machine worked out.

Used by devtask.issue

DevTaskDeclaration

object
What a person authored in the canonical record. Every field is FieldProvenance::Explicit or FieldProvenance::Unknown and nothing else: a value here was written down, or it does not exist.
propertytyperequireddescription
title AttestedText → AttestedText yes One line naming the outcome.
objective AttestedText → AttestedText yes What the issue is for.
why AttestedText → AttestedText yes Why it is worth doing.
current_state AttestedText → AttestedText yes Where the repository stands before it.
desired_state AttestedText → AttestedText yes Where the repository stands once it is real.
completion AttestedText → AttestedText yes What the author says about how far it got. Authored prose, never a status: the status is derived, and this is the one field where a person may disagree with it.
milestone AttestedText → AttestedText yes The milestone it belongs to.
priority AttestedText → AttestedText yes p0 … p3.
profile AttestedText → AttestedText yes The execution profile it is worked under.
parallel_safe AttestedText → AttestedText yes Whether it may run beside another issue of its wave.
owner AttestedText → AttestedText yes Who owns it.
risk AttestedText → AttestedText yes What could go wrong.
slug AttestedText → AttestedText yes The slug.
cancelled AttestedText → AttestedText yes Whether it was withdrawn.
created_at AttestedText → AttestedText yes When the record was created.
updated_at AttestedText → AttestedText yes When it last moved.
started_at AttestedText → AttestedText yes When execution began.
verified_at AttestedText → AttestedText yes When implementation was declared finished.
completed_at AttestedText → AttestedText yes When completion was recorded.
scope AttestedList → AttestedList yes The paths it may touch.
non_scope AttestedList → AttestedList yes The paths it deliberately does not touch.
depends_on AttestedList → AttestedList yes The issues it declares a dependency on, exactly as declared — including one that does not exist, which is a diagnostic and not a silent omission.
acceptance_criteria AttestedList → AttestedList yes What must be true before it is finished.
validation AttestedList → AttestedList yes The commands that check it.
evidence_required AttestedList → AttestedList yes The evidence tokens it requires before it may be complete.
evidence_present AttestedList → AttestedList yes The evidence tokens it actually carries.
evidence_commits AttestedList → AttestedList yes The commits the record's own evidence entries name. Authored, and therefore a different fact from the commits git finds on the branches — which are in DevTaskExecution::commits and are derived.

Used by DevTask

DevTaskDiagnostic

object
One thing wrong with this task's records, in the shape project.finding-carries-reproduce asks for.
propertytyperequireddescription
level string yes FAIL or WARN, as the plan's own finding levels.
code string yes The stable code a reader greps for.
message string yes What is wrong, in one line.
reproduce string yes The one command that shows it again.

Used by DevTask MilestoneGraph

DevTaskExecution

object
Local execution state: what actually happened in this checkout's git history and session records. Derived where the relation was declared, inferred where it was not, and the fields say which.
propertytyperequireddescription
git_consulted boolean yes Whether git was consulted at all. False makes every git-derived field below unknown rather than empty, which is the difference between "nothing realised this" and "nobody looked".
branches AttestedList → AttestedList yes The branches whose name carries this issue's id, local first.
merged_branches AttestedList → AttestedList yes Of those, the ones that reached the trunk.
commits AttestedCount → AttestedCount yes How many distinct commits those branches hold that the trunk did not.
trunk AttestedText → AttestedText yes The trunk every branch was measured against.
commits_complete AttestedText → AttestedText yes True when every branch's commits could be derived. False when one reached the trunk without a merge commit of its own, so part of the work cannot be told from the trunk's — reported rather than counted as zero.
sessions AttestedList → AttestedList yes The session records whose own issues key names this issue. Derived: the key is worked out from the episode's ledger events, not authored and not guessed.
sessions_by_branch AttestedList → AttestedList yes The session records that reach this issue only through their branch name, and which therefore may be wrong. Never overlaps DevTaskExecution::sessions: a session that declared the issue is reported there and not here, so the weaker relation never stands in for the stronger one.

Used by DevTask

DevTaskPosition

object
Where the task sits in the plan graph. Every field is derived; nothing here is authored, and nothing here is stored anywhere.
propertytyperequireddescription
status AttestedText → AttestedText yes The canonical status, from the one derivation of it.
wave AttestedCount → AttestedCount yes The execution wave: one past the longest path to it. Unknown when a cycle prevents it from ever having one.
blocked_by AttestedList → AttestedList yes The dependencies that are not DONE, plus the milestone gate when it applies.
dependents AttestedList → AttestedList yes The issues that wait on this one.
transitive_dependents AttestedCount → AttestedCount yes Every issue that waits on it, directly or through another. The measure of what finishing it unblocks.
milestone_status AttestedText → AttestedText yes The status of the milestone it belongs to.
milestone_rank AttestedCount → AttestedCount yes The milestone's layer in the milestone graph.
milestone_blocked_by AttestedList → AttestedList yes The outcomes that milestone still waits on.
evidence_have AttestedCount → AttestedCount yes How many evidence tokens it carries.
evidence_need AttestedCount → AttestedCount yes How many it needs.

Used by DevTask

DevTaskSynchronisation

object
The external projection. Nothing here is ever written by this executable, and the fields that only the adapter can answer say so rather than reading as empty.
propertytyperequireddescription
adapter string yes The adapter that owns the projection. The one thing that can answer the live state.
repository AttestedText → AttestedText yes The repository the projection targets, from project.yaml.
state AttestedText → AttestedText yes The reconciliation state of the external record. Always unknown from here: it is a network fact, and this executable makes none. The reason names the command.
external_id AttestedText → AttestedText yes The external record's own identifier — a GitHub number — which GitHub assigns and nothing local records. Always unknown, for the same reason.
reconcile_with array of string yes The commands that answer the external half.
writable boolean yes Whether this executable may write any of it. Always false; stated as a field so that a client need not know the rule to respect it.

Used by DevTask

FieldProvenance

"explicit" | "derived" | "inferred" | "unknown"
Where a value came from, and therefore how much weight a reader may put on it.

The four words are not degrees of confidence, they are four different relations to the repository, and the distinction that matters most is the first from the last two: a person wrote it, or a machine worked it out.

use majordomus_cli::devtask::{AttestedText, FieldProvenance};

// a value the record itself carried
let title = AttestedText::explicit("Ship it", ".ai/repo/project/issues/I0001.yaml#title");
assert_eq!(title.provenance, FieldProvenance::Explicit);

// a key the record does not have is unknown, and unknown carries no value
let missing = AttestedText::unknown(
    ".ai/repo/project/issues/I0001.yaml#objective",
    "the record declares no `objective`",
);
assert_eq!(missing.provenance, FieldProvenance::Unknown);
assert!(missing.value.is_none());
  • explicitA person authored it, in the canonical record, under this key. The strongest thing that can be said about a value, and the only one that survives a rewrite of every derivation in this repository.
  • derivedA machine worked it out from records or from git, by a rule that cannot be wrong about a repository it can read: an issue's dependents are the issues that name it. Re-derived on every call and stored nowhere.
  • inferredA machine worked it out by a rule that can be wrong, because the relation it reads was never declared: a session belongs to an issue because its branch name contains the issue's id. Useful, and never to be mistaken for a declaration.
  • unknownNot available. Either the record does not carry the key, or the fact lives outside what this process may read — a live GitHub state, for one — and the field says which in its reason. An unknown field never carries a value.

Used by AttestedCount AttestedList AttestedText

MilestoneCounts

object
One milestone's issues counted by readiness, plus the two denominators.
propertytyperequireddescription
total integer (uint32) yes Every issue naming this milestone.
required integer (uint32) yes Total less cancelled: the denominator a progress figure uses.
by_readiness map of integer (uint32) yes One entry per readiness state that has at least one issue, keyed by its word.

Used by MilestoneGraph

MilestoneEdge

object
One dependency edge of the milestone's graph, from before to.
propertytyperequireddescription
from string yes The issue that must be real first.
to string yes The issue that waits for it.
external boolean yes True when one end is outside this milestone. Such an edge is why a milestone can be entirely blocked with nothing wrong inside it, so it is marked rather than dropped.

Used by MilestoneGraph

MilestoneGraph

object
One milestone as an executable dependency graph.
propertytyperequireddescription
milestone string yes The milestone id, as asked for.
declared boolean yes Whether the canonical model declares it. False is answered, not refused.
record string | null no Repository-relative path of the canonical record, when there is one.
title AttestedText → AttestedText yes One line naming the outcome, as authored.
outcome AttestedText → AttestedText yes What is true once it is real, as authored.
status AttestedText → AttestedText yes The derived milestone status.
rank AttestedCount → AttestedCount yes Its layer in the milestone graph: what orders the roadmap.
depends_on AttestedList → AttestedList yes The milestones it requires, as authored.
blocked_by AttestedList → AttestedList yes Those of them that are not DONE. Non-empty means every issue here is held back whatever its own dependencies say.
dependents AttestedList → AttestedList yes The milestones that require it.
nodes array of MilestoneNode → MilestoneNode yes Every issue of the milestone, in canonical order.
edges array of MilestoneEdge → MilestoneEdge yes Every dependency edge with at least one end in this milestone, sorted.
ready array of string yes The issues a worker may pick up now.
blocked array of string yes The issues waiting on a peer.
waiting array of string yes The issues waiting only on the milestone gate.
active array of string yes The issues somebody has started.
review array of string yes The issues awaiting confirmation.
completion_blocked array of string yes The issues declared complete whose evidence does not back that up.
complete array of string yes The issues finished on their own terms.
cancelled array of string yes The issues withdrawn.
critical_blockers array of CriticalBlocker → CriticalBlocker yes What to unblock first, most downstream work first.
parallelizable array of ParallelSet → ParallelSet yes The startable work partitioned into subsets that may run at the same time.
cycles array of array of string yes Every dependency cycle with an issue of this milestone in it, each as its strongly connected component in canonical order.
diagnostics array of DevTaskDiagnostic → DevTaskDiagnostic yes Everything wrong with the records of this milestone or of its issues.
counts MilestoneCounts → MilestoneCounts yes The issues counted by readiness.

Used by devtask.milestone

MilestoneNode

object
One issue of a milestone, as a node of its graph.
propertytyperequireddescription
issue string yes The issue id.
title string yes One line naming the outcome.
readiness TaskReadiness → TaskReadiness yes Where it stands as work.
canonical_status string yes The canonical status it refines.
wave integer | null no The execution wave, absent when a cycle prevents it from having one.
priority string yes p0 … p3.
parallel_safe boolean yes Whether it may run beside another issue of its wave.
blocked_by array of string yes What is not DONE yet, plus the milestone gate when it applies.
dependents array of string yes The issues that wait on it directly.
transitive_dependents integer (uint32) yes How many issues wait on it directly or through another.
scope array of string yes The paths it touches.

Used by MilestoneGraph

ParallelSet

object
One subset of the startable work that may genuinely run at the same time.
propertytyperequireddescription
wave integer (uint32) yes The wave every issue in it belongs to.
issues array of string yes The issues, in canonical order.
serialised array of ScopeConflict → ScopeConflict yes Why the set is not larger: the candidates of the same wave that had to be serialised against something already in it.

Used by MilestoneGraph

ReadinessVerdict

object
The readiness verdict, with everything it was derived from beside it.
propertytyperequireddescription
state TaskReadiness → TaskReadiness yes Where the task stands, as work.
canonical_status string yes The canonical status it refines, so the two can never be read apart.
reason string yes Why it is in that state, in one line.
startable boolean yes May a worker pick it up right now?
terminal boolean yes Is there nothing further to do?
blockers array of Blocker → Blocker yes Everything standing in the way, each with what to do about it.

Used by DevTask

ScopeConflict

object
Two issues of one wave that cannot run together, and the path that stops them.
propertytyperequireddescription
held string yes The issue already in the set.
excluded string yes The issue that could not join it.
path string yes The scope path they share, as one of them declares it.

Used by ParallelSet

TaskReadiness

"ready" | "blocked" | "waiting" | "in_progress" | "review" | "completion_blocked" | "complete" | "cancelled" | "undeclared"
Where a development task stands, as work.

use majordomus_cli::devtask::TaskReadiness;

// every state names the canonical status it refines, and refines only one
assert_eq!(TaskReadiness::Ready.canonical(), "READY");
assert_eq!(TaskReadiness::Waiting.canonical(), "BLOCKED");
assert_eq!(TaskReadiness::Blocked.canonical(), "BLOCKED");
assert_eq!(TaskReadiness::Review.canonical(), "VERIFY");
assert_eq!(TaskReadiness::CompletionBlocked.canonical(), "VERIFY");

// and one state is the absence of a record rather than a status of one
assert!(TaskReadiness::Undeclared.canonical().is_empty());
  • readyNothing holds it back and nobody has started it. Canonical READY.
  • blockedAt least one issue it depends on is not DONE. Canonical BLOCKED.
  • waitingEvery issue dependency is satisfied; the milestone gate holds it. Canonical BLOCKED, and a distinct situation because it is resolved in another milestone.
  • in_progressExecution began: the record carries started_at. Canonical ACTIVE.
  • reviewImplementation is declared finished and completion has not been recorded: the record carries verified_at. Canonical VERIFY.
  • completion_blockedCompletion was recorded and the evidence the record itself requires is not all there, so the plan refuses to call it DONE. Canonical VERIFY, and the case the evidence_missing finding is about.
  • completeFinished on its own terms: not cancelled, completion recorded, every required evidence token present. Canonical DONE.
  • cancelledWithdrawn. Canonical CANCELLED.
  • undeclaredThe canonical model does not declare this id. Not a status: the absence of a record.

Used by CriticalBlocker MilestoneNode ReadinessVerdict

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