You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Eliminate INVALID_INPUT failures when updating Jira issues via MCP
Problem
Updates to Jira issues via the update_jira_issue MCP tool fail repeatedly with opaque INVALID_INPUT errors when the description_html or comment_html payload contains HTML that the agent has every reason to believe is valid (semantic HTML, well-formed, no obvious problems). Each failure provides zero diagnostic signal ({"errorMessages":["INVALID_INPUT"],"errors":{}}), so the agent burns iterations on blind retries.
The operation is high-frequency and the failure mode is recurring in well-defined ways. The agent is the unreliable step in the middle, regenerating HTML stochastically each time. The goal is to eliminate (or at least sharply reduce) these failures without over-engineering the first intervention.
Context
Observed failure triggers
Three concrete triggers have been seen repeatedly:
Named HTML entities other than &/</> (e.g., —, , …).
Confluence-only macros (<ac:task-list>, <ac:structured-macro>, etc.) inadvertently included by an agent that has been working with Confluence content in the same session.
File-path mode of the MCP tool — passing a path string in lieu of inline HTML.
Why these fail (inferred class)
The MCP tool advertises a permissive HTML surface, but the payload is converted into Atlassian Document Format (ADF) before persistence. The opaque error originates in that conversion. The general class of failure is:
HTML inputs that look valid to a generic HTML validator but cannot be losslessly mapped to Jira's ADF document model.
All three observed triggers fit this shape. There may be additional unknown instances of the class.
Why the agent is the right place to fix this (and why a sanitiser script is not the first move)
All three triggers are agent decisions about what to emit, not artefacts of an unavoidable transformation. The agent authors the HTML; it isn't sanitising third-party input. The first intervention should therefore be an explicit, prescriptive skill that names the rules — not a subprocess that polices the agent's output.
A deterministic sanitiser may be warranted later if explicit rules prove insufficient in practice. That decision should be gated on observed post-deploy failure rate, not on a hypothesis about reliability. To make that decision possible, the skill's recovery protocol must produce evidence (structured failure records) that can be reviewed periodically.
Existing constraints
The MCP tool's interface is fixed; we cannot extend it to accept Markdown directly.
The jira skill is a built-in platform skill (not part of this repo), so we cannot edit it.
Skills installed via codeassembly-agents install ship into ~/.rovodev/skills/<name>/ (or platform equivalents). The path-rewriter expands {platform_home_dir} literally inside SKILL.md.
codeassembly-agents is not installed onto user PATH; only the skill bundle ships globally.
Solution
Create a new user-invocable skill, update-jira-ticket, consisting of SKILL.md only — no helper script, no new dependencies, no install pipeline changes.
Mechanism
The skill body is short (~25–40 lines) and prescriptive. It covers:
When the skill applies — any call to update_jira_issue with description_html or comment_html.
Authoring rules — source content from a local Markdown artefact when one exists; otherwise compose in Markdown first. Convert to HTML using only the allowlisted elements; never hand-author HTML containing constructs outside the allowlist.
Forbidden constructs — <ac:*> macros (Confluence-only); named HTML entities other than &/</> (use literal Unicode: — not —, … not …, regular space or U+00A0 not ).
Invocation rules — always pass HTML inline; never use file-path mode of the MCP tool.
Recovery protocol — if INVALID_INPUT still fires after following the rules: send <p>ok</p> to confirm call shape; bisect the payload to isolate the smallest failing fragment; cap at 4 retries; append a structured failure record to a known JSONL location (see below); surface the failing fragment to the user.
Escalation criterion — explicitly named in the skill body: if recorded failures concentrate in known trigger classes, file a follow-up to add a deterministic sanitiser; if they distribute across unknown classes, the recovery protocol remains the right tool.
Failure record format (interim, until generic logging exists)
The skill instructs the agent, at the end of the recovery protocol, to append a single JSON object per line to ~/ai-artifacts/skill-failures/update-jira-ticket.jsonl. Each record contains at minimum: timestamp, skill (update-jira-ticket), project_slug, failing_fragment, and notes. A separate follow-up ticket will replace this ad-hoc location with a generic skill-failure logging mechanism.
Auto-load
The skill's description: frontmatter is phrased to trigger the agent's skill-loading heuristics whenever the agent is about to call update_jira_issue with description_html or comment_html. The skill is also user-invocable as !update-jira-ticket.
Acceptance criteria
A new skill update-jira-ticket exists at packages/agents/content/skills/update-jira-ticket/SKILL.md, with frontmatter that includes user-invocable: true and a description: phrased to auto-load on calls to update_jira_issue involving description_html or comment_html.
The skill body is body-only — no peer files, no helper script, no new package dependencies, no install-pipeline changes.
The skill body prescribes a single correct path: Markdown source → HTML constrained to the allowlist → inline payload, with explicit forbidden constructs (<ac:*>, named entities outside &/</>, file-path mode).
The skill body includes the recovery protocol (<p>ok</p> probe → bisection → 4-retry cap → surface failing fragment), and instructs the agent to append a structured JSONL failure record to ~/ai-artifacts/skill-failures/update-jira-ticket.jsonl after a failed recovery attempt.
The failure record format is documented inline in the skill body with at minimum these fields: timestamp (ISO 8601 UTC), skill (update-jira-ticket), project_slug, failing_fragment, notes.
The skill body names an explicit escalation criterion: under what observed failure pattern a follow-up to add a deterministic sanitiser would be warranted.
The skill installs successfully via codeassembly-agents install and the {platform_home_dir} mechanism (if used in the body) substitutes correctly.
Any documentation that enumerates skills (if such an index exists in the repo) includes update-jira-ticket. If no such index exists, this is a no-op.
A follow-up ticket is filed proposing a generic skill-failure logging mechanism (JSONL, with at least project_slug, skill, timestamp) that this skill (and others) can adopt in place of the interim ad-hoc location.
Eliminate
INVALID_INPUTfailures when updating Jira issues via MCPProblem
Updates to Jira issues via the
update_jira_issueMCP tool fail repeatedly with opaqueINVALID_INPUTerrors when thedescription_htmlorcomment_htmlpayload contains HTML that the agent has every reason to believe is valid (semantic HTML, well-formed, no obvious problems). Each failure provides zero diagnostic signal ({"errorMessages":["INVALID_INPUT"],"errors":{}}), so the agent burns iterations on blind retries.The operation is high-frequency and the failure mode is recurring in well-defined ways. The agent is the unreliable step in the middle, regenerating HTML stochastically each time. The goal is to eliminate (or at least sharply reduce) these failures without over-engineering the first intervention.
Context
Observed failure triggers
Three concrete triggers have been seen repeatedly:
&/</>(e.g.,—, ,…).<ac:task-list>,<ac:structured-macro>, etc.) inadvertently included by an agent that has been working with Confluence content in the same session.Why these fail (inferred class)
The MCP tool advertises a permissive HTML surface, but the payload is converted into Atlassian Document Format (ADF) before persistence. The opaque error originates in that conversion. The general class of failure is:
All three observed triggers fit this shape. There may be additional unknown instances of the class.
Why the agent is the right place to fix this (and why a sanitiser script is not the first move)
All three triggers are agent decisions about what to emit, not artefacts of an unavoidable transformation. The agent authors the HTML; it isn't sanitising third-party input. The first intervention should therefore be an explicit, prescriptive skill that names the rules — not a subprocess that polices the agent's output.
A deterministic sanitiser may be warranted later if explicit rules prove insufficient in practice. That decision should be gated on observed post-deploy failure rate, not on a hypothesis about reliability. To make that decision possible, the skill's recovery protocol must produce evidence (structured failure records) that can be reviewed periodically.
Existing constraints
jiraskill is a built-in platform skill (not part of this repo), so we cannot edit it.codeassembly-agents installship into~/.rovodev/skills/<name>/(or platform equivalents). The path-rewriter expands{platform_home_dir}literally insideSKILL.md.codeassembly-agentsis not installed onto user PATH; only the skill bundle ships globally.Solution
Create a new user-invocable skill,
update-jira-ticket, consisting ofSKILL.mdonly — no helper script, no new dependencies, no install pipeline changes.Mechanism
The skill body is short (~25–40 lines) and prescriptive. It covers:
update_jira_issuewithdescription_htmlorcomment_html.h1–h6,p,ul,ol,li,strong,em,code,pre,a,blockquote,hr,br,table,thead,tbody,tr,th,td. Nothing else.<ac:*>macros (Confluence-only); named HTML entities other than&/</>(use literal Unicode:—not—,…not…, regular space or U+00A0 not ).INVALID_INPUTstill fires after following the rules: send<p>ok</p>to confirm call shape; bisect the payload to isolate the smallest failing fragment; cap at 4 retries; append a structured failure record to a known JSONL location (see below); surface the failing fragment to the user.Failure record format (interim, until generic logging exists)
The skill instructs the agent, at the end of the recovery protocol, to append a single JSON object per line to
~/ai-artifacts/skill-failures/update-jira-ticket.jsonl. Each record contains at minimum:timestamp,skill(update-jira-ticket),project_slug,failing_fragment, andnotes. A separate follow-up ticket will replace this ad-hoc location with a generic skill-failure logging mechanism.Auto-load
The skill's
description:frontmatter is phrased to trigger the agent's skill-loading heuristics whenever the agent is about to callupdate_jira_issuewithdescription_htmlorcomment_html. The skill is also user-invocable as!update-jira-ticket.Acceptance criteria
update-jira-ticketexists atpackages/agents/content/skills/update-jira-ticket/SKILL.md, with frontmatter that includesuser-invocable: trueand adescription:phrased to auto-load on calls toupdate_jira_issueinvolvingdescription_htmlorcomment_html.<ac:*>, named entities outside&/</>, file-path mode).<p>ok</p>probe → bisection → 4-retry cap → surface failing fragment), and instructs the agent to append a structured JSONL failure record to~/ai-artifacts/skill-failures/update-jira-ticket.jsonlafter a failed recovery attempt.timestamp(ISO 8601 UTC),skill(update-jira-ticket),project_slug,failing_fragment,notes.codeassembly-agents installand the{platform_home_dir}mechanism (if used in the body) substitutes correctly.update-jira-ticket. If no such index exists, this is a no-op.project_slug,skill,timestamp) that this skill (and others) can adopt in place of the interim ad-hoc location.