agentme 0.35.2 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.xdrs/agentme/edrs/application/skills/250-github-connector/SKILL.md +187 -0
- package/.xdrs/agentme/edrs/application/skills/250-github-connector/SKILL.test.md +118 -0
- package/.xdrs/agentme/edrs/application/skills/251-azure-devops-connector/SKILL.md +205 -0
- package/.xdrs/agentme/edrs/application/skills/251-azure-devops-connector/SKILL.test.md +114 -0
- package/.xdrs/agentme/edrs/index.md +3 -0
- package/.xdrs/agentme/edrs/principles/017-skill-testing.md +3 -0
- package/.xdrs/agentme/edrs/principles/skills/150-refine-plan-mode/SKILL.md +25 -8
- package/.xdrs/agentme/edrs/principles/skills/150-refine-plan-mode/SKILL.test.md +27 -3
- package/.xdrs/agentme/edrs/principles/skills/400-pr-owner-assistant/Makefile +8 -0
- package/.xdrs/agentme/edrs/principles/skills/400-pr-owner-assistant/SKILL.md +633 -0
- package/.xdrs/agentme/edrs/principles/skills/400-pr-owner-assistant/SKILL.test.md +174 -0
- package/.xdrs/agentme/edrs/principles/skills/400-pr-owner-assistant/scripts/post-replies-azure-devops.js +219 -0
- package/.xdrs/agentme/edrs/principles/skills/400-pr-owner-assistant/scripts/post-replies-azure-devops.test.js +253 -0
- package/.xdrs/agentme/edrs/principles/skills/400-pr-owner-assistant/scripts/post-replies-github.js +237 -0
- package/.xdrs/agentme/edrs/principles/skills/400-pr-owner-assistant/scripts/post-replies-github.test.js +272 -0
- package/.xdrs/agentme/edrs/principles/skills/400-pr-owner-assistant/scripts/update-section.js +246 -0
- package/.xdrs/agentme/edrs/principles/skills/400-pr-owner-assistant/scripts/update-section.test.js +199 -0
- package/package.json +1 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 250-github-connector
|
|
3
|
+
description: >
|
|
4
|
+
Base connector providing authentication, read access, and write access to GitHub pull
|
|
5
|
+
requests and their comments via the gh CLI. Pure I/O -- no triage logic, no business
|
|
6
|
+
decisions. Activate when an agent or skill (such as pr-owner-assistant) needs to fetch or
|
|
7
|
+
post PR comments, resolve review threads, or check out a PR branch on GitHub.
|
|
8
|
+
metadata:
|
|
9
|
+
author: flaviostutz
|
|
10
|
+
version: "1.1"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
Reusable authentication and connection skill for GitHub pull requests, per
|
|
16
|
+
[agentme-edr-127](../../127-external-system-adapter-skills.md) rule 06 (connector naming).
|
|
17
|
+
Wraps the `gh` CLI -- GitHub's own supported API client -- so callers never construct raw
|
|
18
|
+
REST/GraphQL calls or handle GitHub-specific auth themselves. Contains no business logic (per
|
|
19
|
+
rule 05): it does not decide what a comment means, what action to take, or when to reply --
|
|
20
|
+
it only reads and writes data and normalizes it to the shape consumed by
|
|
21
|
+
[`400-pr-owner-assistant`](../../../principles/skills/400-pr-owner-assistant/SKILL.md).
|
|
22
|
+
|
|
23
|
+
This is a base connector skill (number range 250-299).
|
|
24
|
+
|
|
25
|
+
## Instructions
|
|
26
|
+
|
|
27
|
+
### Authentication check
|
|
28
|
+
|
|
29
|
+
1. Verify the `gh` CLI is installed (`gh --version`); if missing, ask the human whether to
|
|
30
|
+
install it now via the appropriate package manager for their OS (e.g. `brew install gh`
|
|
31
|
+
on macOS). Only run the install command after explicit confirmation; if the human
|
|
32
|
+
declines or the install fails, report the install requirement and stop.
|
|
33
|
+
2. Run `gh auth status`. If authenticated, proceed -- this is the preferred path since `gh`
|
|
34
|
+
manages its own session token securely (per agentme-edr-124's least-exposure principle)
|
|
35
|
+
and needs no secret handling here.
|
|
36
|
+
3. If not authenticated, run
|
|
37
|
+
`gh auth login --hostname github.com --git-protocol https --web` instead of bare
|
|
38
|
+
`gh auth login` -- these flags answer the "Where do you use GitHub?", "preferred
|
|
39
|
+
protocol?", and "how would you like to authenticate?" prompts non-interactively so the
|
|
40
|
+
human is never asked them. `gh` still asks one local yes/no question ("Authenticate Git
|
|
41
|
+
with your GitHub credentials?"); accept its default (`Y`) automatically, since it only
|
|
42
|
+
wires the existing `gh` credential helper into git and needs no human input. The only
|
|
43
|
+
step that still requires the human is the one-time code / "Press Enter to open ... in
|
|
44
|
+
your browser" prompt that follows -- `gh` stores the resulting token in its own secure
|
|
45
|
+
storage once that completes. Never ask the human for a raw PAT and never read, request,
|
|
46
|
+
or feed a token to `gh` directly. Do not proceed with a write operation until
|
|
47
|
+
`gh auth status` reports an authenticated session.
|
|
48
|
+
4. Never substitute `gh` with a direct HTTP call (`curl`, `fetch`, or any other HTTP client)
|
|
49
|
+
against the GitHub REST/GraphQL API, and never scrape the PR's rendered HTML page as a
|
|
50
|
+
workaround -- this applies to reads as much as writes, and applies even when the target
|
|
51
|
+
data is public. If `gh` is missing or unauthenticated, stop and resolve that first (steps
|
|
52
|
+
1-3 above); do not degrade to an alternative retrieval method to route around it.
|
|
53
|
+
|
|
54
|
+
### Reading data
|
|
55
|
+
|
|
56
|
+
All read commands are plain `gh` invocations; none require confirmation (per
|
|
57
|
+
agentme-edr-127 rule 04, read-only operations are exempt from the HITL confirmation step
|
|
58
|
+
only -- they are not exempt from the CLI-only channel). Every read below MUST go through
|
|
59
|
+
`gh`; never construct the equivalent call with `curl`/another HTTP client, and never fetch
|
|
60
|
+
or scrape the PR's rendered web page as a substitute. When running `gh` from an automated
|
|
61
|
+
or non-interactive shell, prefix calls with `GH_PAGER=cat` (see Known Issues) so output is
|
|
62
|
+
never lost to a pager.
|
|
63
|
+
|
|
64
|
+
- PR metadata: `gh pr view <n> --json title,body,baseRefName,headRefName,url,state,isCrossRepository,headRepositoryOwner,headRepository`
|
|
65
|
+
- Issue-level (top) comments: `gh api repos/{owner}/{repo}/issues/{n}/comments`
|
|
66
|
+
- Review (file/line) comments: `gh api repos/{owner}/{repo}/pulls/{n}/comments`
|
|
67
|
+
- Review summaries: `gh api repos/{owner}/{repo}/pulls/{n}/reviews`
|
|
68
|
+
- Thread resolution state (REST does not expose this): `gh api graphql` with a
|
|
69
|
+
`reviewThreads` query on the PR, reading `isResolved` and each thread's comment node ids.
|
|
70
|
+
|
|
71
|
+
Normalize every fetched item to the shared record shape (`id`, `kind`, `status`, `can_reply`,
|
|
72
|
+
`can_resolve`, `path`, `line`, `content`, `author`, `in_reply_to`, `diff_hunk`, `url`):
|
|
73
|
+
- `kind` is `"issue-comment"`, `"review-comment"`, or `"review-summary"`.
|
|
74
|
+
- `status` is `"resolved"` when the GraphQL thread lookup marks it resolved, else `"open"`.
|
|
75
|
+
GitHub has no `wontfix`/`closed` state of its own -- `pr-owner-assistant` tracks those
|
|
76
|
+
locally.
|
|
77
|
+
- `can_resolve` is `true` only for `"review-comment"` items belonging to a resolvable
|
|
78
|
+
thread; `"issue-comment"` and `"review-summary"` are never resolvable -- set `false`.
|
|
79
|
+
- `in_reply_to` is resolved to the thread's top-level/root comment id, never an intermediate
|
|
80
|
+
reply, so replies always thread correctly.
|
|
81
|
+
- If the reply target is a reply-to-a-reply, resolve `in_reply_to` up to the root comment id
|
|
82
|
+
first (GitHub only allows replying to the root of a review thread).
|
|
83
|
+
- `diff_hunk` is taken verbatim from the `diff_hunk` field already present on each
|
|
84
|
+
`"review-comment"` item returned by the review-comments read command above -- no extra
|
|
85
|
+
fetch needed. Null for `"issue-comment"` and `"review-summary"` items, since neither is
|
|
86
|
+
file/line-scoped.
|
|
87
|
+
- `url` is taken verbatim from the `html_url` field already present on every issue-comment,
|
|
88
|
+
review-comment, and review object returned by the read commands above -- no extra fetch
|
|
89
|
+
needed for any `kind`.
|
|
90
|
+
|
|
91
|
+
### Writing data
|
|
92
|
+
|
|
93
|
+
Before any write below, show the mandatory confirmation (per agentme-edr-127 rule 04):
|
|
94
|
+
**System** (`owner/repo` + PR number), **Operation**, **Fields** (exact verbatim text to
|
|
95
|
+
post), **Estimated impact** (visible to PR participants, triggers notifications). Wait for
|
|
96
|
+
explicit confirmation; never proceed on an assumed "yes."
|
|
97
|
+
|
|
98
|
+
- Reply to an issue-level comment: `gh api repos/{owner}/{repo}/issues/{n}/comments -f body="..."`
|
|
99
|
+
- Reply to a review thread: `gh api repos/{owner}/{repo}/pulls/{n}/comments -f body="..." -F in_reply_to=<root-comment-id>`
|
|
100
|
+
- Post a new general PR comment: `gh pr comment <n> --body "..."`
|
|
101
|
+
- Resolve a review thread: `gh api graphql` with a `resolveReviewThread` mutation, passing
|
|
102
|
+
the thread's GraphQL node id (not the REST numeric id -- these are different identifier
|
|
103
|
+
spaces; see Known Issues).
|
|
104
|
+
- Check out the PR branch: `gh pr checkout <n>`.
|
|
105
|
+
|
|
106
|
+
### Constraints
|
|
107
|
+
|
|
108
|
+
- MUST use the `gh` CLI for every read and write handled by this connector -- never fall
|
|
109
|
+
back to `curl`, another raw HTTP client, or scraping the PR's HTML page, even when `gh` is
|
|
110
|
+
missing, unauthenticated, rate-limited, or erroring, and even when the target data is
|
|
111
|
+
public.
|
|
112
|
+
- MUST stop and follow the Authentication check steps above when `gh` cannot complete a
|
|
113
|
+
request, instead of silently degrading to an alternative retrieval method.
|
|
114
|
+
|
|
115
|
+
## Examples
|
|
116
|
+
|
|
117
|
+
**Input**: fetch all comments for `https://github.com/acme/widgets/pull/482`
|
|
118
|
+
|
|
119
|
+
Runs `gh pr view 482 --json ...` for metadata, then the three read commands above for
|
|
120
|
+
issue-comments, review-comments, and reviews, then one `gh api graphql` call for thread
|
|
121
|
+
resolution state, and returns a single normalized list.
|
|
122
|
+
|
|
123
|
+
**Input**: reply to review comment id `review-comment/91234` and mark it resolved
|
|
124
|
+
|
|
125
|
+
Shows the mandatory confirmation summary first. On explicit "yes," posts the reply via
|
|
126
|
+
`gh api repos/{owner}/{repo}/pulls/{n}/comments -F in_reply_to=91234`, then resolves the
|
|
127
|
+
thread via the GraphQL mutation using that comment's thread node id.
|
|
128
|
+
|
|
129
|
+
## Edge Cases
|
|
130
|
+
|
|
131
|
+
- **PR from a fork**: `headRepositoryOwner`/`headRepository` differ from the base repo;
|
|
132
|
+
checkout and branch comparisons must use the fork's remote, not the base repo's.
|
|
133
|
+
- **Review-summary comments**: never resolvable and never file/line-scoped; `path`/`line`
|
|
134
|
+
are always null and `can_resolve` is always `false`.
|
|
135
|
+
- **Reply-to-a-reply**: GitHub only supports replying to a thread's root comment; always
|
|
136
|
+
resolve `in_reply_to` up to the root before posting.
|
|
137
|
+
|
|
138
|
+
## Known Issues
|
|
139
|
+
|
|
140
|
+
- **Symptom:** `resolveReviewThread` mutation fails with a "could not resolve to a node"
|
|
141
|
+
error even though the comment id is valid.
|
|
142
|
+
**Cause:** the mutation requires the review thread's GraphQL node id, not the numeric
|
|
143
|
+
REST comment id or the numeric review id -- these are three different identifier spaces.
|
|
144
|
+
**Fix:** always fetch the thread's node id via the `reviewThreads` GraphQL query first,
|
|
145
|
+
and cache the numeric-id-to-node-id mapping per PR fetch. Verify the exact mutation shape
|
|
146
|
+
via `gh api graphql` introspection before first use in a new environment.
|
|
147
|
+
- **Symptom:** posting a reply or resolving a thread returns HTTP 403 despite `gh auth
|
|
148
|
+
status` showing a valid session.
|
|
149
|
+
**Cause:** the authenticated account lacks write/triage permission on the repository (for
|
|
150
|
+
example, an outside collaborator with read-only access).
|
|
151
|
+
**Fix:** degrade to reply-only where permitted, report the permission gap plainly, and
|
|
152
|
+
never retry the same call silently.
|
|
153
|
+
- **Symptom:** any `gh api` call returns HTTP 404 for a repo the human insists exists.
|
|
154
|
+
**Cause:** the authenticated token lacks the `repo` (or fine-grained equivalent) scope, so
|
|
155
|
+
GitHub reports a private resource as not found rather than as forbidden.
|
|
156
|
+
**Fix:** report this distinction explicitly and ask the human to re-run
|
|
157
|
+
`gh auth refresh -s repo` rather than assuming the PR truly does not exist.
|
|
158
|
+
- **Symptom:** repeated calls start failing with HTTP 403 and a rate-limit message.
|
|
159
|
+
**Cause:** GitHub's REST/GraphQL rate limits were exceeded, often from re-fetching the
|
|
160
|
+
full comment list too frequently in one session.
|
|
161
|
+
**Fix:** space out calls and reuse the already-fetched result within a session; never
|
|
162
|
+
silently retry in a tight loop.
|
|
163
|
+
- **Symptom:** an agent fetched PR metadata, comments, or diffs via `curl`/`api.github.com`
|
|
164
|
+
or by scraping the PR's rendered HTML page instead of using `gh`.
|
|
165
|
+
**Cause:** `gh` was missing or unauthenticated (e.g. `gh auth status` reported not logged
|
|
166
|
+
in), and the agent treated the unauthenticated public REST API or the rendered PR page as
|
|
167
|
+
an acceptable substitute since the target data was technically public.
|
|
168
|
+
**Fix:** never substitute `gh` with a direct HTTP call or a page scrape, regardless of
|
|
169
|
+
whether the data is public. Stop at the Authentication check step, report the missing or
|
|
170
|
+
failed `gh` session plainly, and wait for the human to install or authenticate `gh` before
|
|
171
|
+
retrying the same read or write through `gh`.
|
|
172
|
+
- **Symptom:** a `gh api`/`gh pr view` read command run from an automated shell appears to
|
|
173
|
+
hang or return no captured output at all, even though `gh` itself succeeded.
|
|
174
|
+
**Cause:** `gh` falls back to `$PAGER` (commonly `less`) for output it thinks may be
|
|
175
|
+
interactive; this switches the terminal to its alternate screen buffer, and content shown
|
|
176
|
+
there is not part of normal scrollback, so an automated caller never sees it -- piping
|
|
177
|
+
through `| cat` alone does not reliably prevent this.
|
|
178
|
+
**Fix:** prefix every `gh` invocation with `GH_PAGER=cat` (e.g.
|
|
179
|
+
`GH_PAGER=cat gh api repos/{owner}/{repo}/issues/{n}/comments`) when running non-
|
|
180
|
+
interactively, which disables `gh`'s pager unconditionally.
|
|
181
|
+
|
|
182
|
+
## References
|
|
183
|
+
|
|
184
|
+
- [`400-pr-owner-assistant`](../../../principles/skills/400-pr-owner-assistant/SKILL.md) -- consumes this connector's normalized output.
|
|
185
|
+
- [`agentme-edr-127`](../../127-external-system-adapter-skills.md) -- external system adapter skill rules (connector naming, Known Issues format, HITL-before-write).
|
|
186
|
+
- [`agentme-edr-124`](../../124-secrets-management.md) -- credential storage and retrieval.
|
|
187
|
+
- [`agentme-core-adr-003`](../../../../../agentme-core/adrs/principles/003-skill-numbering-ranges.md) -- skill numbering ranges (250-299 base connectors).
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: 250-github-connector
|
|
3
|
+
skill-version: "1.0"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Test Scenarios
|
|
7
|
+
|
|
8
|
+
### Scenario 1: Fetch and normalize all comment kinds for a PR, happy path
|
|
9
|
+
|
|
10
|
+
**Trigger / Input**
|
|
11
|
+
|
|
12
|
+
Fetch all comments for `https://github.com/acme/widgets/pull/482`, a PR with one issue-level
|
|
13
|
+
comment, two review (file/line) comments in one resolved thread, and one review-summary.
|
|
14
|
+
|
|
15
|
+
**Expected Behaviour**
|
|
16
|
+
|
|
17
|
+
The connector: (1) confirms `gh auth status` is authenticated; (2) runs the PR metadata
|
|
18
|
+
read; (3) runs the issue-comments, review-comments, and reviews read commands; (4) runs one
|
|
19
|
+
`gh api graphql` call to read thread resolution state; (5) returns a single normalized list
|
|
20
|
+
where the issue-level comment has `kind: "issue-comment"` and `can_resolve: false`, the two
|
|
21
|
+
review comments have `kind: "review-comment"`, `status: "resolved"`, and `can_resolve:
|
|
22
|
+
true`, and the review-summary has `kind: "review-summary"` and `can_resolve: false`.
|
|
23
|
+
|
|
24
|
+
**Assertions**
|
|
25
|
+
|
|
26
|
+
- [ ] Output normalizes every fetched item to the shared record shape (id, kind, status,
|
|
27
|
+
can_reply, can_resolve, path, line, content, author, in_reply_to).
|
|
28
|
+
- [ ] Output sets `can_resolve: false` for the issue-comment and the review-summary items.
|
|
29
|
+
- [ ] Output sets `status: "resolved"` for the two review comments in the resolved thread,
|
|
30
|
+
derived from the GraphQL thread lookup rather than the REST response alone.
|
|
31
|
+
- [ ] Connector never branches its own logic on business meaning of comment content.
|
|
32
|
+
|
|
33
|
+
### Scenario 2: Reply-to-a-reply resolves to the thread root before posting
|
|
34
|
+
|
|
35
|
+
**Trigger / Input**
|
|
36
|
+
|
|
37
|
+
Post a reply targeting a review comment that is itself a reply (not the root) within its
|
|
38
|
+
thread.
|
|
39
|
+
|
|
40
|
+
**Expected Behaviour**
|
|
41
|
+
|
|
42
|
+
Before posting, the connector resolves `in_reply_to` up to the thread's root comment id
|
|
43
|
+
(GitHub only accepts replies anchored to the root), shows the mandatory System/Operation/
|
|
44
|
+
Fields/Estimated impact confirmation using the resolved root id, and only posts via
|
|
45
|
+
`gh api repos/{owner}/{repo}/pulls/{n}/comments -F in_reply_to=<root-id>` after explicit
|
|
46
|
+
confirmation.
|
|
47
|
+
|
|
48
|
+
**Assertions**
|
|
49
|
+
|
|
50
|
+
- [ ] Connector resolves `in_reply_to` to the thread's root comment id, not the intermediate
|
|
51
|
+
reply id, before constructing the write call.
|
|
52
|
+
- [ ] Connector shows the mandatory confirmation (System, Operation, Fields, Estimated
|
|
53
|
+
impact) before posting.
|
|
54
|
+
- [ ] Connector does not post before receiving explicit human confirmation.
|
|
55
|
+
|
|
56
|
+
### Scenario 3: Permission-denied write degrades to reply-only, no silent retry
|
|
57
|
+
|
|
58
|
+
**Trigger / Input**
|
|
59
|
+
|
|
60
|
+
A resolve-thread write (`gh api graphql` `resolveReviewThread` mutation) returns HTTP 403
|
|
61
|
+
because the authenticated account lacks triage permission on the repository.
|
|
62
|
+
|
|
63
|
+
**Expected Behaviour**
|
|
64
|
+
|
|
65
|
+
Per the Known Issues entry for this symptom, the connector reports the permission gap
|
|
66
|
+
plainly to the caller, does not retry the same call, and continues to allow a reply-only
|
|
67
|
+
write path for that comment (an already-successful or subsequent reply post is unaffected).
|
|
68
|
+
|
|
69
|
+
**Assertions**
|
|
70
|
+
|
|
71
|
+
- [ ] Connector reports the permission error explicitly rather than failing silently.
|
|
72
|
+
- [ ] Connector does not silently retry the failed resolve call.
|
|
73
|
+
- [ ] Connector still allows a reply-only write for the same comment.
|
|
74
|
+
|
|
75
|
+
### Scenario 4: No GitHub session available halts before any write
|
|
76
|
+
|
|
77
|
+
**Trigger / Input**
|
|
78
|
+
|
|
79
|
+
`gh auth status` reports not logged in.
|
|
80
|
+
|
|
81
|
+
**Expected Behaviour**
|
|
82
|
+
|
|
83
|
+
The connector runs `gh auth login --hostname github.com --git-protocol https --web`
|
|
84
|
+
(non-interactive except for the one local git-credential yes/no, which the connector
|
|
85
|
+
auto-accepts on its default) so the human is only asked to complete the browser/device-code
|
|
86
|
+
step, and does not attempt any write operation until `gh auth status` reports an
|
|
87
|
+
authenticated session. Read-only operations that do not require authentication (if any) are
|
|
88
|
+
unaffected.
|
|
89
|
+
|
|
90
|
+
**Assertions**
|
|
91
|
+
|
|
92
|
+
- [ ] Connector does not attempt a write operation without an authenticated `gh` session.
|
|
93
|
+
- [ ] Connector runs `gh auth login` with `--hostname`/`--git-protocol`/`--web` rather than
|
|
94
|
+
bare `gh auth login`, so the human is not asked the host/protocol/method questions.
|
|
95
|
+
- [ ] Connector never asks for, reads, or feeds `gh` a raw PAT/token directly.
|
|
96
|
+
|
|
97
|
+
### Scenario 5: gh unavailable or unauthenticated never triggers a curl/scrape fallback
|
|
98
|
+
|
|
99
|
+
**Trigger / Input**
|
|
100
|
+
|
|
101
|
+
Fetch PR metadata, comments, and diff for `https://github.com/acme/widgets/pull/482` while
|
|
102
|
+
`gh auth status` reports not logged in (or `gh` is not installed).
|
|
103
|
+
|
|
104
|
+
**Expected Behaviour**
|
|
105
|
+
|
|
106
|
+
The connector does not issue any direct `curl`/HTTP request to `api.github.com`,
|
|
107
|
+
`github.com`, or a `.diff`/`.patch` endpoint, and does not fetch or parse the PR's rendered
|
|
108
|
+
HTML page as a substitute -- even though the target repository and PR are public. Instead it
|
|
109
|
+
follows the Authentication check steps, reports the missing/failed `gh` session plainly, and
|
|
110
|
+
halts every read and write until `gh auth status` reports an authenticated session.
|
|
111
|
+
|
|
112
|
+
**Assertions**
|
|
113
|
+
|
|
114
|
+
- [ ] Connector does not issue a `curl` or other raw HTTP request to any GitHub endpoint as
|
|
115
|
+
a substitute for `gh`.
|
|
116
|
+
- [ ] Connector does not fetch or parse the PR's HTML page as a scraping fallback.
|
|
117
|
+
- [ ] Connector halts reads and writes and prompts for `gh` installation/`gh auth login`
|
|
118
|
+
rather than degrading to an alternative retrieval method.
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 251-azure-devops-connector
|
|
3
|
+
description: >
|
|
4
|
+
Base connector providing authentication, read access, and write access to Azure DevOps
|
|
5
|
+
pull requests and their comment threads via the az CLI. Pure I/O -- no triage logic, no
|
|
6
|
+
business decisions. Activate when an agent or skill (such as pr-owner-assistant) needs to
|
|
7
|
+
fetch or post PR thread comments, change thread status, or check out a PR branch on Azure
|
|
8
|
+
DevOps.
|
|
9
|
+
metadata:
|
|
10
|
+
author: flaviostutz
|
|
11
|
+
version: "1.1"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
Reusable authentication and connection skill for Azure DevOps pull requests, per
|
|
17
|
+
[agentme-edr-127](../../127-external-system-adapter-skills.md) rule 06 (connector naming).
|
|
18
|
+
Wraps the `az` CLI (with the `azure-devops` extension) -- Azure DevOps's own supported API
|
|
19
|
+
client -- plus `az rest` for the handful of operations the extension does not expose as a
|
|
20
|
+
dedicated subcommand. Contains no business logic (per rule 05): it only reads and writes
|
|
21
|
+
data and normalizes it to the shape consumed by
|
|
22
|
+
[`400-pr-owner-assistant`](../../../principles/skills/400-pr-owner-assistant/SKILL.md).
|
|
23
|
+
|
|
24
|
+
This is a base connector skill (number range 250-299).
|
|
25
|
+
|
|
26
|
+
## Instructions
|
|
27
|
+
|
|
28
|
+
### Authentication check
|
|
29
|
+
|
|
30
|
+
1. Verify the `az` CLI is installed (`az --version`); if missing, ask the human whether to
|
|
31
|
+
install it now via the appropriate package manager for their OS (e.g. `brew install
|
|
32
|
+
azure-cli` on macOS). Only run the install command after explicit confirmation; if the
|
|
33
|
+
human declines or the install fails, report the install requirement and stop.
|
|
34
|
+
2. Verify the `azure-devops` extension is present; if missing, install it with
|
|
35
|
+
`az extension add --name azure-devops` (auto-installs on first use in most `az` versions,
|
|
36
|
+
but check explicitly rather than assuming).
|
|
37
|
+
3. Run `az account show`. If authenticated, proceed -- prefer `az login`'s own session over
|
|
38
|
+
handling a token directly.
|
|
39
|
+
4. If not authenticated, check the OS keychain for a stored Azure DevOps PAT per
|
|
40
|
+
[agentme-edr-124](../../124-secrets-management.md) rather than any `.env` file, hardcoded
|
|
41
|
+
value, or shell profile export. If found, export it only transiently as
|
|
42
|
+
`AZURE_DEVOPS_EXT_PAT` for the current command invocation -- never persist it to disk.
|
|
43
|
+
5. If no session and no stored PAT exist, prompt the human to run `az login` interactively
|
|
44
|
+
or to store a PAT in the keychain first, per agentme-edr-124's `setup-secrets` pattern.
|
|
45
|
+
Do not proceed with a write operation without one of these. Unlike `gh auth login`, bare
|
|
46
|
+
`az login` already opens the browser directly with no preceding host/protocol/method
|
|
47
|
+
questions, so no extra flags are needed here to keep it non-interactive.
|
|
48
|
+
6. Set the default organization/project once per session
|
|
49
|
+
(`az devops configure --defaults organization=<url> project=<project>`) to shorten
|
|
50
|
+
subsequent commands.
|
|
51
|
+
7. Never substitute `az`/`az rest` with a direct HTTP call (`curl`, `fetch`, or any other
|
|
52
|
+
HTTP client) against the Azure DevOps REST API, and never scrape the PR's web UI as a
|
|
53
|
+
workaround -- this applies to reads as much as writes, and applies even when the target
|
|
54
|
+
data looks read-only. If `az`, the `azure-devops` extension, or a valid session/PAT is
|
|
55
|
+
missing, stop and resolve that first (steps 1-5 above); do not degrade to an alternative
|
|
56
|
+
retrieval method to route around it.
|
|
57
|
+
|
|
58
|
+
### Reading data
|
|
59
|
+
|
|
60
|
+
All read commands are exempt from HITL confirmation (per agentme-edr-127 rule 04, read-only
|
|
61
|
+
operations need no confirmation -- but they are not exempt from the CLI-only channel).
|
|
62
|
+
Every read below MUST go through `az`/`az rest`; never construct the equivalent REST call
|
|
63
|
+
with `curl`/another HTTP client, and never fetch or scrape the PR's web UI as a substitute.
|
|
64
|
+
|
|
65
|
+
- PR metadata: `az repos pr show --id <n> --output json`
|
|
66
|
+
- All comment threads (Azure DevOps has no separate "list comments" call -- threads are the
|
|
67
|
+
unit of data and already include every comment and their status):
|
|
68
|
+
`az rest --method GET --uri "https://dev.azure.com/{org}/{project}/_apis/git/repositories/{repo}/pullRequests/{n}/threads?api-version=7.1"`
|
|
69
|
+
There is no dedicated `az repos pr` subcommand for threads -- `az rest` is required for both
|
|
70
|
+
reads and writes; verify this generic-URI capability with `az rest --help` and a smoke-test
|
|
71
|
+
GET before first use in a new environment.
|
|
72
|
+
|
|
73
|
+
Normalize every thread's comments to the shared record shape (`id`, `kind`, `status`,
|
|
74
|
+
`can_reply`, `can_resolve`, `path`, `line`, `content`, `author`, `in_reply_to`, `diff_hunk`,
|
|
75
|
+
`url`):
|
|
76
|
+
- `id` is `"thread-comment/<threadId>.<commentId>"` -- Azure DevOps ids are scoped per PR, not
|
|
77
|
+
global, so always keep the PR number alongside when persisting.
|
|
78
|
+
- `kind` is always `"thread-comment"` -- Azure DevOps has no separate review-summary concept;
|
|
79
|
+
never emit a `"review-summary"` kind for this provider.
|
|
80
|
+
- `status` maps from the thread's `status` field: `"active"` -> `"open"`, `"fixed"` /
|
|
81
|
+
`"closed"` -> `"resolved"`, `"wontFix"` -> `"wontfix"`, `"pending"` -> `"open"`.
|
|
82
|
+
- `path`/`line` come from `threadContext.filePath` and the relevant line range; when
|
|
83
|
+
`threadContext` is `null`, this is a general (PR-level, not file-scoped) comment -- classify
|
|
84
|
+
it as a general comment, not a parsing error.
|
|
85
|
+
- `can_reply` and `can_resolve` are `true` for any non-deleted comment in a non-deleted
|
|
86
|
+
thread; Azure DevOps does not have GitHub's permission-driven resolve restriction in the
|
|
87
|
+
same way, but a 403 on write still means `can_resolve` should be treated as `false` for
|
|
88
|
+
that session (see Known Issues).
|
|
89
|
+
- `in_reply_to` is the thread's first comment id whenever the target is a reply within the
|
|
90
|
+
same thread -- Azure DevOps threads are flat, so there is no root-vs-reply distinction to
|
|
91
|
+
resolve.
|
|
92
|
+
- `diff_hunk` has no native equivalent in the Azure DevOps API -- `threadContext` exposes
|
|
93
|
+
only a file path and line range, not a unified-diff-style hunk string. Leave `diff_hunk`
|
|
94
|
+
null rather than fabricating one; `pr-owner-assistant` degrades to relying on
|
|
95
|
+
`source-lines` alone in that case, exactly as it does for a general (non-file-scoped)
|
|
96
|
+
comment.
|
|
97
|
+
- `url` has no direct field in the thread-comment response either. Synthesize a best-effort
|
|
98
|
+
permalink from the PR's own web URL plus a `?discussionId=<threadId>` anchor (Azure
|
|
99
|
+
DevOps' web UI convention for deep-linking to a thread); fall back to the PR's own URL
|
|
100
|
+
with no anchor when this convention cannot be confirmed reliable for the target
|
|
101
|
+
organization, rather than risking a broken or misleading link (see Known Issues).
|
|
102
|
+
|
|
103
|
+
### Writing data
|
|
104
|
+
|
|
105
|
+
Before any write below, show the mandatory confirmation (per agentme-edr-127 rule 04):
|
|
106
|
+
**System** (org/project/repo + PR number), **Operation**, **Fields** (exact verbatim text to
|
|
107
|
+
post), **Estimated impact** (visible to PR participants, triggers notifications). Wait for
|
|
108
|
+
explicit confirmation; never proceed on an assumed "yes."
|
|
109
|
+
|
|
110
|
+
- Reply within an existing thread:
|
|
111
|
+
`az rest --method POST --uri ".../pullRequests/{n}/threads/{threadId}/comments?api-version=7.1" --body '{"content": "...", "parentCommentId": <id>}'`
|
|
112
|
+
- Post a new general (non-file-scoped) comment as a new thread:
|
|
113
|
+
`az rest --method POST --uri ".../pullRequests/{n}/threads?api-version=7.1" --body '{"comments": [{"content": "..."}]}'`
|
|
114
|
+
- Change thread status (the resolve/won't-fix equivalent):
|
|
115
|
+
`az rest --method PATCH --uri ".../pullRequests/{n}/threads/{threadId}?api-version=7.1" --body '{"status": "fixed"}'` (use `"wontFix"` or `"closed"` as appropriate instead of `"fixed"`).
|
|
116
|
+
- Check out the PR branch: `az repos pr checkout --id <n>`.
|
|
117
|
+
|
|
118
|
+
### Constraints
|
|
119
|
+
|
|
120
|
+
- MUST use `az`/`az rest` for every read and write handled by this connector -- never fall
|
|
121
|
+
back to `curl`, another raw HTTP client, or scraping the PR's web UI, even when `az` is
|
|
122
|
+
missing, unauthenticated, or erroring, and even when the target data looks read-only.
|
|
123
|
+
- MUST stop and follow the Authentication check steps above when `az` cannot complete a
|
|
124
|
+
request, instead of silently degrading to an alternative retrieval method.
|
|
125
|
+
|
|
126
|
+
## Examples
|
|
127
|
+
|
|
128
|
+
**Input**: fetch all comments for
|
|
129
|
+
`https://dev.azure.com/contoso/Widgets/_git/widgets-api/pullrequest/1029`
|
|
130
|
+
|
|
131
|
+
Runs `az repos pr show --id 1029` for metadata, then the single threads `az rest GET` call
|
|
132
|
+
above, and returns a single normalized list built from every thread's comments.
|
|
133
|
+
|
|
134
|
+
**Input**: reply to thread comment id `thread-comment/12.1` and set the thread to fixed
|
|
135
|
+
|
|
136
|
+
Shows the mandatory confirmation summary first. On explicit "yes," posts the reply via the
|
|
137
|
+
threads/comments `POST`, then updates thread status via the `PATCH` call.
|
|
138
|
+
|
|
139
|
+
## Edge Cases
|
|
140
|
+
|
|
141
|
+
- **Modern vs legacy URL formats**: recognize both
|
|
142
|
+
`dev.azure.com/{org}/{project}/_git/{repo}/pullrequest/{id}` and
|
|
143
|
+
`{org}.visualstudio.com/{project}/_git/{repo}/pullrequest/{id}` as valid Azure DevOps PR
|
|
144
|
+
URLs; extract org/project/repo/id from either shape.
|
|
145
|
+
- **`threadContext` is `null`**: classify as a general PR-level comment, never as a parse
|
|
146
|
+
failure.
|
|
147
|
+
- **PR-scoped ids**: never assume a thread or comment id is unique outside its PR; always
|
|
148
|
+
carry the PR number alongside when the tracking file persists an id.
|
|
149
|
+
|
|
150
|
+
## Known Issues
|
|
151
|
+
|
|
152
|
+
- **Symptom:** the `azure-devops` extension has no `az repos pr comment` or `az repos pr
|
|
153
|
+
thread` subcommand at all.
|
|
154
|
+
**Cause:** the extension only covers a subset of the Git PR API; thread and comment
|
|
155
|
+
operations were never added as first-class subcommands.
|
|
156
|
+
**Fix:** always use `az rest` with the documented REST endpoints above for every thread
|
|
157
|
+
and comment read or write; do not search for a nonexistent dedicated subcommand.
|
|
158
|
+
- **Symptom:** a thread that should be resolvable cannot be updated; the `PATCH` call returns
|
|
159
|
+
HTTP 403 despite `az account show` showing a valid, logged-in session.
|
|
160
|
+
**Cause:** the authenticated identity lacks the "Contribute to pull requests" permission
|
|
161
|
+
on the repository.
|
|
162
|
+
**Fix:** degrade to reply-only for that thread, report the permission gap plainly, and
|
|
163
|
+
never retry the same call silently.
|
|
164
|
+
- **Symptom:** `az rest` against a `dev.azure.com/.../_apis/...` URL fails most calls with
|
|
165
|
+
`TF400813: The user 'aaaaaaaa-aaaa-...' is not authorized`, or -- observed once, isolated
|
|
166
|
+
to a single call in an otherwise-failing batch -- exits 0 (looks successful) while the
|
|
167
|
+
write never actually appears when the thread is re-read.
|
|
168
|
+
**Cause:** `az rest` cannot always derive the correct Azure AD resource from the URL
|
|
169
|
+
alone and can silently fall back to an anonymous/placeholder identity; this has been
|
|
170
|
+
observed to be intermittent within a batch of otherwise-identical calls.
|
|
171
|
+
**Fix:** always pass `--resource 499b84ac-1321-427f-aa17-267ca6975798` (Azure DevOps'
|
|
172
|
+
well-known, tenant-agnostic AAD resource id) explicitly on every `az rest` call. Even
|
|
173
|
+
then, never treat a zero exit code alone as proof a write persisted -- read the thread
|
|
174
|
+
back afterward and verify the expected content/status is actually present before
|
|
175
|
+
reporting success. `400-pr-owner-assistant`'s `scripts/post-replies-azure-devops.js` does
|
|
176
|
+
this automatically for every write.
|
|
177
|
+
- **Symptom:** a fetched thread has no obvious "kind" like GitHub's review-summary.
|
|
178
|
+
**Cause:** Azure DevOps genuinely has no equivalent concept -- every comment lives inside a
|
|
179
|
+
thread.
|
|
180
|
+
**Fix:** never emit a `"review-summary"` kind for this connector; always normalize to
|
|
181
|
+
`"thread-comment"`.
|
|
182
|
+
- **Symptom:** an agent fetched PR metadata or thread comments via `curl`/direct REST calls
|
|
183
|
+
or by scraping the PR's web UI instead of using `az`/`az rest`.
|
|
184
|
+
**Cause:** `az` was missing, unauthenticated, or lacked the `azure-devops` extension, and
|
|
185
|
+
the agent treated a direct unauthenticated REST call or the rendered PR page as an
|
|
186
|
+
acceptable substitute since the target data looked read-only.
|
|
187
|
+
**Fix:** never substitute `az`/`az rest` with a direct HTTP call or a page scrape. Stop at
|
|
188
|
+
the Authentication check step, report the missing or failed `az` session plainly, and wait
|
|
189
|
+
for the human to install, extend, or authenticate `az` before retrying the same read or
|
|
190
|
+
write through `az`.
|
|
191
|
+
- **Symptom:** a synthesized comment permalink (`url`) 404s, or lands on the PR overview
|
|
192
|
+
instead of the specific thread, when opened.
|
|
193
|
+
**Cause:** Azure DevOps' web UI deep-link format for a specific thread
|
|
194
|
+
(`?discussionId=<threadId>`) is a UI convention, not a documented, versioned part of the
|
|
195
|
+
REST API, and can vary by organization or Azure DevOps version.
|
|
196
|
+
**Fix:** verify the `?discussionId=<threadId>` anchor against a live PR in the target
|
|
197
|
+
organization before relying on it; degrade to the PR's own URL with no anchor when
|
|
198
|
+
uncertain, rather than guessing at a format that might mislead the human.
|
|
199
|
+
|
|
200
|
+
## References
|
|
201
|
+
|
|
202
|
+
- [`400-pr-owner-assistant`](../../../principles/skills/400-pr-owner-assistant/SKILL.md) -- consumes this connector's normalized output.
|
|
203
|
+
- [`agentme-edr-127`](../../127-external-system-adapter-skills.md) -- external system adapter skill rules (connector naming, Known Issues format, HITL-before-write).
|
|
204
|
+
- [`agentme-edr-124`](../../124-secrets-management.md) -- credential storage and retrieval.
|
|
205
|
+
- [`agentme-core-adr-003`](../../../../../agentme-core/adrs/principles/003-skill-numbering-ranges.md) -- skill numbering ranges (250-299 base connectors).
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: 251-azure-devops-connector
|
|
3
|
+
skill-version: "1.0"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Test Scenarios
|
|
7
|
+
|
|
8
|
+
### Scenario 1: Fetch and normalize thread comments, happy path
|
|
9
|
+
|
|
10
|
+
**Trigger / Input**
|
|
11
|
+
|
|
12
|
+
Fetch all comments for
|
|
13
|
+
`https://dev.azure.com/contoso/Widgets/_git/widgets-api/pullrequest/1029`, a PR with one
|
|
14
|
+
active file-scoped thread and one active general (PR-level) thread.
|
|
15
|
+
|
|
16
|
+
**Expected Behaviour**
|
|
17
|
+
|
|
18
|
+
The connector: (1) confirms `az account show` is authenticated; (2) runs
|
|
19
|
+
`az repos pr show --id 1029`; (3) runs the single `az rest --method GET` threads call
|
|
20
|
+
(there is no separate "list comments" call); (4) returns a normalized list where the
|
|
21
|
+
file-scoped thread's comment has non-null `path`/`line` and `kind: "thread-comment"`, and
|
|
22
|
+
the general thread's comment has null `path`/`line` and is still classified as a normal
|
|
23
|
+
`"thread-comment"`, both with `status: "open"`.
|
|
24
|
+
|
|
25
|
+
**Assertions**
|
|
26
|
+
|
|
27
|
+
- [ ] Output normalizes every fetched comment to the shared record shape (id, kind, status,
|
|
28
|
+
can_reply, can_resolve, path, line, content, author, in_reply_to).
|
|
29
|
+
- [ ] Output maps the thread `status: "active"` field to the normalized `status: "open"`.
|
|
30
|
+
- [ ] Connector uses `az rest` for the threads read rather than searching for a dedicated
|
|
31
|
+
`az repos pr` comment subcommand.
|
|
32
|
+
|
|
33
|
+
### Scenario 2: Null threadContext classified as a general comment, not an error
|
|
34
|
+
|
|
35
|
+
**Trigger / Input**
|
|
36
|
+
|
|
37
|
+
A fetched thread has `threadContext: null` in the raw API response.
|
|
38
|
+
|
|
39
|
+
**Expected Behaviour**
|
|
40
|
+
|
|
41
|
+
Per the Reading data normalization rule and the matching Edge Cases entry, the connector
|
|
42
|
+
classifies this thread's comment as a general PR-level comment (`path`/`line` set to null in
|
|
43
|
+
the normalized record) rather than treating the missing `threadContext` as a parsing failure
|
|
44
|
+
or skipping the comment.
|
|
45
|
+
|
|
46
|
+
**Assertions**
|
|
47
|
+
|
|
48
|
+
- [ ] Connector includes the comment in its normalized output with `path`/`line` set to null.
|
|
49
|
+
- [ ] Connector does not raise a parse error or silently drop the comment because of the
|
|
50
|
+
null `threadContext`.
|
|
51
|
+
|
|
52
|
+
### Scenario 3: Thread status change writes via az rest PATCH with mandatory confirmation
|
|
53
|
+
|
|
54
|
+
**Trigger / Input**
|
|
55
|
+
|
|
56
|
+
Set thread id 12 on PR 1029 to resolved ("fixed") status after a fix was applied.
|
|
57
|
+
|
|
58
|
+
**Expected Behaviour**
|
|
59
|
+
|
|
60
|
+
The connector shows the mandatory System/Operation/Fields/Estimated impact confirmation
|
|
61
|
+
(naming org/project/repo + PR number and the target status), waits for explicit
|
|
62
|
+
confirmation, then issues
|
|
63
|
+
`az rest --method PATCH --uri ".../pullRequests/1029/threads/12?api-version=7.1" --body '{"status": "fixed"}'`.
|
|
64
|
+
No dedicated `az repos pr` subcommand is used for this operation.
|
|
65
|
+
|
|
66
|
+
**Assertions**
|
|
67
|
+
|
|
68
|
+
- [ ] Connector shows the mandatory confirmation before issuing the PATCH call.
|
|
69
|
+
- [ ] Connector does not issue the PATCH call before explicit human confirmation.
|
|
70
|
+
- [ ] Connector uses `az rest` rather than a nonexistent dedicated thread-status subcommand.
|
|
71
|
+
|
|
72
|
+
### Scenario 4: Legacy visualstudio.com URL parses the same as a modern dev.azure.com URL
|
|
73
|
+
|
|
74
|
+
**Trigger / Input**
|
|
75
|
+
|
|
76
|
+
`https://contoso.visualstudio.com/Widgets/_git/widgets-api/pullrequest/1029` (legacy format)
|
|
77
|
+
versus `https://dev.azure.com/contoso/Widgets/_git/widgets-api/pullrequest/1029` (modern
|
|
78
|
+
format) for the same underlying PR.
|
|
79
|
+
|
|
80
|
+
**Expected Behaviour**
|
|
81
|
+
|
|
82
|
+
The connector extracts the same org (`contoso`), project (`Widgets`), repo
|
|
83
|
+
(`widgets-api`), and PR id (`1029`) from either URL shape and proceeds identically from
|
|
84
|
+
that point on.
|
|
85
|
+
|
|
86
|
+
**Assertions**
|
|
87
|
+
|
|
88
|
+
- [ ] Connector extracts identical org/project/repo/PR-id values from both URL formats.
|
|
89
|
+
- [ ] Connector does not require the human to reformat a legacy URL before use.
|
|
90
|
+
|
|
91
|
+
### Scenario 5: az unavailable or unauthenticated never triggers a curl/scrape fallback
|
|
92
|
+
|
|
93
|
+
**Trigger / Input**
|
|
94
|
+
|
|
95
|
+
Fetch PR metadata and thread comments for
|
|
96
|
+
`https://dev.azure.com/contoso/Widgets/_git/widgets-api/pullrequest/1029` while `az account
|
|
97
|
+
show` reports no session and no PAT is stored in the keychain (or `az`/the `azure-devops`
|
|
98
|
+
extension is not installed).
|
|
99
|
+
|
|
100
|
+
**Expected Behaviour**
|
|
101
|
+
|
|
102
|
+
The connector does not issue any direct `curl`/HTTP request against the Azure DevOps REST
|
|
103
|
+
API, and does not fetch or scrape the PR's web UI as a substitute -- even if the project
|
|
104
|
+
looks publicly reachable. Instead it follows the Authentication check steps, reports the
|
|
105
|
+
missing session/PAT or missing installation plainly, and halts every read and write until
|
|
106
|
+
`az account show` succeeds or a keychain PAT is available.
|
|
107
|
+
|
|
108
|
+
**Assertions**
|
|
109
|
+
|
|
110
|
+
- [ ] Connector does not issue a `curl` or other raw HTTP request to any Azure DevOps
|
|
111
|
+
endpoint as a substitute for `az`/`az rest`.
|
|
112
|
+
- [ ] Connector does not fetch or scrape the PR's web UI as a fallback.
|
|
113
|
+
- [ ] Connector halts reads and writes and prompts for `az` installation/authentication
|
|
114
|
+
rather than degrading to an alternative retrieval method.
|
|
@@ -10,6 +10,7 @@ Foundational standards, principles, and guidelines.
|
|
|
10
10
|
|
|
11
11
|
- [150-refine-plan-mode](principles/skills/150-refine-plan-mode/SKILL.md) - **Refine plan mode** — MANDATORY skill for ANY planning activity (plan, design, propose, outline, draft, brainstorm, architect). Read and follow in full before any execution begins. Must be read from XDRS even when not in `.agents/skills`. *(skill)*
|
|
12
12
|
- [151-refine-user-story](principles/skills/151-refine-user-story/SKILL.md) - **Refine user stories** — Refine, elaborate, study or develop the contents of a user story used to create a unit of work for an agile team. Runs a structured 10-phase refinement process: understand the request, qualify requirements, research context, review consistency, validate visually, challenge from 9 user-perspective angles (Phase 6), challenge from 8 implementer-perspective angles (Phase 7), produce a ready-to-implement story (Phase 8), and run a final readiness double-check (Phase 9). *(skill)*
|
|
13
|
+
- [400-pr-owner-assistant](principles/skills/400-pr-owner-assistant/SKILL.md) - **PR owner assistant** — Helps the OWNER of a pull request work through comments left by others: fetches every comment (GitHub or Azure DevOps) from its URL, tracks them in a local file, and walks through triaging each one (reply-question, won't-fix, work-on-a-fix) with explicit human confirmation at every step. A hands-on, mutating workflow to answer feedback and land fixes -- not a code-review skill. Delegates provider-specific reads/writes to `250-github-connector` or `251-azure-devops-connector`. *(skill)*
|
|
13
14
|
- [agentme-edr-012](principles/012-continuous-xdr-enrichment.md) - **Continuous xdr improvement policy** - Promote recurring delivery lessons into reusable XDRs
|
|
14
15
|
- [agentme-edr-016](principles/016-cross-language-module-structure.md) - **Cross-language module structure** - Organize modules consistently across supported languages
|
|
15
16
|
- [agentme-edr-017](principles/017-skill-testing.md) - **skill testing** - Mandates a `SKILL.test.md` co-located with every skill in scopes that follow agentme; defines test scenario format (trigger, expected behaviour, assertions) and requires execution before merging any skill change *(includes skill: [200-run-skill-tests](application/skills/200-run-skill-tests/SKILL.md))*
|
|
@@ -30,6 +31,8 @@ Language and framework-specific tooling and project structure.
|
|
|
30
31
|
- [agentme-edr-124](application/124-secrets-management.md) - **Secrets management** - Handle secrets securely using native keychains and cloud secret managers
|
|
31
32
|
- [agentme-edr-125](application/125-coding-abstraction-practices.md) - **Coding abstraction practices** - Define when abstractions are justified and when they must be inlined
|
|
32
33
|
- [agentme-edr-127](application/127-external-system-adapter-skills.md) - **External system adapter skills** - Priority-ordered approach and adapter skill authoring standards for automating interactions with external systems
|
|
34
|
+
- [250-github-connector](application/skills/250-github-connector/SKILL.md) - **GitHub connector** — Base connector providing authentication, read access, and write access to GitHub pull requests and their comments via the `gh` CLI. *(skill)*
|
|
35
|
+
- [251-azure-devops-connector](application/skills/251-azure-devops-connector/SKILL.md) - **Azure DevOps connector** — Base connector providing authentication, read access, and write access to Azure DevOps pull requests and their comment threads via the `az` CLI. *(skill)*
|
|
33
36
|
|
|
34
37
|
### Language and framework tooling
|
|
35
38
|
|
|
@@ -57,6 +57,9 @@ specific enough that two independent agents produce comparable outputs.]
|
|
|
57
57
|
|
|
58
58
|
Rules:
|
|
59
59
|
- MUST contain at least two scenarios: one happy path and one edge or failure case.
|
|
60
|
+
- MUST default to the 3 most relevant scenarios (typically the happy path plus the
|
|
61
|
+
highest-value edge/failure cases) and MUST NOT exceed 3 unless the user explicitly requests
|
|
62
|
+
more — larger suites cost more to execute and slow down verification.
|
|
60
63
|
- Each scenario MUST have at least two assertions.
|
|
61
64
|
- Assertions MUST be falsifiable (a pass/fail determination must be possible without ambiguity).
|
|
62
65
|
- Assertion text MUST start with a verb ("Output contains …", "Skill asks …", "Review reports …").
|