-
Notifications
You must be signed in to change notification settings - Fork 0
feat(unic-ticket-specification): add portable ticket-specification workflow plugin #257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| --- | ||
| description: Fetch (if existing) and analyze a ticket against the configured code repos and linked docs; surface gaps, ambiguities, and open questions. Tracker-agnostic (Jira / Azure DevOps / GitHub). | ||
| argument-hint: <ticket reference or free-text ticket description> | ||
| --- | ||
|
|
||
| # Ticket fetch + analysis | ||
|
|
||
| You are preparing a ticket for implementation readiness. This step gathers all | ||
| context. Do **not** write anything back to the tracker. | ||
|
|
||
| ## Inputs | ||
|
|
||
| - Original user input: `$ARGUMENTS` | ||
| - Detected input (JSON: `mode` = existing|create, `key`, `project`): `$detect-input.output` | ||
| - **Project config: read `.archon/ticket-spec.config.yaml` FIRST** — it defines | ||
| the tracker type, access method, repos, docs source, and tenant/org/project. | ||
|
|
||
| Everything tracker- and project-specific comes from that config. Do not assume a | ||
| particular tracker, tenant, or repo layout. | ||
|
|
||
| ## Tooling: MCP-first, CLI fallback (OS-independent) | ||
|
|
||
| - If `tracker.access.mcp` is `true`, a tracker MCP server is loaded for this | ||
| node. Prefer its tools. The server may need a moment to start (npx cold | ||
| start) — if its tools are not visible on your first attempt, wait briefly and | ||
| retry before giving up. | ||
| - Otherwise (or if MCP tools never appear), fall back to the CLI named in | ||
| `tracker.access.cli` via Bash. Use only portable, non-interactive commands | ||
| that work the same on Windows and macOS (no shell-specific syntax, no | ||
| OS-specific paths). Examples per tracker: | ||
| - jira → Atlassian MCP, else `jira issue view <key> --plain` | ||
| - az → `az boards work-item show --id <id> --output json` (Azure DevOps) | ||
| - gh → `gh issue view <number> --repo <owner/repo> --json ...` (GitHub) | ||
|
|
||
| ## Jira cloudId resolution (jira tracker only) | ||
|
|
||
| If `tracker.type` is `jira` and `tracker.jira.cloud_id` is **empty**, resolve it | ||
| ONCE before any Jira/Confluence call: invoke `getAccessibleAtlassianResources` | ||
| and pick the resource whose `url` matches `tracker.jira.site_url`; use that `id` | ||
| as the cloudId everywhere below. (If only one resource is returned, use it.) If a | ||
| non-empty `cloud_id` is configured, use it directly. The same resolved cloudId | ||
| applies to Confluence when `docs.type` is `confluence`. | ||
|
|
||
| ## Step 0 — Fetch the ticket (existing path only) | ||
|
|
||
| If `$detect-input.output.mode` is `existing`, fetch the ticket FIRST, then write | ||
| it to `$ARTIFACTS_DIR/ticket.md`. Use the method for `tracker.type`: | ||
|
|
||
| - **jira**: `getJiraIssue` (cloudId from `tracker.jira.cloud_id`, issue key from | ||
| `$detect-input.output.key`) for summary, description, issue type, status, | ||
| comments; `getJiraIssueRemoteIssueLinks` to discover linked pages. | ||
| - **azure-devops**: fetch the work item by id (`tracker.azure_devops.org_url` + | ||
| `project`) for title, description/repro steps, work-item type, state, | ||
| comments, and linked artifacts. | ||
| - **github**: fetch the issue from `tracker.github.issues_repo` by number for | ||
| title, body, labels, state, and comments. | ||
|
|
||
| Write the fetched content (summary/title, type, status, full description, | ||
| relevant comments, links) to `$ARTIFACTS_DIR/ticket.md`. Record the exact | ||
| **issue type name** at the top of that file (e.g. `Issue type: Bug`). | ||
|
|
||
| If `mode` is `create`, there is no ticket to fetch — skip this step. | ||
|
|
||
| ## Step 0b — Resolve the target | ||
|
|
||
| Decide where the ticket belongs and write `$ARTIFACTS_DIR/target.json`: | ||
|
|
||
| ``` | ||
| { | ||
| "mode": "create" | "existing", | ||
| "tracker": "jira" | "azure-devops" | "github", | ||
| "project_key": "<Jira project key | ADO project | GitHub owner/repo>", | ||
| "project_name": "<human name>", | ||
| "key": "<existing reference, else empty>", | ||
| "reason": "<one line: why this target>" | ||
| } | ||
| ``` | ||
|
|
||
| - `tracker` = `tracker.type` from config. | ||
| - **Existing**: `key` = `$detect-input.output.key`. `project_key` = | ||
| - jira: the key prefix of that reference; | ||
| - azure-devops: `tracker.azure_devops.project`; | ||
| - github: `tracker.github.issues_repo`. | ||
| - **Create**: | ||
| - jira: if `$detect-input.output.project` is non-empty use it; else if the | ||
| input names a project use that; else use `tracker.jira.default_project`. | ||
| (If the tracker exposes a project list and the right one is ambiguous, you | ||
| may call `getVisibleJiraProjects` to pick the best match; fall back to the | ||
| default and say so in `reason`.) | ||
| - azure-devops: `tracker.azure_devops.project`. | ||
| - github: `tracker.github.issues_repo`. | ||
| - `key` = "". | ||
|
|
||
| This `target.json` is authoritative for the apply step and is shown to the human | ||
| at the approval gate, who can override it. | ||
|
|
||
| ## Step 1 — Analyze | ||
|
|
||
| 1. **Establish the subject.** | ||
|
|
||
| - Existing path: use `$ARTIFACTS_DIR/ticket.md` as the source of truth. | ||
| - Create path: use `$ARGUMENTS` as the raw requirement. | ||
|
|
||
| 2. **Explore the code — ACROSS ALL configured repos.** Iterate over every entry | ||
| in `repos` from the config. For each, resolve its `path` (relative to the | ||
| working directory or absolute; treat paths as forward-slash, OS-neutral) and | ||
| use Read / Grep / Glob within it to locate the components, modules, services | ||
| or pages this ticket touches. Identify: | ||
|
|
||
| - The concrete files / areas that would change (note **which repo** each is in). | ||
| - Existing patterns or prior art for the requested behaviour. | ||
| - Technical constraints, dependencies, and cross-repo integration points. | ||
|
|
||
| If a configured repo path does not exist on this machine, note it as a gap and | ||
| continue with the repos that are present — never fail the analysis over a | ||
| missing checkout. | ||
|
|
||
| 3. **Pull linked documentation** according to `docs.type`: | ||
|
|
||
| - `confluence`: fetch linked/related pages with `getConfluencePage` / | ||
| `searchConfluenceUsingCql` (cloudId from `docs.confluence.cloud_id`). | ||
| - `azure-wiki`: fetch the relevant wiki pages from the Azure DevOps project. | ||
| - `github-wiki`: read the repo wiki / docs. | ||
| - `none`: skip. | ||
| Summarise anything that affects scope or acceptance criteria. | ||
|
|
||
| 4. **Identify gaps.** Explicitly list missing information, | ||
| ambiguities/contradictions, assumptions you would have to make, and open | ||
| questions for the requester / PO. | ||
|
|
||
| ## Output | ||
|
|
||
| Write a structured analysis to **`$ARTIFACTS_DIR/analysis.md`** with these sections: | ||
|
|
||
| ``` | ||
| # Analysis: <ticket summary> | ||
|
|
||
| ## Subject & intent | ||
| ## Affected code areas | ||
| - <repo>: <file/module> — <why it is relevant> | ||
|
|
||
| ## Linked documentation | ||
| ## Technical constraints & dependencies | ||
| ## Open questions | ||
| - [ ] <question> | ||
|
|
||
| ## Assumptions | ||
| - <assumption> | ||
| ``` | ||
|
|
||
| Cite `repo:file_path:line` references where you found relevant code. This | ||
| analysis (plus `ticket.md`) is the foundation for classification, the rewritten | ||
| description, and the estimate — capture everything that affects scope. | ||
|
|
||
| After writing the file(s), print a one-paragraph summary of the key findings and | ||
| the number of open questions to your output. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| --- | ||
| description: Create a new ticket from the approved draft and record the PERT estimate. Tracker-agnostic (Jira / Azure DevOps / GitHub). | ||
| argument-hint: <free-text ticket description> | ||
| --- | ||
|
|
||
| # Apply — CREATE new ticket | ||
|
|
||
| The draft and estimate have been **approved by a human**. Create the ticket now. | ||
|
|
||
| ## Inputs | ||
|
|
||
| - Config: `.archon/ticket-spec.config.yaml` (tracker type, access, ids/types/labels) | ||
| - Original user input: `$ARGUMENTS` | ||
| - Target (JSON: `tracker`, `project_key`, `project_name`, `reason`): read `$ARTIFACTS_DIR/target.json` | ||
| - Approved description: read `$ARTIFACTS_DIR/draft-description.md` | ||
| - Approved estimate: read `$ARTIFACTS_DIR/estimate.md` | ||
| - Classification (JSON: `kind`, `issue_type_name`): `$classify.output` | ||
|
|
||
| The draft, estimate, and `target.json` already reflect any reviewer feedback, so | ||
| apply exactly what is in those files. | ||
|
|
||
| ## Tooling | ||
|
|
||
| MCP-first (the tracker MCP server is loaded for this node), CLI fallback via the | ||
| `tracker.access.cli` tool through Bash. Use only portable, non-interactive | ||
| commands (identical on Windows and macOS). | ||
|
|
||
| ## Steps — branch on `target.tracker` | ||
|
|
||
| Derive a concise, specific **summary/title** from the analysis and input first. | ||
|
|
||
| ### jira | ||
|
|
||
| 0. If `tracker.jira.cloud_id` is empty, resolve it via | ||
| `getAccessibleAtlassianResources` (pick the resource whose `url` matches | ||
| `tracker.jira.site_url`); otherwise use the configured value. Use this cloudId | ||
| for all Jira calls below. | ||
| 1. projectKey = `target.project_key`. | ||
| 2. Resolve the issue-type id for the classified `issue_type_name`: | ||
| - If `projectKey` equals `tracker.jira.default_project` and the name is in | ||
| `tracker.jira.issue_type_ids`, use that id. | ||
| - Otherwise call `getJiraProjectIssueTypesMetadata` (cloudId | ||
| `tracker.jira.cloud_id`, projectKey) and pick the id whose name matches. | ||
| If that exact type does not exist, choose the closest available and note it. | ||
| 3. `createJiraIssue` (cloudId, projectKey, issueTypeId, summary, description = | ||
| full contents of `draft-description.md`). | ||
| 4. Record the estimate with `addCommentToJiraIssue` — post `estimate.md` prefixed | ||
| with `*PERT effort estimate (generated by unic-ticket-specification):*`. | ||
| 5. If a time-tracking original estimate field is editable, optionally set it to | ||
| the weighted E (skip silently otherwise). | ||
|
|
||
| ### azure-devops | ||
|
|
||
| 1. Work-item type = `tracker.azure_devops.work_item_types.bug` when kind=BUG, | ||
| else `...work_item_types.cr_story`. | ||
| 2. Create the work item in `tracker.azure_devops.org_url` / `project` with the | ||
| title and the description = full contents of `draft-description.md` | ||
| (e.g. `az boards work-item create --type "<type>" --title "<title>" ...`, | ||
| then set the description/repro field). | ||
| 3. Record the estimate as a comment on the work item (post `estimate.md`, | ||
| same prefix as above). Optionally set the Effort/Original Estimate field to E. | ||
|
|
||
| ### github | ||
|
|
||
| 1. repo = `target.project_key` (the `issues_repo`). | ||
| 2. labels = `tracker.github.labels.bug` when kind=BUG, else `...labels.cr_story`. | ||
| 3. Create the issue (title + body = full contents of `draft-description.md`) | ||
| with those labels (e.g. `gh issue create --repo <repo> --title ... --body-file ... --label ...`). | ||
| 4. Record the estimate as an issue comment (post `estimate.md`, same prefix). | ||
|
|
||
| ## After writing (all trackers) | ||
|
|
||
| Update the persisted local file (path in `$ARTIFACTS_DIR/local-output-path.txt`): | ||
| change its `Status:` line to `WRITTEN TO TRACKER` and append a `## Result` section | ||
| with the created reference, its URL, issue type, and recorded PERT E value. | ||
|
|
||
| ## Output | ||
|
|
||
| Print the created ticket reference, its URL, the chosen issue type, and the | ||
| recorded PERT E value. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| --- | ||
| description: Update an existing ticket with the approved description and record the PERT estimate. Tracker-agnostic (Jira / Azure DevOps / GitHub). | ||
| argument-hint: <ticket reference> | ||
| --- | ||
|
|
||
| # Apply — UPDATE existing ticket | ||
|
|
||
| The draft and estimate have been **approved by a human**. Write the changes to | ||
| the existing ticket now. | ||
|
|
||
| ## Inputs | ||
|
|
||
| - Config: `.archon/ticket-spec.config.yaml` (tracker type, access) | ||
| - Target (JSON: `tracker`, `project_key`, `key`): read `$ARTIFACTS_DIR/target.json` | ||
| (falls back to `$detect-input.output` for `key` if absent) | ||
| - Approved description: read `$ARTIFACTS_DIR/draft-description.md` | ||
| - Approved estimate: read `$ARTIFACTS_DIR/estimate.md` | ||
|
|
||
| The draft and estimate already reflect any reviewer feedback, so write exactly | ||
| what is in those files. Do not change the title/summary or issue type. | ||
|
|
||
| ## Tooling | ||
|
|
||
| MCP-first (the tracker MCP server is loaded for this node), CLI fallback via the | ||
| `tracker.access.cli` tool through Bash. Use only portable, non-interactive | ||
| commands (identical on Windows and macOS). | ||
|
|
||
| ## Steps — branch on `target.tracker` | ||
|
|
||
| ### jira | ||
|
|
||
| 0. If `tracker.jira.cloud_id` is empty, resolve it via | ||
| `getAccessibleAtlassianResources` (pick the resource whose `url` matches | ||
| `tracker.jira.site_url`); otherwise use the configured value. | ||
| 1. `editJiraIssue` — cloudId (resolved above), issueIdOrKey = `key`, | ||
| set the description field to the full contents of `draft-description.md`. | ||
| 2. Record the estimate with `addCommentToJiraIssue` — post `estimate.md` prefixed | ||
| with `*PERT effort estimate (generated by unic-ticket-specification):*`. | ||
| 3. If the time-tracking original estimate is editable, optionally set it to E. | ||
|
|
||
| ### azure-devops | ||
|
|
||
| 1. Update the work item `key` in `tracker.azure_devops.org_url` / `project`, | ||
| setting the description/repro field to the full contents of | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Azure DevOps Suggest: render GitHub (line 52) is fine as-is since the issue body is Markdown-native; Jira (line 36) should use ADF/wiki markup, also not raw Markdown.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| `draft-description.md` (e.g. `az boards work-item update --id <key> ...`). | ||
| 2. Record the estimate as a comment on the work item (post `estimate.md`, same | ||
| prefix). Optionally set the Effort/Original Estimate field to E. | ||
|
|
||
| ### github | ||
|
|
||
| 1. repo = `target.project_key` (the `issues_repo`); issue number from `key`. | ||
| 2. Update the issue body to the full contents of `draft-description.md` | ||
| (e.g. `gh issue edit <number> --repo <repo> --body-file ...`). | ||
| 3. Record the estimate as an issue comment (post `estimate.md`, same prefix). | ||
|
|
||
| ## After writing (all trackers) | ||
|
|
||
| Update the persisted local file (path in `$ARTIFACTS_DIR/local-output-path.txt`): | ||
| change its `Status:` line to `WRITTEN TO TRACKER` and append a `## Result` section | ||
| with the reference, its URL, and recorded PERT E value. | ||
|
|
||
| ## Output | ||
|
|
||
| Print the updated ticket reference, its URL, confirmation that the description | ||
| was updated, and the recorded PERT E value. | ||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same bug on the create path. Azure DevOps
System.Descriptionis an HTML field; the raw Markdown fromdraft-description.mdrenders as literal#/**/|characters.Suggest rendering MD → HTML before the write:
Mirror of the
uts-apply-update.mdcomment. GitHub (line 67) is correct as Markdown; Jira (line 46) should be ADF/wiki markup.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, diff generated in my own project installation trying to solve this, in case this can help here too: