Submission requirements
Problem summary
create-work-item always writes the body to System.Description, and the field is not configurable. On Azure DevOps processes where the Bug form does not show System.Description — which is the default for Agile, Scrum and CMMI, all of which use Microsoft.VSTS.TCM.ReproSteps — every bug the agent files opens completely blank. The body is stored, on a field the form does not render, so nothing is lost but nothing is visible either.
This is worse than a formatting problem. The work item is created successfully, the safe-output executor reports success, and the pipeline goes green; the only way to notice is for a human to open the bug and find it empty. Our nightly analysis agent filed ten bugs before anyone spotted it.
CreateWorkItemConfig already supports work-item-type, so an operator can select Bug — but selecting Bug is exactly what makes the body invisible. custom-fields does not help: it is a compile-time constant map, so it can carry boilerplate but not the per-item body the agent generated.
For reference, in our project Bug is the only built-in type whose form omits System.Description:
| Work item type |
Large text field on form |
| Bug |
Microsoft.VSTS.TCM.ReproSteps |
| Task, Epic, Feature, Product Backlog Item, Scenario, Test Case, … |
System.Description |
So a bug-filing agent — arguably the most common use of this safe output — is the one case that does not work.
Reproduction details
Environment: ado-aw 0.50.0, standalone target, Azure DevOps msazure/One (Hosted XML process), work-item-type: Bug.
Front matter:
safe-outputs:
create-work-item:
work-item-type: Bug
area-path: "One\\AzureStack\\ASZ-VM self service"
The Bug form definition, from GET /_apis/wit/workitemtypes/Bug — the only HtmlFieldControl for the body is ReproSteps, and System.Description is not on the form at all:
<Control Label="" LabelPosition="Top" FieldName="Microsoft.VSTS.TCM.ReproSteps" Type="HtmlFieldControl" Margin="(0,0,0,10)" />
After a run that created work item 39292210, GET /_apis/wit/workitems/39292210:
System.Description len=1856 (populated, not rendered by the form)
Microsoft.VSTS.TCM.ReproSteps absent (rendered by the form, empty)
Observed: the bug opens with an empty body.
Expected: the body appears on the work item form.
Second, related problem in the same path: the stored value is escaped, so even on a type that does render System.Description the body is unreadable. The MCP layer escapes angle brackets on the way out:
$ ... tools/call create-work-item {"description":"<h2>Hi</h2><p>x <string> y</p>", ...}
emitted ndjson:
{"description":"<h2>Hi</h2><p>x <string> y</p>", ...}
and the executor writes that through unchanged, with multilineFieldsFormat reporting {"System.Description": "markdown"}. The reader sees literal <h2>Overlay nightly regression in Collect</h2> as text. Note < is left alone while < is escaped, so the transform is not idempotent and cannot be reliably undone by the caller either: content that was correctly escaped by the generator is now indistinguishable from content the escaper produced.
Proposed next step
Two things, either of which is useful on its own:
-
Add a description-field (or body-field) key to CreateWorkItemConfig, defaulting to System.Description, so an operator filing bugs can set Microsoft.VSTS.TCM.ReproSteps. This is a small, backward-compatible change and would remove the need for the post-processing job we have had to add.
Better still would be to default it by work item type — Bug → ReproSteps, everything else → System.Description — since the current default is wrong for the single most common case.
-
Make the body format explicit rather than incidental. If the intent is that descriptions are Markdown, escaping HTML is reasonable but the executor should then set multilineFieldsFormat to markdown and the docs should say so, because HTML is what Azure DevOps work item fields natively use and what agents will produce by default. If the intent is HTML, the escaping should not happen. Today the value is escaped as though it were HTML-unsafe and then stored as Markdown, which renders correctly under neither.
Workaround for anyone hitting this: add a teardown: job that copies System.Description into Microsoft.VSTS.TCM.ReproSteps, HTML-decoding on the way, for work items created by the run. That works but it needs a second ADO token and a WIQL query to find the items the run just created, purely to move a field.
Submission requirements
.github/agents/ado-aw.agent.md.githubnext/ado-aw.Problem summary
create-work-itemalways writes the body toSystem.Description, and the field is not configurable. On Azure DevOps processes where the Bug form does not showSystem.Description— which is the default for Agile, Scrum and CMMI, all of which useMicrosoft.VSTS.TCM.ReproSteps— every bug the agent files opens completely blank. The body is stored, on a field the form does not render, so nothing is lost but nothing is visible either.This is worse than a formatting problem. The work item is created successfully, the safe-output executor reports success, and the pipeline goes green; the only way to notice is for a human to open the bug and find it empty. Our nightly analysis agent filed ten bugs before anyone spotted it.
CreateWorkItemConfigalready supportswork-item-type, so an operator can selectBug— but selectingBugis exactly what makes the body invisible.custom-fieldsdoes not help: it is a compile-time constant map, so it can carry boilerplate but not the per-item body the agent generated.For reference, in our project
Bugis the only built-in type whose form omitsSystem.Description:Microsoft.VSTS.TCM.ReproStepsSystem.DescriptionSo a bug-filing agent — arguably the most common use of this safe output — is the one case that does not work.
Reproduction details
Environment:
ado-aw0.50.0, standalone target, Azure DevOpsmsazure/One(Hosted XML process),work-item-type: Bug.Front matter:
The
Bugform definition, fromGET /_apis/wit/workitemtypes/Bug— the onlyHtmlFieldControlfor the body isReproSteps, andSystem.Descriptionis not on the form at all:After a run that created work item 39292210,
GET /_apis/wit/workitems/39292210:Observed: the bug opens with an empty body.
Expected: the body appears on the work item form.
Second, related problem in the same path: the stored value is escaped, so even on a type that does render
System.Descriptionthe body is unreadable. The MCP layer escapes angle brackets on the way out:and the executor writes that through unchanged, with
multilineFieldsFormatreporting{"System.Description": "markdown"}. The reader sees literal<h2>Overlay nightly regression in Collect</h2>as text. Note<is left alone while<is escaped, so the transform is not idempotent and cannot be reliably undone by the caller either: content that was correctly escaped by the generator is now indistinguishable from content the escaper produced.Proposed next step
Two things, either of which is useful on its own:
Add a
description-field(orbody-field) key toCreateWorkItemConfig, defaulting toSystem.Description, so an operator filing bugs can setMicrosoft.VSTS.TCM.ReproSteps. This is a small, backward-compatible change and would remove the need for the post-processing job we have had to add.Better still would be to default it by work item type —
Bug→ReproSteps, everything else →System.Description— since the current default is wrong for the single most common case.Make the body format explicit rather than incidental. If the intent is that descriptions are Markdown, escaping HTML is reasonable but the executor should then set
multilineFieldsFormattomarkdownand the docs should say so, because HTML is what Azure DevOps work item fields natively use and what agents will produce by default. If the intent is HTML, the escaping should not happen. Today the value is escaped as though it were HTML-unsafe and then stored as Markdown, which renders correctly under neither.Workaround for anyone hitting this: add a
teardown:job that copiesSystem.DescriptionintoMicrosoft.VSTS.TCM.ReproSteps, HTML-decoding on the way, for work items created by the run. That works but it needs a second ADO token and a WIQL query to find the items the run just created, purely to move a field.