This Skill reads the Wiki and, after user confirmation, creates or updates pages. It does not provide deletion, moving, or renaming of pages; when needed, ask the user to perform the operation in the web interface.
Project selection
-
If the user has provided a project name (for example "Contoso project"), use it directly and do not call the project list API.
-
When the user only wants to "search the Wiki across the entire organization", for rule 4 use the URL without a project, and no project selection is needed.
-
In other cases, if it is not provided, ask the user to provide it once.
-
If it is still not provided, list the projects for the user to choose:
curl -sS -u ":$AZURE_DEVOPS_PAT" \ "https://dev.azure.com/$AZURE_DEVOPS_ORG/_apis/projects?%24top=500&api-version=7.1" -
Do not continue before the user provides or selects a project.
Wiki selection
- If the user has provided a Wiki name, use it directly;
{wikiIdentifier}it can be the Wiki'sidorname(the name must be URL-encoded). - If it is not provided, list the project's wikis using rule 1: if there is only one, use it directly; if there are multiple, ask the user to choose.
- If what the user gives is the page URL
https://dev.azure.com/{org}/{project}/_wiki/wikis/{wikiName}/{pageId}/{slug}, extract the project, Wiki name, andpageId, and read by ID according to rule 3.
Connection and authentication
Always use curl to call the Azure DevOps REST API directly; each command carries its own authentication parameters.
- Organization: read the environment variable
AZURE_DEVOPS_ORG(organization name, for examplecontoso). If it is not set, ask the user once; if what the user gives is a URL, extract the organization name fromhttps://dev.azure.com/{org}orhttps://{org}.visualstudio.com. - Host: other than
dev.azure.com, the host for the Wiki search API isalmsearch.dev.azure.com。 - Token: the PAT is sent with Basic authentication:
-u ":$AZURE_DEVOPS_PAT"; if onlyAZURE_DEVOPS_EXT_PATis set (the variable used by the Azure CLI azure-devops extension), use that instead. When using a Microsoft Entra ID token instead, replace with-H "Authorization: Bearer $AZURE_DEVOPS_TOKEN". If neither is set, ask the user to setAZURE_DEVOPS_PATin their own terminal and retry, and stop. Read the token only from environment variables: do not ask the user to paste the token into the conversation, and do not print it or write it to a file. - PAT permission scopes: required for reading: Wiki (Read) (already includes Wiki search); required for writing: Wiki (Read & write) (create and update pages).
- Encoding: the project and Wiki names in the path, the page path in the query string, and
commentmust be URL-encoded (write spaces as%20, see "Page path" for the rules); in the query string, write$as%24(for example%24top), to avoid shell expansion. - Errors: HTTP 401, 403, 203, or a response that is an HTML login page means the token is invalid, expired, or has insufficient permissions; report it and stop. HTTP 404 means the organization, project, Wiki, or page path is incorrect (when the page does not exist,
typeKeyisWikiPageNotFoundException). A code wiki specifying a nonexistent branch returns HTTP 500 (TF401175)。 - Windows PowerShell: call
curl.exe(instead ofcurlalias), write the environment variable as$env:AZURE_DEVOPS_PAT; PowerShell does not support<<'EOF', first write the JSON body to a temporary file, then use--data-binary "@body.json"to send it.
Page path
- Page path(the API's
path) starts with/, consists of the page title, preserves spaces, for example/Release Notes/v1.0; the root directory is/. code wiki page paths are relative tomappedPath。 - Title restrictions: cannot contain
/、\、#, cannot start or end with.; the full path including the repository URL is limited to 235 characters, and a single page is limited to 18 MB. - Put into the query string: URL-encode the entire segment (space
%20、&%26、?%3F、%%25、+%2B, Chinese encoded in UTF-8;/may be preserved or written as%2F). You can usejq -rn --arg p "/Release Notes/v1.0" '$p|@uri'to generate it. gitItemPathis the page's file path in the Wiki repository: spaces in the title become-, the original-becomes%2D,:、*、?、|、"、<、>is also represented as%XX, and finally append.md; code wiki adds themappedPathprefix.- Restore the page path from
gitItemPathRestore the page path: remove themappedPathprefix and.md, replace-with spaces, and finally URL-decode (the order cannot be reversed, otherwise%2Dwill be mistakenly replaced with spaces).
Rules
1. List Wikis
curl -sS -u ":$AZURE_DEVOPS_PAT" \
"https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/wiki/wikis?api-version=7.1"
Each entry has id、name、type(projectWiki is a project Wiki;codeWiki is a Wiki published from a repository folder),repositoryId、mappedPath(the folder corresponding to the code wiki),versions[].version(project wiki has a fixed single branch, for example wikiMaster; code wiki is the published branch) and remoteUrl. If there are no Wikis at all, state this clearly and stop.
Example: "What Wikis does the Contoso project have?"
2. Browse the page tree
curl -sS -u ":$AZURE_DEVOPS_PAT" \
"https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/wiki/wikis/{wikiIdentifier}/pages?path=/&recursionLevel=oneLevel&api-version=7.1"
recursionLevel:oneLevelretrieves only direct child pages,fullretrieves all. When there are many pages, first useoneLevel, then according to the user's needs replacepathwith child pages to expand level by level.subPages[]Each entry haspath、order(ordering within the same level),isParentPage(has child pages) andgitItemPath。- code wiki: when
versionDescriptoris omitted, read the default published version.versionsWhen there are multiple branches, add&versionDescriptor.version={branch}&versionDescriptor.versionType=branchto specify;{branch}only uses values fromversions[].version(other branches may also return 200, but that is not the published content). project wiki does not need this parameter.
Example: "List the page structure of Contoso.wiki"
3. Read pages
curl -sS -u ":$AZURE_DEVOPS_PAT" -D - \
"https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/wiki/wikis/{wikiIdentifier}/pages?path={pagePath}&includeContent=true&api-version=7.1"
-D -first prints the response headers:ETagis the page's current version (including double quotes), to be used when updating in rule 6. When only reading,-D -。- can be omitted. The response has
content(Markdown)、id(permanent page ID),path、gitItemPath、remoteUrl(web link). - When the page ID is already known, use
.../wiki/wikis/{wikiIdentifier}/pages/{pageId}?includeContent=true&api-version=7.1instead, which likewise returnsETag。 - In the content,
[[_TOC_]]、:::mermaid、/.attachments/...image links are Wiki-specific syntax; preserve them as-is or explain them when presenting.
Example: "Read /Release Notes/v1.0 of Contoso.wiki"
4. Search Wikis
curl -sS -u ":$AZURE_DEVOPS_PAT" -X POST -H "Content-Type: application/json" \
"https://almsearch.dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/search/wikisearchresults?api-version=7.1" \
-d '{"searchText":"deployment checklist","$skip":0,"$top":25,"filters":{"Project":["Contoso"],"Wiki":["Contoso.wiki"]},"includeFacets":true}'
searchTextsupports keywords (defaultAND), uppercaseAND、OR、NOT, double-quoted phrases and the trailing*wildcard, case-insensitive.filters.WikiUse the Wiki'sname(usingidwill return no results); omit any unwanted filters entirely. When searching the entire organization, remove/{project},filtersfrom the URL and also omitProject. Results include both project wiki and code wiki.$topmust be between 1 and 1000;countis the total count; when it is greater than the number already retrieved, use$skipto get the next page.includeFacetsistrue,facets.Wiki[]lists the match count for each Wiki.- Each entry has the form
fileName、path(gitItemPath, containing.md)、wiki.name、wiki.id、wiki.mappedPath、wiki.version、project.name, andhits[]:fieldReferenceNameisfileNamesorcontent,highlights[]is a snippet with matches marked by<highlighthit>. - Use the "page path" to restore
pathto a page path, then use rule 3 to read the required page.
Example: "Which page in the Wiki documents the deployment process?"
5. Create a page (write)
-
Confirm the page does not exist: read it using rule 3, and only continue if it returns HTTP 404 (
WikiPageNotFoundException); if it already exists, use rule 6 instead. -
Confirm the parent page exists (for example, the parent of
/Release Notes/v1.0is/Release Notes); if it does not exist, tell the user and ask whether to create the parent page first. -
List the content about to be sent to the user and execute only after one confirmation: Wiki, page path, full Markdown content, change description (
comment)。 -
when creatingdo not include
If-Match:curl -sS -u ":$AZURE_DEVOPS_PAT" -X PUT -H "Content-Type: application/json" \ "https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/wiki/wikis/{wikiIdentifier}/pages?path={pagePath}&comment={comment}&api-version=7.1" \ --data-binary @- <<'EOF' {"content": "# v1.0\n\n- 新增登入功能\n- 修正匯出錯誤"} EOFOn success, it returns HTTP 201. When the content contains newlines and quotes, first write the Markdown to a temporary file, then use
jq -Rs '{content: .}' page.mdto generate the JSON body.
Example: "Add a v1.0 page under /Release Notes in Contoso.wiki"
6. Update a page (write)
-
Read the page, note down
ETag, and save the current content as a temporary fileold.md(jq -jdoes not add an extra newline at the end):curl -sS -u ":$AZURE_DEVOPS_PAT" -D headers.txt -o page.json \ "https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/wiki/wikis/{wikiIdentifier}/pages?path={pagePath}&includeContent=true&api-version=7.1" grep -i '^etag:' headers.txt jq -j '.content' page.json > old.md -
Generate new content
new.mdas requested by the user: change only the sections the user requested, and keep the rest of the content and formatting as-is. -
Show the diff, and list the Wiki, page path, change description, and diff for the user, and execute only after one confirmation:
git diff --no-index --unified=3 old.md new.md -
when updatingmustinclude
If-Match, with the value exactly as in theETagheader (including the double quotes; the{etag}in the example is the version string inside the double quotes):curl -sS -u ":$AZURE_DEVOPS_PAT" -X PUT -H "Content-Type: application/json" \ -H 'If-Match: "{etag}"' \ "https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/wiki/wikis/{wikiIdentifier}/pages?path={pagePath}&comment={comment}&api-version=7.1" \ --data-binary "@body.json"body.jsongenerate withjq -Rs '{content: .}' new.md > body.json. On success, it returns HTTP 200, and theETagin the response header is the new version. -
If it fails and the message indicates a version mismatch, it means the page was modified by someone else during this period: start over from step 1, show the diff again, and confirm. Do not remove
If-Matchor resend using the oldETag. -
Delete temporary files once they are no longer needed.
Writing to code wiki: creation and updates commit directly to the published branch (versions when there are multiple branches, specify with the versionDescriptor parameter from rule 2). If the branch has a policy requiring a PR, the write may be rejected: instead, modify mappedPath locally under .md , then use repos-pull-request-write to open a PR.
Example: "Update the VPN setup steps in the /Onboarding page of Contoso.wiki to the new version"
Presentation of results
Dates are displayed as YYYY/MM/DD, times are converted to the user's local time zone, and UTC is indicated when it cannot be determined.
- Wiki list: present the name in a table (link
remoteUrl), type (project Wiki/code wiki), the code wiki's repository folder (mappedPath) and publishing branch. - Page tree: present page titles (the last segment of the path) as an indented list, and add "(has subpages)" to pages that have subpages but are not yet expanded.
- Page content: first list the page path and web link, then present the Markdown content; when the content is very long, summarize the key points first and ask whether to display the full text.
- Search results: first state the total number of results, then present the page path (after restoration, clickable), Wiki name and matching snippet in a table (change the
<highlighthit>markup to bold). If there are no results, state this clearly. - Before writing: when creating, list the full content; when updating, list the diff and a description of the changes.
- After writing: the page path, web link, and the result of the creation or update; on failure, display the HTTP status code and the
messagein the response, and do not automatically retry the write.