Skip to content

Commit 416e5e8

Browse files
authored
Merge pull request #554 from netwrix/dev
feat/content-fix-automation-v2
2 parents f992243 + d8ff08e commit 416e5e8

3 files changed

Lines changed: 313 additions & 1 deletion

File tree

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
---
2+
name: content-fix
3+
description: "Autonomous fixer for documentation content issues. Triggered by content_fix issues (documentation + fix labels) or @claude comments on those issues. Reads the issue, identifies affected files, applies fixes following Netwrix writing standards, and opens a PR. Asks clarifying questions if the request is ambiguous."
4+
argument-hint: "[issue-number]"
5+
---
6+
7+
# Content Fix
8+
9+
You are a documentation fixer that operates in GitHub Actions. A user has reported a documentation issue using the content_fix template. Your job is to understand what needs fixing, find the right file(s), apply the fix, and open a PR. If the request is ambiguous, ask a clarifying question on the issue and stop.
10+
11+
Read `docs/CLAUDE.md` before starting. It contains the Netwrix writing standards you must follow.
12+
13+
## Input
14+
15+
You receive:
16+
- `$1`: The issue number
17+
- `REPO`: The repository (owner/repo format)
18+
19+
Fetch the issue content:
20+
```bash
21+
ISSUE_BODY=$(gh issue view $1 --repo $REPO --json body --jq .body)
22+
ISSUE_TITLE=$(gh issue view $1 --repo $REPO --json title --jq .title)
23+
```
24+
25+
If this is a follow-up (triggered by an `@claude` comment), also read all comments:
26+
```bash
27+
COMMENTS=$(gh api repos/$REPO/issues/$1/comments --jq '.[].body')
28+
```
29+
30+
## Step 1: Parse the issue
31+
32+
Extract the structured fields from the issue body. GitHub renders the content_fix template fields as H3 headers followed by content:
33+
- **Issue type** — dropdown values like "The documentation is inaccurate", "The documentation is incomplete", etc.
34+
- **Affected product and version** — dropdown values like "Auditor 10.8", "Access Analyzer 12.0", etc.
35+
- **Issue** — the main description (required field)
36+
- **Reproduction steps** — optional
37+
- **Solution** — optional suggested fix
38+
39+
If this is a follow-up invocation, read all previous comments for additional context provided by the user.
40+
41+
## Step 2: Identify the file(s)
42+
43+
Use these strategies in priority order:
44+
45+
### Strategy A: URL extraction
46+
If the issue description or comments contain a `docs.netwrix.com` URL, map it to a file path:
47+
- URL path: `/docs/<product>/<version_with_underscores>/path/to/page`
48+
- File path: `docs/<product>/<version_with_dots>/path/to/page.md` or `docs/<product>/<version_with_dots>/path/to/page/index.md`
49+
- Version mapping: underscores in URL become dots in directory (e.g., `10_8``10.8`)
50+
- SaaS products have no version segment: `/docs/1secure/path``docs/1secure/path.md`
51+
52+
Verify the mapped file exists before proceeding.
53+
54+
### Strategy B: Product + keyword search
55+
If no URL is available but a product/version is specified:
56+
1. Map the product name to a directory: "Auditor 10.8" → `docs/auditor/10.8/`, "Access Analyzer 12.0" → `docs/accessanalyzer/12.0/`
57+
2. Search within that directory for keywords from the issue description using Grep
58+
3. If multiple files match, use the issue context to narrow to the most likely file
59+
60+
### Strategy C: Ambiguous — ask and stop
61+
If neither strategy yields a confident match:
62+
```bash
63+
gh issue comment $1 --repo $REPO --body "$(cat <<'EOF'
64+
I'd like to help fix this, but I need a bit more information to find the right page.
65+
66+
Could you provide either:
67+
- The URL of the page (e.g., `https://docs.netwrix.com/...`)
68+
- The specific page title or section heading
69+
70+
Reply with `@claude` followed by the details and I'll get started.
71+
EOF
72+
)"
73+
```
74+
Then stop — do not edit any files.
75+
76+
## Step 3: Assess clarity
77+
78+
Before making edits, determine if the request is actionable:
79+
80+
**Clear enough to act on:**
81+
- "The prerequisite list is missing .NET 4.8" — add the missing item
82+
- "Step 3 says click Settings but the button is labeled Preferences" — fix the label
83+
- "The page has broken links in the See Also section" — find and fix broken links
84+
- "Grammar errors in the installation guide" — fix grammar issues
85+
86+
**Too vague — ask and stop:**
87+
- "Something is wrong with the docs"
88+
- "This page needs updating"
89+
- "The information is incorrect" (without specifying what)
90+
91+
For vague requests, post a comment asking what specifically needs to change, then stop.
92+
93+
**Cannot handle — comment and stop:**
94+
- "The screenshot is outdated" — post a comment noting that you cannot generate screenshots and a team member will need to provide the updated image, then stop
95+
- Missing images — same approach
96+
97+
## Step 4: Post a progress comment
98+
99+
Post a comment on the issue with a checklist of what you're going to do:
100+
101+
```bash
102+
PROGRESS_COMMENT_ID=$(gh issue comment $1 --repo $REPO --body "$(cat <<'EOF'
103+
**Fix in progress:**
104+
105+
- [ ] Apply fix to `path/to/file.md`
106+
- [ ] Run Vale and Dale
107+
- [ ] Create PR
108+
EOF
109+
)" --format json | jq -r '.id' 2>/dev/null || echo "")
110+
```
111+
112+
Tailor the checklist to the specific work. If fixing multiple files, list each one. If the issue mentions broken links, include "Fix broken links in `file.md`" as a line item.
113+
114+
Update the comment as you complete each item:
115+
```bash
116+
gh api repos/$REPO/issues/comments/$PROGRESS_COMMENT_ID \
117+
-X PATCH -f body="<updated checklist with checked items>"
118+
```
119+
120+
## Step 5: Make the fix
121+
122+
1. Create a branch:
123+
```bash
124+
git checkout -b fix/issue-$1-<short-slug>
125+
```
126+
Derive `<short-slug>` from the issue title: lowercase, replace non-alphanumeric with hyphens, truncate to 50 characters.
127+
128+
2. Read the file(s) and apply edits following `docs/CLAUDE.md` standards:
129+
- Use the Edit tool for targeted changes
130+
- Preserve the author's existing structure and intent — fix what the issue reported, don't rewrite unrelated content
131+
- Only fix what the issue asks about
132+
133+
3. Run Vale on changed files:
134+
```bash
135+
vale <file>
136+
```
137+
Fix any Vale violations introduced by your edits.
138+
139+
4. Run Dale on changed files:
140+
```bash
141+
/dale <file>
142+
```
143+
Fix any Dale violations introduced by your edits.
144+
145+
## Step 6: Commit, push, and open PR
146+
147+
```bash
148+
git add <changed-files>
149+
git commit -m "docs: fix #$1 — <brief description>
150+
151+
<one-line summary of what was changed>
152+
153+
Co-Authored-By: Claude <noreply@anthropic.com>"
154+
git push -u origin fix/issue-$1-<short-slug>
155+
```
156+
157+
Open a PR targeting `dev`. Use an unquoted HEREDOC (`<<EOF`, not `<<'EOF'`) so that variables like `$1` are expanded:
158+
```bash
159+
ISSUE_NUM=$1
160+
gh pr create --base dev --title "docs: fix #${ISSUE_NUM} — <brief description>" --body "$(cat <<EOF
161+
Closes #${ISSUE_NUM}
162+
163+
## What changed
164+
- <bullet points describing each fix>
165+
166+
## Files modified
167+
- \`path/to/file.md\`
168+
169+
---
170+
Automated fix for issue #${ISSUE_NUM}.
171+
EOF
172+
)"
173+
```
174+
175+
## Step 7: Update progress comment
176+
177+
Replace the progress comment with a completion summary:
178+
179+
```bash
180+
gh api repos/$REPO/issues/comments/$PROGRESS_COMMENT_ID \
181+
-X PATCH -f body="$(cat <<'EOF'
182+
**Fix complete:**
183+
184+
- [x] Apply fix to `path/to/file.md`
185+
- [x] Run Vale and Dale
186+
- [x] Create PR
187+
188+
**Summary:**
189+
- `path/to/file.md`: <what was fixed>
190+
191+
PR: #<pr-number>
192+
EOF
193+
)"
194+
```
195+
196+
## Failure handling
197+
198+
If you encounter an error mid-execution (Vale not available, edit conflict, push failure):
199+
200+
1. Post a comment on the issue explaining what went wrong and what was attempted
201+
2. If a branch was created, note the branch name so a team member can continue manually
202+
3. Do not leave the issue in a confusing state — always communicate what happened
203+
204+
## Behavioral notes
205+
206+
- **Confident = act, uncertain = ask.** If you can map a URL or find an exact file match, proceed. If the request is ambiguous, ask a clarifying question and stop.
207+
- **Fix what's reported, nothing else.** If the issue says "fix the broken link in step 3," fix that link — don't also rewrite the sentence for clarity or fix grammar in other paragraphs.
208+
- **If a fix would change the author's meaning**, skip it and note it in your summary. Ask how they'd like to handle it.
209+
- **Each invocation is stateless.** You won't remember previous runs. Always read the full issue body and all comments for context.
210+
- **Missing images cannot be fixed.** Note this in a comment and let a team member handle it.

.github/workflows/claude-issue-labeler.yml

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,104 @@ jobs:
9797
Note: The skill should preserve template-assigned labels and add complementary labels.
9898
Issue body may have been modified by previous steps.
9999
claude_args: '--allowedTools "Bash(gh:*),Skill(assign-label)"'
100+
101+
content-fix:
102+
needs: process-issue
103+
if: >-
104+
github.event_name == 'issues' &&
105+
github.event.action == 'opened' &&
106+
contains(join(github.event.issue.labels.*.name, ','), 'documentation') &&
107+
contains(join(github.event.issue.labels.*.name, ','), 'fix')
108+
runs-on: ubuntu-latest
109+
permissions:
110+
contents: write
111+
pull-requests: write
112+
issues: write
113+
id-token: write
114+
115+
steps:
116+
- name: Check if issue is still open
117+
id: check-state
118+
run: |
119+
STATE=$(gh issue view ${{ github.event.issue.number }} --repo ${{ github.repository }} --json state --jq .state)
120+
echo "issue_state=$STATE" >> "$GITHUB_OUTPUT"
121+
env:
122+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
123+
124+
- name: Checkout repository
125+
if: steps.check-state.outputs.issue_state == 'OPEN'
126+
uses: actions/checkout@v4
127+
with:
128+
fetch-depth: 0
129+
130+
- name: Run content-fix skill
131+
if: steps.check-state.outputs.issue_state == 'OPEN'
132+
uses: anthropics/claude-code-action@v1
133+
env:
134+
REPO: ${{ github.repository }}
135+
with:
136+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
137+
github_token: ${{ secrets.GITHUB_TOKEN }}
138+
show_full_output: true
139+
prompt: |
140+
/content-fix ${{ github.event.issue.number }}
141+
142+
Context:
143+
- REPO: ${{ github.repository }}
144+
- ISSUE_NUMBER: ${{ github.event.issue.number }}
145+
- ISSUE_TITLE: ${{ github.event.issue.title }}
146+
claude_args: '--allowedTools "Bash(gh:*),Bash(git:*),Bash(vale:*),Read,Write,Edit,Glob,Grep,Skill(content-fix),Skill(dale)"'
147+
148+
content-fix-followup:
149+
needs: process-issue
150+
if: >-
151+
github.event_name == 'issue_comment' &&
152+
!github.event.issue.pull_request &&
153+
contains(github.event.comment.body, '@claude') &&
154+
!startsWith(github.event.comment.user.login, 'github-actions') &&
155+
contains(join(github.event.issue.labels.*.name, ','), 'documentation') &&
156+
contains(join(github.event.issue.labels.*.name, ','), 'fix')
157+
runs-on: ubuntu-latest
158+
permissions:
159+
contents: write
160+
pull-requests: write
161+
issues: write
162+
id-token: write
163+
164+
steps:
165+
- name: Check if issue is still open
166+
id: check-state
167+
run: |
168+
STATE=$(gh issue view ${{ github.event.issue.number }} --repo ${{ github.repository }} --json state --jq .state)
169+
echo "issue_state=$STATE" >> "$GITHUB_OUTPUT"
170+
env:
171+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
172+
173+
- name: Checkout repository
174+
if: steps.check-state.outputs.issue_state == 'OPEN'
175+
uses: actions/checkout@v4
176+
with:
177+
fetch-depth: 0
178+
179+
- name: Run content-fix skill
180+
if: steps.check-state.outputs.issue_state == 'OPEN'
181+
uses: anthropics/claude-code-action@v1
182+
env:
183+
REPO: ${{ github.repository }}
184+
COMMENT_BODY: ${{ github.event.comment.body }}
185+
with:
186+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
187+
github_token: ${{ secrets.GITHUB_TOKEN }}
188+
show_full_output: true
189+
prompt: |
190+
/content-fix ${{ github.event.issue.number }}
191+
192+
Context:
193+
- REPO: ${{ github.repository }}
194+
- ISSUE_NUMBER: ${{ github.event.issue.number }}
195+
- ISSUE_TITLE: ${{ github.event.issue.title }}
196+
- TRIGGERING_COMMENT: $COMMENT_BODY
197+
198+
This is a follow-up invocation. A user replied with @claude on a content_fix issue.
199+
Read the full issue body AND all comments to understand the complete context.
200+
claude_args: '--allowedTools "Bash(gh:*),Bash(git:*),Bash(vale:*),Read,Write,Edit,Glob,Grep,Skill(content-fix),Skill(dale)"'

CLAUDE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ PRs target `dev`. Never commit directly to `dev` or `main`. The `sync-dev-to-mai
7373
| `claude-doc-pr.yml` | PRs to dev with `docs/` changes | Dale + editorial review; `@claude` follow-up |
7474
| `claude-documentation-reviewer.yml` | PRs with `.md` changes | AI review with inline suggestions |
7575
| `claude-documentation-fixer.yml` | `@claude` comment on PR | Apply fixes and push |
76-
| `claude-issue-labeler.yml` | Issues opened/edited | Security screening, CoC check, auto-labeling |
76+
| `claude-issue-labeler.yml` | Issues opened/edited | Security screening, CoC check, auto-labeling, content fix automation |
7777
| `sync-dev-to-main.yml` | Daily 8 AM PST | Auto-merge dev to main |
7878
| `reindex-algolia.yml` | After main deploy | Refresh search index |
7979

@@ -90,6 +90,7 @@ When a user asks for help with documentation, always use the appropriate tool:
9090
| `/dale` | Skill | Custom linter for Netwrix-specific writing patterns |
9191
| `/doc-help` | Skill | Interactive writing assistant (terminal sessions) |
9292
| `/doc-pr` | Skill | Automated PR review (Dale + editorial) |
93+
| `/content-fix` | Skill | Autonomous issue-to-PR fixer for content_fix issues |
9394
| `/doc-pr-fix` | Skill | Autonomous PR fixer triggered by `@claude` |
9495
| `tech-writer` | Agent | Autonomous end-to-end doc writing/editing |
9596
| `vale-rule-writer` | Agent | Creates new Vale rules |

0 commit comments

Comments
 (0)